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

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