Index: trunk/MagicSoft/Mars/mmain/MProgressBar.cc
===================================================================
--- trunk/MagicSoft/Mars/mmain/MProgressBar.cc	(revision 1957)
+++ trunk/MagicSoft/Mars/mmain/MProgressBar.cc	(revision 1965)
@@ -16,7 +16,7 @@
 !
 !
-!   Author(s): Thomas Bretz  9/2002 <mailto:tbretz@astro-uni-wuerzburg.de>
+!   Author(s): Thomas Bretz, 9/2002 <mailto:tbretz@astro-uni-wuerzburg.de>
 !
-!   Copyright: MAGIC Software Development, 2000-2002
+!   Copyright: MAGIC Software Development, 2000-2003
 !
 !
@@ -25,5 +25,7 @@
 /////////////////////////////////////////////////////////////////////////////
 //
-// MHillasSrc
+// MProgressBar
+//
+// Simple window with progress bar. Can be used in an eventloop.
 //
 /////////////////////////////////////////////////////////////////////////////
Index: trunk/MagicSoft/Mars/mmain/MStatusDisplay.cc
===================================================================
--- trunk/MagicSoft/Mars/mmain/MStatusDisplay.cc	(revision 1957)
+++ trunk/MagicSoft/Mars/mmain/MStatusDisplay.cc	(revision 1965)
@@ -27,5 +27,30 @@
 // MStatusDisplay
 //
-//  upon an idea of Robert Wagner
+// This status display can be used (and is used) to display results in
+// a tabbed window. The window can be written to and read from a root file
+// (see Read and Write) or printed as a postscript file (see SaveAsPS).
+//
+// It has also to half status lines which can be used to display the status
+// or something going on. Together with the status lines it has a progress
+// bar which can display the progress of a job or loop.
+// Access the progress bar by GetProgressBar()
+//
+// To add a new tab and get a pointer to the newly created TCanvas
+// use AddTab.
+//
+// If you have a MStatusDisplay and you are not sure whether it was
+// destroyed by the user meanwhile use:
+//   gROOT->GetListOfSpecials()->FindObject(pointer);
+// Each MStatusDisplay is added to list list by its constructor and
+// removed from the list by the destructor.
+//
+// You can redirect an output to a MLog-logstream by calling SetLogStream().
+// To disable redirction call SetLogStream(NULL)
+//
+// Because updates to the tabs are only done/displayed if a tab is active
+// using the gui doesn't make things slower (<1%) if the first (legend
+// tab) is displayed. This gives you the possibility to look into
+// the current progress of a loop without loosing more time than the
+// single update of the tab.
 //
 /////////////////////////////////////////////////////////////////////////////
@@ -34,21 +59,243 @@
 #include <iostream.h>
 
-#include <TCanvas.h>        // TCanvas
-#include <TSystem.h>        // gSystem
-
-#include <TGTab.h>          // TGTab
-#include <TGLabel.h>        // TGLabel
-#include <TGButton.h>       // TGPictureButton
-#include <TGProgressBar.h>  // TGHProgressBar
+#include <TLine.h>                // TLine
+#include <TText.h>                // TText
+#include <TFile.h>                // gFile
+#include <TFrame.h>               // TFrame
+#include <TStyle.h>               // gStyle
+#include <TCanvas.h>              // TCanvas
+#include <TSystem.h>              // gSystem
+#include <TDatime.h>              // TDatime
+#include <TRandom.h>              // TRandom
+#include <TObjArray.h>            // TObjArray
+#include <TPostScript.h>          // TPostScript
+
+#include <TGTab.h>                // TGTab
+#include <TGLabel.h>              // TGLabel
+#include <TG3DLine.h>             // TGHorizontal3DLine
+#include <TGButton.h>             // TGPictureButton
+#include <TGListBox.h>            // TGListBox
+#include <TGProgressBar.h>        // TGHProgressBar
 
 #include <TRootEmbeddedCanvas.h>  // TRootEmbeddedCanvas
 
-#include "MGList.h"
+#include "MLog.h"                 // MLog
+#include "MLogManip.h"            // inf, warn, err
+
+#include "MGList.h"               // MGList
+#include "MGMenu.h"               // MGMenu, TGMenu
+#include "MParContainer.h"        // MParContainer::GetDescriptor
 
 ClassImp(MStatusDisplay);
 
