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

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