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

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