Roody.cxx

Go to the documentation of this file.
00001 /*********************************************************************
00002   Name:         roody.cxx
00003   Created by:   Greg King
00004 
00005   Contents:     MIROODAS        
00006   $Log$
00007   Revision 1.78  2006/08/21 20:34:26  olchansk
00008   Improvements from ALPHA:
00009   - can show contents of a TDirectory
00010   - better Zoom and Rebinning controls
00011 
00012   Revision 1.77  2006/06/22 16:26:15  chuma
00013   fixed refresh button when setting refresh rate first time
00014 
00015   Revision 1.76  2006/06/08 21:21:03  chuma
00016   commented out debug write related to reset of individual histograms
00017 
00018   Revision 1.75  2006/06/07 22:11:13  chuma
00019   fixed refresh of individual histograms, changed refresh button to allow refresh now
00020 
00021   Revision 1.74  2006/06/05 21:02:49  chuma
00022   using new ROME feature to reset individual histograms
00023 
00024   Revision 1.73  2006/06/01 17:28:19  chuma
00025   pause refresh button now enabled/disabled by refresh rate, also group canvas zones output to xml fixed
00026 
00027   Revision 1.72  2006/05/31 16:40:34  chuma
00028   Copied new TNetFolder.h and .cpp from ROME
00029   Modified reset to use TNetFolder::executeCommand
00030 
00031   Revision 1.71  2006/04/19 16:57:30  chuma
00032   The refresh button was not working because of a confusion about the
00033   TString Compare method return value.
00034 
00035   Revision 1.70  2006/04/18 19:04:54  chuma
00036   Added "Pause/Restart Refresh" button.  The button string changes to reflect
00037   the current state.
00038 
00039   Revision 1.69  2005/12/20 18:57:36  chuma
00040   Fixed Roody.cxx so a histogram on a single zone canvas is saved to xml.
00041 
00042   Revision 1.68  2005/12/13 22:25:46  chuma
00043   Fixed: zone setup in a restore file does not open a canvas
00044 
00045   Revision 1.67  2005/12/13 19:15:53  chuma
00046   Modified Roody to fix problems with choosing which graphics pad to use.
00047 
00048   Revision 1.66  2005/11/29 19:26:01  chuma
00049   Restructuring the roody directories:  creating include/, lib/, and mxml/.
00050   All .h files now in include/. roody.so now in lib/. mxml files in mxml/.
00051   Makefile now in top roody/ directory. Object files go into obj/ directory
00052   (created by Makefile).  The Makefile is simplified.  Roody now uses mxml
00053   and no longer uses libxml2.  The Help About menu item now displays a
00054   message box with the current roody version.
00055 
00056   Revision 1.65  2005/11/21 20:38:38  chuma
00057   XML fixed.  xml code localized into RoodyXML to allow for future
00058   conversion to ROME xml.
00059 
00060   Revision 1.64  2005/08/22 22:03:12  qinggu
00061   Changes:
00062   - add functions to mark object is "online" (by Konstantin)
00063   - fix crash in NULL fUpdateTimer (wrong initialization order)
00064   - add "restore default.xml file"
00065   - cosmetic gui cleanup
00066 
00067   Revision 1.63  2005/08/22 20:41:26  qinggu
00068   Changes:
00069   - add dialog for entering arbitrary refresh period
00070   - add dialog for entering arbitrary zone settings
00071   - removed fZoneChoice
00072   - save current canvas settings
00073   - restore canvas settings from xml file
00074 
00075   Revision 1.62  2005/07/05 21:27:08  chuma
00076   add capability to set default zone settings in XML file
00077   submitted by Qing Gu
00078 
00079   Revision 1.61  2005/06/27 21:34:07  chuma
00080   Error messages from Roody will now appear as TGMsgBox forms which require
00081   the user to click the "Dismiss" button to acknowledge the error message.
00082   If the user chooses the x-axis scales for an online histogram using the mouse
00083   to select a range on the axis, that range will be used for re-displaying the
00084   histogram when it is refreshed. However, if the user chooses "XaxisLimits"
00085   from the context menu, that x-axis scaling will be used for all pads on that
00086   canvas, and a range as described above will be overridden by this scaling.
00087 
00088   Revision 1.60  2005/06/01 18:34:16  chuma
00089   Fixed refreshing of overlayed online histograms.
00090   Fixed refresh now.
00091   main.cxx:  class Roody now created on the stack instead of the heap.
00092   TNetFolder.cpp:  fixed memory leak relating to TMessage pointer
00093                    returned by TSocket::Recv( TMessage * )
00094 
00095   Revision 1.59  2005/05/09 06:12:31  olchansk
00096   Auto-detect presence of HBOOK support
00097   Simplify the Makefile
00098   Fix TNetFolder Makefile entry
00099 
00100   Revision 1.58  2005/05/04 19:47:02  chuma
00101   1) Memory leak fixed:
00102    when plotting destination set to replace, cloned objects with the canvas
00103    about to be closed were not being deleted.
00104   2) Group restore fixed:
00105    when restoring a saved session, and objects from file subdirectories were
00106    added to a group, they were not being included in that group.  Now the
00107    data file is searched recursively for subdirectories.
00108   3) Group draw fixed:
00109    TH2 and TH3 objects in a group were not being drawn.
00110 
00111   Revision 1.57  2005/04/12 18:40:13  chuma
00112   Fixed memory leak in Roody.cxx when getting a NetFolder object.
00113 
00114   Revision 1.56  2005/04/12 18:02:23  chuma
00115   Modified how the reset option is implemented, using "Command" (which has
00116   been modified in mana.c) instead of "Reset" (which has been removed from
00117   mana.c).
00118 
00119   Revision 1.55  2005/04/08 16:11:17  schneebeli
00120   Inserted #ifdef HAVE_HBOOK
00121 
00122   Revision 1.54  2005/03/18 17:42:17  chuma
00123   Context menu for multiple selections now will only display "New canvas",
00124   "Add to group" and, if there are online members, "Reset", since the
00125   options "Current pad", "Overlay on pad" and "Next pad" are not
00126   relevant to multiple selections.
00127 
00128   Revision 1.53  2005/03/18 17:31:07  chuma
00129   Changed the group context menu to "Draw group", "Reset group" and
00130   "Delete group".  Reset group means reset any online members of the group.
00131   Multiple selections, i.e., left click while holding down the control key,
00132   now have the same context menu (right click to open) as single selections.
00133   Online folders now have a context menu with "New canvas", "Add to group"
00134   and "Reset" options.
00135 
00136   Revision 1.52  2005/03/11 22:50:39  chuma
00137   Roody can now reset online histograms via context menu or main menu.  This
00138   requires a small change in mana.c  Also, fixed a problem with segmentation
00139   faults when trying to connect to an invalid server port.
00140 
00141   Revision 1.51  2005/03/10 18:29:43  chuma
00142   Fixed segmentation fault problems when connected online, then having the
00143   connection broken, then re-establishing the connection and then clicking
00144   on an online item in the main window.  The problem is in TGListTree in
00145   the ROOT code, and is fixed here by including 2 routines into MTGListTree.
00146 
00147   Revision 1.50  2005/02/07 19:44:41  chuma
00148   Modified timer for testing whether online connection is still valid.
00149   If the connection is broken, the timer tests the connection every second
00150   until it has reconnected.  When the connection is finally remade, any
00151   online histograms will again be refreshed as before.
00152 
00153   Revision 1.49  2005/02/01 19:27:57  chuma
00154   Two bugs were introduced yesterday...
00155    -- program crashes when trying to connect online via  roody -h nodename
00156       (uninitialized pointer)
00157    -- program crashes when restoring an xml file which tries to use the
00158       external dtd file (unchecked error condition)
00159   Both problems are now fixed.
00160 
00161   Revision 1.48  2005/01/31 23:51:32  chuma
00162   A timer has been added to check if the online socket remains valid.  If, say,
00163   the analyzer has been stopped while running Roody, this will be detected
00164   and the connection closed, then, every second, that connection will be
00165   attempted until successful.  Also, the external dtd file, roody.dtd, has
00166   been eliminated in favour of internal dtd verification.  Roody is being
00167   linked with Root version 4.00.08, as version 4.02.00 introduces problems,
00168   such as context menu errors.
00169 
00170   Revision 1.47  2005/01/28 22:35:13  chuma
00171   The y-axis scales can now be fixed just like the x-axis scales.
00172 
00173   Revision 1.46  2005/01/26 23:11:00  chuma
00174   Added "ZoomOption" option to the context menu produced by right clicking
00175   anywhere on histogram frame.  This opens up a new canvas, titled
00176   "Zoom Canvas", containing a copy of the histograms in the original frame.
00177 
00178   Revision 1.45  2005/01/24 20:03:00  chuma
00179   Modified Roody.cxx to display the histogram name range instead of
00180   the counter range when displaying > 1000 histograms.
00181 
00182   Revision 1.44  2005/01/21 22:24:23  chuma
00183   When opening a .root file, if there are more than 1000 histograms
00184   in the file, the display is divided up into folders, where each
00185   folder holds 250 histograms (except for the final folder, which
00186   may be smaller).  This was done because of a problem with TGListTree
00187   which shows up with large numbers of objects.
00188 
00189   Revision 1.43  2005/01/08 01:11:07  odonnell
00190   Roody will display polygons (TCutG) from online TNetFolder or offline TFile.
00191   With a suitable analyzer, you can right click on any polygon and send it to
00192   an analyzer.
00193 
00194   Revision 1.42  2004/11/04 23:14:02  chuma
00195   To set the x-axis limits, right click anywhere on a histogram frame and
00196   choose "XaxisLimits" from the popup context menu.  This brings up a
00197   dialog box where you can enter the xmin and xmax values. Click "OK" and
00198   all pads within the currently selected canvas will be redrawn with
00199   that x-axis scale.  To reset all pads so the x-axes are unzoomed, click
00200   "Unzoom".
00201 
00202   Every overlayed histogram on a currently drawn histogram, will have be drawn
00203   in a different color (up to the max number of colors).
00204 
00205   When choosing a new pad division for a canvas (from the "Zones" menu),
00206   all currently drawn histograms will be redrawn in the new zones. If there
00207   are fewer pads in the new configuration, the extra histograms are
00208   not drawn.  Overlays (with their color) and x-axis scaling are preserved
00209   in the new configuration.
00210 
00211   Revision 1.41  2004/10/28 22:53:45  chuma
00212   When the number of zones (sub-pads) is changed, the histograms on the
00213   active canvas will be redrawn on the new canvas.  Also, more general
00214   code cleanup.
00215 
00216   Revision 1.40  2004/10/26 10:28:59  schneebeli
00217   Peakfinder is available also when clicking on the TFrame;
00218   Zones get activated by all mouse button clicks
00219 
00220   Revision 1.39  2004/10/21 20:10:14  chuma
00221   Command line argument change:
00222    the space between -h and hostname is optional
00223    the space between -r and filename is optional
00224 
00225   The save file is now an xml file validated with roody.dtd
00226   When saving or restoring, if you enter a filename without an extension,
00227   .xml will be appended.  The previous save file format is no longer
00228   supported.
00229 
00230   New files:  RoodyXML.h, RoodyXML.cxx, roody.dtd
00231 
00232   Fixed up group problems when an online file is located in a folder.
00233 
00234   Makefile modified to support libxml2.
00235 
00236   Revision 1.38  2004/10/08 19:52:02  chuma
00237   Command line argument change:
00238    -h (or -H) followed by nothing shows program usage
00239    -hhostname or -hhostname:port connect to analyzer on given host (and port)
00240    -rsavefile restores savefile
00241 
00242   Offline items added to a group are new removed from the group if the
00243    file is closed.
00244 
00245   Offline item titles are now displayed after the name if different than
00246    the item name.
00247 
00248   "Run# number" added to the item title if the filename contains a runnumber.
00249 
00250   Revision 1.37  2004/09/30 19:03:43  chuma
00251   Right click on the Offline folder opens file dialog.
00252   Right click on the Online folder opens hostname dialog.
00253   If only one group exists, you will not be asked to choose the group
00254   when adding items to a group.
00255   Right click on multiple histogram selection allows for adding to a group.
00256 
00257   Revision 1.36  2004/09/29 18:51:18  olchansk
00258   Rename "TTriumfFileGUI" to "Roody"
00259 
00260   Revision 1.35  2004/09/24 22:08:35  chuma
00261   Added TNetFolder support
00262 
00263   Revision 1.34  2004/09/20 19:39:24  chuma
00264   multiple selection of histograms with CTRL key updated
00265 
00266   Revision 1.33  2004/09/16 16:30:36  schneebeli
00267   Linking on windows and multiple selection of items
00268 
00269   Revision 1.32  2004/07/28 00:05:28  olchansk
00270   Add peak finder to TH1C,S,I,F,D histograms
00271 
00272   Revision 1.31  2004/07/20 18:36:21  chuma
00273   Added right click on online hostname to choose "Disconnect online".
00274   Moved groups to top of the list displayed in the gui.
00275   If the user entered save file name does not contain ".save" it will
00276   be appended to the filename.
00277 
00278   Revision 1.30  2004/07/19 19:39:40  chuma
00279   Fixed some minor bugs:
00280    do not make group named "-1" when TGTextDialog returns "-1" if canceled;
00281    get the port number correct on a restore;
00282    rationalize the host name and port number code;
00283 
00284   Revision 1.29  2004/07/16 17:35:58  chuma
00285   Fixed bugs with SAVE/RESTORE so now you can save and restore as many times
00286   as you in a single session.
00287 
00288   Revision 1.28  2004/07/15 22:25:06  chuma
00289   Added the run number (extracted from the root data file name) to the
00290   title for histogram plots.
00291 
00292   Revision 1.27  2004/07/15 18:40:57  chuma
00293   Fixed the online refresh problem when drawing groups.
00294 
00295   Revision 1.26  2004/07/15 16:16:21  chuma
00296   Implemented SAVE and RESTORE, but without xml (linking trouble).
00297   Draw Group also modified to title the window with the group name.
00298   Still to check, online refresh mode for group canvas.
00299 
00300   Revision 1.25  2004/07/05 21:47:05  olchansk
00301   implement HBOOK files
00302   consolidate DisplayFile() code
00303 
00304   Revision 1.24  2004/06/28 01:25:26  olchansk
00305   fix crash if "draw" an empty group
00306 
00307   Revision 1.23  2004/06/25 21:46:34  chuma
00308   Added:  current online host name is displayed in message dialog
00309   Fixed:  online histograms can now be added and displayed in groups
00310 
00311   Revision 1.22  2004/06/16 21:45:53  chuma
00312   Added:  right click on filename brings up "Close file" option
00313           automatic creation of TEMP folder (under Offline)
00314           right click on Groups folder brings up "Make new group" option
00315           right click on group name brings up "Delete group" and "Draw" options
00316           right click on histogram brings up "Add to group" option which
00317             brings up a list of existing groups
00318 
00319   Revision 1.21  2004/05/08 03:43:34  olchansk
00320   RTFM on TGListTree shows how to place the popup menu without doing the event handler kludge
00321   Implement right-click menus for other list tree items
00322 
00323   Revision 1.20  2004/05/08 03:08:02  olchansk
00324   fix context menu handling:
00325   - pop context menu at the pointer coordinates (kludged from TGFrame.cxx)
00326   - plot histogram from popup does not change the menu "plot in" setting
00327   - changing menu "plot in" setting does not replot the histogram
00328 
00329   Revision 1.19  2004/05/08 01:53:44  olchansk
00330   fgPeakFindPanel() becomes a global (static) object, created once
00331   add PeakFind() context menu once, in the constructor
00332 
00333   Revision 1.18  2004/04/08 17:27:40  chuma
00334   Peak find added to context menu for right click on histograms.
00335   Updated TPeakFindPanel sources added to cvs at the same level as
00336   TTriumfFileGUI sources.  Clear All online histograms added to menu.
00337 
00338   Revision 1.17  2004/04/02 18:52:00  chuma
00339   the previously committed files were the same old files
00340   this commit is to correct that mistake only
00341   these files should make a square gui window with one canvas and no buttons
00342 
00343   Revision 1.15  2004/01/19 19:34:09  chuma
00344   modified TTriumfFileGUI.cxx and .h so the plotting context menu opens when
00345   right clicking on an online histogram, also duplicate online histograms
00346   will not be listed in the lower ListView
00347 
00348   Revision 1.14  2004/01/16 22:36:42  chuma
00349   modified TTriumfFileGUI.cxx and .h so that x-axis zooming is not lost
00350   when an online histogram is refreshed, also fixed the refresh menu so
00351   the current refresh rate is checked correctly
00352 
00353   Revision 1.13  2004/01/15 22:38:57  chuma
00354   create plotting context menu for upper TreeView,
00355   prevent duplicate items in lower ListView, more code cleanup
00356 
00357   Revision 1.12  2004/01/12 23:45:32  chuma
00358   add check marks to menu items so user knows what is in effect
00359 
00360   Revision 1.11  2004/01/09 20:41:16  chuma
00361   modified to draw in first pad when divided into zones
00362 
00363   Revision 1.10  2004/01/01 01:22:44  olchansk
00364   sanitize zone handling
00365   implement "draw in new canvas", "draw in current pad",
00366             "overlay into current pad", "draw in next pad"
00367 
00368   Revision 1.9  2003/12/21 04:45:06  olchansk
00369   do not print the message "no online histograms loaded" every second
00370 
00371   Revision 1.8  2003/12/10 18:07:36  chuma
00372   first pass by Joe Chuma
00373 
00374   Revision 1.7  2003/08/22 19:06:38  gking
00375   TCanvas are shown in .root files;
00376   TCanvas can be drawn and if histograms present (in subpads too),
00377    they are cloned and displayed in list view
00378 
00379   Revision 1.6  2003/08/19 18:42:31  gking
00380   Port Number Displayed by Hostname
00381   Changed default OptStat and FitStat
00382 
00383   Revision 1.5  2003/08/18 22:33:50  gking
00384   New Menus (not functional yet)
00385   Connect to port using : switch
00386   Online Update Functional (not yet complete)
00387 
00388   Revision 1.4  2003/08/08 22:22:11  gking
00389   Online Functionality
00390 
00391   Revision 1.3  2003/07/25 22:14:18  gking
00392   Loading files from command line using -f switch
00393 
00394   Revision 1.2  2003/07/23 01:45:41  gking
00395   Simple Updates
00396 
00397   Revision 1.1.1.1  2003/07/22 19:53:24  gking
00398   INITIAL
00399   Requires:      ROOT v3.05.06
00400 
00401 *********************************************************************/
00402 //////////////////////////////////////////////////////////////////////
00403 // Online Code is based upon code written by Stephan Ritt found in  //
00404 // rmidas.c, a component of the MIDAS (see http://midas.triumf.ca/) //
00405 //////////////////////////////////////////////////////////////////////
00406 
00407 #ifdef HAVE_HBOOK
00408 #include "THbookFile.h"
00409 #endif
00410 #include "Roody.h"
00411 #include "RoodyXML.h"
00412 
00413 #include "TAxisLimitsDialog.h"
00414 
00415 ClassImp(Roody);
00416 
00417 TPeakFindPanel *Roody::fgPeakFindPanel = 0;
00418 
00419 Roody::Roody() : TGMainFrame( 0, 0, 0 )
00420 {}
00421     
00422 Roody::Roody( const TGWindow *p, UInt_t w, UInt_t h,
00423                                 char **filenames, int fileCount,
00424                                 char const *hostname, char const *xmlFile ) 
00425     : TGMainFrame( p, w, h ),
00426       fParentDir( new TDirectory("parent","The Parent Directory") ),
00427       fFileList( new TList() ),
00428       fHistList( new TList() ),
00429       fTreeList( new TList() )
00430 {
00431   /*
00432   filetypes2 = {"All files","*",0,0};         // Used for all files browsing
00433   filetypes3 = {"ROOT macros","*.C",0,0};     // Used for macros browsing
00434   filetypes4 = {"All files","*",
00435                 "ROOT files","*.root",
00436                 "ROOT macros","*.C",
00437                 "Hbook files","*.hbook",0,0}; // Combination of 0,1,2,3
00438   */
00439   //fHbookSupport = gSystem->Load("libHbook");
00440   //
00441   fSock = 0;
00442   fHistNames = 0;
00443   fPopupMenu = 0;
00444   fAddToGroupPopup = 0;
00445   fOpeningFile = false;
00446   //
00447   fCurrentFile = 0;
00448 #ifdef HAVE_HBOOK
00449   fCurrentHbook = 0;
00450 #endif
00451   fSaveFile = 0;
00452   //
00453   fCanvasCount = 0;
00454   fZoomCanvas = 0;
00455   fCurrentCanvas = 0;
00456   //
00457   fFileList->SetOwner();
00458   fHistList->SetOwner();
00459   fTreeList->SetOwner();
00460   //
00461   SetWindowName("Roody");
00462   //
00463 #if 0
00464   gStyle->SetPalette( 1 );
00465   //
00466   gStyle->SetTitleTextColor( kBlue );
00467   gStyle->SetStatTextColor( kBlue );
00468   gStyle->SetTitleBorderSize( 0 );
00469   gStyle->SetStatBorderSize( 0 );
00470   //
00471   gStyle->SetFuncColor( kBlue );
00472   gStyle->SetOptFit( 1111 );
00473   gStyle->SetOptStat( 1111001 );
00474 #endif
00475   //
00476   LayoutGUI();
00477   AddPeakFind();
00478   AddAxisLimits();
00479   AddSetCut();
00480   AddZoomOption();
00481   //
00482   Resize( GetDefaultSize() );
00483   MapSubwindows();
00484   Layout(); // member function of TGCompositeFrame
00485   MapWindow();
00486   fStatusBar->SetText("Welcome to Roody");
00487   //
00488   fZoneRows = 1;  // default zone row setting
00489   fZoneColumns = 1;  // default zone column setting
00490   fUpdateTimerSec = 0;  //default refresh time
00491   fOnlineAborted = kFALSE;
00492   fUpdateTimer = new TTimer(0,kTRUE);
00493 
00494   if( xmlFile )RestoreFile( xmlFile );
00495   else // restore file default.xml if it exists
00496   {
00497     FILE *fp = fopen("default.xml","r");
00498     if( fp )
00499     {
00500       fclose( fp );
00501       RestoreFile( "default.xml" );
00502     }
00503   }
00504   if( filenames!=0 && fileCount>0 )
00505   {
00506     for( int i=0; i<fileCount; ++i )
00507     {
00508       if( TString(filenames[i]).Contains(".root") )OpenRootFile( filenames[i] );
00509 #ifdef HAVE_HBOOK
00510       else if( TString(filenames[i]).Contains(".hbook") )OpenHbookFile( filenames[i] );
00511 #endif
00512     }
00513   }
00514   if( hostname )ConnectServer( hostname );
00515   //
00516   TQObject::Connect( fUpdateTimer,"Timeout()","Roody",this,"UpdateHistograms()" );
00517   StartOnlineTimer(); // Refresh off by default
00518   //
00519   fParentDir->cd();
00520 }
00521 
00522 void Roody::RestoreFile( char const *xmlFilename )
00523 {
00524   RoodyXML xml;
00525   if( !xml.OpenFileForRead(xmlFilename) )
00526   {
00527     TString s("Failed to open XML file: ");
00528     s += xmlFilename;
00529     fStatusBar->SetText( s );
00530     new TGMsgBox( gClient->GetRoot(), this, "Error", s.Data(), kMBIconExclamation, 0, NULL );
00531     return;
00532   }
00533   //xml.PrintTree( 0 );
00534   if( xml.GetOnlineNode() )
00535   {
00536     //std::cout << "online: info=\"" << xml.GetOnlineInfo() << "\"\n";
00537     if( !fSock )ConnectServer( xml.GetOnlineInfo().c_str() );
00538   }
00539   while( xml.GetFileNode() )
00540   {
00541     std::string fileName( xml.GetFileInfo() );
00542     //std::cout << "file: filename = \"" << fileName << "\"\n";
00543     TGListTreeItem *fileItem =
00544         fFileOnlineContents->FindChildByName(fTreeItemFiles,fileName.c_str()); 
00545     if( fileItem ) // file already open
00546     {
00547       fCloseFile = static_cast<TFile*>(static_cast<TObject*>(fileItem->GetUserData())); 
00548       fTreeItemCurrent = fileItem;
00549       CloseFile();
00550     } 
00551     bool errorOccurred = false;
00552     if( fileName.find(".root") != fileName.npos )errorOccurred = OpenRootFile( fileName.c_str() );
00553 #ifdef HAVE_HBOOK
00554     else errorOccurred = OpenHbookFile( fileName.c_str() );
00555 #endif 
00556     if( errorOccurred )
00557     { 
00558       std::string s("Could not open data file \"");
00559       s += fileName + "\"\nerror occurred while parsing xml file \"" + xmlFilename; 
00560       new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00561       //return;
00562     }
00563   }
00564   if( xml.GetGraphicsNode() )
00565   {
00566     xml.GetZones( fZoneColumns, fZoneRows );
00567     SetupZonesMenu();
00568     //SetupZones( fZoneColumns, fZoneRows );
00569     //MakeNewCanvas();
00570     SetRefreshRate( xml.GetRefreshRate() );
00571     //std::cout << "graphics: cols=\"" << fZoneColumns << "\", rows=\"" << fZoneRows
00572     //          << "\", refresh=\"" << xml.GetRefreshRate() << "\"\n";
00573   }
00574   while( xml.GetCanvasNode() )
00575   {
00576     int columns, rows;
00577     xml.GetZones( columns, rows );
00578     //std::cout << "canvas: cols=\"" << columns << "\", rows=\"" << rows << "\"\n";
00579     fZoneColumns = columns;
00580     fZoneRows = rows;
00581     MakeNewCanvas();
00582     fDrawDestination = D_PLOT_NEXT;
00583     while( xml.GetHistogramNode() )
00584     {
00585       std::string name( xml.GetHistogramName() );
00586       std::string source( xml.GetHistogramSource() );
00587       //std::cout << "canvas hist: name=\"" << name << "\", source=\"" << source << "\"\n";
00588       if( source == "online" )
00589       {
00590         if( !fSock )
00591         {
00592           std::string s("no online connection has been made\nerror occurred while parsing xml file \"");
00593           s += xmlFilename;
00594           new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00595           //return;
00596           continue;
00597         }
00598         TObject *netObject = GetNetFolderObject( name.c_str() );
00599         if( !netObject )
00600         {
00601           std::string s("histogram \"");
00602           s += name + "\" not found in online area\nerror occurred while parsing xml file \"" + xmlFilename;
00603           new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00604           //return;
00605           continue;
00606         }
00607         MarkObjectAsOnline( netObject );
00608         DrawObject( netObject );
00609       }
00610       else
00611       {
00612         TGListTreeItem *fileItem = fFileOnlineContents->FindChildByName(fTreeItemFiles,source.c_str());
00613         if( !fileItem )
00614         {
00615           std::string s("file \"");
00616           s += source + "\" not open\nerror occurred while parsing xml file \"" + xmlFilename;
00617           new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00618           //return;
00619           continue;
00620         }
00621         TFile *fileObject = static_cast<TFile*>(static_cast<TObject*>(fileItem->GetUserData()));
00622         TObject *object = SearchDirectory( fileObject, name.c_str() );
00623         if( !object )
00624         {
00625           std::string s("histogram \"");
00626           s += name + "\" not found in \"" + source +
00627               "\"\nerror occurred while parsing xml file \"" + xmlFilename;
00628           new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00629           //return;
00630           continue;
00631         }
00632         DrawObject( object );
00633       }
00634     }
00635   }
00636   while( xml.GetGroupNode() )
00637   {
00638     std::string groupname( xml.GetGroupName() );
00639     //std::cout <<"group: name=\"" << groupname << "\"\n";
00640     TGListTreeItem *groupItem = fFileOnlineContents->FindChildByName(fTreeItemGroups,groupname.c_str());
00641     if( groupItem )
00642     {
00643       fTreeItemCurrent = groupItem;
00644       DeleteGroup();
00645     }
00646     if( !MakeNewGroup(groupname.c_str()) )
00647     {
00648       std::string s("Could not make new group \"");
00649       s += groupname + "\"\nerror occurred while parsing xml file \"" + xmlFilename;
00650       new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00651       //return;
00652       continue;
00653     }
00654     while( xml.GetHistogramNode() )
00655     {
00656       std::string name( xml.GetHistogramName() );
00657       std::string source( xml.GetHistogramSource() );
00658       //std::cout << "group hist: name=\"" << name << "\", source=\"" << source << "\"\n";
00659       TObject *object = 0;
00660       if( source == "online" )
00661       {
00662         if( !fSock )
00663         {
00664           std::string s("no online connection has been made\nerror occurred while parsing xml file \"");
00665           s += xmlFilename;
00666           new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00667           //return;
00668           continue;
00669         }
00670         object = GetNetFolderObject( name.c_str() );
00671         if( !object )
00672         {
00673           std::string s("histogram \"");
00674           s += name + "\" not found in online area\nerror occurred while parsing xml file \"" + xmlFilename;
00675           new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00676           //return;
00677           continue;
00678         }
00679         object = static_cast<TObjString*>(new TObjString(name.c_str()));
00680         AddHistogramToGroup( fGroupFolders.size()-1, object, "online" );    
00681       }
00682       else
00683       {
00684         TGListTreeItem *fileItem =
00685             fFileOnlineContents->FindChildByName(fTreeItemFiles,source.c_str());
00686         if( !fileItem )
00687         {
00688           std::string s("file \"");
00689           s += source + "\" not open\nerror occurred while parsing xml file \"" + xmlFilename;
00690           new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00691           //return;
00692           continue;
00693         }
00694         TFile *fileObject = static_cast<TFile*>(static_cast<TObject*>(fileItem->GetUserData()));
00695         object = SearchDirectory( fileObject, name.c_str() );
00696         if( !object )
00697         {
00698           std::string s("histogram \"");
00699           s += name + "\" not found in \"" + source +
00700               "\"\nerror occurred while parsing xml file \"" + xmlFilename;
00701           new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00702           //return;
00703           continue;
00704         }
00705         AddHistogramToGroup( fGroupFolders.size()-1, object, source.c_str() );    
00706       }
00707     }
00708   }
00709 }
00710 
00711 void Roody::SetupZonesMenu()
00712 {
00713   UncheckAllZones();
00714   switch( fZoneColumns )
00715   {
00716     case 1:
00717     {
00718       switch( fZoneRows )
00719       {
00720         case 1:
00721           fMenuZones->CheckEntry( M_ZONES_11 );
00722           break;
00723         case 2:
00724           fMenuZones->CheckEntry( M_ZONES_12 );
00725           break;
00726         default:
00727           SetZonesUser();
00728       }
00729       break;
00730     }
00731     case 2:
00732     {
00733       switch( fZoneRows )
00734       {
00735         case 1:
00736           fMenuZones->CheckEntry( M_ZONES_21 );
00737           break;
00738         case 2:
00739           fMenuZones->CheckEntry( M_ZONES_22 );
00740           break;
00741         default:
00742           SetZonesUser();
00743       }
00744       break;
00745     }
00746     case 3:
00747     {
00748       switch( fZoneRows )
00749       {
00750         case 3:
00751           fMenuZones->CheckEntry( M_ZONES_33 );
00752           break;
00753         default:
00754           SetZonesUser();
00755       }
00756       break;
00757     }
00758     case 4:
00759     {
00760       switch( fZoneRows )
00761       {
00762         case 3:
00763           fMenuZones->CheckEntry( M_ZONES_44 );
00764           break;
00765         default:
00766           SetZonesUser();
00767       }
00768       break;
00769     }
00770     default:
00771       SetZonesUser();
00772   }
00773 }
00774 
00775 void Roody::SetZonesUser()
00776 {
00777   fMenuZones->DeleteEntry( M_ZONES_USER );
00778   std::stringstream ss;
00779   ss << fZoneColumns << "x" << fZoneRows;
00780   fMenuZones->AddEntry( ss.str().c_str(), M_ZONES_USER,
00781                         0, 0, fMenuZones->GetEntry(M_ZONES_DIALOG) );
00782   fMenuZones->CheckEntry( M_ZONES_USER );
00783 }
00784 
00785 void Roody::SaveFile( char const *xmlFilename )
00786 {
00787   RoodyXML xml;
00788   std::ofstream &output( xml.OpenFileForWrite(xmlFilename) );
00789   if( output.rdstate() != std::ios::goodbit  )
00790   {
00791     std::string s("Failed to open XML file \"");
00792     s += xmlFilename;
00793     new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
00794     return;
00795   }
00796   output << "<roody>\n";
00797   //
00798   // write online section
00799   //
00800   if( fSock )
00801   { 
00802     output << "  <online>\n";
00803     output << "    <host>" << xml.Encode(fHostName.Data()) << "</host>\n";
00804     output << "    <port>" << xml.Encode(fPortName.Data()) << "</port>\n";
00805     output << "  </online>\n";
00806   }
00807   // 
00808   // write file section
00809   // 
00810   TGListTreeItem *temp = fTreeItemFiles->GetFirstChild();
00811   if( temp ) 
00812   { 
00813     output << "  <file>" << xml.Encode(temp->GetText()) << "</file>\n";
00814     TGListTreeItem *temp2;
00815     while( (temp2=temp->GetNextSibling()) )
00816     { 
00817       output << "  <file>" << xml.Encode(temp2->GetText()) << "</file>\n";
00818       temp = temp2;
00819     } 
00820   } 
00821   //
00822   // write graphics section
00823   //
00824   output << "  <graphics>\n";
00825   std::string zones = GetZoneSetting();
00826   output << "    <zones>" << xml.Encode(zones) << "</zones>\n";
00827   output << "    <refresh>" << fUpdateTimerSec << "</refresh>\n";
00828   output << "  </graphics>\n";
00829   //
00830   // write canvas section
00831   //
00832   TIter next( gROOT->GetListOfCanvases() );
00833   TCanvas *canvas;
00834   while((canvas = static_cast<TCanvas*>(next())))
00835   {
00836     output << "  <canvas>\n";
00837     output << "    <zones>" << fZoneSetting[canvas->GetName()] << "</zones>\n";
00838     TIter canvasNext( canvas->GetListOfPrimitives() );
00839     TObject *canvasObject;
00840     while( (canvasObject=static_cast<TObject*>(canvasNext())) )
00841     {
00842       if( canvasObject->InheritsFrom(TH1::Class()) )
00843       {
00844         output << "    <histogram>\n";
00845         output << "      <name>" << xml.Encode(canvasObject->GetName()) << "</name>\n";
00846         if( ObjectIsOnline(canvasObject) )
00847           output << "      <source>online</source>\n"; 
00848         else 
00849           output << "      <source>"
00850                  << xml.Encode(GetFileFromHist(static_cast<TH1*>(canvasObject)))
00851                  << "</source>\n";
00852         output << "    </histogram>\n";
00853       }
00854       else if( canvasObject->InheritsFrom(TPad::Class()) )
00855       {
00856         TPad *pad = static_cast<TPad*>(canvasObject);
00857         TIter padNext( pad->GetListOfPrimitives() );
00858         TObject *padObject;
00859         while( (padObject=static_cast<TObject*>(padNext())) )
00860         {
00861           if( padObject->InheritsFrom(TH1::Class()) )
00862           {
00863             output << "    <histogram>\n";
00864             output << "      <name>" << xml.Encode(padObject->GetName()) << "</name>\n";
00865             if( ObjectIsOnline(padObject) )
00866               output << "      <source>online</source>\n"; 
00867             else 
00868               output << "      <source>"
00869                      << xml.Encode(GetFileFromHist(static_cast<TH1*>(padObject)))
00870                      << "</source>\n";
00871             output << "    </histogram>\n";
00872           }
00873         }
00874       }
00875     }
00876     output << "  </canvas>\n";
00877   }
00878   //
00879   // write group section
00880   //
00881   std::size_t nGroups = fGroupFolders.size();
00882   for( std::size_t i=0; i<nGroups; ++i )
00883   {
00884     output << "  <group>\n";
00885     TGListTreeItem *groupFolder = fGroupFolders[i];
00886     output << "    <name>" << xml.Encode(groupFolder->GetText()) << "</name>\n";
00887     std::pair<GroupMap::iterator,GroupMap::iterator> p = fGroupHists.equal_range( i );
00888     for( GroupMap::iterator i=p.first; i!=p.second; ++i )
00889     {
00890       GroupItem groupItem( i->second );
00891       output << "    <histogram>\n";
00892       output << "      <name>" << xml.Encode(groupItem.item->GetText()) << "</name>\n";
00893       output << "      <source>" << xml.Encode(groupItem.source) << "</source>\n";
00894       output << "    </histogram>\n";
00895     }
00896     output << "  </group>\n";
00897   }
00898   output << "</roody>\n";
00899 }
00900 
00901 std::string Roody::GetFileFromHist( TH1 *hist )
00902 {
00903   TIter funcNext( hist->GetListOfFunctions() );
00904   TObject *func;
00905   std::string filename;
00906   while( (func=static_cast<TObject*>(funcNext())) )
00907   {
00908     if( func->InheritsFrom(TObjString::Class()) )
00909     {
00910       TObjString *str = static_cast<TObjString*>(func);
00911       std::string s( str->GetString().Data() );
00912       std::size_t size = s.size();
00913       if( size>=5 && s.substr(0,5) == "file:" )
00914       {
00915         filename = s.substr(5,size-5);
00916         break;
00917       }
00918     }
00919   }
00920   if( filename.empty() )filename = "unknown";
00921   return filename;
00922 }
00923 
00924 Roody::~Roody()
00925 {
00926   //MENU BAR
00927   delete fMenuBarLayout1;
00928   delete fMenuBarLayout2;
00929   delete fMenuBarLayout3;
00930   delete fMenuFile;
00931   delete fMenuRefresh;
00932   delete fMenuZones;
00933   delete fMenuPlot;
00934   delete fMenuHelp;
00935   delete fMenuBar;
00936   //
00937   //FrameLayouts
00938   delete fFrameLayout1;
00939   delete fFrameLayout2;
00940   delete fFrameLayout3;
00941   delete fStatusBarLayout;
00942   //
00943   //Buttons
00944   delete fRefreshButton;
00945   //
00946   //ListTree
00947   delete fFileOnlineContents;
00948   //
00949   //Canvas
00950   delete fFileOnlineCanvas;
00951   //
00952   //Labels
00953   //
00954   //StatusBar
00955   delete fStatusBar;
00956   //
00957   //Frames
00958   delete fVerticalFrame;
00959   delete fHorizontalFrame;
00960   //
00961   //Timers
00962   delete fUpdateTimer;
00963   //
00964   //Remove All Added files from List ... simple garbage collecting
00965   fFileList->Clear();
00966   fTreeList->Clear();
00967   //
00968   //Lists
00969   delete fFileList;
00970   delete fTreeList;
00971   //
00972   //delete fParentDir;
00973   //Cleanup();
00974   //
00975   std::vector<CanvasLimits*>::const_iterator end = fCanvasLimitsVector.end();
00976   for( std::vector<CanvasLimits*>::const_iterator i=fCanvasLimitsVector.begin(); i!=end; ++i )
00977     delete *i;
00978 }
00979 
00980 void Roody::LayoutGUI()
00981 {
00982   LayoutMenuBar(); // Lay out the MenuBar
00983   //
00984   // Lay out the rest of the GUI
00985   //
00986   fFrameLayout1 = new TGLayoutHints( kLHintsTop|kLHintsLeft, 5, 5, 5, 5 );
00987   fFrameLayout2 = new TGLayoutHints( kLHintsTop|kLHintsExpandX|kLHintsExpandY, 5, 5, 5, 5 );
00988   fFrameLayout3 = new TGLayoutHints( kLHintsTop|kLHintsExpandX, 0, 0, 0, 0 );
00989   //
00990   fVerticalFrame = new TGVerticalFrame( this, 10, 10 );
00991   //
00992   fHorizontalFrame = new TGHorizontalFrame( fVerticalFrame, 10, 10 );
00993   fRefreshButton = new TGTextButton( fHorizontalFrame, "     Refresh NOW      ", M_REFRESH_BUTTON );
00994   fRefreshButton->Associate( this );
00995   fRefreshButton->SetToolTipText( "click to refresh online histograms once right now", 250 );
00996   fHorizontalFrame->AddFrame( fRefreshButton, new TGLayoutHints(kLHintsCenterX,2,2,2,2) );
00997   fRefreshButton->SetEnabled( kFALSE );
00998   fVerticalFrame->AddFrame( fHorizontalFrame, fFrameLayout3 );
00999   //
01000   fFileOnlineCanvas = new TGCanvas( fVerticalFrame, 340, 300 );
01001   fFileOnlineContents = new MTGListTree( fFileOnlineCanvas, kHorizontalFrame );
01002   fFileOnlineContents->AddItem( 0, "/" );
01003   fTreeItemCurrent = fFileOnlineContents->GetFirstItem();
01004   fTreeItemGroups = fFileOnlineContents->AddItem( fTreeItemCurrent, "Groups" );
01005   fTreeItemFiles = fFileOnlineContents->AddItem( fTreeItemCurrent, "Offline" );
01006   //
01007   fTreeItemOnline = fFileOnlineContents->AddItem( fTreeItemCurrent, "Online" );
01008   fFileOnlineContents->OpenItem( fTreeItemCurrent );
01009   fFileOnlineContents->Associate( this );
01010   fVerticalFrame->AddFrame( fFileOnlineCanvas, fFrameLayout2 );
01011   //
01012   AddFrame( fVerticalFrame, fFrameLayout2 );
01013   //
01014   fStatusBarLayout = new TGLayoutHints( kLHintsBottom|kLHintsLeft|kLHintsExpandX,
01015                                         0, 0, 2, 0 );
01016   fStatusBar = new TGStatusBar( this, 50, 10, kHorizontalFrame );
01017   AddFrame( fStatusBar, fStatusBarLayout );
01018 }
01019 
01020 void Roody::LayoutMenuBar()
01021 {
01022   fMenuBarLayout1 = new TGLayoutHints( kLHintsNormal|kLHintsExpandX, 0, 0, 0, 10 );
01023   fMenuBarLayout2 = new TGLayoutHints( kLHintsTop|kLHintsLeft , 5, 0, 0, 0 );
01024   fMenuBarLayout3 = new TGLayoutHints( kLHintsTop|kLHintsRight, 0, 5, 0, 0 );
01025   fMenuFile = new TGPopupMenu( fClient->GetRoot() );
01026   //
01027   fMenuFile->AddEntry( "&Open data file...", M_FILE_OPEN );
01028   fMenuFile->AddEntry( "O&pen online...", M_FILE_ONLINE );
01029   fMenuFile->AddSeparator();
01030   fMenuFile->AddEntry( "&Save session",    M_FILE_SAVE_DEFAULT );
01031   fMenuFile->AddEntry( "&Save session as...",    M_FILE_SAVE );
01032   fMenuFile->AddEntry( "&Restore session...", M_FILE_RESTORE );
01033   fMenuFile->AddSeparator();
01034   fMenuFile->AddEntry( "&Exit", M_FILE_EXIT );
01035   //
01036   fMenuRefresh = new TGPopupMenu( fClient->GetRoot() );
01037   fMenuRefresh->AddEntry( "&Off", M_REFRESH_OFF );
01038   fMenuRefresh->AddEntry( "&Refresh now", M_REFRESH_NOW );
01039   fMenuRefresh->AddEntry( "&1 second", M_REFRESH_1SEC );
01040   fMenuRefresh->AddEntry( "&3 seconds", M_REFRESH_3SEC );
01041   fMenuRefresh->AddEntry( "&5 seconds", M_REFRESH_5SEC );
01042   fMenuRefresh->AddEntry( "10 seconds", M_REFRESH_10SEC );
01043   fMenuRefresh->AddEntry( "&Set refresh period...", M_REFRESH_DIALOG );
01044   //
01045   fMenuZones = new TGPopupMenu( fClient->GetRoot() );
01046   fMenuZones->AddEntry( "1x1", M_ZONES_11 );  
01047   fMenuZones->AddEntry( "1x2", M_ZONES_12 );  
01048   fMenuZones->AddEntry( "2x1", M_ZONES_21 );  
01049   fMenuZones->AddEntry( "2x2", M_ZONES_22 ); 
01050   fMenuZones->AddEntry( "3x3", M_ZONES_33 );
01051   fMenuZones->AddEntry( "4x4", M_ZONES_44 );
01052   fMenuZones->AddEntry( "user", M_ZONES_USER );
01053   fMenuZones->AddEntry( "&Set zones...", M_ZONES_DIALOG );
01054   fMenuZones->CheckEntry(M_ZONES_11); // place check mark on the default
01055   //
01056   fMenuPlot = new TGPopupMenu( fClient->GetRoot() );
01057   fMenuPlot->AddEntry( "New canvas", M_PLOT_NEW );
01058   fMenuPlot->AddEntry( "Current pad", M_PLOT_REPLACE );
01059   fMenuPlot->AddEntry( "Overlay on Current pad", M_PLOT_SAME );
01060   fMenuPlot->AddEntry( "Next pad", M_PLOT_NEXT );
01061   SetDestination( D_PLOT_NEW );
01062   //
01063   fMenuClear = new TGPopupMenu( fClient->GetRoot() );
01064   fMenuClear->AddEntry( "&Reset all", M_RESET_ALL );
01065   //
01066   fMenuHelp = new TGPopupMenu( fClient->GetRoot() );
01067   fMenuHelp->AddEntry( "Contents", M_HELP_CONTENTS );
01068   fMenuHelp->AddEntry( "&About", M_HELP_ABOUT );
01069   //
01070   fMenuFile->Associate( this );
01071   fMenuRefresh->Associate( this );
01072   fMenuZones->Associate( this );
01073   fMenuPlot->Associate( this );
01074   fMenuClear->Associate( this );
01075   fMenuHelp->Associate( this );
01076   //
01077   fMenuBar = new TGMenuBar( this, 1, 1, kRaisedFrame );
01078   fMenuBar->AddPopup( "&File", fMenuFile, fMenuBarLayout2 );
01079   fMenuBar->AddPopup( "&Refresh", fMenuRefresh, fMenuBarLayout2 );
01080   fMenuBar->AddPopup( "&Zones", fMenuZones, fMenuBarLayout2 );
01081   fMenuBar->AddPopup( "&Plot in", fMenuPlot, fMenuBarLayout2 );
01082   fMenuBar->AddPopup( "&Reset", fMenuClear, fMenuBarLayout2 );
01083   fMenuBar->AddPopup( "&Help", fMenuHelp, fMenuBarLayout3 );
01084   //
01085   AddFrame( fMenuBar, fMenuBarLayout1 );
01086 }
01087 
01088 void Roody::AddSetCut()
01089 {
01090   TClassMenuItem *menuItem = new TClassMenuItem( TClassMenuItem::kPopupUserFunction,
01091                                                  Roody::Class(),
01092                                                  "Send to Analyzer", "SetCut", this,
01093                                                  "TObject*", 0);
01094   TCutG::Class()->GetMenuList()->AddFirst(menuItem);
01095 }
01096 
01097 void Roody::SetCut( TObject *o )
01098 {
01099   TCutG *cut = static_cast<TCutG*>(o);
01100   
01101   fSock->Send("SetCut");
01102   fSock->Send(cut->GetName());
01103   TMessage m (kMESS_OBJECT);
01104   m<<cut;
01105   fSock->Send(m);
01106 }
01107 
01108 void Roody::AddZoomOption()
01109 {
01110   TClassMenuItem *menuItem = new TClassMenuItem( TClassMenuItem::kPopupUserFunction,
01111                                                  Roody::Class(),
01112                                                  "ZoomOption", "ZoomOption", this, "" );
01113   TH1C::Class()->GetMenuList()->AddFirst(menuItem);
01114   TH1S::Class()->GetMenuList()->AddFirst(menuItem);
01115   TH1I::Class()->GetMenuList()->AddFirst(menuItem);
01116   TH1F::Class()->GetMenuList()->AddFirst(menuItem);
01117   TH1D::Class()->GetMenuList()->AddFirst(menuItem);
01118   TFrame::Class()->GetMenuList()->AddFirst(menuItem);
01119 }
01120 
01121 void Roody::ZoomOption()
01122 {
01123   // do not allow zoom on the zoom canvas
01124   //
01125   if( !gPad || !strcmp(gPad->GetCanvas()->GetName(),"Zoom Canvas") )return;
01126   //
01127   // find all histograms on the current pad, and store them in a vector
01128   //
01129   std::vector<TH1*> histVec;
01130   TIter padNext( gPad->GetListOfPrimitives() );
01131   TObject *padObject;
01132   while( (padObject=static_cast<TObject*>(padNext())) )
01133   {
01134     if( padObject->InheritsFrom(TH1::Class()) )
01135     {
01136       if( ObjectIsOnline(padObject) )
01137         histVec.push_back(static_cast<TH1*>(GetNetFolderObject(padObject->GetName())));
01138       else
01139         histVec.push_back(static_cast<TH1*>(padObject->Clone(padObject->GetName())));
01140     }
01141   }
01142   // make the zoom canvas (which is always 1x1),
01143   // and then draw the stored histograms on the zoom canvas
01144   //
01145   TVirtualPad *padSave = gPad;
01146   //
01147   MakeZoomCanvas();
01148   std::vector<TH1*>::const_iterator end = histVec.end();
01149   for( std::vector<TH1*>::const_iterator i=histVec.begin(); i!=end; ++i )
01150   {
01151     TH1*h = SetCanvasLimits( fZoomCanvas, *i );
01152     h->DrawCopy();
01153   }
01154   gPad = padSave;
01155 }
01156 
01157 void Roody::AddAxisLimits()
01158 {
01159   TClassMenuItem *menuItem = new TClassMenuItem( TClassMenuItem::kPopupUserFunction,
01160                                                  Roody::Class(),
01161                                                  "XaxisLimits", "XaxisLimits", this, "" );
01162   TH1C::Class()->GetMenuList()->AddFirst(menuItem);
01163   TH1S::Class()->GetMenuList()->AddFirst(menuItem);
01164   TH1I::Class()->GetMenuList()->AddFirst(menuItem);
01165   TH1F::Class()->GetMenuList()->AddFirst(menuItem);
01166   TH1D::Class()->GetMenuList()->AddFirst(menuItem);
01167   TFrame::Class()->GetMenuList()->AddFirst(menuItem);
01168   //
01169   menuItem = new TClassMenuItem( TClassMenuItem::kPopupUserFunction,
01170                                  Roody::Class(),
01171                                  "YaxisLimits", "YaxisLimits", this, "" );
01172   TH1C::Class()->GetMenuList()->AddFirst(menuItem);
01173   TH1S::Class()->GetMenuList()->AddFirst(menuItem);
01174   TH1I::Class()->GetMenuList()->AddFirst(menuItem);
01175   TH1F::Class()->GetMenuList()->AddFirst(menuItem);
01176   TH1D::Class()->GetMenuList()->AddFirst(menuItem);
01177   TFrame::Class()->GetMenuList()->AddFirst(menuItem);
01178 }
01179 
01180 void Roody::XaxisLimits()
01181 {
01182   CanvasLimits *limits = FindCanvasLimits(gPad->GetCanvas()->GetCanvasID());
01183   new TAxisLimitsDialog( gClient->GetRoot(), NULL, 250, 100, limits, this);
01184 }
01185 
01186 void Roody::YaxisLimits()
01187 {
01188   CanvasLimits *limits = FindCanvasLimits(gPad->GetCanvas()->GetCanvasID());
01189   new TAxisLimitsDialog( gClient->GetRoot(), NULL, 250, 100, limits, this);
01190 }
01191 
01192 void Roody::RedrawPad( TPad *pad )
01193 {
01194   TIter padNext( pad->GetListOfPrimitives() );
01195   TObject *padObject;
01196   std::vector<TH1*> histVec;
01197   while( (padObject=static_cast<TObject*>(padNext())) )
01198   {
01199     if( padObject->InheritsFrom(TH1::Class()) )
01200     {
01201       TH1 *hist = static_cast<TH1*>(padObject);
01202       Color_t color = hist->GetLineColor();
01203       TObjString name( hist->GetName() );
01204       if( ObjectIsOnline(padObject) )
01205       {
01206         TObject *netObject = GetNetFolderObject( name.GetString().Data() );
01207         if( netObject )
01208         {
01209           pad->GetListOfPrimitives()->Remove(hist);
01210           delete hist;
01211           hist = static_cast<TH1*>(netObject);
01212           hist->SetLineColor( color );
01213           MarkObjectAsOnline(hist);
01214           histVec.push_back( hist );
01215         }
01216       }
01217       else
01218       {
01219         TH1 *h = static_cast<TH1*>(hist->Clone(hist->GetName()));
01220         h->SetLineColor( color );
01221         histVec.push_back( h );
01222       }
01223     }
01224   }
01225   pad->Clear();
01226   if( !histVec.empty() )
01227   {
01228     TH1* h = SetCanvasLimits( pad->GetCanvas(), histVec[0] );
01229     h->Draw();
01230     std::vector<TH1*>::const_iterator end = histVec.end();
01231     for( std::vector<TH1*>::const_iterator i=histVec.begin()+1; i!=end; ++i )
01232     {
01233       h = SetCanvasLimits( pad->GetCanvas(), *i );
01234       h->Draw("SAME");
01235     }
01236   }
01237   pad->GetCanvas()->Modified();
01238   pad->GetCanvas()->Update();
01239 }
01240 
01241 void Roody::RedrawCanvas()
01242 {
01243   TIter canvasNext( gPad->GetCanvas()->GetListOfPrimitives() );
01244   TObject *canvasObject;
01245   while( (canvasObject=static_cast<TObject*>(canvasNext())) )
01246   {
01247     if( canvasObject->InheritsFrom(TPad::Class()) )
01248       RedrawPad( static_cast<TPad*>(canvasObject) );
01249     else
01250     {
01251       RedrawPad( static_cast<TPad*>(gPad) );
01252       break;
01253     }
01254   }
01255   gPad->GetCanvas()->Modified();
01256   gPad->GetCanvas()->Update();
01257 }
01258 
01259 bool Roody::ObjectIsOnline( TObject *obj )
01260 {
01261   if( !obj->InheritsFrom(TH1::Class()) )
01262   {
01263     std::cerr << "Roody::ObjectIsOnline: Object " << (void*)obj << " \"" << obj->GetName()
01264               << "\" is a \"" << obj->ClassName() << "\", not a TH1, aborting!" << std::endl;
01265     abort();
01266   }
01267   TH1 *hist = static_cast<TH1*>(obj);
01268   TIter funcNext( hist->GetListOfFunctions() );
01269   TObject *func;
01270   while( (func=static_cast<TObject*>(funcNext())) )
01271   {
01272     if( func->InheritsFrom(TObjString::Class()) )
01273     {
01274       TObjString *str = static_cast<TObjString*>(func);
01275       if( !strcmp("ONLINE",str->GetString().Data()) )return true;
01276     }
01277   }
01278   return false;
01279 }
01280 
01281 void Roody::MarkObjectAsOnline( TObject *obj )
01282 {
01283   if( !ObjectIsOnline(obj) ) // we check that obj is a TH1 in ObjectIsOnline()
01284     static_cast<TH1*>(obj)->GetListOfFunctions()->Add( new TObjString("ONLINE") );
01285 }
01286 
01287 CanvasLimits* Roody::FindCanvasLimits(Int_t canvasId)
01288 {
01289   std::vector<CanvasLimits*>::const_iterator end = fCanvasLimitsVector.end();
01290   for( std::vector<CanvasLimits*>::const_iterator i=fCanvasLimitsVector.begin(); i!=end; ++i )
01291     if( (*i)->fCanvasId == canvasId )
01292       return (*i);
01293   return NULL;
01294 }
01295 
01296 TH1* Roody::SetCanvasLimits( TCanvas *canvas, TH1 *h )
01297 {
01298   CanvasLimits* limits = FindCanvasLimits(canvas->GetCanvasID());
01299   if (limits)
01300     return limits->ApplyLimits(h);
01301   else
01302     return h;
01303 }
01304 
01305 TH1* GetOriginal(TH1*orig,const char*name)
01306 {
01307   char buf[256];
01308   strcpy(buf,name);
01309   char*s = strstr(buf,"_rebin");
01310   if (s)
01311     *s = 0;
01312   //printf("rebinned [%s] original [%s]\n",name,buf);
01313   TH1*xxx = (TH1*)gROOT->FindObject(buf);
01314   if (!xxx)
01315     return orig;
01316   else
01317     return xxx;
01318 }
01319   
01320 TH1* CanvasLimits::ApplyLimits(TH1 *h)
01321 {
01322   const char* name = h->GetName();
01323 
01324   if (fRebin > 1)
01325     {
01326       char rebinx[256];
01327       sprintf(rebinx,"_rebin%d_",fRebin);
01328 
01329       if (strstr(name,rebinx)!=NULL)
01330         {
01331           //printf("histogram %s is already rebinned %s (%d)\n",name,rebinx,fRebin);
01332         }
01333       else
01334         {
01335           h = GetOriginal(h,name);
01336           name = h->GetName();
01337           char buf[256];
01338           sprintf(buf,"%s%s",name,rebinx);
01339           h = h->Rebin(fRebin,buf);
01340         }
01341     }
01342   else
01343     {
01344       if (strstr(name,"_rebin")!=NULL)
01345         {
01346           h = GetOriginal(h,name);
01347         }
01348     }
01349 
01350   if (fDoZoomXaxis)
01351     {
01352       h->GetXaxis()->SetRangeUser(fXmin, fXmax);
01353     }
01354   
01355   if (fDoZoomYaxis)
01356     {
01357       h->SetMinimum(fYmin);
01358       h->SetMaximum(fYmax);
01359     }
01360   
01361   if (fForceUnzoomX)
01362     h->GetXaxis()->UnZoom();
01363   
01364   if (fForceUnzoomY)
01365     h->GetYaxis()->UnZoom();
01366   
01367   return h;
01368 }
01369 
01370 void Roody::AddPeakFind()
01371 {
01372   TClassMenuItem *menuItem = new TClassMenuItem( TClassMenuItem::kPopupUserFunction,
01373                                                  Roody::Class(),
01374                                                  "PeakFind", "PeakFind", this, "" );
01375   TH1C::Class()->GetMenuList()->AddFirst(menuItem);
01376   TH1S::Class()->GetMenuList()->AddFirst(menuItem);
01377   TH1I::Class()->GetMenuList()->AddFirst(menuItem);
01378   TH1F::Class()->GetMenuList()->AddFirst(menuItem);
01379   TH1D::Class()->GetMenuList()->AddFirst(menuItem);
01380   TFrame::Class()->GetMenuList()->AddFirst(menuItem);
01381 }
01382 
01383 void Roody::SetDestination( EDrawDestination dest )
01384 {
01385   if( fDrawDestination )fMenuPlot->UnCheckEntry( fDrawDestination );
01386   fDrawDestination = dest;
01387   fMenuPlot->CheckEntry( fDrawDestination );
01388 }
01389 
01390 void Roody::SetPad()
01391 {
01392   //std::cout << "SetPad: canvasname=\"" << gPad->GetCanvas()->GetName() << "\"\n";
01393   int currentNumber = gPad->GetNumber();
01394   //std::cout << "SetPad 1: currentNumber=\"" << currentNumber << "\"\n";
01395   // if currentNumber is 0 do nothing, no zones in this canvas
01396   if( currentNumber > 0 ) // select next pad
01397   {
01398     gPad->GetCanvas()->cd( currentNumber+1 );
01399     //std::cout << "SetPad 2: number=\"" << gPad->GetNumber() << "\"\n";
01400     // if there is no next pad, go back to pad 1
01401     if( gPad->GetNumber() == currentNumber )gPad->GetCanvas()->cd(1);
01402     //std::cout << "SetPad 3: number=\"" << gPad->GetNumber() << "\"\n";
01403   }
01404 }
01405 
01406 std::string Roody::GetZoneSetting()
01407 {
01408   std::stringstream str;
01409   str << fZoneColumns << "x" << fZoneRows;
01410   return str.str();
01411 }
01412 
01413 TH1 *Roody::GetHist( TPad *pad, TObject *object )
01414 {
01415   if( ObjectIsOnline(object) )
01416   {
01417     TObject *netObject = GetNetFolderObject(object->GetName());
01418     if( netObject )
01419     {
01420       pad->GetListOfPrimitives()->Remove(object);
01421       delete object;
01422       MarkObjectAsOnline(netObject);
01423       return static_cast<TH1*>(netObject);
01424     }
01425     else
01426       return static_cast<TH1*>(object);
01427   }
01428   else
01429     return static_cast<TH1*>(object->Clone(object->GetName()));
01430 }
01431 
01432 void Roody::SetupZones( int columns, int rows )
01433 {
01434   // set up the pads on the canvas
01435   // if the canvas already has things drawn on it,
01436   // redraw them in the new pads
01437   //
01438   fZoneColumns = columns;
01439   fZoneRows = rows;
01440   bool newCanvas = false;
01441   if( !gPad || std::string(gPad->GetCanvas()->GetName()).find("canvas")!=0 )
01442   {
01443     MakeNewCanvas();
01444     newCanvas = true;
01445   }
01446   else
01447   {
01448     fZoneSetting[gPad->GetCanvas()->GetName()] = GetZoneSetting();
01449     fZoneColumns*fZoneRows==1 ? SetDestination(D_PLOT_REPLACE) : SetDestination(D_PLOT_NEXT);
01450   }
01451   // get the stuff that is currently drawn on the canvas
01452   //
01453   std::vector<HistPad*> histPadVec;
01454   TIter canvasNext( gPad->GetCanvas()->GetListOfPrimitives() );
01455   TObject *canvasObject;
01456   while( (canvasObject=static_cast<TObject*>(canvasNext())) )
01457   {
01458     if( canvasObject->InheritsFrom(TH1::Class()) ) // take care of no sub-pad case
01459     {
01460       HistPad *hp = new HistPad;
01461       hp->padNumber = 0;
01462       hp->hist = GetHist( static_cast<TPad*>(gPad), canvasObject );
01463       histPadVec.push_back( hp );
01464     }
01465     else if( canvasObject->InheritsFrom(TPad::Class()) )
01466     {
01467       TPad *pad = static_cast<TPad*>(canvasObject);
01468       TIter padNext( pad->GetListOfPrimitives() );
01469       TObject *padObject;
01470       while( (padObject=static_cast<TObject*>(padNext())) )
01471       {
01472         if( padObject->InheritsFrom(TH1::Class()) )
01473         {
01474           HistPad *hp = new HistPad;
01475           hp->padNumber = pad->GetNumber();
01476           hp->hist = GetHist( pad, padObject );
01477           histPadVec.push_back( hp );
01478         }
01479       }
01480     }
01481   }
01482   if( !newCanvas )
01483   {
01484     gPad->GetCanvas()->cd(); // gPad should now be the parent canvas
01485     gPad->Clear();
01486     if( columns*rows != 1 )
01487     {
01488       gPad->Divide( columns, rows );
01489       gPad->cd( columns*rows ); // set to last pad so next plot will go into pad 1
01490     }
01491     gPad->GetCanvas()->Modified();
01492     gPad->GetCanvas()->Update();
01493   }
01494   /*
01495   map <std::string, string> :: iterator pIter;
01496   std::cout  << "The keys of the mapped elements are:";
01497   for( pIter = fZoneSetting.begin( ); pIter != fZoneSetting.end( ); ++pIter )
01498     std::cout << " " << pIter -> first;
01499   std::cout << ".\n";
01500   
01501   std::cout << "The values of the mapped elements are:";
01502   for( pIter = fZoneSetting.begin( ); pIter != fZoneSetting.end( ); ++pIter )
01503     std::cout << " " << pIter -> second;
01504   std::cout << ".\n";   
01505   */
01506   if( histPadVec.empty() )
01507   {
01508     gPad->GetCanvas()->cd( columns*rows ); // set to last pad so next plot will go into pad 1
01509   }
01510   else // redraw the previously drawn objects on the new canvas
01511   {
01512     Int_t histPadNumber = -1;
01513     Int_t padNumber = 0;
01514     std::vector<HistPad*>::const_iterator end = histPadVec.end();
01515     for( std::vector<HistPad*>::const_iterator i=histPadVec.begin(); i!=end; ++i )
01516     {
01517       TH1*h = SetCanvasLimits( gPad->GetCanvas(), (*i)->hist );
01518       if( (*i)->padNumber != histPadNumber )
01519       {
01520         if( ++padNumber > columns*rows )break;
01521         gPad->GetCanvas()->cd( padNumber );
01522         h->Draw();
01523         histPadNumber = (*i)->padNumber;
01524       }
01525       else h->Draw("SAME");
01526       delete *i;
01527     }
01528     gPad->GetCanvas()->Modified();
01529     gPad->GetCanvas()->Update();
01530   }
01531 }
01532 
01533 void Roody::SelectPad( Int_t ev, Int_t x, Int_t y, TObject* obj )
01534 {
01535   // Makes the pad active for all mousebutton clicks
01536   if( ev==kButton1Down || ev==kButton3Down )
01537     gPad->GetCanvas()->HandleInput( kButton2Down, x, y );
01538 }
01539 
01540 void Roody::CleanupCurrentCanvas()
01541 {
01542   gPad->GetCanvas()->cd();
01543   TIter canvasNext( gPad->GetListOfPrimitives() );
01544   TObject *canvasObject;
01545   while( (canvasObject=static_cast<TObject*>(canvasNext())) )
01546   {
01547     if( canvasObject->InheritsFrom(TH1::Class()) )
01548     {
01549       TH1 *h1 = static_cast<TH1*>(canvasObject);
01550       TList *functions = h1->GetListOfFunctions();
01551       TIter histNext( functions );
01552       TObject *histObject = 0;
01553       while( (histObject=static_cast<TObject*>(histNext())) )delete histObject;
01554       functions->Clear();
01555       delete h1;
01556     }
01557   }
01558 }
01559 
01560 void Roody::DrawObject( TObject *obj )
01561 {
01562 
01563   //if( !gPad )std::cout << "DrawObject: gPad = 0\n";
01564   if( !gPad || fDrawDestination==D_PLOT_NEW ||
01565       std::string(gPad->GetCanvas()->GetName()).find("canvas")!=0 )MakeNewCanvas();
01566   //std::cout << "DrawObject: fDrawDestination=\"" << fDrawDestination << "\"\n";
01567   if( fDrawDestination == D_PLOT_NEXT )SetPad();
01568   if( obj->InheritsFrom(TH3::Class()) )
01569   {
01570     TH3 *h = static_cast<TH3*>(obj);
01571     if( fDrawDestination == D_PLOT_REPLACE )CleanupCurrentCanvas();
01572     h->Draw();
01573   }
01574   else if( obj->InheritsFrom(TH2::Class()) )
01575   {
01576     TH2 *h = static_cast<TH2*>(obj);
01577     if( fDrawDestination == D_PLOT_REPLACE )CleanupCurrentCanvas();
01578     h->Draw();
01579     //h->ProjectionX("_px",-1,-1,"d");
01580     //h->ProjectionY("_py",-1,-1,"d");
01581   }
01582   else if( obj->InheritsFrom(TH1::Class()) )
01583   {
01584     TH1 *h = static_cast<TH1*>(obj);
01585     h = SetCanvasLimits( gPad->GetCanvas(), h );
01586     if( fDrawDestination == D_PLOT_SAME )
01587     {
01588       TIter padNext( gPad->GetListOfPrimitives() );
01589       TObject *padObject;
01590       Color_t color = 0;
01591       while( (padObject=static_cast<TObject*>(padNext())) )
01592       {
01593         if( padObject->InheritsFrom(TH1::Class()) )
01594           color = static_cast<TH1*>(padObject)->GetLineColor();
01595       }
01596       h->SetLineColor( ++color );
01597       h->Draw("SAME");
01598     }
01599     else
01600     {
01601       if( fDrawDestination == D_PLOT_REPLACE )CleanupCurrentCanvas();
01602       h->Draw();
01603     }
01604   }
01605   else if( obj->InheritsFrom(TCutG::Class()) )
01606   {
01607     TCutG *c = static_cast<TCutG*>(obj);
01608     c->Draw();
01609   }
01610   else
01611   {
01612     std::string s("DrawObject: unsure how to Draw object ");
01613     s += obj->GetName() + std::string(" of type ") + obj->ClassName();
01614     new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
01615     fDrawDestination==D_PLOT_SAME ? obj->Draw("SAME") : obj->Draw();
01616   }
01617   gPad->Modified();
01618   gPad->Update();
01619 }
01620 
01621 void Roody::PeakFind()
01622 {
01623   if( fgPeakFindPanel )
01624     fgPeakFindPanel->MapRaised();
01625   else
01626     fgPeakFindPanel = new TPeakFindPanel(gClient->GetRoot(),0,250,220);
01627 }
01628 
01629 void Roody::PopupPlot( int x, int y, bool isFolder )
01630 {
01631   if( fPopupMenu )delete fPopupMenu;
01632   //
01633   bool online = false;
01634   ItemVec::const_iterator end = fTreeItems.end();
01635   for( ItemVec::const_iterator i=fTreeItems.begin(); i!=end; ++i )
01636   {
01637     TObject *object = static_cast<TObject*>((*i)->GetUserData());
01638     if( object && object->InheritsFrom(TObjString::Class()) )
01639     {
01640       online = true;
01641       break;
01642     }
01643   }
01644   //
01645   fPopupMenu = new TGPopupMenu( gClient->GetRoot() );
01646   fPopupMenu->AddEntry( "New canvas",  C_PLOT_NEW );
01647   if( !isFolder && fTreeItems.size()==1 )
01648   {
01649     fPopupMenu->AddEntry( "Current pad", C_PLOT_REPLACE );
01650     fPopupMenu->AddEntry( "Overlay on Current pad", C_PLOT_SAME );
01651     fPopupMenu->AddEntry( "Next pad",    C_PLOT_NEXT );
01652   }
01653   fPopupMenu->AddSeparator( static_cast<TGMenuEntry*>(0) );
01654   fPopupMenu->AddEntry( "Add to group", C_ADD_TO_GROUP );
01655   if( online )
01656   {
01657     fPopupMenu->AddSeparator( static_cast<TGMenuEntry*>(0) );
01658     fPopupMenu->AddEntry( "Reset", C_RESET_OBJECT );
01659   }
01660   fPopupMenu->PlaceMenu( x, y, false, true );
01661   fXSave = x;
01662   fYSave = y;
01663   fPopupMenu->Associate( this );
01664 }
01665 
01666 void Roody::PopupOnlineMenu( int x, int y )
01667 {
01668   if( fPopupMenu )delete fPopupMenu;
01669   fPopupMenu = new TGPopupMenu( gClient->GetRoot() );
01670   fPopupMenu->AddEntry( "Disconnect online", C_CLOSE_ONLINE );
01671   fPopupMenu->PlaceMenu( x, y, false, true );
01672   fPopupMenu->Associate( this );
01673 }
01674 
01675 void Roody::PopupFileMenu( int x, int y )
01676 {
01677   if( fPopupMenu )delete fPopupMenu;
01678   fPopupMenu = new TGPopupMenu( gClient->GetRoot() );
01679   fPopupMenu->AddEntry( "Close file", C_CLOSE_FILE );
01680   fPopupMenu->PlaceMenu( x, y, false, true );
01681   fPopupMenu->Associate( this );
01682 }
01683 
01684 void Roody::PopupNewGroup( int x, int y )
01685 {
01686   if( fPopupMenu )delete fPopupMenu;
01687   fPopupMenu = new TGPopupMenu( gClient->GetRoot() );
01688   fPopupMenu->AddEntry( "Make new group", C_NEW_GROUP );
01689   fPopupMenu->PlaceMenu( x, y, false, true );
01690   fPopupMenu->Associate( this );
01691 }
01692 
01693 void Roody::PopupGroup( int x, int y )
01694 {
01695   if( fPopupMenu )delete fPopupMenu;
01696   fPopupMenu = new TGPopupMenu( gClient->GetRoot() );
01697   fPopupMenu->AddEntry( "Draw group", C_DRAW_GROUP );
01698   fPopupMenu->AddEntry( "Reset group", C_RESET_GROUP );
01699   fPopupMenu->AddEntry( "Delete group", C_DELETE_GROUP );
01700   fPopupMenu->PlaceMenu( x, y, false, true );
01701   fPopupMenu->Associate( this );
01702 }
01703 
01704 void Roody::AddNewGroup()
01705 {
01706   TObjString *objString = new TObjString();
01707   new TGTextDialog( gClient->GetRoot(), this, 100, 100, "Group name: ", "", objString );
01708   if( objString )
01709   {
01710     TString newGroupName( objString->GetString() );
01711     if( newGroupName.Length()>0 && !newGroupName.Contains("-1") )MakeNewGroup( newGroupName.Data() );
01712     delete objString;
01713   }
01714 }
01715 
01716 bool Roody::MakeNewGroup( char const *name )
01717 {
01718   if( fFileOnlineContents->FindChildByName(fTreeItemGroups,name) )
01719   {
01720     std::string s("Error in making new group: \"");
01721     s += std::string(name) + "\" already exists";
01722     new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
01723     return false;
01724   }
01725   TGListTreeItem *groupFolder = fFileOnlineContents->AddItem( fTreeItemGroups, name );
01726   fGroupFolders.push_back( groupFolder ); // fGroupFolders is a vector of TGListTreeItem*
01727   fFileOnlineContents->Resize();
01728   Layout();
01729   fParentDir->cd();
01730   return true;
01731 }
01732 
01733 void Roody::PopupAddToGroup()
01734 {
01735   if( fGroupFolders.empty() )
01736   {
01737     std::string s("There are no groups");
01738     new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
01739     return;
01740   }
01741   if( fGroupFolders.size() == 1 )
01742   {
01743     // if there is only one group, no need to bring up the context menu listing
01744     // the groups, so just add the items to the group
01745     //
01746     std::size_t nEntries = fTreeItems.size();
01747     for( std::size_t i=0; i<nEntries; ++i )
01748     {
01749       fTreeItemCurrent = fTreeItems[i];
01750       if( fTreeItemCurrent )
01751       {
01752         TObject *object = static_cast<TObject*>(fTreeItemCurrent->GetUserData());
01753         if( object )
01754         {
01755           std::auto_ptr<TString> className( new TString(object->ClassName()) );
01756           if( className->Contains("TH1") || className->Contains("TH2") ||
01757               className->Contains("TH3") )
01758           {
01759             TGListTreeItem *temp = fTreeItemCurrent;
01760             while( strcmp(temp->GetParent()->GetText(),"Offline") )temp = temp->GetParent();
01761             AddHistogramToGroup( 0, object, temp->GetText() );
01762           }
01763           else if( className->Contains("TObjString") )
01764           {
01765             AddHistogramToGroup( 0, object, "online" );
01766           }
01767         }
01768       }
01769     }
01770     return;
01771   }
01772   if( fAddToGroupPopup )delete fAddToGroupPopup;
01773   fAddToGroupPopup = new TGPopupMenu( gClient->GetRoot() );
01774   ItemVec::const_iterator end = fGroupFolders.end();
01775   int id = 99;
01776   for( ItemVec::const_iterator i=fGroupFolders.begin(); i!=end; ++i )
01777     fAddToGroupPopup->AddEntry( (*i)->GetText(), ++id );
01778   fAddToGroupPopup->PlaceMenu( fXSave, fYSave, false, true );
01779   fAddToGroupPopup->Associate( this );
01780 }
01781 
01782 void Roody::DeleteGroup()
01783 {
01784   // deletes group item pointed to by fTreeItemCurrent
01785   //
01786   // possibly add confirmation before delete
01787   //
01788   int id = 0;
01789   ItemVec::iterator end = fGroupFolders.end();
01790   for( ItemVec::iterator i=fGroupFolders.begin(); i!=end; ++i, ++id )
01791   {
01792     if( fTreeItemCurrent == *i )
01793     {
01794       std::size_t end = fGroupFolders.size();
01795       fGroupFolders.erase(i);
01796       std::pair<GroupMap::iterator,GroupMap::iterator> p = fGroupHists.equal_range( id );
01797       fGroupHists.erase( p.first, p.second );
01798       for( std::size_t j=id+1; j<end; ++j )
01799       {
01800         p = fGroupHists.equal_range( j );
01801         for( GroupMap::iterator k=p.first; k!=p.second; ++k )
01802         {
01803           GroupItem item = k->second;
01804           fGroupHists.erase( k );
01805           fGroupHists.insert( value_type(j-1,item) );
01806         }
01807       }
01808       break;
01809     }
01810   }
01811   fFileOnlineContents->MDeleteItem( fTreeItemCurrent );
01812   fFileOnlineContents->Resize();
01813 }
01814 
01815 void Roody::MakeNewCanvas()
01816 {
01817   std::stringstream ss;
01818   ss << "canvas" << fCanvasCount++;
01819   std::string name( ss.str() );
01820   fCurrentCanvas = new TCanvas( name.c_str(), name.c_str() );
01821   //
01822   fCanvasLimitsVector.push_back(new CanvasLimits(fCurrentCanvas->GetCanvasID()));
01823   //
01824   fZoneSetting[name] = GetZoneSetting();
01825   //std::cout << "columns=" << fZoneColumns << ", rows=" << fZoneRows << "\n";
01826   fZoneColumns*fZoneRows==1 ? SetDestination(D_PLOT_REPLACE) : SetDestination(D_PLOT_NEXT);
01827   //
01828   fCurrentCanvas->cd();  // at this point, gPad should be set to the new canvas
01829   //
01830   fCurrentCanvas->Clear();
01831   if( fZoneColumns*fZoneRows != 1 )
01832   {
01833     fCurrentCanvas->Divide( fZoneColumns, fZoneRows );
01834     // gPad set to last pad so next plot will go into pad 1
01835     fCurrentCanvas->cd( fZoneColumns*fZoneRows );
01836   }
01837   fCurrentCanvas->Modified();
01838   fCurrentCanvas->Update();
01839   //
01840   fCurrentCanvas->Connect( "ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", "Roody",
01841                            this, "SelectPad(Int_t,Int_t,Int_t,TObject*)" );
01842 }
01843 
01844 TCanvas* Roody::MakeGroupCanvas( char const *title, int columns, int rows )
01845 {
01846   TCanvas *canvas = new TCanvas( title, title );
01847   //
01848   fCanvasLimitsVector.push_back(new CanvasLimits(canvas->GetCanvasID()));
01849   //
01850   canvas->Clear();
01851   if( columns*rows != 1 )
01852   {
01853     canvas->Divide( columns, rows );
01854     canvas->cd( columns*rows ); // set to last pad so next plot will go into pad 1
01855   }
01856   std::stringstream str;
01857   str << columns << "x" << rows;
01858   fZoneSetting[std::string(title)] = str.str();
01859   //
01860   canvas->Modified();
01861   canvas->Update();
01862   //
01863   canvas->Connect( "ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", "Roody",
01864                    this, "SelectPad(Int_t,Int_t,Int_t,TObject*)" );
01865   return canvas;
01866 }
01867 
01868 void Roody::MakeZoomCanvas()
01869 {
01870   if( fZoomCanvas )delete fZoomCanvas;
01871   fZoomCanvas = new TCanvas( "Zoom Canvas", "Zoom Canvas" );
01872   //
01873   fCanvasLimitsVector.push_back(new CanvasLimits(fZoomCanvas->GetCanvasID()));
01874   //
01875   fZoomCanvas->cd();  // gPad should now be set to fZoomCanvas
01876   fZoomCanvas->Clear();
01877   fZoomCanvas->Modified();
01878   fZoomCanvas->Update();
01879   //
01880   fZoomCanvas->Connect( "ProcessedEvent(Int_t,Int_t,Int_t,TObject*)", "Roody",
01881                         this, "SelectPad(Int_t,Int_t,Int_t,TObject*)" );
01882 }
01883 
01884 void Roody::DrawItemsOnNewCanvas()
01885 {
01886   std::size_t nItems = fTreeItems.size();
01887   std::size_t columns, rows;
01888   columns = static_cast<std::size_t>(sqrt(static_cast<double>(nItems)));
01889   rows = nItems/columns;
01890   while( rows*columns < nItems )++rows;
01891   //
01892   fZoneColumns = columns;
01893   fZoneRows = rows;
01894   MakeNewCanvas();
01895   int padNumber = 0;
01896   //
01897   ItemVec::const_iterator end = fTreeItems.end();
01898   for( ItemVec::const_iterator i=fTreeItems.begin(); i!=end; ++i )
01899   {
01900     TGListTreeItem *item = *i;
01901     if( !item )continue;
01902     gPad->GetCanvas()->cd( ++padNumber );
01903     TObject *object = static_cast<TObject*>(item->GetUserData());
01904     if( object && object->InheritsFrom(TH1::Class()) )
01905     {
01906       TH1 *tmp = static_cast<TH1*>(object);
01907       TH1 *th1 = static_cast<TH1*>( tmp->Clone(tmp->GetName()) );
01908       th1 = SetCanvasLimits( gPad->GetCanvas(), th1 );
01909       th1->Draw();
01910     }
01911     else if( object && object->InheritsFrom(TObjString::Class()) )
01912     {
01913       if( !fSock )
01914       {
01915         std::string s("no online connection, so online items cannot be drawn");
01916         new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
01917         continue;
01918       }
01919       TObject *tmp = GetNetFolderObject( (static_cast<TObjString*>(object))->GetString().Data() );
01920       if( tmp && tmp->InheritsFrom(TH1::Class()) )
01921       {
01922         TH1 *th1 = static_cast<TH1*>(tmp);
01923         MarkObjectAsOnline(th1);
01924         th1 = SetCanvasLimits( gPad->GetCanvas(), th1 );
01925         th1->Draw();
01926       }
01927     }
01928     gPad->Modified();
01929     gPad->Update();
01930   }
01931 }
01932 
01933 void Roody::DrawGroup()
01934 {
01935   fTreeItemCurrent = fFileOnlineContents->GetSelected();
01936   int id = -1;
01937   std::size_t end = fGroupFolders.size();
01938   for( std::size_t i=0; i<end; ++i )
01939   {
01940     if( fTreeItemCurrent == fGroupFolders[i] )
01941     {
01942       id = static_cast<int>(i);
01943       break;
01944     }
01945   }
01946   if( id == -1 )
01947   {
01948     new TGMsgBox( gClient->GetRoot(), this, "Error", "unable to find group",
01949                   kMBIconExclamation, 0, NULL );
01950     return;
01951   }
01952   int numHists = fGroupHists.count( id );
01953   if( numHists < 1 )
01954   {
01955     new TGMsgBox( gClient->GetRoot(), this, "Error", "group is empty",
01956                   kMBIconExclamation, 0, NULL );
01957     return;
01958   }
01959   int columns, rows;
01960   columns = static_cast<int>(sqrt(static_cast<double>(numHists)));
01961   rows = numHists/columns;
01962   while( rows*columns < numHists )++rows;
01963   //
01964   TVirtualPad *padSave = gPad;
01965   //std::cout << "DrawGroup: ";
01966   //if( gPad )std::cout << "gPad name=\"" << gPad->GetCanvas()->GetName() << "\"\n";
01967   //else      std::cout << "gPad = 0\n";
01968   //
01969   std::string title( "Group canvas: " );
01970   title += std::string( fTreeItemCurrent->GetText() );
01971   TCanvas *canvas = MakeGroupCanvas( title.c_str(), columns, rows );
01972   int padNumber = 0;
01973   //
01974   std::pair<GroupMap::iterator,GroupMap::iterator> p = fGroupHists.equal_range( id );
01975   for( GroupMap::iterator i=p.first; i!=p.second; ++i )
01976   {
01977     canvas->cd( ++padNumber );
01978     TGListTreeItem *item = i->second.item;
01979     TObject *object = static_cast<TObject*>(item->GetUserData());
01980     std::auto_ptr<TString> className( new TString(object->ClassName()) );
01981     if( className->Contains("TH1") )
01982     {
01983       TH1 *tmp = static_cast<TH1*>(object);
01984       TH1 *th1 = static_cast<TH1*>( tmp->Clone(tmp->GetName()) );
01985       th1 = SetCanvasLimits( canvas, th1 );
01986       th1->Draw();
01987     }
01988     else if( className->Contains("TH2") )
01989     {
01990       TH2 *tmp = static_cast<TH2*>(object);
01991       TH2 *th2 = static_cast<TH2*>( tmp->Clone(tmp->GetName()) );
01992       th2->Draw();
01993     }
01994     else if( className->Contains("TH3") )
01995     {
01996       TH3 *tmp = static_cast<TH3*>(object);
01997       TH3 *th3 = static_cast<TH3*>( tmp->Clone(tmp->GetName()) );
01998       th3->Draw();
01999     }
02000     else if( className->Contains("TObjString") )
02001     {
02002       if( !fSock )
02003       {
02004         new TGMsgBox( gClient->GetRoot(), this,
02005                       "Error", "no online connection, so online group items cannot be drawn",
02006                       kMBIconExclamation, 0, NULL );
02007         continue;
02008       }
02009       TObjString *oName = new TObjString( (static_cast<TObjString*>(object))->GetString().Data() );
02010       TObject *tmp = GetNetFolderObject( oName->GetString().Data() );
02011       if( tmp && tmp->InheritsFrom(TH1::Class()) )
02012       {
02013         TH1 *h = static_cast<TH1*>(tmp);
02014         h = SetCanvasLimits( canvas, h );
02015         h->Draw();
02016         MarkObjectAsOnline(h);
02017       }
02018     }
02019     gPad->Modified();
02020     gPad->Update();
02021   }
02022   gPad = padSave;
02023 }
02024 
02025 void Roody::SetRefreshRate( int newrefresh )
02026 {
02027   fUpdateTimerSec = newrefresh;
02028   StartOnlineTimer();
02029   fSock ? fRefreshButton->SetEnabled(kTRUE) : fRefreshButton->SetEnabled(kFALSE);
02030   if( fUpdateTimerSec > 0 )
02031   {
02032     std::stringstream str;
02033     str << "  Pause Refresh (" << fUpdateTimerSec << ")  ";
02034     fRefreshButton->SetText( str.str().c_str() );
02035     fRefreshButton->SetToolTipText( "click to PAUSE refresh of online histograms", 250 );
02036   }
02037   else
02038   {
02039     fRefreshButton->SetText( "     Refresh NOW      " );
02040     fRefreshButton->SetToolTipText( "click to refresh online histograms once right now", 250 );
02041   }
02042 }
02043 
02044 void Roody::UncheckAllZones()
02045 {
02046   fMenuZones->UnCheckEntry(M_ZONES_11);
02047   fMenuZones->UnCheckEntry(M_ZONES_12);
02048   fMenuZones->UnCheckEntry(M_ZONES_21);
02049   fMenuZones->UnCheckEntry(M_ZONES_22);
02050   fMenuZones->UnCheckEntry(M_ZONES_33);
02051   fMenuZones->UnCheckEntry(M_ZONES_44);
02052   fMenuZones->UnCheckEntry(M_ZONES_USER);
02053 }
02054 
02055 Bool_t Roody::ProcessMessage( Long_t msg, Long_t parm1, Long_t parm2 )
02056 {
02057   // ProcessMessage overrides the virtual function in TGCompositeFrame
02058   // (which is the base class for TGMainFrame)
02059   //
02060   // to see the predefined message types look at 
02061   // $ROOTSYS/include/WidgetMessageTypes.h
02062   //
02063   switch (GET_MSG(msg))
02064   {
02065     case kC_LISTTREE: // an event in TreeView
02066     {
02067       switch (GET_SUBMSG(msg))
02068       {
02069         case kCT_ITEMCLICK:  // single mouse click
02070         {
02071           switch (parm1)
02072           {
02073             case kButton1: // left mouse button click
02074             {
02075               //fFileOnlineContents->GetSelectedItems( fTreeItems );
02076               break;
02077             }
02078             case kButton2:
02079             {
02080               break;
02081             }
02082             case kButton3: // right mouse button click
02083             {
02084               // see http://root.cern.ch/root/htmldoc/TGListTree.html#TGListTree:description
02085               int x = parm2&0xFFFF;
02086               int y = (parm2&0xFFFF0000)>>16;
02087               //
02088               fFileOnlineContents->GetSelectedItems( fTreeItems );
02089               std::size_t nEntries = fTreeItems.size();
02090               if( nEntries == 0 )break;
02091               fTreeItemCurrent = fTreeItems[0];
02092               //
02093               TObject *object = static_cast<TObject*>(fTreeItemCurrent->GetUserData());
02094               if( object )
02095               {
02096                 std::auto_ptr<TString> className( new TString(object->ClassName()) );
02097                 if( object->InheritsFrom(TH1::Class()) )
02098                 {
02099                   PopupPlot( x, y );
02100                 }
02101                 else if( object->InheritsFrom(TObjString::Class()) )
02102                 {
02103                   PopupPlot( x, y );
02104                 }
02105                 else if( object->InheritsFrom(TFile::Class()) )
02106                 {
02107                   fCloseFile = static_cast<TFile*>(object);
02108                   PopupFileMenu( x, y );
02109                 }
02110                 else if( object->InheritsFrom(TSocket::Class()) )
02111                 {
02112                   if( fSock )PopupOnlineMenu( x, y );
02113                 }
02114               }
02115               else if( fTreeItemCurrent == fTreeItemGroups )
02116               {
02117                 PopupNewGroup( x, y );
02118               }
02119               else if( fTreeItemCurrent == fTreeItemFiles )
02120               {
02121                 OpenFileDialog();
02122               }
02123               else if( fTreeItemCurrent == fTreeItemOnline )
02124               {
02125                 if( !fSock )
02126                 {
02127                   std::auto_ptr<TObjString> os( new TObjString() );
02128                   new TGTextDialog( gClient->GetRoot(), this, 100, 100, "&Host name:", 
02129                                     fHostName.Data(), os.get() );
02130                   TString s( os.get()->GetString() );
02131                   if( !s.Contains("-1") )ConnectServer( s.Data() );
02132                 }
02133               }
02134               else
02135               {
02136                 bool foundGroupFolder = false;
02137                 ItemVec::const_iterator end = fGroupFolders.end();
02138                 for( ItemVec::const_iterator i=fGroupFolders.begin(); i!=end; ++i )
02139                 {
02140                   if( *i == fTreeItemCurrent )
02141                   {
02142                     PopupGroup( x, y );
02143                     foundGroupFolder = true;
02144                     break;
02145                   }
02146                 }
02147                 if( !foundGroupFolder )
02148                 {
02149                   fTreeItems.clear();
02150                   GetFolderItems( fTreeItemCurrent );
02151                   PopupPlot( x, y, true );
02152                 }
02153               }
02154               break;
02155             }
02156             default:
02157             {
02158               break;
02159             }
02160           }
02161           break;
02162         }
02163         case kCT_ITEMDBLCLICK:  // double mouse click
02164         {
02165           PlotItem();
02166           break;
02167         }
02168         default:
02169           break;
02170       }
02171       break;
02172     }
02173     case kC_COMMAND:  // 
02174     {
02175       switch (GET_SUBMSG(msg))
02176       {
02177         case kCM_BUTTON:  // a button was pressed
02178         {
02179           switch (parm1)
02180           {
02181             case M_REFRESH_BUTTON:
02182             {
02183               if( fSock )
02184               {
02185                 if( fUpdateTimerSec > 0 )
02186                 {
02187                   if( fRefreshButton->GetString().BeginsWith("  Pause") )
02188                   {
02189                     fUpdateTimer->Stop();
02190                     std::stringstream str;
02191                     str << "  Restart Refresh (" << fUpdateTimerSec << ")  ";
02192                     fRefreshButton->SetText( str.str().c_str() );
02193                     fRefreshButton->SetToolTipText( "click to RESTART refresh of online histograms", 250 );
02194                   }
02195                   else
02196                   {
02197                     fUpdateTimer->Start();
02198                     std::stringstream str;
02199                     str << "  Pause Refresh (" << fUpdateTimerSec << ")  ";
02200                     fRefreshButton->SetText( str.str().c_str() );
02201                     fRefreshButton->SetToolTipText( "click to PAUSE refresh of online histograms", 250 );
02202                   }
02203                 }
02204                 else  // refresh now
02205                 {
02206                   fUpdateTimerSec = 1;
02207                   UpdateHistograms();
02208                   fUpdateTimerSec = 0;
02209                 }
02210               }
02211               break;
02212             }
02213             default:
02214               break;
02215           }
02216           break;
02217         }
02218         case kCM_MENUSELECT:
02219         {
02220           break;
02221         }
02222         case kCM_MENU: // menu item event
02223         {
02224           switch (parm1)
02225           {
02226             case M_FILE_OPEN:
02227             {
02228               fStatusBar->SetText("Opening ...");
02229               OpenFileDialog();
02230               fStatusBar->SetText(" ");
02231               break;
02232             }
02233             case M_FILE_ONLINE:
02234             {
02235               if( fSock )
02236               {
02237                 new TGMsgBox( gClient->GetRoot(), this,
02238                               "Error", "Online connection already made",
02239                               kMBIconExclamation, 0, NULL );
02240               }
02241               else
02242               {
02243                 std::auto_ptr<TObjString> os( new TObjString() );
02244                 new TGTextDialog( gClient->GetRoot(), this, 100, 100, "&Host name:",
02245                                   fHostName.Data(), os.get() );
02246                 TString s( os.get()->GetString() );
02247                 if( !s.Contains("-1") )ConnectServer( s.Data() );
02248               }
02249               break;
02250             }
02251             case M_FILE_SAVE_DEFAULT:
02252             {
02253               TString savefileName = "default.xml";
02254               fStatusBar->SetText("Saving session: " + savefileName);
02255               SaveFile( savefileName.Data() );
02256               break;
02257             }
02258             case M_FILE_SAVE:
02259             {
02260               OpenSaveDialog();
02261               break;
02262             }
02263             case M_FILE_RESTORE:
02264             {
02265               OpenRestoreDialog();
02266               break;
02267             }
02268             case M_FILE_EXIT:
02269             {
02270               CloseWindow();
02271               break;
02272             }
02273             case M_HELP_ABOUT:
02274             {
02275               new TGMsgBox( gClient->GetRoot(), this, "About Roody",
02276               "Roody is an application based solely on CERN-ROOT for histogram display.\nIt is meant for display of .root files and .hbook files.\nRunning this application in conjunction with either the Midas or ROME analyzer\nwill allow you to visualize online data retrieved through a socket port.\n\nThe current version of Roody is 1.7", kMBIconQuestion, kMBOk, NULL );
02277               break;
02278             }
02279             case M_HELP_CONTENTS:
02280             {
02281               fStatusBar->SetText("HELP CONTENTS -- Not yet available");
02282               std::cout << "HELP CONTENTS -- Not yet available" << std::endl;
02283               break;
02284             }
02285             case M_REFRESH_OFF:
02286             {
02287               SetRefreshRate(0); 
02288               break;
02289             }
02290             case M_REFRESH_NOW:
02291             {
02292               int tmp = fUpdateTimerSec;
02293               fUpdateTimerSec = 1;
02294               UpdateHistograms();
02295               fUpdateTimerSec = tmp;
02296               break;
02297             }
02298             case M_REFRESH_1SEC:
02299             {
02300               SetRefreshRate(1); 
02301               break;
02302             }
02303             case M_REFRESH_3SEC:
02304             {
02305               SetRefreshRate(3); 
02306               break;
02307             }
02308             case M_REFRESH_5SEC:
02309             {
02310               SetRefreshRate(5); 
02311               break;
02312             }
02313             case M_REFRESH_10SEC:
02314             {
02315               SetRefreshRate(10); 
02316               break;
02317             }
02318             case M_REFRESH_DIALOG:
02319             {
02320               OpenRefreshDialog();
02321               break;
02322             }
02323             case M_ZONES_11:
02324             {
02325               UncheckAllZones();
02326               fMenuZones->CheckEntry(M_ZONES_11);
02327               SetupZones( 1, 1 );
02328               break;
02329             }
02330             case M_ZONES_12:
02331             {
02332               UncheckAllZones();
02333               fMenuZones->CheckEntry(M_ZONES_12);
02334               SetupZones( 1, 2 );
02335               break;
02336             }
02337             case M_ZONES_21:
02338             {
02339               UncheckAllZones();
02340               fMenuZones->CheckEntry(M_ZONES_21);
02341               SetupZones( 2, 1 );
02342               break;
02343             }
02344             case M_ZONES_22:
02345             {
02346               UncheckAllZones();
02347               fMenuZones->CheckEntry(M_ZONES_22);
02348               SetupZones( 2, 2 );
02349               break;
02350             }
02351             case M_ZONES_33:
02352             {
02353               UncheckAllZones();
02354               fMenuZones->CheckEntry(M_ZONES_33);
02355               SetupZones( 3, 3 );
02356               break;
02357             }
02358             case M_ZONES_44:
02359             {
02360               UncheckAllZones();
02361               fMenuZones->CheckEntry(M_ZONES_44);
02362               SetupZones( 4, 4 );
02363               break;
02364             }
02365             case M_ZONES_USER:
02366             {
02367               std::string name( fMenuZones->GetEntry(M_ZONES_USER)->GetName() );
02368               if( name.find("user") == 0 )OpenZoneDialog();
02369               else
02370               {
02371                 std::size_t x = name.find("x");
02372                 int cols, rows;
02373                 StringTo<int>( cols, name.substr(0,x), std::dec );
02374                 StringTo<int>( rows, name.substr(x+1,name.size()-x-1), std::dec );
02375                 SetupZones( cols, rows );
02376               }
02377               SetupZonesMenu();
02378               break;
02379             }
02380             case M_ZONES_DIALOG:
02381             {
02382               OpenZoneDialog();
02383               SetupZonesMenu();
02384               break;
02385             }
02386             case M_PLOT_NEW:
02387               SetDestination(D_PLOT_NEW);
02388               break;
02389             case M_PLOT_SAME:
02390               SetDestination(D_PLOT_SAME);
02391               break;
02392             case M_PLOT_REPLACE:
02393               SetDestination(D_PLOT_REPLACE);
02394               break;
02395             case M_PLOT_NEXT:
02396               SetDestination(D_PLOT_NEXT);
02397               break;
02398 
02399             case C_PLOT_NEW:
02400               DrawItemsOnNewCanvas();
02401               break;
02402             case C_PLOT_SAME:
02403               fDrawDestination = D_PLOT_SAME;
02404               PlotItem();
02405               break;
02406             case C_PLOT_REPLACE:
02407               fDrawDestination = D_PLOT_REPLACE;
02408               PlotItem();
02409               break;
02410             case C_PLOT_NEXT:
02411               fDrawDestination = D_PLOT_NEXT;
02412               PlotItem();
02413               break;
02414 
02415             case C_CLOSE_FILE:
02416               CloseFile();
02417               break;
02418             case C_CLOSE_ONLINE:
02419               CloseOnline();
02420               break;
02421 
02422             case C_NEW_GROUP:
02423               AddNewGroup();
02424               break;
02425             case C_DRAW_GROUP:
02426               DrawGroup();
02427               break;
02428             case C_DELETE_GROUP:
02429               //fTreeItemCurrent = fFileOnlineContents->GetSelected();
02430               DeleteGroup();
02431               break;
02432             case C_ADD_TO_GROUP:
02433               PopupAddToGroup();
02434               break;
02435             case C_RESET_GROUP:
02436               fTreeItems.clear();
02437               GetFolderItems( fTreeItemCurrent );
02438               ResetMultiple();
02439               break;
02440             case C_RESET_OBJECT:
02441               ResetMultiple();
02442               break;
02443               
02444             case M_RESET_ALL:
02445               //fTreeItems.clear();
02446               //GetFolderItems( fTreeItemOnline );
02447               //ResetMultiple();
02448               ResetAll();
02449               break;
02450 
02451             default:
02452             {
02453               int id = parm1-100;
02454               if( id>=0 && id<static_cast<int>(fGroupFolders.size()) )
02455               {
02456                 std::size_t nEntries = fTreeItems.size();
02457                 for( std::size_t i=0; i<nEntries; ++i )
02458                 {
02459                   fTreeItemCurrent = fTreeItems[i];
02460                   if( fTreeItemCurrent )
02461                   {
02462                     TObject *object = static_cast<TObject*>(fTreeItemCurrent->GetUserData());
02463                     if( object )
02464                     {
02465                       std::auto_ptr<TString> className( new TString(object->ClassName()) );
02466                       if( className->Contains("TH1") || className->Contains("TH2") ||
02467                           className->Contains("TH3") )
02468                       {
02469                         TGListTreeItem *temp = fTreeItemCurrent;
02470                         while( strcmp(temp->GetParent()->GetText(),"Offline") )temp = temp->GetParent();
02471                         AddHistogramToGroup( id, object, temp->GetText() );
02472                       }
02473                       else if( className->Contains("TObjString") )
02474                       {
02475                         AddHistogramToGroup( id, object, "online" );
02476                       }
02477                     }
02478                   }
02479                 }
02480               }
02481               else
02482               {
02483                 new TGMsgBox( gClient->GetRoot(), this,
02484                               "Error", "Unimplemented menu command", kMBIconExclamation, 0, NULL );
02485               }
02486               break;
02487             }
02488           }
02489           break;
02490         }
02491         default:
02492           break;
02493       }
02494       break;
02495     }
02496   }
02497   return kTRUE;
02498 }
02499 
02500 bool Roody::AddHistogramToGroup( int id, TObject *object, char const *source )
02501 {
02502   TGListTreeItem *itemFound = fFileOnlineContents->FindChildByData( fGroupFolders[id], (void*)object );
02503   if( !itemFound )
02504   {
02505     GroupItem groupItem;
02506     groupItem.source = std::string( source );
02507     fFileOnlineContents->AddItem( fGroupFolders[id],
02508                                   object->GetName(),
02509                                   (void*)object,
02510                                   gClient->GetPicture("h1_t.xpm"),
02511                                   gClient->GetPicture("h1_t.xpm") );
02512     fFileOnlineContents->Resize();
02513     Layout();
02514 
02515     fTreeItemCurrent = fFileOnlineContents->FindChildByData( fGroupFolders[id], (void*)object );
02516     groupItem.item = fTreeItemCurrent;
02517     fGroupHists.insert( value_type(id,groupItem) );
02518   }
02519   return true;
02520 }
02521 
02522 void Roody::CloseOnline()
02523 {
02524   fSock->Close();
02525   delete fSock;
02526   fSock = 0;
02527   fFileOnlineContents->MDeleteItem(
02528     fFileOnlineContents->FindChildByName(fTreeItemOnline,(fHostName+":"+fPortName).Data()) );
02529   fFileOnlineContents->Resize();
02530   Layout();
02531   fStatusBar->SetText( "Socket disconnected" );
02532   fRefreshButton->SetEnabled( kFALSE );
02533 }
02534 
02535 void Roody::CloseFile()
02536 {
02537   std::string filename( fTreeItemCurrent->GetText() );
02538   //
02539   fFileList->Remove( fCloseFile );
02540   fCloseFile->Close();
02541   delete fCloseFile;
02542   fFileOnlineContents->MDeleteItem( fTreeItemCurrent );
02543   fFileOnlineContents->Resize();
02544   Layout();
02545   //
02546   std::size_t end = fGroupFolders.size();
02547   for( std::size_t id=0; id<end; ++id )
02548   {
02549     std::pair<GroupMap::iterator,GroupMap::iterator> p = fGroupHists.equal_range( id );
02550     for( GroupMap::iterator k=p.first; k!=p.second; ++k )
02551     {
02552       if( k->second.source == filename )
02553       {
02554         fGroupHists.erase( k );
02555         fFileOnlineContents->MDeleteItem( k->second.item );
02556       }
02557     }
02558   }
02559   fFileOnlineContents->Resize();
02560   Layout();
02561 }
02562 
02563 void Roody::GetFolderItems( TGListTreeItem *item )
02564 {
02565   // fill fTreeItems with the TGListTreeItem pointers which are contained 
02566   // within the tree of items headed by the input item
02567   //
02568   TGListTreeItem *firstChild = item->GetFirstChild();
02569   if( firstChild )GetItemsRecursive( firstChild );
02570   if( item->GetUserData() && 
02571       find(fTreeItems.begin(),fTreeItems.end(),item) == fTreeItems.end() )
02572     fTreeItems.push_back( item );
02573 }
02574 
02575 void Roody::GetItemsRecursive( TGListTreeItem *item )
02576 {
02577   // fill fTreeItems with the TGListTreeItem pointers which are contained 
02578   // within the tree of items headed by the input item
02579   //
02580   while( item )
02581   {
02582     TGListTreeItem *firstChild = item->GetFirstChild();
02583     if( firstChild )GetItemsRecursive( firstChild );
02584     if( item->GetUserData() && 
02585         find(fTreeItems.begin(),fTreeItems.end(),item) == fTreeItems.end() )
02586       fTreeItems.push_back( item );
02587     item = item->GetNextSibling();
02588   }
02589 }
02590 
02591 void Roody::ResetAll()
02592 {
02593   if( !fSock )return;
02594   TNetFolder netFolder( "histos", "online histos", fSock );
02595   netFolder.ExecuteCommand( "gAnalyzer->ResetAllHistos()" );
02596 }
02597 
02598 void Roody::ResetMultiple()
02599 {
02600   // fTreeItems, a vector of TGListTreeItem pointers, contains multiply selected items
02601   // i.e., items selected while holding down the control key
02602   //
02603   ItemVec::const_iterator end = fTreeItems.end();
02604   for( ItemVec::const_iterator i=fTreeItems.begin(); i!=end; ++i )
02605   {
02606     if( *i )ResetObject( static_cast<TObject*>((*i)->GetUserData()) );
02607   }
02608 }
02609 
02610 void Roody::ResetObject( TObject *object )
02611 {
02612   if( !fSock )return;
02613   if( !object )return;
02614   std::auto_ptr<TString> className( new TString(object->ClassName()) );
02615   if( className->Contains("TObjString") )
02616   {
02617     TNetFolder netFolder( "histos", "online histos", fSock );
02618     std::string s("gAnalyzer->GetHisto(\"");
02619     std::string path(
02620       netFolder.FindFullPathName( static_cast<TObjString*>(object)->GetString().Data() ) );
02621     if( path.substr(0,2) == "//" )path.erase(0,2);
02622     s += path + "\")->Reset()";
02623     netFolder.ExecuteCommand( s.c_str() );
02624 
02625     //std::cout << "full path=|" << s << "|\n";
02626 
02627     //fSock->Send( "Command" );
02628     //fSock->Send( static_cast<TObjString*>(object)->GetString().Data() );
02629     //fSock->Send( "Reset" );
02630   }
02631 }
02632 
02633 void Roody::PlotItem()
02634 {
02635   TGListTreeItem *item = fFileOnlineContents->GetSelected();
02636   if( !item )return;
02637   TObject *object = static_cast<TObject*>(item->GetUserData());
02638   if( !object )return;
02639   if( object->InheritsFrom(TH1::Class()) )
02640   {        
02641     // This clones the object ... (creates a new identical object)
02642     // allowing one to pass it to the list of hist or trees without worry
02643     //
02644     TH1 *tmp = static_cast<TH1*>(object);
02645     DrawObject( tmp->Clone(tmp->GetName()) );
02646   }
02647   else if( object->InheritsFrom(TTree::Class()) )
02648   {
02649     static_cast<TTree*>(object)->StartViewer();
02650   }
02651   else if( object->InheritsFrom(TNtuple::Class()) )
02652   {
02653     static_cast<TNtuple*>(object)->StartViewer();
02654   }
02655   else if( object->InheritsFrom(TCanvas::Class()) )
02656   {
02657     static_cast<TCanvas*>(object)->Draw();
02658   }
02659   else if( object->InheritsFrom(TFile::Class()) )
02660   {
02661     DisplayFile( item );
02662   }
02663 #ifdef HAVE_HBOOK
02664   else if( object->InheritsFrom(THbookFile::Class()) )
02665   {
02666     DisplayFile( item );
02667   }
02668 #endif
02669   else if( object->InheritsFrom(TSocket::Class()) )
02670   {
02671     GetHistList( item );
02672   }
02673   else if( object->InheritsFrom(TObjString::Class()) )
02674   {
02675     DrawOnlineObject( static_cast<TObjString*>(object) );
02676   }
02677   else if( object->InheritsFrom(TCutG::Class()) )
02678   {
02679     DrawObject( object );
02680   }
02681   Layout();
02682 }
02683 
02684 void Roody::CloseWindow()
02685 {
02686   gApplication->Terminate(0);
02687 }
02688 
02689 void Roody::OpenFileDialog()
02690 {
02691   fFileInfo.fFilename = 0;
02692 #ifdef HAVE_HBOOK
02693   char const *fileTypes[] = {"Root files","*.root","Hbook files","*.hbook",0,0};
02694 #else
02695   char const *fileTypes[] = {"Root files","*.root",0,0};
02696 #endif
02697   fFileInfo.fFileTypes = fileTypes;
02698   new TGFileDialog( fClient->GetRoot(), this, kFDOpen, &fFileInfo );
02699   if( fFileInfo.fFilename )
02700   {
02701     if( TString(fFileInfo.fFilename).Contains(".root") )OpenRootFile( fFileInfo.fFilename );
02702 #ifdef HAVE_HBOOK
02703     else OpenHbookFile( fFileInfo.fFilename );
02704 #endif
02705   }
02706   else
02707   {
02708     fStatusBar->SetText("NO FILE SELECTED");
02709   }
02710 }
02711 
02712 bool Roody::OpenRootFile( char const *filename )
02713 {
02714   if( fFileOnlineContents->FindChildByName(fTreeItemFiles,filename) )
02715   {
02716     std::string s("Error in loading file: \"");
02717     s += std::string(filename) + "\" is already loaded";
02718     new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
02719     return true;
02720   }
02721   fFileInfo.fFilename = const_cast<char*>(filename);
02722   fCurrentFile = new TFile( filename, "READ" );
02723   if( !fCurrentFile )
02724   {
02725     new TGMsgBox( gClient->GetRoot(), this, "Error", "Error in loading file: could not allocate TFile object",
02726                   kMBIconExclamation, 0, NULL );
02727     fCurrentFile = 0;
02728     return true;
02729   }
02730   if( fCurrentFile->IsZombie() )
02731   {
02732     std::string s("Error in loading file: \"");
02733     s += std::string(filename) + "\" is not a root file or the file doesn't exist";
02734     new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
02735     delete fCurrentFile;
02736     fCurrentFile = 0;
02737     return true;
02738   }
02739   fOpeningFile = true;
02740   fFileList->AddLast( fCurrentFile );
02741   AddFileEntryTreeView( fCurrentFile );
02742   fParentDir->cd();
02743   return false;
02744 }
02745 
02746 #ifdef HAVE_HBOOK
02747 bool Roody::OpenHbookFile( char const *filename )
02748 {
02749   fFileInfo.fFilename = const_cast<char*>(filename);
02750   fCurrentHbook = new THbookFile( filename );
02751   if( !fCurrentFile )
02752   {
02753     std::string s("Error in loading file: \"");
02754     s += std::string(filename) + "\" could not allocate THbookFile object";
02755     new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
02756     fCurrentHbook = 0;
02757     return true;
02758   }
02759   if( !fCurrentHbook->IsOpen() )
02760   {
02761     std::string s("Error in loading file: \"");
02762     s += std::string(filename) + "\" is not an hbook file or the file doesn't exist";
02763     new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
02764     delete fCurrentHbook;
02765     fCurrentHbook = 0;
02766     return true;
02767   }
02768   if( fFileOnlineContents->FindChildByName(fTreeItemFiles,filename) )
02769   {
02770     std::string s("Error in loading file: \"");
02771     s += std::string(filename) + "\" is already loaded";
02772     new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
02773     delete fCurrentHbook;
02774     fCurrentHbook = 0;
02775     return true;
02776   }
02777   fFileList->AddLast( fCurrentHbook );
02778   AddFileEntryTreeView( fCurrentHbook );
02779   fParentDir->cd();
02780   return false;
02781 }
02782 #endif
02783 
02784 void Roody::AddFileEntryTreeView( TFile *file )
02785 {
02786   fFileOnlineContents->AddItem( fTreeItemFiles,
02787                                 fFileInfo.fFilename,(void*)file,
02788                                 gClient->GetPicture("rootdb_t.xpm"),
02789                                 gClient->GetPicture("rootdb_t.xpm") );
02790   fTreeItemCurrent = fFileOnlineContents->FindChildByName( fTreeItemFiles, fFileInfo.fFilename );
02791   fFileOnlineContents->OpenItem( fTreeItemFiles );
02792   DisplayFile( fTreeItemCurrent );
02793   fFileOnlineContents->OpenItem( fTreeItemCurrent );
02794   fFileOnlineContents->Resize();
02795   Layout();
02796 }
02797 
02798 #ifdef HAVE_HBOOK
02799 void Roody::AddFileEntryTreeView( THbookFile *file )
02800 {
02801   fFileOnlineContents->AddItem( fTreeItemFiles,
02802                                 fFileInfo.fFilename,(void*)file,
02803                                 gClient->GetPicture("rootdb_t.xpm"),
02804                                 gClient->GetPicture("rootdb_t.xpm") );
02805   fTreeItemCurrent = fFileOnlineContents->FindChildByName( fTreeItemFiles, fFileInfo.fFilename );
02806   fFileOnlineContents->OpenItem( fTreeItemFiles );
02807   DisplayFile( fTreeItemCurrent );
02808   fFileOnlineContents->OpenItem( fTreeItemCurrent );
02809   fFileOnlineContents->Resize();
02810   Layout();
02811 }
02812 #endif
02813 
02814 void Roody::DisplayFile( TGListTreeItem *item )
02815 {
02816   TObject *tmp = static_cast<TObject*>(item->GetUserData());
02817   if( tmp->InheritsFrom(TFile::Class()) )DisplayFile( static_cast<TFile*>(tmp), item );
02818 #ifdef HAVE_HBOOK
02819   else if( tmp->InheritsFrom(THbookFile::Class()) )DisplayFile( static_cast<THbookFile*>(tmp), item );
02820 #endif
02821 }
02822 
02823 #ifdef HAVE_HBOOK
02824 class MyTHbookKey: public THbookKey
02825 {
02826 public:
02827   int GetID() const { return fID; };
02828 };
02829 #endif
02830 
02831 #ifdef HAVE_HBOOK
02832 void Roody::DisplayFile( THbookFile *file, TGListTreeItem *item )
02833 {
02834   fCurrentHbook = file;
02835   TIter next( file->GetListOfKeys() );
02836   MyTHbookKey *key;
02837   while( (key=static_cast<MyTHbookKey*>(next())) )
02838   {
02839     TObject *obj;
02840     if( (obj=file->Get( key->GetID())) )DisplayObject( obj, item, "" );
02841     Layout();
02842   }
02843   fFileOnlineCanvas->Layout();
02844 }
02845 #endif
02846 
02847 void Roody::DisplayFile( TFile *file, TGListTreeItem *item )
02848 {
02849   // When called, the fCurrentFile is pointing to an open .root file
02850   // and TGListTreeItem *item points to the parent of the items of interest
02851   // in the file.
02852   // This method could be made more general by passing in a TGListTree, 
02853   //  and then generating file structure
02854   //
02855   fCurrentFile = file;
02856   //
02857   TString runNumber( GetRunNumber(file->GetName()) );
02858   //
02859   // Do not need to delete since the object is stored in the list,
02860   // and will be deleted later
02861   //
02862   TIter next( file->GetListOfKeys() );
02863   TKey *key = 0;
02864   Int_t nKeys = file->GetNkeys();
02865   if( nKeys > 1000 )
02866   {
02867     if( fOpeningFile )
02868     {
02869       Int_t nFolders = nKeys/250;
02870       if( nFolders*250 < nKeys )++nFolders;
02871       for( Int_t i=0; i<nFolders; ++i )
02872       {
02873         int start = i*250 + 1;
02874         int end = std::min(nKeys,(i+1)*250);
02875         std::string id1, id2;
02876         TGListTreeItem *groupFolder = fFileOnlineContents->AddItem( fTreeItemCurrent, " " );
02877         for( int j=start; j<=end; ++j )
02878         {
02879           TString hname = static_cast<TKey*>(next())->GetName();
02880           TObject *obj = file->Get( hname.Data() );
02881           if( obj )
02882           {
02883             DisplayObject( obj, groupFolder, runNumber.Data() );
02884             if( j == start )id1 = obj->GetName();
02885             if( j == end )id2 = obj->GetName();
02886           }
02887         }
02888         std::string name( id1 + " - " + id2 );
02889         groupFolder->Rename( name.c_str() );
02890       }
02891       fOpeningFile = false;
02892     }
02893     fFileOnlineContents->Resize();
02894     Layout();
02895     fParentDir->cd();
02896   }
02897   else
02898   {
02899     while( (key=static_cast<TKey*>(next())) )
02900     {
02901       TString name = key->GetName();
02902       TObject *obj = file->Get( name.Data() );
02903       if( obj )DisplayObject( obj, item, runNumber.Data() );
02904       Layout();
02905     }
02906   }
02907   fFileOnlineCanvas->Layout();
02908 }
02909 
02910 TString Roody::GetRunNumber( char const *filename )
02911 {
02912   int end = strlen( filename );
02913   while( --end >= 0 )
02914   {
02915     if( filename[end] <= '9' && filename[end] >= '0' )break;
02916   }
02917   int begin = end;
02918   while( --begin >= 0 )
02919   {
02920     if( filename[begin] < '0' || filename[begin] > '9' )break;
02921   }
02922   ++begin;
02923   int len = end-begin+1;
02924   return TString( filename+begin, len );
02925 }
02926 
02927 TObject *Roody::SearchDirectory( TDirectory *tdir, char const *histname )
02928 {
02929   // Enters a TDirectory in a .root file to find histname
02930   //
02931   TObject *obj = 0;
02932   TIter next( tdir->GetList() );
02933   while( (obj=next()) )
02934   {
02935     if( obj->InheritsFrom(TDirectory::Class()) )
02936     {
02937       if( (obj=SearchDirectory(static_cast<TDirectory*>(obj),histname)) )break;
02938     }
02939     if( TString(obj->GetName()) == TString(histname) )break;
02940   }
02941   return obj;
02942 }
02943 
02944 void Roody::DisplayFile( TDirectory *tdir, TGListTreeItem *item )
02945 {
02946   // Enters a TDirectory in a .root file and find all objects of interest
02947   // called from DisplayObject
02948   //
02949   TIter next( tdir->GetListOfKeys() );
02950   TKey *key;
02951   while( (key=static_cast<TKey*>(next())) )
02952   {
02953     TObject *obj = tdir->Get( key->GetName() );
02954     if( obj )DisplayObject(obj,item,"");
02955     Layout();
02956   }
02957   fFileOnlineCanvas->Layout();
02958 }
02959 
02960 void Roody::DisplayObject( TObject *obj, TGListTreeItem *item, char const *rn )
02961 {
02962   std::string className( obj->ClassName() );
02963   std::string name( obj->GetName() );
02964   std::string title( obj->GetTitle() );
02965   std::string itemDescription( name );
02966   std::string runNumber( rn );
02967   std::string file("file:");
02968   file += fCurrentFile->GetName();
02969   //
02970   //  gClient->GetPicture("rootdb_t.xpm");//ROOT FILE
02971   //  gClient->GetPicture("h1_t.xpm");//TH1
02972   //  gClient->GetPicture("h2_t.xpm");//TH2
02973   //  gClient->GetPicture("h3_t.xpm");//TH3
02974   //  gClient->GetPicture("tree_t.xpm");//TREE
02975   //  gClient->GetPicture("ntuple_t.xpm");//NTUPLE
02976   //  gClient->GetPicture("profile_t.xpm");//1D Profile
02977   //  gClient->GetPicture("h2_t.xpm");//2D Profile same as TH2
02978   //
02979   //obj->InheritsFrom(TH1::Class()) could be used,
02980   // although there is a slight complication
02981   //note:  - All histogram classes are obj from the base class TH1
02982   //
02983   //                                TH1
02984   //                                 ^
02985   //                                 |
02986   //                                 |
02987   //                                 |
02988   //         -----------------------------------------------------------
02989   //                |                |       |      |      |     |     |
02990   //                |                |      TH1C   TH1S   TH1I  TH1F  TH1D
02991   //                |                |                                 |
02992   //                |                |                                 |
02993   //                |               TH2                             TProfile
02994   //                |                |
02995   //                |                |
02996   //                |                ----------------------------------
02997   //                |                        |      |      |     |     |
02998   //                |                       TH2C   TH2S   TH2I  TH2F  TH2D
02999   //                |                                                  |
03000   //               TH3                                                 |
03001   //                |                                               TProfile2D
03002   //                |
03003   //                -------------------------------------
03004   //                        |      |      |      |      |
03005   //                       TH3C   TH3S   TH3I   TH3F   TH3D
03006   //      The TH*C classes also inherit from the array class TArrayC.
03007   //      The TH*S classes also inherit from the array class TArrayS.
03008   //      The TH*I classes also inherit from the array class TArrayI.
03009   //      The TH*F classes also inherit from the array class TArrayF.
03010   //      The TH*D classes also inherit from the array class TArrayD.
03011   //
03012   if( className.find("TH1") != className.npos )
03013   {
03014     if( title.find("Run#") == title.npos &&                   // Run# not in title and
03015         runNumber.find_first_not_of(" ") != runNumber.npos )  // runNumber not blank
03016     {
03017       std::string s( title );
03018       s += "    Run# ";
03019       s += runNumber;
03020       static_cast<TH1*>(obj)->SetTitle( s.c_str() );
03021     }
03022     if( name != title )
03023     {
03024       itemDescription += " ";
03025       itemDescription += title;
03026     }
03027     fFileOnlineContents->AddItem( item, itemDescription.c_str(),
03028                                   (void*)obj,
03029                                   gClient->GetPicture("h1_t.xpm"),
03030                                   gClient->GetPicture("h1_t.xpm") );
03031     //
03032     // add the filename as a TObjString to the histograms so when saving
03033     // the histograms on a canvas, they know what files they come from
03034     //
03035     static_cast<TH1*>(obj)->GetListOfFunctions()->Add( new TObjString(file.c_str()) );
03036   }
03037   else if( className.find("TH2") != className.npos )
03038   {
03039     if( title.find("Run#") == title.npos &&                   // Run# not in title and
03040         runNumber.find_first_not_of(" ") != runNumber.npos )  // runNumber not blank
03041     {
03042       std::string s( title );
03043       s += "    Run# ";
03044       s += runNumber;
03045       static_cast<TH2*>(obj)->SetTitle( s.c_str() );
03046     }
03047     if( name != title )
03048     {
03049       itemDescription += " ";
03050       itemDescription += title;
03051     }
03052     fFileOnlineContents->AddItem( item, itemDescription.c_str(),
03053                                   (void*)obj,
03054                                   gClient->GetPicture("h2_t.xpm"),
03055                                   gClient->GetPicture("h2_t.xpm") );
03056     //
03057     // add the filename as a TObjString to the histograms so when saving
03058     // the histograms on a canvas, they know what files they come from
03059     //
03060     static_cast<TH1*>(obj)->GetListOfFunctions()->Add( new TObjString(file.c_str()) );
03061   }
03062   else if( className.find("TH3") != className.npos )
03063   {
03064     if( title.find("Run#") == title.npos &&                   // Run# not in title and
03065         runNumber.find_first_not_of(" ") != runNumber.npos )  // runNumber not blank
03066     {
03067       std::string s( title );
03068       s += "    Run# ";
03069       s += runNumber;
03070       static_cast<TH3*>(obj)->SetTitle( s.c_str() );
03071     }
03072     if( name != title )
03073     {
03074       itemDescription += " ";
03075       itemDescription += title;
03076     }
03077     fFileOnlineContents->AddItem( item, itemDescription.c_str(),
03078                                   (void*)obj,
03079                                   gClient->GetPicture("h3_t.xpm"),
03080                                   gClient->GetPicture("h3_t.xpm") );
03081     //
03082     // add the filename as a TObjString to the histograms so when saving
03083     // the histograms on a canvas, they know what files they come from
03084     //
03085     static_cast<TH1*>(obj)->GetListOfFunctions()->Add( new TObjString(file.c_str()) );
03086   }
03087   else if( className.find("Folder") != className.npos )
03088   {
03089     TGListTreeItem *itemFound = fFileOnlineContents->FindChildByName( item, name.c_str() );
03090     if( !itemFound )
03091     {
03092       TGListTreeItem *folderItem = fFileOnlineContents->AddItem( item, name.c_str() );
03093       TCollection *folderList = static_cast<TFolder*>(obj)->GetListOfFolders();
03094       TIterator *iterator = folderList->MakeIterator();
03095       TObject *next = 0;
03096       while ( (next=iterator->Next()) )DisplayObject( next, folderItem, runNumber.c_str() );
03097     }
03098   }
03099   else if( className.find("Tree") != className.npos )
03100     fFileOnlineContents->AddItem( item, name.c_str(),
03101                                   (void*)obj,
03102                                   gClient->GetPicture("tree_t.xpm"),
03103                                   gClient->GetPicture("tree_t.xpm") );
03104   else if( className.find("Ntuple") != className.npos )
03105     fFileOnlineContents->AddItem( item, name.c_str(),
03106                                   (void*)obj,
03107                                   gClient->GetPicture("ntuple_t.xpm"),
03108                                   gClient->GetPicture("ntuple_t.xpm") );
03109   else if( className.find("Profile") != className.npos )
03110   {
03111      if( className.find("2D") != className.npos )
03112        fFileOnlineContents->AddItem( item, name.c_str(),
03113                                      (void*)obj,
03114                                      gClient->GetPicture("h2_t.xpm"),
03115                                      gClient->GetPicture("h2_t.xpm") );
03116      else
03117        fFileOnlineContents->AddItem( item, name.c_str(),
03118                                      (void*)obj,
03119                                      gClient->GetPicture("profile_t.xpm"),
03120                                      gClient->GetPicture("profile_t.xpm") );
03121   }
03122   else if( className.find("Directory") != className.npos )
03123   {
03124     TDirectory *d = static_cast<TDirectory *>(fCurrentFile->Get(name.c_str()));
03125     TGListTreeItem *folderItem = fFileOnlineContents->AddItem( item, name.c_str() );
03126     DisplayFile(d,folderItem);
03127   }
03128   else if( className.find("TCanvas") != className.npos )
03129   {
03130     fFileOnlineContents->AddItem( item, name.c_str(),
03131                                   (void*)obj,
03132                                   gClient->GetPicture("h1_t.xpm"),
03133                                   gClient->GetPicture("h1_t.xpm") );
03134   }
03135   else if( className.find("TCutG") != className.npos )
03136   {
03137     fFileOnlineContents->AddItem( item, name.c_str(),
03138                                   (void*)obj,
03139                                   gClient->GetPicture("cut_t.xpm"),
03140                                   gClient->GetPicture("cut_t.xpm") );
03141   }
03142   else
03143   {
03144     fFileOnlineContents->AddItem( item, name.c_str(),
03145                                   (void*)obj,
03146                                   gClient->GetPicture("diamond.xpm"),
03147                                   gClient->GetPicture("diamond.xpm") );
03148   }
03149 }
03150 
03151 void Roody::ConnectServer( char const *host, Bool_t displayMsgBox )
03152 {
03153   Int_t port = 9090;
03154   std::string hostString( host );
03155   std::string hostname( host );
03156   std::string portname( "9090" );
03157   std::size_t colonLoc;
03158   if( (colonLoc=hostString.find(":")) != hostString.npos )
03159   {
03160     if( !colonLoc )
03161     {
03162       new TGMsgBox( gClient->GetRoot(), this, "Error", "A host name must be provided", kMBIconExclamation, 0, NULL );
03163       return;
03164     }
03165     hostname = hostString.substr( 0, colonLoc );
03166     portname = hostString.substr( colonLoc+1, hostString.size()-colonLoc-1 );
03167     port = 0;
03168     std::size_t portLen = portname.size();
03169     for( std::size_t i=0; i<portLen; ++i )
03170     {
03171       if( (static_cast<int>(portname[i]))>47 && static_cast<int>(portname[i])<58 )
03172       {
03173         // ignore char not in number region
03174         port *= 10;
03175         port += static_cast<int>(portname[i]) - 48; // Getting the port number
03176       }
03177     }
03178     if( port == 0 )
03179     {
03180       port = 9090; // use default port just in case
03181       portname = std::string("9090");
03182     }
03183   }
03184   std::string s( hostname+":"+portname );
03185   if( fFileOnlineContents->FindChildByName(fTreeItemOnline,s.c_str()) )
03186   {
03187     fStatusBar->SetText( TString("Already connected to ")+TString(s.c_str()) );
03188     return;
03189   }
03190   fSock = new TSocket( hostname.c_str(), port );
03191   if( !fSock || !fSock->IsValid() )
03192   {
03193     delete fSock;
03194     fSock = 0;
03195     if( displayMsgBox )
03196     {
03197       TString s("Cannot connect to Midas server on host ");
03198       s += TString(hostname.c_str()) + TString(", port ") + TString(portname.c_str());
03199       fStatusBar->SetText( s );
03200       new TGMsgBox( gClient->GetRoot(), this, "Error", s.Data(),
03201                     kMBIconExclamation, 0, NULL );
03202     }
03203   }
03204   else
03205   {
03206     fHostName = TString( hostname.c_str() );
03207     fPortName = TString( portname.c_str() );
03208     fStatusBar->SetText( TString("Connected to ")+fHostName+TString(":")+fPortName );
03209     AddOnlineEntryTreeView();
03210     fRefreshButton->SetEnabled(kTRUE);
03211     if( fUpdateTimerSec > 0 )
03212     {
03213       std::stringstream str;
03214       str << "  Pause Refresh (" << fUpdateTimerSec << ")  ";
03215       fRefreshButton->SetText( str.str().c_str() );
03216       fRefreshButton->SetToolTipText( "click to PAUSE refresh of online histograms", 250 );
03217     }
03218     else
03219     {
03220       fRefreshButton->SetText( "     Refresh NOW      " );
03221       fRefreshButton->SetToolTipText( "click to refresh online histograms once right now", 250 );
03222     }
03223   }
03224 }
03225 
03226 void Roody::AddOnlineEntryTreeView()
03227 {
03228   TString s( fHostName + TString(":") + fPortName );
03229   fFileOnlineContents->AddItem( fTreeItemOnline, s.Data(), (void*)fSock );
03230   fTreeItemCurrent = fFileOnlineContents->FindChildByName( fTreeItemOnline, s.Data() );
03231   fFileOnlineContents->OpenItem( fTreeItemOnline );
03232   GetHistList( fTreeItemCurrent );
03233   fFileOnlineContents->OpenItem( fTreeItemCurrent );
03234   fFileOnlineContents->Resize();
03235   Layout();
03236 }
03237 
03238 TObjArray* Roody::GetHistList( TSocket *sock )
03239 {
03240   TObjArray *tmp = 0;
03241   TMessage *m;
03242   if( sock && sock->IsValid() )
03243   {
03244     sock->Send("LIST");
03245     if( sock->Recv(m) )
03246     {
03247       tmp = static_cast<TObjArray*>(m->ReadObject(m->GetClass()));
03248       delete m;
03249     }
03250   }
03251   return tmp;
03252 }
03253 
03254 void Roody::GetHistList( TGListTreeItem *item, char const *folderName )
03255 {
03256   if( !fSock )return;
03257   TNetFolder *netFolder = new TNetFolder( folderName, "online histos", fSock );
03258   if( !netFolder )
03259   {
03260     new TGMsgBox( gClient->GetRoot(), this, "Error", "TNetFolder not made", kMBIconExclamation, 0, NULL );
03261     return;
03262   }
03263   TObjArray *fNames = netFolder->GetListOfFolders();
03264   if( !fNames )
03265   {
03266     new TGMsgBox( gClient->GetRoot(), this, "Error", "list of folders not made", kMBIconExclamation, 0, NULL );
03267     return;
03268   }
03269   int nNames = fNames->GetLast();
03270   if( fHistNames )delete fHistNames;
03271   fHistNames = new TObjArray( fNames->GetLast()+1 );
03272   while( item->GetFirstChild() )
03273   {
03274     delete static_cast<TObject*>(item->GetFirstChild()->GetUserData());
03275     // might be currently used in an Active Histogram
03276     fFileOnlineContents->MDeleteItem( item->GetFirstChild() );
03277   }
03278   for( int i=0; i<=nNames; ++i )
03279   {
03280     TObjString *oName = static_cast<TObjString*>(fNames->At(i));
03281     std::string name( oName->GetString().Data() );
03282     TGListTreeItem *found = fFileOnlineContents->FindChildByName( item, name.c_str() );
03283     TObject *object = netFolder->FindObjectAny( name.c_str() );
03284     if( !object )
03285     {
03286       std::string s("object \"");
03287       s += name + "\" not found in net folder \"" + folderName + "\"";
03288       new TGMsgBox( gClient->GetRoot(), this, "Error", s.c_str(), kMBIconExclamation, 0, NULL );
03289       return;
03290     }
03291     std::string title( object->GetTitle() );
03292     std::string itemDescription( name );
03293     if( name != title )
03294     {
03295       itemDescription += std::string(" ");
03296       itemDescription += title;
03297     }
03298     TString *type = new TString(object->ClassName());
03299     if( type && type->Contains("TH1") && !found )
03300     {
03301       fFileOnlineContents->AddItem( item, itemDescription.c_str(),
03302                                     (void*)new TObjString(name.c_str()),
03303                                     gClient->GetPicture("h1_t.xpm"),
03304                                     gClient->GetPicture("h1_t.xpm") );
03305     }
03306     else if( type && type->Contains("TH2") && !found )
03307     {
03308       fFileOnlineContents->AddItem( item, itemDescription.c_str(),
03309                                     (void*)new TObjString(name.c_str()),
03310                                     gClient->GetPicture("h2_t.xpm"),
03311                                     gClient->GetPicture("h2_t.xpm") );
03312     }
03313     else if( type && type->Contains("TH3") && !found )
03314     {
03315       fFileOnlineContents->AddItem( item, itemDescription.c_str(),
03316                                     (void*)new TObjString(name.c_str()),
03317                                     gClient->GetPicture("h3_t.xpm"),
03318                                     gClient->GetPicture("h3_t.xpm") );
03319     }
03320     else if( type && type->Contains("TProfile") && !found )
03321     {
03322       if( type->Contains("2D") )
03323         fFileOnlineContents->AddItem( item, itemDescription.c_str(),
03324                                       (void*)new TObjString(name.c_str()),
03325                                       gClient->GetPicture("h2_t.xpm"),
03326                                       gClient->GetPicture("h2_t.xpm") );
03327       else
03328         fFileOnlineContents->AddItem( item, itemDescription.c_str(),
03329                                       (void*)new TObjString(name.c_str()),
03330                                       gClient->GetPicture("profile_t.xpm"),
03331                                       gClient->GetPicture("profile_t.xpm") );
03332     }
03333     else if( type && type->Contains("TCutG") && !found )
03334     {
03335       fFileOnlineContents->AddItem( item, itemDescription.c_str(),
03336                                     (void*)new TObjString(name.c_str()),
03337                                     gClient->GetPicture("cut_t.xpm"),
03338                                     gClient->GetPicture("cut_t.xpm") );
03339     }
03340     else if( type && type->Contains("Folder") && !found )
03341     {
03342       TGListTreeItem *folderItem = fFileOnlineContents->AddItem( item, name.c_str() );
03343       GetHistList( folderItem, name.c_str() );
03344     }
03345     else if( type && !found )
03346     {
03347       std::cout << "Unexpected Type: " << type->Data() << std::endl;
03348     }
03349     if( type )delete type;
03350   }
03351   delete netFolder;
03352   delete fNames;
03353   fFileOnlineContents->Resize();
03354 }
03355 
03356 TObject *Roody::GetNetFolderObject( char const *itemName, char const *folderName )
03357 {
03358   TNetFolder netFolder( folderName, "online histos", fSock );
03359   TObject *object = netFolder.FindObjectAny( itemName );
03360   if( !object )
03361   {
03362     TObjArray *names = 0;
03363     if( (names=netFolder.GetListOfFolders()) )
03364     {
03365       int nNames = names->GetLast();
03366       for( int i=0; i<=nNames; ++i )
03367       {
03368         char const *folderName = static_cast<TObjString*>(names->At(i))->GetString().Data();
03369         if( TString(names->At(i)->ClassName()).Contains("TNetFolder") )
03370         {
03371           object = GetNetFolderObject( itemName, folderName );
03372           if( object )break;
03373         }
03374       }
03375     }
03376   }
03377   return object;
03378 }
03379 
03380 void Roody::DrawOnlineObject( TObjString *objString )
03381 {
03382   TObject *object = GetNetFolderObject( objString->GetString().Data() );
03383   if( !object )return;
03384   if( object->InheritsFrom(TH1::Class()) )
03385   {
03386     MarkObjectAsOnline(object);
03387     DrawObject( object );
03388   }
03389   else if( object->InheritsFrom(TCutG::Class()) )
03390   {
03391     DrawObject( object );
03392   }
03393   else
03394   {
03395     std::cout << "DrawOnlineObject: encountered a " << object->ClassName()
03396               << ", this was unexpected" << std::endl;
03397   }
03398 }
03399 
03400 void Roody::StartOnlineTimer()
03401 {
03402   fMenuRefresh->UnCheckEntry(M_REFRESH_OFF);
03403   fMenuRefresh->UnCheckEntry(M_REFRESH_NOW);
03404   fMenuRefresh->UnCheckEntry(M_REFRESH_1SEC);
03405   fMenuRefresh->UnCheckEntry(M_REFRESH_3SEC);
03406   fMenuRefresh->UnCheckEntry(M_REFRESH_5SEC);
03407   fMenuRefresh->UnCheckEntry(M_REFRESH_10SEC);
03408   if( fUpdateTimerSec > 0 )
03409   {
03410     fUpdateTimer->SetTime(fUpdateTimerSec*1000); // changes timer length and restarts it
03411     fUpdateTimer->Start();
03412     switch( fUpdateTimerSec )
03413     {
03414       case 1:  fMenuRefresh->CheckEntry( M_REFRESH_1SEC ); break;
03415       case 3:  fMenuRefresh->CheckEntry( M_REFRESH_3SEC ); break;
03416       case 5:  fMenuRefresh->CheckEntry( M_REFRESH_5SEC ); break;
03417       case 10: fMenuRefresh->CheckEntry( M_REFRESH_10SEC ); break;
03418     }
03419   }
03420   else
03421   {
03422     fMenuRefresh->CheckEntry( M_REFRESH_OFF );
03423     fUpdateTimer->Stop();
03424   }
03425 }
03426 
03427 void Roody::UpdateHistograms()
03428 {
03429   if( fSock )
03430   {
03431     fUpdateTimer->Stop(); // so multiple updates do not occur at once
03432     if( fSock->GetLocalPort() == -1 )
03433     {
03434       CloseOnline();
03435       fOnlineAborted = kTRUE;
03436       fUpdateTimer->SetTime(1000);
03437       fUpdateTimer->Start();
03438     }
03439     else
03440     {
03441       if( fUpdateTimerSec > 0 )
03442       {
03443         TIter next( gROOT->GetListOfCanvases() );
03444         TCanvas *canvas;
03445         while( (canvas=static_cast<TCanvas*>(next())) )UpdateHistograms( static_cast<TPad*>(canvas) );
03446       }
03447     }
03448     fUpdateTimer->Start();
03449   }
03450   else
03451   {
03452     if( fOnlineAborted )
03453     {
03454       ConnectServer( (fHostName+":"+fPortName).Data(), kFALSE );
03455       if( fSock )
03456       {
03457         fOnlineAborted = kFALSE;
03458         StartOnlineTimer();
03459       }
03460     }
03461   }
03462 }
03463 
03464 void Roody::UpdateHistograms( TPad *pad )
03465 {
03466   //std::cout << "UpdateHistograms" << std::endl;
03467   TIter padNext( pad->GetListOfPrimitives() );
03468   std::vector<TH1*> histVec;
03469   TObject *padObject;
03470   bool first = true;
03471   while( (padObject=static_cast<TObject*>(padNext())) )
03472   {
03473     if( padObject && padObject->InheritsFrom(TPad::Class()) )
03474     {
03475       UpdateHistograms( static_cast<TPad*>(padObject) );
03476     }
03477     else if( padObject && padObject->InheritsFrom(TH1::Class()) )
03478     {
03479       TH1 *hist = static_cast<TH1*>(padObject);
03480       if( ObjectIsOnline(padObject) )
03481       {
03482         TObject *netObject = GetNetFolderObject(padObject->GetName());
03483         if( !netObject )return;
03484         //
03485         // get the current axis values for zooming in
03486         // these zoom values only apply to this pad
03487         // use the XaxisLimits popup form to set the limits for all pads on a canvas
03488         //
03489         Int_t xfirst = hist->GetXaxis()->GetFirst();
03490         Int_t xlast = hist->GetXaxis()->GetLast();
03491         //
03492         Color_t color = hist->GetLineColor();
03493         pad->GetListOfPrimitives()->Remove( static_cast<TObject*>(hist) );
03494         delete hist;
03495         //
03496         hist = static_cast<TH1*>(netObject);
03497         hist->SetLineColor( color );
03498         if( first )
03499         {
03500           first = false;
03501           //
03502           // fix the axis values to the previous ones
03503           //
03504           hist->GetXaxis()->SetRange( xfirst, xlast );
03505           //
03506           // zoom the y-axis
03507           //
03508           CanvasLimits *limits = FindCanvasLimits(pad->GetCanvas()->GetCanvasID());
03509           if (limits)
03510             limits->ApplyLimits(hist);
03511         }
03512         MarkObjectAsOnline(hist);
03513         histVec.push_back( hist );
03514       }
03515     }
03516   }
03517   if( histVec.empty() )return;
03518   gPad = pad;
03519   TH1* h = SetCanvasLimits( pad->GetCanvas(), histVec[0] );
03520   h->Draw();
03521   std::vector<TH1*>::const_iterator end = histVec.end();
03522   for( std::vector<TH1*>::const_iterator i=histVec.begin()+1; i!=end; ++i )
03523     {
03524       h = SetCanvasLimits(pad->GetCanvas(),(*i));
03525       h->Draw("SAME");
03526     }
03527   pad->GetCanvas()->Modified();
03528   pad->GetCanvas()->Update();
03529 }
03530 
03531 void Roody::OpenRefreshDialog()
03532 {
03533   std::auto_ptr<TObjString> objString(new TObjString());
03534   new TGTextDialog( gClient->GetRoot(), this, 100, 100,
03535                     "Refresh time in seconds: ", "", objString.get() );
03536   TString refreshString = objString->GetString();
03537   if( refreshString.Contains("-1") )fStatusBar->SetText( "Refresh not changed");
03538   else                              SetRefreshRate(atoi(refreshString.Data()));
03539 }
03540 
03541 void Roody::OpenZoneDialog()
03542 {
03543   std::auto_ptr<TObjString> objString( new TObjString() );
03544   new TGTextDialog( gClient->GetRoot(), this, 100, 100,
03545                     "Zone Setting: (columns x rows, e.g. 2x2): ", "", objString.get() );
03546   TString zoneString = objString->GetString();
03547   if( zoneString.Contains("-1") )
03548   {
03549     fStatusBar->SetText( "Zone status not changed");
03550     return;
03551   }
03552   int columns, rows;
03553   std::string s( zoneString.Data() );
03554   std::size_t x = s.find("x");
03555   if( x == s.npos ) // "x" not found in string
03556   {
03557     columns = 1;
03558     rows = 1;
03559   }
03560   else
03561   {
03562     if( !StringTo<int>(columns,s.substr(0,x),std::dec) )
03563     {
03564       columns = 1;
03565       std::string err( "invalid number of columns: \"" );
03566       err += s.substr(0,x) + "\"\n" + "columns set to 1\n";
03567       new TGMsgBox( gClient->GetRoot(), this, "Error", err.c_str(), kMBIconExclamation, 0, NULL );
03568     }
03569     if( !StringTo<int>(rows,s.substr(x+1,s.size()-x-1),std::dec) )
03570     {
03571       rows = 1;
03572       std::string err( "invalid number of rows: \"" );
03573       err += s.substr(x+1,s.size()-x-1) + "\"\n" + "rows set to 1\n";
03574       new TGMsgBox( gClient->GetRoot(), this, "Error", err.c_str(), kMBIconExclamation, 0, NULL );
03575     }
03576   }
03577   //char *str = (char*)zoneString.Data();
03578   //fZoneColumns = strtoul( str, &str, 0 );
03579   //str++;
03580   //fZoneRows = strtoul( str, &str, 0 );
03581   SetupZones( columns, rows );
03582   SetupZonesMenu();
03583 }
03584 
03585 void Roody::OpenSaveDialog()
03586 {
03587   fFileInfo.fFilename = 0;
03588   char const *fileTypes[] = {"Save file","*.xml","Any file","*",0,0};
03589   fFileInfo.fFileTypes = fileTypes;
03590   //std::auto_ptr<TObjString> objString( new TObjString() );
03591   //new TGTextDialog( gClient->GetRoot(), this, 100, 100, "Save file name: ", "", objString.get() );
03592   //TString savefileName( objString->GetString() );
03593   new TGFileDialog( fClient->GetRoot(), this, kFDOpen, &fFileInfo);
03594   TString savefileName = fFileInfo.fFilename;
03595   if( savefileName.Contains("-1") )
03596   {
03597     fStatusBar->SetText( "NO FILE SELECTED" );
03598   }
03599   else
03600   {
03601     if( !savefileName.Contains(".xml") )savefileName += ".xml";
03602     fStatusBar->SetText("Saving session: " + savefileName);
03603     SaveFile( savefileName.Data() );
03604   }
03605 }
03606 
03607 void Roody::OpenRestoreDialog()
03608 {
03609   fFileInfo.fFilename = 0;
03610   char const *fileTypes[] = {"Save file","*.xml","Any file","*",0,0};
03611   fFileInfo.fFileTypes = fileTypes;
03612   new TGFileDialog( fClient->GetRoot(), this, kFDOpen, &fFileInfo );
03613   if( fFileInfo.fFilename )
03614   {
03615     RestoreFile( fFileInfo.fFilename );
03616   }
03617   else
03618   {
03619     fStatusBar->SetText( "NO FILE SELECTED" );
03620   }
03621 }
03622 
03623 // end of code

Roody DOC Version 1.0.1 ---- TRIUMF ----
Contributions: Pierre-Andre Amaudruz - Joe Chuma - Doxygen - Greg King - Konstantin Olchanski - Matthias Schneebeli