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

Last change on this file since 5250 was 4766, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 66.4 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 }
1494 fStatus = kFileExit;
1495 //gLog << dbg << fName << ".fStatus=kFileExit;" << endl;
1496}
1497
1498// --------------------------------------------------------------------------
1499//
1500// Calls SetBit(kNoContextMenu) for all TCanvas objects found in the
1501// Tabs.
1502//
1503void MStatusDisplay::SetNoContextMenu(Bool_t flag)
1504{
1505 if (fIsLocked>1 || gROOT->IsBatch())
1506 return;
1507
1508 flag ? SetBit(kNoContextMenu) : ResetBit(kNoContextMenu);
1509
1510 for (int i=1; i<fTab->GetNumberOfTabs(); i++)
1511 {
1512 TCanvas *c = GetCanvas(i);
1513 if (c)
1514 flag ? c->SetBit(kNoContextMenu) : c->ResetBit(kNoContextMenu);
1515 }
1516}
1517
1518// --------------------------------------------------------------------------
1519//
1520// Updates the canvas (if existing) in the currenly displayed Tab.
1521// The update intervall is controlled by StartUpdate and StopUpdate
1522//
1523Bool_t MStatusDisplay::HandleTimer(TTimer *timer)
1524{
1525 if (gROOT->IsBatch())
1526 return kTRUE;
1527
1528 const Int_t c = fTab->GetCurrent();
1529
1530 // Skip Legend Tab
1531 if (c==0)
1532 return kTRUE;
1533
1534 // Update a canvas tab (if visible)
1535 if (timer==&fTimer && c!=fLogIdx)
1536 {
1537 UpdateTab(fTab->GetCurrentContainer());
1538 return kTRUE;
1539 }
1540
1541 // update the logbook tab (if visible)
1542 if (timer==&fLogTimer && c==fLogIdx)
1543 {
1544 fLog->UpdateGui();
1545
1546 /*
1547 if (!fLogBox->TestBit(kHasChanged))
1548 return kTRUE;
1549
1550 fLogBox->ResetBit(kHasChanged);
1551 */
1552 return kTRUE;
1553 }
1554
1555 return kTRUE;
1556}
1557
1558// --------------------------------------------------------------------------
1559//
1560// Draws a clone of a canvas into a new canvas. Taken from TCanvas.
1561//
1562void MStatusDisplay::DrawClonePad(TCanvas &newc, const TCanvas &oldc) const
1563{
1564 //copy pad attributes
1565 newc.Range(oldc.GetX1(),oldc.GetY1(),oldc.GetX2(),oldc.GetY2());
1566 newc.SetTickx(oldc.GetTickx());
1567 newc.SetTicky(oldc.GetTicky());
1568 newc.SetGridx(oldc.GetGridx());
1569 newc.SetGridy(oldc.GetGridy());
1570 newc.SetLogx(oldc.GetLogx());
1571 newc.SetLogy(oldc.GetLogy());
1572 newc.SetLogz(oldc.GetLogz());
1573 newc.SetBorderSize(oldc.GetBorderSize());
1574 newc.SetBorderMode(oldc.GetBorderMode());
1575 ((TAttLine&)oldc).Copy((TAttLine&)newc);
1576 ((TAttFill&)oldc).Copy((TAttFill&)newc);
1577 ((TAttPad&)oldc).Copy((TAttPad&)newc);
1578
1579 //copy primitives
1580 TObject *obj;
1581 TIter next(oldc.GetListOfPrimitives());
1582 while ((obj=next())) {
1583 gROOT->SetSelectedPad(&newc);
1584 newc.GetListOfPrimitives()->Add(obj->Clone(),obj->GetDrawOption());
1585 }
1586 newc.Modified();
1587 newc.Update();
1588}
1589
1590Bool_t MStatusDisplay::Display(const TObjArray &list)
1591{
1592 TIter Next(&list);
1593
1594 TObject *o=Next();
1595 if (!o)
1596 {
1597 *fLog << err << "MStatusDisplay::Display: No entry in TObjArray." << endl;
1598 return kFALSE;
1599 }
1600
1601 fTitle = o->GetTitle();
1602
1603 TCanvas *c;
1604 while ((c=(TCanvas*)Next()))
1605 if (!GetCanvas(c->GetName()))
1606 DrawClonePad(AddTab(c->GetName()), *c);
1607
1608 return kTRUE;
1609}
1610
1611// --------------------------------------------------------------------------
1612//
1613// Reads the contents of a saved MStatusDisplay from a file.
1614//
1615Int_t MStatusDisplay::Read(const char *name)
1616{
1617 if (!gFile)
1618 {
1619 *fLog << warn << "MStatusDisplay::Read: No file found. Please create a TFile first." << endl;
1620 return 0;
1621 }
1622
1623 if (!gFile->IsOpen())
1624 {
1625 *fLog << warn << "MStatusDisplay::Read: File not open. Please open the TFile first." << endl;
1626 return 0;
1627 }
1628
1629 MStatusArray list;
1630
1631 const Int_t n = list.Read(name);
1632 if (n==0)
1633 {
1634 *fLog << warn << "MStatusDisplay::Read: No objects read." << endl;
1635 return 0;
1636 }
1637
1638 if (!Display(list))
1639 {
1640 *fLog << err << "MStatusDisplay::Display: No entry in " << name << "." << endl;
1641 return 0;
1642 }
1643
1644 *fLog << inf << "MStatusDisplay: Key " << name << " with " << n << " keys read from file." << endl;
1645
1646 return n;
1647}
1648
1649// --------------------------------------------------------------------------
1650//
1651// Writes the contents of a MStatusDisplay to a file.
1652//
1653Int_t MStatusDisplay::Write(Int_t num, const char *name, Int_t option, Int_t bufsize)
1654{
1655 if (!gFile)
1656 {
1657 *fLog << warn << "MStatusDisplay::Write: No file found. Please create a TFile first." << endl;
1658 return 0;
1659 }
1660
1661 if (!gFile->IsOpen())
1662 {
1663 *fLog << warn << "MStatusDisplay::Write: File not open. Please open the TFile first." << endl;
1664 return 0;
1665 }
1666
1667 if (!gFile->IsWritable())
1668 {
1669 *fLog << warn << "MStatusDisplay::Write: File not writable." << endl;
1670 return 0;
1671 }
1672
1673 if (num==0)
1674 {
1675 *fLog << warn << "MStatusDisplay::Write: Tab doesn't contain an embedded Canvas... skipped." << endl;
1676 return 0;
1677 }
1678
1679 if (!gROOT->IsBatch() && num>=fTab->GetNumberOfTabs())
1680 {
1681 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
1682 return 0;
1683 }
1684 if (gROOT->IsBatch() && num>fBatch->GetSize())
1685 {
1686 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
1687 return 0;
1688 }
1689
1690 MStatusArray list;
1691
1692 TNamed named;
1693 named.SetTitle(fTitle);
1694 list.Add(&named);
1695
1696 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
1697 const Int_t from = num<0 ? 1 : num;
1698 const Int_t to = num<0 ? max : num+1;
1699
1700 TCanvas *c;
1701 for (int i=from; i<to; i++)
1702 if ((c = GetCanvas(i)))
1703 list.Add(c);
1704
1705 const Int_t n = list.Write(name, kSingleKey);
1706
1707 *fLog << inf << "MStatusDisplay: " << n << " keys written to file as key " << name << "." << endl;
1708
1709 return n;
1710}
1711
1712// --------------------------------------------------------------------------
1713//
1714// Use this to start the synchronous (GUI eventloop driven) tab update.
1715// Can also be used to change the update intervall. If millisec<0
1716// the intervall given in SetUpdateTime is used. If the intervall in
1717// SetUpdateTime is <0 nothing is done. (Call SetUpdateTime(-1) to
1718// disable the automatic update in a MEventloop.
1719//
1720void MStatusDisplay::StartUpdate(Int_t millisec)
1721{
1722 if (fIsLocked>1)
1723 return;
1724
1725 if (fTimer.GetTime()<TTime(0))
1726 return;
1727 fTimer.Start(millisec);
1728}
1729
1730// --------------------------------------------------------------------------
1731//
1732// Stops the automatic GUI update
1733//
1734void MStatusDisplay::StopUpdate()
1735{
1736 if (fIsLocked>1)
1737 return;
1738
1739 fTimer.Stop();
1740}
1741
1742// --------------------------------------------------------------------------
1743//
1744// Set the update interval for the GUI update, see StartUpdate.
1745//
1746void MStatusDisplay::SetUpdateTime(Long_t t)
1747{
1748 fTimer.SetTime(t);
1749}
1750
1751// --------------------------------------------------------------------------
1752//
1753// Set the background color in a canvas
1754//
1755void MStatusDisplay::CanvasSetFillColor(TPad &p, Int_t col) const
1756{
1757 TObject *obj;
1758
1759 // See also TPad::UseCurrentStyle
1760 TIter Next(p.GetListOfPrimitives());
1761 while ((obj=Next()))
1762 {
1763 if (obj->InheritsFrom(TPad::Class()))
1764 CanvasSetFillColor(*(TPad*)obj, col);
1765 if (obj->InheritsFrom(TFrame::Class()))
1766 ((TFrame*)obj)->SetFillColor(col);
1767 }
1768
1769 p.SetFillColor(col);
1770}
1771
1772void MStatusDisplay::AddExtension(TString &name, const TString &ext, Int_t num) const
1773{
1774 if (name.IsNull())
1775 {
1776 name = "status";
1777 if (num>0)
1778 {
1779 name += "-";
1780 name += num;
1781 }
1782 }
1783
1784 if (name.EndsWith("."+ext))
1785 return;
1786
1787 name += ".";
1788 name += ext;
1789}
1790
1791Bool_t MStatusDisplay::CheckTabForCanvas(int num) const
1792{
1793 if (gROOT->IsBatch())
1794 return num>0 && num<=fBatch->GetSize() || num<0;
1795
1796 if (num>=fTab->GetNumberOfTabs())
1797 {
1798 *fLog << warn << "Tab #" << num << " doesn't exist..." << endl;
1799 return kFALSE;
1800 }
1801 if (num==0)
1802 {
1803 *fLog << warn << "Tab #" << num << " doesn't contain an embedded canvas..." << endl;
1804 return kFALSE;
1805 }
1806 if (fTab->GetNumberOfTabs()<2 || !gPad)
1807 {
1808 *fLog << warn << "Sorry, you must have at least one existing canvas (gPad!=NULL)" << endl;
1809 return kFALSE;
1810 }
1811 return kTRUE;
1812}
1813
1814// --------------------------------------------------------------------------
1815//
1816// Insert the following two lines into the postscript header:
1817//
1818// %%DocumentPaperSizes: a4
1819// %%Orientation: Landscape
1820//
1821void MStatusDisplay::UpdatePSHeader(const TString &name) const
1822{
1823 const TString newstr("%%DocumentPaperSizes: a4\n%%Orientation: Landscape\n");
1824
1825 ifstream fin(name);
1826 ofstream fout(name+".$$$");
1827
1828 char c;
1829
1830 TString str;
1831 fin >> str >> c; // Read "%!PS-Adobe-2.0\n"
1832 fout << str << endl << newstr;
1833
1834 // Doing it in blocks seems not to gain much for small (MB) files
1835 while (fin)
1836 {
1837 fin.read(&c, 1);
1838 fout.write(&c, 1);
1839 }
1840
1841 gSystem->Unlink(name);
1842 gSystem->Rename(name+".$$$", name);
1843/*
1844 //
1845 // Old style algorithm. Shifts blocks inside a single file --- SLOW!
1846 //
1847 const Int_t l = newstr.Length();
1848
1849 Long_t t[4]; // { id, size, flags, modtime }
1850 gSystem->GetPathInfo(name, t, t+1, t+2, t+3);
1851
1852 char *c[2] = { new char[l], new char[l] };
1853
1854 fstream f(name, ios::in|ios::out);
1855
1856 TString str;
1857 f >> str >> c[0][0]; // Read "%!PS-Adobe-2.0\n" (Mini Header)
1858 f.read(c[0], l);
1859 f.seekp(-l, ios::cur);
1860 f.write(newstr, l);
1861
1862 int i=0;
1863 while (1)
1864 {
1865 f.read(c[(i+1)%2], l);
1866 f.seekp(-l, ios::cur);
1867
1868 if (f)
1869 {
1870 f.write(c[i%2],l);
1871 i++;
1872 i%=2;
1873 continue;
1874 }
1875
1876 const Int_t ssz = str.Length()+1; // Length of Mini-Header
1877 const Int_t block = t[1]-ssz; // Length of block to be shifted
1878 const Int_t size = block%l; // Reminder
1879 const Int_t pos = (block/l)*l + ssz + 1; // Position to start writing
1880
1881 f.clear();
1882 f.seekp(pos);
1883 f.write(c[i%2], l);
1884 f.write(c[(i+1)%2], size);
1885 break;
1886 }
1887
1888 delete c[1];
1889 delete c[0];
1890*/
1891}
1892
1893// --------------------------------------------------------------------------
1894//
1895// In case of num<0 all tabs are written into the PS file. If num>0
1896// the canvas in the corresponding tab is written to the file.
1897// Name is the name of the file (with or without extension).
1898//
1899// Returns the number of pages written.
1900//
1901// To write all tabs you can also use SaveAsPS(name)
1902//
1903// If the third argument is given a bottom line is drawn with the text
1904// under it. If no argument is given a bottom line is drawn if
1905// fTitle (SetTitle) is not empty.
1906//
1907Int_t MStatusDisplay::SaveAsPS(Int_t num, TString name, const TString addon)
1908{
1909 SetStatusLine1("Writing Postscript file...");
1910 SetStatusLine2("");
1911
1912 if (!CheckTabForCanvas(num))
1913 {
1914 SetStatusLine2("Failed!");
1915 return 0;
1916 }
1917
1918 AddExtension(name, "ps", num);
1919
1920 if (num<0)
1921 *fLog << inf << "Open ps-File: " << name << endl;
1922
1923 TPad *padsav = (TPad*)gPad;
1924 TVirtualPS *psave = gVirtualPS;
1925
1926 TDatime d;
1927
1928 TPostScript ps(name, 112);
1929 ps.SetBit(TPad::kPrintingPS);
1930 ps.PrintFast(13, "/nan {1} def ");
1931
1932 gVirtualPS = &ps;
1933
1934 //
1935 // Create a list to delete the canvas clones
1936 //
1937 TList l;
1938 l.SetOwner();
1939
1940 //
1941 // Create some GUI elements for a page legend
1942 //
1943 TLine line;
1944
1945 int page = 1;
1946
1947 //
1948 // Maintain tab numbers
1949 //
1950 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
1951 const Int_t from = num<0 ? 1 : num;
1952 const Int_t to = num<0 ? max : num+1;
1953
1954 for (int i=from; i<to; i++)
1955 {
1956 TCanvas *c;
1957 if (!(c = GetCanvas(i)))
1958 {
1959 if (num<0)
1960 *fLog << inf << " - ";
1961 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
1962 continue;
1963 }
1964
1965 SetStatusLine2(Form("Tab #%d", i));
1966
1967 //
1968 // Init page and page size, make sure, that the canvas in the file
1969 // has the same Aspect Ratio than on the screen.
1970 //
1971 ps.NewPage();
1972
1973 //
1974 // 28 is used here to scale the canvas into a height of 28,
1975 // such that the page title can be set above the canvas...
1976 //
1977 Float_t psw = 28.0; // A4 - width (29.7)
1978 Float_t psh = 21.0; // A4 - height (21.0)
1979
1980 const Float_t cw = c->GetWw();
1981 const Float_t ch = c->GetWh();
1982
1983 if (psw/psh>cw/ch)
1984 psw = cw/ch*psh;
1985 else
1986 psh = ch/cw*psw;
1987
1988 ps.Range(psw, psh); // A4
1989
1990 //
1991 // Clone canvas and change background color and schedule for
1992 // deletion
1993 //
1994 TCanvas *n = (TCanvas*)c->Clone();
1995 CanvasSetFillColor(*n, kWhite);
1996 l.Add(n);
1997
1998 //
1999 // Paint canvas into root file
2000 //
2001 if (num<0)
2002 *fLog << inf << " - ";
2003 *fLog << inf << "Writing Tab #" << i << ": " << c->GetName() << " (" << c << ") ";
2004 if (num>0)
2005 *fLog << "to " << name;
2006 *fLog << "... " << flush;
2007
2008 n->SetBatch(kTRUE);
2009 n->Paint();
2010
2011 //
2012 // Use the canvas as coordinate system for the overlaying text
2013 //
2014 gPad = n;
2015 //n->cd();
2016
2017 //
2018 // Print overlaying text (NDC = %)
2019 //
2020 ps.SetTextColor(kBlack);
2021 ps.SetTextSize(0.015);
2022 ps.SetTextFont(22);
2023 ps.SetTextAlign(11); // left top
2024 ps.TextNDC(0, 1.015, TString(" ")+n->GetName());
2025 ps.SetTextAlign(21); // cent top
2026 ps.TextNDC(0.5, 1.015, TString("MARS - Magic Analysis and Reconstruction Software - ")+d.AsString());
2027 ps.SetTextAlign(31); // right top
2028 ps.TextNDC(1, 1.015, Form("Page No.%i (%i) ", page++, i));
2029 line.PaintLineNDC(0, 1.01, 1, 1.01);
2030
2031 TString txt(addon.IsNull() ? fTitle : addon);
2032 if (!txt.IsNull())
2033 {
2034 line.PaintLineNDC(0, -0.00, 1, -0.00);
2035 ps.SetTextAlign(11); // left top
2036 ps.TextNDC(0, -0.015, TString(" ")+txt);
2037 ps.SetTextAlign(31); // right top
2038 ps.TextNDC(1, -0.015, "(c) 2000-2004, Thomas Bretz ");
2039 }
2040
2041 //
2042 // Finish drawing page
2043 //
2044 n->SetBatch(kFALSE);
2045 *fLog << "done." << endl;
2046 }
2047
2048 gPad = NULL; // Important!
2049 l.Delete();
2050
2051 ps.Close();
2052
2053 SetStatusLine2("Updating header of PS file...");
2054
2055 if (num<0)
2056 *fLog << " - Updating header of PS file... " << flush;
2057 UpdatePSHeader(name);
2058 if (num<0)
2059 *fLog << inf << "done." << endl;
2060
2061 gVirtualPS = psave;
2062 if (padsav)
2063 padsav->cd();
2064
2065 if (num<0)
2066 *fLog << inf << "done." << endl;
2067
2068 SetStatusLine2(Form("Done (%dpages)", page-1));
2069
2070 return page-1;
2071}
2072
2073Bool_t MStatusDisplay::SaveAsGIF(Int_t num, TString name)
2074{
2075 if (gROOT->IsBatch())
2076 {
2077 *fLog << warn << "Sorry, writing gif-files is not available in batch mode." << endl;
2078 return 0;
2079 }
2080 SetStatusLine1("Writing GIF file...");
2081 SetStatusLine2("");
2082
2083 if (!CheckTabForCanvas(num))
2084 {
2085 SetStatusLine2("Failed!");
2086 return 0;
2087 }
2088
2089 AddExtension(name, "gif", num);
2090
2091 if (num<0)
2092 *fLog << inf << "Writing gif-Files..." << endl;
2093
2094 TPad *padsav = (TPad*)gPad;
2095
2096 int page = 1;
2097
2098 //
2099 // Maintain tab numbers
2100 //
2101 const Int_t from = num<0 ? 1 : num;
2102 const Int_t to = num<0 ? fTab->GetNumberOfTabs() : num+1;
2103
2104 for (int i=from; i<to; i++)
2105 {
2106 TCanvas *c;
2107 if (!(c = GetCanvas(i)))
2108 {
2109 if (num<0)
2110 *fLog << inf << " - ";
2111 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
2112 continue;
2113 }
2114
2115 SetStatusLine2(Form("Tab #%d", i));
2116
2117 //
2118 // Clone canvas and change background color and schedule for
2119 // deletion
2120 //
2121 //TCanvas *n = (TCanvas*)c->Clone();
2122 //CanvasSetFillColor(*n, kWhite);
2123
2124 //
2125 // Paint canvas into root file
2126 //
2127 TString writename = name;
2128 if (num<0)
2129 {
2130 TString numname = "-";
2131 numname += i;
2132 writename.Insert(name.Last('.'), numname);
2133 }
2134 if (num<0)
2135 *fLog << inf << " - ";
2136 *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << c << ") ";
2137 if (num>0)
2138 *fLog << "to " << name;
2139 *fLog << "..." << flush;
2140
2141 c->Draw();
2142 c->SaveAs(writename);
2143 /*
2144 n->Draw();
2145 n->SaveAs(writename);
2146 delete n;
2147 */
2148
2149 if (num<0)
2150 *fLog << "done." << endl;
2151 }
2152
2153 padsav->cd();
2154
2155 *fLog << inf << "done." << endl;
2156
2157 SetStatusLine2("Done.");
2158
2159 return page-1;
2160}
2161
2162Bool_t MStatusDisplay::SaveAsC(Int_t num, TString name)
2163{
2164 SetStatusLine1("Writing C++ file...");
2165 SetStatusLine2("");
2166
2167 if (!CheckTabForCanvas(num))
2168 {
2169 SetStatusLine2("Failed!");
2170 return 0;
2171 }
2172
2173 AddExtension(name, "C", num);
2174
2175 if (num<0)
2176 *fLog << inf << "Writing C-Files..." << endl;
2177
2178 TPad *padsav = (TPad*)gPad;
2179
2180 int page = 1;
2181
2182 //
2183 // Maintain tab numbers
2184 //
2185 const Int_t from = num<0 ? 1 : num;
2186 const Int_t to = num<0 ? fTab->GetNumberOfTabs() : num+1;
2187
2188 for (int i=from; i<to; i++)
2189 {
2190 TCanvas *c;
2191 if (!(c = GetCanvas(i)))
2192 {
2193 if (num<0)
2194 *fLog << inf << " - ";
2195 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
2196 continue;
2197 }
2198
2199 SetStatusLine2(Form("Tab #%d", i));
2200
2201 //
2202 // Clone canvas and change background color and schedule for
2203 // deletion
2204 //
2205 TCanvas *n = (TCanvas*)c->Clone();
2206 CanvasSetFillColor(*n, kWhite);
2207
2208 //
2209 // Paint canvas into root file
2210 //
2211 TString writename = name;
2212 if (num<0)
2213 {
2214 TString numname = "-";
2215 numname += i;
2216 writename.Insert(name.Last('.'), numname);
2217 }
2218 if (num<0)
2219 *fLog << inf << " - ";
2220 *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << n << ") ";
2221 if (num>0)
2222 *fLog << "to " << name;
2223 *fLog << "..." << flush;
2224
2225 n->SaveSource(writename, "");
2226 delete n;
2227
2228 if (num<0)
2229 *fLog << "done." << endl;
2230 }
2231
2232 padsav->cd();
2233
2234 *fLog << inf << "done." << endl;
2235
2236 SetStatusLine2("Done.");
2237
2238 return page-1;
2239}
2240
2241// --------------------------------------------------------------------------
2242//
2243// In case of num<0 all tabs are written into the PS file. If num>0
2244// the canvas in the corresponding tab is written to the file.
2245// Name is the name of the file (with or without extension).
2246//
2247// Returns the number of keys written.
2248//
2249// To write all tabs you can also use SaveAsPS(name)
2250//
2251Int_t MStatusDisplay::SaveAsRoot(Int_t num, TString name)
2252{
2253 SetStatusLine1("Writing root file...");
2254 SetStatusLine2("");
2255
2256 if (!CheckTabForCanvas(num))
2257 {
2258 SetStatusLine2("Failed!");
2259 return 0;
2260 }
2261
2262 AddExtension(name, "root", num);
2263
2264 TFile *fsave = gFile;
2265 TFile file(name, "RECREATE", "MARS - Status Window Contents", 9);
2266 const Int_t keys = Write(num);
2267 gFile = fsave;
2268
2269 SetStatusLine2("Done.");
2270
2271 return keys;
2272}
2273
2274// --------------------------------------------------------------------------
2275//
2276// Opens a save as dialog
2277//
2278Int_t MStatusDisplay::SaveAs(Int_t num)
2279{
2280 static const char *gSaveAsTypes[] =
2281 {
2282 "PostScript", "*.ps",
2283 "Gif files", "*.gif",
2284 "Macro files", "*.C",
2285 "ROOT files", "*.root",
2286 "All files", "*",
2287 NULL, NULL
2288 };
2289
2290 static TString dir(".");
2291
2292 TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
2293
2294 fi.fFileTypes = (const char**)gSaveAsTypes;
2295 fi.fIniDir = StrDup(dir);
2296
2297 new TGFileDialog(fClient->GetRoot(), this, kFDSave, &fi);
2298
2299 if (!fi.fFilename)
2300 return 0;
2301
2302 dir = fi.fIniDir;
2303
2304 const TString name(fi.fFilename);
2305
2306 if (name.EndsWith(".root")) return SaveAsRoot(num, name);
2307 if (name.EndsWith(".ps")) return SaveAsPS(num, name);
2308 if (name.EndsWith(".gif")) return SaveAsGIF(num, name);
2309 if (name.EndsWith(".C")) return SaveAsC(num, name);
2310
2311 Warning("MStatusDisplay::SaveAs", "Unknown Extension: %s", fi.fFilename);
2312 return 0;
2313}
2314
2315// --------------------------------------------------------------------------
2316//
2317// Open contents of a MStatusDisplay with key name from file fname.
2318//
2319Int_t MStatusDisplay::Open(TString fname, const char *name)
2320{
2321 TFile file(fname, "READ");
2322 if (file.IsZombie())
2323 {
2324 gLog << warn << "WARNING - Cannot open file " << fname << endl;
2325 return 0;
2326 }
2327
2328 return Read(name);
2329}
2330
2331// --------------------------------------------------------------------------
2332//
2333// Opens an open dialog
2334//
2335Int_t MStatusDisplay::Open()
2336{
2337 static const char *gOpenTypes[] =
2338 {
2339 "ROOT files", "*.root",
2340 "All files", "*",
2341 NULL, NULL
2342 };
2343
2344 static TString dir(".");
2345
2346 TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
2347
2348 fi.fFileTypes = (const char**)gOpenTypes;
2349 fi.fIniDir = StrDup(dir);
2350
2351 new TGFileDialog(fClient->GetRoot(), this, kFDSave, &fi);
2352
2353 if (!fi.fFilename)
2354 return 0;
2355
2356 dir = fi.fIniDir;
2357
2358 return Open(fi.fFilename);
2359}
2360
2361Bool_t MStatusDisplay::HandleConfigureNotify(Event_t *evt)
2362{
2363 //
2364 // The initialization of the GUI is not yet enough finished...
2365 //
2366 if (!fTab)
2367 return kTRUE;
2368
2369 UInt_t w = evt->fWidth;
2370 UInt_t h = evt->fHeight;
2371
2372 /*
2373 cout << "Old: " << GetWidth() << " " << GetHeight() << " " << GetBorderWidth() << endl;
2374 cout << "New: " << w << " " << h << " ";
2375 cout << "New: " << GetDefaultWidth() << " " << GetDefaultHeight() << " " << endl;
2376 */
2377
2378 Bool_t wchanged = w!=GetWidth();
2379 Bool_t hchanged = h!=GetHeight();
2380
2381 if (!wchanged && !hchanged)
2382 {
2383 Layout();
2384 // FIXME: Make sure that this doesn't result in endless loops.
2385 return kTRUE;
2386 }
2387
2388
2389 if (GetWidth()==1 && GetHeight()==1)
2390 return kTRUE;
2391
2392 // calculate the constant part of the window
2393 const UInt_t cw = GetWidth() -fTab->GetWidth();
2394 const UInt_t ch = GetHeight()-fTab->GetHeight();
2395
2396 // calculate new size of frame (canvas @ 1:sqrt(2))
2397 if (hchanged)
2398 w = (UInt_t)((h-ch)*sqrt(2.)+.5)+cw;
2399 else
2400 h = (UInt_t)((w-cw)/sqrt(2.)+.5)+ch;
2401
2402 // resize frame
2403 Resize(w, h);
2404
2405 return kTRUE;
2406}
2407
2408Bool_t MStatusDisplay::HandleEvent(Event_t *event)
2409{
2410 Bool_t rc = TGMainFrame::HandleEvent(event);
2411
2412 //
2413 // This fixes a bug in older root versions which makes
2414 // TCanvas crash if gPad==NULL. So we make sure, that
2415 // gPad!=NULL -- be carfull, this may have other side
2416 // effects.
2417 //
2418#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
2419 if (!gPad && fTab)
2420 for (int i=0; i<fTab->GetNumberOfTabs(); i++)
2421 {
2422 TCanvas *c = GetCanvas(i);
2423 if (c)
2424 {
2425 c->cd();
2426 gLog << dbg << "MStatusDisplay::HandleEvent - Workaround: gPad=" << gPad << "." << endl;
2427 break;
2428 }
2429 }
2430#endif
2431
2432 return rc;
2433}
Note: See TracBrowser for help on using the repository browser.