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

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