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

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