+// --------------------------------------------------------------------------
+//
+// Add menu bar to the GUI
+//
+void MStatusDisplay::AddMenuBar()
+{
+    //
+    // File Menu
+    //
+    MGPopupMenu *filemenu = new MGPopupMenu(gClient->GetRoot());
+    // filemenu->AddEntry("S&ave [F2]", kFileSave);
+    // filemenu->AddEntry("Save &As... [Shift-F2]", kFileSaveAs);
+    filemenu->AddEntry("Save As status.&ps", kFileSaveAsPS);
+    // filemenu->AddEntry("Save As status.&gif", kFileSaveAsGIF);
+    // filemenu->AddEntry("Save As status.&C", kFileSaveAsC);
+    filemenu->AddEntry("Save As status.&root", kFileSaveAsRoot);
+    filemenu->AddSeparator();
+    filemenu->AddEntry("Print with &lpr", kFilePrint);
+    filemenu->AddEntry("Set printer &name", kFilePrinterName);
+    filemenu->AddSeparator();
+    filemenu->AddEntry("E&xit", kFileExit);
+    filemenu->Associate(this);
+
+    //
+    // Tab Menu
+    //
+    MGPopupMenu *tabmenu = new MGPopupMenu(gClient->GetRoot());
+    // tabmenu->AddEntry("S&ave [F2]", kFileSave);
+    // tabmenu->AddEntry("Save &As... [Shift-F2]", kFileSaveAs);
+    tabmenu->AddEntry("Save As tab-i.&ps", kTabSaveAsPS);
+    // tabmenu->AddEntry("Save As tab-i.&gif", kTabSaveAsGIF);
+    // tabmenu->AddEntry("Save As tab-i.&C", kTabSaveAsC);
+    tabmenu->AddEntry("Save As tab-i.&root", kTabSaveAsRoot);
+    tabmenu->AddSeparator();
+    tabmenu->AddEntry("Print with &lpr", kFilePrint);
+    tabmenu->AddSeparator();
+    tabmenu->AddEntry("Next [&+]",     kTabNext);
+    tabmenu->AddEntry("Previous [&-]", kTabPrevious);
+    tabmenu->Associate(this);
+
+    //
+    // Loop Menu
+    //
+    MGPopupMenu *loopmenu = new MGPopupMenu(gClient->GetRoot());
+    loopmenu->AddEntry("&Stop", kLoopStop);
+    loopmenu->Associate(this);
+
+    //
+    // Menu Bar
+    //
+    MGMenuBar *menubar = new MGMenuBar(this, 1, 1, kHorizontalFrame);
+    menubar->AddPopup("&File", filemenu, NULL);
+    menubar->AddPopup("&Tab",  tabmenu,  NULL);
+    menubar->AddPopup("&Loop", loopmenu, NULL);
+    menubar->BindKeys(this);
+    AddFrame(menubar);
+
+    //
+    // Line below menu bar
+    //
+    TGLayoutHints *laylinesep  = new TGLayoutHints(kLHintsTop|kLHintsExpandX);
+    fList->Add(laylinesep);
+
+    TGHorizontal3DLine *linesep = new TGHorizontal3DLine(this);
+    AddFrame(linesep, laylinesep);
+
+    //
+    // Add everything to autodel list
+    //
+    fList->Add(filemenu);
+    fList->Add(loopmenu);
+    fList->Add(menubar);
+    fList->Add(tabmenu);
+    fList->Add(linesep);
+}
+
+// --------------------------------------------------------------------------
+//
+// Add the title tab
+//
+void MStatusDisplay::AddMarsTab()
+{
+    // Create Tab1
+    TGCompositeFrame *f = fTab->AddTab("-=MARS=-");
+
+    // Add MARS version
+    TString txt = "Official Release: V";
+    TGLabel *l = new TGLabel(f, txt+MARSVER);
+    fList->Add(l);
+
+    TGLayoutHints *layb = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 10, 10);
+    fList->Add(layb);
+    f->AddFrame(l, layb);
+
+    // Add root version
+    txt = "Using ROOT v";
+    l = new TGLabel(f, txt+ROOTVER);
+    fList->Add(l);
+
+    TGLayoutHints *lay = new TGLayoutHints(kLHintsCenterX|kLHintsTop);
+    fList->Add(lay);
+    f->AddFrame(l, lay);
+
+    // Add Mars logo picture
+    const TGPicture *pic2 = fList->GetPicture("marslogo.xpm");
+    if (pic2)
+    {
+        TGPictureButton *mars  = new TGPictureButton(f, pic2, kPicMars);
+        fList->Add(mars);
+        mars->Associate(this);
+
+        TGLayoutHints *lay2 = new TGLayoutHints(kLHintsCenterX|kLHintsCenterY, 10, 10, 10, 10);
+        fList->Add(lay2);
+        f->AddFrame(mars, lay2);
+    }
+
+    // Add date and time
+    TDatime d;
+    l = new TGLabel(f, d.AsString());
+    fList->Add(l);
+    f->AddFrame(l, lay);
+
+    // Add copyright notice
+    l = new TGLabel(f, "(c) MAGIC Software Development, 2000-2003");
+    fList->Add(l);
+    f->AddFrame(l, layb);
+}
+
+// --------------------------------------------------------------------------
+//
+// Adds the logbook tab to the GUI if it was not added previously.
+//
+// The logbook is updated four times a second only if the tab is visible.
+//
+// You can redirect an output to a MLog-logstream by calling SetLogStream().
+// To disable redirction call SetLogStream(NULL)
+//
+void MStatusDisplay::SetLogStream(MLog *log)
+{
+    if (log && fLogBox==NULL)
+    {
+        fLogIdx = fTab->GetNumberOfTabs();
+
+        // Create Tab1
+        TGCompositeFrame *f = fTab->AddTab("-Logbook-");
+
+        // Create TGListBox for logging contents
+        fLogBox = new TGListBox(f, 1, 1);
+        fLogBox->ChangeBackground(TGFrame::GetBlackPixel());
+
+        // Add List box to the tab
+        TGLayoutHints *lay = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY);//, 5, 6, 5);
+        f->AddFrame(fLogBox, lay);
+
+        // layout and map tab
+        Layout();
+        MapSubwindows();
+
+        // make it visible
+        gClient->ProcessEventsFor(fTab);
+    }
+
+    if (log)
+    {
+        fLog = log;
+
+        log->SetOutputGui(fLogBox, kTRUE);
+        log->DisableOutputDevice(MLog::eStdout);
+        log->EnableOutputDevice(MLog::eGui);
+
+        fLogTimer.Start();
+    }
+    else
+    {
+        fLogTimer.Stop();
+
+        fLog->DisableOutputDevice(MLog::eGui);
+        fLog->EnableOutputDevice(MLog::eStdout);
+        fLog->SetOutputGui(NULL);
+
+        fLog = &gLog;
+    }
+}
+
+// --------------------------------------------------------------------------
+//
+// Add the Tabs and the predifined Tabs to the GUI
+//
+void MStatusDisplay::AddTabs()
+{
+    fTab = new TGTab(this, 300, 300);
+
+    AddMarsTab();
+
+    // Add fTab to Frame
+    TGLayoutHints *laytabs = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 5, 6, 5);
+    AddFrame(fTab, laytabs);
+
+    fList->Add(fTab);
+    fList->Add(laytabs);
+}
+
+// --------------------------------------------------------------------------
+//
+// Add the progress bar to the GUI
+//
 void MStatusDisplay::AddProgressBar()
 {
-    TGLayoutHints *laybar=new TGLayoutHints(kLHintsExpandX, 10,10,10,10);
+    TGLayoutHints *laybar=new TGLayoutHints(kLHintsExpandX, 5, 6, 5, 5);
     fList->Add(laybar);
 
@@ -59,97 +306,73 @@
 }
 
