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

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