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

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