-enum {
-    kPicMagic,
-    kPicMars
-};
-
-void MStatusDisplay::AddTabs()
-{
-    fTab = new TGTab(this, 300, 300);
-
-    //
-    // Create Tab1
-    //
-    TGCompositeFrame *f = fTab->AddTab("-=MARS=-");
-
-    /*
-    TGHorizontalFrame *hf = new TGHorizontalFrame(f, 1, 1);
-
-    TGLayoutHints *lay = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 10., 10., 10., 10.);
-    fList->Add(lay);
-    f->AddFrame(hf, lay);
-
-    const TGPicture *pic1 = fList->GetPicture("magiclogo.xpm");
-    if (pic1)
-    {
-        TGPictureButton *magic = new TGPictureButton(hf, pic1, kPicMagic);
-        fList->Add(magic);
-        magic->Associate(this);
-
-        TGLayoutHints *lay1 = new TGLayoutHints(kLHintsLeft|kLHintsTop,  10., 10., 20., 10.);
-        fList->Add(lay1);
-        hf->AddFrame(magic, lay1);
-    }
-    */
-    const TGPicture *pic2 = fList->GetPicture("marslogo.xpm");
-    if (pic2)
-    {
-        TGPictureButton *mars  = new TGPictureButton(f, pic2, kPicMars);
-        fList->Add(mars);
-        mars->Associate(this);
-
-        TGLayoutHints *lay2 = new TGLayoutHints(kLHintsCenterX|kLHintsCenterY, 10., 10., 10., 10.);
-        fList->Add(lay2);
-        f->AddFrame(mars, lay2);
-    }
-
-    //
-    // Crete second gui elemet for tab1 (TGVertical Frame)
-    //
-    TGLayoutHints *laytabs = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 10, 10, 10, 10);
-    AddFrame(fTab, laytabs);
-
-    fList->Add(fTab);
-    fList->Add(laytabs);
-}
-
-void MStatusDisplay::AddStatusLine1()
-{
-    TGCompositeFrame *f = new TGCompositeFrame(this, 1, 1, kSunkenFrame);
+
+// --------------------------------------------------------------------------
+//
+// Adds the status lines to the GUI
+//
+void MStatusDisplay::AddStatusLines()
+{
+    TGHorizontalFrame *hf = new TGHorizontalFrame(this, 1, 1);
+
+    TGCompositeFrame *f = new TGCompositeFrame(hf, 1, 1, kSunkenFrame);
 
     fLine1 = new TGLabel(f, "");
 
-    TGLayoutHints *lay = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 5, 5, 2, 2);
+    TGLayoutHints *lay = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 0, 5);
     f->AddFrame(fLine1, lay);
-    AddFrame(f, lay);
+    hf->AddFrame(f, lay);
 
     fList->Add(f);
     fList->Add(fLine1);
     fList->Add(lay);
-}
-
-void MStatusDisplay::AddStatusLine2()
-{
-    TGCompositeFrame *f = new TGCompositeFrame(this, 1, 1, kSunkenFrame);
+
+    f = new TGCompositeFrame(hf, 1, 1, kSunkenFrame);
 
     fLine2 = new TGLabel(f, "");
-
-    TGLayoutHints *lay = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 5, 5, 2, 2);
     f->AddFrame(fLine2, lay);
-    AddFrame(f, lay);
-
+    hf->AddFrame(f, lay);
+
+    TGLayoutHints *layf = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 5, 0, 0, 3);
+    AddFrame(hf, layf);
+
+    fList->Add(layf);
     fList->Add(f);
     fList->Add(fLine2);
-    fList->Add(lay);
-}
-
+    fList->Add(hf);
+}
+
+// --------------------------------------------------------------------------
+//
+// Change the text in the status line 1
+//
 void MStatusDisplay::SetStatusLine1(const char *txt)
 {
     fLine1->SetText(txt);
-}
-
+    gClient->ProcessEventsFor(fLine1);
+}
+
+// --------------------------------------------------------------------------
+//
+// Change the text in the status line 2
+//
 void MStatusDisplay::SetStatusLine2(const char *txt)
 {
     fLine2->SetText(txt);
+    gClient->ProcessEventsFor(fLine2);
+}
+
+// --------------------------------------------------------------------------
+//
+// Display information about the name of a container
+//
+void MStatusDisplay::SetStatusLine2(const MParContainer &cont)
+{
+    TString txt = cont.GetDescriptor();
+    txt += ": ";
+    txt += cont.GetTitle();
+
+    cout << txt << endl;
+
+    SetStatusLine2(txt);
 }
 
@@ -164,23 +387,42 @@
 //   always by deleting the corresponding object.
 //
-MStatusDisplay::MStatusDisplay() : TGTransientFrame(gClient->GetRoot(), gClient->GetRoot(), 1, 1)
-{
+// Update time default: 10s
+//
+MStatusDisplay::MStatusDisplay(Long_t t)
+: TGMainFrame(gClient->GetRoot(), 1, 1), fTimer(this, t, kTRUE), fLog(&gLog), fLogIdx(-1), fLogTimer(this, 250, kTRUE), fLogBox(NULL)
+{
+    gROOT->GetListOfSpecials()->Add(this);
+
+    //
+    // Create a list handling GUI widgets
+    //
     fList = new MGList;
     fList->SetOwner();
 
-    SetWMSizeHints(640, 480, 1280, 1024, 10, 10); // set the smallest and biggest size of the Main frame
+    //
+    // set the smallest and biggest size of the Main frame
+    // and move it to its appearance position
+    SetWMSizeHints(640, 548, 1280, 1024, 10, 10);
     Move(rand()%100+50, rand()%100+50);
 
-    fLayCanvas = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY, 3, 3, 3, 3);
+    //
+    // Create the layout hint for the root embedded canavses
+    //
+    fLayCanvas = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY);
     fList->Add(fLayCanvas);
 
+    //
+    // Add Widgets (from top to bottom)
+    //
+    AddMenuBar();
     AddTabs();
     AddProgressBar();
-    AddStatusLine1();
-    AddStatusLine2();
-
+    AddStatusLines();
+
+    //
+    // Now do an automatic layout of the widgets and display the window
+    //
+    Layout();
     MapSubwindows();
-
-    Layout();
 
     SetWindowName("Status Display");
@@ -188,4 +430,7 @@
 
     MapWindow();
