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

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