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

Last change on this file since 5557 was 5557, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 67.1 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 4/2003 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2003-2004
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MStatusDisplay
28//
29// This status display can be used (and is used) to display results in
30// a tabbed window. The window can be written to and read from a root file
31// (see Read and Write) or printed as a postscript file (see SaveAsPS).
32//
33// To write gif files of C-Macros use SaveAsGif() or SaveAsC().
34// Direct printing to the default printer (via lpr) can be done by
35// PrintToLpr().
36//
37// It has also to half status lines which can be used to display the status
38// or something going on. Together with the status lines it has a progress
39// bar which can display the progress of a job or loop.
40// Access the progress bar by GetProgressBar()
41//
42// To add a new tab and get a pointer to the newly created TCanvas
43// use AddTab.
44//
45// If you have a MStatusDisplay and you are not sure whether it was
46// destroyed by the user meanwhile use:
47// gROOT->GetListOfSpecials()->FindObject(pointer);
48// Each MStatusDisplay is added to list list by its constructor and
49// removed from the list by the destructor.
50//
51// You can redirect an output to a MLog-logstream by calling SetLogStream().
52// To disable redirction call SetLogStream(NULL)
53//
54// Because updates to the tabs are only done/displayed if a tab is active
55// using the gui doesn't make things slower (<1%) if the first (legend
56// tab) is displayed. This gives you the possibility to look into
57// the current progress of a loop without loosing more time than the
58// single update of the tab.
59//
60/////////////////////////////////////////////////////////////////////////////
61#include "MStatusDisplay.h"
62
63#include <fstream> // fstream
64
65#include <TLine.h> // TLine
66#include <TText.h> // TText
67#include <TFile.h> // gFile
68#include <TFrame.h> // TFrame
69#include <TStyle.h> // gStyle
70#include <TCanvas.h> // TCanvas
71#include <TSystem.h> // gSystem
72#include <TDatime.h> // TDatime
73#include <TRandom.h> // TRandom
74#include <TThread.h> // TThread::Self()
75#include <TBrowser.h> // TBrowser
76#include <TObjArray.h> // TObjArray
77#include <TPostScript.h> // TPostScript
78#include <TMethodCall.h> // TMethodCall
79
80//#include <TRint.h> // gApplication, TRint::Class()
81#include <TInterpreter.h> // gInterpreter
82
83#include <TGTab.h> // TGTab
84#include <TGLabel.h> // TGLabel
85#include <TG3DLine.h> // TGHorizontal3DLine
86#include <TGButton.h> // TGPictureButton
87#include <TGTextView.h> // TGTextView
88#include <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// Returns j-th pad of the i-th Tab.
764// Sets the pad to fill an entire window.
765//
766// This function can be used if single pad's out of an MStatusDisplay
767// have to be stored to file.
768//
769// ATTENTION: This function modifies the requested tab in MStatusDisplay itself!
770//
771TVirtualPad *MStatusDisplay::GetFullPad(const Int_t i, const Int_t j)
772{
773
774 TVirtualPad *vpad = GetCanvas(i)->GetPad(j);
775 if (vpad)
776 vpad->SetPad(0.,0.,1.,1.);
777 else
778 *fLog << warn << "MStatusDisplay::GetFullPad: Pad is out of range." << endl;
779
780 return vpad;
781}
782
783
784
785// --------------------------------------------------------------------------
786//
787// Searches for a TRootEmbeddedCanvas in the TGCompositeFramme of the
788// Tab with the name 'name'. Returns the corresponding TCanvas or
789// NULL if something isn't found.
790//
791TCanvas *MStatusDisplay::GetCanvas(const TString &name) const
792{
793 TGFrameElement *f;
794 TIter Next(fTab->GetList());
795 while ((f=(TGFrameElement*)Next()))
796 {
797 TObject *frame = f->fFrame;
798 if (!frame->InheritsFrom(TGTabElement::Class()))
799 continue;
800
801 TGTabElement *tab = (TGTabElement*)frame;
802 if (tab->GetString()==name)
803 break;
804 }
805
806 // Search for the next TGCompositeFrame in the list
807 while ((f=(TGFrameElement*)Next()))
808 {
809 TObject *frame = f->fFrame;
810 if (frame->InheritsFrom(TGCompositeFrame::Class()))
811 return GetCanvas((TGCompositeFrame*)frame);
812 }
813
814 return NULL;
815}
816
817// --------------------------------------------------------------------------
818//
819// Calls TCanvas::cd(), for the canvas returned by GetCanvas.
820//
821Bool_t MStatusDisplay::CdCanvas(const TString &name)
822{
823 TCanvas *c = GetCanvas(name);
824 if (!c)
825 return kFALSE;
826
827 c->cd();
828 return kTRUE;
829}
830
831TGCompositeFrame *MStatusDisplay::AddRawTab(const char *name)
832{
833 // Add new tab
834 TGCompositeFrame *f = fTab->AddTab(name);
835
836 TGComboBox *box = (TGComboBox*)fList->FindWidget(kTabs);
837 box->AddEntry(name, box->GetListBox()->GetNumberOfEntries());
838
839 // layout and map new tab
840 Layout();
841 MapSubwindows();
842 Layout();
843
844 // display new tab in the main frame
845 // FIXME: This is a workaround, because TApplication::Run is not
846 // thread safe against ProcessEvents. We assume, that if
847 // we are not in the Main-Thread ProcessEvents() is
848 // called by the TApplication Event Loop...
849 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
850 gClient->ProcessEventsFor(fTab);
851
852 *fLog << inf << "Adding Raw Tab '" << name << "' (" << f->GetWidth() << "x";
853 *fLog << f->GetHeight() << ")" << endl;
854
855 // return pointer to new canvas
856 return f;
857}
858
859// --------------------------------------------------------------------------
860//
861// This function was connected to all created canvases. It is used
862// to redirect GetObjectInfo into our own status bar.
863//
864// The 'connection' is done in AddTab
865//
866void MStatusDisplay::EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected)
867{
868 // Writes the event status in the status bar parts
869 if (!selected)
870 return;
871
872 TCanvas *c = (TCanvas*)gTQSender;
873
874 TVirtualPad* save=gPad;
875
876 gPad = c ? c->GetSelectedPad() : NULL;
877
878 if (gPad)
879 SetStatusLine2(selected->GetObjectInfo(px,py));
880
881 gPad=save;
882}
883
884// --------------------------------------------------------------------------
885//
886// Adds a new tab with the name 'name'. Adds a TRootEmbeddedCanvas to the
887// tab and returns a reference to the corresponding TCanvas.
888//
889TCanvas &MStatusDisplay::AddTab(const char *name)
890{
891 if (gROOT->IsBatch())
892 {
893 TCanvas *c = new TCanvas(name, name);
894 fBatch->Add(c);
895 return *c;
896 }
897
898 // Add new tab
899 TGCompositeFrame *f = fTab->AddTab(name);
900
901 // create root embedded canvas and add it to the tab
902 TRootEmbeddedCanvas *ec = new TRootEmbeddedCanvas(name, f, f->GetWidth(), f->GetHeight(), 0);
903 f->AddFrame(ec, fLayCanvas);
904 fList->Add(ec);
905
906 // set background and border mode of the canvas
907 TCanvas &c = *ec->GetCanvas();
908
909 c.SetFillColor(16/*165*//*17*//*203*/);
910 c.SetBorderMode(0);
911
912 // If kNoContextMenu set set kNoContextMenu of the canvas
913 if (TestBit(kNoContextMenu))
914 c.SetBit(kNoContextMenu);
915
916 // Connect all TCanvas::ProcessedEvent to this->EventInfo
917 // This means, that after TCanvas has processed an event
918 // EventInfo of this class is called, see TCanvas::HandleInput
919 c.Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)",
920 "MStatusDisplay", this, "EventInfo(Int_t,Int_t,Int_t,TObject*)");
921
922 TGComboBox *box = (TGComboBox*)fList->FindWidget(kTabs);
923 box->AddEntry(name, box->GetListBox()->GetNumberOfEntries());
924
925 // layout and map new tab
926 Layout(); // seems to layout the TGCompositeFrame
927 MapSubwindows(); // maps the TGCompositeFrame
928 Layout(); // layout the embedded canvas in the frame
929
930 // display new tab in the main frame
931 // FIXME: This is a workaround, because TApplication::Run is not
932 // thread safe against ProcessEvents. We assume, that if
933 // we are not in the Main-Thread ProcessEvents() is
934 // called by the TApplication Event Loop...
935 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
936 gClient->ProcessEventsFor(fTab);
937
938 *fLog << inf << "Adding Tab '" << name << "' (" << f->GetWidth() << "x";
939 *fLog << f->GetHeight() << ", TCanvas=" << &c << ")" << endl;
940
941 // return pointer to new canvas
942 return c;
943}
944
945// --------------------------------------------------------------------------
946//
947// Update a canvas in a tab, takes the corresponding TGCompositeFrame
948// as an argument. This is necessary, because not all functions
949// changing the contents of a canvas or pad can call SetModified()
950// for the corresponding tab. If this is not called correctly the
951// tab won't be updated calling TCanvas::Update(). So we simply
952// redraw it by our own (instead we could recursively call
953// TPad::Modified() for everything contained by the TCanvas and
954// call TCanvas::Update() afterwards)
955//
956void MStatusDisplay::UpdateTab(TGCompositeFrame *f)
957{
958 if (!f)
959 return;
960
961 TCanvas *c=GetCanvas(f);
962 if (!c)
963 return;
964
965 //
966 // If we are in a multithreaded environment (gThreadXAR) we
967 // have to make sure, that thus function is called from
968 // the main thread.
969 //
970 if (gThreadXAR)
971 {
972 // Tell the X-Requester how to call this method
973 TString str = Form("%d", (ULong_t)f);
974
975 TMethodCall call(IsA(), "UpdateTab", "NULL");
976 void *arr[4] = { NULL, &call, this, (void*)(const char*)str };
977
978 // If this is not the main thread return
979 if (((*gThreadXAR)("METH", 4, arr, NULL)))
980 return;
981 }
982
983 //
984 // Secure calls to update the tabs against itself, at least
985 // c->Paint() or c->Flush() may crash X (bad drawable).
986 // This makes sure, that a X call is not interuppted by
987 // another X-call which was started from an gui interrrupt
988 // in the same thread
989 //
990 if (fMutex->TryLock())
991 return;
992
993#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,02)
994 TPad *padsav = (TPad*)gPad;
995 if (!gPad)
996 c->cd();
997#endif
998
999 if (!c->IsBatch())
1000 c->FeedbackMode(kFALSE); // Goto double buffer mode
1001
1002 //
1003 // Doing this ourself gives us the possibility to repaint
1004 // the canvas in any case (Paint() instead of PaintModified())
1005 //
1006 c->Paint(); // Repaint all pads
1007 c->Flush(); // Copy all pad pixmaps to the screen
1008
1009#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,02)
1010 if (padsav)
1011 padsav->cd();
1012 else
1013 gPad=NULL;
1014#endif
1015
1016 //c->SetCursor(kCross);
1017
1018 // Old version
1019 //c->Modified();
1020 //c->Update();
1021 //c->Paint();
1022
1023 fMutex->UnLock();
1024}
1025
1026// --------------------------------------------------------------------------
1027//
1028// Saves the given canvas (pad) or all pads (num<0) as a temporary
1029// postscript file and prints it using 'lpr'. If a printer name is set
1030// via SetPrinter 'lpr -Pname' is used.
1031//
1032Int_t MStatusDisplay::PrintToLpr(Int_t num)
1033{
1034 TString name = "mars";
1035
1036 for (int i=0; i<6; i++)
1037 name += (char)(gRandom->Uniform(25)+65);
1038
1039 name += ".ps";
1040
1041 const Int_t pages = SaveAsPS(num, name);
1042
1043 SetStatusLine1("Printing...");
1044 SetStatusLine2("");
1045
1046 if (!pages)
1047 {
1048 *fLog << warn << "MStatusDisplay::PrintToLpr: Sorry, couldn't save file as temporary postscript!" << endl;
1049 SetStatusLine2("Failed!");
1050 return 0;
1051 }
1052
1053 TString cmd="lpr ";
1054 if (!fPrinter.IsNull())
1055 {
1056 cmd += "-P";
1057 cmd += fPrinter;
1058 cmd += " ";
1059 }
1060 cmd += name;
1061
1062 gSystem->Exec(cmd);
1063 gSystem->Unlink(name);
1064
1065 SetStatusLine2(Form("Done (%dpage(s))", pages));
1066
1067 return pages;
1068}
1069
1070// --------------------------------------------------------------------------
1071//
1072// Remove tab no i if this tab contains a TRootEmbeddedCanvas
1073//
1074void MStatusDisplay::RemoveTab(int i)
1075{
1076 TGCompositeFrame *f = fTab->GetTabContainer(i);
1077 if (!f)
1078 return;
1079
1080 TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(f);
1081 if (!ec)
1082 return;
1083
1084 TCanvas *c = ec->GetCanvas();
1085 if (!c)
1086 return;
1087
1088 const TString name(c->GetName());
1089
1090 f->RemoveFrame(ec);
1091 delete fList->Remove(ec);
1092
1093 fTab->RemoveTab(i);
1094 fTab->SetTab(0);
1095
1096 TGComboBox *box = (TGComboBox*)fList->FindWidget(kTabs);
1097 box->RemoveEntry(i);
1098 for (int j=i; j<box->GetListBox()->GetNumberOfEntries(); j++)
1099 {
1100 TGTextLBEntry *entry = (TGTextLBEntry *)box->GetListBox()->Select(j+1, kFALSE);
1101 box->AddEntry(entry->GetText()->GetString(), j);
1102 box->RemoveEntry(j+1);
1103 }
1104 box->GetListBox()->Select(0);
1105
1106 // Looks strange...
1107 // const Int_t n = fTab->GetNumberOfTabs();
1108 // fTab->SetTab(i<=n-1 ? i : i-1);
1109
1110 // layout and map new tab
1111 Layout(); // seems to layout the TGCompositeFrame
1112 MapSubwindows(); // maps the TGCompositeFrame
1113 Layout(); // layout the embedded canvas in the frame
1114
1115 // display new tab in the main frame
1116 // FIXME: This is a workaround, because TApplication::Run is not
1117 // thread safe against ProcessEvents. We assume, that if
1118 // we are not in the Main-Thread ProcessEvents() is
1119 // called by the TApplication Event Loop...
1120 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
1121 gClient->ProcessEventsFor(fTab);
1122
1123 *fLog << inf << "Removed Tab #" << i << " '" << name << "'" << endl;
1124}
1125
1126// --------------------------------------------------------------------------
1127//
1128// Use this to check whether the MStatusDisplay still contains the
1129// TCanvas c. It could be removed meanwhile by menu usage.
1130//
1131Bool_t MStatusDisplay::HasCanvas(const TCanvas *c) const
1132{
1133 if (!c)
1134 return kFALSE;
1135
1136 if (gROOT->IsBatch())
1137 return (Bool_t)fBatch->FindObject(c);
1138
1139 for (int i=1; i<fTab->GetNumberOfTabs(); i++)
1140 if (c==GetCanvas(i))
1141 return kTRUE;
1142 return kFALSE;
1143}
1144
1145/*
1146 if (...)
1147 fMenu->AddPopup("&CaOs", fCaOs, NULL);
1148 else
1149 fMenu->RemovePopup("CaOs");
1150 fMenu->Resize(fMenu->GetDefaultSize());
1151 MapSubwindows();
1152 MapWindow();
1153 */
1154
1155void MStatusDisplay::Reset()
1156{
1157 if (gROOT->IsBatch())
1158 {
1159 fBatch->Delete();
1160 return;
1161 }
1162
1163 for (int i=fTab->GetNumberOfTabs()-1; i>0; i--)
1164 RemoveTab(i);
1165}
1166
1167// --------------------------------------------------------------------------
1168//
1169// Process the kC_COMMAND, kCM_MENU messages
1170//
1171Bool_t MStatusDisplay::ProcessMessageCommandMenu(Long_t id)
1172{
1173 switch (id)
1174 {
1175 case kLoopStop:
1176 case kFileClose:
1177 case kFileExit:
1178 if (id==kFileExit || id==kFileClose)
1179 CloseWindow();
1180 fStatus = (Status_t)id;
1181 return kTRUE;
1182
1183 case kFileCanvas:
1184 new TCanvas;
1185 return kTRUE;
1186
1187 case kFileBrowser:
1188 new TBrowser;
1189 return kTRUE;
1190
1191 case kFileReset:
1192 Reset();
1193 return kTRUE;
1194
1195 case kFileOpen:
1196 Open();
1197 return kTRUE;
1198
1199 case kFileSaveAs:
1200 SaveAs();
1201 return kTRUE;
1202
1203 case kFileSaveAsPS:
1204 SaveAsPS();
1205 return kTRUE;
1206
1207 case kFileSaveAsGIF:
1208 SaveAsGIF();
1209 return kTRUE;
1210
1211 case kFileSaveAsC:
1212 SaveAsC();
1213 return kTRUE;
1214
1215 case kFileSaveAsRoot:
1216 SaveAsRoot();
1217 return kTRUE;
1218
1219 case kFilePrint:
1220 PrintToLpr();
1221 return kTRUE;
1222
1223 case kTabSaveAs:
1224 SaveAs(fTab->GetCurrent());
1225 return kTRUE;
1226
1227 case kTabSaveAsPS:
1228 SaveAsPS(fTab->GetCurrent());
1229 return kTRUE;
1230
1231 case kTabSaveAsGIF:
1232 SaveAsGIF(fTab->GetCurrent());
1233 return kTRUE;
1234
1235 case kTabSaveAsC:
1236 SaveAsC(fTab->GetCurrent());
1237 return kTRUE;
1238
1239 case kTabSaveAsRoot:
1240 SaveAsRoot(fTab->GetCurrent());
1241 return kTRUE;
1242
1243 case kTabPrint:
1244 PrintToLpr(fTab->GetCurrent());
1245 return kTRUE;
1246
1247 case kTabNext:
1248 fTab->SetTab(fTab->GetCurrent()+1);
1249 return kTRUE;
1250
1251 case kTabPrevious:
1252 fTab->SetTab(fTab->GetCurrent()-1);
1253 return kTRUE;
1254
1255 case kTabRemove:
1256 RemoveTab(fTab->GetCurrent());
1257 return kTRUE;
1258
1259 case kSize640:
1260 Resize(570, 480);
1261 return kTRUE;
1262 case kSize800:
1263 Resize(740, 600);
1264 return kTRUE;
1265 case kSize960:
1266 Resize(880, 700);
1267 return kTRUE;
1268 case kSize1024:
1269 Resize(980, 768);
1270 return kTRUE;
1271 case kSize1280:
1272 Resize(1280, 980);
1273 return kTRUE;
1274
1275 case kLogClear:
1276 fLogBox->Clear();
1277 return kTRUE;
1278 case kLogCopy:
1279 fLogBox->Copy();
1280 return kTRUE;
1281 case kLogSelect:
1282 fLogBox->SelectAll();
1283 return kTRUE;
1284 case kLogFind:
1285 new MSearch(this);
1286 return kTRUE;
1287 case kLogSave:
1288 SetStatusLine1("Saving log...");
1289 SetStatusLine2("");
1290 *fLog << inf << "Saving log... " << flush;
1291 if (fLogBox->GetText()->Save("statusdisplay.log"))
1292 {
1293 *fLog << "done." << endl;
1294 SetStatusLine2("done.");
1295 }
1296 else
1297 {
1298 *fLog << "failed!" << endl;
1299 SetStatusLine2("Failed!");
1300 }
1301 return kTRUE;
1302
1303 case kLogAppend:
1304 SetStatusLine1("Appending logg...");
1305 SetStatusLine2("");
1306 *fLog << inf << "Appending log... " << flush;
1307 if (fLogBox->GetText()->Append("statusdisplay.log"))
1308 {
1309 *fLog << "done." << endl;
1310 SetStatusLine2("done.");
1311 }
1312 else
1313 {
1314 *fLog << "failed!" << endl;
1315 SetStatusLine2("Failed!");
1316 }
1317 return kTRUE;
1318#ifdef DEBUG
1319 default:
1320 cout << "Command-Menu #" << id << endl;
1321#endif
1322 }
1323 return kTRUE;
1324
1325}
1326
1327// --------------------------------------------------------------------------
1328//
1329// Process the kC_COMMAND messages
1330//
1331Bool_t MStatusDisplay::ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2)
1332{
1333 switch (submsg)
1334 {
1335 case kCM_MENU: // 1
1336 return ProcessMessageCommandMenu(mp1); // mp2=userdata
1337 case kCM_TAB: // 8
1338 /*
1339 for (int i=0; i<fTab->GetNumberOfTabs(); i++)
1340 fTab->GetTabContainer(i)->UnmapWindow();
1341 */
1342 UpdateTab(fTab->GetTabContainer(mp1));
1343 //fTab->GetTabContainer(mp1)->MapWindow();
1344
1345 /*
1346 if (mp1>0)
1347 fMenu->AddPopup("&CaOs", fCaOs, NULL);
1348 else
1349 fMenu->RemovePopup("CaOs");
1350 fMenu->Resize(fMenu->GetDefaultSize());
1351 MapSubwindows();
1352 MapWindow();
1353 */
1354 return kTRUE;
1355 case kCM_COMBOBOX: // 7
1356 if (mp1==kTabs)
1357 fTab->SetTab(mp2);
1358 return kTRUE;
1359#ifdef DEBUG
1360 case kCM_MENUSELECT: // 2
1361 cout << "Command-Menuselect #" << mp1 << " (UserData=" << (void*)mp2 << ")" << endl;
1362 return kTRUE;
1363
1364 case kCM_BUTTON: // 3
1365 cout << "Command-Button." << endl;
1366 return kTRUE;
1367
1368 case kCM_CHECKBUTTON: // 4
1369 cout << "Command-CheckButton." << endl;
1370 return kTRUE;
1371
1372 case kCM_RADIOBUTTON: // 5
1373 cout << "Command-RadioButton." << endl;
1374 return kTRUE;
1375
1376 case kCM_LISTBOX: // 6
1377 cout << "Command-Listbox #" << mp1 << " (LineId #" << mp2 << ")" << endl;
1378 return kTRUE;
1379 default:
1380 cout << "Command: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1381#endif
1382 }
1383 return kTRUE;
1384}
1385
1386// --------------------------------------------------------------------------
1387//
1388// Process the kC_TEXTVIEW messages
1389//
1390Bool_t MStatusDisplay::ProcessMessageTextview(Long_t submsg, Long_t mp1, Long_t mp2)
1391{
1392 // kC_TEXTVIEW, kTXT_ISMARKED, widget id, [true|false] //
1393 // kC_TEXTVIEW, kTXT_DATACHANGE, widget id, 0 //
1394 // kC_TEXTVIEW, kTXT_CLICK2, widget id, position (y << 16) | x) //
1395 // kC_TEXTVIEW, kTXT_CLICK3, widget id, position (y << 16) | x) //
1396 // kC_TEXTVIEW, kTXT_F3, widget id, true //
1397 // kC_TEXTVIEW, kTXT_OPEN, widget id, 0 //
1398 // kC_TEXTVIEW, kTXT_CLOSE, widget id, 0 //
1399 // kC_TEXTVIEW, kTXT_SAVE, widget id, 0 //
1400#ifdef DEBUG
1401 switch (submsg)
1402 {
1403 case kTXT_ISMARKED:
1404 cout << "Textview-IsMarked #" << mp1 << " " << (mp2?"yes":"no") << endl;
1405 return kTRUE;
1406
1407 case kTXT_DATACHANGE:
1408 cout << "Textview-DataChange #" << mp1 << endl;
1409 return kTRUE;
1410
1411 case kTXT_CLICK2:
1412 cout << "Textview-Click2 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
1413 return kTRUE;
1414
1415 case kTXT_CLICK3:
1416 cout << "Textview-Click3 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
1417 return kTRUE;
1418
1419 case kTXT_F3:
1420 cout << "Textview-F3 #" << mp1 << endl;
1421 return kTRUE;
1422
1423 case kTXT_OPEN:
1424 cout << "Textview-Open #" << mp1 << endl;
1425 return kTRUE;
1426
1427 case kTXT_CLOSE:
1428 cout << "Textview-Close #" << mp1 << endl;
1429 return kTRUE;
1430
1431 case kTXT_SAVE:
1432 cout << "Textview-Save #" << mp1 << endl;
1433 return kTRUE;
1434
1435 default:
1436 cout << "Textview: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1437 }
1438#endif
1439 return kTRUE;
1440}
1441
1442// --------------------------------------------------------------------------
1443//
1444// Process the kC_USER messages
1445//
1446Bool_t MStatusDisplay::ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2)
1447{
1448 // kS_START, case sensitive | backward<<1, char *txt
1449 switch (submsg)
1450 {
1451 case kS_START:
1452 fLogBox->Search((char*)mp2, !(mp1&2>>1), mp1&1);
1453 return kTRUE;
1454#ifdef DEBUG
1455 default:
1456 cout << "User: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1457#endif
1458 }
1459 return kTRUE;
1460}
1461
1462// --------------------------------------------------------------------------
1463//
1464// Process the messages from the GUI
1465//
1466Bool_t MStatusDisplay::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2)
1467{
1468 // Can be found in WidgetMessageTypes.h
1469#ifdef DEBUG
1470 cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
1471 cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1472#endif
1473 switch (GET_MSG(msg))
1474 {
1475 case kC_COMMAND: // 1
1476 return ProcessMessageCommand(GET_SUBMSG(msg), mp1, mp2);
1477
1478 case kC_TEXTVIEW: // 9
1479 return ProcessMessageTextview(GET_SUBMSG(msg), mp1, mp2);
1480
1481 case kC_USER: // 1001
1482 return ProcessMessageUser(GET_SUBMSG(msg), mp1, mp2);
1483 }
1484#ifdef DEBUG
1485 cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
1486 cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1487#endif
1488 return kTRUE;
1489}
1490
1491void MStatusDisplay::CloseWindow()
1492{
1493 // Got close message for this MainFrame. Calls parent CloseWindow()
1494 // (which destroys the window) and terminate the application.
1495 // The close message is generated by the window manager when its close
1496 // window menu item is selected.
1497
1498 // CloseWindow must be overwritten because otherwise CloseWindow
1499 // and the destructor are calling DestroyWindow which seems to be
1500 // in conflict with the TRootEmbeddedCanvas.
1501
1502 // FIXME: Make sure that the Status Display is deleted from every
1503 // where (eg Eventloop) first!
1504
1505 //gLog << dbg << fName << " is on heap: " << (int)IsOnHeap() << endl;
1506
1507 if (TestBit(kExitLoopOnExit) || TestBit(kExitLoopOnClose))
1508 {
1509 //gLog << dbg << "CloseWindow() calling ExitLoop." << endl;
1510 gSystem->ExitLoop();
1511 }
1512
1513 if (fIsLocked<=0 && IsOnHeap())
1514 {
1515 //gLog << dbg << "delete " << fName << ";" << endl;
1516 delete this;
1517 // DO NOT EXECUTE ANY COMMAND AFTER this!
1518 }
1519 else
1520 {
1521 fStatus = kFileExit;
1522 //gLog << dbg << fName << ".fStatus=kFileExit;" << endl;
1523 }
1524}
1525
1526// --------------------------------------------------------------------------
1527//
1528// Calls SetBit(kNoContextMenu) for all TCanvas objects found in the
1529// Tabs.
1530//
1531void MStatusDisplay::SetNoContextMenu(Bool_t flag)
1532{
1533 if (fIsLocked>1 || gROOT->IsBatch())
1534 return;
1535
1536 flag ? SetBit(kNoContextMenu) : ResetBit(kNoContextMenu);
1537
1538 for (int i=1; i<fTab->GetNumberOfTabs(); i++)
1539 {
1540 TCanvas *c = GetCanvas(i);
1541 if (c)
1542 flag ? c->SetBit(kNoContextMenu) : c->ResetBit(kNoContextMenu);
1543 }
1544}
1545
1546// --------------------------------------------------------------------------
1547//
1548// Updates the canvas (if existing) in the currenly displayed Tab.
1549// The update intervall is controlled by StartUpdate and StopUpdate
1550//
1551Bool_t MStatusDisplay::HandleTimer(TTimer *timer)
1552{
1553 if (gROOT->IsBatch())
1554 return kTRUE;
1555
1556 const Int_t c = fTab->GetCurrent();
1557
1558 // Skip Legend Tab
1559 if (c==0)
1560 return kTRUE;
1561
1562 // Update a canvas tab (if visible)
1563 if (timer==&fTimer && c!=fLogIdx)
1564 {
1565 UpdateTab(fTab->GetCurrentContainer());
1566 return kTRUE;
1567 }
1568
1569 // update the logbook tab (if visible)
1570 if (timer==&fLogTimer && c==fLogIdx)
1571 {
1572 fLog->UpdateGui();
1573
1574 /*
1575 if (!fLogBox->TestBit(kHasChanged))
1576 return kTRUE;
1577
1578 fLogBox->ResetBit(kHasChanged);
1579 */
1580 return kTRUE;
1581 }
1582
1583 return kTRUE;
1584}
1585
1586// --------------------------------------------------------------------------
1587//
1588// Draws a clone of a canvas into a new canvas. Taken from TCanvas.
1589//
1590void MStatusDisplay::DrawClonePad(TCanvas &newc, const TCanvas &oldc) const
1591{
1592 //copy pad attributes
1593 newc.Range(oldc.GetX1(),oldc.GetY1(),oldc.GetX2(),oldc.GetY2());
1594 newc.SetTickx(oldc.GetTickx());
1595 newc.SetTicky(oldc.GetTicky());
1596 newc.SetGridx(oldc.GetGridx());
1597 newc.SetGridy(oldc.GetGridy());
1598 newc.SetLogx(oldc.GetLogx());
1599 newc.SetLogy(oldc.GetLogy());
1600 newc.SetLogz(oldc.GetLogz());
1601 newc.SetBorderSize(oldc.GetBorderSize());
1602 newc.SetBorderMode(oldc.GetBorderMode());
1603 ((TAttLine&)oldc).Copy((TAttLine&)newc);
1604 ((TAttFill&)oldc).Copy((TAttFill&)newc);
1605 ((TAttPad&)oldc).Copy((TAttPad&)newc);
1606
1607 //copy primitives
1608 TObject *obj;
1609 TIter next(oldc.GetListOfPrimitives());
1610 while ((obj=next())) {
1611 gROOT->SetSelectedPad(&newc);
1612 newc.GetListOfPrimitives()->Add(obj->Clone(),obj->GetDrawOption());
1613 }
1614 newc.Modified();
1615 newc.Update();
1616}
1617
1618Bool_t MStatusDisplay::Display(const TObjArray &list)
1619{
1620 TIter Next(&list);
1621
1622 TObject *o=Next();
1623 if (!o)
1624 {
1625 *fLog << err << "MStatusDisplay::Display: No entry in TObjArray." << endl;
1626 return kFALSE;
1627 }
1628
1629 fTitle = o->GetTitle();
1630
1631 TCanvas *c;
1632 while ((c=(TCanvas*)Next()))
1633 if (!GetCanvas(c->GetName()))
1634 DrawClonePad(AddTab(c->GetName()), *c);
1635
1636 return kTRUE;
1637}
1638
1639// --------------------------------------------------------------------------
1640//
1641// Reads the contents of a saved MStatusDisplay from a file.
1642//
1643Int_t MStatusDisplay::Read(const char *name)
1644{
1645 if (!gFile)
1646 {
1647 *fLog << warn << "MStatusDisplay::Read: No file found. Please create a TFile first." << endl;
1648 return 0;
1649 }
1650
1651 if (!gFile->IsOpen())
1652 {
1653 *fLog << warn << "MStatusDisplay::Read: File not open. Please open the TFile first." << endl;
1654 return 0;
1655 }
1656
1657 MStatusArray list;
1658
1659 const Int_t n = list.Read(name);
1660 if (n==0)
1661 {
1662 *fLog << warn << "MStatusDisplay::Read: No objects read." << endl;
1663 return 0;
1664 }
1665
1666 if (!Display(list))
1667 {
1668 *fLog << err << "MStatusDisplay::Display: No entry in " << name << "." << endl;
1669 return 0;
1670 }
1671
1672 *fLog << inf << "MStatusDisplay: Key " << name << " with " << n << " keys read from file." << endl;
1673
1674 return n;
1675}
1676
1677// --------------------------------------------------------------------------
1678//
1679// Writes the contents of a MStatusDisplay to a file.
1680//
1681Int_t MStatusDisplay::Write(Int_t num, const char *name, Int_t option, Int_t bufsize)
1682{
1683 if (!gFile)
1684 {
1685 *fLog << warn << "MStatusDisplay::Write: No file found. Please create a TFile first." << endl;
1686 return 0;
1687 }
1688
1689 if (!gFile->IsOpen())
1690 {
1691 *fLog << warn << "MStatusDisplay::Write: File not open. Please open the TFile first." << endl;
1692 return 0;
1693 }
1694
1695 if (!gFile->IsWritable())
1696 {
1697 *fLog << warn << "MStatusDisplay::Write: File not writable." << endl;
1698 return 0;
1699 }
1700
1701 if (num==0)
1702 {
1703 *fLog << warn << "MStatusDisplay::Write: Tab doesn't contain an embedded Canvas... skipped." << endl;
1704 return 0;
1705 }
1706
1707 if (!gROOT->IsBatch() && num>=fTab->GetNumberOfTabs())
1708 {
1709 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
1710 return 0;
1711 }
1712 if (gROOT->IsBatch() && num>fBatch->GetSize())
1713 {
1714 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
1715 return 0;
1716 }
1717
1718 MStatusArray list;
1719
1720 TNamed named;
1721 named.SetTitle(fTitle);
1722 list.Add(&named);
1723
1724 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
1725 const Int_t from = num<0 ? 1 : num;
1726 const Int_t to = num<0 ? max : num+1;
1727
1728 TCanvas *c;
1729 for (int i=from; i<to; i++)
1730 if ((c = GetCanvas(i)))
1731 list.Add(c);
1732
1733 const Int_t n = list.Write(name, kSingleKey);
1734
1735 //*fLog << inf << "MStatusDisplay: " << n << " keys written to file as key " << name << "." << endl;
1736
1737 return n;
1738}
1739
1740// --------------------------------------------------------------------------
1741//
1742// Use this to start the synchronous (GUI eventloop driven) tab update.
1743// Can also be used to change the update intervall. If millisec<0
1744// the intervall given in SetUpdateTime is used. If the intervall in
1745// SetUpdateTime is <0 nothing is done. (Call SetUpdateTime(-1) to
1746// disable the automatic update in a MEventloop.
1747//
1748void MStatusDisplay::StartUpdate(Int_t millisec)
1749{
1750 if (fIsLocked>1)
1751 return;
1752
1753 if (fTimer.GetTime()<TTime(0))
1754 return;
1755 fTimer.Start(millisec);
1756}
1757
1758// --------------------------------------------------------------------------
1759//
1760// Stops the automatic GUI update
1761//
1762void MStatusDisplay::StopUpdate()
1763{
1764 if (fIsLocked>1)
1765 return;
1766
1767 fTimer.Stop();
1768}
1769
1770// --------------------------------------------------------------------------
1771//
1772// Set the update interval for the GUI update, see StartUpdate.
1773//
1774void MStatusDisplay::SetUpdateTime(Long_t t)
1775{
1776 fTimer.SetTime(t);
1777}
1778
1779// --------------------------------------------------------------------------
1780//
1781// Set the background color in a canvas
1782//
1783void MStatusDisplay::CanvasSetFillColor(TPad &p, Int_t col) const
1784{
1785 TObject *obj;
1786
1787 // See also TPad::UseCurrentStyle
1788 TIter Next(p.GetListOfPrimitives());
1789 while ((obj=Next()))
1790 {
1791 if (obj->InheritsFrom(TPad::Class()))
1792 CanvasSetFillColor(*(TPad*)obj, col);
1793 if (obj->InheritsFrom(TFrame::Class()))
1794 ((TFrame*)obj)->SetFillColor(col);
1795 }
1796
1797 p.SetFillColor(col);
1798}
1799
1800void MStatusDisplay::AddExtension(TString &name, const TString &ext, Int_t num) const
1801{
1802 if (name.IsNull())
1803 {
1804 name = "status";
1805 if (num>0)
1806 {
1807 name += "-";
1808 name += num;
1809 }
1810 }
1811
1812 if (name.EndsWith("."+ext))
1813 return;
1814
1815 name += ".";
1816 name += ext;
1817}
1818
1819Bool_t MStatusDisplay::CheckTabForCanvas(int num) const
1820{
1821 if (gROOT->IsBatch())
1822 return num>0 && num<=fBatch->GetSize() || num<0;
1823
1824 if (num>=fTab->GetNumberOfTabs())
1825 {
1826 *fLog << warn << "Tab #" << num << " doesn't exist..." << endl;
1827 return kFALSE;
1828 }
1829 if (num==0)
1830 {
1831 *fLog << warn << "Tab #" << num << " doesn't contain an embedded canvas..." << endl;
1832 return kFALSE;
1833 }
1834 if (fTab->GetNumberOfTabs()<2 || !gPad)
1835 {
1836 *fLog << warn << "Sorry, you must have at least one existing canvas (gPad!=NULL)" << endl;
1837 return kFALSE;
1838 }
1839 return kTRUE;
1840}
1841
1842// --------------------------------------------------------------------------
1843//
1844// Insert the following two lines into the postscript header:
1845//
1846// %%DocumentPaperSizes: a4
1847// %%Orientation: Landscape
1848//
1849void MStatusDisplay::UpdatePSHeader(const TString &name) const
1850{
1851 const TString newstr("%%DocumentPaperSizes: a4\n%%Orientation: Landscape\n");
1852
1853 ifstream fin(name);
1854 ofstream fout(name+".$$$");
1855
1856 char c;
1857
1858 TString str;
1859 fin >> str >> c; // Read "%!PS-Adobe-2.0\n"
1860 fout << str << endl << newstr;
1861
1862 // Doing it in blocks seems not to gain much for small (MB) files
1863 while (fin)
1864 {
1865 fin.read(&c, 1);
1866 fout.write(&c, 1);
1867 }
1868
1869 gSystem->Unlink(name);
1870 gSystem->Rename(name+".$$$", name);
1871/*
1872 //
1873 // Old style algorithm. Shifts blocks inside a single file --- SLOW!
1874 //
1875 const Int_t l = newstr.Length();
1876
1877 Long_t t[4]; // { id, size, flags, modtime }
1878 gSystem->GetPathInfo(name, t, t+1, t+2, t+3);
1879
1880 char *c[2] = { new char[l], new char[l] };
1881
1882 fstream f(name, ios::in|ios::out);
1883
1884 TString str;
1885 f >> str >> c[0][0]; // Read "%!PS-Adobe-2.0\n" (Mini Header)
1886 f.read(c[0], l);
1887 f.seekp(-l, ios::cur);
1888 f.write(newstr, l);
1889
1890 int i=0;
1891 while (1)
1892 {
1893 f.read(c[(i+1)%2], l);
1894 f.seekp(-l, ios::cur);
1895
1896 if (f)
1897 {
1898 f.write(c[i%2],l);
1899 i++;
1900 i%=2;
1901 continue;
1902 }
1903
1904 const Int_t ssz = str.Length()+1; // Length of Mini-Header
1905 const Int_t block = t[1]-ssz; // Length of block to be shifted
1906 const Int_t size = block%l; // Reminder
1907 const Int_t pos = (block/l)*l + ssz + 1; // Position to start writing
1908
1909 f.clear();
1910 f.seekp(pos);
1911 f.write(c[i%2], l);
1912 f.write(c[(i+1)%2], size);
1913 break;
1914 }
1915
1916 delete c[1];
1917 delete c[0];
1918*/
1919}
1920
1921// --------------------------------------------------------------------------
1922//
1923// In case of num<0 all tabs are written into the PS file. If num>0
1924// the canvas in the corresponding tab is written to the file.
1925// Name is the name of the file (with or without extension).
1926//
1927// Returns the number of pages written.
1928//
1929// To write all tabs you can also use SaveAsPS(name)
1930//
1931// If the third argument is given a bottom line is drawn with the text
1932// under it. If no argument is given a bottom line is drawn if
1933// fTitle (SetTitle) is not empty.
1934//
1935Int_t MStatusDisplay::SaveAsPS(Int_t num, TString name, const TString addon)
1936{
1937 SetStatusLine1("Writing Postscript file...");
1938 SetStatusLine2("");
1939
1940 if (!CheckTabForCanvas(num))
1941 {
1942 SetStatusLine2("Failed!");
1943 return 0;
1944 }
1945
1946 AddExtension(name, "ps", num);
1947
1948 if (num<0)
1949 *fLog << inf << "Open ps-File: " << name << endl;
1950
1951 TPad *padsav = (TPad*)gPad;
1952 TVirtualPS *psave = gVirtualPS;
1953
1954 TDatime d;
1955
1956 TPostScript ps(name, 112);
1957 ps.SetBit(TPad::kPrintingPS);
1958 ps.PrintFast(13, "/nan {1} def ");
1959
1960 gVirtualPS = &ps;
1961
1962 //
1963 // Create a list to delete the canvas clones
1964 //
1965 TList l;
1966 l.SetOwner();
1967
1968 //
1969 // Create some GUI elements for a page legend
1970 //
1971 TLine line;
1972
1973 int page = 1;
1974
1975 //
1976 // Maintain tab numbers
1977 //
1978 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
1979 const Int_t from = num<0 ? 1 : num;
1980 const Int_t to = num<0 ? max : num+1;
1981
1982 for (int i=from; i<to; i++)
1983 {
1984 TCanvas *c;
1985 if (!(c = GetCanvas(i)))
1986 {
1987 if (num<0)
1988 *fLog << inf << " - ";
1989 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
1990 continue;
1991 }
1992
1993 SetStatusLine2(Form("Tab #%d", i));
1994
1995 //
1996 // Init page and page size, make sure, that the canvas in the file
1997 // has the same Aspect Ratio than on the screen.
1998 //
1999 ps.NewPage();
2000
2001 //
2002 // 28 is used here to scale the canvas into a height of 28,
2003 // such that the page title can be set above the canvas...
2004 //
2005 Float_t psw = 28.0; // A4 - width (29.7)
2006 Float_t psh = 21.0; // A4 - height (21.0)
2007
2008 const Float_t cw = c->GetWw();
2009 const Float_t ch = c->GetWh();
2010
2011 if (psw/psh>cw/ch)
2012 psw = cw/ch*psh;
2013 else
2014 psh = ch/cw*psw;
2015
2016 ps.Range(psw, psh); // A4
2017
2018 //
2019 // Clone canvas and change background color and schedule for
2020 // deletion
2021 //
2022 TCanvas *n = (TCanvas*)c->Clone();
2023 CanvasSetFillColor(*n, kWhite);
2024 l.Add(n);
2025
2026 //
2027 // Paint canvas into root file
2028 //
2029 if (num<0)
2030 *fLog << inf << " - ";
2031 *fLog << inf << "Writing Tab #" << i << ": " << c->GetName() << " (" << c << ") ";
2032 if (num>0)
2033 *fLog << "to " << name;
2034 *fLog << "... " << flush;
2035
2036 n->SetBatch(kTRUE);
2037 n->Paint();
2038
2039 //
2040 // Use the canvas as coordinate system for the overlaying text
2041 //
2042 gPad = n;
2043 //n->cd();
2044
2045 //
2046 // Print overlaying text (NDC = %)
2047 //
2048 ps.SetTextColor(kBlack);
2049 ps.SetTextSize(0.015);
2050 ps.SetTextFont(22);
2051 ps.SetTextAlign(11); // left top
2052 ps.TextNDC(0, 1.015, TString(" ")+n->GetName());
2053 ps.SetTextAlign(21); // cent top
2054 ps.TextNDC(0.5, 1.015, TString("MARS - Magic Analysis and Reconstruction Software - ")+d.AsString());
2055 ps.SetTextAlign(31); // right top
2056 ps.TextNDC(1, 1.015, Form("Page No.%i (%i) ", page++, i));
2057 line.PaintLineNDC(0, 1.01, 1, 1.01);
2058
2059 TString txt(addon.IsNull() ? fTitle : addon);
2060 if (!txt.IsNull())
2061 {
2062 line.PaintLineNDC(0, -0.00, 1, -0.00);
2063 ps.SetTextAlign(11); // left top
2064 ps.TextNDC(0, -0.015, TString(" ")+txt);
2065 ps.SetTextAlign(31); // right top
2066 ps.TextNDC(1, -0.015, "(c) 2000-2004, Thomas Bretz ");
2067 }
2068
2069 //
2070 // Finish drawing page
2071 //
2072 n->SetBatch(kFALSE);
2073 *fLog << "done." << endl;
2074 }
2075
2076 gPad = NULL; // Important!
2077 l.Delete();
2078
2079 ps.Close();
2080
2081 SetStatusLine2("Updating header of PS file...");
2082
2083 if (num<0)
2084 *fLog << " - Updating header of PS file... " << flush;
2085 UpdatePSHeader(name);
2086 if (num<0)
2087 *fLog << inf << "done." << endl;
2088
2089 gVirtualPS = psave;
2090 if (padsav)
2091 padsav->cd();
2092
2093 if (num<0)
2094 *fLog << inf << "done." << endl;
2095
2096 SetStatusLine2(Form("Done (%dpages)", page-1));
2097
2098 return page-1;
2099}
2100
2101Bool_t MStatusDisplay::SaveAsGIF(Int_t num, TString name)
2102{
2103 if (gROOT->IsBatch())
2104 {
2105 *fLog << warn << "Sorry, writing gif-files is not available in batch mode." << endl;
2106 return 0;
2107 }
2108 SetStatusLine1("Writing GIF file...");
2109 SetStatusLine2("");
2110
2111 if (!CheckTabForCanvas(num))
2112 {
2113 SetStatusLine2("Failed!");
2114 return 0;
2115 }
2116
2117 AddExtension(name, "gif", num);
2118
2119 if (num<0)
2120 *fLog << inf << "Writing gif-Files..." << endl;
2121
2122 TPad *padsav = (TPad*)gPad;
2123
2124 int page = 1;
2125
2126 //
2127 // Maintain tab numbers
2128 //
2129 const Int_t from = num<0 ? 1 : num;
2130 const Int_t to = num<0 ? fTab->GetNumberOfTabs() : num+1;
2131
2132 for (int i=from; i<to; i++)
2133 {
2134 TCanvas *c;
2135 if (!(c = GetCanvas(i)))
2136 {
2137 if (num<0)
2138 *fLog << inf << " - ";
2139 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
2140 continue;
2141 }
2142
2143 SetStatusLine2(Form("Tab #%d", i));
2144
2145 //
2146 // Clone canvas and change background color and schedule for
2147 // deletion
2148 //
2149 //TCanvas *n = (TCanvas*)c->Clone();
2150 //CanvasSetFillColor(*n, kWhite);
2151
2152 //
2153 // Paint canvas into root file
2154 //
2155 TString writename = name;
2156 if (num<0)
2157 {
2158 TString numname = "-";
2159 numname += i;
2160 writename.Insert(name.Last('.'), numname);
2161 }
2162 if (num<0)
2163 *fLog << inf << " - ";
2164 *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << c << ") ";
2165 if (num>0)
2166 *fLog << "to " << name;
2167 *fLog << "..." << flush;
2168
2169 c->Draw();
2170 c->SaveAs(writename);
2171 /*
2172 n->Draw();
2173 n->SaveAs(writename);
2174 delete n;
2175 */
2176
2177 if (num<0)
2178 *fLog << "done." << endl;
2179 }
2180
2181 padsav->cd();
2182
2183 *fLog << inf << "done." << endl;
2184
2185 SetStatusLine2("Done.");
2186
2187 return page-1;
2188}
2189
2190Bool_t MStatusDisplay::SaveAsC(Int_t num, TString name)
2191{
2192 SetStatusLine1("Writing C++ file...");
2193 SetStatusLine2("");
2194
2195 if (!CheckTabForCanvas(num))
2196 {
2197 SetStatusLine2("Failed!");
2198 return 0;
2199 }
2200
2201 AddExtension(name, "C", num);
2202
2203 if (num<0)
2204 *fLog << inf << "Writing C-Files..." << endl;
2205
2206 TPad *padsav = (TPad*)gPad;
2207
2208 int page = 1;
2209
2210 //
2211 // Maintain tab numbers
2212 //
2213 const Int_t from = num<0 ? 1 : num;
2214 const Int_t to = num<0 ? fTab->GetNumberOfTabs() : num+1;
2215
2216 for (int i=from; i<to; i++)
2217 {
2218 TCanvas *c;
2219 if (!(c = GetCanvas(i)))
2220 {
2221 if (num<0)
2222 *fLog << inf << " - ";
2223 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
2224 continue;
2225 }
2226
2227 SetStatusLine2(Form("Tab #%d", i));
2228
2229 //
2230 // Clone canvas and change background color and schedule for
2231 // deletion
2232 //
2233 TCanvas *n = (TCanvas*)c->Clone();
2234 CanvasSetFillColor(*n, kWhite);
2235
2236 //
2237 // Paint canvas into root file
2238 //
2239 TString writename = name;
2240 if (num<0)
2241 {
2242 TString numname = "-";
2243 numname += i;
2244 writename.Insert(name.Last('.'), numname);
2245 }
2246 if (num<0)
2247 *fLog << inf << " - ";
2248 *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << n << ") ";
2249 if (num>0)
2250 *fLog << "to " << name;
2251 *fLog << "..." << flush;
2252
2253 n->SaveSource(writename, "");
2254 delete n;
2255
2256 if (num<0)
2257 *fLog << "done." << endl;
2258 }
2259
2260 padsav->cd();
2261
2262 *fLog << inf << "done." << endl;
2263
2264 SetStatusLine2("Done.");
2265
2266 return page-1;
2267}
2268
2269// --------------------------------------------------------------------------
2270//
2271// In case of num<0 all tabs are written into the PS file. If num>0
2272// the canvas in the corresponding tab is written to the file.
2273// Name is the name of the file (with or without extension).
2274//
2275// Returns the number of keys written.
2276//
2277// To write all tabs you can also use SaveAsPS(name)
2278//
2279Int_t MStatusDisplay::SaveAsRoot(Int_t num, TString name)
2280{
2281 SetStatusLine1("Writing root file...");
2282 SetStatusLine2("");
2283
2284 if (!CheckTabForCanvas(num))
2285 {
2286 SetStatusLine2("Failed!");
2287 return 0;
2288 }
2289
2290 AddExtension(name, "root", num);
2291
2292 TFile *fsave = gFile;
2293 TFile file(name, "RECREATE", "MARS - Status Window Contents", 9);
2294 const Int_t keys = Write(num);
2295 gFile = fsave;
2296
2297 SetStatusLine2("Done.");
2298
2299 return keys;
2300}
2301
2302// --------------------------------------------------------------------------
2303//
2304// Opens a save as dialog
2305//
2306Int_t MStatusDisplay::SaveAs(Int_t num)
2307{
2308 static const char *gSaveAsTypes[] =
2309 {
2310 "PostScript", "*.ps",
2311 "Gif files", "*.gif",
2312 "Macro files", "*.C",
2313 "ROOT files", "*.root",
2314 "All files", "*",
2315 NULL, NULL
2316 };
2317
2318 static TString dir(".");
2319
2320 TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
2321
2322 fi.fFileTypes = (const char**)gSaveAsTypes;
2323 fi.fIniDir = StrDup(dir);
2324
2325 new TGFileDialog(fClient->GetRoot(), this, kFDSave, &fi);
2326
2327 if (!fi.fFilename)
2328 return 0;
2329
2330 dir = fi.fIniDir;
2331
2332 const TString name(fi.fFilename);
2333
2334 if (name.EndsWith(".root")) return SaveAsRoot(num, name);
2335 if (name.EndsWith(".ps")) return SaveAsPS(num, name);
2336 if (name.EndsWith(".gif")) return SaveAsGIF(num, name);
2337 if (name.EndsWith(".C")) return SaveAsC(num, name);
2338
2339 Warning("MStatusDisplay::SaveAs", "Unknown Extension: %s", fi.fFilename);
2340 return 0;
2341}
2342
2343// --------------------------------------------------------------------------
2344//
2345// Open contents of a MStatusDisplay with key name from file fname.
2346//
2347Int_t MStatusDisplay::Open(TString fname, const char *name)
2348{
2349 TFile file(fname, "READ");
2350 if (file.IsZombie())
2351 {
2352 gLog << warn << "WARNING - Cannot open file " << fname << endl;
2353 return 0;
2354 }
2355
2356 return Read(name);
2357}
2358
2359// --------------------------------------------------------------------------
2360//
2361// Opens an open dialog
2362//
2363Int_t MStatusDisplay::Open()
2364{
2365 static const char *gOpenTypes[] =
2366 {
2367 "ROOT files", "*.root",
2368 "All files", "*",
2369 NULL, NULL
2370 };
2371
2372 static TString dir(".");
2373
2374 TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
2375
2376 fi.fFileTypes = (const char**)gOpenTypes;
2377 fi.fIniDir = StrDup(dir);
2378
2379 new TGFileDialog(fClient->GetRoot(), this, kFDSave, &fi);
2380
2381 if (!fi.fFilename)
2382 return 0;
2383
2384 dir = fi.fIniDir;
2385
2386 return Open(fi.fFilename);
2387}
2388
2389Bool_t MStatusDisplay::HandleConfigureNotify(Event_t *evt)
2390{
2391 //
2392 // The initialization of the GUI is not yet enough finished...
2393 //
2394 if (!fTab)
2395 return kTRUE;
2396
2397 UInt_t w = evt->fWidth;
2398 UInt_t h = evt->fHeight;
2399
2400 /*
2401 cout << "Old: " << GetWidth() << " " << GetHeight() << " " << GetBorderWidth() << endl;
2402 cout << "New: " << w << " " << h << " ";
2403 cout << "New: " << GetDefaultWidth() << " " << GetDefaultHeight() << " " << endl;
2404 */
2405
2406 Bool_t wchanged = w!=GetWidth();
2407 Bool_t hchanged = h!=GetHeight();
2408
2409 if (!wchanged && !hchanged)
2410 {
2411 Layout();
2412 // FIXME: Make sure that this doesn't result in endless loops.
2413 return kTRUE;
2414 }
2415
2416
2417 if (GetWidth()==1 && GetHeight()==1)
2418 return kTRUE;
2419
2420 // calculate the constant part of the window
2421 const UInt_t cw = GetWidth() -fTab->GetWidth();
2422 const UInt_t ch = GetHeight()-fTab->GetHeight();
2423
2424 // calculate new size of frame (canvas @ 1:sqrt(2))
2425 if (hchanged)
2426 w = (UInt_t)((h-ch)*sqrt(2.)+.5)+cw;
2427 else
2428 h = (UInt_t)((w-cw)/sqrt(2.)+.5)+ch;
2429
2430 // resize frame
2431 Resize(w, h);
2432
2433 return kTRUE;
2434}
2435
2436Bool_t MStatusDisplay::HandleEvent(Event_t *event)
2437{
2438 Bool_t rc = TGMainFrame::HandleEvent(event);
2439
2440 //
2441 // This fixes a bug in older root versions which makes
2442 // TCanvas crash if gPad==NULL. So we make sure, that
2443 // gPad!=NULL -- be carfull, this may have other side
2444 // effects.
2445 //
2446#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
2447 if (!gPad && fTab)
2448 for (int i=0; i<fTab->GetNumberOfTabs(); i++)
2449 {
2450 TCanvas *c = GetCanvas(i);
2451 if (c)
2452 {
2453 c->cd();
2454 gLog << dbg << "MStatusDisplay::HandleEvent - Workaround: gPad=" << gPad << "." << endl;
2455 break;
2456 }
2457 }
2458#endif
2459
2460 return rc;
2461}
Note: See TracBrowser for help on using the repository browser.