+
+    //lient->ProcessEventsFor(this);
+    gSystem->ProcessEvents();
 }
 
@@ -198,7 +443,15 @@
 {
     delete fList;
+
+    gROOT->GetListOfSpecials()->Remove(this);
 } 
 
-TCanvas *MStatusDisplay::GetCanvas(TGCompositeFrame *cf)
+// --------------------------------------------------------------------------
+//
+// Takes a TGCompositeFrame as argument. Searches for the first
+// TRootEmbeddedCanvas which is contained by it and returns a pointer
+// to the corresponding TCanvas. If it isn't found NULL is returned.
+//
+TCanvas *MStatusDisplay::GetCanvas(TGCompositeFrame *cf) const
 {
     TIter Next(cf->GetList());
@@ -212,9 +465,13 @@
 }
 
-TCanvas *MStatusDisplay::GetCanvas(int i)
+// --------------------------------------------------------------------------
+//
+// Returns GetCanvas of the i-th Tab.
+//
+TCanvas *MStatusDisplay::GetCanvas(int i) const
 {
     if (i<0 || i>=fTab->GetNumberOfTabs())
     {
-        cout << "MStatusDisplay::GetCanvas: Out of range." << endl;
+        *fLog << warn << "MStatusDisplay::GetCanvas: Out of range." << endl;
         return NULL;
     }
@@ -223,5 +480,11 @@
 }
 
-TCanvas *MStatusDisplay::GetCanvas(const TString &name)
+// --------------------------------------------------------------------------
+//
+// Searches for a TRootEmbeddedCanvas in the TGCompositeFramme of the
+// Tab with the name 'name'. Returns the corresponding TCanvas or
+// NULL if something isn't found.
+//
+TCanvas *MStatusDisplay::GetCanvas(const TString &name) const
 {
     TGFrameElement *f;
@@ -249,30 +512,250 @@
 }
 
+// --------------------------------------------------------------------------
+//
+// Calls TCanvas::cd(), for the canvas returned by GetCanvas.
+//
+Bool_t MStatusDisplay::CdCanvas(const TString &name)
+{
+    TCanvas *c = GetCanvas(name);
+    if (!c)
+        return kFALSE;
+
+    c->cd();
+    return kTRUE;
+}
+
+// --------------------------------------------------------------------------
+//
+// Adds a new tab with the name 'name'. Adds a TRootEmbeddedCanvas to the
+// tab and returns a reference to the corresponding TCanvas.
+//
 TCanvas &MStatusDisplay::AddTab(const char *name)
 {
+    // Add new tab
     TGCompositeFrame *f = fTab->AddTab(name);
 
-    TRootEmbeddedCanvas *ec = new TRootEmbeddedCanvas(name, f, 100, 100, 0);
+    // create root embedded canvas and add it to the tab
+    TRootEmbeddedCanvas *ec = new TRootEmbeddedCanvas(name, f, f->GetWidth(), f->GetHeight(), 0);
     f->AddFrame(ec, fLayCanvas);
     fList->Add(ec);
 
+    // set background and border mode of the canvas
     TCanvas &c = *ec->GetCanvas();
 
-    c.SetFillColor(/*165*/17);
+    c.SetFillColor(16/*165*//*17*//*203*/);
     c.SetBorderMode(0);
 
+    // If kNoContaxtMenu set set kNoCOntextMenu of the canvas
+    if (TestBit(kNoContextMenu))
+        c.SetBit(kNoContextMenu);
+
+    // layout and map new tab
+    Layout();
     MapSubwindows();
-    Layout();
-    // MapWindow();
-
-    cout << "Adding Tab '" << name << "' (TCanvas=" << &c << ")" <<  ec << endl;
-
+
+    // display new tab in the main frame
+    gClient->ProcessEventsFor(fTab);
+
+    *fLog << inf << "Adding Tab '" << name << "' (" << f->GetWidth() << "x";
+    *fLog << f->GetHeight() << ", TCanvas=" << &c << ")" << endl;
+
+    // return pointer to new canvas
     return c;
 }
 
