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

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