source: trunk/Mars/mbase/MStatusDisplay.cc@ 17205

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