+// --------------------------------------------------------------------------
+//
+// Update a canvas in a tab, takes the corresponding TGCompositeFrame
+// as an argument
+//
+void MStatusDisplay::UpdateTab(TGCompositeFrame *f)
+{
+    if (!f)
+        return;
+
+    TCanvas *c=GetCanvas(f);
+    if (!c)
+        return;
+
+    c->Modified();
+    c->Update();
+    c->Paint();
+}
+
+// --------------------------------------------------------------------------
+//
+// Saves the given canvas (pad) or all pads (num<0) as a temporary
+// postscript file and prints it using 'lpr'. If a printer name is set
+// via SetPrinter 'lpr -Pname' is used.
+//
+Int_t MStatusDisplay::PrintToLpr(Int_t num) const
+{
+    TString name = "mars";
+
+    for (int i=0; i<6; i++)
+        name += (char)(gRandom->Uniform(25)+65);
+
+    name += ".ps";
+
+    const Int_t pages = SaveAsPS(num, name);
+    if (!pages)
+    {
+        *fLog << warn << "MStatusDisplay::PrintToLpr: Sorry, couldn't save file as temporary postscript!" << endl;
+        return 0;
+    }
+
+    TString cmd="lpr ";
+    if (!fPrinter.IsNull())
+    {
+        cmd += "-P";
+        cmd += fPrinter;
+        cmd += " ";
+    }
+    cmd += name;
+
+    gSystem->Exec(cmd);
+    gSystem->Unlink(name);
+
+    return pages;
+}
+
+// --------------------------------------------------------------------------
+//
+// Process the kC_COMMAND, kCM_MENU  messages
+//
+Bool_t MStatusDisplay::ProcessMessageCommandMenu(Long_t id)
+{
+    //cout << "Menu #" << id << endl;
+    switch (id)
+    {
+    case kLoopStop:
+    case kFileExit:
+        if (id==kFileExit && !TestBit(kIsLocked))
+            delete this;
+        fStatus = (Status_t)id;
+        return kTRUE;
+/*
+    case kFileSave:
+        cout << "Save..." << endl;
+        return kTRUE;
+
+    case kFileSaveAs:
+        cout << "SaveAs..." << endl;
+        return kTRUE;
+*/
+    case kFileSaveAsPS:
+        //cout << "FileSaveAsPS..." << endl;
+        SaveAsPS();
+        return kTRUE;
+/*
+    case kFileSaveAsGIF:
+        cout << "FileSaveAsGIF..." << endl;
+        SaveAsGIF();
+        return kTRUE;
+
+    case kFileSaveAsC:
+        cout << "FileSaveAsC..." << endl;
+        SaveAsC();
+        return kTRUE;
+*/
+    case kFileSaveAsRoot:
+        SaveAsRoot();
+        return kTRUE;
+
+    case kFilePrint:
+        PrintToLpr();
+        return kTRUE;
+
+    case kTabSaveAsPS:
+        SaveAsPS(fTab->GetCurrent());
+        return kTRUE;
+/*
+    case kTabSaveAsGIF:
+        cout << "TabSaveAsGIF... " << fTab->GetCurrent() <<  endl;
+        SaveAsGIF(fTab->GetCurrent());
+        return kTRUE;
+
+    case kTabSaveAsC:
+        cout << "TabSaveAsC... " << fTab->GetCurrent() <<  endl;
+        SaveAsC(fTab->GetCurrent());
+        return kTRUE;
+*/
+    case kTabSaveAsRoot:
+        SaveAsRoot(fTab->GetCurrent());
+        return kTRUE;
+
+    case kTabPrint:
+        PrintToLpr(fTab->GetCurrent());
+        return kTRUE;
+
+    case kTabNext:
+        fTab->SetTab(fTab->GetCurrent()+1);
+        return kTRUE;
+
+    case kTabPrevious:
+        fTab->SetTab(fTab->GetCurrent()-1);
+        return kTRUE;
+    }
+    return kTRUE;
+
+    cout << "Command-Menu: Id=" << id << endl;
+}
+
+// --------------------------------------------------------------------------
+//
+// Process the kC_COMMAND messages
+//
+Bool_t MStatusDisplay::ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2)
+{
+    switch (submsg)
+    {
+    case kCM_MENU:
+        return ProcessMessageCommandMenu(mp1);
+
+    case kCM_MENUSELECT:
+        cout << "Menuselect #" << mp1 << endl;
+        return kTRUE;
+
+    case kCM_TAB:
+        for (int i=1; i<fTab->GetNumberOfTabs(); i++)
+            fTab->GetTabContainer(i)->UnmapWindow();
+        UpdateTab(fTab->GetTabContainer(mp1));
+        fTab->GetTabContainer(mp1)->MapWindow();
+        /*
+        if (mp1>0)
+            fMenu->AddPopup("&CaOs", fCaOs, NULL);
+        else
+            fMenu->RemovePopup("CaOs");
+        fMenu->Resize(fMenu->GetDefaultSize());
+        MapSubwindows();
+        MapWindow();
+        */
+        return kTRUE;
+
+    case kCM_BUTTON:
+        if (mp1==kPicMars)
+            return kTRUE;
+        return kTRUE;
+    }
+
+    cout << "Command: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
+    return kTRUE;
+}
+
+// --------------------------------------------------------------------------
+//
+// Process the messages from the GUI
+//
 Bool_t MStatusDisplay::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2)
 {
-    cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg) << " Mp1=";
-    cout << mp1 << " Mp2=" << mp2 << endl;
+    switch (GET_MSG(msg))
+    {
+    case kC_COMMAND:
+        return ProcessMessageCommand(GET_SUBMSG(msg), mp1, mp2);
+    }
+
+    cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
+    cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
 
     return kTRUE;
@@ -292,2 +775,458 @@
 }
 
