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

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