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

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