+// --------------------------------------------------------------------------
+//
+// Calls SetBit(kNoContextMenu) for all TCanvas objects found in the
+// Tabs.
+//
+void MStatusDisplay::SetNoContextMenu(Bool_t flag=kTRUE)
+{
+    flag ? SetBit(kNoContextMenu) : ResetBit(kNoContextMenu);
+    for (int i=1; i<fTab->GetNumberOfTabs(); i++)
+    {
+        TCanvas *c = GetCanvas(i);
+        if (c)
+            flag ? c->SetBit(kNoContextMenu) : c->ResetBit(kNoContextMenu);
+    }
+}
+
+// --------------------------------------------------------------------------
+//
+// Updates the canvas (if existing) in the currenly displayed Tab.
+// The update intervall is controlled by StartUpdate and StopUpdate
+//
+Bool_t MStatusDisplay::HandleTimer(TTimer *timer)
+{
+    const Int_t c = fTab->GetCurrent();
+
+    // Skip Legend Tab
+    if (c==0)
+        return kTRUE;
+
+    if (timer==&fTimer)
+    {
+        TGCompositeFrame *f=fTab->GetCurrentContainer();
+        if (f!=fLogBox)
+            return kTRUE;
+
+        UpdateTab(f);
+        return kTRUE;
+    }
+    if (timer==&fLogTimer && c==fLogIdx)
+    {
+        fLog->UpdateGui();
+
+        if (!fLogBox->TestBit(kHasChanged))
+            return kTRUE;
+
+        fLogBox->MapSubwindows();
+        fLogBox->Layout();
+        fLogBox->ResetBit(kHasChanged);
+        return kTRUE;
+    }
+
+    return kTRUE;
+}
+
+// --------------------------------------------------------------------------
+//
+// Draws a clone of a canvas into a new canvas. Taken from TCanvas.
+//
+void MStatusDisplay::DrawClonePad(TCanvas &newc, const TCanvas &oldc) const
+{
+    //copy pad attributes
+    newc.Range(oldc.GetX1(),oldc.GetY1(),oldc.GetX2(),oldc.GetY2());
+    newc.SetTickx(oldc.GetTickx());
+    newc.SetTicky(oldc.GetTicky());
+    newc.SetGridx(oldc.GetGridx());
+    newc.SetGridy(oldc.GetGridy());
+    newc.SetLogx(oldc.GetLogx());
+    newc.SetLogy(oldc.GetLogy());
+    newc.SetLogz(oldc.GetLogz());
+    newc.SetBorderSize(oldc.GetBorderSize());
+    newc.SetBorderMode(oldc.GetBorderMode());
+    ((TAttLine&)oldc).Copy((TAttLine&)newc);
+    ((TAttFill&)oldc).Copy((TAttFill&)newc);
+    ((TAttPad&)oldc).Copy((TAttPad&)newc);
+
+    //copy primitives
+    TObject *obj;
+    TIter next(oldc.GetListOfPrimitives());
+    while ((obj=next())) {
+        gROOT->SetSelectedPad(&newc);
+        newc.GetListOfPrimitives()->Add(obj->Clone(),obj->GetDrawOption());
+    }
+    newc.Modified();
+    newc.Update();
+}
+
+// --------------------------------------------------------------------------
+//
+// Reads the contents of a saved MStatusDisplay from a file.
+//
+Int_t MStatusDisplay::Read(const char *name)
+{
+    if (!gFile)
+    {
+        *fLog << warn << "MStatusDisplay::Read: No file found. Please create a TFile first." << endl;
+        return 0;
+    }
+
+    if (!gFile->IsOpen())
+    {
+        *fLog << warn << "MStatusDisplay::Read: File not open. Please open the TFile first." << endl;
+        return 0;
+    }
+
+    TObjArray list;
+
+    const Int_t n = list.Read(name);
+    if (n==0)
+    {
+        *fLog << warn << "MStatusDisplay::Read: No objects read." << endl;
+        return 0;
+    }
+
+    TIter Next(&list);
+    TCanvas *c;
+    while ((c=(TCanvas*)Next()))
+        DrawClonePad(AddTab(c->GetName()), *c);
+
+    *fLog << inf << "MStatusDisplay: Key " << name << " with " << n << " keys read from file." << endl;
+
+    return n;
+}
+
+// --------------------------------------------------------------------------
+//
+// Writes the contents of a MStatusDisplay to a file.
+//
+Int_t MStatusDisplay::Write(Int_t num, const char *name, Int_t option, Int_t bufsize)
+{
+    if (!gFile)
+    {
+        *fLog << warn << "MStatusDisplay::Write: No file found. Please create a TFile first." << endl;
+        return 0;
+    }
+
+    if (!gFile->IsOpen())
+    {
+        *fLog << warn << "MStatusDisplay::Write: File not open. Please open the TFile first." << endl;
+        return 0;
+    }
+
+    if (!gFile->IsWritable())
+    {
+        *fLog << warn << "MStatusDisplay::Write: File not writable." << endl;
+        return 0;
+    }
+
+    if (num==0)
+    {
+        *fLog << warn << "MStatusDisplay::Write: Tab doesn't contain an embedded Canvas... skipped." << endl;
+        return 0;
+    }
+
+    if (num>=fTab->GetNumberOfTabs())
+    {
+        *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
+        return 0;
+    }
+
+    TObjArray list;
+
+    const Int_t from = num<0 ? 1 : num;
+    const Int_t to   = num<0 ? fTab->GetNumberOfTabs() : num+1;
+
+    TCanvas *c;
+    for (int i=from; i<to; i++)
+        if ((c = GetCanvas(i)))
+            list.Add(c);
+
+    const Int_t n = list.Write(name, kSingleKey);
+
+    *fLog << inf << "MStatusDisplay: " << n << " keys written to file as key " << name << "." << endl;
+
+    return n;
+}
+
+// --------------------------------------------------------------------------
+//
+// Use this to start the synchronous (GUI eventloop driven) tab update.
+// Can also be used to change the update intervall. If millisec<0
+// the intervall given in SetUpdateTime is used. If the intervall in
+// SetUpdateTime is <0 nothing is done. (Call SetUpdateTime(-1) to
+// disable the automatic update in a MEventloop.
+//
+void MStatusDisplay::StartUpdate(Int_t millisec=-1)
+{
+    if (fTimer.GetTime()<TTime(0))
+        return;
+    fTimer.Start(millisec);
+}
+
+// --------------------------------------------------------------------------
+//
+// Stops the automatic GUI update
+//
+void MStatusDisplay::StopUpdate()
+{
+    fTimer.Stop();
+}
+
+// --------------------------------------------------------------------------
+//
+// Set the update interval for the GUI update, see StartUpdate.
+//
+void MStatusDisplay::SetUpdateTime(Long_t t)
+{
+    fTimer.SetTime(t);
+}
+
+// --------------------------------------------------------------------------
+//
+// Set the background color in a canvas
+//
+void MStatusDisplay::CanvasSetFillColor(TPad &p, Int_t col) const
+{
+    TObject *obj;
+
+    TIter Next(p.GetListOfPrimitives());
+    while ((obj=Next()))
+    {
+        if (obj->InheritsFrom(TPad::Class()))
+            CanvasSetFillColor(*(TPad*)obj, col);
+        if (obj->InheritsFrom(TFrame::Class()))
+            ((TFrame*)obj)->SetFillColor(col);
+    }
+
+    p.SetFillColor(col);
+}
+
+void MStatusDisplay::AddExtension(TString &name, const TString &ext, Int_t num) const
+{
+    if (name.IsNull())
+    {
+        name = "status";
+        if (num>0)
+        {
+            name += "-";
+            name += num;
+        }
+    }
+
+    if (name.EndsWith("."+ext))
+        return;
+
+    name += ".";
+    name += ext;
+}
+
+// --------------------------------------------------------------------------
+//
+// In case of num<0 all tabs are written into the PS file. If num>0
+// the canvas in the corresponding tab is written to the file.
+// Name is the name of the file (with or without extension).
+//
+// Returns the number of pages written.
+//
+// To write all tabs you can also use SaveAsPS(name)
+//
+Int_t MStatusDisplay::SaveAsPS(Int_t num, TString name) const
+{
+    if (num>=fTab->GetNumberOfTabs())
+    {
+        *fLog << warn << "Tab #" << num << " doesn't exist..." << endl;
+        return 0;
+    }
+    if (num==0)
+    {
+        *fLog << warn << "Tab #" << num << " doesn't contain an embedded canvas..." << endl;
+        return 0;
+    }
+    if (fTab->GetNumberOfTabs()<2 || !gPad)
+    {
+        *fLog << warn << "Sorry, you must have at least one existing canvas (gPad!=NULL)" << endl;
+        return 0;
+    }
+
+    AddExtension(name, "ps", num);
+
+    if (num<0)
+        *fLog << inf << "Open ps-File: " << name << endl;
+
+    TPad       *padsav = (TPad*)gPad;
+    TVirtualPS *psave  = gVirtualPS;
+
+    TPostScript ps(name, 112);
+    ps.SetBit(TPad::kPrintingPS);
+    ps.PrintFast(13, "/nan {1} def ");
+
+    gVirtualPS = &ps;
+
+    //
+    // Create a list to delete the canvas clones
+    //
+    TList l;
+    l.SetOwner();
+
+    //
+    // Create some GUI elements for a page legend
+    //
+    TLine line;
+
+    int page = 1;
+
+    //
+    // Maintain tab numbers
+    //
+    const Int_t from = num<0 ? 1 : num;
+    const Int_t to   = num<0 ? fTab->GetNumberOfTabs() : num+1;
+
+    for (int i=from; i<to; i++)
+    {
+        TCanvas *c;
+        if (!(c = GetCanvas(i)))
+        {
+            if (num<0)
+                *fLog << inf << " - ";
+            *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
+            continue;
+        }
+
+        //
+        // Init page and page size, make sure, that the canvas in the file
+        // has the same Aspect Ratio than on the screen.
+        //
+        ps.NewPage();
+
+        Float_t psw = 26; // A4 - width
+        Float_t psh = 20; // A4 - height
+
+        const Float_t cw = c->GetWw();
+        const Float_t ch = c->GetWh();
+
+        if (psw/psh>cw/ch)
+            psw = cw/ch*psh;
+        else
+            psh = ch/cw*psw;
+
+        ps.Range(psw, psh); // A4
+
+        //
+        // Clone canvas and change background color and schedule for
+        // deletion
+        //
+        TCanvas *n = (TCanvas*)c->Clone();
+        CanvasSetFillColor(*n, kWhite);
+        l.Add(n);
+
+        //
+        // Paint canvas into root file
+        //
+        if (num<0)
+            *fLog << inf << " - ";
+        *fLog << "Writing Tab #" << i << ": " << c->GetName() << " (" << n << ") ";
+        if (num>0)
+            *fLog << "to " << name;
+        *fLog << "..." << flush;
+
+        n->SetBatch(kTRUE);
+        n->Paint();
+
+        //
+        // Use the canvas as coordinate system for the overlaying text
+        //
+        gPad = n;
+
+        //
+        // Print overlaying text (NDC = %)
+        //
+        ps.SetTextColor(kBlack);
+        ps.SetTextSize(0.015);
+        ps.SetTextFont(22);
+        ps.SetTextAlign(11); // left top
+        ps.TextNDC(0, 1.02, TString("  ")+n->GetName());
+        ps.SetTextAlign(21); // cent top
+        ps.TextNDC(0.5, 1.02, "MARS - Magic Analysis and Reconstruction Software");
+        ps.SetTextAlign(31); // right top
+        ps.TextNDC(1, 1.02, Form("Page No.%i (%i)  ", page++, i));
+        line.PaintLineNDC(0, 1.015, 1, 1.015);
+
+        //
+        // Finish drawing page
+        //
+        n->SetBatch(kFALSE);
+        if (num<0)
+            *fLog << "done." << endl;
+    }
+
+    gPad = NULL; // Important!
+
+    l.Delete();
+
+    ps.Close();
+
+    gVirtualPS = psave;
+    padsav->cd();
+
+    *fLog << inf << "done." << endl;
+
+    return page-1;
+}
+
+/*
+void MStatusDisplay::SaveAsGIF(Int_t num, TString name) const
+{
+    AddExtension(name, "gif", num);
+
+    cout << "Open gif-File: " << name << endl;
+    cout << " SORRY, not implemented." << endl;
+}
+
+void MStatusDisplay::SaveAsC(Int_t num, TString name) const
+{
+    AddExtension(name, "C", num);
+
+    cout << "Open C-File: " << name << endl;
+    cout << " SORRY, not implemented." << endl;
+}
+*/
+
+// --------------------------------------------------------------------------
+//
+// In case of num<0 all tabs are written into the PS file. If num>0
+// the canvas in the corresponding tab is written to the file.
+// Name is the name of the file (with or without extension).
+//
+// Returns the number of keys written.
+//
+// To write all tabs you can also use SaveAsPS(name)
+//
+Int_t MStatusDisplay::SaveAsRoot(Int_t num, TString name)
+{
+    if (num>=fTab->GetNumberOfTabs())
+    {
+        *fLog << warn << "Tab #" << num << " doesn't exist..." << endl;
+        return 0;
+    }
+    if (num==0)
+    {
+        *fLog << warn << "Tab #" << num << " doesn't contain an embedded canvas..." << endl;
+        return 0;
+    }
+    if (fTab->GetNumberOfTabs()<2 || !gPad)
+    {
+        *fLog << warn << "Sorry, you must have at least one existing canvas." << endl;
+        return 0;
+    }
+
+    AddExtension(name, "root", num);
+
+    TFile *fsave = gFile;
+    TFile file(name, "RECREATE", "MARS - Status Window Contents", 9);
+    const Int_t keys = Write(num);
+    gFile = fsave;
+
+    return keys;
+}
Index: trunk/MagicSoft/Mars/mmain/MStatusDisplay.h
===================================================================
--- trunk/MagicSoft/Mars/mmain/MStatusDisplay.h	(revision 1957)
+++ trunk/MagicSoft/Mars/mmain/MStatusDisplay.h	(revision 1965)
@@ -10,15 +10,50 @@
 #endif
 
