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

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