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

Last change on this file since 4245 was 3825, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 66.3 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 for (int i=fTab->GetNumberOfTabs()-1; i>0; i--)
1134 RemoveTab(i);
1135}
1136
1137// --------------------------------------------------------------------------
1138//
1139// Process the kC_COMMAND, kCM_MENU messages
1140//
1141Bool_t MStatusDisplay::ProcessMessageCommandMenu(Long_t id)
1142{
1143 switch (id)
1144 {
1145 case kLoopStop:
1146 case kFileClose:
1147 case kFileExit:
1148 if (id==kFileExit || id==kFileClose)
1149 CloseWindow();
1150 fStatus = (Status_t)id;
1151 return kTRUE;
1152
1153 case kFileCanvas:
1154 new TCanvas;
1155 return kTRUE;
1156
1157 case kFileBrowser:
1158 new TBrowser;
1159 return kTRUE;
1160
1161 case kFileReset:
1162 Reset();
1163 return kTRUE;
1164
1165 case kFileOpen:
1166 Open();
1167 return kTRUE;
1168
1169 case kFileSaveAs:
1170 SaveAs();
1171 return kTRUE;
1172
1173 case kFileSaveAsPS:
1174 SaveAsPS();
1175 return kTRUE;
1176
1177 case kFileSaveAsGIF:
1178 SaveAsGIF();
1179 return kTRUE;
1180
1181 case kFileSaveAsC:
1182 SaveAsC();
1183 return kTRUE;
1184
1185 case kFileSaveAsRoot:
1186 SaveAsRoot();
1187 return kTRUE;
1188
1189 case kFilePrint:
1190 PrintToLpr();
1191 return kTRUE;
1192
1193 case kTabSaveAs:
1194 SaveAs(fTab->GetCurrent());
1195 return kTRUE;
1196
1197 case kTabSaveAsPS:
1198 SaveAsPS(fTab->GetCurrent());
1199 return kTRUE;
1200
1201 case kTabSaveAsGIF:
1202 SaveAsGIF(fTab->GetCurrent());
1203 return kTRUE;
1204
1205 case kTabSaveAsC:
1206 SaveAsC(fTab->GetCurrent());
1207 return kTRUE;
1208
1209 case kTabSaveAsRoot:
1210 SaveAsRoot(fTab->GetCurrent());
1211 return kTRUE;
1212
1213 case kTabPrint:
1214 PrintToLpr(fTab->GetCurrent());
1215 return kTRUE;
1216
1217 case kTabNext:
1218 fTab->SetTab(fTab->GetCurrent()+1);
1219 return kTRUE;
1220
1221 case kTabPrevious:
1222 fTab->SetTab(fTab->GetCurrent()-1);
1223 return kTRUE;
1224
1225 case kTabRemove:
1226 RemoveTab(fTab->GetCurrent());
1227 return kTRUE;
1228
1229 case kSize640:
1230 Resize(570, 480);
1231 return kTRUE;
1232 case kSize800:
1233 Resize(740, 600);
1234 return kTRUE;
1235 case kSize960:
1236 Resize(880, 700);
1237 return kTRUE;
1238 case kSize1024:
1239 Resize(980, 768);
1240 return kTRUE;
1241 case kSize1280:
1242 Resize(1280, 980);
1243 return kTRUE;
1244
1245 case kLogClear:
1246 fLogBox->Clear();
1247 return kTRUE;
1248 case kLogCopy:
1249 fLogBox->Copy();
1250 return kTRUE;
1251 case kLogSelect:
1252 fLogBox->SelectAll();
1253 return kTRUE;
1254 case kLogFind:
1255 new MSearch(this);
1256 return kTRUE;
1257 case kLogSave:
1258 SetStatusLine1("Saving log...");
1259 SetStatusLine2("");
1260 *fLog << inf << "Saving log... " << flush;
1261 if (fLogBox->GetText()->Save("statusdisplay.log"))
1262 {
1263 *fLog << "done." << endl;
1264 SetStatusLine2("done.");
1265 }
1266 else
1267 {
1268 *fLog << "failed!" << endl;
1269 SetStatusLine2("Failed!");
1270 }
1271 return kTRUE;
1272
1273 case kLogAppend:
1274 SetStatusLine1("Appending logg...");
1275 SetStatusLine2("");
1276 *fLog << inf << "Appending log... " << flush;
1277 if (fLogBox->GetText()->Append("statusdisplay.log"))
1278 {
1279 *fLog << "done." << endl;
1280 SetStatusLine2("done.");
1281 }
1282 else
1283 {
1284 *fLog << "failed!" << endl;
1285 SetStatusLine2("Failed!");
1286 }
1287 return kTRUE;
1288#ifdef DEBUG
1289 default:
1290 cout << "Command-Menu #" << id << endl;
1291#endif
1292 }
1293 return kTRUE;
1294
1295}
1296
1297// --------------------------------------------------------------------------
1298//
1299// Process the kC_COMMAND messages
1300//
1301Bool_t MStatusDisplay::ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2)
1302{
1303 switch (submsg)
1304 {
1305 case kCM_MENU: // 1
1306 return ProcessMessageCommandMenu(mp1); // mp2=userdata
1307 case kCM_TAB: // 8
1308 /*
1309 for (int i=0; i<fTab->GetNumberOfTabs(); i++)
1310 fTab->GetTabContainer(i)->UnmapWindow();
1311 */
1312 UpdateTab(fTab->GetTabContainer(mp1));
1313 //fTab->GetTabContainer(mp1)->MapWindow();
1314
1315 /*
1316 if (mp1>0)
1317 fMenu->AddPopup("&CaOs", fCaOs, NULL);
1318 else
1319 fMenu->RemovePopup("CaOs");
1320 fMenu->Resize(fMenu->GetDefaultSize());
1321 MapSubwindows();
1322 MapWindow();
1323 */
1324 return kTRUE;
1325 case kCM_COMBOBOX: // 7
1326 if (mp1==kTabs)
1327 fTab->SetTab(mp2);
1328 return kTRUE;
1329#ifdef DEBUG
1330 case kCM_MENUSELECT: // 2
1331 cout << "Command-Menuselect #" << mp1 << " (UserData=" << (void*)mp2 << ")" << endl;
1332 return kTRUE;
1333
1334 case kCM_BUTTON: // 3
1335 cout << "Command-Button." << endl;
1336 return kTRUE;
1337
1338 case kCM_CHECKBUTTON: // 4
1339 cout << "Command-CheckButton." << endl;
1340 return kTRUE;
1341
1342 case kCM_RADIOBUTTON: // 5
1343 cout << "Command-RadioButton." << endl;
1344 return kTRUE;
1345
1346 case kCM_LISTBOX: // 6
1347 cout << "Command-Listbox #" << mp1 << " (LineId #" << mp2 << ")" << endl;
1348 return kTRUE;
1349 default:
1350 cout << "Command: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1351#endif
1352 }
1353 return kTRUE;
1354}
1355
1356// --------------------------------------------------------------------------
1357//
1358// Process the kC_TEXTVIEW messages
1359//
1360Bool_t MStatusDisplay::ProcessMessageTextview(Long_t submsg, Long_t mp1, Long_t mp2)
1361{
1362 // kC_TEXTVIEW, kTXT_ISMARKED, widget id, [true|false] //
1363 // kC_TEXTVIEW, kTXT_DATACHANGE, widget id, 0 //
1364 // kC_TEXTVIEW, kTXT_CLICK2, widget id, position (y << 16) | x) //
1365 // kC_TEXTVIEW, kTXT_CLICK3, widget id, position (y << 16) | x) //
1366 // kC_TEXTVIEW, kTXT_F3, widget id, true //
1367 // kC_TEXTVIEW, kTXT_OPEN, widget id, 0 //
1368 // kC_TEXTVIEW, kTXT_CLOSE, widget id, 0 //
1369 // kC_TEXTVIEW, kTXT_SAVE, widget id, 0 //
1370#ifdef DEBUG
1371 switch (submsg)
1372 {
1373 case kTXT_ISMARKED:
1374 cout << "Textview-IsMarked #" << mp1 << " " << (mp2?"yes":"no") << endl;
1375 return kTRUE;
1376
1377 case kTXT_DATACHANGE:
1378 cout << "Textview-DataChange #" << mp1 << endl;
1379 return kTRUE;
1380
1381 case kTXT_CLICK2:
1382 cout << "Textview-Click2 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
1383 return kTRUE;
1384
1385 case kTXT_CLICK3:
1386 cout << "Textview-Click3 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
1387 return kTRUE;
1388
1389 case kTXT_F3:
1390 cout << "Textview-F3 #" << mp1 << endl;
1391 return kTRUE;
1392
1393 case kTXT_OPEN:
1394 cout << "Textview-Open #" << mp1 << endl;
1395 return kTRUE;
1396
1397 case kTXT_CLOSE:
1398 cout << "Textview-Close #" << mp1 << endl;
1399 return kTRUE;
1400
1401 case kTXT_SAVE:
1402 cout << "Textview-Save #" << mp1 << endl;
1403 return kTRUE;
1404
1405 default:
1406 cout << "Textview: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1407 }
1408#endif
1409 return kTRUE;
1410}
1411
1412// --------------------------------------------------------------------------
1413//
1414// Process the kC_USER messages
1415//
1416Bool_t MStatusDisplay::ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2)
1417{
1418 // kS_START, case sensitive | backward<<1, char *txt
1419 switch (submsg)
1420 {
1421 case kS_START:
1422 fLogBox->Search((char*)mp2, !(mp1&2>>1), mp1&1);
1423 return kTRUE;
1424#ifdef DEBUG
1425 default:
1426 cout << "User: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1427#endif
1428 }
1429 return kTRUE;
1430}
1431
1432// --------------------------------------------------------------------------
1433//
1434// Process the messages from the GUI
1435//
1436Bool_t MStatusDisplay::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2)
1437{
1438 // Can be found in WidgetMessageTypes.h
1439#ifdef DEBUG
1440 cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
1441 cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1442#endif
1443 switch (GET_MSG(msg))
1444 {
1445 case kC_COMMAND: // 1
1446 return ProcessMessageCommand(GET_SUBMSG(msg), mp1, mp2);
1447
1448 case kC_TEXTVIEW: // 9
1449 return ProcessMessageTextview(GET_SUBMSG(msg), mp1, mp2);
1450
1451 case kC_USER: // 1001
1452 return ProcessMessageUser(GET_SUBMSG(msg), mp1, mp2);
1453 }
1454#ifdef DEBUG
1455 cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
1456 cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1457#endif
1458 return kTRUE;
1459}
1460
1461void MStatusDisplay::CloseWindow()
1462{
1463 // Got close message for this MainFrame. Calls parent CloseWindow()
1464 // (which destroys the window) and terminate the application.
1465 // The close message is generated by the window manager when its close
1466 // window menu item is selected.
1467
1468 // CloseWindow must be overwritten because otherwise CloseWindow
1469 // and the destructor are calling DestroyWindow which seems to be
1470 // in conflict with the TRootEmbeddedCanvas.
1471
1472 // FIXME: Make sure that the Status Display is deleted from every
1473 // where (eg Eventloop) first!
1474
1475 //gLog << dbg << fName << " is on heap: " << (int)IsOnHeap() << endl;
1476
1477 if (TestBit(kExitLoopOnExit) || TestBit(kExitLoopOnClose))
1478 {
1479 gLog << dbg << "CloseWindow() calling ExitLoop." << endl;
1480 gSystem->ExitLoop();
1481 }
1482
1483 if (fIsLocked<=0 && IsOnHeap())
1484 {
1485 //gLog << dbg << "delete " << fName << ";" << endl;
1486 delete this;
1487 }
1488 fStatus = kFileExit;
1489 //gLog << dbg << fName << ".fStatus=kFileExit;" << endl;
1490}
1491
1492// --------------------------------------------------------------------------
1493//
1494// Calls SetBit(kNoContextMenu) for all TCanvas objects found in the
1495// Tabs.
1496//
1497void MStatusDisplay::SetNoContextMenu(Bool_t flag)
1498{
1499 if (fIsLocked>1 || gROOT->IsBatch())
1500 return;
1501
1502 flag ? SetBit(kNoContextMenu) : ResetBit(kNoContextMenu);
1503
1504 for (int i=1; i<fTab->GetNumberOfTabs(); i++)
1505 {
1506 TCanvas *c = GetCanvas(i);
1507 if (c)
1508 flag ? c->SetBit(kNoContextMenu) : c->ResetBit(kNoContextMenu);
1509 }
1510}
1511
1512// --------------------------------------------------------------------------
1513//
1514// Updates the canvas (if existing) in the currenly displayed Tab.
1515// The update intervall is controlled by StartUpdate and StopUpdate
1516//
1517Bool_t MStatusDisplay::HandleTimer(TTimer *timer)
1518{
1519 if (gROOT->IsBatch())
1520 return kTRUE;
1521
1522 const Int_t c = fTab->GetCurrent();
1523
1524 // Skip Legend Tab
1525 if (c==0)
1526 return kTRUE;
1527
1528 // Update a canvas tab (if visible)
1529 if (timer==&fTimer && c!=fLogIdx)
1530 {
1531 UpdateTab(fTab->GetCurrentContainer());
1532 return kTRUE;
1533 }
1534
1535 // update the logbook tab (if visible)
1536 if (timer==&fLogTimer && c==fLogIdx)
1537 {
1538 fLog->UpdateGui();
1539
1540 /*
1541 if (!fLogBox->TestBit(kHasChanged))
1542 return kTRUE;
1543
1544 fLogBox->ResetBit(kHasChanged);
1545 */
1546 return kTRUE;
1547 }
1548
1549 return kTRUE;
1550}
1551
1552// --------------------------------------------------------------------------
1553//
1554// Draws a clone of a canvas into a new canvas. Taken from TCanvas.
1555//
1556void MStatusDisplay::DrawClonePad(TCanvas &newc, const TCanvas &oldc) const
1557{
1558 //copy pad attributes
1559 newc.Range(oldc.GetX1(),oldc.GetY1(),oldc.GetX2(),oldc.GetY2());
1560 newc.SetTickx(oldc.GetTickx());
1561 newc.SetTicky(oldc.GetTicky());
1562 newc.SetGridx(oldc.GetGridx());
1563 newc.SetGridy(oldc.GetGridy());
1564 newc.SetLogx(oldc.GetLogx());
1565 newc.SetLogy(oldc.GetLogy());
1566 newc.SetLogz(oldc.GetLogz());
1567 newc.SetBorderSize(oldc.GetBorderSize());
1568 newc.SetBorderMode(oldc.GetBorderMode());
1569 ((TAttLine&)oldc).Copy((TAttLine&)newc);
1570 ((TAttFill&)oldc).Copy((TAttFill&)newc);
1571 ((TAttPad&)oldc).Copy((TAttPad&)newc);
1572
1573 //copy primitives
1574 TObject *obj;
1575 TIter next(oldc.GetListOfPrimitives());
1576 while ((obj=next())) {
1577 gROOT->SetSelectedPad(&newc);
1578 newc.GetListOfPrimitives()->Add(obj->Clone(),obj->GetDrawOption());
1579 }
1580 newc.Modified();
1581 newc.Update();
1582}
1583
1584Bool_t MStatusDisplay::Display(const TObjArray &list)
1585{
1586 TIter Next(&list);
1587
1588 TObject *o=Next();
1589 if (!o)
1590 {
1591 *fLog << err << "MStatusDisplay::Display: No entry in TObjArray." << endl;
1592 return kFALSE;
1593 }
1594
1595 fTitle = o->GetTitle();
1596
1597 TCanvas *c;
1598 while ((c=(TCanvas*)Next()))
1599 if (!GetCanvas(c->GetName()))
1600 DrawClonePad(AddTab(c->GetName()), *c);
1601
1602 return kTRUE;
1603}
1604
1605// --------------------------------------------------------------------------
1606//
1607// Reads the contents of a saved MStatusDisplay from a file.
1608//
1609Int_t MStatusDisplay::Read(const char *name)
1610{
1611 if (!gFile)
1612 {
1613 *fLog << warn << "MStatusDisplay::Read: No file found. Please create a TFile first." << endl;
1614 return 0;
1615 }
1616
1617 if (!gFile->IsOpen())
1618 {
1619 *fLog << warn << "MStatusDisplay::Read: File not open. Please open the TFile first." << endl;
1620 return 0;
1621 }
1622
1623 MStatusArray list;
1624
1625 const Int_t n = list.Read(name);
1626 if (n==0)
1627 {
1628 *fLog << warn << "MStatusDisplay::Read: No objects read." << endl;
1629 return 0;
1630 }
1631
1632 if (!Display(list))
1633 {
1634 *fLog << err << "MStatusDisplay::Display: No entry in " << name << "." << endl;
1635 return 0;
1636 }
1637
1638 *fLog << inf << "MStatusDisplay: Key " << name << " with " << n << " keys read from file." << endl;
1639
1640 return n;
1641}
1642
1643// --------------------------------------------------------------------------
1644//
1645// Writes the contents of a MStatusDisplay to a file.
1646//
1647Int_t MStatusDisplay::Write(Int_t num, const char *name, Int_t option, Int_t bufsize)
1648{
1649 if (!gFile)
1650 {
1651 *fLog << warn << "MStatusDisplay::Write: No file found. Please create a TFile first." << endl;
1652 return 0;
1653 }
1654
1655 if (!gFile->IsOpen())
1656 {
1657 *fLog << warn << "MStatusDisplay::Write: File not open. Please open the TFile first." << endl;
1658 return 0;
1659 }
1660
1661 if (!gFile->IsWritable())
1662 {
1663 *fLog << warn << "MStatusDisplay::Write: File not writable." << endl;
1664 return 0;
1665 }
1666
1667 if (num==0)
1668 {
1669 *fLog << warn << "MStatusDisplay::Write: Tab doesn't contain an embedded Canvas... skipped." << endl;
1670 return 0;
1671 }
1672
1673 if (!gROOT->IsBatch() && num>=fTab->GetNumberOfTabs())
1674 {
1675 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
1676 return 0;
1677 }
1678 if (gROOT->IsBatch() && num>fBatch->GetSize())
1679 {
1680 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
1681 return 0;
1682 }
1683
1684 MStatusArray list;
1685
1686 TNamed named;
1687 named.SetTitle(fTitle);
1688 list.Add(&named);
1689
1690 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
1691 const Int_t from = num<0 ? 1 : num;
1692 const Int_t to = num<0 ? max : num+1;
1693
1694 TCanvas *c;
1695 for (int i=from; i<to; i++)
1696 if ((c = GetCanvas(i)))
1697 list.Add(c);
1698
1699 const Int_t n = list.Write(name, kSingleKey);
1700
1701 *fLog << inf << "MStatusDisplay: " << n << " keys written to file as key " << name << "." << endl;
1702
1703 return n;
1704}
1705
1706// --------------------------------------------------------------------------
1707//
1708// Use this to start the synchronous (GUI eventloop driven) tab update.
1709// Can also be used to change the update intervall. If millisec<0
1710// the intervall given in SetUpdateTime is used. If the intervall in
1711// SetUpdateTime is <0 nothing is done. (Call SetUpdateTime(-1) to
1712// disable the automatic update in a MEventloop.
1713//
1714void MStatusDisplay::StartUpdate(Int_t millisec)
1715{
1716 if (fIsLocked>1)
1717 return;
1718
1719 if (fTimer.GetTime()<TTime(0))
1720 return;
1721 fTimer.Start(millisec);
1722}
1723
1724// --------------------------------------------------------------------------
1725//
1726// Stops the automatic GUI update
1727//
1728void MStatusDisplay::StopUpdate()
1729{
1730 if (fIsLocked>1)
1731 return;
1732
1733 fTimer.Stop();
1734}
1735
1736// --------------------------------------------------------------------------
1737//
1738// Set the update interval for the GUI update, see StartUpdate.
1739//
1740void MStatusDisplay::SetUpdateTime(Long_t t)
1741{
1742 fTimer.SetTime(t);
1743}
1744
1745// --------------------------------------------------------------------------
1746//
1747// Set the background color in a canvas
1748//
1749void MStatusDisplay::CanvasSetFillColor(TPad &p, Int_t col) const
1750{
1751 TObject *obj;
1752
1753 // See also TPad::UseCurrentStyle
1754 TIter Next(p.GetListOfPrimitives());
1755 while ((obj=Next()))
1756 {
1757 if (obj->InheritsFrom(TPad::Class()))
1758 CanvasSetFillColor(*(TPad*)obj, col);
1759 if (obj->InheritsFrom(TFrame::Class()))
1760 ((TFrame*)obj)->SetFillColor(col);
1761 }
1762
1763 p.SetFillColor(col);
1764}
1765
1766void MStatusDisplay::AddExtension(TString &name, const TString &ext, Int_t num) const
1767{
1768 if (name.IsNull())
1769 {
1770 name = "status";
1771 if (num>0)
1772 {
1773 name += "-";
1774 name += num;
1775 }
1776 }
1777
1778 if (name.EndsWith("."+ext))
1779 return;
1780
1781 name += ".";
1782 name += ext;
1783}
1784
1785Bool_t MStatusDisplay::CheckTabForCanvas(int num) const
1786{
1787 if (gROOT->IsBatch())
1788 return num>0 && num<=fBatch->GetSize() || num<0;
1789
1790 if (num>=fTab->GetNumberOfTabs())
1791 {
1792 *fLog << warn << "Tab #" << num << " doesn't exist..." << endl;
1793 return kFALSE;
1794 }
1795 if (num==0)
1796 {
1797 *fLog << warn << "Tab #" << num << " doesn't contain an embedded canvas..." << endl;
1798 return kFALSE;
1799 }
1800 if (fTab->GetNumberOfTabs()<2 || !gPad)
1801 {
1802 *fLog << warn << "Sorry, you must have at least one existing canvas (gPad!=NULL)" << endl;
1803 return kFALSE;
1804 }
1805 return kTRUE;
1806}
1807
1808// --------------------------------------------------------------------------
1809//
1810// Insert the following two lines into the postscript header:
1811//
1812// %%DocumentPaperSizes: a4
1813// %%Orientation: Landscape
1814//
1815void MStatusDisplay::UpdatePSHeader(const TString &name) const
1816{
1817 const TString newstr("%%DocumentPaperSizes: a4\n%%Orientation: Landscape\n");
1818
1819 ifstream fin(name);
1820 ofstream fout(name+".$$$");
1821
1822 char c;
1823
1824 TString str;
1825 fin >> str >> c; // Read "%!PS-Adobe-2.0\n"
1826 fout << str << endl << newstr;
1827
1828 // Doing it in blocks seems not to gain much for small (MB) files
1829 while (fin)
1830 {
1831 fin.read(&c, 1);
1832 fout.write(&c, 1);
1833 }
1834
1835 gSystem->Unlink(name);
1836 gSystem->Rename(name+".$$$", name);
1837/*
1838 //
1839 // Old style algorithm. Shifts blocks inside a single file --- SLOW!
1840 //
1841 const Int_t l = newstr.Length();
1842
1843 Long_t t[4]; // { id, size, flags, modtime }
1844 gSystem->GetPathInfo(name, t, t+1, t+2, t+3);
1845
1846 char *c[2] = { new char[l], new char[l] };
1847
1848 fstream f(name, ios::in|ios::out);
1849
1850 TString str;
1851 f >> str >> c[0][0]; // Read "%!PS-Adobe-2.0\n" (Mini Header)
1852 f.read(c[0], l);
1853 f.seekp(-l, ios::cur);
1854 f.write(newstr, l);
1855
1856 int i=0;
1857 while (1)
1858 {
1859 f.read(c[(i+1)%2], l);
1860 f.seekp(-l, ios::cur);
1861
1862 if (f)
1863 {
1864 f.write(c[i%2],l);
1865 i++;
1866 i%=2;
1867 continue;
1868 }
1869
1870 const Int_t ssz = str.Length()+1; // Length of Mini-Header
1871 const Int_t block = t[1]-ssz; // Length of block to be shifted
1872 const Int_t size = block%l; // Reminder
1873 const Int_t pos = (block/l)*l + ssz + 1; // Position to start writing
1874
1875 f.clear();
1876 f.seekp(pos);
1877 f.write(c[i%2], l);
1878 f.write(c[(i+1)%2], size);
1879 break;
1880 }
1881
1882 delete c[1];
1883 delete c[0];
1884*/
1885}
1886
1887// --------------------------------------------------------------------------
1888//
1889// In case of num<0 all tabs are written into the PS file. If num>0
1890// the canvas in the corresponding tab is written to the file.
1891// Name is the name of the file (with or without extension).
1892//
1893// Returns the number of pages written.
1894//
1895// To write all tabs you can also use SaveAsPS(name)
1896//
1897// If the third argument is given a bottom line is drawn with the text
1898// under it. If no argument is given a bottom line is drawn if
1899// fTitle (SetTitle) is not empty.
1900//
1901Int_t MStatusDisplay::SaveAsPS(Int_t num, TString name, const TString addon)
1902{
1903 SetStatusLine1("Writing Postscript file...");
1904 SetStatusLine2("");
1905
1906 if (!CheckTabForCanvas(num))
1907 {
1908 SetStatusLine2("Failed!");
1909 return 0;
1910 }
1911
1912 AddExtension(name, "ps", num);
1913
1914 if (num<0)
1915 *fLog << inf << "Open ps-File: " << name << endl;
1916
1917 TPad *padsav = (TPad*)gPad;
1918 TVirtualPS *psave = gVirtualPS;
1919
1920 TDatime d;
1921
1922 TPostScript ps(name, 112);
1923 ps.SetBit(TPad::kPrintingPS);
1924 ps.PrintFast(13, "/nan {1} def ");
1925
1926 gVirtualPS = &ps;
1927
1928 //
1929 // Create a list to delete the canvas clones
1930 //
1931 TList l;
1932 l.SetOwner();
1933
1934 //
1935 // Create some GUI elements for a page legend
1936 //
1937 TLine line;
1938
1939 int page = 1;
1940
1941 //
1942 // Maintain tab numbers
1943 //
1944 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
1945 const Int_t from = num<0 ? 1 : num;
1946 const Int_t to = num<0 ? max : num+1;
1947
1948 for (int i=from; i<to; i++)
1949 {
1950 TCanvas *c;
1951 if (!(c = GetCanvas(i)))
1952 {
1953 if (num<0)
1954 *fLog << inf << " - ";
1955 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
1956 continue;
1957 }
1958
1959 SetStatusLine2(Form("Tab #%d", i));
1960
1961 //
1962 // Init page and page size, make sure, that the canvas in the file
1963 // has the same Aspect Ratio than on the screen.
1964 //
1965 ps.NewPage();
1966
1967 //
1968 // 28 is used here to scale the canvas into a height of 28,
1969 // such that the page title can be set above the canvas...
1970 //
1971 Float_t psw = 28.0; // A4 - width (29.7)
1972 Float_t psh = 21.0; // A4 - height (21.0)
1973
1974 const Float_t cw = c->GetWw();
1975 const Float_t ch = c->GetWh();
1976
1977 if (psw/psh>cw/ch)
1978 psw = cw/ch*psh;
1979 else
1980 psh = ch/cw*psw;
1981
1982 ps.Range(psw, psh); // A4
1983
1984 //
1985 // Clone canvas and change background color and schedule for
1986 // deletion
1987 //
1988 TCanvas *n = (TCanvas*)c->Clone();
1989 CanvasSetFillColor(*n, kWhite);
1990 l.Add(n);
1991
1992 //
1993 // Paint canvas into root file
1994 //
1995 if (num<0)
1996 *fLog << inf << " - ";
1997 *fLog << inf << "Writing Tab #" << i << ": " << c->GetName() << " (" << c << ") ";
1998 if (num>0)
1999 *fLog << "to " << name;
2000 *fLog << "... " << flush;
2001
2002 n->SetBatch(kTRUE);
2003 n->Paint();
2004
2005 //
2006 // Use the canvas as coordinate system for the overlaying text
2007 //
2008 gPad = n;
2009 //n->cd();
2010
2011 //
2012 // Print overlaying text (NDC = %)
2013 //
2014 ps.SetTextColor(kBlack);
2015 ps.SetTextSize(0.015);
2016 ps.SetTextFont(22);
2017 ps.SetTextAlign(11); // left top
2018 ps.TextNDC(0, 1.015, TString(" ")+n->GetName());
2019 ps.SetTextAlign(21); // cent top
2020 ps.TextNDC(0.5, 1.015, TString("MARS - Magic Analysis and Reconstruction Software - ")+d.AsString());
2021 ps.SetTextAlign(31); // right top
2022 ps.TextNDC(1, 1.015, Form("Page No.%i (%i) ", page++, i));
2023 line.PaintLineNDC(0, 1.01, 1, 1.01);
2024
2025 TString txt(addon.IsNull() ? fTitle : addon);
2026 if (!txt.IsNull())
2027 {
2028 line.PaintLineNDC(0, -0.00, 1, -0.00);
2029 ps.SetTextAlign(11); // left top
2030 ps.TextNDC(0, -0.005, txt);
2031 ps.SetTextAlign(31); // right top
2032 ps.TextNDC(1, -0.005, "(c) 2000-2004, Thomas Bretz");
2033 }
2034
2035 //
2036 // Finish drawing page
2037 //
2038 n->SetBatch(kFALSE);
2039 *fLog << "done." << endl;
2040 }
2041
2042 gPad = NULL; // Important!
2043 l.Delete();
2044
2045 ps.Close();
2046
2047 SetStatusLine2("Updating header of PS file...");
2048
2049 if (num<0)
2050 *fLog << " - Updating header of PS file... " << flush;
2051 UpdatePSHeader(name);
2052 if (num<0)
2053 *fLog << inf << "done." << endl;
2054
2055 gVirtualPS = psave;
2056 if (padsav)
2057 padsav->cd();
2058
2059 if (num<0)
2060 *fLog << inf << "done." << endl;
2061
2062 SetStatusLine2(Form("Done (%dpages)", page-1));
2063
2064 return page-1;
2065}
2066
2067Bool_t MStatusDisplay::SaveAsGIF(Int_t num, TString name)
2068{
2069 if (gROOT->IsBatch())
2070 {
2071 *fLog << warn << "Sorry, writing gif-files is not available in batch mode." << endl;
2072 return 0;
2073 }
2074 SetStatusLine1("Writing GIF file...");
2075 SetStatusLine2("");
2076
2077 if (!CheckTabForCanvas(num))
2078 {
2079 SetStatusLine2("Failed!");
2080 return 0;
2081 }
2082
2083 AddExtension(name, "gif", num);
2084
2085 if (num<0)
2086 *fLog << inf << "Writing gif-Files..." << endl;
2087
2088 TPad *padsav = (TPad*)gPad;
2089
2090 int page = 1;
2091
2092 //
2093 // Maintain tab numbers
2094 //
2095 const Int_t from = num<0 ? 1 : num;
2096 const Int_t to = num<0 ? fTab->GetNumberOfTabs() : num+1;
2097
2098 for (int i=from; i<to; i++)
2099 {
2100 TCanvas *c;
2101 if (!(c = GetCanvas(i)))
2102 {
2103 if (num<0)
2104 *fLog << inf << " - ";
2105 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
2106 continue;
2107 }
2108
2109 SetStatusLine2(Form("Tab #%d", i));
2110
2111 //
2112 // Clone canvas and change background color and schedule for
2113 // deletion
2114 //
2115 //TCanvas *n = (TCanvas*)c->Clone();
2116 //CanvasSetFillColor(*n, kWhite);
2117
2118 //
2119 // Paint canvas into root file
2120 //
2121 TString writename = name;
2122 if (num<0)
2123 {
2124 TString numname = "-";
2125 numname += i;
2126 writename.Insert(name.Last('.'), numname);
2127 }
2128 if (num<0)
2129 *fLog << inf << " - ";
2130 *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << c << ") ";
2131 if (num>0)
2132 *fLog << "to " << name;
2133 *fLog << "..." << flush;
2134
2135 c->Draw();
2136 c->SaveAs(writename);
2137 /*
2138 n->Draw();
2139 n->SaveAs(writename);
2140 delete n;
2141 */
2142
2143 if (num<0)
2144 *fLog << "done." << endl;
2145 }
2146
2147 padsav->cd();
2148
2149 *fLog << inf << "done." << endl;
2150
2151 SetStatusLine2("Done.");
2152
2153 return page-1;
2154}
2155
2156Bool_t MStatusDisplay::SaveAsC(Int_t num, TString name)
2157{
2158 SetStatusLine1("Writing C++ file...");
2159 SetStatusLine2("");
2160
2161 if (!CheckTabForCanvas(num))
2162 {
2163 SetStatusLine2("Failed!");
2164 return 0;
2165 }
2166
2167 AddExtension(name, "C", num);
2168
2169 if (num<0)
2170 *fLog << inf << "Writing C-Files..." << endl;
2171
2172 TPad *padsav = (TPad*)gPad;
2173
2174 int page = 1;
2175
2176 //
2177 // Maintain tab numbers
2178 //
2179 const Int_t from = num<0 ? 1 : num;
2180 const Int_t to = num<0 ? fTab->GetNumberOfTabs() : num+1;
2181
2182 for (int i=from; i<to; i++)
2183 {
2184 TCanvas *c;
2185 if (!(c = GetCanvas(i)))
2186 {
2187 if (num<0)
2188 *fLog << inf << " - ";
2189 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
2190 continue;
2191 }
2192
2193 SetStatusLine2(Form("Tab #%d", i));
2194
2195 //
2196 // Clone canvas and change background color and schedule for
2197 // deletion
2198 //
2199 TCanvas *n = (TCanvas*)c->Clone();
2200 CanvasSetFillColor(*n, kWhite);
2201
2202 //
2203 // Paint canvas into root file
2204 //
2205 TString writename = name;
2206 if (num<0)
2207 {
2208 TString numname = "-";
2209 numname += i;
2210 writename.Insert(name.Last('.'), numname);
2211 }
2212 if (num<0)
2213 *fLog << inf << " - ";
2214 *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << n << ") ";
2215 if (num>0)
2216 *fLog << "to " << name;
2217 *fLog << "..." << flush;
2218
2219 n->SaveSource(writename, "");
2220 delete n;
2221
2222 if (num<0)
2223 *fLog << "done." << endl;
2224 }
2225
2226 padsav->cd();
2227
2228 *fLog << inf << "done." << endl;
2229
2230 SetStatusLine2("Done.");
2231
2232 return page-1;
2233}
2234
2235// --------------------------------------------------------------------------
2236//
2237// In case of num<0 all tabs are written into the PS file. If num>0
2238// the canvas in the corresponding tab is written to the file.
2239// Name is the name of the file (with or without extension).
2240//
2241// Returns the number of keys written.
2242//
2243// To write all tabs you can also use SaveAsPS(name)
2244//
2245Int_t MStatusDisplay::SaveAsRoot(Int_t num, TString name)
2246{
2247 SetStatusLine1("Writing root file...");
2248 SetStatusLine2("");
2249
2250 if (!CheckTabForCanvas(num))
2251 {
2252 SetStatusLine2("Failed!");
2253 return 0;
2254 }
2255
2256 AddExtension(name, "root", num);
2257
2258 TFile *fsave = gFile;
2259 TFile file(name, "RECREATE", "MARS - Status Window Contents", 9);
2260 const Int_t keys = Write(num);
2261 gFile = fsave;
2262
2263 SetStatusLine2("Done.");
2264
2265 return keys;
2266}
2267
2268// --------------------------------------------------------------------------
2269//
2270// Opens a save as dialog
2271//
2272Int_t MStatusDisplay::SaveAs(Int_t num)
2273{
2274 static const char *gSaveAsTypes[] =
2275 {
2276 "PostScript", "*.ps",
2277 "Gif files", "*.gif",
2278 "Macro files", "*.C",
2279 "ROOT files", "*.root",
2280 "All files", "*",
2281 NULL, NULL
2282 };
2283
2284 static TString dir(".");
2285
2286 TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
2287
2288 fi.fFileTypes = (const char**)gSaveAsTypes;
2289 fi.fIniDir = StrDup(dir);
2290
2291 new TGFileDialog(fClient->GetRoot(), this, kFDSave, &fi);
2292
2293 if (!fi.fFilename)
2294 return 0;
2295
2296 dir = fi.fIniDir;
2297
2298 const TString name(fi.fFilename);
2299
2300 if (name.EndsWith(".root")) return SaveAsRoot(num, name);
2301 if (name.EndsWith(".ps")) return SaveAsPS(num, name);
2302 if (name.EndsWith(".gif")) return SaveAsGIF(num, name);
2303 if (name.EndsWith(".C")) return SaveAsC(num, name);
2304
2305 Warning("MStatusDisplay::SaveAs", "Unknown Extension: %s", fi.fFilename);
2306 return 0;
2307}
2308
2309// --------------------------------------------------------------------------
2310//
2311// Open contents of a MStatusDisplay with key name from file fname.
2312//
2313Int_t MStatusDisplay::Open(TString fname, const char *name)
2314{
2315 TFile file(fname, "READ");
2316 if (file.IsZombie())
2317 {
2318 gLog << warn << "WARNING - Cannot open file " << fname << endl;
2319 return 0;
2320 }
2321
2322 return Read(name);
2323}
2324
2325// --------------------------------------------------------------------------
2326//
2327// Opens an open dialog
2328//
2329Int_t MStatusDisplay::Open()
2330{
2331 static const char *gOpenTypes[] =
2332 {
2333 "ROOT files", "*.root",
2334 "All files", "*",
2335 NULL, NULL
2336 };
2337
2338 static TString dir(".");
2339
2340 TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
2341
2342 fi.fFileTypes = (const char**)gOpenTypes;
2343 fi.fIniDir = StrDup(dir);
2344
2345 new TGFileDialog(fClient->GetRoot(), this, kFDSave, &fi);
2346
2347 if (!fi.fFilename)
2348 return 0;
2349
2350 dir = fi.fIniDir;
2351
2352 return Open(fi.fFilename);
2353}
2354
2355Bool_t MStatusDisplay::HandleConfigureNotify(Event_t *evt)
2356{
2357 //
2358 // The initialization of the GUI is not yet enough finished...
2359 //
2360 if (!fTab)
2361 return kTRUE;
2362
2363 UInt_t w = evt->fWidth;
2364 UInt_t h = evt->fHeight;
2365
2366 /*
2367 cout << "Old: " << GetWidth() << " " << GetHeight() << " " << GetBorderWidth() << endl;
2368 cout << "New: " << w << " " << h << " ";
2369 cout << "New: " << GetDefaultWidth() << " " << GetDefaultHeight() << " " << endl;
2370 */
2371
2372 Bool_t wchanged = w!=GetWidth();
2373 Bool_t hchanged = h!=GetHeight();
2374
2375 if (!wchanged && !hchanged)
2376 {
2377 Layout();
2378 // FIXME: Make sure that this doesn't result in endless loops.
2379 return kTRUE;
2380 }
2381
2382
2383 if (GetWidth()==1 && GetHeight()==1)
2384 return kTRUE;
2385
2386 // calculate the constant part of the window
2387 const UInt_t cw = GetWidth() -fTab->GetWidth();
2388 const UInt_t ch = GetHeight()-fTab->GetHeight();
2389
2390 // calculate new size of frame (canvas @ 1:sqrt(2))
2391 if (hchanged)
2392 w = (UInt_t)((h-ch)*sqrt(2.)+.5)+cw;
2393 else
2394 h = (UInt_t)((w-cw)/sqrt(2.)+.5)+ch;
2395
2396 // resize frame
2397 Resize(w, h);
2398
2399 return kTRUE;
2400}
2401
2402Bool_t MStatusDisplay::HandleEvent(Event_t *event)
2403{
2404 Bool_t rc = TGMainFrame::HandleEvent(event);
2405
2406 //
2407 // This fixes a bug in older root versions which makes
2408 // TCanvas crash if gPad==NULL. So we make sure, that
2409 // gPad!=NULL -- be carfull, this may have other side
2410 // effects.
2411 //
2412#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
2413 if (!gPad && fTab)
2414 for (int i=0; i<fTab->GetNumberOfTabs(); i++)
2415 {
2416 TCanvas *c = GetCanvas(i);
2417 if (c)
2418 {
2419 c->cd();
2420 gLog << dbg << "MStatusDisplay::HandleEvent - Workaround: gPad=" << gPad << "." << endl;
2421 break;
2422 }
2423 }
2424#endif
2425
2426 return rc;
2427}
Note: See TracBrowser for help on using the repository browser.