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

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