+#ifndef ROOT_TTimer
+#include <TTimer.h>
+#endif
+
+class MLog;
 class MGList;
+class MParContainer;
 
+class TPad;
+class TTimer;
 class TCanvas;
 
 class TGTab;
 class TGLabel;
+class TGListBox;
 class TGProgressBar;
 class TGHProgressBar;
 
-class MStatusDisplay : public TGTransientFrame
+class MStatusDisplay : public TGMainFrame
 {
+public:
+    typedef enum {
+        kLoopNone,
+        kLoopStop,
+        kFileSave,
+        kFileSaveAs,
+        kFileSaveAsPS,
+        kFileSaveAsRoot,
+        kFileSaveAsGIF,
+        kFileSaveAsC,
+        kFilePrint,
+        kFilePrinterName,
+        kTabSave,
+        kTabSaveAs,
+        kTabSaveAsPS,
+        kTabSaveAsRoot,
+        kTabSaveAsGIF,
+        kTabSaveAsC,
+        kTabPrint,
+        kTabNext,
+        kTabPrevious,
+        kFileExit,
+        kPicMagic,
+        kPicMars
+    } Status_t;
+
 private:
     MGList         *fList;
@@ -27,21 +62,52 @@
     TGLayoutHints  *fLayCanvas;
 
+    TTimer fTimer;
 
     TGLabel *fLine1;
     TGLabel *fLine2;
 
+    Status_t fStatus;
+
+    TString fPrinter;
+
+    MLog *fLog;
+    Int_t fLogIdx;
+    TTimer fLogTimer;
+    TGListBox *fLogBox;
+
+    void AddMenuBar();
     void AddProgressBar();
+    void AddMarsTab();
+    void AddLogTab();
     void AddTabs();
-    void AddStatusLine1();
-    void AddStatusLine2();
+    void AddStatusLines();
 
-    TCanvas *GetCanvas(TGCompositeFrame *f);
+    TCanvas *GetCanvas(TGCompositeFrame *f) const;
 
+    Bool_t ProcessMessageCommandMenu(Long_t mp1);
+    Bool_t ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2);
     Bool_t ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2);
     void   CloseWindow();
 
