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

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