source: tags/Mars-V2.1.1/mbase/MStatusDisplay.cc

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