source: trunk/Mars/mbase/MStatusDisplay.cc @ 19259

Last change on this file since 19259 was 19259, checked in by tbretz, 8 months ago
root 6 need TMutex to be included.
File size: 99.8 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-2008
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// PrintPS().
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 <errno.h>
64#include <stdlib.h>               // mktemp (Ubunto 8.10)
65
66#include <fstream>                // fstream
67
68#include <TH1.h>                  // TH1::AddDirectory
69#include <TPDF.h>                 // TPDF
70#include <TSVG.h>                 // TSVG
71#include <TEnv.h>                 // TEnv
72#include <TLine.h>                // TLine
73#include <TMath.h>
74#include <TText.h>                // TText
75#include <TFile.h>                // gFile
76#include <TFrame.h>               // TFrame
77#include <TStyle.h>               // gStyle
78#include <TMutex.h>               // TMutex (since root 6)
79#include <TCanvas.h>              // TCanvas
80#include <TSystem.h>              // gSystem
81#include <TDatime.h>              // TDatime
82#include <TRandom.h>              // TRandom
83#include <TRegexp.h>              // TRegexp
84#include <TThread.h>              // TThread::Self()
85#include <TBrowser.h>             // TBrowser
86#include <TObjArray.h>            // TObjArray
87#include <TPostScript.h>          // TPostScript
88#include <TMethodCall.h>          // TMethodCall
89
90#include <TInterpreter.h>         // gInterpreter
91
92#include <TGTab.h>                // TGTab
93#include <TGLabel.h>              // TGLabel
94#include <TG3DLine.h>             // TGHorizontal3DLine
95#include <TGButton.h>             // TGPictureButton
96#include <TGTextView.h>           // TGTextView
97#include <TGComboBox.h>           // TGComboBox
98#include <TGStatusBar.h>          // TGStatusBar
99#include <TGFileDialog.h>         // TGFileDialog
100#include <TGProgressBar.h>        // TGHProgressBar
101#include <TGTextEditDialogs.h>    // TGPrintDialog
102#include <TRootEmbeddedCanvas.h>  // TRootEmbeddedCanvas
103
104#include "MString.h"
105
106#include "MLog.h"                 // MLog
107#include "MLogManip.h"            // inf, warn, err
108
109#include "MGList.h"               // MGList
110#include "MGMenu.h"               // MGMenu, TGMenu
111#include "MSearch.h"              // MSearch
112#include "MParContainer.h"        // MParContainer::GetDescriptor
113#include "MStatusArray.h"         // MStatusArray
114
115#if ROOT_VERSION_CODE <= ROOT_VERSION(5,22,00)
116#include "../mhbase/MH.h"
117#endif
118
119#undef DEBUG
120//#define DEBUG
121
122ClassImp(MStatusDisplay);
123
124using namespace std;
125
126// ------------ Workaround for a non working TGTextView::Search -------------
127#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,05)
128class MGTextView : public TGTextView
129{
130public:
131    MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, Int_t id = -1,
132               UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
133    TGTextView(parent, w, h, id, sboptions, back) {}
134    MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, TGText *text,
135               Int_t id = -1, UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
136    TGTextView(parent, w, h, text, id, sboptions, back) {}
137    MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, const char *string,
138               Int_t id = -1, UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
139    TGTextView(parent, w, h, string, id, sboptions, back) {}
140
141    void Mark(Long_t xPos, Long_t yPos) { TGTextView::Mark(xPos, yPos); }
142    void UnMark()                       { TGTextView::UnMark(); }
143
144    Bool_t Search(const char *string, Bool_t direction, Bool_t caseSensitive)
145    {
146        // Taken from TGTextView::Search and modified.
147
148        TGLongPosition pos, pos2;
149        pos2.fX = pos2.fY = 0;
150        if (fIsMarked) {
151            if (!direction)
152            {
153                pos2.fX = fMarkedStart.fX;
154                pos2.fY = fMarkedStart.fY;
155            }
156            else
157            {
158                pos2.fX = fMarkedEnd.fX + 1;
159                pos2.fY = fMarkedEnd.fY;
160            }
161        }
162        if (!fText->Search(&pos, pos2, string, direction, caseSensitive))
163            return kFALSE;
164        UnMark();
165        fIsMarked = kTRUE;
166        fMarkedStart.fY = fMarkedEnd.fY = pos.fY;
167        fMarkedStart.fX = pos.fX;
168        fMarkedEnd.fX = fMarkedStart.fX + strlen(string);
169        pos.fY = ToObjYCoord(fVisible.fY);
170        if ((fMarkedStart.fY < pos.fY) ||
171            (ToScrYCoord(fMarkedStart.fY) >= (Int_t)fCanvas->GetHeight()))
172            pos.fY = fMarkedStart.fY;
173        pos.fX = ToObjXCoord(fVisible.fX, pos.fY);
174        if ((fMarkedStart.fX < pos.fX) ||
175            (ToScrXCoord(fMarkedStart.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()))
176            pos.fX = fMarkedStart.fX;
177
178        SetVsbPosition((ToScrYCoord(pos.fY) + fVisible.fY)/fScrollVal.fY);
179        SetHsbPosition((ToScrXCoord(pos.fX, pos.fY) + fVisible.fX)/fScrollVal.fX);
180        DrawRegion(0, (Int_t)ToScrYCoord(fMarkedStart.fY), fCanvas->GetWidth(),
181                   UInt_t(ToScrYCoord(fMarkedEnd.fY+1) - ToScrYCoord(fMarkedEnd.fY)));
182
183        return kTRUE;
184    }
185};
186#else
187#define MGTextView TGTextView
188#endif
189
190// --------------------------------------------------------------------------
191
192TGCompositeFrame *MStatusDisplay::GetTabContainer(const char *name) const
193{
194#if ROOT_VERSION_CODE < ROOT_VERSION(4,03,05)
195    if (!fTab)
196        return 0;
197
198   TGFrameElement *el;
199   TGTabElement *tab = 0;
200   TGCompositeFrame *comp = 0;
201
202   TIter next(fTab->GetList());
203   next();           // skip first container
204
205   while ((el = (TGFrameElement *) next())) {
206      el = (TGFrameElement *) next();
207      comp = (TGCompositeFrame *) el->fFrame;
208      next();
209      tab = (TGTabElement *)el->fFrame;
210      if (name == tab->GetText()->GetString()) {
211         return comp;
212      }
213   }
214
215   return 0;
216#else
217   return fTab ? fTab->GetTabContainer(name) : 0;
218#endif
219}
220
221TGTabElement *MStatusDisplay::GetTabTab(const char *name) const
222{
223#if ROOT_VERSION_CODE < ROOT_VERSION(4,03,05)
224    if (!fTab)
225        return 0;
226
227   TGFrameElement *el;
228   TGTabElement *tab = 0;
229
230   TIter next(fTab->GetList());
231   next();           // skip first container
232
233   while ((el = (TGFrameElement *) next())) {
234      next();
235      tab = (TGTabElement *)el->fFrame;
236      if (name == tab->GetText()->GetString()) {
237         return tab;
238      }
239   }
240
241   return 0;
242#else
243   return fTab ? fTab->GetTabTab(name) : 0;
244#endif
245}
246// --------------------------------------------------------------------------
247
248
249// --------------------------------------------------------------------------
250//
251// Add menu bar to the GUI
252//
253void MStatusDisplay::AddMenuBar()
254{
255    //
256    // File Menu
257    //
258    MGPopupMenu *filemenu = new MGPopupMenu(gClient->GetDefaultRoot());
259    filemenu->AddEntry("New &Canvas",       kFileCanvas);
260    filemenu->AddEntry("New &Browser",      kFileBrowser);
261    filemenu->AddEntry("New &Tab",          kFileTab);
262    filemenu->AddSeparator();
263
264    const TString fname(MString::Format("Save %s.", gROOT->GetName()));
265    MGPopupMenu *savemenu = new MGPopupMenu(gClient->GetDefaultRoot());
266    savemenu->AddEntry(MString::Format("%s&ps",  fname.Data()),  kFileSaveAsPS);
267    savemenu->AddEntry(MString::Format("%sp&df", fname.Data()),  kFileSaveAsPDF);
268    savemenu->AddEntry(MString::Format("%s&svg", fname.Data()),  kFileSaveAsSVG);
269    savemenu->AddSeparator();
270    savemenu->AddEntry(MString::Format("%sp&ng", fname.Data()),  kFileSaveAsPNG);
271    savemenu->AddEntry(MString::Format("%s&gif", fname.Data()),  kFileSaveAsGIF);
272    savemenu->AddEntry(MString::Format("%s&jpg", fname.Data()),  kFileSaveAsJPG);
273    savemenu->AddEntry(MString::Format("%s&xpm", fname.Data()),  kFileSaveAsXPM);
274    savemenu->AddEntry(MString::Format("%s&tiff",fname.Data()),  kFileSaveAsTIFF);
275    savemenu->AddEntry(MString::Format("%s&bmp", fname.Data()),  kFileSaveAsBMP);
276    savemenu->AddEntry(MString::Format("%sx&ml", fname.Data()),  kFileSaveAsXML);
277    savemenu->AddEntry(MString::Format("%scs&v", fname.Data()),  kFileSaveAsCSV);
278    savemenu->AddSeparator();
279    savemenu->AddEntry(MString::Format("%s&C",    fname.Data()), kFileSaveAsC);
280    savemenu->AddEntry(MString::Format("%s&root", fname.Data()), kFileSaveAsRoot);
281    savemenu->AddEntry(MString::Format("%s&root (plain)", fname.Data()), kFileSaveAsPlainRoot);
282    savemenu->Associate(this);
283
284    filemenu->AddEntry("&Open...",          kFileOpen);
285    filemenu->AddPopup("&Save", savemenu);
286    filemenu->AddEntry("Save &As...",       kFileSaveAs);
287    filemenu->AddSeparator();
288    filemenu->AddEntry("&Reset",            kFileReset);
289    filemenu->AddSeparator();
290    filemenu->AddEntry("&Print",            kFilePrint);
291    filemenu->AddSeparator();
292    filemenu->AddEntry("C&lose",            kFileClose);
293    filemenu->AddEntry("E&xit",             kFileExit);
294    filemenu->Associate(this);
295
296    //
297    // Tab Menu
298    //
299    MGPopupMenu *tabmenu = new MGPopupMenu(gClient->GetDefaultRoot());
300    tabmenu->AddEntry("Next [&+]",          kTabNext);
301    tabmenu->AddEntry("Previous [&-]",      kTabPrevious);
302    tabmenu->AddSeparator();
303
304    const TString fname2(MString::Format("Save %s-i.", gROOT->GetName()));
305    MGPopupMenu *savemenu2 = new MGPopupMenu(gClient->GetDefaultRoot());
306    savemenu2->AddEntry(MString::Format("%s&ps",  fname2.Data()),  kTabSaveAsPS);
307    savemenu2->AddEntry(MString::Format("%sp&df", fname2.Data()),  kTabSaveAsPDF);
308    savemenu2->AddEntry(MString::Format("%s&svg", fname2.Data()),  kTabSaveAsSVG);
309    savemenu2->AddSeparator();
310    savemenu2->AddEntry(MString::Format("%sp&ng", fname2.Data()),  kTabSaveAsPNG);
311    savemenu2->AddEntry(MString::Format("%s&gif", fname2.Data()),  kTabSaveAsGIF);
312    savemenu2->AddEntry(MString::Format("%s&jpg", fname2.Data()),  kTabSaveAsJPG);
313    savemenu2->AddEntry(MString::Format("%s&xpm", fname2.Data()),  kTabSaveAsXPM);
314    savemenu2->AddEntry(MString::Format("%s&tiff",fname2.Data()),  kTabSaveAsTIFF);
315    savemenu2->AddEntry(MString::Format("%s&bmp", fname2.Data()),  kTabSaveAsBMP);
316    savemenu2->AddEntry(MString::Format("%sx&ml", fname2.Data()),  kTabSaveAsXML);
317    savemenu2->AddEntry(MString::Format("%scs&v", fname2.Data()),  kTabSaveAsCSV);
318    savemenu2->AddSeparator();
319    savemenu2->AddEntry(MString::Format("%s&C",    fname2.Data()), kTabSaveAsC);
320    savemenu2->AddEntry(MString::Format("%s&root", fname2.Data()), kTabSaveAsRoot);
321    savemenu2->Associate(this);
322
323    tabmenu->AddPopup("&Save", savemenu2);
324    tabmenu->AddEntry("Save tab &As...",    kTabSaveAs);
325    tabmenu->AddSeparator();
326    tabmenu->AddEntry("&Remove",            kTabRemove);
327    tabmenu->AddSeparator();
328    tabmenu->AddEntry("&Print",             kTabPrint);
329    tabmenu->Associate(this);
330
331    //
332    // Loop Menu
333    //
334    MGPopupMenu *loopmenu = new MGPopupMenu(gClient->GetDefaultRoot());
335    loopmenu->AddEntry("&Pause",       kLoopPause);
336    loopmenu->AddEntry("Single S&tep", kLoopStep);
337    loopmenu->AddSeparator();
338    loopmenu->AddEntry("&Stop",  kLoopStop);
339    loopmenu->Associate(this);
340
341    loopmenu->DisableEntry(kLoopStep);
342
343    //
344    // Loop Menu
345    //
346    MGPopupMenu *sizemenu = new MGPopupMenu(gClient->GetDefaultRoot());
347    sizemenu->AddEntry("Fit to 640x&480",   kSize640);
348    sizemenu->AddEntry("Fit to 768x&576",   kSize768);
349    sizemenu->AddEntry("Fit to 800x&600",   kSize800);
350    sizemenu->AddEntry("Fit to 960x7&20",   kSize960);
351    sizemenu->AddEntry("Fit to 1024x&768",  kSize1024);
352    sizemenu->AddEntry("Fit to 1152x&864",  kSize1152);
353    sizemenu->AddEntry("Fit to 1280x&1024", kSize1280);
354    sizemenu->AddEntry("Fit to 1400x1050",  kSize1400);
355    sizemenu->AddEntry("Fit to 1600x1200",  kSize1600);
356    sizemenu->AddEntry("Fit to &Desktop",   kSizeOptimum);
357    sizemenu->Associate(this);
358
359    //
360    // Log Menu
361    //
362    MGPopupMenu *logmenu = new MGPopupMenu(gClient->GetDefaultRoot());
363    logmenu->AddEntry("&Copy Selected", kLogCopy);
364    logmenu->AddEntry("Cl&ear all",     kLogClear);
365    logmenu->AddSeparator();
366    logmenu->AddEntry("Select &All",    kLogSelect);
367    logmenu->AddSeparator();
368    logmenu->AddEntry("&Find...",       kLogFind);
369    logmenu->AddSeparator();
370    logmenu->AddEntry("&Save",          kLogSave);
371    logmenu->AddEntry("Save &append",   kLogAppend);
372    logmenu->AddSeparator();
373    logmenu->AddEntry("&Print",         kLogPrint);
374    logmenu->Associate(this);
375
376    //
377    // Menu Bar
378    //
379    TGLayoutHints *layitem = new TGLayoutHints(kLHintsNormal, 0, 4, 0, 0);
380    fList->Add(layitem);
381
382    fMenuBar = new MGMenuBar(this, 1, 1, kHorizontalFrame);
383    fMenuBar->AddPopup("&File", filemenu, layitem);
384    fMenuBar->AddPopup("Lo&g",  logmenu,  layitem);
385    fMenuBar->AddPopup("&Size", sizemenu, layitem);
386    fMenuBar->AddPopup("&Tab",  tabmenu,  layitem);
387    fMenuBar->AddPopup("&Loop", loopmenu, layitem);
388    fMenuBar->BindKeys(this);
389    AddFrame(fMenuBar);
390
391    //
392    // Line below menu bar
393    //
394    TGLayoutHints *laylinesep  = new TGLayoutHints(kLHintsTop|kLHintsExpandX);
395    fList->Add(laylinesep);
396
397    TGHorizontal3DLine *linesep = new TGHorizontal3DLine(this);
398    AddFrame(linesep, laylinesep);
399
400    //
401    // Add everything to autodel list
402    //
403    fList->Add(savemenu);
404    fList->Add(savemenu2);
405    fList->Add(filemenu);
406    fList->Add(loopmenu);
407    fList->Add(sizemenu);
408    fList->Add(fMenuBar);
409    fList->Add(tabmenu);
410    fList->Add(logmenu);
411    fList->Add(linesep);
412}
413
414// --------------------------------------------------------------------------
415//
416// Adds an empty TGCompositeFrame which might be filled by the user
417//
418void MStatusDisplay::AddUserFrame()
419{
420    TGLayoutHints *lay=new TGLayoutHints(kLHintsExpandX);
421    fList->Add(lay);
422
423    fUserFrame = new TGCompositeFrame(this, 1, 1);
424    AddFrame(fUserFrame, lay);
425    fList->Add(fUserFrame);
426}
427
428// --------------------------------------------------------------------------
429//
430// Add the title tab
431//
432void MStatusDisplay::AddMarsTab()
433{
434    // Create Tab1
435    TGCompositeFrame *f = fTab->AddTab("-=MARS=-");
436
437    // Add list of tabs
438
439    TGComboBox *filter = new TGComboBox(f, kTabs);
440    fList->Add(filter);
441    filter->Associate(this);
442    filter->AddEntry("-=MARS=-", 0);
443    filter->Select(0);
444
445
446    TGLayoutHints *lay3 = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 10, 5);
447    fList->Add(lay3);
448    f->AddFrame(filter, lay3);
449
450    // Add MARS version
451    TGLabel *l = new TGLabel(f, MString::Format("Official Release: V%s", MARSVER));
452    fList->Add(l);
453
454    filter->SetWidth(5*l->GetWidth()/4);
455    filter->SetHeight(4*l->GetHeight()/3);
456    filter->GetListBox()->SetHeight(l->GetHeight()*16);
457
458    TGLayoutHints *layb = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 5, 5);
459    fList->Add(layb);
460    f->AddFrame(l, layb);
461
462    // Add root version
463    l = new TGLabel(f, MString::Format("Using ROOT v%s", ROOT_RELEASE));
464    fList->Add(l);
465
466    TGLayoutHints *lay = new TGLayoutHints(kLHintsCenterX|kLHintsTop);
467    fList->Add(lay);
468    f->AddFrame(l, lay);
469
470    {
471#define static static const
472#include "marslogo.xpm"
473#undef static
474
475        // Add Mars logo picture
476        const TGPicture *pic2 = fList->GetPicture("marslogo", marslogo);
477        if (pic2)
478        {
479            TGPictureButton *mars  = new TGPictureButton(f, pic2, kPicMars);
480            fList->Add(mars);
481            mars->Associate(this);
482
483            TGLayoutHints *lay2 = new TGLayoutHints(kLHintsCenterX|kLHintsCenterY, 10, 10, 5, 5);
484            fList->Add(lay2);
485            f->AddFrame(mars, lay2);
486        }
487    }
488
489    // Add date and time
490    l = new TGLabel(f, TDatime().AsString());
491    fList->Add(l);
492    f->AddFrame(l, lay);
493
494    // Add copyright notice
495    l = new TGLabel(f, MString::Format("(c) MARS Software Development, 2000-%d", TDatime().GetYear()));
496    fList->Add(l);
497    f->AddFrame(l, layb);
498
499    TGLayoutHints *layc = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 0, 5);
500    fList->Add(layc);
501
502    const char *txt = "<< Thomas Bretz >>";
503    l = new TGLabel(f, txt);
504    fList->Add(l);
505    f->AddFrame(l, layc);
506}
507
508// --------------------------------------------------------------------------
509//
510// Adds the logbook tab to the GUI if it was not added previously.
511//
512// The logbook is updated four times a second only if the tab is visible.
513//
514// You can redirect an output to a MLog-logstream by calling SetLogStream().
515// To disable redirction call SetLogStream(NULL)
516//
517// if enable==kFALSE the stdout is disabled/enabled. Otherwise stdout
518// is ignored.
519//
520void MStatusDisplay::SetLogStream(MLog *log, Bool_t enable)
521{
522    if (gROOT->IsBatch())
523        return;
524
525    if (log && fLogBox==NULL)
526    {
527        fLogIdx = fTab->GetNumberOfTabs();
528
529        // Create Tab1
530        TGCompositeFrame *f = AddRawTab("-Logbook-");//fTab->AddTab("-Logbook-");
531
532        // Create Text View
533        fLogBox = new MGTextView(f, 1, 1); // , -1, 0, TGFrame::GetDefaultFrameBackground());
534        if (fFont)
535            fLogBox->SetFont(fFont);
536        //fLogBox->Associate(this);
537
538        // Add List box to the tab
539        TGLayoutHints *lay = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY,2,2,2,2);
540        f->AddFrame(fLogBox, lay);
541
542        // layout and map tab
543        Layout();
544        MapSubwindows();
545
546        // make it visible
547        // FIXME: This is a workaround, because TApplication::Run is not
548        //        thread safe against ProcessEvents. We assume, that if
549        //        we are not in the Main-Thread ProcessEvents() is
550        //        called by the TApplication Event Loop...
551        if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
552            gClient->ProcessEventsFor(fTab);
553    }
554
555    if (log)
556    {
557        fLog = log;
558
559        log->SetOutputGui(fLogBox, kTRUE);
560        log->EnableOutputDevice(MLog::eGui);
561        if (!enable)
562            log->DisableOutputDevice(MLog::eStdout);
563
564        fLogTimer.Start();
565    }
566    else
567    {
568        fLogTimer.Stop();
569
570        fLog->DisableOutputDevice(MLog::eGui);
571        fLog->SetOutputGui(NULL);
572        if (!enable)
573            fLog->EnableOutputDevice(MLog::eStdout);
574
575        fLog = &gLog;
576    }
577}
578
579// --------------------------------------------------------------------------
580//
581// Add the Tabs and the predifined Tabs to the GUI
582//
583void MStatusDisplay::AddTabs()
584{
585    fTab = new TGTab(this, 300, 300);
586
587    AddMarsTab();
588
589    // Add fTab to Frame
590    TGLayoutHints *laytabs = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 5, 5, 5);
591    AddFrame(fTab, laytabs);
592
593    fList->Add(fTab);
594    fList->Add(laytabs);
595}
596
597// --------------------------------------------------------------------------
598//
599// Add the progress bar to the GUI. The Progress Bar range is set to
600// (0,1) as default.
601//
602void MStatusDisplay::AddProgressBar()
603{
604    TGLayoutHints *laybar=new TGLayoutHints(kLHintsExpandX, 5, 5, 5, 5);
605    fList->Add(laybar);
606
607    fBar=new TGHProgressBar(this);
608    fBar->SetRange(0, 1);
609    fBar->ShowPosition();
610    AddFrame(fBar, laybar);
611    fList->Add(fBar);
612}
613
614// --------------------------------------------------------------------------
615//
616// Set the progress bar position between 0 and 1. The Progress bar range
617// is assumed to be (0,1)
618//
619void MStatusDisplay::SetProgressBarPosition(Float_t p, Bool_t upd)
620{
621    if (!gClient || gROOT->IsBatch())
622        return;
623
624    fBar->SetPosition(p);
625    if (upd)
626        gClient->ProcessEventsFor(fBar);
627}
628
629// --------------------------------------------------------------------------
630//
631// Adds the status bar to the GUI
632//
633void MStatusDisplay::AddStatusBar()
634{
635    fStatusBar = new TGStatusBar(this, 1, 1);
636
637    //
638    // Divide it like the 'Golden Cut' (goldener Schnitt)
639    //
640    //     1-a     a
641    // 1: ------|----
642    //
643    // a/(1-a) = (1-a)/1
644    // a^2+a-1 = 0
645    //       a = (-1+-sqrt(1+4))/2 = sqrt(5)/2-1/2 = 0.618
646    //
647    Int_t p[] = {38-2, 62-8, 10};
648
649    fStatusBar->SetParts(p, 3);
650
651    TGLayoutHints *layb = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 5, 4, 0, 3);
652    AddFrame(fStatusBar, layb);
653
654    fList->Add(fStatusBar);
655    fList->Add(layb);
656}
657
658// --------------------------------------------------------------------------
659//
660// Change the text in the status line 1
661//
662void MStatusDisplay::SetStatusLine(const char *txt, Int_t i)
663{
664    if (gROOT->IsBatch())
665        return;
666    fStatusBar->SetText(txt, i);
667
668    // FIXME: This is a workaround, because TApplication::Run is not
669    //        thread safe against ProcessEvents. We assume, that if
670    //        we are not in the Main-Thread ProcessEvents() is
671    //        called by the TApplication Event Loop...
672    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
673        gClient->ProcessEventsFor(fStatusBar);
674}
675
676// --------------------------------------------------------------------------
677//
678// Display information about the name of a container
679//
680void MStatusDisplay::SetStatusLine2(const MParContainer &cont)
681{
682    SetStatusLine2(MString::Format("%s: %s", cont.GetDescriptor().Data(), cont.GetTitle()));
683}
684
685// --------------------------------------------------------------------------
686//
687// Get TGPopupMenu as defined by name from fMenuBar
688//
689TGPopupMenu *MStatusDisplay::GetPopup(const char *name)
690{
691    if (!fMenuBar)
692        return 0;
693
694    TGPopupMenu *m = fMenuBar->GetPopup(name);
695    if (!m)
696    {
697        *fLog << warn << name << " doesn't exist in menu bar." << endl;
698        return 0;
699    }
700
701    return m;
702}
703
704// --------------------------------------------------------------------------
705//
706// Default constructor. Opens a window with a progress bar. Get a pointer
707// to the bar by calling GetBar. This pointer can be used for the
708// eventloop.
709//
710// Be carefull: killing or closing the window while the progress meter
711//   is still in use may cause segmentation faults. Please kill the window
712//   always by deleting the corresponding object.
713//
714// You can give either width or height. (Set the value not given to -1)
715// The other value is calculated accordingly. If width and height are
716// given height is ignored. If width=height=0 an optimum size from
717// the desktop size is calculated.
718//
719// Update time default: 10s
720//
721MStatusDisplay::MStatusDisplay(Int_t w, Int_t h, Long_t t)
722: TGMainFrame((TGWindow*)((gClient?gClient:new TGClient),NULL), 1, 1), fName("MStatusDisplay"), fLog(&gLog), fBar(NULL), fTab(NULL), fTimer(this, t, kTRUE), fStatus(kLoopNone), fLogIdx(-1), fLogTimer(this, 250, kTRUE), fLogBox(NULL), fIsLocked(0)
723{
724    // p==NULL means: Take gClient->GetRoot() if not in batch mode
725    // see TGWindow::TGWindow()
726
727    // Make sure that the display is removed via RecursiveRemove
728    // from whereever possible.
729    SetBit(kMustCleanup);
730
731    //
732    // This is a possibility for the user to check whether this
733    // object has already been deleted. It will be removed
734    // from the list in the destructor.
735    //
736    gROOT->GetListOfSpecials()->Add(this);
737
738    fFont = gVirtualX->LoadQueryFont("7x13bold");
739    fMutex = new TMutex;
740
741    //
742    // In case we are in batch mode use a list of canvases
743    // instead of the Root Embedded Canvases in the TGTab
744    //
745    fBatch = new TList;
746    fBatch->SetOwner();
747
748    //
749    // Create a list handling GUI widgets
750    //
751    fList = new MGList;
752    fList->SetOwner();
753
754    //
755    // Create the layout hint for the root embedded canavses
756    //
757    fLayCanvas = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY);
758    fList->Add(fLayCanvas);
759
760    //
761    // Add Widgets (from top to bottom)
762    //
763    // In newer root versions gClient!=NULL in batch mode!
764    if (!gClient || !gClient->GetRoot() || gROOT->IsBatch()) // BATCH MODE
765    {
766        Resize(644, 484);
767        return;
768    }
769
770    AddMenuBar();
771    AddUserFrame();
772    AddTabs();
773    AddProgressBar();
774    AddStatusBar();
775
776    //
777    // set the smallest and biggest size of the Main frame
778    // and move it to its appearance position
779    SetWMSizeHints(566, 476, 2048, 1536, 1, 1);
780    MoveResize(rand()%100+566, rand()%100+476, 566, 476);
781    if (h>0)
782        SetDisplayHeight(h);
783    if (w>0)
784        SetDisplayWidth(w);
785    if (w==0 && h==0)
786        SetOptimumSize();
787
788    //
789    // Now do an automatic layout of the widgets and display the window
790    //
791    Layout();
792    MapSubwindows();
793
794    SetWindowName("Status Display");
795    SetIconName("Status Display");
796
797    MapWindow();
798
799    UpdateMemory();
800
801    // FIXME: This is a workaround, because TApplication::Run is not
802    //        thread safe against ProcessEvents. We assume, that if
803    //        we are not in the Main-Thread ProcessEvents() is
804    //        called by the TApplication Event Loop...
805    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
806        gSystem->ProcessEvents();
807}
808
809// --------------------------------------------------------------------------
810//
811// Destruct the window with all its tiles. Also the Progress Bar object
812// is deleted.
813//
814MStatusDisplay::~MStatusDisplay()
815{
816    fTimer.Stop();
817
818#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
819    fTab = NULL; // See HandleEvent
820#endif
821
822    //
823    // Delete object from global object table so it cannot
824    // be deleted by chance a second time
825    //
826    gInterpreter->DeleteGlobal(this);
827
828    //
829    // This is a possibility for the user to check whether this
830    // object has already been deleted. It has been added
831    // to the list in the constructor.
832    //
833    gROOT->GetListOfSpecials()->Remove(this);
834
835    SetLogStream(NULL);
836
837    //
838    // Delete the list of objects corresponding to this object
839    //
840    delete fList;
841
842    //
843    // Delete the list of canvases used in batch mode
844    // instead of the Root Embedded Canvases in the TGTab
845    //
846    delete fBatch;
847
848    //
849    // Delete the font used for the logging window
850    //
851    if (fFont)
852        gVirtualX->DeleteFont(fFont);
853
854    //
855    // Delete mutex
856    //
857    delete fMutex;
858}
859
860// --------------------------------------------------------------------------
861//
862// Takes a TGCompositeFrame as argument. Searches for the first
863// TRootEmbeddedCanvas which is contained by it and returns a pointer
864// to the corresponding TCanvas. If it isn't found NULL is returned.
865//
866TRootEmbeddedCanvas *MStatusDisplay::GetEmbeddedCanvas(TGCompositeFrame &cf)
867{
868    TIter Next(cf.GetList());
869
870    TGFrameElement *f;
871    while ((f=(TGFrameElement*)Next()))
872        if (f->fFrame->InheritsFrom(TRootEmbeddedCanvas::Class()))
873            return (TRootEmbeddedCanvas*)f->fFrame;
874
875    return NULL;
876}
877
878// --------------------------------------------------------------------------
879//
880// Takes a TGCompositeFrame as argument. Searches for the first
881// TRootEmbeddedCanvas which is contained by it and returns a pointer
882// to the corresponding TCanvas. If it isn't found NULL is returned.
883//
884TCanvas *MStatusDisplay::GetCanvas(TGCompositeFrame &cf)
885{
886    TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(cf);
887    return ec ? ec->GetCanvas() : NULL;
888}
889
890// --------------------------------------------------------------------------
891//
892// Returns the range of tabs containing valid canvases for the condition
893// num.
894//
895void MStatusDisplay::GetCanvasRange(Int_t &from, Int_t &to, Int_t num) const
896{
897    const Int_t max  = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
898
899    from = num<0 ?   1 : num;
900    to   = num<0 ? max : num+1;
901}
902
903// --------------------------------------------------------------------------
904//
905// Returns GetCanvas of the i-th Tab.
906//
907TCanvas *MStatusDisplay::GetCanvas(int i) const
908{
909    if (gROOT->IsBatch())
910        return (TCanvas*)fBatch->At(i-1);
911
912    if (i<0 || i>=fTab->GetNumberOfTabs())
913    {
914        *fLog << warn << "MStatusDisplay::GetCanvas: Out of range." << endl;
915        return NULL;
916    }
917
918    return GetCanvas(*fTab->GetTabContainer(i));
919}
920
921// --------------------------------------------------------------------------
922//
923// Returns j-th pad of the i-th Tab.
924// Sets the pad to fill an entire window.
925//
926// This function can be used if single pad's out of an MStatusDisplay
927// have to be stored to file.
928//
929// ATTENTION: This function modifies the requested tab in MStatusDisplay itself!
930//
931TVirtualPad *MStatusDisplay::GetFullPad(const Int_t i, const Int_t j)
932{
933    if (!GetCanvas(i))
934    {
935        *fLog << warn << "MStatusDisplay::GetFullPad: i-th canvas not dound." << endl;
936        return NULL;
937    }
938
939    TVirtualPad *vpad = GetCanvas(i)->GetPad(j);
940    if (!vpad)
941    {
942        *fLog << warn << "MStatusDisplay::GetFullPad: Pad is out of range." << endl;
943        return NULL;
944    }
945
946    vpad->SetPad(0.,0.,1.,1.);
947    return vpad;
948}
949
950// --------------------------------------------------------------------------
951//
952// Searches for a TRootEmbeddedCanvas in the TGCompositeFramme of the
953// Tab with the name 'name'. Returns the corresponding TCanvas or
954// NULL if something isn't found.
955//
956TCanvas *MStatusDisplay::GetCanvas(const TString &name) const
957{
958    if (gROOT->IsBatch())
959        return (TCanvas*)fBatch->FindObject(name);
960
961    TGFrameElement *f;
962    TIter Next(fTab->GetList());
963    while ((f=(TGFrameElement*)Next()))
964    {
965        TObject *frame = f->fFrame;
966        if (!frame->InheritsFrom(TGTabElement::Class()))
967            continue;
968
969        TGTabElement *tab = (TGTabElement*)frame;
970        if (tab->GetString()==name)
971            break;
972    }
973
974    // Search for the next TGCompositeFrame in the list
975    while ((f=(TGFrameElement*)Next()))
976    {
977        TObject *frame = f->fFrame;
978        if (frame->InheritsFrom(TGCompositeFrame::Class()))
979            return GetCanvas(*(TGCompositeFrame*)frame);
980    }
981
982    return NULL;
983}
984
985// --------------------------------------------------------------------------
986//
987// Calls TCanvas::cd(), for the canvas returned by GetCanvas.
988//
989Bool_t MStatusDisplay::CdCanvas(const TString &name)
990{
991    TCanvas *c = GetCanvas(name);
992    if (!c)
993        return kFALSE;
994
995    c->cd();
996    return kTRUE;
997}
998
999// --------------------------------------------------------------------------
1000//
1001// Return the number of user added tabs (not that in batch mode this
1002// exclude tabs without a canvas)
1003//
1004Int_t MStatusDisplay::GetNumTabs() const
1005{
1006    return gROOT->IsBatch() ? fBatch->GetEntries() : fTab->GetNumberOfTabs()-1;
1007}
1008
1009TGCompositeFrame *MStatusDisplay::AddRawTab(const char *name)
1010{
1011    // Add new tab
1012    TGCompositeFrame *f = fTab->AddTab(name);
1013
1014    TGComboBox *box = (TGComboBox*)fList->FindWidget(kTabs);
1015    box->AddEntry(name, box->GetListBox()->GetNumberOfEntries());
1016
1017    // layout and map new tab
1018    Layout();
1019    MapSubwindows();
1020    Layout();
1021
1022    UpdateMemory();
1023
1024    // display new tab in the main frame
1025    // FIXME: This is a workaround, because TApplication::Run is not
1026    //        thread safe against ProcessEvents. We assume, that if
1027    //        we are not in the Main-Thread ProcessEvents() is
1028    //        called by the TApplication Event Loop...
1029    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
1030        gClient->ProcessEventsFor(fTab);
1031
1032    *fLog << inf3 << "Adding Raw Tab '" << name << "' (" << f->GetWidth() << "x";
1033    *fLog << f->GetHeight() << ")" << endl;
1034
1035    // return pointer to new canvas
1036    return f;
1037}
1038
1039// --------------------------------------------------------------------------
1040//
1041// This function was connected to all created canvases. It is used
1042// to redirect GetObjectInfo into our own status bar.
1043//
1044// The 'connection' is done in AddTab
1045//
1046void MStatusDisplay::EventInfo(Int_t /*event*/, Int_t px, Int_t py, TObject *selected)
1047{
1048    //  Writes the event status in the status bar parts
1049    if (!selected)
1050        return;
1051
1052    TCanvas *c = (TCanvas*)gTQSender;
1053
1054    TVirtualPad* save=gPad;
1055
1056    gPad = c ? c->GetSelectedPad() : NULL;
1057
1058    if (gPad)
1059    {
1060        // Find the object which will get picked by the GetObjectInfo
1061        // due to buffer overflows in many root-versions
1062        // in TH1 and TProfile we have to work around and implement
1063        // our own GetObjectInfo which make everything a bit more
1064        // complicated.
1065#if ROOT_VERSION_CODE > ROOT_VERSION(5,22,00)
1066        SetStatusLine2(selected->GetObjectInfo(px,py));
1067#else
1068        TObjLink *link=0;
1069        static_cast<TPad*>(gPad)->Pick(px, py, link);
1070
1071        const TObject *o = link ? link->GetObject() : 0;
1072        if (o)
1073            SetStatusLine2(MH::GetObjectInfo(px, py, *o));
1074#endif
1075    }
1076
1077    gPad=save;
1078}
1079
1080// --------------------------------------------------------------------------
1081//
1082// Adds a new tab with the name 'name'. Adds a TRootEmbeddedCanvas to the
1083// tab and returns a reference to the corresponding TCanvas.
1084//
1085TCanvas &MStatusDisplay::AddTab(const char *name, const char *title)
1086{
1087    /*
1088    if (GetCanvas(name))
1089    {
1090        *fLog << warn;
1091        *fLog << "WARNING - A canvas '" << name << "' is already existing in the Status Display." << endl;
1092        *fLog << "          This can cause unexpected crahes!" << endl;
1093    }*/
1094
1095    gROOT->SetSelectedPad(0);
1096
1097    if (gROOT->IsBatch())
1098    {
1099        // 4 = 2*default border width of a canvas
1100        const UInt_t cw = GetWidth();
1101        const UInt_t ch = 2*cw/3 + 25; // 25: Menu, etc
1102
1103        // The constructor of TCanvas adds the canvas to the global list
1104        // of canvases gROOT->GetListOfCanvases(). If a canvas with an
1105        // identical name exists already in this list, the canvas is
1106        // deleted. In normal operation this might make sense and doesn't harm
1107        // because the embedded canvases behave different.
1108        // By creating the canvas without a name it is made sure that no
1109        // older canvas/tab vanished silently from the system (deleted from
1110        // the construtor). To make the handling of our canvases nevertheless
1111        // work well the name is set later. The list of canvases is also
1112        // part of the list of cleanups, thus fBatch need not to be added
1113        // to the list of cleanups.
1114        TCanvas *c = new TCanvas("", title?title:"", -cw, ch);
1115        c->SetName(name);
1116        c->SetFillColor(10); // White
1117        c->SetFrameBorderMode(0);
1118        c->SetBorderMode(0);
1119        fBatch->Add(c);
1120
1121        *fLog << inf3 << "Adding Canvas '" << name << "' (" << c->GetWw() << "x";
1122        *fLog << c->GetWh() << ", TCanvas=" << c << ")" << endl;
1123
1124        // Remove the canvas from the global list to make sure it is
1125        // not found by gROOT->FindObject
1126        //gROOT->GetListOfCanvases()->Remove(c);
1127        //gROOT->GetListOfCleanups()->Add(c);
1128
1129        return *c;
1130    }
1131
1132    // Add new tab
1133    TGCompositeFrame *f = fTab->AddTab(name);
1134
1135    // create root embedded canvas and add it to the tab
1136    TRootEmbeddedCanvas *ec = new TRootEmbeddedCanvas(name, f, f->GetWidth(), f->GetHeight(), kSunkenFrame);
1137    f->AddFrame(ec, fLayCanvas);
1138    fList->Add(ec);
1139
1140    // set background and border mode of the canvas
1141    TCanvas &c = *ec->GetCanvas();
1142
1143    if (title)
1144        c.SetTitle(title);
1145
1146    c.SetFillColor(10); // White
1147    c.SetFrameBorderMode(0);
1148    c.SetBorderMode(0);
1149
1150    // If kNoContextMenu set set kNoContextMenu of the canvas
1151    if (TestBit(kNoContextMenu))
1152        c.SetBit(kNoContextMenu);
1153
1154    // Connect all TCanvas::ProcessedEvent to this->EventInfo
1155    // This means, that after TCanvas has processed an event
1156    // EventInfo of this class is called, see TCanvas::HandleInput
1157    c.Connect("ProcessedEvent(Int_t,Int_t,Int_t,TObject*)",
1158              "MStatusDisplay", this, "EventInfo(Int_t,Int_t,Int_t,TObject*)");
1159
1160    // Make sure that root itself doesn't try to call GetObjectInfo
1161    // This is now handled from EventsInfo. This is necessary
1162    // due to the buffer overflow bug in GetObjectInfo of
1163    // TProfile and TH1
1164    c.ResetBit(TCanvas::kShowEventStatus);
1165
1166    // Remove the canvas from the global list to make sure it is
1167    // not found by gROOT->FindObject
1168    //gROOT->GetListOfCanvases()->Remove(&c);
1169    //gROOT->GetListOfCleanups()->Add(&c);
1170
1171    TGComboBox *box = (TGComboBox*)fList->FindWidget(kTabs);
1172    box->AddEntry(name, box->GetListBox()->GetNumberOfEntries());
1173
1174    // layout and map new tab
1175    Layout();          // seems to layout the TGCompositeFrame
1176    MapSubwindows();   // maps the TGCompositeFrame
1177    Layout();          // layout the embedded canvas in the frame
1178
1179    UpdateMemory();
1180
1181    // display new tab in the main frame
1182    // FIXME: This is a workaround, because TApplication::Run is not
1183    //        thread safe against ProcessEvents. We assume, that if
1184    //        we are not in the Main-Thread ProcessEvents() is
1185    //        called by the TApplication Event Loop...
1186    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
1187        gClient->ProcessEventsFor(fTab);
1188
1189    *fLog << inf3 << "Adding Tab '" << name << "' (" << f->GetWidth() << "x";
1190    *fLog << f->GetHeight() << ", TCanvas=" << &c << ")" << endl;
1191
1192    // return pointer to new canvas
1193    return c;
1194}
1195
1196// --------------------------------------------------------------------------
1197//
1198// Update a canvas in a tab, takes the corresponding TGCompositeFrame
1199// as an argument. This is necessary, because not all functions
1200// changing the contents of a canvas or pad can call SetModified()
1201// for the corresponding tab. If this is not called correctly the
1202// tab won't be updated calling TCanvas::Update(). So we simply
1203// redraw it by our own (instead we could recursively call
1204// TPad::Modified() for everything contained by the TCanvas and
1205// call TCanvas::Update() afterwards)
1206//
1207void MStatusDisplay::UpdateTab(TGCompositeFrame *f)
1208{
1209    if (!f)
1210        return;
1211
1212    //
1213    // If we are in a multithreaded environment (gThreadXAR) we
1214    // have to make sure, that thus function is called from
1215    // the main thread.
1216    //
1217    if (gThreadXAR)
1218    {
1219        // Tell the X-Requester how to call this method
1220        const TString str = MString::Format("%ld", (ULong_t)f);
1221
1222        TMethodCall call(IsA(), "UpdateTab", "NULL");
1223        void *arr[4] = { NULL, &call, this, (void*)(const char*)str };
1224
1225        // If this is not the main thread return
1226        if (((*gThreadXAR)("METH", 4, arr, NULL)))
1227            return;
1228    }
1229
1230    TCanvas *c=GetCanvas(*f);
1231    if (!c)
1232        return;
1233
1234    const TString name  = c->GetName();
1235    const TString title = c->GetTitle();
1236
1237    if (!gROOT->IsBatch())
1238        fStatusBar->SetText(title, 0);
1239
1240    // It seems that we cannot use this because an update
1241    // initiated by a gui event can interfere with the regular
1242    // update from the timer and then ProcessEvents will
1243    // end in an infinite loop.
1244    // SetStatusLine1(title);
1245
1246
1247    //
1248    // Secure calls to update the tabs against itself, at least
1249    // c->Paint() or c->Flush() may crash X (bad drawable).
1250    // This makes sure, that a X call is not interuppted by
1251    // another X-call which was started from an gui interrrupt
1252    // in the same thread
1253    //
1254    const Int_t rc = fMutex->TryLock();
1255    if (rc==13)
1256        gLog << warn << "MStatusDisplay::UpdateTab - mutex is already locked by this thread." << endl;
1257
1258    if (rc)
1259        return;
1260
1261#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,02)
1262    TPad *padsav = (TPad*)gPad;
1263    if (!gPad)
1264        c->cd();
1265#endif
1266
1267    if (!c->IsBatch())
1268        c->FeedbackMode(kFALSE);  // Goto double buffer mode
1269
1270    //
1271    // Doing this ourself gives us the possibility to repaint
1272    // the canvas in any case (Paint() instead of PaintModified())
1273    //
1274    c->Paint();                   // Repaint all pads
1275    c->Flush();                   // Copy all pad pixmaps to the screen
1276
1277#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,02)
1278    if (padsav)
1279        padsav->cd();
1280    else
1281        gPad=NULL;
1282#endif
1283
1284    //c->SetCursor(kCross);
1285
1286    // Old version
1287    //c->Modified();
1288    //c->Update();
1289    //c->Paint();
1290
1291    fMutex->UnLock();
1292}
1293
1294TString MStatusDisplay::PrintDialog(TString &p, TString &c, TString &t, const char *ext)
1295{
1296    // If not in batch mode open a user dialog
1297    if (!gROOT->IsBatch())
1298    {
1299        char *cprinter = StrDup(p);
1300        char *ccmd     = StrDup(c);
1301
1302        Int_t rc=0;
1303        new TGPrintDialog(fClient->GetRoot(), this, 400, 150, &cprinter, &ccmd, &rc);
1304        if (rc)
1305        {
1306            p = cprinter; // default has been changed
1307            c = ccmd;
1308        }
1309
1310        delete [] cprinter;
1311        delete [] ccmd;
1312
1313        if (!rc)
1314            return "";
1315    }
1316
1317    if (c.Contains("%f") && ext)
1318    {
1319        // Get temporary file name
1320        TString name = "mars";
1321
1322        FILE *f = gSystem->TempFileName(name, t);
1323        if (!f)
1324        {
1325            *fLog << warn << "MStatusDisplay::PrintDialog: Couldn't create temporary file in " << t << endl;
1326            SetStatusLine2("failed!");
1327            return "";
1328        }
1329        fclose(f);
1330
1331        // remove temp file
1332        gSystem->Unlink(name);
1333        name += ".";
1334        name += ext;
1335
1336        t = name;
1337    }
1338
1339    // compile command
1340    TString cmd(c);
1341
1342    // if sprinter.IsNull we assume that everything around %p can
1343    // be omitted and the program uses some kind of default
1344    if (p.IsNull())
1345    {
1346        TString sub;
1347        while (1)
1348        {
1349            sub = TString(cmd(TRegexp(" .*%p.* "))).Strip(TString::kBoth);
1350            if (sub.IsNull())
1351                break;
1352
1353            cmd.ReplaceAll(sub, "");
1354        }
1355    }
1356
1357    cmd.ReplaceAll("%p", p);
1358    cmd.ReplaceAll("%f", t);
1359
1360    return cmd;
1361}
1362
1363// --------------------------------------------------------------------------
1364//
1365// Saves the given canvas (pad) or all pads (num<0) as a temporary
1366// postscript file and prints it.
1367//
1368// The default command line c is: lpr -P%p %f
1369//   %p: printer name
1370//   %f: temporary file name
1371//
1372// The default printer name p is: <empty>
1373//
1374// Both can be changed in .rootrc by:
1375//   PrintPS.Printer
1376//   PrintPS.Command
1377//
1378// Ant the location of the temporary file t can by changed by
1379//   Print.Directory
1380// the default is the system default directory (normally /tmp)
1381//
1382Int_t MStatusDisplay::PrintPS(Int_t num, const char *p, const char *c, const char *t)
1383{
1384    static TString sprinter = gEnv->GetValue("PrintPS.Printer", p&&*p?p:"");
1385    static TString scmd     = gEnv->GetValue("PrintPS.Command", c&&*c?c:"lpr -P%p %f");
1386
1387    TString tmp = gEnv->GetValue("Print.Directory", t&&*t?t:gSystem->TempDirectory());
1388
1389    TString cmd = PrintDialog(sprinter, scmd, tmp, "ps");
1390    if (cmd.IsNull())
1391        return 0;
1392
1393    // set status lines
1394    SetStatusLine1("Printing...");
1395    SetStatusLine2("");
1396
1397    // print to temporary file
1398    const Int_t pages = SaveAsPS(num, tmp);
1399
1400    // check
1401    if (!pages)
1402    {
1403        *fLog << warn << "MStatusDisplay::Print: Sorry, couldn't save file as temporary postscript!" << endl;
1404        SetStatusLine2("Failed!");
1405        return 0;
1406    }
1407
1408    // execute command
1409    *fLog << dbg << "Executing: " << cmd << endl;
1410    gSystem->Exec(cmd);
1411
1412    // remove temporary file
1413    gSystem->Unlink(tmp);
1414
1415    SetStatusLine2(MString::Format("Done (%dpage(s))", pages));
1416
1417    return pages;
1418}
1419
1420// --------------------------------------------------------------------------
1421//
1422// Remove tab no i if this tab contains a TRootEmbeddedCanvas
1423//
1424void MStatusDisplay::RemoveTab(int i)
1425{
1426    TGCompositeFrame *f = fTab->GetTabContainer(i);
1427    if (!f)
1428        return;
1429
1430    TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(*f);
1431    if (!ec)
1432        return;
1433
1434    TCanvas *c = ec->GetCanvas();
1435    if (!c)
1436        return;
1437
1438    // Repair the "Workaround" being in the RecursiveRemove list
1439    // but not in a list checked by gROOT->FindObject
1440    //gROOT->GetListOfCleanups()->Remove(c);
1441    //gROOT->GetListOfCanvases()->Add(c);
1442
1443    // FIXME: Due to our workaround this is necessary for a successfull deletion
1444    //c->cd();
1445
1446    const TString name(c->GetName());
1447
1448    f->RemoveFrame(ec);
1449    delete fList->Remove(ec);
1450
1451    fTab->RemoveTab(i);
1452    fTab->SetTab(0);
1453
1454    TGComboBox *box = (TGComboBox*)fList->FindWidget(kTabs);
1455    box->RemoveEntry(i);
1456    for (int j=i; j<box->GetListBox()->GetNumberOfEntries(); j++)
1457    {
1458        TGTextLBEntry *entry = (TGTextLBEntry *)box->GetListBox()->Select(j+1, kFALSE);
1459        box->AddEntry(entry->GetText()->GetString(), j);
1460        box->RemoveEntry(j+1);
1461    }
1462    box->GetListBox()->Select(0);
1463
1464    // Looks strange...
1465    // const Int_t n = fTab->GetNumberOfTabs();
1466    // fTab->SetTab(i<=n-1 ? i : i-1);
1467
1468    // layout and map new tab
1469    Layout();          // seems to layout the TGCompositeFrame
1470    MapSubwindows();   // maps the TGCompositeFrame
1471    Layout();          // layout the embedded canvas in the frame
1472
1473    UpdateMemory();
1474
1475    // display new tab in the main frame
1476    // FIXME: This is a workaround, because TApplication::Run is not
1477    //        thread safe against ProcessEvents. We assume, that if
1478    //        we are not in the Main-Thread ProcessEvents() is
1479    //        called by the TApplication Event Loop...
1480    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
1481        gClient->ProcessEventsFor(fTab);
1482
1483    *fLog << inf << "Removed Tab #" << i << " '" << name << "'" << endl;
1484}
1485
1486// --------------------------------------------------------------------------
1487//
1488// Use this to check whether the MStatusDisplay still contains the
1489// TCanvas c. It could be removed meanwhile by menu usage.
1490//
1491Bool_t MStatusDisplay::HasCanvas(const TCanvas *c) const
1492{
1493    if (!c)
1494        return kFALSE;
1495
1496    // If you encounter unexpected crashes here, check if
1497    // a canvas is existing twice in the list or has been
1498    // deleted by accident. (Check AddTab)
1499
1500    if (gROOT->IsBatch())
1501        return (Bool_t)fBatch->FindObject(c);
1502
1503    for (int i=1; i<fTab->GetNumberOfTabs(); i++)
1504        if (c==GetCanvas(i))
1505            return kTRUE;
1506    return kFALSE;
1507}
1508
1509/*
1510    if (...)
1511       fMenu->AddPopup("&CaOs", fCaOs, NULL);
1512    else
1513       fMenu->RemovePopup("CaOs");
1514    fMenu->Resize(fMenu->GetDefaultSize());
1515    MapSubwindows();
1516    MapWindow();
1517 */
1518
1519void MStatusDisplay::Reset()
1520{
1521    if (gROOT->IsBatch())
1522    {
1523        fBatch->Delete();
1524        return;
1525    }
1526
1527    for (int i=fTab->GetNumberOfTabs()-1; i>0; i--)
1528        RemoveTab(i);
1529}
1530
1531Bool_t MStatusDisplay::SaveLogAsPS(const char *n) const
1532{
1533    TString name(n);
1534    AddExtension(name, "ps");
1535
1536    // Code taken from TGTextEdit::Print
1537    const TString pipe = MString::Format("a2ps -o%s", name.Data());
1538    FILE *p = gSystem->OpenPipe(pipe, "w");
1539    if (!p)
1540    {
1541        *fLog << err << "ERROR - Couldn't open pipe " << pipe << ": " << strerror(errno) << endl;
1542        return kFALSE;
1543    }
1544
1545    TGText *text = fLogBox->GetText();
1546
1547    char   *buf1, *buf2;
1548    Long_t  len;
1549    ULong_t i = 0;
1550    TGLongPosition pos;
1551
1552    Bool_t rc = kTRUE;
1553
1554    pos.fX = pos.fY = 0;
1555    while (pos.fY < text->RowCount())
1556    {
1557        len = text->GetLineLength(pos.fY);
1558        buf1 = text->GetLine(pos, len);
1559        buf2 = new char[len + 2];
1560        strncpy(buf2, buf1, (UInt_t)len);
1561        buf2[len]   = '\n';
1562        buf2[len+1] = '\0';
1563        while (buf2[i] != '\0') {
1564            if (buf2[i] == '\t') {
1565                ULong_t j = i+1;
1566                while (buf2[j] == 16 && buf2[j] != '\0')
1567                    j++;
1568                strcpy(buf2+i+1, buf2+j);
1569            }
1570            i++;
1571        }
1572
1573        len = sizeof(char)*(strlen(buf2)+1);
1574
1575        const size_t ret = fwrite(buf2, len, 1, p);
1576        delete [] buf1;
1577        delete [] buf2;
1578
1579        if (ret!=1)
1580        {
1581            *fLog << err << "ERROR - fwrite to pipe " << pipe << " failed: " << strerror(errno) << endl;
1582            rc = kFALSE;
1583            break;
1584        }
1585
1586        pos.fY++;
1587    }
1588    gSystem->ClosePipe(p);
1589
1590    return rc;
1591}
1592
1593// --------------------------------------------------------------------------
1594//
1595// Print the log text.
1596//
1597// The default command line c is: a2ps -P%p
1598//   %p: printer name
1599//
1600// The default printer name p is: <empty>
1601//
1602// Both can be changed in .rootrc by:
1603//   PrintText.Printer
1604//   PrintText.Command
1605//
1606Bool_t MStatusDisplay::PrintLog(const char *p, const char *c)
1607{
1608    static TString sprinter = gEnv->GetValue("PrintText.Printer", p&&*p?p:"");
1609    static TString scmd     = gEnv->GetValue("PrintText.Command", c&&*c?c:"a2ps -P%p");
1610
1611    TString tmp;
1612    TString cmd = PrintDialog(sprinter, scmd, tmp);
1613    if (cmd.IsNull())
1614        return kFALSE;
1615
1616    // set status lines
1617    SetStatusLine1("Printing...");
1618    SetStatusLine2("");
1619
1620    // print to temporary file
1621    if (!SaveLogAsPS(cmd))
1622    {
1623        *fLog << warn << "MStatusDisplay::PrintLog: Sorry, couldn't create postscript!" << endl;
1624        SetStatusLine2("Failed!");
1625        return kFALSE;
1626    }
1627
1628    // execute command
1629    *fLog << dbg << "Executing: " << cmd << endl;
1630    gSystem->Exec(cmd);
1631
1632    SetStatusLine2("Done.");
1633
1634    return kTRUE;
1635}
1636
1637// --------------------------------------------------------------------------
1638//
1639// Process the kC_COMMAND, kCM_MENU  messages
1640//
1641Bool_t MStatusDisplay::ProcessMessageCommandMenu(Long_t id)
1642{
1643    switch (id)
1644    {
1645    case kLoopPause:
1646        {
1647            TGPopupMenu *m = GetPopup("Loop");
1648            if (!m)
1649                return kTRUE;
1650
1651            if (fStatus==kLoopNone)
1652            {
1653                fStatus = (Status_t)kLoopPause;
1654                m->CheckEntry(kLoopPause);
1655                m->EnableEntry(kLoopStep);
1656                return kTRUE;
1657            }
1658            if (fStatus==kLoopPause)
1659            {
1660                fStatus = (Status_t)kLoopNone;
1661                m->UnCheckEntry(kLoopPause);
1662                m->DisableEntry(kLoopStep);
1663                return kTRUE;
1664            }
1665        }
1666        return kTRUE;
1667
1668    case kLoopStep:
1669        fStatus = (Status_t)kLoopStep;
1670        return kTRUE;
1671
1672    case kLoopStop:
1673    case kFileClose:
1674    case kFileExit:
1675        if (id==kFileExit || id==kFileClose)
1676            if (Close())
1677                delete this;
1678        fStatus = (Status_t)id;
1679        return kTRUE;
1680
1681    case kFileCanvas:
1682        new TCanvas;
1683        return kTRUE;
1684
1685    case kFileBrowser:
1686        new TBrowser;
1687        return kTRUE;
1688
1689    case kFileTab:
1690        AddTab(MString::Format("%d", fTab->GetNumberOfTabs()));
1691        return kTRUE;
1692
1693    case kFileReset:
1694        Reset();
1695        return kTRUE;
1696
1697    case kFileOpen:
1698        Open();
1699        return kTRUE;
1700
1701    case kFileSaveAs:
1702        SaveAs();
1703        return kTRUE;
1704
1705    case kFileSaveAsPS:
1706        SaveAsPS();
1707        return kTRUE;
1708
1709    case kFileSaveAsPDF:
1710        SaveAsPDF();
1711        return kTRUE;
1712
1713    case kFileSaveAsSVG:
1714        SaveAsSVG();
1715        return kTRUE;
1716
1717    case kFileSaveAsPNG:
1718        SaveAsPNG();
1719        return kTRUE;
1720
1721    case kFileSaveAsGIF:
1722        SaveAsGIF();
1723        return kTRUE;
1724
1725    case kFileSaveAsXPM:
1726        SaveAsXPM();
1727        return kTRUE;
1728
1729    case kFileSaveAsJPG:
1730        SaveAsJPG();
1731        return kTRUE;
1732
1733    case kFileSaveAsTIFF:
1734        SaveAsTIFF();
1735        return kTRUE;
1736
1737    case kFileSaveAsBMP:
1738        SaveAsBMP();
1739        return kTRUE;
1740
1741    case kFileSaveAsXML:
1742        SaveAsXML();
1743        return kTRUE;
1744
1745    case kFileSaveAsCSV:
1746        SaveAsCSV();
1747        return kTRUE;
1748
1749    case kFileSaveAsC:
1750        SaveAsC();
1751        return kTRUE;
1752
1753    case kFileSaveAsRoot:
1754        SaveAsRoot();
1755        return kTRUE;
1756
1757    case kFileSaveAsPlainRoot:
1758        SaveAsPlainRoot(kTRUE);
1759        return kTRUE;
1760
1761    case kFilePrint:
1762        PrintPS();
1763        return kTRUE;
1764
1765    case kTabSaveAs:
1766        SaveAs(fTab->GetCurrent());
1767        return kTRUE;
1768
1769    case kTabSaveAsPS:
1770        SaveAsPS(fTab->GetCurrent());
1771        return kTRUE;
1772
1773    case kTabSaveAsPDF:
1774        SaveAsPDF(fTab->GetCurrent());
1775        return kTRUE;
1776
1777    case kTabSaveAsSVG:
1778        SaveAsSVG(fTab->GetCurrent());
1779        return kTRUE;
1780
1781    case kTabSaveAsPNG:
1782        SaveAsPNG(fTab->GetCurrent());
1783        return kTRUE;
1784
1785    case kTabSaveAsGIF:
1786        SaveAsGIF(fTab->GetCurrent());
1787        return kTRUE;
1788
1789    case kTabSaveAsXPM:
1790        SaveAsXPM(fTab->GetCurrent());
1791        return kTRUE;
1792
1793    case kTabSaveAsJPG:
1794        SaveAsJPG(fTab->GetCurrent());
1795        return kTRUE;
1796
1797    case kTabSaveAsTIFF:
1798        SaveAsTIFF(fTab->GetCurrent());
1799        return kTRUE;
1800
1801    case kTabSaveAsBMP:
1802        SaveAsBMP(fTab->GetCurrent());
1803        return kTRUE;
1804
1805    case kTabSaveAsXML:
1806        SaveAsXML(fTab->GetCurrent());
1807        return kTRUE;
1808
1809    case kTabSaveAsCSV:
1810        SaveAsCSV(fTab->GetCurrent());
1811        return kTRUE;
1812
1813    case kTabSaveAsC:
1814        SaveAsC(fTab->GetCurrent());
1815        return kTRUE;
1816
1817    case kTabSaveAsPlainRoot:
1818        SaveAsPlainRoot(fTab->GetCurrent());
1819        return kTRUE;
1820
1821    case kTabSaveAsRoot:
1822        SaveAsRoot(fTab->GetCurrent());
1823        return kTRUE;
1824
1825    case kTabPrint:
1826        PrintPS(fTab->GetCurrent());
1827        return kTRUE;
1828
1829    case kTabNext:
1830        fTab->SetTab(fTab->GetCurrent()+1);
1831        return kTRUE;
1832
1833    case kTabPrevious:
1834        fTab->SetTab(fTab->GetCurrent()-1);
1835        return kTRUE;
1836
1837    case kTabRemove:
1838        RemoveTab(fTab->GetCurrent());
1839        return kTRUE;
1840
1841    case kSize640:
1842        SetDisplaySize(640, 480);
1843        return kTRUE;
1844    case kSize768: 
1845        SetDisplaySize(768, 576);
1846        return kTRUE;
1847    case kSize800: 
1848        SetDisplaySize(800, 600);
1849        return kTRUE;
1850    case kSize960: 
1851        SetDisplaySize(960, 720);
1852        return kTRUE;
1853    case kSize1024: 
1854        SetDisplaySize(1024, 768);
1855        return kTRUE;
1856    case kSize1152:
1857        SetDisplaySize(1152, 864);
1858        return kTRUE;
1859    case kSize1280: 
1860        SetDisplaySize(1280, 1024);
1861        return kTRUE;
1862    case kSize1400:
1863        SetDisplaySize(1400, 1050);
1864        return kTRUE;
1865    case kSize1600:
1866        SetDisplaySize(1600, 1200);
1867        return kTRUE;
1868    case kSizeOptimum:
1869        SetOptimumSize();
1870        return kTRUE;
1871
1872    case kLogClear:
1873        fLogBox->Clear();
1874        return kTRUE;
1875    case kLogCopy:
1876        fLogBox->Copy();
1877        return kTRUE;
1878    case kLogSelect:
1879        fLogBox->SelectAll();
1880        return kTRUE;
1881    case kLogFind:
1882        new MSearch(this);
1883        return kTRUE;
1884    case kLogSave:
1885        SetStatusLine1("Saving log...");
1886        SetStatusLine2("");
1887        *fLog << inf << "Saving log... " << flush;
1888        if (fLogBox->GetText()->Save(MString::Format("%s.log", gROOT->GetName())))
1889        {
1890            *fLog << "done." << endl;
1891            SetStatusLine2("done.");
1892        }
1893        else
1894        {
1895            *fLog << "failed!" << endl;
1896            SetStatusLine2("Failed!");
1897        }
1898        return kTRUE;
1899
1900    case kLogAppend:
1901        SetStatusLine1("Appending log...");
1902        SetStatusLine2("");
1903        *fLog << inf << "Appending log... " << flush;
1904        if (fLogBox->GetText()->Append(MString::Format("%s.log", gROOT->GetName())))
1905        {
1906            *fLog << "done." << endl;
1907            SetStatusLine2("done.");
1908        }
1909        else
1910        {
1911            *fLog << "failed!" << endl;
1912            SetStatusLine2("Failed!");
1913        }
1914        return kTRUE;
1915
1916    case kLogPrint:
1917        PrintLog();
1918        return kTRUE;
1919#ifdef DEBUG
1920    default:
1921        cout << "Command-Menu #" << id << endl;
1922#endif
1923    }
1924    return kTRUE;
1925
1926}
1927
1928// --------------------------------------------------------------------------
1929//
1930// Process the kC_COMMAND messages
1931//
1932Bool_t MStatusDisplay::ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2)
1933{
1934    switch (submsg)
1935    {
1936    case kCM_MENU: // 1
1937        return ProcessMessageCommandMenu(mp1); // mp2=userdata
1938    case kCM_TAB:  // 8
1939        /*
1940         for (int i=0; i<fTab->GetNumberOfTabs(); i++)
1941         fTab->GetTabContainer(i)->UnmapWindow();
1942         */
1943        UpdateTab(fTab->GetTabContainer(mp1));
1944        //fTab->GetTabContainer(mp1)->MapWindow();
1945
1946        /*
1947        if (mp1>0)
1948            fMenu->AddPopup("&CaOs", fCaOs, NULL);
1949        else
1950            fMenu->RemovePopup("CaOs");
1951        fMenu->Resize(fMenu->GetDefaultSize());
1952        MapSubwindows();
1953        MapWindow();
1954        */
1955        return kTRUE;
1956    case kCM_COMBOBOX: // 7
1957        if (mp1==kTabs)
1958            fTab->SetTab(mp2);
1959        return kTRUE;
1960#ifdef DEBUG
1961    case kCM_MENUSELECT: // 2
1962        cout << "Command-Menuselect #" << mp1 << " (UserData=" << (void*)mp2 << ")" << endl;
1963        return kTRUE;
1964
1965    case kCM_BUTTON: // 3
1966        cout << "Command-Button." << endl;
1967        return kTRUE;
1968
1969    case kCM_CHECKBUTTON: // 4
1970        cout << "Command-CheckButton." << endl;
1971        return kTRUE;
1972
1973    case kCM_RADIOBUTTON: // 5
1974        cout << "Command-RadioButton." << endl;
1975        return kTRUE;
1976
1977    case kCM_LISTBOX: // 6
1978        cout << "Command-Listbox #" << mp1 << " (LineId #" << mp2 << ")" << endl;
1979        return kTRUE;
1980    default:
1981        cout << "Command: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
1982#endif
1983    }
1984    return kTRUE;
1985}
1986
1987// --------------------------------------------------------------------------
1988//
1989// Process the kC_TEXTVIEW messages
1990//
1991Bool_t MStatusDisplay::ProcessMessageTextview(Long_t /*submsg*/, Long_t /*mp1*/, Long_t /*mp2*/)
1992{
1993    // kC_TEXTVIEW, kTXT_ISMARKED, widget id, [true|false]                  //
1994    // kC_TEXTVIEW, kTXT_DATACHANGE, widget id, 0                           //
1995    // kC_TEXTVIEW, kTXT_CLICK2, widget id, position (y << 16) | x)         //
1996    // kC_TEXTVIEW, kTXT_CLICK3, widget id, position (y << 16) | x)         //
1997    // kC_TEXTVIEW, kTXT_F3, widget id, true                                //
1998    // kC_TEXTVIEW, kTXT_OPEN, widget id, 0                                 //
1999    // kC_TEXTVIEW, kTXT_CLOSE, widget id, 0                                //
2000    // kC_TEXTVIEW, kTXT_SAVE, widget id, 0                                 //
2001#ifdef DEBUG
2002    switch (submsg)
2003    {
2004    case kTXT_ISMARKED:
2005        cout << "Textview-IsMarked #" << mp1 << " " << (mp2?"yes":"no") << endl;
2006        return kTRUE;
2007
2008    case kTXT_DATACHANGE:
2009        cout << "Textview-DataChange #" << mp1 << endl;
2010        return kTRUE;
2011
2012    case kTXT_CLICK2:
2013        cout << "Textview-Click2 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
2014        return kTRUE;
2015
2016    case kTXT_CLICK3:
2017        cout << "Textview-Click3 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
2018        return kTRUE;
2019
2020    case kTXT_F3:
2021        cout << "Textview-F3 #" << mp1 << endl;
2022        return kTRUE;
2023
2024    case kTXT_OPEN:
2025        cout << "Textview-Open #" << mp1 << endl;
2026        return kTRUE;
2027
2028    case kTXT_CLOSE:
2029        cout << "Textview-Close #" << mp1 << endl;
2030        return kTRUE;
2031
2032    case kTXT_SAVE:
2033        cout << "Textview-Save #" << mp1 << endl;
2034        return kTRUE;
2035
2036    default:
2037        cout << "Textview: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
2038    }
2039#endif
2040    return kTRUE;
2041}
2042
2043// --------------------------------------------------------------------------
2044//
2045// Process the kC_USER messages
2046//
2047Bool_t MStatusDisplay::ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2)
2048{
2049    // kS_START, case sensitive | backward<<1, char *txt
2050    switch (submsg)
2051    {
2052    case kS_START:
2053        fLogBox->Search((char*)mp2, !(mp1&2>>1), mp1&1);
2054        return kTRUE;
2055#ifdef DEBUG
2056    default:
2057        cout << "User: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
2058#endif
2059    }
2060    return kTRUE;
2061}
2062
2063// --------------------------------------------------------------------------
2064//
2065// Process the messages from the GUI
2066//
2067Bool_t MStatusDisplay::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2)
2068{
2069    // Can be found in WidgetMessageTypes.h
2070#ifdef DEBUG
2071    cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
2072    cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
2073#endif
2074    switch (GET_MSG(msg))
2075    {
2076    case kC_COMMAND:  // 1
2077        return ProcessMessageCommand(GET_SUBMSG(msg), mp1, mp2);
2078
2079    case kC_TEXTVIEW: // 9
2080        return ProcessMessageTextview(GET_SUBMSG(msg), mp1, mp2);
2081
2082    case kC_USER:     // 1001
2083        return ProcessMessageUser(GET_SUBMSG(msg), mp1, mp2);
2084    }
2085#ifdef DEBUG
2086    cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
2087    cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
2088#endif
2089    return kTRUE;
2090}
2091
2092Bool_t MStatusDisplay::Close()
2093{
2094    // Got close message for this MainFrame. Calls parent CloseWindow()
2095    // (which destroys the window) and terminate the application.
2096    // The close message is generated by the window manager when its close
2097    // window menu item is selected.
2098
2099    // CloseWindow must be overwritten because otherwise CloseWindow
2100    // and the destructor are calling DestroyWindow which seems to be
2101    // in conflict with the TRootEmbeddedCanvas.
2102
2103    // FIXME: Make sure that the Status Display is deleted from every
2104    //        where (eg Eventloop) first!
2105
2106    //gLog << dbg << fName << " is on heap: " << (int)IsOnHeap() << endl;
2107
2108    if (TestBit(kExitLoopOnExit) || TestBit(kExitLoopOnClose))
2109    {
2110        //gLog << dbg << "CloseWindow() calling ExitLoop." << endl;
2111        gSystem->ExitLoop();
2112    }
2113
2114    if (fIsLocked<=0 && IsOnHeap())
2115        return kTRUE;
2116
2117    fStatus = kFileExit;
2118    return kFALSE;
2119}
2120
2121void MStatusDisplay::CloseWindow()
2122{
2123    if (Close())
2124        delete this;
2125}
2126
2127// --------------------------------------------------------------------------
2128//
2129// Calls SetBit(kNoContextMenu) for all TCanvas objects found in the
2130// Tabs.
2131//
2132void MStatusDisplay::SetNoContextMenu(Bool_t flag)
2133{
2134    if (fIsLocked>1 || gROOT->IsBatch())
2135        return;
2136
2137    flag ? SetBit(kNoContextMenu) : ResetBit(kNoContextMenu);
2138
2139    for (int i=1; i<fTab->GetNumberOfTabs(); i++)
2140    {
2141        TCanvas *c = GetCanvas(i);
2142        if (c)
2143            flag ? c->SetBit(kNoContextMenu) : c->ResetBit(kNoContextMenu);
2144    }
2145}
2146
2147// --------------------------------------------------------------------------
2148//
2149// Update the memory display in the status bar
2150//
2151void MStatusDisplay::UpdateMemory() const
2152{
2153    const TString path = MString::Format("/proc/%d/status", gSystem->GetPid());
2154    if (gSystem->AccessPathName(path, kFileExists))
2155        return;
2156
2157    TEnv env(path);
2158    const UInt_t kb = env.GetValue("VmSize", 0);
2159    if (kb==0)
2160        return;
2161
2162    char type = 'k';
2163    Float_t val = kb;
2164
2165    if (val>999)
2166    {
2167        type = 'M';
2168        val /= 1000;
2169    }
2170    if (val>999)
2171    {
2172        type = 'G';
2173        val /= 1000;
2174    }
2175    const TString txt = MString::Format("%.1f%c", val, type);
2176    fStatusBar->SetText(txt, 2);
2177}
2178
2179// --------------------------------------------------------------------------
2180//
2181// Updates the canvas (if existing) in the currenly displayed Tab.
2182// The update intervall is controlled by StartUpdate and StopUpdate
2183//
2184Bool_t MStatusDisplay::HandleTimer(TTimer *timer)
2185{
2186    if (gROOT->IsBatch())
2187        return kTRUE;
2188
2189    UpdateMemory();
2190
2191    const Int_t c = fTab->GetCurrent();
2192
2193    // Skip Legend Tab
2194    if (c==0)
2195        return kTRUE;
2196
2197    // Update a canvas tab (if visible)
2198    if (timer==&fTimer && c!=fLogIdx)
2199    {
2200        UpdateTab(fTab->GetCurrentContainer());
2201        return kTRUE;
2202    }
2203
2204    // update the logbook tab (if visible)
2205    if (timer==&fLogTimer && c==fLogIdx)
2206    {
2207        fLog->UpdateGui();
2208
2209        /*
2210        if (!fLogBox->TestBit(kHasChanged))
2211            return kTRUE;
2212
2213            fLogBox->ResetBit(kHasChanged);
2214            */
2215        return kTRUE;
2216    }
2217
2218    return kTRUE;
2219}
2220
2221// --------------------------------------------------------------------------
2222//
2223// Find an object in a canvas (uses MStatusArray as helper)
2224//
2225void MStatusDisplay::PrintContent(Option_t *o) const
2226{
2227    MStatusArray(*this).Print(o);
2228}
2229
2230// --------------------------------------------------------------------------
2231//
2232// Find an object in a canvas (uses MStatusArray as helper)
2233//
2234TObject *MStatusDisplay::FindObjectInCanvas(const char *obj, const char *base, const char *canv) const
2235{
2236    return MStatusArray(*this).FindObjectInCanvas(obj, base, canv);
2237}
2238
2239// --------------------------------------------------------------------------
2240//
2241// Draws a clone of a canvas into a new canvas. Taken from TCanvas.
2242//
2243void MStatusDisplay::DrawClonePad(TCanvas &newc, TCanvas &oldc) const
2244{
2245    //copy pad attributes
2246    newc.Range(oldc.GetX1(),oldc.GetY1(),oldc.GetX2(),oldc.GetY2());
2247    newc.SetTickx(oldc.GetTickx());
2248    newc.SetTicky(oldc.GetTicky());
2249    newc.SetGridx(oldc.GetGridx());
2250    newc.SetGridy(oldc.GetGridy());
2251    newc.SetLogx(oldc.GetLogx());
2252    newc.SetLogy(oldc.GetLogy());
2253    newc.SetLogz(oldc.GetLogz());
2254    newc.SetBorderSize(oldc.GetBorderSize());
2255    newc.SetBorderMode(oldc.GetBorderMode());
2256    ((TAttLine&)oldc).Copy((TAttLine&)newc);
2257    ((TAttFill&)oldc).Copy((TAttFill&)newc);
2258    ((TAttPad&)oldc).Copy((TAttPad&)newc);
2259
2260    // This must be there: Otherwise GetDrawOption() won't work
2261    TVirtualPad *padsav = gPad;
2262    oldc.cd();
2263
2264    const Bool_t store = TH1::AddDirectoryStatus();
2265    TH1::AddDirectory(kFALSE);
2266
2267    //copy primitives
2268    TObject *obj;
2269    TIter next(oldc.GetListOfPrimitives());
2270    while ((obj=next()))
2271    {
2272        // Old line - I think it is not necessary anymore because of the cd()
2273        //gROOT->SetSelectedPad(&newc);
2274
2275        // Now make a clone of the object
2276        TObject *clone = obj->Clone();
2277
2278        // Clone also important bits (FIXME: Is this correct)
2279        clone->SetBit(obj->TestBits(kCannotPick|kNoContextMenu));
2280
2281        // Now make sure that the clones are deleted at a later time
2282        clone->SetBit(kCanDelete|kMustCleanup);
2283
2284        // FIXME: This is a workaround for the problem with the MAstroCatalog in
2285        // MHFalseSource. It doesn't harm. We'll still try to find the reason
2286        //if (clone->IsA()==TPad::Class())
2287        //    gROOT->GetListOfCleanups()->Add(clone);
2288
2289        // Add the clone and its draw-option to the current pad
2290        TVirtualPad *save2 = gPad;
2291        gPad = &oldc; // Don't do this before Clone()!
2292        newc.GetListOfPrimitives()->Add(clone, obj->GetDrawOption());
2293        gPad = save2;
2294    }
2295    newc.Modified();
2296    newc.Update();
2297
2298    TH1::AddDirectory(store);
2299
2300    padsav->cd();
2301}
2302
2303// --------------------------------------------------------------------------
2304//
2305// Display the contexts of a TObjArray in the display (all canvases)
2306//
2307Bool_t MStatusDisplay::Display(const TObjArray &list, const char *tab)
2308{
2309    TIter Next(&list);
2310
2311    TObject *o=Next();
2312    if (!o)
2313    {
2314        *fLog << err << "MStatusDisplay::Display: No entry in TObjArray." << endl;
2315        return kFALSE;
2316    }
2317
2318    // The first entry in the list is a TNamed which is expected to
2319    // contain the status display title.
2320    fTitle = o->GetTitle();
2321
2322    TCanvas *c;
2323    while ((c=(TCanvas*)Next()))
2324        //if (!GetCanvas(c->GetName()))
2325        if (c->InheritsFrom(TCanvas::Class()))
2326            if (!tab || c->GetName()==(TString)tab)
2327                DrawClonePad(AddTab(c->GetName(), c->GetTitle()), *c);
2328
2329    return kTRUE;
2330}
2331
2332// --------------------------------------------------------------------------
2333//
2334// Reads the contents of a saved MStatusDisplay from a file.
2335//
2336Int_t MStatusDisplay::Read(const char *name, const char *tab)
2337{
2338    if (!gFile)
2339    {
2340        *fLog << warn << "MStatusDisplay::Read: No file found. Please create a TFile first." << endl;
2341        return 0;
2342    }
2343
2344    if (!gFile->IsOpen())
2345    {
2346        *fLog << warn << "MStatusDisplay::Read: File not open. Please open the TFile first." << endl;
2347        return 0;
2348    }
2349
2350    MStatusArray list;
2351
2352    Int_t n = list.Read(name);
2353
2354    //
2355    // If no status display was found with this name try to find canvases
2356    // in the file and display them instead.
2357    //
2358    if (n==0)
2359    {
2360        // Either read the title from the file or create our own
2361        TNamed *title=0;
2362        gFile->GetObject("Title", title); // FIXME: Is the list allowed to take ownership?
2363        list.Add(title ? title : new TNamed(GetName(), GetTitle()));
2364
2365        const Bool_t store = TH1::AddDirectoryStatus();
2366        TH1::AddDirectory(kFALSE);
2367
2368        TIter Next(gFile->GetListOfKeys());
2369        TObject *key = 0;
2370        while ((key=Next()))
2371        {
2372            MStatusArray *arr=0;
2373            gFile->GetObject(key->GetName(), arr);
2374            if (arr)
2375            {
2376                Display(*arr, tab);
2377                n++;
2378                continue;
2379            }
2380
2381            if (tab && key->GetName()!=(TString)tab)
2382                continue;
2383
2384            TCanvas *c=0;
2385            gFile->GetObject(key->GetName(), c);
2386
2387            // If key doesn't correspond to a TCanvas create a new canvas
2388            // and draw the object itself instead.
2389            if (!c)
2390            {
2391                TObject *obj = gFile->Get(key->GetName());
2392
2393                if (MParContainer::Overwrites(TObject::Class(), *obj, "Draw") ||
2394                    MParContainer::Overwrites(TObject::Class(), *obj, "Paint"))
2395                {
2396                    AddTab(key->GetName(), key->GetTitle());
2397                    obj->SetBit(kCanDelete);
2398                    obj->Draw();
2399                }
2400                // FIXME: Is the object deleted?
2401                continue;
2402            }
2403
2404            // Add the canvas to the list
2405            const TString _name  = c->GetName();
2406            const TString _title = c->GetTitle();
2407            if (_title.IsNull() || _name==_title)
2408                c->SetTitle(gFile->GetName());
2409            list.Add(c);
2410        }
2411
2412        TH1::AddDirectory(store);
2413
2414        if (list.GetEntries()<=1)
2415        {
2416            *fLog << warn << "MStatusDisplay::Read: No drawable objects read from " << gFile->GetName() << endl;
2417            return 0;
2418        }
2419
2420        *fLog << inf << "MStatusDisplay: " << list.GetEntries()-1 << " canvases directly read from file." << endl;
2421    }
2422
2423
2424    if (!Display(list, tab))
2425    {
2426        *fLog << err << "MStatusDisplay::Display: No entries found." << endl;
2427        return 0;
2428    }
2429
2430    if (n==0)
2431        return list.GetEntries();
2432
2433    *fLog << inf << "MStatusDisplay: Key " << name << " with " << n << " keys read from file." << endl;
2434    return n;
2435}
2436
2437// --------------------------------------------------------------------------
2438//
2439// Add all canvases to the MStatusArray
2440//
2441void MStatusDisplay::FillArray(MStatusArray &list, Int_t num) const
2442{
2443    Int_t from, to;
2444    GetCanvasRange(from, to, num);
2445
2446    TCanvas *c;
2447    for (int i=from; i<to; i++)
2448        if ((c = GetCanvas(i)))
2449            list.Add(c);
2450}
2451
2452// --------------------------------------------------------------------------
2453//
2454// Writes the contents of a MStatusDisplay to a file.
2455//
2456Int_t MStatusDisplay::Write(Int_t num, const char *name, Option_t *opt) const
2457{
2458    if (!gFile)
2459    {
2460        *fLog << warn << "MStatusDisplay::Write: No file found. Please create a TFile first." << endl;
2461        return 0;
2462    }
2463
2464    if (!gFile->IsOpen())
2465    {
2466        *fLog << warn << "MStatusDisplay::Write: File not open. Please open the TFile first." << endl;
2467        return 0;
2468    }
2469
2470    if (!gFile->IsWritable())
2471    {
2472        *fLog << warn << "MStatusDisplay::Write: File not writable." << endl;
2473        return 0;
2474    }
2475
2476    if (num==0)
2477    {
2478        *fLog << warn << "MStatusDisplay::Write: Tab doesn't contain an embedded Canvas... skipped." << endl;
2479        return 0;
2480    }
2481
2482    if (!gROOT->IsBatch() && num>=fTab->GetNumberOfTabs())
2483    {
2484        *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
2485        return 0;
2486    }
2487    if (gROOT->IsBatch() && num>fBatch->GetSize())
2488    {
2489        *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
2490        return 0;
2491    }
2492
2493    Int_t n = 0; // Number of keys written
2494
2495    TNamed named("Title", fTitle.Data());
2496
2497    if (TString(opt)=="plain")
2498    {
2499        // Get canvas range to store
2500        Int_t from, to;
2501        GetCanvasRange(from, to, num);
2502
2503        n += named.Write();
2504
2505        TCanvas *c;
2506        for (int i=from; i<to; i++)
2507            if ((c = GetCanvas(i)))
2508                n += c->Write();
2509    }
2510    else
2511    {
2512        // Be careful: So far Display() assumes that the TNamed
2513        // is the first entry in the list
2514        MStatusArray list;
2515        list.Add(&named);
2516
2517        FillArray(list, num);
2518
2519        n += list.Write(name, kSingleKey);
2520    }
2521
2522    *fLog << inf << "MStatusDisplay: " << n << " keys written to file as key " << name << "." << endl;
2523
2524    return n;
2525}
2526
2527// --------------------------------------------------------------------------
2528//
2529// Use this to start the synchronous (GUI eventloop driven) tab update.
2530// Can also be used to change the update intervall. If millisec<0
2531// the intervall given in SetUpdateTime is used. If the intervall in
2532// SetUpdateTime is <0 nothing is done. (Call SetUpdateTime(-1) to
2533// disable the automatic update in a MEventloop.
2534//
2535void MStatusDisplay::StartUpdate(Int_t millisec)
2536{
2537    if (fIsLocked>1)
2538        return;
2539
2540    if (fTimer.GetTime()<TTime(0))
2541        return;
2542    fTimer.Start(millisec);
2543}
2544
2545// --------------------------------------------------------------------------
2546//
2547// Stops the automatic GUI update
2548//
2549void MStatusDisplay::StopUpdate()
2550{
2551    if (fIsLocked>1)
2552        return;
2553
2554    fTimer.Stop();
2555}
2556
2557// --------------------------------------------------------------------------
2558//
2559// Set the update interval for the GUI update, see StartUpdate.
2560//
2561void MStatusDisplay::SetUpdateTime(Long_t t)
2562{
2563    fTimer.SetTime(t);
2564}
2565
2566// --------------------------------------------------------------------------
2567//
2568// If the filename name doesn't end with ext, ext is added to the end.
2569// If name.IsNull() "status" is assumed and the a number (>0) is added
2570// as "status-6".
2571// The extension is returned.
2572//
2573const TString &MStatusDisplay::AddExtension(TString &name, const TString &ext, Int_t num) const
2574{
2575    if (name.IsNull())
2576    {
2577        name = gROOT->GetName();
2578        if (num>0)
2579        {
2580            name += "-";
2581            name += num;
2582        }
2583    }
2584
2585    if (name.EndsWith("."+ext))
2586        return ext;
2587
2588    name += ".";
2589    name += ext;
2590
2591    return ext;
2592}
2593
2594Bool_t MStatusDisplay::CheckTabForCanvas(int num) const
2595{
2596    if (gROOT->IsBatch())
2597        return (num>0 && num<=fBatch->GetSize()) || num<0;
2598
2599    if (num>=fTab->GetNumberOfTabs())
2600    {
2601        *fLog << warn << "Tab #" << num << " doesn't exist..." << endl;
2602        return kFALSE;
2603    }
2604    if (num==0)
2605    {
2606        *fLog << warn << "Tab #" << num << " doesn't contain an embedded canvas..." << endl;
2607        return kFALSE;
2608    }
2609    if (fTab->GetNumberOfTabs()<2 || !gPad)
2610    {
2611        *fLog << warn << "Sorry, you must have at least one existing canvas (gPad!=NULL)" << endl;
2612        return kFALSE;
2613    }
2614    return kTRUE;
2615}
2616
2617// --------------------------------------------------------------------------
2618//
2619// Insert the following two lines into the postscript header:
2620//
2621//   %%DocumentPaperSizes: a4
2622//   %%Orientation: Landscape
2623//
2624void MStatusDisplay::UpdatePSHeader(const TString &name) const
2625{
2626    const TString newstr("%%DocumentPaperSizes: a4\n%%Orientation: Landscape\n");
2627
2628    TString tmp(name+"XXXXXX");
2629
2630    // FIXME: Use mkstemp instead
2631    if (!mkstemp(const_cast<char*>(tmp.Data())))
2632    {
2633        *fLog << err << "ERROR - MStatusDisplay::UpdatePSHeader: mktemp failed." << endl;
2634        return;
2635    }
2636
2637    ifstream fin(name);
2638    ofstream fout(tmp);
2639    if (!fout)
2640    {
2641        *fLog << err << "Cannot open file " << name << ": " << strerror(errno) << endl;
2642        return;
2643    }
2644
2645    char c;
2646
2647    TString str;
2648    fin >> str >> c;                // Read "%!PS-Adobe-2.0\n"
2649    fout << str << endl << newstr;
2650
2651    // Doing it in blocks seems not to gain much for small (MB) files
2652    while (fin)
2653    {
2654        fin.read(&c, 1);
2655        fout.write(&c, 1);
2656    }
2657
2658    gSystem->Unlink(name);
2659    gSystem->Rename(tmp, name);
2660}
2661
2662// --------------------------------------------------------------------------
2663//
2664void MStatusDisplay::PSToolsRange(TVirtualPS &vps, Float_t psw, Float_t psh) const
2665{
2666    if (vps.InheritsFrom(TPostScript::Class()))
2667        static_cast<TPostScript&>(vps).Range(psw, psh);
2668    // if (vps.InheritsFrom(TPDF::Class()))
2669    //     static_cast<TPDF&>(vps).Range(psw*0.69, psh*0.69);
2670    // if (vps.InheritsFrom(TSVG::Class()))
2671    //     static_cast<TSVG&>(vps).Range(psw, psh);
2672}
2673
2674// --------------------------------------------------------------------------
2675//
2676void MStatusDisplay::PSToolsTextNDC(TVirtualPS &vps, Double_t u, Double_t v, const char *string) const
2677{
2678    if (vps.InheritsFrom(TPostScript::Class()))
2679        static_cast<TPostScript&>(vps).TextNDC(u, v, string);
2680    if (vps.InheritsFrom(TPDF::Class()))
2681        static_cast<TPDF&>(vps).TextNDC(u, v, string);
2682    // if (vps.InheritsFrom(TSVG::Class()))
2683    //    static_cast<TSVG&>(vps).TextNDC(u, v, string);
2684}
2685
2686// --------------------------------------------------------------------------
2687//
2688Int_t MStatusDisplay::InitWriteDisplay(Int_t num, TString &name, const TString &ext)
2689{
2690    SetStatusLine1(MString::Format("Writing %s file...",ext.Data()));
2691    SetStatusLine2("Please be patient!");
2692
2693    if (!CheckTabForCanvas(num))
2694    {
2695        SetStatusLine2("Failed!");
2696        return 0;
2697    }
2698
2699    AddExtension(name, ext, num);
2700
2701    if (num<0)
2702        *fLog << inf << "Open " << ext << "-File: " << name << endl;
2703
2704    return num;
2705}
2706
2707// --------------------------------------------------------------------------
2708//
2709TCanvas *MStatusDisplay::InitWriteTab(Int_t num, TString &name)
2710{
2711    const Int_t i = TMath::Abs(num);
2712
2713    TCanvas *c = GetCanvas(i);
2714    if (!c)
2715    {
2716        if (num<0)
2717            *fLog << inf << " - ";
2718        *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
2719        return 0;
2720    }
2721
2722    SetStatusLine2(MString::Format("Tab #%d", i));
2723
2724    //
2725    // Paint canvas into root file
2726    //
2727    if (num<0 && !name.IsNull())
2728    {
2729        Bool_t found = kFALSE;
2730        if (name.Index("%%%%name%%%%")>=0)
2731        {
2732            name.ReplaceAll("%%name%%", c->GetName());
2733            found = kTRUE;
2734        }
2735
2736        if (name.Index("%%%%title%%%%")>=0)
2737        {
2738            name.ReplaceAll("%%title%%", c->GetTitle());
2739            found = kTRUE;
2740        }
2741
2742        if (name.Index("%%%%tab%%%%")>=0)
2743        {
2744            name.ReplaceAll("%%tab%%", MString::Format("%d", i));
2745            found = kTRUE;
2746        }
2747
2748        if (!found)
2749            name.Insert(name.Last('.'), MString::Format("-%d", i));
2750    }
2751
2752    if (num<0)
2753        *fLog << inf << " - ";
2754    *fLog << inf << "Writing Tab #" << i;
2755
2756    if (!name.IsNull())
2757        *fLog << " to " << name;
2758
2759    *fLog << ": " << c->GetName() << "... " << flush;
2760
2761    return c;
2762}
2763
2764// This is a stupid workaround to get rid of the damned clipping
2765// of the text. Who the hell needs clipping?
2766class MyCanvas : public TCanvas
2767{
2768public:
2769    void Scale(Double_t val)
2770    {
2771        fAbsXlowNDC = -val;
2772        fAbsYlowNDC = -val;
2773        fAbsWNDC    = 1+2*val;
2774        fAbsHNDC    = 1+2*val;
2775    }
2776};
2777
2778// --------------------------------------------------------------------------
2779//
2780// Write some VGF (vector graphics format). Currently PS, PDF and SVG
2781// is available. Specified by ext.
2782//
2783// In case of num<0 all tabs are written into the VGF file. If num>0
2784// the canvas in the corresponding tab is written to the file.
2785// Name is the name of the file (with or without extension).
2786//
2787// Returns the number of pages written.
2788//
2789// To write all tabs you can also use SaveAsVGF(name, ext)
2790//
2791// If the third argument is given a bottom line is drawn with the text
2792// under it. If no argument is given a bottom line is drawn if
2793// fTitle (SetTitle) is not empty.
2794//
2795Int_t MStatusDisplay::SaveAsVGF(Int_t num, TString name, const TString addon, const TString ext)
2796{
2797    num = InitWriteDisplay(num, name, ext);
2798    if (num==0)
2799        return 0;
2800
2801    TPad       *padsav = (TPad*)gPad;
2802    TVirtualPS *psave  = gVirtualPS;
2803
2804    TDatime d;
2805
2806    Int_t type = -1;
2807
2808    TVirtualPS *ps =0;
2809    if (!ext.CompareTo("ps", TString::kIgnoreCase))
2810    {
2811        gStyle->SetColorModelPS(1);
2812        ps = new TPostScript(name, 112);
2813        type = 1;
2814    }
2815    if (!ext.CompareTo("pdf", TString::kIgnoreCase))
2816    {
2817        ps = new TPDF(name, 112);
2818        type = 2;
2819    }
2820    if (!ext.CompareTo("svg", TString::kIgnoreCase))
2821    {
2822        ps = new TSVG(name, 112);
2823        type = 3;
2824    }
2825
2826    if (!ps)
2827    {
2828        *fLog << err << "Extension " << ext << " unknown..." << endl;
2829        SetStatusLine2("Failed!");
2830        return 0;
2831    }
2832
2833    ps->SetBit(TPad::kPrintingPS);
2834    if (type==1)
2835        ps->PrintFast(13, "/nan {1} def ");
2836
2837    gVirtualPS = ps;
2838
2839    //
2840    // Create some GUI elements for a page legend
2841    //
2842    TLine line;
2843
2844    int page = 1;
2845
2846    //
2847    // Maintain tab numbers
2848    //
2849    Int_t from, to;
2850    GetCanvasRange(from, to, num);
2851
2852    for (int i=from; i<to; i++)
2853    {
2854        TCanvas *c = InitWriteTab(num<0?-i:i);
2855        if (c==0)
2856            continue;
2857
2858        //
2859        // Init page and page size, make sure, that the canvas in the file
2860        // has the same Aspect Ratio than on the screen.
2861        //
2862        if (type==1 || i>from)
2863            ps->NewPage();
2864
2865        //
2866        // 28 is used here to scale the canvas into a height of 28,
2867        // such that the page title can be set above the canvas...
2868        //
2869        Float_t psw = 28.0; // A4 - width  (29.7)
2870        Float_t psh = 21.0; // A4 - height (21.0)
2871
2872        const Float_t cw = c->GetWw();
2873        const Float_t ch = c->GetWh();
2874
2875        if (psw/psh>cw/ch)
2876            psw = cw/ch*psh;
2877        else
2878            psh = ch/cw*psw;
2879
2880        PSToolsRange(*ps, psw, psh);
2881
2882        //
2883        // Clone canvas and change background color and schedule for
2884        // deletion
2885        //
2886
2887        //const Bool_t store = c->IsBatch();
2888        //c->SetBatch(kTRUE);
2889        c->Paint();
2890        //c->SetBatch(store);
2891
2892        //
2893        // Change/fix the canvas coordinate system for the overlaying text.
2894        // This is necessary because root clip everything away which is
2895        // outside a predefined area, which is (0,0)/(1,1)
2896        //
2897        const Double_t height = 0.015;  // Text height
2898        const Double_t off    = 0.005;  // Line offset from text
2899
2900        const Double_t bot = height+off;
2901        const Double_t top = 1-bot;
2902
2903        static_cast<MyCanvas*>(c)->Scale(bot);
2904
2905        // If gPad is not set to c all follwing commands will
2906        // get the wrong numbers for alignment
2907        gPad = c;
2908
2909        // Separator Lines
2910        line.PaintLineNDC(0.01, top, 0.99, top);
2911        line.PaintLineNDC(0.01, bot, 0.99, bot);
2912
2913        //
2914        // Print overlaying text (NDC = %)
2915        //
2916        // align phi col font size (11=left top)
2917        const TString txt(addon.IsNull() ? fTitle : addon);
2918
2919        // Text Attributes
2920        TAttText(11, 0, kBlack, 22, height).Copy(*ps);
2921
2922        // Text on top
2923        ps->SetTextAlign(11); // left bottom
2924        PSToolsTextNDC(*ps, 0.01, top+off, c->GetName());
2925
2926        ps->SetTextAlign(21); // cent bottom
2927        PSToolsTextNDC(*ps, 0.50, top+off, TString("MARS V" MARSVER " - Modular Analysis and Reconstruction Software - ")+d.AsString());
2928
2929        ps->SetTextAlign(31); // right bottom
2930        PSToolsTextNDC(*ps, 0.99, top+off, MString::Format("Page No.%i (%i)", page++, i));
2931
2932        // Text on bottom
2933        ps->SetTextAlign(13); // left top
2934        PSToolsTextNDC(*ps, 0.01, bot-off, c->GetTitle());
2935
2936        ps->SetTextAlign(23); // cent top
2937        PSToolsTextNDC(*ps, 0.50, bot-off, txt);
2938
2939        ps->SetTextAlign(33); // right top
2940        PSToolsTextNDC(*ps, 0.99, bot-off, MString::Format("(c) 2000-%d, Thomas Bretz", TDatime().GetYear()));
2941
2942        static_cast<MyCanvas*>(c)->Scale(0);
2943
2944        //
2945        // Finish drawing page
2946        //
2947        *fLog << "done." << endl;
2948    }
2949
2950    gPad = NULL; // Important!
2951
2952    ps->Close();
2953    delete ps;
2954
2955#if ROOT_VERSION_CODE < ROOT_VERSION(5,12,00)
2956    if (type==1)
2957    {
2958        SetStatusLine2("Updating header of PS file...");
2959
2960        if (num<0)
2961            *fLog << inf3 << " - Updating header of PS file... " << flush;
2962        UpdatePSHeader(name);
2963        if (num<0)
2964            *fLog << inf3 << "done." << endl;
2965    }
2966#endif
2967
2968    gVirtualPS = psave;
2969    if (padsav)
2970        padsav->cd();
2971
2972    if (num<0)
2973        *fLog << inf << "done." << endl;
2974
2975    SetStatusLine2(MString::Format("Done (%dpages)", page-1));
2976
2977    return page-1;
2978}
2979
2980// --------------------------------------------------------------------------
2981//
2982Bool_t MStatusDisplay::SaveAsImage(Int_t num, TString name, TImage::EImageFileTypes type)
2983{
2984#if ROOT_VERSION_CODE < ROOT_VERSION(5,12,00)
2985    if (gROOT->IsBatch())
2986    {
2987        *fLog << warn << "Sorry, writing image-files is not available in batch mode." << endl;
2988        return 0;
2989    }
2990#endif
2991
2992    TString ext;
2993    switch (type)
2994    {
2995    case TImage::kXpm:
2996    case TImage::kZCompressedXpm:  ext = "xpm";     break;
2997    case TImage::kPng:             ext = "png";     break;
2998    case TImage::kJpeg:            ext = "jpg";     break;
2999    case TImage::kGif:             ext = "gif";     break;
3000    case TImage::kTiff:            ext = "tiff";    break;
3001    case TImage::kBmp:             ext = "bmp";     break;
3002    case TImage::kXml:             ext = "xml";     break;
3003    //case TImage::kGZCompressedXpm: ext = "xpm.gz";  break;
3004    //case TImage::kPpm:             ext = "ppm";     break;
3005    //case TImage::kPnm:             ext = "pnm";     break;
3006    //case TImage::kIco:             ext = "ico";     break;
3007    //case TImage::kCur:             ext = "cur";     break;
3008    //case TImage::kXcf:             ext = "xcf";     break;
3009    //case TImage::kXbm:             ext = "xbm";     break;
3010    //case TImage::kFits:            ext = "fits";    break;
3011    //case TImage::kTga:             ext = "tga";     break;
3012    default:
3013        *fLog << warn << "Sorry, unknown or unsupported file type..." << endl;
3014        return 0;
3015    }
3016
3017    num = InitWriteDisplay(num, name, ext);
3018    if (num==0)
3019        return 0;
3020
3021    TPad *padsav = (TPad*)gPad;
3022
3023    Int_t counter = 0;
3024
3025    //
3026    // Maintain tab numbers
3027    //
3028    Int_t from, to;
3029    GetCanvasRange(from, to, num);
3030
3031    for (int i=from; i<to; i++)
3032    {
3033        TString writename(name);
3034
3035        TCanvas *c = InitWriteTab(num<0 ? -i : i, writename);
3036        if (!c)
3037            continue;
3038
3039        //
3040        // Paint canvas into root file
3041        //
3042
3043        // TImage *img = TImage::Create();
3044        // img->FromPad(c);
3045        // img->WriteImage(writename, type);
3046        // delete img;
3047
3048        // FIXME: Not all file types are supported by Print()
3049        c->Print(writename);
3050
3051        if (num<0)
3052            *fLog << "done." << endl;
3053
3054        counter++;
3055    }
3056
3057    if (padsav)
3058        padsav->cd();
3059
3060    *fLog << inf << "done." << endl;
3061
3062    SetStatusLine2("Done.");
3063
3064    return counter>0;
3065}
3066
3067// --------------------------------------------------------------------------
3068//
3069Bool_t MStatusDisplay::SaveAsC(Int_t num, TString name)
3070{
3071    num = InitWriteDisplay(num, name, "C");
3072    if (num==0)
3073        return kFALSE;
3074
3075    TPad *padsav = (TPad*)gPad;
3076
3077    Int_t counter = 0;
3078
3079    //
3080    // Maintain tab numbers
3081    //
3082    Int_t from, to;
3083    GetCanvasRange(from, to, num);
3084
3085    for (int i=from; i<to; i++)
3086    {
3087        TString writename(name);
3088
3089        TCanvas *c = InitWriteTab(num<0 ? -i : i, writename);
3090        if (!c)
3091            continue;
3092
3093        //
3094        // Clone canvas and change background color and schedule for
3095        // deletion
3096        //
3097        c->SaveSource(writename, "");
3098
3099        if (num<0)
3100            *fLog << "done." << endl;
3101
3102        counter++;
3103    }
3104
3105    if (padsav)
3106        padsav->cd();
3107
3108    *fLog << inf << "done." << endl;
3109
3110    SetStatusLine2("Done.");
3111
3112    return counter>0;
3113}
3114
3115// --------------------------------------------------------------------------
3116//
3117// In case of num<0 all tabs are written into a root file. As plain
3118// TCanvas objects if plain==kTRUE otherwise in a MStatusArray. If num>0
3119// the canvas in the corresponding tab is written to the file.
3120// Name is the name of the file (with or without extension).
3121//
3122// Returns the number of keys written.
3123//
3124// To write all tabs you can also use SaveAsRoot(name)
3125//
3126Int_t MStatusDisplay::SaveAsRoot(Int_t num, TString name, Bool_t plain)
3127{
3128    num = InitWriteDisplay(num, name, "root");
3129    if (num==0)
3130        return -1;
3131
3132    TFile *fsave = gFile;
3133    TFile file(name, "RECREATE", GetTitle(), 9);
3134    const Int_t keys = Write(num, "MStatusDisplay", plain ? "plain" : "");
3135    gFile = fsave;
3136
3137    SetStatusLine2("Done.");
3138
3139    return keys;
3140}
3141
3142// --------------------------------------------------------------------------
3143//
3144Bool_t MStatusDisplay::SaveAsCSV(Int_t num, TString name, Char_t delim)
3145{
3146    num = InitWriteDisplay(num, name, "csv");
3147    if (num==0)
3148        return kFALSE;
3149
3150    gSystem->ExpandPathName(name);
3151
3152    ofstream fout(name);
3153    if (!fout)
3154    {
3155        *fLog << err << "Cannot open file " << name << ": " << strerror(errno) << endl;
3156        return kFALSE;
3157    }
3158
3159    fout << 0 << delim << GetName() << delim << GetTitle() << endl;
3160
3161    Int_t from, to;
3162    GetCanvasRange(from, to, num);
3163
3164    for (int i=from; i<to; i++)
3165    {
3166        TCanvas *c;
3167        if (!(c = GetCanvas(i)))
3168        {
3169            if (num<0)
3170                *fLog << inf << " - ";
3171            *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
3172            continue;
3173        }
3174
3175        fout << i << delim << c->GetName() << delim << c->GetTitle() << endl;
3176    }
3177
3178    SetStatusLine2("Done.");
3179
3180    return kTRUE;
3181}
3182
3183/*
3184Bool_t MStatusDisplay::SaveAsCSV(Int_t num, TString name)
3185{
3186    num = InitWriteDisplay(num, name, "csv");
3187    if (num==0)
3188        return kFALSE;
3189
3190    gSystem->ExpandPathName(name);
3191
3192    ofstream fout(name);
3193    if (!fout)
3194    {
3195        *fLog << err << "Cannot open file " << name << ": " << strerror(errno) << endl;
3196        return kFALSE;
3197    }
3198
3199    fout << "<?xml version=\"1.0\"?>" << endl;
3200    fout << "<display name='" << GetName() << "'>" << endl;
3201    fout << "   <file>" << name << "</file>" << endl;
3202    fout << "   <status>" << endl;
3203    fout << "      <name>" << GetName() << "</name>" << endl;
3204    fout << "      <title>" << GetTitle() << "</title>" << endl;
3205    fout << "   </status>" << endl;
3206    fout << "   <tabs>" << endl;
3207
3208    fout << 0 << delim << GetName() << delim << GetTitle() << endl;
3209
3210    Int_t from, to;
3211    GetCanvasRange(from, to, num);
3212
3213    for (int i=from; i<to; i++)
3214    {
3215        TCanvas *c;
3216        if (!(c = GetCanvas(i)))
3217        {
3218            if (num<0)
3219                *fLog << inf << " - ";
3220            *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
3221            continue;
3222        }
3223
3224        fout << "      <tab index='" << i << "'>" << endl;
3225        fout << "         <index>" << i << "</index>" << endl;
3226        fout << "         <name>" << c->GetName()  << "</name>" << endl;
3227        fout << "         <title>" << c->GetName()  << "</title>" << endl;
3228        fout << "      </tab>" << endl;
3229    }
3230
3231    fout << "  </tabs>" << endl;
3232    fout << "</display>" << endl;
3233
3234    SetStatusLine2("Done.");
3235
3236    return kTRUE;
3237}
3238*/
3239
3240// --------------------------------------------------------------------------
3241//
3242void MStatusDisplay::SaveAs(const char *c, const Option_t *o) const
3243{
3244#if ROOT_VERSION_CODE >= ROOT_VERSION(5,18,00)
3245    TGObject::SaveAs(c, o);
3246#endif
3247}
3248
3249// --------------------------------------------------------------------------
3250//
3251// Determin File type to save file as by extension. Allowed extensions are:
3252//   root, ps, pdf, svg, gif, png, jpg, xpm, C
3253//
3254// returns -1 if file type is unknown. Otherwise return value of SaveAs*
3255//
3256Int_t MStatusDisplay::SaveAs(Int_t num, TString name)
3257{
3258    if (name.EndsWith(".root")) return SaveAsRoot(num, name); // kFileSaveAsRoot
3259    if (name.EndsWith(".ps"))   return SaveAsPS(num, name);   // kFileSaveAsPS
3260    if (name.EndsWith(".pdf"))  return SaveAsPDF(num, name);  // kFileSaveAsPDF
3261    if (name.EndsWith(".svg"))  return SaveAsSVG(num, name);  // kFileSaveAsSVG
3262    if (name.EndsWith(".gif"))  return SaveAsGIF(num, name);  // kFileSaveAsGIF
3263    if (name.EndsWith(".png"))  return SaveAsPNG(num, name);  // kFileSaveAsPNG
3264    if (name.EndsWith(".bmp"))  return SaveAsBMP(num, name);  // kFileSaveAsBMP
3265    if (name.EndsWith(".xml"))  return SaveAsXML(num, name);  // kFileSaveAsXML
3266    if (name.EndsWith(".jpg"))  return SaveAsJPG(num, name);  // kFileSaveAsJPG
3267    if (name.EndsWith(".xpm"))  return SaveAsXPM(num, name);  // kFileSaveAsXPM
3268    if (name.EndsWith(".csv"))  return SaveAsCSV(num, name);  // kFileSaveAsCSV
3269    if (name.EndsWith(".tiff")) return SaveAsTIFF(num, name); // kFileSaveAsTIFF
3270    if (name.EndsWith(".C"))    return SaveAsC(num, name);    // kFileSaveAsC
3271    return -1;
3272}
3273
3274// --------------------------------------------------------------------------
3275//
3276//  Opens a save as dialog
3277//
3278Int_t MStatusDisplay::SaveAs(Int_t num)
3279{
3280    static const char *gSaveAsTypes[] =
3281    {
3282        "PostScript",   "*.ps",
3283        "Acrobat pdf",  "*.pdf",
3284        "SVG vector",   "*.svg",
3285        "Gif files",    "*.gif",
3286        "Png files",    "*.png",
3287        "Gif files",    "*.gif",
3288        "Jpeg files",   "*.jpeg",
3289        "Xpm files",    "*.xpm",
3290        "Bmp files",    "*.bmp",
3291        "Xml files",    "*.xml",
3292        "Tiff files",   "*.tiff",
3293        "Csv files",    "*.csv",
3294        "Macro files",  "*.C",
3295        "ROOT files",   "*.root",
3296        "All files",    "*",
3297        NULL,           NULL
3298    };
3299
3300    static TString dir(".");
3301
3302    TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
3303
3304    fi.fFileTypes = (const char**)gSaveAsTypes;
3305    fi.fIniDir    = StrDup(dir);
3306
3307    new TGFileDialog(fClient->GetRoot(), this, kFDSave, &fi);
3308
3309    if (!fi.fFilename)
3310        return 0;
3311
3312    dir = fi.fIniDir;
3313
3314    const Int_t rc = SaveAs(num, fi.fFilename);
3315    if (rc>=0)
3316        return rc;
3317
3318    Warning("MStatusDisplay::SaveAs", "Unknown Extension: %s", fi.fFilename);
3319    return 0;
3320}
3321
3322// --------------------------------------------------------------------------
3323//
3324//  Open contents of a MStatusDisplay with key name from file fname.
3325//
3326Int_t MStatusDisplay::Open(TString fname, const char *name)
3327{
3328    TFile file(fname, "READ");
3329    if (file.IsZombie())
3330    {
3331        gLog << warn << "WARNING - Cannot open file " << fname << endl;
3332        return 0;
3333    }
3334
3335    return Read(name);
3336}
3337
3338// --------------------------------------------------------------------------
3339//
3340//  Opens an open dialog
3341//
3342Int_t MStatusDisplay::Open()
3343{
3344    static const char *gOpenTypes[] =
3345    {
3346        "ROOT files", "*.root",
3347        "All files",  "*",
3348        NULL,           NULL
3349    };
3350
3351    static TString dir(".");
3352
3353    TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
3354
3355    fi.fFileTypes = (const char**)gOpenTypes;
3356    fi.fIniDir    = StrDup(dir);
3357
3358    new TGFileDialog(fClient->GetRoot(), this, kFDOpen, &fi);
3359
3360    if (!fi.fFilename)
3361        return 0;
3362
3363    dir = fi.fIniDir;
3364
3365    return Open(fi.fFilename);
3366}
3367
3368// --------------------------------------------------------------------------
3369//
3370//  Change width of display. The height is calculated accordingly.
3371//
3372void MStatusDisplay::SetDisplayWidth(UInt_t dw)
3373{
3374    if (gROOT->IsBatch())
3375    {
3376        SetCanvasWidth(dw);
3377        return;
3378    }
3379
3380    // 4 == 2*default border with of canvas
3381    dw -= 4;
3382
3383    // Difference between canvas size and display size
3384    const UInt_t cw = GetWidth() -fTab->GetWidth();
3385    const UInt_t ch = GetHeight()-fTab->GetHeight()+fTab->GetTabHeight();
3386
3387    const UInt_t dh = TMath::Nint((dw - cw)/1.5 + ch);
3388
3389    Resize(dw, dh); // Set display size
3390}
3391
3392// --------------------------------------------------------------------------
3393//
3394//  Change height of display. The width is calculated accordingly.
3395//
3396void MStatusDisplay::SetDisplayHeight(UInt_t dh)
3397{
3398    if (gROOT->IsBatch())
3399    {
3400        SetCanvasHeight(dh);
3401        return;
3402    }
3403
3404    // 4 == 2*default border with of canvas
3405    dh -= 4;
3406
3407    // Difference between canvas size and display size
3408    const UInt_t cw = GetWidth() -fTab->GetWidth();
3409    const UInt_t ch = GetHeight()-fTab->GetHeight()+fTab->GetTabHeight();
3410
3411    const UInt_t dw = TMath::Nint((dh - ch)*1.5 + cw);
3412
3413    Resize(dw, dh); // Set display size
3414}
3415
3416// --------------------------------------------------------------------------
3417//
3418//  Change width of canvas. The height is calculated accordingly.
3419//
3420void MStatusDisplay::SetCanvasWidth(UInt_t w)
3421{
3422    // 4 == 2*default border with of canvas
3423    w += 4;
3424
3425    if (gROOT->IsBatch())
3426    {
3427        Resize(w, 3*w/2);
3428        return;
3429    }
3430
3431    // Difference between canvas size and display size
3432    const UInt_t cw = GetWidth() -fTab->GetWidth();
3433    const UInt_t ch = GetHeight()-fTab->GetHeight()+fTab->GetTabHeight();
3434
3435    const UInt_t h  = TMath::Nint(w/1.5 + ch);
3436
3437    Resize(w + cw, h); // Set display size
3438}
3439
3440// --------------------------------------------------------------------------
3441//
3442//  Change height of canvas. The width is calculated accordingly.
3443//
3444void MStatusDisplay::SetCanvasHeight(UInt_t h)
3445{
3446    // 4 == 2*default border with of canvas
3447    h += 4;
3448
3449    if (gROOT->IsBatch())
3450    {
3451        Resize(2*h/3, h);
3452        return;
3453    }
3454
3455    // Difference between canvas size and display size
3456    const UInt_t cw = GetWidth() -fTab->GetWidth();
3457    const UInt_t ch = GetHeight()-fTab->GetHeight()+fTab->GetTabHeight();
3458
3459    // 4 == 2*default border with of canvas
3460    const UInt_t dw  = TMath::Nint((h+4)*1.5 + cw);
3461
3462    Resize(dw, h + ch); // Set display size
3463}
3464
3465// --------------------------------------------------------------------------
3466//
3467// Calculate width and height of the display such that it fits into the
3468// defined box.
3469//
3470void MStatusDisplay::SetDisplaySize(UInt_t w, UInt_t h)
3471{
3472    if (gROOT->IsBatch())
3473        return;
3474
3475    SetDisplayHeight(h);
3476
3477    if (GetWidth()>w)
3478        SetDisplayWidth(w);
3479}
3480
3481// --------------------------------------------------------------------------
3482//
3483//  Calculate an optimum size for the display from the desktop size
3484//
3485void MStatusDisplay::SetOptimumSize()
3486{
3487    if (gROOT->IsBatch())
3488        return;
3489
3490    const UInt_t w = TMath::Nint(0.95*gClient->GetDisplayWidth());
3491    const UInt_t h = TMath::Nint(0.95*gClient->GetDisplayHeight());
3492
3493    SetDisplaySize(w, h);
3494}
3495
3496
3497Bool_t MStatusDisplay::HandleConfigureNotify(Event_t *evt)
3498{
3499    //
3500    // The initialization of the GUI is not yet enough finished...
3501    //
3502    if (!fTab)
3503        return kTRUE;
3504
3505    UInt_t w = evt->fWidth;
3506    UInt_t h = evt->fHeight;
3507
3508    const Bool_t wchanged = w!=GetWidth()-fTab->GetWidth();
3509    const Bool_t hchanged = h!=GetHeight()-fTab->GetHeight();
3510
3511    if (!wchanged && !hchanged)
3512    {
3513        Layout();
3514        // FIXME: Make sure that this doesn't result in endless loops.
3515        return kTRUE;
3516    }
3517
3518    if (GetWidth()==1 && GetHeight()==1)
3519        return kTRUE;
3520
3521    // calculate the constant part of the window
3522    const UInt_t cw = GetWidth() -fTab->GetWidth();
3523    const UInt_t ch = GetHeight()-fTab->GetHeight()+fTab->GetTabHeight();
3524
3525    // calculate new size of frame (canvas @ 2:3)
3526    if (hchanged)
3527        w = TMath::Nint((h-ch)*1.5+cw);
3528    else
3529        h = TMath::Nint((w-cw)/1.5+ch);
3530
3531    // resize frame
3532    Resize(w, h);
3533
3534    return kTRUE;
3535}
3536
3537Bool_t MStatusDisplay::HandleEvent(Event_t *event)
3538{
3539    // Instead  of doing this in CloseWindow (called from HandleEvent)
3540    // we do it here. This makes sure, that handle event doesn't
3541    // execute code after deleting this.
3542    if (event->fType==kDestroyNotify)
3543    {
3544        if (Close())
3545            delete this;
3546//        Close();
3547        return kTRUE;
3548    }
3549
3550    const Bool_t rc = TGMainFrame::HandleEvent(event);
3551
3552    //
3553    // This fixes a bug in older root versions which makes
3554    // TCanvas crash if gPad==NULL. So we make sure, that
3555    // gPad!=NULL -- be carfull, this may have other side
3556    // effects.
3557    //
3558#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
3559    if (!gPad && fTab)
3560        for (int i=0; i<fTab->GetNumberOfTabs(); i++)
3561        {
3562            TCanvas *c = GetCanvas(i);
3563            if (c)
3564            {
3565                c->cd();
3566                gLog << dbg << "MStatusDisplay::HandleEvent - Workaround: gPad=" << gPad << "." << endl;
3567                break;
3568            }
3569        }
3570#endif
3571
3572    return rc;
3573}
Note: See TracBrowser for help on using the repository browser.