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

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