source: trunk/MagicSoft/Mars/mbase/MStatusDisplay.cc@ 8964

Last change on this file since 8964 was 8962, checked in by tbretz, 18 years ago
*** empty log message ***
File size: 91.8 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 4/2003 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2003-2008
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MStatusDisplay
28//
29// This status display can be used (and is used) to display results in
30// a tabbed window. The window can be written to and read from a root file
31// (see Read and Write) or printed as a postscript file (see SaveAsPS).
32//
33// To write gif files of C-Macros use SaveAsGif()/SaveAsPNG() or SaveAsC().
34// Direct printing to the default printer (via lpr) can be done by
35// PrintPS().
36//
37// It has also to half status lines which can be used to display the status
38// or something going on. Together with the status lines it has a progress
39// bar which can display the progress of a job or loop.
40// Access the progress bar by GetProgressBar()
41//
42// To add a new tab and get a pointer to the newly created TCanvas
43// use AddTab.
44//
45// If you have a MStatusDisplay and you are not sure whether it was
46// destroyed by the user meanwhile use:
47// gROOT->GetListOfSpecials()->FindObject(pointer);
48// Each MStatusDisplay is added to list list by its constructor and
49// removed from the list by the destructor.
50//
51// You can redirect an output to a MLog-logstream by calling SetLogStream().
52// To disable redirction call SetLogStream(NULL)
53//
54// Because updates to the tabs are only done/displayed if a tab is active
55// using the gui doesn't make things slower (<1%) if the first (legend
56// tab) is displayed. This gives you the possibility to look into
57// the current progress of a loop without loosing more time than the
58// single update of the tab.
59//
60/////////////////////////////////////////////////////////////////////////////
61#include "MStatusDisplay.h"
62
63#include <errno.h>
64
65#include <fstream> // fstream
66
67#include <TH1.h> // TH1::AddDirectory
68#include <TPDF.h> // TPDF
69#include <TSVG.h> // TSVG
70#include <TEnv.h> // TEnv
71#include <TLine.h> // TLine
72#include <TMath.h>
73#include <TText.h> // TText
74#include <TFile.h> // gFile
75#include <TFrame.h> // TFrame
76#include <TStyle.h> // gStyle
77#include <TCanvas.h> // TCanvas
78#include <TSystem.h> // gSystem
79#include <TDatime.h> // TDatime
80#include <TRandom.h> // TRandom
81#include <TRegexp.h> // TRegexp
82#include <TThread.h> // TThread::Self()
83#include <TBrowser.h> // TBrowser
84#include <TObjArray.h> // TObjArray
85#include <TPostScript.h> // TPostScript
86#include <TMethodCall.h> // TMethodCall
87
88#include <TInterpreter.h> // gInterpreter
89
90#include <TGTab.h> // TGTab
91#include <TGLabel.h> // TGLabel
92#include <TG3DLine.h> // TGHorizontal3DLine
93#include <TGButton.h> // TGPictureButton
94#include <TGTextView.h> // TGTextView
95#include <TGComboBox.h> // TGComboBox
96#include <TGStatusBar.h> // TGStatusBar
97#include <TGFileDialog.h> // TGFileDialog
98#include <TGProgressBar.h> // TGHProgressBar
99#include <TGTextEditDialogs.h> // TGPrintDialog
100#include <TRootEmbeddedCanvas.h> // TRootEmbeddedCanvas
101
102#include "MString.h"
103
104#include "MLog.h" // MLog
105#include "MLogManip.h" // inf, warn, err
106
107#include "MGList.h" // MGList
108#include "MGMenu.h" // MGMenu, TGMenu
109#include "MSearch.h" // MSearch
110#include "MParContainer.h" // MParContainer::GetDescriptor
111#include "MStatusArray.h" // MStatusArray
112
113#undef DEBUG
114//#define DEBUG
115
116ClassImp(MStatusDisplay);
117
118using namespace std;
119
120// ------------ Workaround for a non working TGTextView::Search -------------
121#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,05)
122class MGTextView : public TGTextView
123{
124public:
125 MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, Int_t id = -1,
126 UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
127 TGTextView(parent, w, h, id, sboptions, back) {}
128 MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, TGText *text,
129 Int_t id = -1, UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
130 TGTextView(parent, w, h, text, id, sboptions, back) {}
131 MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, const char *string,
132 Int_t id = -1, UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
133 TGTextView(parent, w, h, string, id, sboptions, back) {}
134
135 void Mark(Long_t xPos, Long_t yPos) { TGTextView::Mark(xPos, yPos); }
136 void UnMark() { TGTextView::UnMark(); }
137
138 Bool_t Search(const char *string, Bool_t direction, Bool_t caseSensitive)
139 {
140 // Taken from TGTextView::Search and modified.
141
142 TGLongPosition pos, pos2;
143 pos2.fX = pos2.fY = 0;
144 if (fIsMarked) {
145 if (!direction)
146 {
147 pos2.fX = fMarkedStart.fX;
148 pos2.fY = fMarkedStart.fY;
149 }
150 else
151 {
152 pos2.fX = fMarkedEnd.fX + 1;
153 pos2.fY = fMarkedEnd.fY;
154 }
155 }
156 if (!fText->Search(&pos, pos2, string, direction, caseSensitive))
157 return kFALSE;
158 UnMark();
159 fIsMarked = kTRUE;
160 fMarkedStart.fY = fMarkedEnd.fY = pos.fY;
161 fMarkedStart.fX = pos.fX;
162 fMarkedEnd.fX = fMarkedStart.fX + strlen(string);
163 pos.fY = ToObjYCoord(fVisible.fY);
164 if ((fMarkedStart.fY < pos.fY) ||
165 (ToScrYCoord(fMarkedStart.fY) >= (Int_t)fCanvas->GetHeight()))
166 pos.fY = fMarkedStart.fY;
167 pos.fX = ToObjXCoord(fVisible.fX, pos.fY);
168 if ((fMarkedStart.fX < pos.fX) ||
169 (ToScrXCoord(fMarkedStart.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()))
170 pos.fX = fMarkedStart.fX;
171
172 SetVsbPosition((ToScrYCoord(pos.fY) + fVisible.fY)/fScrollVal.fY);
173 SetHsbPosition((ToScrXCoord(pos.fX, pos.fY) + fVisible.fX)/fScrollVal.fX);
174 DrawRegion(0, (Int_t)ToScrYCoord(fMarkedStart.fY), fCanvas->GetWidth(),
175 UInt_t(ToScrYCoord(fMarkedEnd.fY+1) - ToScrYCoord(fMarkedEnd.fY)));
176
177 return kTRUE;
178 }
179};
180#else
181#define MGTextView TGTextView
182#endif
183
184// --------------------------------------------------------------------------
185
186TGCompositeFrame *MStatusDisplay::GetTabContainer(const char *name) const
187{
188#if ROOT_VERSION_CODE < ROOT_VERSION(4,03,05)
189 if (!fTab)
190 return 0;
191
192 TGFrameElement *el;
193 TGTabElement *tab = 0;
194 TGCompositeFrame *comp = 0;
195
196 TIter next(fTab->GetList());
197 next(); // skip first container
198
199 while ((el = (TGFrameElement *) next())) {
200 el = (TGFrameElement *) next();
201 comp = (TGCompositeFrame *) el->fFrame;
202 next();
203 tab = (TGTabElement *)el->fFrame;
204 if (name == tab->GetText()->GetString()) {
205 return comp;
206 }
207 }
208
209 return 0;
210#else
211 return fTab ? fTab->GetTabContainer(name) : 0;
212#endif
213}
214
215TGTabElement *MStatusDisplay::GetTabTab(const char *name) const
216{
217#if ROOT_VERSION_CODE < ROOT_VERSION(4,03,05)
218 if (!fTab)
219 return 0;
220
221 TGFrameElement *el;
222 TGTabElement *tab = 0;
223
224 TIter next(fTab->GetList());
225 next(); // skip first container
226
227 while ((el = (TGFrameElement *) next())) {
228 next();
229 tab = (TGTabElement *)el->fFrame;
230 if (name == tab->GetText()->GetString()) {
231 return tab;
232 }
233 }
234
235 return 0;
236#else
237 return fTab ? fTab->GetTabTab(name) : 0;
238#endif
239}
240// --------------------------------------------------------------------------
241
242
243// --------------------------------------------------------------------------
244//
245// Add menu bar to the GUI
246//
247void MStatusDisplay::AddMenuBar()
248{
249 //
250 // File Menu
251 //
252 MGPopupMenu *filemenu = new MGPopupMenu(gClient->GetRoot());
253 filemenu->AddEntry("New &Canvas", kFileCanvas);
254 filemenu->AddEntry("New &Browser", kFileBrowser);
255 filemenu->AddEntry("New &Tab", kFileTab);
256 filemenu->AddSeparator();
257
258 const TString fname(MString::Format("Save %s.", gROOT->GetName()));
259 MGPopupMenu *savemenu = new MGPopupMenu(gClient->GetRoot());
260 savemenu->AddEntry(MString::Format("%s&ps", fname.Data()), kFileSaveAsPS);
261 savemenu->AddEntry(MString::Format("%sp&df", fname.Data()), kFileSaveAsPDF);
262 savemenu->AddEntry(MString::Format("%s&svg", fname.Data()), kFileSaveAsSVG);
263 savemenu->AddSeparator();
264 savemenu->AddEntry(MString::Format("%sp&ng", fname.Data()), kFileSaveAsPNG);
265 savemenu->AddEntry(MString::Format("%s&gif", fname.Data()), kFileSaveAsGIF);
266 savemenu->AddEntry(MString::Format("%s&jpg", fname.Data()), kFileSaveAsJPG);
267 savemenu->AddEntry(MString::Format("%s&xpm", fname.Data()), kFileSaveAsXPM);
268 savemenu->AddEntry(MString::Format("%s&tiff",fname.Data()), kFileSaveAsTIFF);
269 savemenu->AddEntry(MString::Format("%s&bmp", fname.Data()), kFileSaveAsBMP);
270 savemenu->AddEntry(MString::Format("%sx&ml", fname.Data()), kFileSaveAsXML);
271 savemenu->AddEntry(MString::Format("%scs&v", fname.Data()), kFileSaveAsCSV);
272 savemenu->AddSeparator();
273 savemenu->AddEntry(MString::Format("%s&C", fname.Data()), kFileSaveAsC);
274 savemenu->AddEntry(MString::Format("%s&root", fname.Data()), kFileSaveAsRoot);
275 savemenu->Associate(this);
276
277 filemenu->AddEntry("&Open...", kFileOpen);
278 filemenu->AddPopup("&Save", savemenu);
279 filemenu->AddEntry("Save &As...", kFileSaveAs);
280 filemenu->AddSeparator();
281 filemenu->AddEntry("&Reset", kFileReset);
282 filemenu->AddSeparator();
283 filemenu->AddEntry("&Print", kFilePrint);
284 filemenu->AddSeparator();
285 filemenu->AddEntry("C&lose", kFileClose);
286 filemenu->AddEntry("E&xit", kFileExit);
287 filemenu->Associate(this);
288
289 //
290 // Tab Menu
291 //
292 MGPopupMenu *tabmenu = new MGPopupMenu(gClient->GetRoot());
293 tabmenu->AddEntry("Next [&+]", kTabNext);
294 tabmenu->AddEntry("Previous [&-]", kTabPrevious);
295 tabmenu->AddSeparator();
296
297 const TString fname2(MString::Format("Save %s-i.", gROOT->GetName()));
298 MGPopupMenu *savemenu2 = new MGPopupMenu(gClient->GetRoot());
299 savemenu2->AddEntry(MString::Format("%s&ps", fname2.Data()), kTabSaveAsPS);
300 savemenu2->AddEntry(MString::Format("%sp&df", fname2.Data()), kTabSaveAsPDF);
301 savemenu2->AddEntry(MString::Format("%s&svg", fname2.Data()), kTabSaveAsSVG);
302 savemenu2->AddSeparator();
303 savemenu2->AddEntry(MString::Format("%sp&ng", fname2.Data()), kTabSaveAsPNG);
304 savemenu2->AddEntry(MString::Format("%s&gif", fname2.Data()), kTabSaveAsGIF);
305 savemenu2->AddEntry(MString::Format("%s&jpg", fname2.Data()), kTabSaveAsJPG);
306 savemenu2->AddEntry(MString::Format("%s&xpm", fname2.Data()), kTabSaveAsXPM);
307 savemenu2->AddEntry(MString::Format("%s&tiff",fname2.Data()), kTabSaveAsTIFF);
308 savemenu2->AddEntry(MString::Format("%s&bmp", fname2.Data()), kTabSaveAsBMP);
309 savemenu2->AddEntry(MString::Format("%sx&ml", fname2.Data()), kTabSaveAsXML);
310 savemenu2->AddEntry(MString::Format("%scs&v", fname2.Data()), kTabSaveAsCSV);
311 savemenu2->AddSeparator();
312 savemenu2->AddEntry(MString::Format("%s&C", fname2.Data()), kTabSaveAsC);
313 savemenu2->AddEntry(MString::Format("%s&root", fname2.Data()), kTabSaveAsRoot);
314 savemenu2->Associate(this);
315
316 tabmenu->AddPopup("&Save", savemenu2);
317 tabmenu->AddEntry("Save tab &As...", kTabSaveAs);
318 tabmenu->AddSeparator();
319 tabmenu->AddEntry("&Remove", kTabRemove);
320 tabmenu->AddSeparator();
321 tabmenu->AddEntry("&Print", kTabPrint);
322 tabmenu->Associate(this);
323
324 //
325 // Loop Menu
326 //
327 MGPopupMenu *loopmenu = new MGPopupMenu(gClient->GetRoot());
328 loopmenu->AddEntry("&Stop", kLoopStop);
329 loopmenu->Associate(this);
330
331 //
332 // Loop Menu
333 //
334 MGPopupMenu *sizemenu = new MGPopupMenu(gClient->GetRoot());
335 sizemenu->AddEntry("Fit to 640x&480", kSize640);
336 sizemenu->AddEntry("Fit to 768x&576", kSize768);
337 sizemenu->AddEntry("Fit to 800x&600", kSize800);
338 sizemenu->AddEntry("Fit to 960x7&20", kSize960);
339 sizemenu->AddEntry("Fit to 1024x&768", kSize1024);
340 sizemenu->AddEntry("Fit to 1152x&864", kSize1152);
341 sizemenu->AddEntry("Fit to 1280x&1024", kSize1280);
342 sizemenu->AddEntry("Fit to 1400x1050", kSize1400);
343 sizemenu->AddEntry("Fit to 1600x1200", kSize1600);
344 sizemenu->AddEntry("Fit to &Desktop", kSizeOptimum);
345 sizemenu->Associate(this);
346
347 //
348 // Log Menu
349 //
350 MGPopupMenu *logmenu = new MGPopupMenu(gClient->GetRoot());
351 logmenu->AddEntry("&Copy Selected", kLogCopy);
352 logmenu->AddEntry("Cl&ear all", kLogClear);
353 logmenu->AddSeparator();
354 logmenu->AddEntry("Select &All", kLogSelect);
355 logmenu->AddSeparator();
356 logmenu->AddEntry("&Find...", kLogFind);
357 logmenu->AddSeparator();
358 logmenu->AddEntry("&Save", kLogSave);
359 logmenu->AddEntry("Save &append", kLogAppend);
360 logmenu->AddSeparator();
361 logmenu->AddEntry("&Print", kLogPrint);
362 logmenu->Associate(this);
363
364 //
365 // Menu Bar
366 //
367 TGLayoutHints *layitem = new TGLayoutHints(kLHintsNormal, 0, 4, 0, 0);
368 fList->Add(layitem);
369
370 MGMenuBar *menubar = new MGMenuBar(this, 1, 1, kHorizontalFrame);
371 menubar->AddPopup("&File", filemenu, layitem);
372 menubar->AddPopup("Lo&g", logmenu, layitem);
373 menubar->AddPopup("&Size", sizemenu, layitem);
374 menubar->AddPopup("&Tab", tabmenu, layitem);
375 menubar->AddPopup("&Loop", loopmenu, layitem);
376 menubar->BindKeys(this);
377 AddFrame(menubar);
378
379 //
380 // Line below menu bar
381 //
382 TGLayoutHints *laylinesep = new TGLayoutHints(kLHintsTop|kLHintsExpandX);
383 fList->Add(laylinesep);
384
385 TGHorizontal3DLine *linesep = new TGHorizontal3DLine(this);
386 AddFrame(linesep, laylinesep);
387
388 //
389 // Add everything to autodel list
390 //
391 fList->Add(savemenu);
392 fList->Add(savemenu2);
393 fList->Add(filemenu);
394 fList->Add(loopmenu);
395 fList->Add(sizemenu);
396 fList->Add(menubar);
397 fList->Add(tabmenu);
398 fList->Add(logmenu);
399 fList->Add(linesep);
400}
401
402// --------------------------------------------------------------------------
403//
404// Adds an empty TGCompositeFrame which might be filled by the user
405//
406void MStatusDisplay::AddUserFrame()
407{
408 TGLayoutHints *lay=new TGLayoutHints(kLHintsExpandX);
409 fList->Add(lay);
410
411 fUserFrame = new TGCompositeFrame(this, 1, 1);
412 AddFrame(fUserFrame, lay);
413 fList->Add(fUserFrame);
414}
415
416char *rot128(char *c)
417{
418 char *rc=c;
419 while (*c) *c++ += 128;
420 return rc;
421}
422
423// --------------------------------------------------------------------------
424//
425// Add the title tab
426//
427void MStatusDisplay::AddMarsTab()
428{
429 // Create Tab1
430 TGCompositeFrame *f = fTab->AddTab("-=MARS=-");
431
432 // Add list of tabs
433
434 TGComboBox *filter = new TGComboBox(f, kTabs);
435 fList->Add(filter);
436 filter->Associate(this);
437 filter->AddEntry("-=MARS=-", 0);
438 filter->Select(0);
439
440 TGLayoutHints *lay3 = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 10, 5);
441 fList->Add(lay3);
442 f->AddFrame(filter, lay3);
443
444 // Add MARS version
445 TGLabel *l = new TGLabel(f, MString::Format("Official Release: V%s", MARSVER));
446 fList->Add(l);
447
448 filter->SetWidth(l->GetWidth());
449 filter->SetHeight(4*l->GetHeight()/3);
450
451 TGLayoutHints *layb = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 5, 5);
452 fList->Add(layb);
453 f->AddFrame(l, layb);
454
455 // Add root version
456 l = new TGLabel(f, MString::Format("Using ROOT v%s", ROOT_RELEASE));
457 fList->Add(l);
458
459 TGLayoutHints *lay = new TGLayoutHints(kLHintsCenterX|kLHintsTop);
460 fList->Add(lay);
461 f->AddFrame(l, lay);
462
463 // Add Mars logo picture
464 const TGPicture *pic2 = fList->GetPicture("marslogo.xpm");
465 if (pic2)
466 {
467 TGPictureButton *mars = new TGPictureButton(f, pic2, kPicMars);
468 fList->Add(mars);
469 mars->Associate(this);
470
471 TGLayoutHints *lay2 = new TGLayoutHints(kLHintsCenterX|kLHintsCenterY, 10, 10, 5, 5);
472 fList->Add(lay2);
473 f->AddFrame(mars, lay2);
474 }
475
476 // Add date and time
477 l = new TGLabel(f, TDatime().AsString());
478 fList->Add(l);
479 f->AddFrame(l, lay);
480
481 // Add copyright notice
482 l = new TGLabel(f, Form("(c) MARS Software Development, 2000-%d", TDatime().GetYear()));
483 fList->Add(l);
484 f->AddFrame(l, layb);
485
486 TGLayoutHints *layc = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 0, 5);
487 fList->Add(layc);
488
489 const char *txt = "<< Thomas Bretz >>";
490 l = new TGLabel(f, txt);
491 fList->Add(l);
492 f->AddFrame(l, layc);
493}
494
495// --------------------------------------------------------------------------
496//
497// Adds the logbook tab to the GUI if it was not added previously.
498//
499// The logbook is updated four times a second only if the tab is visible.
500//
501// You can redirect an output to a MLog-logstream by calling SetLogStream().
502// To disable redirction call SetLogStream(NULL)
503//
504// if enable==kFALSE the stdout is disabled/enabled. Otherwise stdout
505// is ignored.
506//
507void MStatusDisplay::SetLogStream(MLog *log, Bool_t enable)
508{
509 if (gROOT->IsBatch())
510 return;
511
512 if (log && fLogBox==NULL)
513 {
514 fLogIdx = fTab->GetNumberOfTabs();
515
516 // Create Tab1
517 TGCompositeFrame *f = AddRawTab("-Logbook-");//fTab->AddTab("-Logbook-");
518
519 // Create Text View
520 fLogBox = new MGTextView(f, 1, 1); // , -1, 0, TGFrame::GetDefaultFrameBackground());
521 if (fFont)
522 fLogBox->SetFont(fFont);
523 //fLogBox->Associate(this);
524
525 // Add List box to the tab
526 TGLayoutHints *lay = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY,2,2,2,2);
527 f->AddFrame(fLogBox, lay);
528
529 // layout and map tab
530 Layout();
531 MapSubwindows();
532
533 // make it visible
534 // FIXME: This is a workaround, because TApplication::Run is not
535 // thread safe against ProcessEvents. We assume, that if
536 // we are not in the Main-Thread ProcessEvents() is
537 // called by the TApplication Event Loop...
538 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
539 gClient->ProcessEventsFor(fTab);
540 }
541
542 if (log)
543 {
544 fLog = log;
545
546 log->SetOutputGui(fLogBox, kTRUE);
547 log->EnableOutputDevice(MLog::eGui);
548 if (!enable)
549 log->DisableOutputDevice(MLog::eStdout);
550
551 fLogTimer.Start();
552 }
553 else
554 {
555 fLogTimer.Stop();
556
557 fLog->DisableOutputDevice(MLog::eGui);
558 fLog->SetOutputGui(NULL);
559 if (!enable)
560 fLog->EnableOutputDevice(MLog::eStdout);
561
562 fLog = &gLog;
563 }
564}
565
566// --------------------------------------------------------------------------
567//
568// Add the Tabs and the predifined Tabs to the GUI
569//
570void MStatusDisplay::AddTabs()
571{
572 fTab = new TGTab(this, 300, 300);
573
574 AddMarsTab();
575
576 // Add fTab to Frame
577 TGLayoutHints *laytabs = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 5, 5, 5);
578 AddFrame(fTab, laytabs);
579
580 fList->Add(fTab);
581 fList->Add(laytabs);
582}
583
584// --------------------------------------------------------------------------
585//
586// Add the progress bar to the GUI. The Progress Bar range is set to
587// (0,1) as default.
588//
589void MStatusDisplay::AddProgressBar()
590{
591 TGLayoutHints *laybar=new TGLayoutHints(kLHintsExpandX, 5, 5, 5, 5);
592 fList->Add(laybar);
593
594 fBar=new TGHProgressBar(this);
595 fBar->SetRange(0, 1);
596 fBar->ShowPosition();
597 AddFrame(fBar, laybar);
598 fList->Add(fBar);
599}
600
601// --------------------------------------------------------------------------
602//
603// Set the progress bar position between 0 and 1. The Progress bar range
604// is assumed to be (0,1)
605//
606void MStatusDisplay::SetProgressBarPosition(Float_t p, Bool_t upd)
607{
608 if (!gClient || gROOT->IsBatch())
609 return;
610
611 fBar->SetPosition(p);
612 if (upd)
613 gClient->ProcessEventsFor(fBar);
614}
615
616// --------------------------------------------------------------------------
617//
618// Adds the status bar to the GUI
619//
620void MStatusDisplay::AddStatusBar()
621{
622 fStatusBar = new TGStatusBar(this, 1, 1);
623
624 //
625 // Divide it like the 'Golden Cut' (goldener Schnitt)
626 //
627 // 1-a a
628 // 1: ------|----
629 //
630 // a/(1-a) = (1-a)/1
631 // a^2+a-1 = 0
632 // a = (-1+-sqrt(1+4))/2 = sqrt(5)/2-1/2 = 0.618
633 //
634 Int_t p[] = {38-2, 62-8, 10};
635
636 fStatusBar->SetParts(p, 3);
637
638 TGLayoutHints *layb = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 5, 4, 0, 3);
639 AddFrame(fStatusBar, layb);
640
641 fList->Add(fStatusBar);
642 fList->Add(layb);
643}
644
645// --------------------------------------------------------------------------
646//
647// Change the text in the status line 1
648//
649void MStatusDisplay::SetStatusLine(const char *txt, Int_t i)
650{
651 if (gROOT->IsBatch())
652 return;
653 fStatusBar->SetText(txt, i);
654
655 // FIXME: This is a workaround, because TApplication::Run is not
656 // thread safe against ProcessEvents. We assume, that if
657 // we are not in the Main-Thread ProcessEvents() is
658 // called by the TApplication Event Loop...
659 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
660 gClient->ProcessEventsFor(fStatusBar);
661}
662
663// --------------------------------------------------------------------------
664//
665// Display information about the name of a container
666//
667void MStatusDisplay::SetStatusLine2(const MParContainer &cont)
668{
669 SetStatusLine2(MString::Format("%s: %s", cont.GetDescriptor().Data(), cont.GetTitle()));
670}
671
672// --------------------------------------------------------------------------
673//
674// Default constructor. Opens a window with a progress bar. Get a pointer
675// to the bar by calling GetBar. This pointer can be used for the
676// eventloop.
677//
678// Be carefull: killing or closing the window while the progress meter
679// is still in use may cause segmentation faults. Please kill the window
680// always by deleting the corresponding object.
681//
682// You can give either width or height. (Set the value not given to -1)
683// The other value is calculated accordingly. If width and height are
684// given height is ignored. If width=height=0 an optimum size from
685// the desktop size is calculated.
686//
687// Update time default: 10s
688//
689MStatusDisplay::MStatusDisplay(Int_t w, Int_t h, Long_t t)
690: TGMainFrame((TGWindow*)((gClient?gClient:new TGClient),NULL), 1, 1), fName("MStatusDisplay"), fLog(&gLog), fBar(NULL), fTab(NULL), fTimer(this, t, kTRUE), fStatus(kLoopNone), fLogIdx(-1), fLogTimer(this, 250, kTRUE), fLogBox(NULL), fIsLocked(0)
691{
692 // p==NULL means: Take gClient->GetRoot() if not in batch mode
693 // see TGWindow::TGWindow()
694
695 // Make sure that the display is removed via RecursiveRemove
696 // from whereever possible.
697 SetBit(kMustCleanup);
698
699 //
700 // This is a possibility for the user to check whether this
701 // object has already been deleted. It will be removed
702 // from the list in the destructor.
703 //
704 gROOT->GetListOfSpecials()->Add(this);
705
706 fFont = gVirtualX->LoadQueryFont("7x13bold");
707 fMutex = new TMutex;
708
709 //
710 // In case we are in batch mode use a list of canvases
711 // instead of the Root Embedded Canvases in the TGTab
712 //
713 fBatch = new TList;
714 fBatch->SetOwner();
715
716 //
717 // Create a list handling GUI widgets
718 //
719 fList = new MGList;
720 fList->SetOwner();
721
722 //
723 // Create the layout hint for the root embedded canavses
724 //
725 fLayCanvas = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY);
726 fList->Add(fLayCanvas);
727
728 //
729 // Add Widgets (from top to bottom)
730 //
731 // In newer root versions gClient!=NULL in batch mode!
732 if (!gClient || !gClient->GetRoot() || gROOT->IsBatch()) // BATCH MODE
733 {
734 Resize(644, 484);
735 return;
736 }
737
738 AddMenuBar();
739 AddUserFrame();
740 AddTabs();
741 AddProgressBar();
742 AddStatusBar();
743
744 //
745 // set the smallest and biggest size of the Main frame
746 // and move it to its appearance position
747 SetWMSizeHints(566, 476, 2048, 1536, 1, 1);
748 MoveResize(rand()%100+566, rand()%100+476, 566, 476);
749 if (h>0)
750 SetDisplayHeight(h);
751 if (w>0)
752 SetDisplayWidth(w);
753 if (w==0 && h==0)
754 SetOptimumSize();
755
756 //
757 // Now do an automatic layout of the widgets and display the window
758 //
759 Layout();
760 MapSubwindows();
761
762 SetWindowName("Status Display");
763 SetIconName("Status Display");
764
765 MapWindow();
766
767 // FIXME: This is a workaround, because TApplication::Run is not
768 // thread safe against ProcessEvents. We assume, that if
769 // we are not in the Main-Thread ProcessEvents() is
770 // called by the TApplication Event Loop...
771 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
772 gSystem->ProcessEvents();
773}
774
775// --------------------------------------------------------------------------
776//
777// Destruct the window with all its tiles. Also the Progress Bar object
778// is deleted.
779//
780MStatusDisplay::~MStatusDisplay()
781{
782#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
783 fTab = NULL; // See HandleEvent
784#endif
785
786 //
787 // Delete object from global object table so it cannot
788 // be deleted by chance a second time
789 //
790 gInterpreter->DeleteGlobal(this);
791
792 //
793 // This is a possibility for the user to check whether this
794 // object has already been deleted. It has been added
795 // to the list in the constructor.
796 //
797 gROOT->GetListOfSpecials()->Remove(this);
798
799 SetLogStream(NULL);
800
801 //
802 // Delete the list of objects corresponding to this object
803 //
804 delete fList;
805
806 //
807 // Delete the list of canvases used in batch mode
808 // instead of the Root Embedded Canvases in the TGTab
809 //
810 delete fBatch;
811
812 //
813 // Delete the font used for the logging window
814 //
815 if (fFont)
816 gVirtualX->DeleteFont(fFont);
817
818 //
819 // Delete mutex
820 //
821 delete fMutex;
822}
823
824// --------------------------------------------------------------------------
825//
826// Takes a TGCompositeFrame as argument. Searches for the first
827// TRootEmbeddedCanvas which is contained by it and returns a pointer
828// to the corresponding TCanvas. If it isn't found NULL is returned.
829//
830TRootEmbeddedCanvas *MStatusDisplay::GetEmbeddedCanvas(TGCompositeFrame &cf)
831{
832 TIter Next(cf.GetList());
833
834 TGFrameElement *f;
835 while ((f=(TGFrameElement*)Next()))
836 if (f->fFrame->InheritsFrom(TRootEmbeddedCanvas::Class()))
837 return (TRootEmbeddedCanvas*)f->fFrame;
838
839 return NULL;
840}
841
842// --------------------------------------------------------------------------
843//
844// Takes a TGCompositeFrame as argument. Searches for the first
845// TRootEmbeddedCanvas which is contained by it and returns a pointer
846// to the corresponding TCanvas. If it isn't found NULL is returned.
847//
848TCanvas *MStatusDisplay::GetCanvas(TGCompositeFrame &cf)
849{
850 TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(cf);
851 return ec ? ec->GetCanvas() : NULL;
852}
853
854// --------------------------------------------------------------------------
855//
856// Returns the range of tabs containing valid canvases for the condition
857// num.
858//
859void MStatusDisplay::GetCanvasRange(Int_t &from, Int_t &to, Int_t num) const
860{
861 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
862
863 from = num<0 ? 1 : num;
864 to = num<0 ? max : num+1;
865}
866
867// --------------------------------------------------------------------------
868//
869// Returns GetCanvas of the i-th Tab.
870//
871TCanvas *MStatusDisplay::GetCanvas(int i) const
872{
873 if (gROOT->IsBatch())
874 return (TCanvas*)fBatch->At(i-1);
875
876 if (i<0 || i>=fTab->GetNumberOfTabs())
877 {
878 *fLog << warn << "MStatusDisplay::GetCanvas: Out of range." << endl;
879 return NULL;
880 }
881
882 return GetCanvas(*fTab->GetTabContainer(i));
883}
884
885// --------------------------------------------------------------------------
886//
887// Returns j-th pad of the i-th Tab.
888// Sets the pad to fill an entire window.
889//
890// This function can be used if single pad's out of an MStatusDisplay
891// have to be stored to file.
892//
893// ATTENTION: This function modifies the requested tab in MStatusDisplay itself!
894//
895TVirtualPad *MStatusDisplay::GetFullPad(const Int_t i, const Int_t j)
896{
897 if (!GetCanvas(i))
898 {
899 *fLog << warn << "MStatusDisplay::GetFullPad: i-th canvas not dound." << endl;
900 return NULL;
901 }
902
903 TVirtualPad *vpad = GetCanvas(i)->GetPad(j);
904 if (!vpad)
905 {
906 *fLog << warn << "MStatusDisplay::GetFullPad: Pad is out of range." << endl;
907 return NULL;
908 }
909
910 vpad->SetPad(0.,0.,1.,1.);
911 return vpad;
912}
913
914// --------------------------------------------------------------------------
915//
916// Searches for a TRootEmbeddedCanvas in the TGCompositeFramme of the
917// Tab with the name 'name'. Returns the corresponding TCanvas or
918// NULL if something isn't found.
919//
920TCanvas *MStatusDisplay::GetCanvas(const TString &name) const
921{
922 if (gROOT->IsBatch())
923 return (TCanvas*)fBatch->FindObject(name);
924
925 TGFrameElement *f;
926 TIter Next(fTab->GetList());
927 while ((f=(TGFrameElement*)Next()))
928 {
929 TObject *frame = f->fFrame;
930 if (!frame->InheritsFrom(TGTabElement::Class()))
931 continue;
932
933 TGTabElement *tab = (TGTabElement*)frame;
934 if (tab->GetString()==name)
935 break;
936 }
937
938 // Search for the next TGCompositeFrame in the list
939 while ((f=(TGFrameElement*)Next()))
940 {
941 TObject *frame = f->fFrame;
942 if (frame->InheritsFrom(TGCompositeFrame::Class()))
943 return GetCanvas(*(TGCompositeFrame*)frame);
944 }
945
946 return NULL;
947}
948
949// --------------------------------------------------------------------------
950//
951// Calls TCanvas::cd(), for the canvas returned by GetCanvas.
952//
953Bool_t MStatusDisplay::CdCanvas(const TString &name)
954{
955 TCanvas *c = GetCanvas(name);
956 if (!c)
957 return kFALSE;
958
959 c->cd();
960 return kTRUE;
961}
962
963TGCompositeFrame *MStatusDisplay::AddRawTab(const char *name)
964{
965 // Add new tab
966 TGCompositeFrame *f = fTab->AddTab(name);
967
968 TGComboBox *box = (TGComboBox*)fList->FindWidget(kTabs);
969 box->AddEntry(name, box->GetListBox()->GetNumberOfEntries());
970
971 // layout and map new tab
972 Layout();
973 MapSubwindows();
974 Layout();
975
976 // display new tab in the main frame
977 // FIXME: This is a workaround, because TApplication::Run is not
978 // thread safe against ProcessEvents. We assume, that if
979 // we are not in the Main-Thread ProcessEvents() is
980 // called by the TApplication Event Loop...
981 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
982 gClient->ProcessEventsFor(fTab);
983
984 *fLog << inf3 << "Adding Raw Tab '" << name << "' (" << f->GetWidth() << "x";
985 *fLog << f->GetHeight() << ")" << endl;
986
987 // return pointer to new canvas
988 return f;
989}
990
991// --------------------------------------------------------------------------
992//
993// This function was connected to all created canvases. It is used
994// to redirect GetObjectInfo into our own status bar.
995//
996// The 'connection' is done in AddTab
997//
998void MStatusDisplay::EventInfo(Int_t /*event*/, Int_t px, Int_t py, TObject *selected)
999{
1000 // Writes the event status in the status bar parts
1001 if (!selected)
1002 return;
1003
1004 TCanvas *c = (TCanvas*)gTQSender;
1005
1006 TVirtualPad* save=gPad;
1007
1008 gPad = c ? c->GetSelectedPad() : NULL;
1009
1010 if (gPad)
1011 SetStatusLine2(selected->GetObjectInfo(px,py));
1012
1013 gPad=save;
1014}
1015
1016// --------------------------------------------------------------------------
1017//
1018// Adds a new tab with the name 'name'. Adds a TRootEmbeddedCanvas to the
1019// tab and returns a reference to the corresponding TCanvas.
1020//
1021TCanvas &MStatusDisplay::AddTab(const char *name, const char *title)
1022{
1023 /*
1024 if (GetCanvas(name))
1025 {
1026 *fLog << warn;
1027 *fLog << "WARNING - A canvas '" << name << "' is already existing in the Status Display." << endl;
1028 *fLog << " This can cause unexpected crahes!" << endl;
1029 }*/
1030
1031 if (gROOT->IsBatch())
1032 {
1033 // 4 = 2*default border width of a canvas
1034 const UInt_t cw = GetWidth();
1035 const UInt_t ch = 2*cw/3 + 25; // 25: Menu, etc
1036
1037 // The constructor of TCanvas adds the canvas to the global list
1038 // of canvases gROOT->GetListOfCanvases(). If a canvas with an
1039 // identical name exists already in this list, the canvas is
1040 // deleted. In normal operation this might make sense and doesn't harm
1041 // because the embedded canvases behave different.
1042 // By creating the canvas without a name it is made sure that no
1043 // older canvas/tab vanished silently from the system (deleted from
1044 // the construtor). To make the handling of our canvases nevertheless
1045 // work well the name is set later. The list of canvases is also
1046 // part of the list of cleanups, thus fBatch need not to be added
1047 // to the list of cleanups.
1048 TCanvas *c = new TCanvas("", title?title:"", -cw, ch);
1049 c->SetName(name);
1050 fBatch->Add(c);
1051
1052 // Remove the canvas from the global list to make sure it is
1053 // not found by gROOT->FindObject
1054 //gROOT->GetListOfCanvases()->Remove(c);
1055 //gROOT->GetListOfCleanups()->Add(c);
1056
1057 return *c;
1058 }
1059
1060 // Add new tab
1061 TGCompositeFrame *f = fTab->AddTab(name);
1062
1063 // create root embedded canvas and add it to the tab
1064 TRootEmbeddedCanvas *ec = new TRootEmbeddedCanvas(name, f, f->GetWidth(), f->GetHeight(), 0);
1065 f->AddFrame(ec, fLayCanvas);
1066 fList->Add(ec);
1067
1068 // set background and border mode of the canvas
1069 TCanvas &c = *ec->GetCanvas();
1070
1071 if (title)
1072 c.SetTitle(title);
1073
1074 c.SetFillColor(16/*165*//*17*//*203*/);
1075 c.SetFrameBorderMode(0);
1076 c.SetBorderMode(0);
1077
1078 // If kNoContextMenu set set kNoContextMenu of the canvas
1079 if (TestBit(kNoContextMenu))
1080 c.SetBit(kNoContextMenu);
1081
1082 // Connect all TCanvas::ProcessedEvent to this->EventInfo
1083 // This means, that after TCanvas has processed an event
1084 // EventInfo of this class is called, see TCanvas::HandleInput
1085 c.Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)",
1086 "MStatusDisplay", this, "EventInfo(Int_t,Int_t,Int_t,TObject*)");
1087
1088 // Remove the canvas from the global list to make sure it is
1089 // not found by gROOT->FindObject
1090 //gROOT->GetListOfCanvases()->Remove(&c);
1091 //gROOT->GetListOfCleanups()->Add(&c);
1092
1093 TGComboBox *box = (TGComboBox*)fList->FindWidget(kTabs);
1094 box->AddEntry(name, box->GetListBox()->GetNumberOfEntries());
1095
1096 // layout and map new tab
1097 Layout(); // seems to layout the TGCompositeFrame
1098 MapSubwindows(); // maps the TGCompositeFrame
1099 Layout(); // layout the embedded canvas in the frame
1100
1101 // display new tab in the main frame
1102 // FIXME: This is a workaround, because TApplication::Run is not
1103 // thread safe against ProcessEvents. We assume, that if
1104 // we are not in the Main-Thread ProcessEvents() is
1105 // called by the TApplication Event Loop...
1106 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
1107 gClient->ProcessEventsFor(fTab);
1108
1109 *fLog << inf3 << "Adding Tab '" << name << "' (" << f->GetWidth() << "x";
1110 *fLog << f->GetHeight() << ", TCanvas=" << &c << ")" << endl;
1111
1112 // return pointer to new canvas
1113 return c;
1114}
1115
1116// --------------------------------------------------------------------------
1117//
1118// Update a canvas in a tab, takes the corresponding TGCompositeFrame
1119// as an argument. This is necessary, because not all functions
1120// changing the contents of a canvas or pad can call SetModified()
1121// for the corresponding tab. If this is not called correctly the
1122// tab won't be updated calling TCanvas::Update(). So we simply
1123// redraw it by our own (instead we could recursively call
1124// TPad::Modified() for everything contained by the TCanvas and
1125// call TCanvas::Update() afterwards)
1126//
1127void MStatusDisplay::UpdateTab(TGCompositeFrame *f)
1128{
1129 if (!f)
1130 return;
1131
1132 TCanvas *c=GetCanvas(*f);
1133 if (!c)
1134 return;
1135
1136 //
1137 // If we are in a multithreaded environment (gThreadXAR) we
1138 // have to make sure, that thus function is called from
1139 // the main thread.
1140 //
1141 if (gThreadXAR)
1142 {
1143 // Tell the X-Requester how to call this method
1144 TString str = MString::Format("%d", (ULong_t)f);
1145
1146 TMethodCall call(IsA(), "UpdateTab", "NULL");
1147 void *arr[4] = { NULL, &call, this, (void*)(const char*)str };
1148
1149 // If this is not the main thread return
1150 if (((*gThreadXAR)("METH", 4, arr, NULL)))
1151 return;
1152 }
1153
1154 //
1155 // Secure calls to update the tabs against itself, at least
1156 // c->Paint() or c->Flush() may crash X (bad drawable).
1157 // This makes sure, that a X call is not interuppted by
1158 // another X-call which was started from an gui interrrupt
1159 // in the same thread
1160 //
1161 if (fMutex->TryLock())
1162 return;
1163
1164#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,02)
1165 TPad *padsav = (TPad*)gPad;
1166 if (!gPad)
1167 c->cd();
1168#endif
1169
1170 if (!c->IsBatch())
1171 c->FeedbackMode(kFALSE); // Goto double buffer mode
1172
1173 //
1174 // Doing this ourself gives us the possibility to repaint
1175 // the canvas in any case (Paint() instead of PaintModified())
1176 //
1177 c->Paint(); // Repaint all pads
1178 c->Flush(); // Copy all pad pixmaps to the screen
1179
1180#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,02)
1181 if (padsav)
1182 padsav->cd();
1183 else
1184 gPad=NULL;
1185#endif
1186
1187 //c->SetCursor(kCross);
1188
1189 // Old version
1190 //c->Modified();
1191 //c->Update();
1192 //c->Paint();
1193
1194 fMutex->UnLock();
1195}
1196
1197TString MStatusDisplay::PrintDialog(TString &p, TString &c, TString &t, const char *ext)
1198{
1199 // If not in batch mode open a user dialog
1200 if (!gROOT->IsBatch())
1201 {
1202 char *cprinter = StrDup(p);
1203 char *ccmd = StrDup(c);
1204
1205 Int_t rc=0;
1206 new TGPrintDialog(fClient->GetRoot(), this, 400, 150, &cprinter, &ccmd, &rc);
1207 if (rc)
1208 {
1209 p = cprinter; // default has been changed
1210 c = ccmd;
1211 }
1212
1213 delete [] cprinter;
1214 delete [] ccmd;
1215
1216 if (!rc)
1217 return "";
1218 }
1219
1220 if (c.Contains("%f") && ext)
1221 {
1222 // Get temporary file name
1223 TString name = "mars";
1224
1225 FILE *f = gSystem->TempFileName(name, t);
1226 if (!f)
1227 {
1228 *fLog << warn << "MStatusDisplay::PrintDialog: Couldn't create temporary file in " << t << endl;
1229 SetStatusLine2("failed!");
1230 return "";
1231 }
1232 fclose(f);
1233
1234 // remove temp file
1235 gSystem->Unlink(name);
1236 name += ".";
1237 name += ext;
1238
1239 t = name;
1240 }
1241
1242 // compile command
1243 TString cmd(c);
1244
1245 // if sprinter.IsNull we assume that everything around %p can
1246 // be omitted and the program uses some kind of default
1247 if (p.IsNull())
1248 {
1249 TString sub;
1250 while (1)
1251 {
1252 sub = TString(cmd(TRegexp(" .*%p.* "))).Strip(TString::kBoth);
1253 if (sub.IsNull())
1254 break;
1255
1256 cmd.ReplaceAll(sub, "");
1257 }
1258 }
1259
1260 cmd.ReplaceAll("%p", p);
1261 cmd.ReplaceAll("%f", t);
1262
1263 return cmd;
1264}
1265
1266// --------------------------------------------------------------------------
1267//
1268// Saves the given canvas (pad) or all pads (num<0) as a temporary
1269// postscript file and prints it.
1270//
1271// The default command line c is: lpr -P%p %f
1272// %p: printer name
1273// %f: temporary file name
1274//
1275// The default printer name p is: <empty>
1276//
1277// Both can be changed in .rootrc by:
1278// PrintPS.Printer
1279// PrintPS.Command
1280//
1281// Ant the location of the temporary file t can by changed by
1282// Print.Directory
1283// the default is the system default directory (normally /tmp)
1284//
1285Int_t MStatusDisplay::PrintPS(Int_t num, const char *p, const char *c, const char *t)
1286{
1287 static TString sprinter = gEnv->GetValue("PrintPS.Printer", p&&*p?p:"");
1288 static TString scmd = gEnv->GetValue("PrintPS.Command", c&&*c?c:"lpr -P%p %f");
1289
1290 TString tmp = gEnv->GetValue("Print.Directory", t&&*t?t:gSystem->TempDirectory());
1291
1292 TString cmd = PrintDialog(sprinter, scmd, tmp, "ps");
1293 if (cmd.IsNull())
1294 return 0;
1295
1296 // set status lines
1297 SetStatusLine1("Printing...");
1298 SetStatusLine2("");
1299
1300 // print to temporary file
1301 const Int_t pages = SaveAsPS(num, tmp);
1302
1303 // check
1304 if (!pages)
1305 {
1306 *fLog << warn << "MStatusDisplay::Print: Sorry, couldn't save file as temporary postscript!" << endl;
1307 SetStatusLine2("Failed!");
1308 return 0;
1309 }
1310
1311 // execute command
1312 *fLog << dbg << "Executing: " << cmd << endl;
1313 gSystem->Exec(cmd);
1314
1315 // remove temporary file
1316 gSystem->Unlink(tmp);
1317
1318 SetStatusLine2(MString::Format("Done (%dpage(s))", pages));
1319
1320 return pages;
1321}
1322
1323// --------------------------------------------------------------------------
1324//
1325// Remove tab no i if this tab contains a TRootEmbeddedCanvas
1326//
1327void MStatusDisplay::RemoveTab(int i)
1328{
1329 TGCompositeFrame *f = fTab->GetTabContainer(i);
1330 if (!f)
1331 return;
1332
1333 TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(*f);
1334 if (!ec)
1335 return;
1336
1337 TCanvas *c = ec->GetCanvas();
1338 if (!c)
1339 return;
1340
1341 // Repair the "Workaround" being in the RecursiveRemove list
1342 // but not in a list checked by gROOT->FindObject
1343 //gROOT->GetListOfCleanups()->Remove(c);
1344 //gROOT->GetListOfCanvases()->Add(c);
1345
1346 // FIXME: Due to our workaround this is necessary for a successfull deletion
1347 //c->cd();
1348
1349 const TString name(c->GetName());
1350
1351 f->RemoveFrame(ec);
1352 delete fList->Remove(ec);
1353
1354 fTab->RemoveTab(i);
1355 fTab->SetTab(0);
1356
1357 TGComboBox *box = (TGComboBox*)fList->FindWidget(kTabs);
1358 box->RemoveEntry(i);
1359 for (int j=i; j<box->GetListBox()->GetNumberOfEntries(); j++)
1360 {
1361 TGTextLBEntry *entry = (TGTextLBEntry *)box->GetListBox()->Select(j+1, kFALSE);
1362 box->AddEntry(entry->GetText()->GetString(), j);
1363 box->RemoveEntry(j+1);
1364 }
1365 box->GetListBox()->Select(0);
1366
1367 // Looks strange...
1368 // const Int_t n = fTab->GetNumberOfTabs();
1369 // fTab->SetTab(i<=n-1 ? i : i-1);
1370
1371 // layout and map new tab
1372 Layout(); // seems to layout the TGCompositeFrame
1373 MapSubwindows(); // maps the TGCompositeFrame
1374 Layout(); // layout the embedded canvas in the frame
1375
1376 // display new tab in the main frame
1377 // FIXME: This is a workaround, because TApplication::Run is not
1378 // thread safe against ProcessEvents. We assume, that if
1379 // we are not in the Main-Thread ProcessEvents() is
1380 // called by the TApplication Event Loop...
1381 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
1382 gClient->ProcessEventsFor(fTab);
1383
1384 *fLog << inf << "Removed Tab #" << i << " '" << name << "'" << endl;
1385}
1386
1387// --------------------------------------------------------------------------
1388//
1389// Use this to check whether the MStatusDisplay still contains the
1390// TCanvas c. It could be removed meanwhile by menu usage.
1391//
1392Bool_t MStatusDisplay::HasCanvas(const TCanvas *c) const
1393{
1394 if (!c)
1395 return kFALSE;
1396
1397 // If you encounter unexpected crashes here, check if
1398 // a canvas is existing twice in the list or has been
1399 // deleted by accident. (Check AddTab)
1400
1401 if (gROOT->IsBatch())
1402 return (Bool_t)fBatch->FindObject(c);
1403
1404 for (int i=1; i<fTab->GetNumberOfTabs(); i++)
1405 if (c==GetCanvas(i))
1406 return kTRUE;
1407 return kFALSE;
1408}
1409
1410/*
1411 if (...)
1412 fMenu->AddPopup("&CaOs", fCaOs, NULL);
1413 else
1414 fMenu->RemovePopup("CaOs");
1415 fMenu->Resize(fMenu->GetDefaultSize());
1416 MapSubwindows();
1417 MapWindow();
1418 */
1419
1420void MStatusDisplay::Reset()
1421{
1422 if (gROOT->IsBatch())
1423 {
1424 fBatch->Delete();
1425 return;
1426 }
1427
1428 for (int i=fTab->GetNumberOfTabs()-1; i>0; i--)
1429 RemoveTab(i);
1430}
1431
1432Bool_t MStatusDisplay::SaveLogAsPS(const char *n) const
1433{
1434 TString name(n);
1435 AddExtension(name, "ps");
1436
1437 // Code taken from TGTextEdit::Print
1438 const TString pipe = MString::Format("a2ps -o%s", name.Data());
1439 FILE *p = gSystem->OpenPipe(pipe, "w");
1440 if (!p)
1441 {
1442 *fLog << err << "ERROR - Couldn't open pipe " << pipe << endl;
1443 return kFALSE;
1444 }
1445
1446 TGText *text = fLogBox->GetText();
1447
1448 char *buf1, *buf2;
1449 Long_t len;
1450 ULong_t i = 0;
1451 TGLongPosition pos;
1452
1453 pos.fX = pos.fY = 0;
1454 while (pos.fY < text->RowCount())
1455 {
1456 len = text->GetLineLength(pos.fY);
1457 buf1 = text->GetLine(pos, len);
1458 buf2 = new char[len + 2];
1459 strncpy(buf2, buf1, (UInt_t)len);
1460 buf2[len] = '\n';
1461 buf2[len+1] = '\0';
1462 while (buf2[i] != '\0') {
1463 if (buf2[i] == '\t') {
1464 ULong_t j = i+1;
1465 while (buf2[j] == 16 && buf2[j] != '\0')
1466 j++;
1467 strcpy(buf2+i+1, buf2+j);
1468 }
1469 i++;
1470 }
1471 fwrite(buf2, sizeof(char), strlen(buf2)+1, p);
1472
1473 delete [] buf1;
1474 delete [] buf2;
1475 pos.fY++;
1476 }
1477 gSystem->ClosePipe(p);
1478 return kTRUE;
1479}
1480
1481// --------------------------------------------------------------------------
1482//
1483// Print the log text.
1484//
1485// The default command line c is: a2ps -P%p
1486// %p: printer name
1487//
1488// The default printer name p is: <empty>
1489//
1490// Both can be changed in .rootrc by:
1491// PrintText.Printer
1492// PrintText.Command
1493//
1494Bool_t MStatusDisplay::PrintLog(const char *p, const char *c)
1495{
1496 static TString sprinter = gEnv->GetValue("PrintText.Printer", p&&*p?p:"");
1497 static TString scmd = gEnv->GetValue("PrintText.Command", c&&*c?c:"a2ps -P%p");
1498
1499 TString tmp;
1500 TString cmd = PrintDialog(sprinter, scmd, tmp);
1501 if (cmd.IsNull())
1502 return kFALSE;
1503
1504 // set status lines
1505 SetStatusLine1("Printing...");
1506 SetStatusLine2("");
1507
1508 // print to temporary file
1509 if (!SaveLogAsPS(cmd))
1510 {
1511 *fLog << warn << "MStatusDisplay::PrintLog: Sorry, couldn't create postscript!" << endl;
1512 SetStatusLine2("Failed!");
1513 return kFALSE;
1514 }
1515
1516 // execute command
1517 *fLog << dbg << "Executing: " << cmd << endl;
1518 gSystem->Exec(cmd);
1519
1520 SetStatusLine2("Done.");
1521
1522 return kTRUE;
1523}
1524
1525// --------------------------------------------------------------------------
1526//
1527// Process the kC_COMMAND, kCM_MENU messages
1528//
1529Bool_t MStatusDisplay::ProcessMessageCommandMenu(Long_t id)
1530{
1531 switch (id)
1532 {
1533 case kLoopStop:
1534 case kFileClose:
1535 case kFileExit:
1536 if (id==kFileExit || id==kFileClose)
1537 if (Close())
1538 delete this;
1539 fStatus = (Status_t)id;
1540 return kTRUE;
1541
1542 case kFileCanvas:
1543 new TCanvas;
1544 return kTRUE;
1545
1546 case kFileBrowser:
1547 new TBrowser;
1548 return kTRUE;
1549
1550 case kFileTab:
1551 AddTab(MString::Format("%d", fTab->GetNumberOfTabs()));
1552 return kTRUE;
1553
1554 case kFileReset:
1555 Reset();
1556 return kTRUE;
1557
1558 case kFileOpen:
1559 Open();
1560 return kTRUE;
1561
1562 case kFileSaveAs:
1563 SaveAs();
1564 return kTRUE;
1565
1566 case kFileSaveAsPS:
1567 SaveAsPS();
1568 return kTRUE;
1569
1570 case kFileSaveAsPDF:
1571 SaveAsPDF();
1572 return kTRUE;
1573
1574 case kFileSaveAsSVG:
1575 SaveAsSVG();
1576 return kTRUE;
1577
1578 case kFileSaveAsPNG:
1579 SaveAsPNG();
1580 return kTRUE;
1581
1582 case kFileSaveAsGIF:
1583 SaveAsGIF();
1584 return kTRUE;
1585
1586 case kFileSaveAsXPM:
1587 SaveAsXPM();
1588 return kTRUE;
1589
1590 case kFileSaveAsJPG:
1591 SaveAsJPG();
1592 return kTRUE;
1593
1594 case kFileSaveAsTIFF:
1595 SaveAsTIFF();
1596 return kTRUE;
1597
1598 case kFileSaveAsBMP:
1599 SaveAsBMP();
1600 return kTRUE;
1601
1602 case kFileSaveAsXML:
1603 SaveAsXML();
1604 return kTRUE;
1605
1606 case kFileSaveAsCSV:
1607 SaveAsCSV();
1608 return kTRUE;
1609
1610 case kFileSaveAsC:
1611 SaveAsC();
1612 return kTRUE;
1613
1614 case kFileSaveAsRoot:
1615 SaveAsRoot();
1616 return kTRUE;
1617
1618 case kFilePrint:
1619 PrintPS();
1620 return kTRUE;
1621
1622 case kTabSaveAs:
1623 SaveAs(fTab->GetCurrent());
1624 return kTRUE;
1625
1626 case kTabSaveAsPS:
1627 SaveAsPS(fTab->GetCurrent());
1628 return kTRUE;
1629
1630 case kTabSaveAsPDF:
1631 SaveAsPDF(fTab->GetCurrent());
1632 return kTRUE;
1633
1634 case kTabSaveAsSVG:
1635 SaveAsSVG(fTab->GetCurrent());
1636 return kTRUE;
1637
1638 case kTabSaveAsPNG:
1639 SaveAsPNG(fTab->GetCurrent());
1640 return kTRUE;
1641
1642 case kTabSaveAsGIF:
1643 SaveAsGIF(fTab->GetCurrent());
1644 return kTRUE;
1645
1646 case kTabSaveAsXPM:
1647 SaveAsXPM(fTab->GetCurrent());
1648 return kTRUE;
1649
1650 case kTabSaveAsJPG:
1651 SaveAsJPG(fTab->GetCurrent());
1652 return kTRUE;
1653
1654 case kTabSaveAsTIFF:
1655 SaveAsTIFF(fTab->GetCurrent());
1656 return kTRUE;
1657
1658 case kTabSaveAsBMP:
1659 SaveAsBMP(fTab->GetCurrent());
1660 return kTRUE;
1661
1662 case kTabSaveAsXML:
1663 SaveAsXML(fTab->GetCurrent());
1664 return kTRUE;
1665
1666 case kTabSaveAsCSV:
1667 SaveAsCSV(fTab->GetCurrent());
1668 return kTRUE;
1669
1670 case kTabSaveAsC:
1671 SaveAsC(fTab->GetCurrent());
1672 return kTRUE;
1673
1674 case kTabSaveAsRoot:
1675 SaveAsRoot(fTab->GetCurrent());
1676 return kTRUE;
1677
1678 case kTabPrint:
1679 PrintPS(fTab->GetCurrent());
1680 return kTRUE;
1681
1682 case kTabNext:
1683 fTab->SetTab(fTab->GetCurrent()+1);
1684 return kTRUE;
1685
1686 case kTabPrevious:
1687 fTab->SetTab(fTab->GetCurrent()-1);
1688 return kTRUE;
1689
1690 case kTabRemove:
1691 RemoveTab(fTab->GetCurrent());
1692 return kTRUE;
1693
1694 case kSize640:
1695 SetDisplaySize(640, 480);
1696 return kTRUE;
1697 case kSize768:
1698 SetDisplaySize(768, 576);
1699 return kTRUE;
1700 case kSize800:
1701 SetDisplaySize(800, 600);
1702 return kTRUE;
1703 case kSize960:
1704 SetDisplaySize(960, 720);
1705 return kTRUE;
1706 case kSize1024:
1707 SetDisplaySize(1024, 768);
1708 return kTRUE;
1709 case kSize1152:
1710 SetDisplaySize(1152, 864);
1711 return kTRUE;
1712 case kSize1280:
1713 SetDisplaySize(1280, 1024);
1714 return kTRUE;
1715 case kSize1400:
1716 SetDisplaySize(1400, 1050);
1717 return kTRUE;
1718 case kSize1600:
1719 SetDisplaySize(1600, 1200);
1720 return kTRUE;
1721 case kSizeOptimum:
1722 SetOptimumSize();
1723 return kTRUE;
1724
1725 case kLogClear:
1726 fLogBox->Clear();
1727 return kTRUE;
1728 case kLogCopy:
1729 fLogBox->Copy();
1730 return kTRUE;
1731 case kLogSelect:
1732 fLogBox->SelectAll();
1733 return kTRUE;
1734 case kLogFind:
1735 new MSearch(this);
1736 return kTRUE;
1737 case kLogSave:
1738 SetStatusLine1("Saving log...");
1739 SetStatusLine2("");
1740 *fLog << inf << "Saving log... " << flush;
1741 if (fLogBox->GetText()->Save(MString::Format("%s.log", gROOT->GetName())))
1742 {
1743 *fLog << "done." << endl;
1744 SetStatusLine2("done.");
1745 }
1746 else
1747 {
1748 *fLog << "failed!" << endl;
1749 SetStatusLine2("Failed!");
1750 }
1751 return kTRUE;
1752
1753 case kLogAppend:
1754 SetStatusLine1("Appending log...");
1755 SetStatusLine2("");
1756 *fLog << inf << "Appending log... " << flush;
1757 if (fLogBox->GetText()->Append(MString::Format("%s.log", gROOT->GetName())))
1758 {
1759 *fLog << "done." << endl;
1760 SetStatusLine2("done.");
1761 }
1762 else
1763 {
1764 *fLog << "failed!" << endl;
1765 SetStatusLine2("Failed!");
1766 }
1767 return kTRUE;
1768
1769 case kLogPrint:
1770 PrintLog();
1771 return kTRUE;
1772#ifdef DEBUG
1773 default:
1774 cout << "Command-Menu #" << id << endl;
1775#endif
1776 }
1777 return kTRUE;
1778
1779}
1780
1781// --------------------------------------------------------------------------
1782//
1783// Process the kC_COMMAND messages
1784//
1785Bool_t MStatusDisplay::ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2)
1786{
1787 switch (submsg)
1788 {
1789 case kCM_MENU: // 1
1790 return ProcessMessageCommandMenu(mp1); // mp2=userdata
1791 case kCM_TAB: // 8
1792 /*
1793 for (int i=0; i<fTab->GetNumberOfTabs(); i++)
1794 fTab->GetTabContainer(i)->UnmapWindow();
1795 */
1796 UpdateTab(fTab->GetTabContainer(mp1));
1797 //fTab->GetTabContainer(mp1)->MapWindow();
1798
1799 /*
1800 if (mp1>0)
1801 fMenu->AddPopup("&CaOs", fCaOs, NULL);
1802 else
1803 fMenu->RemovePopup("CaOs");
1804 fMenu->Resize(fMenu->GetDefaultSize());
1805 MapSubwindows();
1806 MapWindow();
1807 */
1808 return kTRUE;
1809 case kCM_COMBOBOX: // 7
1810 if (mp1==kTabs)
1811 fTab->SetTab(mp2);
1812 return kTRUE;
1813#ifdef DEBUG
1814 case kCM_MENUSELECT: // 2
1815 cout << "Command-Menuselect #" << mp1 << " (UserData=" << (void*)mp2 << ")" << endl;
1816 return kTRUE;
1817
1818 case kCM_BUTTON: // 3
1819 cout << "Command-Button." << endl;
1820 return kTRUE;
1821
1822 case kCM_CHECKBUTTON: // 4
1823 cout << "Command-CheckButton." << endl;
1824 return kTRUE;
1825
1826 case kCM_RADIOBUTTON: // 5
1827 cout << "Command-RadioButton." << endl;
1828 return kTRUE;
1829
1830 case kCM_LISTBOX: // 6
1831 cout << "Command-Listbox #" << mp1 << " (LineId #" << mp2 << ")" << endl;
1832 return kTRUE;
1833 default:
1834 cout << "Command: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1835#endif
1836 }
1837 return kTRUE;
1838}
1839
1840// --------------------------------------------------------------------------
1841//
1842// Process the kC_TEXTVIEW messages
1843//
1844Bool_t MStatusDisplay::ProcessMessageTextview(Long_t /*submsg*/, Long_t /*mp1*/, Long_t /*mp2*/)
1845{
1846 // kC_TEXTVIEW, kTXT_ISMARKED, widget id, [true|false] //
1847 // kC_TEXTVIEW, kTXT_DATACHANGE, widget id, 0 //
1848 // kC_TEXTVIEW, kTXT_CLICK2, widget id, position (y << 16) | x) //
1849 // kC_TEXTVIEW, kTXT_CLICK3, widget id, position (y << 16) | x) //
1850 // kC_TEXTVIEW, kTXT_F3, widget id, true //
1851 // kC_TEXTVIEW, kTXT_OPEN, widget id, 0 //
1852 // kC_TEXTVIEW, kTXT_CLOSE, widget id, 0 //
1853 // kC_TEXTVIEW, kTXT_SAVE, widget id, 0 //
1854#ifdef DEBUG
1855 switch (submsg)
1856 {
1857 case kTXT_ISMARKED:
1858 cout << "Textview-IsMarked #" << mp1 << " " << (mp2?"yes":"no") << endl;
1859 return kTRUE;
1860
1861 case kTXT_DATACHANGE:
1862 cout << "Textview-DataChange #" << mp1 << endl;
1863 return kTRUE;
1864
1865 case kTXT_CLICK2:
1866 cout << "Textview-Click2 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
1867 return kTRUE;
1868
1869 case kTXT_CLICK3:
1870 cout << "Textview-Click3 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
1871 return kTRUE;
1872
1873 case kTXT_F3:
1874 cout << "Textview-F3 #" << mp1 << endl;
1875 return kTRUE;
1876
1877 case kTXT_OPEN:
1878 cout << "Textview-Open #" << mp1 << endl;
1879 return kTRUE;
1880
1881 case kTXT_CLOSE:
1882 cout << "Textview-Close #" << mp1 << endl;
1883 return kTRUE;
1884
1885 case kTXT_SAVE:
1886 cout << "Textview-Save #" << mp1 << endl;
1887 return kTRUE;
1888
1889 default:
1890 cout << "Textview: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1891 }
1892#endif
1893 return kTRUE;
1894}
1895
1896// --------------------------------------------------------------------------
1897//
1898// Process the kC_USER messages
1899//
1900Bool_t MStatusDisplay::ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2)
1901{
1902 // kS_START, case sensitive | backward<<1, char *txt
1903 switch (submsg)
1904 {
1905 case kS_START:
1906 fLogBox->Search((char*)mp2, !(mp1&2>>1), mp1&1);
1907 return kTRUE;
1908#ifdef DEBUG
1909 default:
1910 cout << "User: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1911#endif
1912 }
1913 return kTRUE;
1914}
1915
1916// --------------------------------------------------------------------------
1917//
1918// Process the messages from the GUI
1919//
1920Bool_t MStatusDisplay::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2)
1921{
1922 // Can be found in WidgetMessageTypes.h
1923#ifdef DEBUG
1924 cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
1925 cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1926#endif
1927 switch (GET_MSG(msg))
1928 {
1929 case kC_COMMAND: // 1
1930 return ProcessMessageCommand(GET_SUBMSG(msg), mp1, mp2);
1931
1932 case kC_TEXTVIEW: // 9
1933 return ProcessMessageTextview(GET_SUBMSG(msg), mp1, mp2);
1934
1935 case kC_USER: // 1001
1936 return ProcessMessageUser(GET_SUBMSG(msg), mp1, mp2);
1937 }
1938#ifdef DEBUG
1939 cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
1940 cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1941#endif
1942 return kTRUE;
1943}
1944
1945Bool_t MStatusDisplay::Close()
1946{
1947 // Got close message for this MainFrame. Calls parent CloseWindow()
1948 // (which destroys the window) and terminate the application.
1949 // The close message is generated by the window manager when its close
1950 // window menu item is selected.
1951
1952 // CloseWindow must be overwritten because otherwise CloseWindow
1953 // and the destructor are calling DestroyWindow which seems to be
1954 // in conflict with the TRootEmbeddedCanvas.
1955
1956 // FIXME: Make sure that the Status Display is deleted from every
1957 // where (eg Eventloop) first!
1958
1959 //gLog << dbg << fName << " is on heap: " << (int)IsOnHeap() << endl;
1960
1961 if (TestBit(kExitLoopOnExit) || TestBit(kExitLoopOnClose))
1962 {
1963 //gLog << dbg << "CloseWindow() calling ExitLoop." << endl;
1964 gSystem->ExitLoop();
1965 }
1966
1967 if (fIsLocked<=0 && IsOnHeap())
1968 return kTRUE;
1969
1970 fStatus = kFileExit;
1971 return kFALSE;
1972}
1973
1974void MStatusDisplay::CloseWindow()
1975{
1976 if (Close())
1977 delete this;
1978}
1979
1980// --------------------------------------------------------------------------
1981//
1982// Calls SetBit(kNoContextMenu) for all TCanvas objects found in the
1983// Tabs.
1984//
1985void MStatusDisplay::SetNoContextMenu(Bool_t flag)
1986{
1987 if (fIsLocked>1 || gROOT->IsBatch())
1988 return;
1989
1990 flag ? SetBit(kNoContextMenu) : ResetBit(kNoContextMenu);
1991
1992 for (int i=1; i<fTab->GetNumberOfTabs(); i++)
1993 {
1994 TCanvas *c = GetCanvas(i);
1995 if (c)
1996 flag ? c->SetBit(kNoContextMenu) : c->ResetBit(kNoContextMenu);
1997 }
1998}
1999
2000// --------------------------------------------------------------------------
2001//
2002// Update the memory display in the status bar
2003//
2004void MStatusDisplay::UpdateMemory() const
2005{
2006 const TString path = MString::Format("/proc/%d/status", gSystem->GetPid());
2007 if (gSystem->AccessPathName(path, kFileExists))
2008 return;
2009
2010 TEnv env(path);
2011 const UInt_t kb = env.GetValue("VmSize", 0);
2012 if (kb==0)
2013 return;
2014
2015 char type = 'k';
2016 Float_t val = kb;
2017
2018 if (val>999)
2019 {
2020 type = 'M';
2021 val /= 1000;
2022 }
2023 if (val>999)
2024 {
2025 type = 'G';
2026 val /= 1000;
2027 }
2028 const TString txt = MString::Format("%.1f%c", val, type);
2029 fStatusBar->SetText(txt, 2);
2030}
2031
2032// --------------------------------------------------------------------------
2033//
2034// Updates the canvas (if existing) in the currenly displayed Tab.
2035// The update intervall is controlled by StartUpdate and StopUpdate
2036//
2037Bool_t MStatusDisplay::HandleTimer(TTimer *timer)
2038{
2039 if (gROOT->IsBatch())
2040 return kTRUE;
2041
2042 UpdateMemory();
2043
2044 const Int_t c = fTab->GetCurrent();
2045
2046 // Skip Legend Tab
2047 if (c==0)
2048 return kTRUE;
2049
2050 // Update a canvas tab (if visible)
2051 if (timer==&fTimer && c!=fLogIdx)
2052 {
2053 UpdateTab(fTab->GetCurrentContainer());
2054 return kTRUE;
2055 }
2056
2057 // update the logbook tab (if visible)
2058 if (timer==&fLogTimer && c==fLogIdx)
2059 {
2060 fLog->UpdateGui();
2061
2062 /*
2063 if (!fLogBox->TestBit(kHasChanged))
2064 return kTRUE;
2065
2066 fLogBox->ResetBit(kHasChanged);
2067 */
2068 return kTRUE;
2069 }
2070
2071 return kTRUE;
2072}
2073
2074// --------------------------------------------------------------------------
2075//
2076// Find an object in a canvas (uses MStatusArray as helper)
2077//
2078void MStatusDisplay::PrintContent(Option_t *o) const
2079{
2080 MStatusArray(*this).Print(o);
2081}
2082
2083// --------------------------------------------------------------------------
2084//
2085// Find an object in a canvas (uses MStatusArray as helper)
2086//
2087TObject *MStatusDisplay::FindObjectInCanvas(const char *obj, const char *base, const char *canv) const
2088{
2089 return MStatusArray(*this).FindObjectInCanvas(obj, base, canv);
2090}
2091
2092// --------------------------------------------------------------------------
2093//
2094// Draws a clone of a canvas into a new canvas. Taken from TCanvas.
2095//
2096void MStatusDisplay::DrawClonePad(TCanvas &newc, TCanvas &oldc) const
2097{
2098 //copy pad attributes
2099 newc.Range(oldc.GetX1(),oldc.GetY1(),oldc.GetX2(),oldc.GetY2());
2100 newc.SetTickx(oldc.GetTickx());
2101 newc.SetTicky(oldc.GetTicky());
2102 newc.SetGridx(oldc.GetGridx());
2103 newc.SetGridy(oldc.GetGridy());
2104 newc.SetLogx(oldc.GetLogx());
2105 newc.SetLogy(oldc.GetLogy());
2106 newc.SetLogz(oldc.GetLogz());
2107 newc.SetBorderSize(oldc.GetBorderSize());
2108 newc.SetBorderMode(oldc.GetBorderMode());
2109 ((TAttLine&)oldc).Copy((TAttLine&)newc);
2110 ((TAttFill&)oldc).Copy((TAttFill&)newc);
2111 ((TAttPad&)oldc).Copy((TAttPad&)newc);
2112
2113 // This must be there: Otherwise GetDrawOption() won't work
2114 TVirtualPad *padsav = gPad;
2115 oldc.cd();
2116
2117 const Bool_t store = TH1::AddDirectoryStatus();
2118 TH1::AddDirectory(kFALSE);
2119
2120 //copy primitives
2121 TObject *obj;
2122 TIter next(oldc.GetListOfPrimitives());
2123 while ((obj=next()))
2124 {
2125 // Old line - I think it is not necessary anymore because of the cd()
2126 //gROOT->SetSelectedPad(&newc);
2127
2128 // Now make a clone of the object
2129 TObject *clone = obj->Clone();
2130
2131 // Clone also important bits (FIXME: Is this correct)
2132 clone->SetBit(obj->TestBits(kCannotPick|kNoContextMenu));
2133
2134 // Now make sure that the clones are deleted at a later time
2135 clone->SetBit(kCanDelete|kMustCleanup);
2136
2137 // FIXME: This is a workaround for the problem with the MAstroCatalog in
2138 // MHFalseSource. It doesn't harm. We'll still try to find the reason
2139 if (clone->IsA()==TPad::Class())
2140 gROOT->GetListOfCleanups()->Add(clone);
2141
2142 // Add the clone and its draw-option to the current pad
2143 TVirtualPad *save2 = gPad;
2144 gPad = &oldc; // Don't do this before Clone()!
2145 newc.GetListOfPrimitives()->Add(clone, obj->GetDrawOption());
2146 gPad = save2;
2147 }
2148 newc.Modified();
2149 newc.Update();
2150
2151 TH1::AddDirectory(store);
2152
2153 padsav->cd();
2154}
2155
2156// --------------------------------------------------------------------------
2157//
2158// Display the contexts of a TObjArray in the display (all canvases)
2159//
2160Bool_t MStatusDisplay::Display(const TObjArray &list, const char *tab)
2161{
2162 TIter Next(&list);
2163
2164 TObject *o=Next();
2165 if (!o)
2166 {
2167 *fLog << err << "MStatusDisplay::Display: No entry in TObjArray." << endl;
2168 return kFALSE;
2169 }
2170
2171 fTitle = o->GetTitle();
2172
2173 TCanvas *c;
2174 while ((c=(TCanvas*)Next()))
2175 //if (!GetCanvas(c->GetName()))
2176 if (c->InheritsFrom(TCanvas::Class()))
2177 if (!tab || c->GetName()==(TString)tab)
2178 DrawClonePad(AddTab(c->GetName(), c->GetTitle()), *c);
2179
2180 return kTRUE;
2181}
2182
2183// --------------------------------------------------------------------------
2184//
2185// Reads the contents of a saved MStatusDisplay from a file.
2186//
2187Int_t MStatusDisplay::Read(const char *name, const char *tab)
2188{
2189 if (!gFile)
2190 {
2191 *fLog << warn << "MStatusDisplay::Read: No file found. Please create a TFile first." << endl;
2192 return 0;
2193 }
2194
2195 if (!gFile->IsOpen())
2196 {
2197 *fLog << warn << "MStatusDisplay::Read: File not open. Please open the TFile first." << endl;
2198 return 0;
2199 }
2200
2201 MStatusArray list;
2202
2203 const Int_t n = list.Read(name);
2204
2205 //
2206 // If no status display was found with this name try to find canvases
2207 // in the file and s´display them instead.
2208 //
2209 if (n==0)
2210 {
2211 const Bool_t store = TH1::AddDirectoryStatus();
2212 TH1::AddDirectory(kFALSE);
2213
2214 TIter Next(gFile->GetListOfKeys());
2215 TObject *key = 0;
2216 while ((key=Next()))
2217 {
2218 TCanvas *c=0;
2219 gFile->GetObject(key->GetName(), c);
2220 if (!c)
2221 break;
2222
2223 if (list.GetEntries()==0)
2224 list.Add(new TNamed(GetName(), GetTitle()));
2225
2226 list.Add(c);
2227 }
2228
2229 TH1::AddDirectory(store);
2230
2231 if (list.GetEntries()==0)
2232 {
2233 *fLog << warn << "MStatusDisplay::Read: No objects read." << endl;
2234 return 0;
2235 }
2236
2237 *fLog << inf << "MStatusDisplay: " << list.GetEntries() << " canvases directly read from file." << endl;
2238 }
2239
2240
2241 if (!Display(list, tab))
2242 {
2243 *fLog << err << "MStatusDisplay::Display: No entries found." << endl;
2244 return 0;
2245 }
2246
2247
2248 cout << "Display done." << endl;
2249
2250 if (n==0)
2251 return list.GetEntries();
2252
2253 *fLog << inf << "MStatusDisplay: Key " << name << " with " << n << " keys read from file." << endl;
2254 return n;
2255}
2256
2257// --------------------------------------------------------------------------
2258//
2259// Add all canvases to the MStatusArray
2260//
2261void MStatusDisplay::FillArray(MStatusArray &list, Int_t num) const
2262{
2263 Int_t from, to;
2264 GetCanvasRange(from, to, num);
2265
2266 TCanvas *c;
2267 for (int i=from; i<to; i++)
2268 if ((c = GetCanvas(i)))
2269 list.Add(c);
2270}
2271
2272// --------------------------------------------------------------------------
2273//
2274// Writes the contents of a MStatusDisplay to a file.
2275//
2276Int_t MStatusDisplay::Write(Int_t num, const char *name, Int_t /*option*/, Int_t /*bufsize*/) const
2277{
2278 if (!gFile)
2279 {
2280 *fLog << warn << "MStatusDisplay::Write: No file found. Please create a TFile first." << endl;
2281 return 0;
2282 }
2283
2284 if (!gFile->IsOpen())
2285 {
2286 *fLog << warn << "MStatusDisplay::Write: File not open. Please open the TFile first." << endl;
2287 return 0;
2288 }
2289
2290 if (!gFile->IsWritable())
2291 {
2292 *fLog << warn << "MStatusDisplay::Write: File not writable." << endl;
2293 return 0;
2294 }
2295
2296 if (num==0)
2297 {
2298 *fLog << warn << "MStatusDisplay::Write: Tab doesn't contain an embedded Canvas... skipped." << endl;
2299 return 0;
2300 }
2301
2302 if (!gROOT->IsBatch() && num>=fTab->GetNumberOfTabs())
2303 {
2304 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
2305 return 0;
2306 }
2307 if (gROOT->IsBatch() && num>fBatch->GetSize())
2308 {
2309 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
2310 return 0;
2311 }
2312
2313 MStatusArray list;
2314
2315 // Be careful: So far Display() assumes that it is the first entry in the list
2316 TNamed named;
2317 named.SetTitle(fTitle);
2318 list.Add(&named);
2319
2320 FillArray(list, num);
2321
2322 const Int_t n = list.Write(name, kSingleKey);
2323
2324 //*fLog << inf << "MStatusDisplay: " << n << " keys written to file as key " << name << "." << endl;
2325
2326 return n;
2327}
2328
2329// --------------------------------------------------------------------------
2330//
2331// Use this to start the synchronous (GUI eventloop driven) tab update.
2332// Can also be used to change the update intervall. If millisec<0
2333// the intervall given in SetUpdateTime is used. If the intervall in
2334// SetUpdateTime is <0 nothing is done. (Call SetUpdateTime(-1) to
2335// disable the automatic update in a MEventloop.
2336//
2337void MStatusDisplay::StartUpdate(Int_t millisec)
2338{
2339 if (fIsLocked>1)
2340 return;
2341
2342 if (fTimer.GetTime()<TTime(0))
2343 return;
2344 fTimer.Start(millisec);
2345}
2346
2347// --------------------------------------------------------------------------
2348//
2349// Stops the automatic GUI update
2350//
2351void MStatusDisplay::StopUpdate()
2352{
2353 if (fIsLocked>1)
2354 return;
2355
2356 fTimer.Stop();
2357}
2358
2359// --------------------------------------------------------------------------
2360//
2361// Set the update interval for the GUI update, see StartUpdate.
2362//
2363void MStatusDisplay::SetUpdateTime(Long_t t)
2364{
2365 fTimer.SetTime(t);
2366}
2367
2368// --------------------------------------------------------------------------
2369//
2370// If the filename name doesn't end with ext, ext is added to the end.
2371// If name.IsNull() "status" is assumed and the a number (>0) is added
2372// as "status-6".
2373// The extension is returned.
2374//
2375const TString &MStatusDisplay::AddExtension(TString &name, const TString &ext, Int_t num) const
2376{
2377 if (name.IsNull())
2378 {
2379 name = gROOT->GetName();
2380 if (num>0)
2381 {
2382 name += "-";
2383 name += num;
2384 }
2385 }
2386
2387 if (name.EndsWith("."+ext))
2388 return ext;
2389
2390 name += ".";
2391 name += ext;
2392
2393 return ext;
2394}
2395
2396Bool_t MStatusDisplay::CheckTabForCanvas(int num) const
2397{
2398 if (gROOT->IsBatch())
2399 return num>0 && num<=fBatch->GetSize() || num<0;
2400
2401 if (num>=fTab->GetNumberOfTabs())
2402 {
2403 *fLog << warn << "Tab #" << num << " doesn't exist..." << endl;
2404 return kFALSE;
2405 }
2406 if (num==0)
2407 {
2408 *fLog << warn << "Tab #" << num << " doesn't contain an embedded canvas..." << endl;
2409 return kFALSE;
2410 }
2411 if (fTab->GetNumberOfTabs()<2 || !gPad)
2412 {
2413 *fLog << warn << "Sorry, you must have at least one existing canvas (gPad!=NULL)" << endl;
2414 return kFALSE;
2415 }
2416 return kTRUE;
2417}
2418
2419// --------------------------------------------------------------------------
2420//
2421// Insert the following two lines into the postscript header:
2422//
2423// %%DocumentPaperSizes: a4
2424// %%Orientation: Landscape
2425//
2426void MStatusDisplay::UpdatePSHeader(const TString &name) const
2427{
2428 const TString newstr("%%DocumentPaperSizes: a4\n%%Orientation: Landscape\n");
2429
2430 TString tmp(name+"XXXXXX");
2431
2432 // FIXME: Use mkstemp instead
2433 if (!mktemp(const_cast<char*>(tmp.Data())))
2434 {
2435 *fLog << err << "ERROR - MStatusDisplay::UpdatePSHeader: mktemp failed." << endl;
2436 return;
2437 }
2438
2439 ifstream fin(name);
2440 ofstream fout(tmp);
2441 if (!fout)
2442 {
2443 *fLog << err << "Cannot open file " << name << ": " << strerror(errno) << endl;
2444 return;
2445 }
2446
2447 char c;
2448
2449 TString str;
2450 fin >> str >> c; // Read "%!PS-Adobe-2.0\n"
2451 fout << str << endl << newstr;
2452
2453 // Doing it in blocks seems not to gain much for small (MB) files
2454 while (fin)
2455 {
2456 fin.read(&c, 1);
2457 fout.write(&c, 1);
2458 }
2459
2460 gSystem->Unlink(name);
2461 gSystem->Rename(tmp, name);
2462}
2463
2464// --------------------------------------------------------------------------
2465//
2466void MStatusDisplay::PSToolsRange(TVirtualPS &vps, Float_t psw, Float_t psh) const
2467{
2468 if (vps.InheritsFrom(TPostScript::Class()))
2469 static_cast<TPostScript&>(vps).Range(psw, psh);
2470 // if (vps.InheritsFrom(TPDF::Class()))
2471 // static_cast<TPDF&>(vps).Range(psw*0.69, psh*0.69);
2472 // if (vps.InheritsFrom(TSVG::Class()))
2473 // static_cast<TSVG&>(vps).Range(psw, psh);
2474}
2475
2476// --------------------------------------------------------------------------
2477//
2478void MStatusDisplay::PSToolsTextNDC(TVirtualPS &vps, Double_t u, Double_t v, const char *string) const
2479{
2480 if (vps.InheritsFrom(TPostScript::Class()))
2481 static_cast<TPostScript&>(vps).TextNDC(u, v, string);
2482 if (vps.InheritsFrom(TPDF::Class()))
2483 static_cast<TPDF&>(vps).TextNDC(u, v, string);
2484 // if (vps.InheritsFrom(TSVG::Class()))
2485 // static_cast<TSVG&>(vps).TextNDC(u, v, string);
2486}
2487
2488// --------------------------------------------------------------------------
2489//
2490Int_t MStatusDisplay::InitWriteDisplay(Int_t num, TString &name, const TString &ext)
2491{
2492 SetStatusLine1(Form("Writing %s file...",ext.Data()));
2493 SetStatusLine2("Please be patient!");
2494
2495 if (!CheckTabForCanvas(num))
2496 {
2497 SetStatusLine2("Failed!");
2498 return 0;
2499 }
2500
2501 AddExtension(name, ext, num);
2502
2503 if (num<0)
2504 *fLog << inf << "Open " << ext << "-File: " << name << endl;
2505
2506 return num;
2507}
2508
2509// --------------------------------------------------------------------------
2510//
2511TCanvas *MStatusDisplay::InitWriteTab(Int_t num, TString &name)
2512{
2513 const Int_t i = TMath::Abs(num);
2514
2515 TCanvas *c = GetCanvas(i);
2516 if (!c)
2517 {
2518 if (num<0)
2519 *fLog << inf << " - ";
2520 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
2521 return 0;
2522 }
2523
2524 SetStatusLine2(MString::Format("Tab #%d", i));
2525
2526 //
2527 // Paint canvas into root file
2528 //
2529 if (num<0 && !name.IsNull())
2530 {
2531 Bool_t found = kFALSE;
2532 if (name.Index("%%%%name%%%%"))
2533 {
2534 name.ReplaceAll("%%name%%", c->GetName());
2535 found = kTRUE;
2536 }
2537
2538 if (name.Index("%%%%tab%%%%"))
2539 {
2540 name.ReplaceAll("%%tab%%", MString::Format("%d", i));
2541 found = kTRUE;
2542 }
2543
2544 if (!found)
2545 name.Insert(name.Last('.'), MString::Format("-%d", i));
2546 }
2547
2548 if (num<0)
2549 *fLog << inf << " - ";
2550 *fLog << inf << "Writing Tab #" << i;
2551
2552 if (!name.IsNull())
2553 *fLog << " to " << name;
2554
2555 *fLog << ": " << c->GetName() << "... " << flush;
2556
2557 return c;
2558}
2559
2560// This is a stupid workaround to get rid of the damned clipping
2561// of the text. Who the hell needs clipping?
2562class MyCanvas : public TCanvas
2563{
2564public:
2565 void Scale(Double_t val)
2566 {
2567 fAbsXlowNDC = -val;
2568 fAbsYlowNDC = -val;
2569 fAbsWNDC = 1+2*val;
2570 fAbsHNDC = 1+2*val;
2571 }
2572};
2573
2574// --------------------------------------------------------------------------
2575//
2576// Write some VGF (vector graphics format). Currently PS, PDF and SVG
2577// is available. Specified by ext.
2578//
2579// In case of num<0 all tabs are written into the VGF file. If num>0
2580// the canvas in the corresponding tab is written to the file.
2581// Name is the name of the file (with or without extension).
2582//
2583// Returns the number of pages written.
2584//
2585// To write all tabs you can also use SaveAsVGF(name, ext)
2586//
2587// If the third argument is given a bottom line is drawn with the text
2588// under it. If no argument is given a bottom line is drawn if
2589// fTitle (SetTitle) is not empty.
2590//
2591Int_t MStatusDisplay::SaveAsVGF(Int_t num, TString name, const TString addon, const TString ext)
2592{
2593 num = InitWriteDisplay(num, name, ext);
2594 if (num==0)
2595 return 0;
2596
2597 TPad *padsav = (TPad*)gPad;
2598 TVirtualPS *psave = gVirtualPS;
2599
2600 TDatime d;
2601
2602 Int_t type = -1;
2603
2604 TVirtualPS *ps =0;
2605 if (!ext.CompareTo("ps", TString::kIgnoreCase))
2606 {
2607 gStyle->SetColorModelPS(1);
2608 ps = new TPostScript(name, 112);
2609 type = 1;
2610 }
2611 if (!ext.CompareTo("pdf", TString::kIgnoreCase))
2612 {
2613 ps = new TPDF(name, 112);
2614 type = 2;
2615 }
2616 if (!ext.CompareTo("svg", TString::kIgnoreCase))
2617 {
2618 ps = new TSVG(name, 112);
2619 type = 3;
2620 }
2621
2622 if (!ps)
2623 {
2624 *fLog << err << "Extension " << ext << " unknown..." << endl;
2625 SetStatusLine2("Failed!");
2626 return 0;
2627 }
2628
2629 ps->SetBit(TPad::kPrintingPS);
2630 if (type==1)
2631 ps->PrintFast(13, "/nan {1} def ");
2632
2633 gVirtualPS = ps;
2634
2635 //
2636 // Create some GUI elements for a page legend
2637 //
2638 TLine line;
2639
2640 int page = 1;
2641
2642 //
2643 // Maintain tab numbers
2644 //
2645 Int_t from, to;
2646 GetCanvasRange(from, to, num);
2647
2648 for (int i=from; i<to; i++)
2649 {
2650 TCanvas *c = InitWriteTab(num<0?-i:i);
2651 if (c==0)
2652 continue;
2653
2654 //
2655 // Init page and page size, make sure, that the canvas in the file
2656 // has the same Aspect Ratio than on the screen.
2657 //
2658 if (type==1 || i>from)
2659 ps->NewPage();
2660
2661 //
2662 // 28 is used here to scale the canvas into a height of 28,
2663 // such that the page title can be set above the canvas...
2664 //
2665 Float_t psw = 28.0; // A4 - width (29.7)
2666 Float_t psh = 21.0; // A4 - height (21.0)
2667
2668 const Float_t cw = c->GetWw();
2669 const Float_t ch = c->GetWh();
2670
2671 if (psw/psh>cw/ch)
2672 psw = cw/ch*psh;
2673 else
2674 psh = ch/cw*psw;
2675
2676 PSToolsRange(*ps, psw, psh);
2677
2678 //
2679 // Clone canvas and change background color and schedule for
2680 // deletion
2681 //
2682 const Bool_t store = c->IsBatch();
2683
2684 c->SetBatch(kTRUE);
2685 c->Paint();
2686 c->SetBatch(store);
2687
2688 //
2689 // Use the canvas as coordinate system for the overlaying text
2690 //
2691 gPad = c;
2692 //n->cd();
2693
2694 const Double_t height = 0.015;
2695
2696 const Double_t off = 0.005;
2697 const Double_t bot = height+off;
2698 const Double_t top = 1-bot;
2699
2700 static_cast<MyCanvas*>(c)->Scale(bot);
2701
2702 // Separator Lines
2703 line.PaintLineNDC(0.01, top, 0.99, top);
2704 line.PaintLineNDC(0.01, bot, 0.99, bot);
2705
2706 //
2707 // Print overlaying text (NDC = %)
2708 //
2709 // align phi col font size (11=left top)
2710 const TString txt(addon.IsNull() ? fTitle : addon);
2711
2712 // Text Attributes
2713 TAttText(11, 0, kBlack, 22, height).Copy(*ps);
2714
2715 // Text on top
2716 ps->SetTextAlign(11); // left bottom
2717 PSToolsTextNDC(*ps, 0.01, top+off, c->GetName());
2718
2719 ps->SetTextAlign(21); // cent bottom
2720 PSToolsTextNDC(*ps, 0.50, top+off, TString("MARS V"MARSVER" - Modular Analysis and Reconstruction Software - ")+d.AsString());
2721
2722 ps->SetTextAlign(31); // right bottom
2723 PSToolsTextNDC(*ps, 0.99, top+off, MString::Format("Page No.%i (%i)", page++, i));
2724
2725 // Text on bottom
2726 ps->SetTextAlign(13); // left top
2727 PSToolsTextNDC(*ps, 0.01, bot-off, c->GetTitle());
2728
2729 ps->SetTextAlign(23); // cent top
2730 PSToolsTextNDC(*ps, 0.50, bot-off, txt);
2731
2732 ps->SetTextAlign(33); // right top
2733 PSToolsTextNDC(*ps, 0.99, bot-off, MString::Format("(c) 2000-%d, Thomas Bretz", TDatime().GetYear()));
2734
2735 static_cast<MyCanvas*>(c)->Scale(0);
2736
2737 //
2738 // Finish drawing page
2739 //
2740 *fLog << "done." << endl;
2741 }
2742
2743 gPad = NULL; // Important!
2744
2745 ps->Close();
2746 delete ps;
2747
2748#if ROOT_VERSION_CODE < ROOT_VERSION(5,12,00)
2749 if (type==1)
2750 {
2751 SetStatusLine2("Updating header of PS file...");
2752
2753 if (num<0)
2754 *fLog << inf3 << " - Updating header of PS file... " << flush;
2755 UpdatePSHeader(name);
2756 if (num<0)
2757 *fLog << inf3 << "done." << endl;
2758 }
2759#endif
2760
2761 gVirtualPS = psave;
2762 if (padsav)
2763 padsav->cd();
2764
2765 if (num<0)
2766 *fLog << inf << "done." << endl;
2767
2768 SetStatusLine2(MString::Format("Done (%dpages)", page-1));
2769
2770 return page-1;
2771}
2772
2773// --------------------------------------------------------------------------
2774//
2775Bool_t MStatusDisplay::SaveAsImage(Int_t num, TString name, TImage::EImageFileTypes type)
2776{
2777#if ROOT_VERSION_CODE < ROOT_VERSION(5,12,00)
2778 if (gROOT->IsBatch())
2779 {
2780 *fLog << warn << "Sorry, writing image-files is not available in batch mode." << endl;
2781 return 0;
2782 }
2783#endif
2784
2785 TString ext;
2786 switch (type)
2787 {
2788 case TImage::kXpm:
2789 case TImage::kZCompressedXpm: ext = "xpm"; break;
2790 case TImage::kPng: ext = "png"; break;
2791 case TImage::kJpeg: ext = "jpg"; break;
2792 case TImage::kGif: ext = "gif"; break;
2793 case TImage::kTiff: ext = "tiff"; break;
2794 case TImage::kBmp: ext = "bmp"; break;
2795 case TImage::kXml: ext = "xml"; break;
2796 //case TImage::kGZCompressedXpm: ext = "xpm.gz"; break;
2797 //case TImage::kPpm: ext = "ppm"; break;
2798 //case TImage::kPnm: ext = "pnm"; break;
2799 //case TImage::kIco: ext = "ico"; break;
2800 //case TImage::kCur: ext = "cur"; break;
2801 //case TImage::kXcf: ext = "xcf"; break;
2802 //case TImage::kXbm: ext = "xbm"; break;
2803 //case TImage::kFits: ext = "fits"; break;
2804 //case TImage::kTga: ext = "tga"; break;
2805 default:
2806 *fLog << warn << "Sorry, unknown or unsupported file type..." << endl;
2807 return 0;
2808 }
2809
2810 num = InitWriteDisplay(num, name, ext);
2811 if (num==0)
2812 return 0;
2813
2814 TPad *padsav = (TPad*)gPad;
2815
2816 Int_t counter = 0;
2817
2818 //
2819 // Maintain tab numbers
2820 //
2821 Int_t from, to;
2822 GetCanvasRange(from, to, num);
2823
2824 for (int i=from; i<to; i++)
2825 {
2826 TString writename(name);
2827
2828 TCanvas *c = InitWriteTab(num<0 ? -i : i, writename);
2829 if (!c)
2830 continue;
2831
2832 //
2833 // Paint canvas into root file
2834 //
2835
2836 // TImage *img = TImage::Create();
2837 // img->FromPad(c);
2838 // img->WriteImage(writename, type);
2839 // delete img;
2840
2841 // FIXME: Not all file types are supported by Print()
2842 c->Print(writename);
2843
2844 if (num<0)
2845 *fLog << "done." << endl;
2846
2847 counter++;
2848 }
2849
2850 if (padsav)
2851 padsav->cd();
2852
2853 *fLog << inf << "done." << endl;
2854
2855 SetStatusLine2("Done.");
2856
2857 return counter>0;
2858}
2859
2860// --------------------------------------------------------------------------
2861//
2862Bool_t MStatusDisplay::SaveAsC(Int_t num, TString name)
2863{
2864 num = InitWriteDisplay(num, name, "C");
2865 if (num==0)
2866 return kFALSE;
2867
2868 TPad *padsav = (TPad*)gPad;
2869
2870 Int_t counter = 0;
2871
2872 //
2873 // Maintain tab numbers
2874 //
2875 Int_t from, to;
2876 GetCanvasRange(from, to, num);
2877
2878 for (int i=from; i<to; i++)
2879 {
2880 TString writename(name);
2881
2882 TCanvas *c = InitWriteTab(num<0 ? -i : i, writename);
2883 if (!c)
2884 continue;
2885
2886 //
2887 // Clone canvas and change background color and schedule for
2888 // deletion
2889 //
2890 c->SaveSource(writename, "");
2891
2892 if (num<0)
2893 *fLog << "done." << endl;
2894
2895 counter++;
2896 }
2897
2898 if (padsav)
2899 padsav->cd();
2900
2901 *fLog << inf << "done." << endl;
2902
2903 SetStatusLine2("Done.");
2904
2905 return counter>0;
2906}
2907
2908// --------------------------------------------------------------------------
2909//
2910// In case of num<0 all tabs are written into the PS file. If num>0
2911// the canvas in the corresponding tab is written to the file.
2912// Name is the name of the file (with or without extension).
2913//
2914// Returns the number of keys written.
2915//
2916// To write all tabs you can also use SaveAsPS(name)
2917//
2918Int_t MStatusDisplay::SaveAsRoot(Int_t num, TString name)
2919{
2920 num = InitWriteDisplay(num, name, "root");
2921 if (num==0)
2922 return -1;
2923
2924 TFile *fsave = gFile;
2925 TFile file(name, "RECREATE", GetTitle(), 9);
2926 const Int_t keys = Write(num);
2927 gFile = fsave;
2928
2929 SetStatusLine2("Done.");
2930
2931 return keys;
2932}
2933
2934// --------------------------------------------------------------------------
2935//
2936Bool_t MStatusDisplay::SaveAsCSV(Int_t num, TString name, Char_t delim)
2937{
2938 num = InitWriteDisplay(num, name, "csv");
2939 if (num==0)
2940 return kFALSE;
2941
2942 ofstream fout(name);
2943 if (!fout)
2944 {
2945 *fLog << err << "Cannot open file " << name << ": " << strerror(errno) << endl;
2946 return kFALSE;
2947 }
2948
2949 fout << 0 << delim << GetName() << delim << GetTitle() << endl;
2950
2951 Int_t from, to;
2952 GetCanvasRange(from, to, num);
2953
2954 for (int i=from; i<to; i++)
2955 {
2956 TCanvas *c;
2957 if (!(c = GetCanvas(i)))
2958 {
2959 if (num<0)
2960 *fLog << inf << " - ";
2961 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
2962 continue;
2963 }
2964
2965 fout << i << delim << c->GetName() << delim << c->GetTitle() << endl;
2966 }
2967
2968 SetStatusLine2("Done.");
2969
2970 return kTRUE;
2971}
2972
2973// --------------------------------------------------------------------------
2974//
2975void MStatusDisplay::SaveAs(const char *c, const Option_t *o) const
2976{
2977#if ROOT_VERSION_CODE >= ROOT_VERSION(5,18,00)
2978 TGObject::SaveAs(c, o);
2979#endif
2980}
2981
2982// --------------------------------------------------------------------------
2983//
2984// Determin File type to save file as by extension. Allowed extensions are:
2985// root, ps, pdf, svg, gif, png, jpg, xpm, C
2986//
2987// returns -1 if file type is unknown. Otherwise return value of SaveAs*
2988//
2989Int_t MStatusDisplay::SaveAs(Int_t num, TString name)
2990{
2991 if (name.EndsWith(".root")) return SaveAsRoot(num, name); // kFileSaveAsRoot
2992 if (name.EndsWith(".ps")) return SaveAsPS(num, name); // kFileSaveAsPS
2993 if (name.EndsWith(".pdf")) return SaveAsPDF(num, name); // kFileSaveAsPDF
2994 if (name.EndsWith(".svg")) return SaveAsSVG(num, name); // kFileSaveAsSVG
2995 if (name.EndsWith(".gif")) return SaveAsGIF(num, name); // kFileSaveAsGIF
2996 if (name.EndsWith(".png")) return SaveAsPNG(num, name); // kFileSaveAsPNG
2997 if (name.EndsWith(".bmp")) return SaveAsBMP(num, name); // kFileSaveAsBMP
2998 if (name.EndsWith(".xml")) return SaveAsXML(num, name); // kFileSaveAsXML
2999 if (name.EndsWith(".jpg")) return SaveAsJPG(num, name); // kFileSaveAsJPG
3000 if (name.EndsWith(".xpm")) return SaveAsXPM(num, name); // kFileSaveAsXPM
3001 if (name.EndsWith(".csv")) return SaveAsCSV(num, name); // kFileSaveAsCSV
3002 if (name.EndsWith(".tiff")) return SaveAsTIFF(num, name); // kFileSaveAsTIFF
3003 if (name.EndsWith(".C")) return SaveAsC(num, name); // kFileSaveAsC
3004 return -1;
3005}
3006
3007// --------------------------------------------------------------------------
3008//
3009// Opens a save as dialog
3010//
3011Int_t MStatusDisplay::SaveAs(Int_t num)
3012{
3013 static const char *gSaveAsTypes[] =
3014 {
3015 "PostScript", "*.ps",
3016 "Acrobat pdf", "*.pdf",
3017 "SVG vector", "*.svg",
3018 "Gif files", "*.gif",
3019 "Png files", "*.png",
3020 "Gif files", "*.gif",
3021 "Jpeg files", "*.jpeg",
3022 "Xpm files", "*.xpm",
3023 "Bmp files", "*.bmp",
3024 "Xml files", "*.xml",
3025 "Tiff files", "*.tiff",
3026 "Csv files", "*.csv",
3027 "Macro files", "*.C",
3028 "ROOT files", "*.root",
3029 "All files", "*",
3030 NULL, NULL
3031 };
3032
3033 static TString dir(".");
3034
3035 TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
3036
3037 fi.fFileTypes = (const char**)gSaveAsTypes;
3038 fi.fIniDir = StrDup(dir);
3039
3040 new TGFileDialog(fClient->GetRoot(), this, kFDSave, &fi);
3041
3042 if (!fi.fFilename)
3043 return 0;
3044
3045 dir = fi.fIniDir;
3046
3047 const Int_t rc = SaveAs(num, fi.fFilename);
3048 if (rc>=0)
3049 return rc;
3050
3051 Warning("MStatusDisplay::SaveAs", "Unknown Extension: %s", fi.fFilename);
3052 return 0;
3053}
3054
3055// --------------------------------------------------------------------------
3056//
3057// Open contents of a MStatusDisplay with key name from file fname.
3058//
3059Int_t MStatusDisplay::Open(TString fname, const char *name)
3060{
3061 TFile file(fname, "READ");
3062 if (file.IsZombie())
3063 {
3064 gLog << warn << "WARNING - Cannot open file " << fname << endl;
3065 return 0;
3066 }
3067
3068 return Read(name);
3069}
3070
3071// --------------------------------------------------------------------------
3072//
3073// Opens an open dialog
3074//
3075Int_t MStatusDisplay::Open()
3076{
3077 static const char *gOpenTypes[] =
3078 {
3079 "ROOT files", "*.root",
3080 "All files", "*",
3081 NULL, NULL
3082 };
3083
3084 static TString dir(".");
3085
3086 TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
3087
3088 fi.fFileTypes = (const char**)gOpenTypes;
3089 fi.fIniDir = StrDup(dir);
3090
3091 new TGFileDialog(fClient->GetRoot(), this, kFDOpen, &fi);
3092
3093 if (!fi.fFilename)
3094 return 0;
3095
3096 dir = fi.fIniDir;
3097
3098 return Open(fi.fFilename);
3099}
3100
3101// --------------------------------------------------------------------------
3102//
3103// Change width of display. The height is calculated accordingly.
3104//
3105void MStatusDisplay::SetDisplayWidth(UInt_t dw)
3106{
3107 if (gROOT->IsBatch())
3108 {
3109 SetCanvasWidth(dw);
3110 return;
3111 }
3112
3113 // 4 == 2*default border with of canvas
3114 dw -= 4;
3115
3116 // Difference between canvas size and display size
3117 const UInt_t cw = GetWidth() -fTab->GetWidth();
3118 const UInt_t ch = GetHeight()-fTab->GetHeight()+fTab->GetTabHeight();
3119
3120 const UInt_t dh = TMath::Nint((dw - cw)/1.5 + ch);
3121
3122 Resize(dw, dh); // Set display size
3123}
3124
3125// --------------------------------------------------------------------------
3126//
3127// Change height of display. The width is calculated accordingly.
3128//
3129void MStatusDisplay::SetDisplayHeight(UInt_t dh)
3130{
3131 if (gROOT->IsBatch())
3132 {
3133 SetCanvasHeight(dh);
3134 return;
3135 }
3136
3137 // 4 == 2*default border with of canvas
3138 dh -= 4;
3139
3140 // Difference between canvas size and display size
3141 const UInt_t cw = GetWidth() -fTab->GetWidth();
3142 const UInt_t ch = GetHeight()-fTab->GetHeight()+fTab->GetTabHeight();
3143
3144 const UInt_t dw = TMath::Nint((dh - ch)*1.5 + cw);
3145
3146 Resize(dw, dh); // Set display size
3147}
3148
3149// --------------------------------------------------------------------------
3150//
3151// Change width of canvas. The height is calculated accordingly.
3152//
3153void MStatusDisplay::SetCanvasWidth(UInt_t w)
3154{
3155 // 4 == 2*default border with of canvas
3156 w += 4;
3157
3158 if (gROOT->IsBatch())
3159 {
3160 Resize(w, 3*w/2);
3161 return;
3162 }
3163
3164 // Difference between canvas size and display size
3165 const UInt_t cw = GetWidth() -fTab->GetWidth();
3166 const UInt_t ch = GetHeight()-fTab->GetHeight()+fTab->GetTabHeight();
3167
3168 const UInt_t h = TMath::Nint(w/1.5 + ch);
3169
3170 Resize(w + cw, h); // Set display size
3171}
3172
3173// --------------------------------------------------------------------------
3174//
3175// Change height of canvas. The width is calculated accordingly.
3176//
3177void MStatusDisplay::SetCanvasHeight(UInt_t h)
3178{
3179 // 4 == 2*default border with of canvas
3180 h += 4;
3181
3182 if (gROOT->IsBatch())
3183 {
3184 Resize(2*h/3, h);
3185 return;
3186 }
3187
3188 // Difference between canvas size and display size
3189 const UInt_t cw = GetWidth() -fTab->GetWidth();
3190 const UInt_t ch = GetHeight()-fTab->GetHeight()+fTab->GetTabHeight();
3191
3192 // 4 == 2*default border with of canvas
3193 const UInt_t dw = TMath::Nint((h+4)*1.5 + cw);
3194
3195 Resize(dw, h + ch); // Set display size
3196}
3197
3198// --------------------------------------------------------------------------
3199//
3200// Calculate width and height of the display such that it fits into the
3201// defined box.
3202//
3203void MStatusDisplay::SetDisplaySize(UInt_t w, UInt_t h)
3204{
3205 if (gROOT->IsBatch())
3206 return;
3207
3208 SetDisplayHeight(h);
3209
3210 if (GetWidth()>w)
3211 SetDisplayWidth(w);
3212}
3213
3214// --------------------------------------------------------------------------
3215//
3216// Calculate an optimum size for the display from the desktop size
3217//
3218void MStatusDisplay::SetOptimumSize()
3219{
3220 if (gROOT->IsBatch())
3221 return;
3222
3223 const UInt_t w = TMath::Nint(0.95*gClient->GetDisplayWidth());
3224 const UInt_t h = TMath::Nint(0.95*gClient->GetDisplayHeight());
3225
3226 SetDisplaySize(w, h);
3227}
3228
3229
3230Bool_t MStatusDisplay::HandleConfigureNotify(Event_t *evt)
3231{
3232 //
3233 // The initialization of the GUI is not yet enough finished...
3234 //
3235 if (!fTab)
3236 return kTRUE;
3237
3238 UInt_t w = evt->fWidth;
3239 UInt_t h = evt->fHeight;
3240
3241 const Bool_t wchanged = w!=GetWidth()-fTab->GetWidth();
3242 const Bool_t hchanged = h!=GetHeight()-fTab->GetHeight();
3243
3244 if (!wchanged && !hchanged)
3245 {
3246 Layout();
3247 // FIXME: Make sure that this doesn't result in endless loops.
3248 return kTRUE;
3249 }
3250
3251 if (GetWidth()==1 && GetHeight()==1)
3252 return kTRUE;
3253
3254 // calculate the constant part of the window
3255 const UInt_t cw = GetWidth() -fTab->GetWidth();
3256 const UInt_t ch = GetHeight()-fTab->GetHeight()+fTab->GetTabHeight();
3257
3258 // calculate new size of frame (canvas @ 2:3)
3259 if (hchanged)
3260 w = TMath::Nint((h-ch)*1.5+cw);
3261 else
3262 h = TMath::Nint((w-cw)/1.5+ch);
3263
3264 // resize frame
3265 Resize(w, h);
3266
3267 return kTRUE;
3268}
3269
3270Bool_t MStatusDisplay::HandleEvent(Event_t *event)
3271{
3272 // Instead of doing this in CloseWindow (called from HandleEvent)
3273 // we do it here. This makes sure, that handle event doesn't
3274 // execute code after deleting this.
3275 if (event->fType==kDestroyNotify)
3276 {
3277 if (Close())
3278 delete this;
3279// Close();
3280 return kTRUE;
3281 }
3282
3283 const Bool_t rc = TGMainFrame::HandleEvent(event);
3284
3285 //
3286 // This fixes a bug in older root versions which makes
3287 // TCanvas crash if gPad==NULL. So we make sure, that
3288 // gPad!=NULL -- be carfull, this may have other side
3289 // effects.
3290 //
3291#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
3292 if (!gPad && fTab)
3293 for (int i=0; i<fTab->GetNumberOfTabs(); i++)
3294 {
3295 TCanvas *c = GetCanvas(i);
3296 if (c)
3297 {
3298 c->cd();
3299 gLog << dbg << "MStatusDisplay::HandleEvent - Workaround: gPad=" << gPad << "." << endl;
3300 break;
3301 }
3302 }
3303#endif
3304
3305 return rc;
3306}
Note: See TracBrowser for help on using the repository browser.