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

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