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

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