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

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