+    Bool_t HandleTimer(TTimer *timer=NULL);
+    void UpdateTab(TGCompositeFrame *f);
+
+    void DrawClonePad(TCanvas &newc, const TCanvas &oldc) const;
+    void CanvasSetFillColor(TPad &c, Int_t col) const;
+
+    void AddExtension(TString &name, const TString &ext, Int_t num) const;
+
+    enum {
+        kIsLocked = BIT(14)
+    };
 public:
-     MStatusDisplay();
+     MStatusDisplay(Long_t t=1000);
      virtual ~MStatusDisplay();
+
+     void SetLogStream(MLog *log);
+
+     void StartUpdate(Int_t millisec=-1);
+     void StopUpdate();                  
+     void SetUpdateTime(Long_t t);       
 
      TGProgressBar *GetBar() const { return (TGProgressBar*)fBar; }
@@ -49,9 +115,41 @@
      void SetStatusLine1(const char *txt);
      void SetStatusLine2(const char *txt);
+     void SetStatusLine2(const MParContainer &cont);
+
+     void SetPrinter(const TString &lpr) { fPrinter = lpr; }
 
      TCanvas &AddTab(const char *name);
 
-     TCanvas *GetCanvas(int i);
-     TCanvas *GetCanvas(const TString &name);
+     TCanvas *GetCanvas(int i) const;
+     TCanvas *GetCanvas(const TString &name) const;
+
+     Int_t Read(const char *name="MStatusDisplay");
+     Int_t Write(const char *name="MStatusDisplay", Int_t option=0, Int_t bufsize=0)
+     {
+         return Write(-1, name, option, bufsize);
+     }
+     Int_t Write(Int_t num, const char *name="MStatusDisplay", Int_t option=0, Int_t bufsize=0);
+
+     Bool_t CdCanvas(const TString &name);
+
+     void SetNoContextMenu(Bool_t flag=kTRUE);
+
+     Int_t SaveAsPS(TString name="") const { return SaveAsPS(-1, name); }
+     //Bool_t SaveAsGIF(TString name="") const { return SaveAsGIF(-1, name); }
+     //Bool_t SaveAsC(TString name="") const { return SaveAsC(-1, name); }
+     Int_t SaveAsRoot(TString name="") { return SaveAsRoot(-1, name); }
+     Int_t PrintToLpr() const { return PrintToLpr(-1); }
+
+     Int_t SaveAsPS(Int_t num, TString name="") const;
+     //Bool_t SaveAsGIF(Int_t num, TString name="") const;
+     //Bool_t SaveAsC(Int_t num, TString name="") const;
+     Int_t SaveAsRoot(Int_t num, TString name="");
+     Int_t PrintToLpr(Int_t num) const;
+
+     Status_t CheckStatus() const { return fStatus; }
+     void ClearStatus() { fStatus = kLoopNone; }
+
+     void Lock() { SetBit(kIsLocked); }
+     void UnLock() { ResetBit(kIsLocked); }
 
      ClassDef(MStatusDisplay, 0)   // Window for a status display
Index: trunk/MagicSoft/Mars/mmain/MainLinkDef.h
===================================================================
--- trunk/MagicSoft/Mars/mmain/MainLinkDef.h	(revision 1957)
+++ trunk/MagicSoft/Mars/mmain/MainLinkDef.h	(revision 1965)
@@ -8,10 +8,12 @@
 
 #pragma link C++ class MMars+;
+#pragma link C++ class MEvtDisp+;
 #pragma link C++ class MAnalysis+;
-#pragma link C++ class MEvtDisp+;
+//#pragma link C++ class MTextEntry+;
 #pragma link C++ class MDataCheck+;
 #pragma link C++ class MMonteCarlo+;
 #pragma link C++ class MProgressBar+;
 #pragma link C++ class MCameraDisplay+;
+#pragma link C++ class MStatusDisplay+;
 
 #endif
Index: trunk/MagicSoft/Mars/mmain/Makefile
===================================================================
--- trunk/MagicSoft/Mars/mmain/Makefile	(revision 1957)
+++ trunk/MagicSoft/Mars/mmain/Makefile	(revision 1965)
@@ -32,6 +32,8 @@
 SRCFILES = MBrowser.cc \
 	   MEvtDisp.cc \
+	   MStatusDisplay.cc \
 	   MDataCheck.cc \
 	   MMars.cc \
+           MGMenu.cc \
            MAnalysis.cc \
 	   MMonteCarlo.cc \
