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

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