source: trunk/MagicSoft/Mars/mmain/MStatusDisplay.cc@ 2422

Last change on this file since 2422 was 2416, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 55.9 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
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 <TBrowser.h> // TBrowser
75#include <TObjArray.h> // TObjArray
76#include <TPostScript.h> // TPostScript
77
78#include <TRint.h> // gApplication, TRint::Class()
79#include <TInterpreter.h> // gInterpreter
80
81#include <TGTab.h> // TGTab
82#include <TGLabel.h> // TGLabel
83#include <TG3DLine.h> // TGHorizontal3DLine
84#include <TGButton.h> // TGPictureButton
85#include <TGTextView.h> // TGTextView
86#include <TGStatusBar.h> // TGStatusBar
87#include <TGProgressBar.h> // TGHProgressBar
88
89#include <TRootEmbeddedCanvas.h> // TRootEmbeddedCanvas
90
91#include "MLog.h" // MLog
92#include "MLogManip.h" // inf, warn, err
93
94#include "MGList.h" // MGList
95#include "MGMenu.h" // MGMenu, TGMenu
96#include "MSearch.h" // MSearch
97#include "MParContainer.h" // MParContainer::GetDescriptor
98
99#undef DEBUG
100//#define DEBUG
101
102ClassImp(MStatusDisplay);
103
104using namespace std;
105
106// ------------ Workaround for a non working TGTextView::Search -------------
107class MGTextView : public TGTextView
108{
109public:
110 MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, Int_t id = -1,
111 UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
112 TGTextView(parent, w, h, id, sboptions, back) {}
113 MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, TGText *text,
114 Int_t id = -1, UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
115 TGTextView(parent, w, h, text, id, sboptions, back) {}
116 MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, const char *string,
117 Int_t id = -1, UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
118 TGTextView(parent, w, h, string, id, sboptions, back) {}
119
120 void Mark(Long_t xPos, Long_t yPos) { TGTextView::Mark(xPos, yPos); }
121 void UnMark() { TGTextView::UnMark(); }
122
123 Bool_t Search(const char *string, Bool_t direction, Bool_t caseSensitive)
124 {
125 // Taken from TGTextView::Search and modified.
126
127 TGLongPosition pos, pos2;
128 pos2.fX = pos2.fY = 0;
129 if (fIsMarked) {
130 if (!direction)
131 {
132 pos2.fX = fMarkedStart.fX;
133 pos2.fY = fMarkedStart.fY;
134 }
135 else
136 {
137 pos2.fX = fMarkedEnd.fX + 1;
138 pos2.fY = fMarkedEnd.fY;
139 }
140 }
141 if (!fText->Search(&pos, pos2, string, direction, caseSensitive))
142 return kFALSE;
143 UnMark();
144 fIsMarked = kTRUE;
145 fMarkedStart.fY = fMarkedEnd.fY = pos.fY;
146 fMarkedStart.fX = pos.fX;
147 fMarkedEnd.fX = fMarkedStart.fX + strlen(string);
148 pos.fY = ToObjYCoord(fVisible.fY);
149 if ((fMarkedStart.fY < pos.fY) ||
150 (ToScrYCoord(fMarkedStart.fY) >= (Int_t)fCanvas->GetHeight()))
151 pos.fY = fMarkedStart.fY;
152 pos.fX = ToObjXCoord(fVisible.fX, pos.fY);
153 if ((fMarkedStart.fX < pos.fX) ||
154 (ToScrXCoord(fMarkedStart.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()))
155 pos.fX = fMarkedStart.fX;
156
157 SetVsbPosition((ToScrYCoord(pos.fY) + fVisible.fY)/fScrollVal.fY);
158 SetHsbPosition((ToScrXCoord(pos.fX, pos.fY) + fVisible.fX)/fScrollVal.fX);
159 DrawRegion(0, (Int_t)ToScrYCoord(fMarkedStart.fY), fCanvas->GetWidth(),
160 UInt_t(ToScrYCoord(fMarkedEnd.fY+1) - ToScrYCoord(fMarkedEnd.fY)));
161
162 return kTRUE;
163 }
164};
165// --------------------------------------------------------------------------
166
167// --------------------------------------------------------------------------
168//
169// Add menu bar to the GUI
170//
171void MStatusDisplay::AddMenuBar()
172{
173 //
174 // File Menu
175 //
176 MGPopupMenu *filemenu = new MGPopupMenu(gClient->GetRoot());
177 // filemenu->AddEntry("Save &As...", kFileSaveAs);
178 filemenu->AddEntry("New Can&vas", kFileCanvas);
179 filemenu->AddEntry("New &Browser", kFileBrowser);
180 filemenu->AddSeparator();
181 filemenu->AddEntry("Save As status.&ps", kFileSaveAsPS);
182 filemenu->AddEntry("Save As status.&gif", kFileSaveAsGIF);
183 filemenu->AddEntry("Save As status.&C", kFileSaveAsC);
184 filemenu->AddEntry("Save As status.&root", kFileSaveAsRoot);
185 filemenu->AddSeparator();
186 filemenu->AddEntry("Re&set", kFileReset);
187 filemenu->AddSeparator();
188 filemenu->AddEntry("Print with &lpr", kFilePrint);
189 //filemenu->AddEntry("Set printer &name", kFilePrinterName);
190 filemenu->AddSeparator();
191 filemenu->AddEntry("C&lose", kFileClose);
192 filemenu->AddEntry("E&xit", kFileExit);
193 filemenu->Associate(this);
194
195 //
196 // Tab Menu
197 //
198 MGPopupMenu *tabmenu = new MGPopupMenu(gClient->GetRoot());
199 // tabmenu->AddEntry("Save &As...", kFileSaveAs);
200 tabmenu->AddEntry("Next [&+]", kTabNext);
201 tabmenu->AddEntry("Previous [&-]", kTabPrevious);
202 tabmenu->AddSeparator();
203 tabmenu->AddEntry("Save As tab-i.&ps", kTabSaveAsPS);
204 tabmenu->AddEntry("Save As tab-i.&gif", kTabSaveAsGIF);
205 tabmenu->AddEntry("Save As tab-i.&C", kTabSaveAsC);
206 tabmenu->AddEntry("Save As tab-i.&root", kTabSaveAsRoot);
207 tabmenu->AddSeparator();
208 tabmenu->AddEntry("Re&move", kTabRemove);
209 tabmenu->AddSeparator();
210 tabmenu->AddEntry("Print with &lpr", kFilePrint);
211 tabmenu->Associate(this);
212
213 //
214 // Loop Menu
215 //
216 MGPopupMenu *loopmenu = new MGPopupMenu(gClient->GetRoot());
217 loopmenu->AddEntry("&Stop", kLoopStop);
218 loopmenu->Associate(this);
219
220 //
221 // Loop Menu
222 //
223 MGPopupMenu *sizemenu = new MGPopupMenu(gClient->GetRoot());
224 sizemenu->AddEntry("Fit to 640x&480", kSize640);
225 sizemenu->AddEntry("Fit to 800x&600", kSize800);
226 sizemenu->AddEntry("Fit to 960x7&20", kSize960);
227 sizemenu->AddEntry("Fit to 1024x&768", kSize1024);
228 sizemenu->AddEntry("Fit to 1280x&1024", kSize1280);
229 sizemenu->Associate(this);
230
231 //
232 // Log Menu
233 //
234 MGPopupMenu *logmenu = new MGPopupMenu(gClient->GetRoot());
235 logmenu->AddEntry("&Copy Selected", kLogCopy);
236 logmenu->AddEntry("Cl&ear all", kLogClear);
237 logmenu->AddSeparator();
238 logmenu->AddEntry("Select &All", kLogSelect);
239 logmenu->AddSeparator();
240 logmenu->AddEntry("&Find...", kLogFind);
241 logmenu->AddSeparator();
242 logmenu->AddEntry("&Save", kLogSave);
243 logmenu->AddEntry("Save &append", kLogAppend);
244 logmenu->Associate(this);
245
246 //
247 // Menu Bar
248 //
249 TGLayoutHints *layitem = new TGLayoutHints(kLHintsNormal, 0, 4, 0, 0);
250 fList->Add(layitem);
251
252 MGMenuBar *menubar = new MGMenuBar(this, 1, 1, kHorizontalFrame);
253 menubar->AddPopup("&File", filemenu, layitem);
254 menubar->AddPopup("Lo&g", logmenu, layitem);
255 menubar->AddPopup("&Size", sizemenu, layitem);
256 menubar->AddPopup("&Tab", tabmenu, layitem);
257 menubar->AddPopup("&Loop", loopmenu, layitem);
258 menubar->BindKeys(this);
259 AddFrame(menubar);
260
261 //
262 // Line below menu bar
263 //
264 TGLayoutHints *laylinesep = new TGLayoutHints(kLHintsTop|kLHintsExpandX);
265 fList->Add(laylinesep);
266
267 TGHorizontal3DLine *linesep = new TGHorizontal3DLine(this);
268 AddFrame(linesep, laylinesep);
269
270 //
271 // Add everything to autodel list
272 //
273 fList->Add(filemenu);
274 fList->Add(loopmenu);
275 fList->Add(sizemenu);
276 fList->Add(menubar);
277 fList->Add(tabmenu);
278 fList->Add(logmenu);
279 fList->Add(linesep);
280}
281
282// --------------------------------------------------------------------------
283//
284// Add the title tab
285//
286void MStatusDisplay::AddMarsTab()
287{
288 // Create Tab1
289 TGCompositeFrame *f = fTab->AddTab("-=MARS=-");
290
291 // Add MARS version
292 TGLabel *l = new TGLabel(f, Form("Official Release: V%s", MARSVER));
293 fList->Add(l);
294
295 TGLayoutHints *layb = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 5, 5);
296 fList->Add(layb);
297 f->AddFrame(l, layb);
298
299 // Add root version
300 l = new TGLabel(f, Form("Using ROOT v%s", ROOTVER));
301 fList->Add(l);
302
303 TGLayoutHints *lay = new TGLayoutHints(kLHintsCenterX|kLHintsTop);
304 fList->Add(lay);
305 f->AddFrame(l, lay);
306
307 // Add Mars logo picture
308 const TGPicture *pic2 = fList->GetPicture("marslogo.xpm");
309 if (pic2)
310 {
311 TGPictureButton *mars = new TGPictureButton(f, pic2, kPicMars);
312 fList->Add(mars);
313 mars->Associate(this);
314
315 TGLayoutHints *lay2 = new TGLayoutHints(kLHintsCenterX|kLHintsCenterY, 10, 10, 5, 5);
316 fList->Add(lay2);
317 f->AddFrame(mars, lay2);
318 }
319
320 // Add date and time
321 TDatime d;
322 l = new TGLabel(f, d.AsString());
323 fList->Add(l);
324 f->AddFrame(l, lay);
325
326 // Add copyright notice
327 l = new TGLabel(f, "(c) MAGIC Software Development, 2000-2003");
328 fList->Add(l);
329 f->AddFrame(l, layb);
330
331 TGLayoutHints *layc = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 0, 5);
332 fList->Add(layc);
333
334 l = new TGLabel(f, "<< Thomas Bretz >>");
335 fList->Add(l);
336 f->AddFrame(l, layc);
337}
338
339// --------------------------------------------------------------------------
340//
341// Adds the logbook tab to the GUI if it was not added previously.
342//
343// The logbook is updated four times a second only if the tab is visible.
344//
345// You can redirect an output to a MLog-logstream by calling SetLogStream().
346// To disable redirction call SetLogStream(NULL)
347//
348// if enable==kFALSE the stdout is disabled/enabled. Otherwise stdout
349// is ignored.
350//
351void MStatusDisplay::SetLogStream(MLog *log, Bool_t enable)
352{
353 if (gROOT->IsBatch())
354 return;
355
356 if (log && fLogBox==NULL)
357 {
358 fLogIdx = fTab->GetNumberOfTabs();
359
360 // Create Tab1
361 TGCompositeFrame *f = fTab->AddTab("-Logbook-");
362
363 // Create Text View
364 fLogBox = new MGTextView(f, 1, 1); // , -1, 0, TGFrame::GetDefaultFrameBackground());
365 if (fFont)
366 fLogBox->SetFont(fFont);
367 //fLogBox->Associate(this);
368
369 // Add List box to the tab
370 TGLayoutHints *lay = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY,2,2,2,2);
371 f->AddFrame(fLogBox, lay);
372
373 // layout and map tab
374 Layout();
375 MapSubwindows();
376
377 // make it visible
378 // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
379 if (gApplication->InheritsFrom(TRint::Class()))
380 gClient->ProcessEventsFor(fTab);
381 }
382
383 if (log)
384 {
385 fLog = log;
386
387 log->SetOutputGui(fLogBox, kTRUE);
388 log->EnableOutputDevice(MLog::eGui);
389 if (!enable)
390 log->DisableOutputDevice(MLog::eStdout);
391
392 fLogTimer.Start();
393 }
394 else
395 {
396 fLogTimer.Stop();
397
398 fLog->DisableOutputDevice(MLog::eGui);
399 fLog->SetOutputGui(NULL);
400 if (!enable)
401 fLog->EnableOutputDevice(MLog::eStdout);
402
403 fLog = &gLog;
404 }
405}
406
407// --------------------------------------------------------------------------
408//
409// Add the Tabs and the predifined Tabs to the GUI
410//
411void MStatusDisplay::AddTabs()
412{
413 fTab = new TGTab(this, 300, 300);
414
415 AddMarsTab();
416
417 // Add fTab to Frame
418 TGLayoutHints *laytabs = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 5, 5, 5);
419 AddFrame(fTab, laytabs);
420
421 fList->Add(fTab);
422 fList->Add(laytabs);
423}
424
425// --------------------------------------------------------------------------
426//
427// Add the progress bar to the GUI
428//
429void MStatusDisplay::AddProgressBar()
430{
431 TGLayoutHints *laybar=new TGLayoutHints(kLHintsExpandX, 5, 5, 5, 5);
432 fList->Add(laybar);
433
434 fBar=new TGHProgressBar(this);
435 fBar->ShowPosition();
436 AddFrame(fBar, laybar);
437 fList->Add(fBar);
438}
439
440// --------------------------------------------------------------------------
441//
442// Adds the status bar to the GUI
443//
444void MStatusDisplay::AddStatusBar()
445{
446 fStatusBar = new TGStatusBar(this, 1, 1);
447
448 //
449 // 1-a a
450 // 1: ------|----
451 //
452 // a/(1-a) = (1-a)/1
453 // a^2+a-1 = 0
454 // a = (-1+-sqrt(1+4))/2 = sqrt(5)/2-1/2 = 0.618
455 //
456 Int_t p[2] = {38, 62};
457
458 fStatusBar->SetParts(p, 2);
459
460 TGLayoutHints *layb = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 5, 4, 0, 3);
461 AddFrame(fStatusBar, layb);
462
463 fList->Add(fStatusBar);
464 fList->Add(layb);
465}
466
467// --------------------------------------------------------------------------
468//
469// Change the text in the status line 1
470//
471void MStatusDisplay::SetStatusLine1(const char *txt)
472{
473 if (gROOT->IsBatch())
474 return;
475 fStatusBar->SetText(txt, 0);
476 // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
477 if (gApplication->InheritsFrom(TRint::Class()))
478 gClient->ProcessEventsFor(fStatusBar);
479}
480
481// --------------------------------------------------------------------------
482//
483// Change the text in the status line 2
484//
485void MStatusDisplay::SetStatusLine2(const char *txt)
486{
487 if (gROOT->IsBatch())
488 return;
489 fStatusBar->SetText(txt, 1);
490 // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
491 if (gApplication->InheritsFrom(TRint::Class()))
492 gClient->ProcessEventsFor(fStatusBar);
493}
494
495// --------------------------------------------------------------------------
496//
497// Display information about the name of a container
498//
499void MStatusDisplay::SetStatusLine2(const MParContainer &cont)
500{
501 SetStatusLine2(Form("%s: %s", cont.GetDescriptor(), cont.GetTitle()));
502}
503
504// --------------------------------------------------------------------------
505//
506// Default constructor. Opens a window with a progress bar. Get a pointer
507// to the bar by calling GetBar. This pointer can be used for the
508// eventloop.
509//
510// Be carefull: killing or closing the window while the progress meter
511// is still in use may cause segmentation faults. Please kill the window
512// always by deleting the corresponding object.
513//
514// Update time default: 10s
515//
516MStatusDisplay::MStatusDisplay(Long_t t)
517: TGMainFrame(gClient ? gClient->GetRoot() : NULL, 1, 1), fTimer(this, t, kTRUE), fStatus(kLoopNone), fLog(&gLog), fLogIdx(-1), fLogTimer(this, 250, kTRUE), fLogBox(NULL), fIsLocked(0)
518{
519 //
520 // This is a possibility for the user to check whether this
521 // object has already been deleted. It will be removed
522 // from the list in the destructor.
523 //
524 gROOT->GetListOfSpecials()->Add(this);
525
526 fFont = gVirtualX->LoadQueryFont("7x13bold");
527
528 //
529 // In case we are in batch mode use a list of canvases
530 // instead of the Root Embedded Canvases in the TGTab
531 //
532 fBatch = new TList;
533 fBatch->SetOwner();
534
535 //
536 // Create a list handling GUI widgets
537 //
538 fList = new MGList;
539 fList->SetOwner();
540
541 //
542 // set the smallest and biggest size of the Main frame
543 // and move it to its appearance position
544 SetWMSizeHints(570, 480, 1280, 980, 1, 1);
545 Move(rand()%100+50, rand()%100+50);
546 //Resize(740, 600);
547 Resize(570, 480);
548
549 //
550 // Create the layout hint for the root embedded canavses
551 //
552 fLayCanvas = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY);
553 fList->Add(fLayCanvas);
554
555 //
556 // Add Widgets (from top to bottom)
557 //
558 if (gClient) // BATCH MODE
559 {
560 AddMenuBar();
561 AddTabs();
562 AddProgressBar();
563 AddStatusBar();
564 }
565
566 //
567 // Now do an automatic layout of the widgets and display the window
568 //
569 Layout();
570 MapSubwindows();
571
572 SetWindowName("Status Display");
573 SetIconName("Status Display");
574
575 MapWindow();
576
577 // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
578 if (gApplication->InheritsFrom(TRint::Class()))
579 gSystem->ProcessEvents();
580}
581
582// --------------------------------------------------------------------------
583//
584// Destruct the window with all its tiles. Also the Progress Bar object
585// is deleted.
586//
587MStatusDisplay::~MStatusDisplay()
588{
589 //
590 // Delete object from global object table so it cannot
591 // be deleted by chance a second time
592 //
593 gInterpreter->DeleteGlobal(this);
594
595 //
596 // This is a possibility for the user to check whether this
597 // object has already been deleted. It has been added
598 // to the list in the constructor.
599 //
600 gROOT->GetListOfSpecials()->Remove(this);
601
602 SetLogStream(NULL);
603
604 //
605 // Delete the list of objects corresponding to this object
606 //
607 delete fList;
608
609 //
610 // Delete the list list of canvases used in batch mode
611 // instead of the Root Embedded Canvases in the TGTab
612 //
613 delete fBatch;
614
615 //
616 // Delete the font used for the logging window
617 //
618 if (fFont)
619 gVirtualX->DeleteFont(fFont);
620}
621
622// --------------------------------------------------------------------------
623//
624// Takes a TGCompositeFrame as argument. Searches for the first
625// TRootEmbeddedCanvas which is contained by it and returns a pointer
626// to the corresponding TCanvas. If it isn't found NULL is returned.
627//
628TRootEmbeddedCanvas *MStatusDisplay::GetEmbeddedCanvas(TGCompositeFrame *cf) const
629{
630 TIter Next(cf->GetList());
631
632 TGFrameElement *f;
633 while ((f=(TGFrameElement*)Next()))
634 if (f->fFrame->InheritsFrom(TRootEmbeddedCanvas::Class()))
635 return (TRootEmbeddedCanvas*)f->fFrame;
636
637 return NULL;
638}
639
640// --------------------------------------------------------------------------
641//
642// Takes a TGCompositeFrame as argument. Searches for the first
643// TRootEmbeddedCanvas which is contained by it and returns a pointer
644// to the corresponding TCanvas. If it isn't found NULL is returned.
645//
646TCanvas *MStatusDisplay::GetCanvas(TGCompositeFrame *cf) const
647{
648 TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(cf);
649 return ec ? ec->GetCanvas() : NULL;
650}
651
652// --------------------------------------------------------------------------
653//
654// Returns GetCanvas of the i-th Tab.
655//
656TCanvas *MStatusDisplay::GetCanvas(int i) const
657{
658 if (gROOT->IsBatch())
659 return (TCanvas*)fBatch->At(i-1);
660
661 if (i<0 || i>=fTab->GetNumberOfTabs())
662 {
663 *fLog << warn << "MStatusDisplay::GetCanvas: Out of range." << endl;
664 return NULL;
665 }
666
667 return GetCanvas(fTab->GetTabContainer(i));
668}
669
670// --------------------------------------------------------------------------
671//
672// Searches for a TRootEmbeddedCanvas in the TGCompositeFramme of the
673// Tab with the name 'name'. Returns the corresponding TCanvas or
674// NULL if something isn't found.
675//
676TCanvas *MStatusDisplay::GetCanvas(const TString &name) const
677{
678 TGFrameElement *f;
679 TIter Next(fTab->GetList());
680 while ((f=(TGFrameElement*)Next()))
681 {
682 TObject *frame = f->fFrame;
683 if (!frame->InheritsFrom(TGTabElement::Class()))
684 continue;
685
686 TGTabElement *tab = (TGTabElement*)frame;
687 if (tab->GetString()==name)
688 break;
689 }
690
691 // Search for the next TGCompositeFrame in the list
692 while ((f=(TGFrameElement*)Next()))
693 {
694 TObject *frame = f->fFrame;
695 if (frame->InheritsFrom(TGCompositeFrame::Class()))
696 return GetCanvas((TGCompositeFrame*)frame);
697 }
698
699 return NULL;
700}
701
702// --------------------------------------------------------------------------
703//
704// Calls TCanvas::cd(), for the canvas returned by GetCanvas.
705//
706Bool_t MStatusDisplay::CdCanvas(const TString &name)
707{
708 TCanvas *c = GetCanvas(name);
709 if (!c)
710 return kFALSE;
711
712 c->cd();
713 return kTRUE;
714}
715
716/*
717class MCanvas : public TRootEmbeddedCanvas
718{
719public:
720 MCanvas(const char* name, const TGWindow* p, UInt_t w, UInt_t h, UInt_t o) :
721 TRootEmbeddedCanvas(name, p, w, h, o) {}
722 void Layout()
723 {
724 cout << "EmbLayout: " << GetCanvas()->GetName() << endl;
725
726 // Create layout for canvas. Depending on the size of the container
727 // we need to add the scrollbars.
728 TRootEmbeddedCanvas::Layout();
729 }
730};
731*/
732
733TGCompositeFrame *MStatusDisplay::AddRawTab(const char *name)
734{
735 // Add new tab
736 TGCompositeFrame *f = fTab->AddTab(name);
737
738 // layout and map new tab
739 Layout();
740 MapSubwindows();
741 Layout();
742
743 // display new tab in the main frame
744 // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
745 if (gApplication->InheritsFrom(TRint::Class()))
746 gClient->ProcessEventsFor(fTab);
747
748 *fLog << inf << "Adding Raw Tab '" << name << "' (" << f->GetWidth() << "x";
749 *fLog << f->GetHeight() << ")" << endl;
750
751 // return pointer to new canvas
752 return f;
753}
754
755// --------------------------------------------------------------------------
756//
757// Adds a new tab with the name 'name'. Adds a TRootEmbeddedCanvas to the
758// tab and returns a reference to the corresponding TCanvas.
759//
760TCanvas &MStatusDisplay::AddTab(const char *name)
761{
762 if (gROOT->IsBatch())
763 {
764 TCanvas *c = new TCanvas(name, name);
765 fBatch->Add(c);
766 return *c;
767 }
768
769 // Add new tab
770 TGCompositeFrame *f = fTab->AddTab(name);
771
772 // create root embedded canvas and add it to the tab
773 TRootEmbeddedCanvas *ec = new TRootEmbeddedCanvas(name, f, f->GetWidth(), f->GetHeight(), 0);
774 f->AddFrame(ec, fLayCanvas);
775 fList->Add(ec);
776
777 // set background and border mode of the canvas
778 TCanvas &c = *ec->GetCanvas();
779
780 c.SetFillColor(16/*165*//*17*//*203*/);
781 c.SetBorderMode(0);
782
783 // If kNoContextMenu set set kNoContextMenu of the canvas
784 if (TestBit(kNoContextMenu))
785 c.SetBit(kNoContextMenu);
786
787 // layout and map new tab
788//#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,00)
789// MapSubwindows();
790// Layout();
791//#else
792 Layout();
793 MapSubwindows();
794 Layout();
795//#endif
796
797 // display new tab in the main frame
798 // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
799 if (gApplication->InheritsFrom(TRint::Class()))
800 gClient->ProcessEventsFor(fTab);
801
802 *fLog << inf << "Adding Tab '" << name << "' (" << f->GetWidth() << "x";
803 *fLog << f->GetHeight() << ", TCanvas=" << &c << ")" << endl;
804
805 // return pointer to new canvas
806 return c;
807}
808
809
810// --------------------------------------------------------------------------
811//
812// Update a canvas in a tab, takes the corresponding TGCompositeFrame
813// as an argument
814//
815void MStatusDisplay::UpdateTab(TGCompositeFrame *f)
816{
817 if (!f)
818 return;
819
820 TCanvas *c=GetCanvas(f);
821 if (!c)
822 return;
823
824 // Code taken from TCanvas::Update() and TCanvas::Paint()
825 // replaces PaintModified() by Paint()
826 if (gThreadXAR)
827 {
828 void *arr[2] = { NULL, c };
829 if (((*gThreadXAR)("CUPD", 2, arr, NULL)))
830 return;
831 }
832
833 if (!c->IsBatch())
834 c->FeedbackMode(kFALSE); // Goto double buffer mode
835
836 c->Paint(); // Repaint all pads
837 c->Flush(); // Copy all pad pixmaps to the screen
838
839 //c->SetCursor(kCross);
840
841 // Old version
842 //c->Modified();
843 //c->Update();
844 //c->Paint();
845}
846
847// --------------------------------------------------------------------------
848//
849// Saves the given canvas (pad) or all pads (num<0) as a temporary
850// postscript file and prints it using 'lpr'. If a printer name is set
851// via SetPrinter 'lpr -Pname' is used.
852//
853Int_t MStatusDisplay::PrintToLpr(Int_t num)
854{
855 TString name = "mars";
856
857 for (int i=0; i<6; i++)
858 name += (char)(gRandom->Uniform(25)+65);
859
860 name += ".ps";
861
862 const Int_t pages = SaveAsPS(num, name);
863
864 SetStatusLine1("Printing...");
865 SetStatusLine2("");
866
867 if (!pages)
868 {
869 *fLog << warn << "MStatusDisplay::PrintToLpr: Sorry, couldn't save file as temporary postscript!" << endl;
870 SetStatusLine2("Failed!");
871 return 0;
872 }
873
874 TString cmd="lpr ";
875 if (!fPrinter.IsNull())
876 {
877 cmd += "-P";
878 cmd += fPrinter;
879 cmd += " ";
880 }
881 cmd += name;
882
883 gSystem->Exec(cmd);
884 gSystem->Unlink(name);
885
886 SetStatusLine2(Form("Done (%dpages)", pages));
887
888 return pages;
889}
890
891// --------------------------------------------------------------------------
892//
893// Remove tab no i if this tab contains a TRootEmbeddedCanvas
894//
895void MStatusDisplay::RemoveTab(int i)
896{
897 TGCompositeFrame *f = fTab->GetTabContainer(i);
898 if (!f)
899 return;
900
901 TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(f);
902 if (!ec)
903 return;
904
905 TCanvas *c = ec->GetCanvas();
906 if (!c)
907 return;
908
909 const TString name(c->GetName());
910
911 f->RemoveFrame(ec);
912 delete fList->Remove(ec);
913
914 fTab->RemoveTab(i);
915
916 // layout and map new tab
917#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,00)
918 MapSubwindows();
919 Layout();
920#else
921 Layout();
922 MapSubwindows();
923#endif
924
925 // display new tab in the main frame
926 // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
927 if (gApplication->InheritsFrom(TRint::Class()))
928 gClient->ProcessEventsFor(fTab);
929
930 *fLog << inf << "Removed Tab #" << i << " '" << name << "'" << endl;
931}
932
933// --------------------------------------------------------------------------
934//
935// Use this to check whether the MStatusDisplay still contains the
936// TCanvas c. It could be removed meanwhile by menu usage.
937//
938Bool_t MStatusDisplay::HasCanvas(const TCanvas *c) const
939{
940 if (!c)
941 return kFALSE;
942
943 if (gROOT->IsBatch())
944 return (Bool_t)fBatch->FindObject(c);
945
946 for (int i=1; i<fTab->GetNumberOfTabs(); i++)
947 if (c==GetCanvas(i))
948 return kTRUE;
949 return kFALSE;
950}
951
952/*
953 if (...)
954 fMenu->AddPopup("&CaOs", fCaOs, NULL);
955 else
956 fMenu->RemovePopup("CaOs");
957 fMenu->Resize(fMenu->GetDefaultSize());
958 MapSubwindows();
959 MapWindow();
960 */
961
962// --------------------------------------------------------------------------
963//
964// Process the kC_COMMAND, kCM_MENU messages
965//
966Bool_t MStatusDisplay::ProcessMessageCommandMenu(Long_t id)
967{
968 switch (id)
969 {
970 case kLoopStop:
971 case kFileClose:
972 case kFileExit:
973 if (id==kFileExit || id==kFileClose)
974 CloseWindow();
975 fStatus = (Status_t)id;
976 return kTRUE;
977
978 case kFileCanvas:
979 new TCanvas;
980 return kTRUE;
981
982 case kFileBrowser:
983 new TBrowser;
984 return kTRUE;
985
986 case kFileReset:
987 for (int i=fTab->GetNumberOfTabs()-1; i>0; i--)
988 RemoveTab(i);
989 return kTRUE;
990 /*
991 case kFileSave:
992 cout << "Save..." << endl;
993 return kTRUE;
994
995 case kFileSaveAs:
996 cout << "SaveAs..." << endl;
997 return kTRUE;
998*/
999 case kFileSaveAsPS:
1000 SaveAsPS();
1001 return kTRUE;
1002
1003 case kFileSaveAsGIF:
1004 SaveAsGIF();
1005 return kTRUE;
1006
1007 case kFileSaveAsC:
1008 SaveAsC();
1009 return kTRUE;
1010
1011 case kFileSaveAsRoot:
1012 SaveAsRoot();
1013 return kTRUE;
1014
1015 case kFilePrint:
1016 PrintToLpr();
1017 return kTRUE;
1018
1019 case kTabSaveAsPS:
1020 SaveAsPS(fTab->GetCurrent());
1021 return kTRUE;
1022
1023 case kTabSaveAsGIF:
1024 SaveAsGIF(fTab->GetCurrent());
1025 return kTRUE;
1026
1027 case kTabSaveAsC:
1028 SaveAsC(fTab->GetCurrent());
1029 return kTRUE;
1030
1031 case kTabSaveAsRoot:
1032 SaveAsRoot(fTab->GetCurrent());
1033 return kTRUE;
1034
1035 case kTabPrint:
1036 PrintToLpr(fTab->GetCurrent());
1037 return kTRUE;
1038
1039 case kTabNext:
1040 fTab->SetTab(fTab->GetCurrent()+1);
1041 return kTRUE;
1042
1043 case kTabPrevious:
1044 fTab->SetTab(fTab->GetCurrent()-1);
1045 return kTRUE;
1046
1047 case kTabRemove:
1048 RemoveTab(fTab->GetCurrent());
1049 return kTRUE;
1050
1051 case kSize640:
1052 Resize(570, 480);
1053 return kTRUE;
1054 case kSize800:
1055 Resize(740, 600);
1056 return kTRUE;
1057 case kSize960:
1058 Resize(880, 700);
1059 return kTRUE;
1060 case kSize1024:
1061 Resize(980, 768);
1062 return kTRUE;
1063 case kSize1280:
1064 Resize(1280, 980);
1065 return kTRUE;
1066
1067 case kLogClear:
1068 fLogBox->Clear();
1069 return kTRUE;
1070 case kLogCopy:
1071 fLogBox->Copy();
1072 return kTRUE;
1073 case kLogSelect:
1074 fLogBox->SelectAll();
1075 return kTRUE;
1076 case kLogFind:
1077 new MSearch(this);
1078 return kTRUE;
1079 case kLogSave:
1080 SetStatusLine1("Saving log...");
1081 SetStatusLine2("");
1082 *fLog << inf << "Saving log... " << flush;
1083 if (fLogBox->GetText()->Save("statusdisplay.log"))
1084 {
1085 *fLog << "done." << endl;
1086 SetStatusLine2("done.");
1087 }
1088 else
1089 {
1090 *fLog << "failed!" << endl;
1091 SetStatusLine2("Failed!");
1092 }
1093 return kTRUE;
1094
1095 case kLogAppend:
1096 SetStatusLine1("Appending logg...");
1097 SetStatusLine2("");
1098 *fLog << inf << "Appending log... " << flush;
1099 if (fLogBox->GetText()->Append("statusdisplay.log"))
1100 {
1101 *fLog << "done." << endl;
1102 SetStatusLine2("done.");
1103 }
1104 else
1105 {
1106 *fLog << "failed!" << endl;
1107 SetStatusLine2("Failed!");
1108 }
1109 return kTRUE;
1110#ifdef DEBUG
1111 default:
1112 cout << "Command-Menu #" << id << endl;
1113#endif
1114 }
1115 return kTRUE;
1116
1117}
1118
1119// --------------------------------------------------------------------------
1120//
1121// Process the kC_COMMAND messages
1122//
1123Bool_t MStatusDisplay::ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2)
1124{
1125 switch (submsg)
1126 {
1127 case kCM_MENU:
1128 return ProcessMessageCommandMenu(mp1); // mp2=userdata
1129 case kCM_TAB:
1130 /*
1131 for (int i=0; i<fTab->GetNumberOfTabs(); i++)
1132 fTab->GetTabContainer(i)->UnmapWindow();
1133 */
1134 UpdateTab(fTab->GetTabContainer(mp1));
1135 //fTab->GetTabContainer(mp1)->MapWindow();
1136
1137 /*
1138 if (mp1>0)
1139 fMenu->AddPopup("&CaOs", fCaOs, NULL);
1140 else
1141 fMenu->RemovePopup("CaOs");
1142 fMenu->Resize(fMenu->GetDefaultSize());
1143 MapSubwindows();
1144 MapWindow();
1145 */
1146 return kTRUE;
1147#ifdef DEBUG
1148 case kCM_MENUSELECT:
1149 cout << "Command-Menuselect #" << mp1 << " (UserData=" << (void*)mp2 << ")" << endl;
1150 return kTRUE;
1151
1152 case kCM_BUTTON:
1153 cout << "Command-Button." << endl;
1154 return kTRUE;
1155
1156 case kCM_CHECKBUTTON:
1157 cout << "Command-CheckButton." << endl;
1158 return kTRUE;
1159
1160 case kCM_RADIOBUTTON:
1161 cout << "Command-RadioButton." << endl;
1162 return kTRUE;
1163
1164 case kCM_LISTBOX:
1165 cout << "Command-Listbox #" << mp1 << " (LineId #" << mp2 << ")" << endl;
1166 return kTRUE;
1167
1168 case kCM_COMBOBOX:
1169 cout << "Command-ComboBox." << endl;
1170 return kTRUE;
1171 default:
1172 cout << "Command: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1173#endif
1174 }
1175 return kTRUE;
1176}
1177
1178// --------------------------------------------------------------------------
1179//
1180// Process the kC_TEXTVIEW messages
1181//
1182Bool_t MStatusDisplay::ProcessMessageTextview(Long_t submsg, Long_t mp1, Long_t mp2)
1183{
1184 // kC_TEXTVIEW, kTXT_ISMARKED, widget id, [true|false] //
1185 // kC_TEXTVIEW, kTXT_DATACHANGE, widget id, 0 //
1186 // kC_TEXTVIEW, kTXT_CLICK2, widget id, position (y << 16) | x) //
1187 // kC_TEXTVIEW, kTXT_CLICK3, widget id, position (y << 16) | x) //
1188 // kC_TEXTVIEW, kTXT_F3, widget id, true //
1189 // kC_TEXTVIEW, kTXT_OPEN, widget id, 0 //
1190 // kC_TEXTVIEW, kTXT_CLOSE, widget id, 0 //
1191 // kC_TEXTVIEW, kTXT_SAVE, widget id, 0 //
1192#ifdef DEBUG
1193 switch (submsg)
1194 {
1195 case kTXT_ISMARKED:
1196 cout << "Textview-IsMarked #" << mp1 << " " << (mp2?"yes":"no") << endl;
1197 return kTRUE;
1198
1199 case kTXT_DATACHANGE:
1200 cout << "Textview-DataChange #" << mp1 << endl;
1201 return kTRUE;
1202
1203 case kTXT_CLICK2:
1204 cout << "Textview-Click2 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
1205 return kTRUE;
1206
1207 case kTXT_CLICK3:
1208 cout << "Textview-Click3 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
1209 return kTRUE;
1210
1211 case kTXT_F3:
1212 cout << "Textview-F3 #" << mp1 << endl;
1213 return kTRUE;
1214
1215 case kTXT_OPEN:
1216 cout << "Textview-Open #" << mp1 << endl;
1217 return kTRUE;
1218
1219 case kTXT_CLOSE:
1220 cout << "Textview-Close #" << mp1 << endl;
1221 return kTRUE;
1222
1223 case kTXT_SAVE:
1224 cout << "Textview-Save #" << mp1 << endl;
1225 return kTRUE;
1226
1227 default:
1228 cout << "Textview: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1229 }
1230#endif
1231 return kTRUE;
1232}
1233
1234// --------------------------------------------------------------------------
1235//
1236// Process the kC_USER messages
1237//
1238Bool_t MStatusDisplay::ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2)
1239{
1240 // kS_START, case sensitive | backward<<1, char *txt
1241 switch (submsg)
1242 {
1243 case kS_START:
1244 fLogBox->Search((char*)mp2, !(mp1&2>>1), mp1&1);
1245 return kTRUE;
1246#ifdef DEBUG
1247 default:
1248 cout << "User: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1249#endif
1250 }
1251 return kTRUE;
1252}
1253
1254// --------------------------------------------------------------------------
1255//
1256// Process the messages from the GUI
1257//
1258Bool_t MStatusDisplay::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2)
1259{
1260 // Can be found in WidgetMessageTypes.h
1261 cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
1262 cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1263 switch (GET_MSG(msg))
1264 {
1265 case kC_COMMAND:
1266 return ProcessMessageCommand(GET_SUBMSG(msg), mp1, mp2);
1267
1268 case kC_TEXTVIEW:
1269 return ProcessMessageTextview(GET_SUBMSG(msg), mp1, mp2);
1270
1271 case kC_USER:
1272 return ProcessMessageUser(GET_SUBMSG(msg), mp1, mp2);
1273 }
1274#ifdef DEBUG
1275 cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
1276 cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1277#endif
1278 return kTRUE;
1279}
1280
1281void MStatusDisplay::CloseWindow()
1282{
1283 // Got close message for this MainFrame. Calls parent CloseWindow()
1284 // (which destroys the window) and terminate the application.
1285 // The close message is generated by the window manager when its close
1286 // window menu item is selected.
1287
1288 // CloseWindow must be overwritten because otherwise CloseWindow
1289 // and the destructor are calling DestroyWindow which seems to be
1290 // in conflict with the TRootEmbeddedCanvas.
1291
1292 // FIXME: Make sure that the Status Display is deleted from every
1293 // where (eg Eventloop) first!
1294
1295 gLog << dbg << "MStatusDisplay is on heap: " << (int)IsOnHeap() << endl;
1296
1297 if (fIsLocked<=0 && IsOnHeap())
1298 delete this;
1299 fStatus = kFileExit;
1300}
1301
1302// --------------------------------------------------------------------------
1303//
1304// Calls SetBit(kNoContextMenu) for all TCanvas objects found in the
1305// Tabs.
1306//
1307void MStatusDisplay::SetNoContextMenu(Bool_t flag)
1308{
1309 if (fIsLocked>1 || gROOT->IsBatch())
1310 return;
1311
1312 flag ? SetBit(kNoContextMenu) : ResetBit(kNoContextMenu);
1313
1314 for (int i=1; i<fTab->GetNumberOfTabs(); i++)
1315 {
1316 TCanvas *c = GetCanvas(i);
1317 if (c)
1318 flag ? c->SetBit(kNoContextMenu) : c->ResetBit(kNoContextMenu);
1319 }
1320}
1321
1322// --------------------------------------------------------------------------
1323//
1324// Updates the canvas (if existing) in the currenly displayed Tab.
1325// The update intervall is controlled by StartUpdate and StopUpdate
1326//
1327Bool_t MStatusDisplay::HandleTimer(TTimer *timer)
1328{
1329 if (gROOT->IsBatch())
1330 return kTRUE;
1331
1332 const Int_t c = fTab->GetCurrent();
1333
1334 // Skip Legend Tab
1335 if (c==0)
1336 return kTRUE;
1337
1338 // Update a canvas tab (if visible)
1339 if (timer==&fTimer && c!=fLogIdx)
1340 {
1341 UpdateTab(fTab->GetCurrentContainer());
1342 return kTRUE;
1343 }
1344
1345 // update the logbook tab (if visible)
1346 if (timer==&fLogTimer && c==fLogIdx)
1347 {
1348 fLog->UpdateGui();
1349
1350 /*
1351 if (!fLogBox->TestBit(kHasChanged))
1352 return kTRUE;
1353
1354 fLogBox->ResetBit(kHasChanged);
1355 */
1356 return kTRUE;
1357 }
1358
1359 return kTRUE;
1360}
1361
1362// --------------------------------------------------------------------------
1363//
1364// Draws a clone of a canvas into a new canvas. Taken from TCanvas.
1365//
1366void MStatusDisplay::DrawClonePad(TCanvas &newc, const TCanvas &oldc) const
1367{
1368 //copy pad attributes
1369 newc.Range(oldc.GetX1(),oldc.GetY1(),oldc.GetX2(),oldc.GetY2());
1370 newc.SetTickx(oldc.GetTickx());
1371 newc.SetTicky(oldc.GetTicky());
1372 newc.SetGridx(oldc.GetGridx());
1373 newc.SetGridy(oldc.GetGridy());
1374 newc.SetLogx(oldc.GetLogx());
1375 newc.SetLogy(oldc.GetLogy());
1376 newc.SetLogz(oldc.GetLogz());
1377 newc.SetBorderSize(oldc.GetBorderSize());
1378 newc.SetBorderMode(oldc.GetBorderMode());
1379 ((TAttLine&)oldc).Copy((TAttLine&)newc);
1380 ((TAttFill&)oldc).Copy((TAttFill&)newc);
1381 ((TAttPad&)oldc).Copy((TAttPad&)newc);
1382
1383 //copy primitives
1384 TObject *obj;
1385 TIter next(oldc.GetListOfPrimitives());
1386 while ((obj=next())) {
1387 gROOT->SetSelectedPad(&newc);
1388 newc.GetListOfPrimitives()->Add(obj->Clone(),obj->GetDrawOption());
1389 }
1390 newc.Modified();
1391 newc.Update();
1392}
1393
1394// --------------------------------------------------------------------------
1395//
1396// Reads the contents of a saved MStatusDisplay from a file.
1397//
1398Int_t MStatusDisplay::Read(const char *name)
1399{
1400 if (!gFile)
1401 {
1402 *fLog << warn << "MStatusDisplay::Read: No file found. Please create a TFile first." << endl;
1403 return 0;
1404 }
1405
1406 if (!gFile->IsOpen())
1407 {
1408 *fLog << warn << "MStatusDisplay::Read: File not open. Please open the TFile first." << endl;
1409 return 0;
1410 }
1411
1412 TObjArray list;
1413
1414 const Int_t n = list.Read(name);
1415 if (n==0)
1416 {
1417 *fLog << warn << "MStatusDisplay::Read: No objects read." << endl;
1418 return 0;
1419 }
1420
1421 TIter Next(&list);
1422 TCanvas *c;
1423 while ((c=(TCanvas*)Next()))
1424 DrawClonePad(AddTab(c->GetName()), *c);
1425
1426 *fLog << inf << "MStatusDisplay: Key " << name << " with " << n << " keys read from file." << endl;
1427
1428 return n;
1429}
1430
1431// --------------------------------------------------------------------------
1432//
1433// Writes the contents of a MStatusDisplay to a file.
1434//
1435Int_t MStatusDisplay::Write(Int_t num, const char *name, Int_t option, Int_t bufsize)
1436{
1437 if (!gFile)
1438 {
1439 *fLog << warn << "MStatusDisplay::Write: No file found. Please create a TFile first." << endl;
1440 return 0;
1441 }
1442
1443 if (!gFile->IsOpen())
1444 {
1445 *fLog << warn << "MStatusDisplay::Write: File not open. Please open the TFile first." << endl;
1446 return 0;
1447 }
1448
1449 if (!gFile->IsWritable())
1450 {
1451 *fLog << warn << "MStatusDisplay::Write: File not writable." << endl;
1452 return 0;
1453 }
1454
1455 if (num==0)
1456 {
1457 *fLog << warn << "MStatusDisplay::Write: Tab doesn't contain an embedded Canvas... skipped." << endl;
1458 return 0;
1459 }
1460
1461 if (!gROOT->IsBatch() && num>=fTab->GetNumberOfTabs())
1462 {
1463 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
1464 return 0;
1465 }
1466 if (gROOT->IsBatch() && num>fBatch->GetSize())
1467 {
1468 *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
1469 return 0;
1470 }
1471
1472 TObjArray list;
1473
1474 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
1475 const Int_t from = num<0 ? 1 : num;
1476 const Int_t to = num<0 ? max : num+1;
1477
1478 TCanvas *c;
1479 for (int i=from; i<to; i++)
1480 if ((c = GetCanvas(i)))
1481 list.Add(c);
1482
1483 const Int_t n = list.Write(name, kSingleKey);
1484
1485 *fLog << inf << "MStatusDisplay: " << n << " keys written to file as key " << name << "." << endl;
1486
1487 return n;
1488}
1489
1490// --------------------------------------------------------------------------
1491//
1492// Use this to start the synchronous (GUI eventloop driven) tab update.
1493// Can also be used to change the update intervall. If millisec<0
1494// the intervall given in SetUpdateTime is used. If the intervall in
1495// SetUpdateTime is <0 nothing is done. (Call SetUpdateTime(-1) to
1496// disable the automatic update in a MEventloop.
1497//
1498void MStatusDisplay::StartUpdate(Int_t millisec)
1499{
1500 if (fIsLocked>1)
1501 return;
1502
1503 if (fTimer.GetTime()<TTime(0))
1504 return;
1505 fTimer.Start(millisec);
1506}
1507
1508// --------------------------------------------------------------------------
1509//
1510// Stops the automatic GUI update
1511//
1512void MStatusDisplay::StopUpdate()
1513{
1514 if (fIsLocked>1)
1515 return;
1516
1517 fTimer.Stop();
1518}
1519
1520// --------------------------------------------------------------------------
1521//
1522// Set the update interval for the GUI update, see StartUpdate.
1523//
1524void MStatusDisplay::SetUpdateTime(Long_t t)
1525{
1526 fTimer.SetTime(t);
1527}
1528
1529// --------------------------------------------------------------------------
1530//
1531// Set the background color in a canvas
1532//
1533void MStatusDisplay::CanvasSetFillColor(TPad &p, Int_t col) const
1534{
1535 TObject *obj;
1536
1537 // See also TPad::UseCurrentStyle
1538 TIter Next(p.GetListOfPrimitives());
1539 while ((obj=Next()))
1540 {
1541 if (obj->InheritsFrom(TPad::Class()))
1542 CanvasSetFillColor(*(TPad*)obj, col);
1543 if (obj->InheritsFrom(TFrame::Class()))
1544 ((TFrame*)obj)->SetFillColor(col);
1545 }
1546
1547 p.SetFillColor(col);
1548}
1549
1550void MStatusDisplay::AddExtension(TString &name, const TString &ext, Int_t num) const
1551{
1552 if (name.IsNull())
1553 {
1554 name = "status";
1555 if (num>0)
1556 {
1557 name += "-";
1558 name += num;
1559 }
1560 }
1561
1562 if (name.EndsWith("."+ext))
1563 return;
1564
1565 name += ".";
1566 name += ext;
1567}
1568
1569Bool_t MStatusDisplay::CheckTabForCanvas(int num) const
1570{
1571 if (gROOT->IsBatch())
1572 return num>0 && num<=fBatch->GetSize() || num<0;
1573
1574 if (num>=fTab->GetNumberOfTabs())
1575 {
1576 *fLog << warn << "Tab #" << num << " doesn't exist..." << endl;
1577 return kFALSE;
1578 }
1579 if (num==0)
1580 {
1581 *fLog << warn << "Tab #" << num << " doesn't contain an embedded canvas..." << endl;
1582 return kFALSE;
1583 }
1584 if (fTab->GetNumberOfTabs()<2 || !gPad)
1585 {
1586 *fLog << warn << "Sorry, you must have at least one existing canvas (gPad!=NULL)" << endl;
1587 return kFALSE;
1588 }
1589 return kTRUE;
1590}
1591
1592// --------------------------------------------------------------------------
1593//
1594// Insert the following two lines into the postscript header:
1595//
1596// %%DocumentPaperSizes: a4
1597// %%Orientation: Landscape
1598//
1599void MStatusDisplay::UpdatePSHeader(const TString &name) const
1600{
1601 const TString newstr("%%DocumentPaperSizes: a4\n%%Orientation: Landscape\n");
1602 const Int_t l = newstr.Length();
1603
1604 Long_t t[4]; // { id, size, flags, modtime }
1605 gSystem->GetPathInfo(name, t, t+1, t+2, t+3);
1606
1607 char *c[2] = { new char[l], new char[l] };
1608
1609 fstream f(name, ios::in|ios::out);
1610
1611 TString str;
1612 f >> str >> c[0][0]; // Read "%!PS-Adobe-2.0\n" (Mini Header)
1613 f.read(c[0], l);
1614 f.seekp(-l, ios::cur);
1615 f.write(newstr, l);
1616
1617 int i=0;
1618 while (1)
1619 {
1620 f.read(c[(i+1)%2], l);
1621 f.seekp(-l, ios::cur);
1622
1623 if (f)
1624 {
1625 f.write(c[i%2],l);
1626 i++;
1627 i%=2;
1628 continue;
1629 }
1630
1631 const Int_t ssz = str.Length()+1; // Length of Mini-Header
1632 const Int_t block = t[1]-ssz; // Length of block to be shifted
1633 const Int_t size = block%l; // Reminder
1634 const Int_t pos = (block/l)*l + ssz + 1; // Position to start writing
1635
1636 f.clear();
1637 f.seekp(pos);
1638 f.write(c[i%2], l);
1639 f.write(c[(i+1)%2], size);
1640 break;
1641 }
1642
1643 delete c[1];
1644 delete c[0];
1645}
1646
1647// --------------------------------------------------------------------------
1648//
1649// In case of num<0 all tabs are written into the PS file. If num>0
1650// the canvas in the corresponding tab is written to the file.
1651// Name is the name of the file (with or without extension).
1652//
1653// Returns the number of pages written.
1654//
1655// To write all tabs you can also use SaveAsPS(name)
1656//
1657Int_t MStatusDisplay::SaveAsPS(Int_t num, TString name)
1658{
1659 SetStatusLine1("Writing Postscript file...");
1660 SetStatusLine2("");
1661
1662 if (!CheckTabForCanvas(num))
1663 {
1664 SetStatusLine2("Failed!");
1665 return 0;
1666 }
1667
1668 AddExtension(name, "ps", num);
1669
1670 if (num<0)
1671 *fLog << inf << "Open ps-File: " << name << endl;
1672
1673 TPad *padsav = (TPad*)gPad;
1674 TVirtualPS *psave = gVirtualPS;
1675
1676 TDatime d;
1677
1678 TPostScript ps(name, 112);
1679 ps.SetBit(TPad::kPrintingPS);
1680 ps.PrintFast(13, "/nan {1} def ");
1681
1682 gVirtualPS = &ps;
1683
1684 //
1685 // Create a list to delete the canvas clones
1686 //
1687 TList l;
1688 l.SetOwner();
1689
1690 //
1691 // Create some GUI elements for a page legend
1692 //
1693 TLine line;
1694
1695 int page = 1;
1696
1697 //
1698 // Maintain tab numbers
1699 //
1700 const Int_t max = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
1701 const Int_t from = num<0 ? 1 : num;
1702 const Int_t to = num<0 ? max : num+1;
1703
1704 for (int i=from; i<to; i++)
1705 {
1706 TCanvas *c;
1707 if (!(c = GetCanvas(i)))
1708 {
1709 if (num<0)
1710 *fLog << inf << " - ";
1711 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
1712 continue;
1713 }
1714
1715 SetStatusLine2(Form("Tab #%d", i));
1716
1717 //
1718 // Init page and page size, make sure, that the canvas in the file
1719 // has the same Aspect Ratio than on the screen.
1720 //
1721 ps.NewPage();
1722
1723 //
1724 // 26 is used here to scale the canvas into a height of 26,
1725 // such that the page title can be set above the canvas...
1726 //
1727 Float_t psw = 26; //29.7; // A4 - width
1728 Float_t psh = 21.0; // A4 - height
1729
1730 const Float_t cw = c->GetWw();
1731 const Float_t ch = c->GetWh();
1732
1733 if (psw/psh>cw/ch)
1734 psw = cw/ch*psh;
1735 else
1736 psh = ch/cw*psw;
1737
1738 ps.Range(psw, psh); // A4
1739
1740 //
1741 // Clone canvas and change background color and schedule for
1742 // deletion
1743 //
1744 TCanvas *n = (TCanvas*)c->Clone();
1745 CanvasSetFillColor(*n, kWhite);
1746 l.Add(n);
1747 //
1748 // Paint canvas into root file
1749 //
1750 if (num<0)
1751 *fLog << inf << " - ";
1752 *fLog << inf << "Writing Tab #" << i << ": " << c->GetName() << " (" << c << ") ";
1753 if (num>0)
1754 *fLog << "to " << name;
1755 *fLog << "..." << flush;
1756
1757 n->SetBatch(kTRUE);
1758 n->Paint();
1759
1760 //
1761 // Use the canvas as coordinate system for the overlaying text
1762 //
1763 gPad = n;
1764
1765 //
1766 // Print overlaying text (NDC = %)
1767 //
1768 ps.SetTextColor(kBlack);
1769 ps.SetTextSize(0.015);
1770 ps.SetTextFont(22);
1771 ps.SetTextAlign(11); // left top
1772 ps.TextNDC(0, 1.02, TString(" ")+n->GetName());
1773 ps.SetTextAlign(21); // cent top
1774 ps.TextNDC(0.5, 1.02, TString("MARS - Magic Analysis and Reconstruction Software - ")+d.AsString());
1775 ps.SetTextAlign(31); // right top
1776 ps.TextNDC(1, 1.02, Form("Page No.%i (%i) ", page++, i));
1777 line.PaintLineNDC(0, 1.015, 1, 1.015);
1778
1779 //
1780 // Finish drawing page
1781 //
1782 n->SetBatch(kFALSE);
1783 if (num<0)
1784 *fLog << "done." << endl;
1785 }
1786
1787 gPad = NULL; // Important!
1788 l.Delete();
1789
1790 ps.Close();
1791 UpdatePSHeader(name);
1792
1793 gVirtualPS = psave;
1794 if (padsav)
1795 padsav->cd();
1796
1797 *fLog << inf << "done." << endl;
1798
1799 SetStatusLine2(Form("Done (%dpages)", page-1));
1800
1801 return page-1;
1802}
1803
1804Bool_t MStatusDisplay::SaveAsGIF(Int_t num, TString name)
1805{
1806 if (gROOT->IsBatch())
1807 {
1808 *fLog << warn << "Sorry, writing gif-files is not available in batch mode." << endl;
1809 return 0;
1810 }
1811 SetStatusLine1("Writing GIF file...");
1812 SetStatusLine2("");
1813
1814 if (!CheckTabForCanvas(num))
1815 {
1816 SetStatusLine2("Failed!");
1817 return 0;
1818 }
1819
1820 AddExtension(name, "gif", num);
1821
1822 if (num<0)
1823 *fLog << inf << "Writing gif-Files..." << endl;
1824
1825 TPad *padsav = (TPad*)gPad;
1826
1827 int page = 1;
1828
1829 //
1830 // Maintain tab numbers
1831 //
1832 const Int_t from = num<0 ? 1 : num;
1833 const Int_t to = num<0 ? fTab->GetNumberOfTabs() : num+1;
1834
1835 for (int i=from; i<to; i++)
1836 {
1837 TCanvas *c;
1838 if (!(c = GetCanvas(i)))
1839 {
1840 if (num<0)
1841 *fLog << inf << " - ";
1842 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
1843 continue;
1844 }
1845
1846 SetStatusLine2(Form("Tab #%d", i));
1847
1848 //
1849 // Clone canvas and change background color and schedule for
1850 // deletion
1851 //
1852 //TCanvas *n = (TCanvas*)c->Clone();
1853 //CanvasSetFillColor(*n, kWhite);
1854
1855 //
1856 // Paint canvas into root file
1857 //
1858 TString writename = name;
1859 if (num<0)
1860 {
1861 TString numname = "-";
1862 numname += i;
1863 writename.Insert(name.Last('.'), numname);
1864 }
1865 if (num<0)
1866 *fLog << inf << " - ";
1867 *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << c << ") ";
1868 if (num>0)
1869 *fLog << "to " << name;
1870 *fLog << "..." << flush;
1871
1872 c->Draw();
1873 c->SaveAs(writename);
1874 /*
1875 n->Draw();
1876 n->SaveAs(writename);
1877 delete n;
1878 */
1879
1880 if (num<0)
1881 *fLog << "done." << endl;
1882 }
1883
1884 padsav->cd();
1885
1886 *fLog << inf << "done." << endl;
1887
1888 SetStatusLine2("Done.");
1889
1890 return page-1;
1891}
1892
1893Bool_t MStatusDisplay::SaveAsC(Int_t num, TString name)
1894{
1895 SetStatusLine1("Writing C++ file...");
1896 SetStatusLine2("");
1897
1898 if (!CheckTabForCanvas(num))
1899 {
1900 SetStatusLine2("Failed!");
1901 return 0;
1902 }
1903
1904 AddExtension(name, "C", num);
1905
1906 if (num<0)
1907 *fLog << inf << "Writing C-Files..." << endl;
1908
1909 TPad *padsav = (TPad*)gPad;
1910
1911 int page = 1;
1912
1913 //
1914 // Maintain tab numbers
1915 //
1916 const Int_t from = num<0 ? 1 : num;
1917 const Int_t to = num<0 ? fTab->GetNumberOfTabs() : num+1;
1918
1919 for (int i=from; i<to; i++)
1920 {
1921 TCanvas *c;
1922 if (!(c = GetCanvas(i)))
1923 {
1924 if (num<0)
1925 *fLog << inf << " - ";
1926 *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
1927 continue;
1928 }
1929
1930 SetStatusLine2(Form("Tab #%d", i));
1931
1932 //
1933 // Clone canvas and change background color and schedule for
1934 // deletion
1935 //
1936 TCanvas *n = (TCanvas*)c->Clone();
1937 CanvasSetFillColor(*n, kWhite);
1938
1939 //
1940 // Paint canvas into root file
1941 //
1942 TString writename = name;
1943 if (num<0)
1944 {
1945 TString numname = "-";
1946 numname += i;
1947 writename.Insert(name.Last('.'), numname);
1948 }
1949 if (num<0)
1950 *fLog << inf << " - ";
1951 *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << n << ") ";
1952 if (num>0)
1953 *fLog << "to " << name;
1954 *fLog << "..." << flush;
1955
1956 n->SaveSource(writename, "");
1957 delete n;
1958
1959 if (num<0)
1960 *fLog << "done." << endl;
1961 }
1962
1963 padsav->cd();
1964
1965 *fLog << inf << "done." << endl;
1966
1967 SetStatusLine2("Done.");
1968
1969 return page-1;
1970}
1971
1972// --------------------------------------------------------------------------
1973//
1974// In case of num<0 all tabs are written into the PS file. If num>0
1975// the canvas in the corresponding tab is written to the file.
1976// Name is the name of the file (with or without extension).
1977//
1978// Returns the number of keys written.
1979//
1980// To write all tabs you can also use SaveAsPS(name)
1981//
1982Int_t MStatusDisplay::SaveAsRoot(Int_t num, TString name)
1983{
1984 SetStatusLine1("Writing root file...");
1985 SetStatusLine2("");
1986
1987 if (!CheckTabForCanvas(num))
1988 {
1989 SetStatusLine2("Failed!");
1990 return 0;
1991 }
1992
1993 AddExtension(name, "root", num);
1994
1995 TFile *fsave = gFile;
1996 TFile file(name, "RECREATE", "MARS - Status Window Contents", 9);
1997 const Int_t keys = Write(num);
1998 gFile = fsave;
1999
2000 SetStatusLine2("Done.");
2001
2002 return keys;
2003}
2004
2005Bool_t MStatusDisplay::HandleConfigureNotify(Event_t *evt)
2006{
2007 //cout << "----- Start -----" << endl;
2008
2009 UInt_t w = evt->fWidth;
2010 UInt_t h = evt->fHeight;
2011
2012 //cout << "Old: " << GetWidth() << " " << GetHeight() << " " << GetBorderWidth() << endl;
2013 //cout << "New: " << w << " " << h << endl;
2014
2015 Bool_t wchanged = w!=GetWidth();
2016 Bool_t hchanged = h!=GetHeight();
2017
2018 if (!wchanged && !hchanged)
2019 {
2020 Layout();
2021 return kTRUE;
2022 }
2023
2024 if (GetWidth()==1 && GetHeight()==1)
2025 return kTRUE;
2026
2027 // calculate the constant part of the window
2028 const UInt_t cw = GetWidth() -fTab->GetWidth();
2029 const UInt_t ch = GetHeight()-fTab->GetHeight();
2030
2031 // canculate new size of frame (canvas @ 1:sqrt(2))
2032 if (hchanged)
2033 w = (UInt_t)((h-ch)*sqrt(2.)+.5)+cw;
2034 else
2035 h = (UInt_t)((w-cw)/sqrt(2.)+.5)+ch;
2036
2037 //cout << "Res: " << w << " " << h << " " << evt->fX << " " << evt->fY << endl;
2038
2039 // resize frame
2040 Resize(w, h);
2041
2042 return kTRUE;
2043}
2044
2045Bool_t MStatusDisplay::HandleEvent(Event_t *event)
2046{
2047 /*
2048 if (event->fType!=9)
2049 {
2050 cout << "Event: " << event->fType << " ";
2051 cout << event->fX << " " << event->fY << endl;
2052 }
2053 */
2054 /*
2055 switch (event->fType) {
2056 case kConfigureNotify:
2057 //while (gVirtualX->CheckEvent(fId, kConfigureNotify, *event))
2058 // ;
2059 HandleConfigureNotify(event);
2060 return kTRUE;
2061 }
2062 */
2063 // if (event->fType==kConfigureNotify && event->fX!=0 && event->fY!=0)
2064 // return kTRUE;
2065
2066 return TGMainFrame::HandleEvent(event);
2067}
2068
Note: See TracBrowser for help on using the repository browser.