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

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