source: tags/Mars-V0.10.3/mbase/MStatusDisplay.cc

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