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

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