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

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