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

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