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

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