source: sasview/guiframe/gui_manager.py @ 3cd5806

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 3cd5806 was a45037aa, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on toolbar

  • Property mode set to 100644
File size: 66.7 KB
RevLine 
[41d466f]1
[d955bf19]2################################################################################
3#This software was developed by the University of Tennessee as part of the
4#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
5#project funded by the US National Science Foundation.
6#
7#See the license text in license.txt
8#
9#copyright 2008, University of Tennessee
10################################################################################
[7681bac]11
[d68c655]12
[41d466f]13import wx
14import wx.aui
[32c0841]15import os
16import sys
[b0eee0f0]17import xml
[db10f97]18
[41d466f]19try:
20    # Try to find a local config
21    import imp
22    path = os.getcwd()
[cbb2e40]23    if(os.path.isfile("%s/%s.py" % (path, 'local_config'))) or \
[32c0841]24        (os.path.isfile("%s/%s.pyc" % (path, 'local_config'))):
25        fObj, path, descr = imp.find_module('local_config', [path])
26        config = imp.load_module('local_config', fObj, path, descr) 
[278cc25]27    else:
[cbb2e40]28        # Try simply importing local_config
29        import local_config as config
[41d466f]30except:
31    # Didn't find local config, load the default
32    import config
[4e9583c]33   
34import warnings
35warnings.simplefilter("ignore")
[3c44c66]36
[4e9583c]37import logging
[32c0841]38
[f444b20]39from sans.guiframe.events import EVT_STATUS
[a45037aa]40from sans.guiframe.events import EVT_PANEL_ON_FOCUS
[f444b20]41from sans.guiframe.events import StatusEvent
42from sans.guiframe.events import NewPlotEvent
[f036c692]43from sans.guiframe.gui_style import GUIFRAME
44from sans.guiframe.gui_style import GUIFRAME_ID
[52b8b74]45from sans.guiframe.events import NewLoadedDataEvent
[3feed3e]46from sans.guiframe.data_panel import DataPanel
[d828481]47from sans.guiframe.panel_base import PanelBase
[f036c692]48from sans.guiframe.gui_toolbar import GUIToolBar
[b5ca223]49
[3feed3e]50STATE_FILE_EXT = ['.inv', '.fitv', '.prv']
[f444b20]51DATA_MANAGER = False
52AUTO_PLOT = False
53AUTO_SET_DATA = True
[3feed3e]54PLOPANEL_WIDTH = 400
55PLOPANEL_HEIGTH = 400
[3385795]56GUIFRAME_WIDTH = 1000
57GUIFRAME_HEIGHT = 800
[4753fc2]58PROG_SPLASH_SCREEN = "images/danse_logo.png" 
[7681bac]59
[41d466f]60class ViewerFrame(wx.Frame):
61    """
[d955bf19]62    Main application frame
[41d466f]63    """
[f444b20]64   
[3385795]65    def __init__(self, parent, title, 
[4753fc2]66                 size=(GUIFRAME_WIDTH, GUIFRAME_HEIGHT),
[3385795]67                 gui_style=GUIFRAME.DEFAULT_STYLE, 
68                 pos=wx.DefaultPosition):
[41d466f]69        """
[d955bf19]70        Initialize the Frame object
[41d466f]71        """
[b7c7a1c]72       
[3385795]73        wx.Frame.__init__(self, parent=parent, title=title, pos=pos,size=size)
[d0802c3]74        # Preferred window size
[3385795]75        self._window_width, self._window_height = size
[52b8b74]76        self.__gui_style = gui_style
[41d466f]77       
[fc2b91a]78        # Logging info
79        logging.basicConfig(level=logging.DEBUG,
80                    format='%(asctime)s %(levelname)s %(message)s',
81                    filename='sans_app.log',
82                    filemode='w')       
[c44e7cc]83        path = os.path.dirname(__file__)
[32c0841]84        temp_path = os.path.join(path,'images')
[c44e7cc]85        ico_file = os.path.join(temp_path,'ball.ico')
[278cc25]86        if os.path.isfile(ico_file):
87            self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
[cbb2e40]88        else:
[32c0841]89            temp_path = os.path.join(os.getcwd(),'images')
[c44e7cc]90            ico_file = os.path.join(temp_path,'ball.ico')
[cbb2e40]91            if os.path.isfile(ico_file):
92                self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
[41d466f]93       
94        ## Application manager
95        self.app_manager = None
[32c0841]96        self._mgr = None
[f444b20]97        #add current perpsective
98        self._current_perspective = None
[52b8b74]99        self._plotting_plugin = None
100        self._data_plugin = None
101        #Menu bar and item
102        self._menubar = None
103        self._file_menu = None
104        self._data_menu = None
105        self._window_menu = None
106        self._window_menu = None
[c5e84fb]107        self._help_menu = None
108        self._tool_menu = None
[95f9cc4]109        self._applications_menu_pos = -1
110        self._applications_menu = None
[d828481]111        self._edit_menu = None
[a45037aa]112        self._toolbar_menu = None
[f036c692]113        #tool bar
114        self._toolbar = None
[41d466f]115        ## Find plug-ins
116        # Modify this so that we can specify the directory to look into
[32c0841]117        self.plugins = []
[b7c7a1c]118        #add local plugin
[52b8b74]119        self.plugins += self._get_local_plugins()
[a88ac04]120        self.plugins += self._find_plugins()
[41d466f]121        ## List of panels
122        self.panels = {}
123
[2310d69]124        # Default locations
125        self._default_save_location = os.getcwd()       
[f444b20]126       
[f9e803e]127        # Welcome panel
128        self.defaultPanel = None
[b91c736]129        #panel on focus
130        self.panel_on_focus = None
[213892bc]131         #data manager
132        from data_manager import DataManager
133        self._data_manager = DataManager()
134        self._data_panel = DataPanel(parent=self)
135        if self.panel_on_focus is not None:
[6db811e]136            self._data_panel.set_panel_on_focus(self.panel_on_focus.window_caption)
[a0d56d5]137        # Check for update
[af20f6b]138        #self._check_update(None)
[278cc25]139        # Register the close event so it calls our own method
[52725d6]140        wx.EVT_CLOSE(self, self.Close)
[278cc25]141        # Register to status events
142        self.Bind(EVT_STATUS, self._on_status_event)
[b91c736]143        #Register add extra data on the same panel event on load
[a45037aa]144        self.Bind(EVT_PANEL_ON_FOCUS, self.set_panel_on_focus)
[b91c736]145       
146    def set_panel_on_focus(self, event):
147        """
[d955bf19]148        Store reference to the last panel on focus
[f036c692]149        update the toolbar if available
150        update edit menu if available
[b91c736]151        """
152        self.panel_on_focus = event.panel
[a45037aa]153        panel_name = 'No panel on focus'
154        application_name = 'No Selected Application'
[213892bc]155        if self.panel_on_focus is not None and self._data_panel is not None:
[a45037aa]156            panel_name = self.panel_on_focus.window_caption
157            self._data_panel.set_panel_on_focus(panel_name)
158        #update toolbar
159        self._update_toolbar_helper()
160        #update edit menu
161        self.enable_edit_menu()
162        print "set_panel_on_focus", event.panel.window_caption
[213892bc]163           
[278cc25]164    def build_gui(self):
[d955bf19]165        """
166        """
[41d466f]167        # Set up the layout
168        self._setup_layout()
169        # Set up the menu
170        self._setup_menus()
[f036c692]171        # set tool bar
172        self._setup_tool_bar()
[c9454bb]173        #self.Fit()
[af20f6b]174        #self._check_update(None)
[41d466f]175             
176    def _setup_layout(self):
177        """
[d955bf19]178        Set up the layout
[41d466f]179        """
180        # Status bar
[010c251]181        from gui_statusbar import StatusBar
[db10f97]182        self.sb = StatusBar(self, wx.ID_ANY)
[dd66fbd]183        self.SetStatusBar(self.sb)
[41d466f]184        # Add panel
[a45037aa]185        default_flag = wx.aui.AUI_MGR_DEFAULT#| wx.aui.AUI_MGR_ALLOW_ACTIVE_PANE
[52b8b74]186        self._mgr = wx.aui.AuiManager(self, flags=default_flag)
[7a67e075]187   
[41d466f]188        # Load panels
189        self._load_panels()
[c5e84fb]190        self.set_default_perspective()
[41d466f]191        self._mgr.Update()
[db10f97]192       
193    def SetStatusText(self, *args, **kwds):
[d955bf19]194        """
195        """
[db10f97]196        number = self.sb.get_msg_position()
197        wx.Frame.SetStatusText(number=number, *args, **kwds)
198       
199    def PopStatusText(self, *args, **kwds):
[d955bf19]200        """
201        """
[db10f97]202        field = self.sb.get_msg_position()
203        wx.Frame.PopStatusText(field=field)
204       
205    def PushStatusText(self, *args, **kwds):
[d955bf19]206        """
207        """
[db10f97]208        field = self.sb.get_msg_position()
[32c0841]209        wx.Frame.PushStatusText(self, field=field, string=string)
[278cc25]210
211    def add_perspective(self, plugin):
212        """
[d955bf19]213        Add a perspective if it doesn't already
214        exist.
[278cc25]215        """
216        is_loaded = False
217        for item in self.plugins:
[32c0841]218            if plugin.__class__ == item.__class__:
[f444b20]219                msg = "Plugin %s already loaded" % plugin.__class__.__name__
220                logging.info(msg)
[32c0841]221                is_loaded = True   
[278cc25]222        if not is_loaded:
223            self.plugins.append(plugin)
[41d466f]224     
[52b8b74]225    def _get_local_plugins(self):
226        """
227        get plugins local to guiframe and others
228        """
229        plugins = []
230        #import guiframe local plugins
[7a67e075]231        #check if the style contain guiframe.dataloader
232        style1 = self.__gui_style & GUIFRAME.DATALOADER_ON
[3feed3e]233        style2 = self.__gui_style & GUIFRAME.PLOTTING_ON
[7a67e075]234        if style1 == GUIFRAME.DATALOADER_ON:
[52b8b74]235            try:
236                from sans.guiframe.local_perspectives.data_loader import data_loader
[3feed3e]237                self._data_plugin = data_loader.Plugin()
[52b8b74]238                plugins.append(self._data_plugin)
239            except:
[3feed3e]240                msg = "ViewerFrame._get_local_plugins:"
[52b8b74]241                msg += "cannot import dataloader plugin.\n %s" % sys.exc_value
242                logging.error(msg)
[3feed3e]243        if style2 == GUIFRAME.PLOTTING_ON:
[52b8b74]244            try:
245                from sans.guiframe.local_perspectives.plotting import plotting
246                self._plotting_plugin = plotting.Plugin()
247                plugins.append(self._plotting_plugin)
248            except:
[3feed3e]249                msg = "ViewerFrame._get_local_plugins:"
[52b8b74]250                msg += "cannot import plotting plugin.\n %s" % sys.exc_value
251                logging.error(msg)
[3feed3e]252     
[52b8b74]253        return plugins
254   
[41d466f]255    def _find_plugins(self, dir="perspectives"):
256        """
[d955bf19]257        Find available perspective plug-ins
258       
259        :param dir: directory in which to look for plug-ins
260       
261        :return: list of plug-ins
262       
[41d466f]263        """
264        import imp
265        plugins = []
266        # Go through files in panels directory
267        try:
268            list = os.listdir(dir)
[a88ac04]269            ## the default panel is the panel is the last plugin added
270            for item in list:
[41d466f]271                toks = os.path.splitext(os.path.basename(item))
272                name = None
273                if not toks[0] == '__init__':
274                   
[32c0841]275                    if toks[1] == '.py' or toks[1] == '':
[41d466f]276                        name = toks[0]
277               
278                    path = [os.path.abspath(dir)]
279                    file = None
280                    try:
[32c0841]281                        if toks[1] == '':
[41d466f]282                            mod_path = '.'.join([dir, name])
[32c0841]283                            module = __import__(mod_path, globals(),
284                                                locals(), [name])
[41d466f]285                        else:
286                            (file, path, info) = imp.find_module(name, path)
[32c0841]287                            module = imp.load_module( name, file, item, info)
[41d466f]288                        if hasattr(module, "PLUGIN_ID"):
[f444b20]289                            try: 
290                                plug = module.Plugin()
291                                if plug.set_default_perspective():
292                                    self._current_perspective = plug
293                                plugins.append(plug)
[32c0841]294                                msg = "Found plug-in: %s" % module.PLUGIN_ID
295                                logging.info(msg)
[41d466f]296                            except:
[32c0841]297                                msg = "Error accessing PluginPanel"
298                                msg += " in %s\n  %s" % (name, sys.exc_value)
299                                config.printEVT(msg)
[41d466f]300                    except:
[3feed3e]301                        print sys.exc_value
[32c0841]302                        msg = "ViewerFrame._find_plugins: %s" % sys.exc_value
303                        logging.error(msg)
[41d466f]304                    finally:
[32c0841]305                        if not file == None:
[41d466f]306                            file.close()
307        except:
[32c0841]308            # Should raise and catch at a higher level and
309            # display error on status bar
[41d466f]310            pass   
311        return plugins
312   
[f9e803e]313    def set_welcome_panel(self, panel_class):
314        """
[d955bf19]315        Sets the default panel as the given welcome panel
316       
317        :param panel_class: class of the welcome panel to be instantiated
318       
[f9e803e]319        """
[d955bf19]320        self.defaultPanel = panel_class(self, -1, style=wx.RAISED_BORDER)
[b28278e]321       
[3feed3e]322    def _get_panels_size(self, p):
323        """
324        find the proper size of the current panel
325        get the proper panel width and height
326        """
327        panel_height_min = self._window_height
328        panel_width_min = self._window_width
329        style = self.__gui_style & (GUIFRAME.MANAGER_ON)
330        if self._data_panel is not None  and (p == self._data_panel):
[6db811e]331            panel_width_min = self._window_width * 2/25 
[3feed3e]332            return panel_width_min, panel_height_min
333        if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
334            style = self.__gui_style & (GUIFRAME.PLOTTING_ON|GUIFRAME.MANAGER_ON)
335            if style == (GUIFRAME.PLOTTING_ON|GUIFRAME.MANAGER_ON):
[6db811e]336                panel_width_min = self._window_width * 17/25 
[3feed3e]337            return panel_width_min, panel_height_min
338        return panel_width_min, panel_height_min
339   
[41d466f]340    def _load_panels(self):
341        """
[d955bf19]342        Load all panels in the panels directory
[41d466f]343        """
344       
345        # Look for plug-in panels
[c1469ebe]346        panels = []   
[41d466f]347        for item in self.plugins:
348            if hasattr(item, "get_panels"):
349                ps = item.get_panels(self)
350                panels.extend(ps)
[3feed3e]351       
[41d466f]352        # Show a default panel with some help information
353        # It also sets the size of the application windows
[c9454bb]354        #TODO: Use this for slpash screen
[f9e803e]355        if self.defaultPanel is None:
[32c0841]356            self.defaultPanel = DefaultPanel(self, -1, style=wx.RAISED_BORDER)
[3feed3e]357        # add a blank default panel always present
[41d466f]358        self.panels["default"] = self.defaultPanel
359        self._mgr.AddPane(self.defaultPanel, wx.aui.AuiPaneInfo().
360                              Name("default").
[3feed3e]361                              Center().
[a45037aa]362                              CloseButton(False).
363                              MinimizeButton(False).
[32c0841]364                              # This is where we set the size of
365                              # the application window
366                              BestSize(wx.Size(self._window_width, 
367                                               self._window_height)).
[41d466f]368                              Show())
[3feed3e]369        #add data panel
370        self.panels["data_panel"] = self._data_panel
371        w, h = self._get_panels_size(self._data_panel)
372        self._mgr.AddPane(self._data_panel, wx.aui.AuiPaneInfo().
373                              Name(self._data_panel.window_name).
374                              Left().
375                              MinimizeButton().
376                              MinSize(wx.Size(w, h)).
[d828481]377                              Hide())
[3feed3e]378        style = self.__gui_style & GUIFRAME.MANAGER_ON
379        if style != GUIFRAME.MANAGER_ON:
380            self._mgr.GetPane(self.panels["data_panel"].window_name).Hide()
[d828481]381        else:
382            self._mgr.GetPane(self.panels["data_panel"].window_name).Show()
[3feed3e]383           
[41d466f]384        # Add the panels to the AUI manager
385        for panel_class in panels:
386            p = panel_class
387            id = wx.NewId()
[3feed3e]388            w, h = self._get_panels_size(p)
[41d466f]389            # Check whether we need to put this panel
390            # in the center pane
[6f59a98]391            if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
[41d466f]392                if p.CENTER_PANE:
393                    self.panels[str(id)] = p
394                    self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
395                                          Name(p.window_name).Caption(p.window_caption).
[a45037aa]396                                           #CenterPane().
397                                            Center().
398                                            CloseButton(False).
399                                            MinimizeButton(False).
[3feed3e]400                                           MinSize(wx.Size(w, h)).
401                                           Hide())
[41d466f]402            else:
403                self.panels[str(id)] = p
404                self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
405                                  Name(p.window_name).Caption(p.window_caption).
406                                  Right().
407                                  Dock().
408                                  TopDockable().
409                                  BottomDockable().
410                                  LeftDockable().
411                                  RightDockable().
412                                  MinimizeButton().
[3feed3e]413                                  Hide())       
[b28278e]414     
[2310d69]415    def get_context_menu(self, graph=None):
[41d466f]416        """
[d955bf19]417        Get the context menu items made available
418        by the different plug-ins.
419        This function is used by the plotting module
[41d466f]420        """
421        menu_list = []
422        for item in self.plugins:
423            if hasattr(item, "get_context_menu"):
[2310d69]424                menu_list.extend(item.get_context_menu(graph))
[41d466f]425        return menu_list
426       
427    def popup_panel(self, p):
428        """
[d955bf19]429        Add a panel object to the AUI manager
430       
431        :param p: panel object to add to the AUI manager
[41d466f]432       
[d955bf19]433        :return: ID of the event associated with the new panel [int]
434       
435        """
[41d466f]436        ID = wx.NewId()
437        self.panels[str(ID)] = p
438        count = 0
439        for item in self.panels:
[383189f9]440            if self.panels[item].window_name.startswith(p.window_name): 
[41d466f]441                count += 1
442        windowname = p.window_name
443        caption = p.window_caption
[32c0841]444        if count > 0:
[41d466f]445            windowname += str(count+1)
446            caption += (' '+str(count))
447        p.window_name = windowname
448        p.window_caption = caption
449           
[7a67e075]450        style1 = self.__gui_style & GUIFRAME.FIXED_PANEL
451        style2 = self.__gui_style & GUIFRAME.FLOATING_PANEL
452        if style1 == GUIFRAME.FIXED_PANEL:
453            self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
454                              Name(windowname).Caption(caption).
455                              MinimizeButton().
456                              Resizable(True).
[c5e84fb]457                              # Use a large best size to make sure the AUI
458                              # manager takes all the available space
[3feed3e]459                              BestSize(wx.Size(PLOPANEL_WIDTH, PLOPANEL_HEIGTH)))
460            self._popup_fixed_panel(p)
[213892bc]461   
[0663dfb1]462        elif style2 == GUIFRAME.FLOATING_PANEL:
[7a67e075]463            self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
464                              Name(windowname).Caption(caption).
465                              MinimizeButton().
466                              Resizable(True).
[c5e84fb]467                              # Use a large best size to make sure the AUI
468                              #  manager takes all the available space
[3feed3e]469                              BestSize(wx.Size(PLOPANEL_WIDTH, PLOPANEL_HEIGTH)))
470            self._popup_floating_panel(p)
[7a67e075]471           
[d0802c3]472        pane = self._mgr.GetPane(windowname)
473        self._mgr.MaximizePane(pane)
474        self._mgr.RestoreMaximizedPane()
[41d466f]475        # Register for showing/hiding the panel
476        wx.EVT_MENU(self, ID, self._on_view)
477       
478        self._mgr.Update()
479        return ID
480       
[b7c7a1c]481    def _populate_file_menu(self):
482        """
483        Insert menu item under file menu
484        """
485        for plugin in self.plugins:
486            if len(plugin.populate_file_menu()) > 0:
487                for item in plugin.populate_file_menu():
[df23f90]488                    id = wx.NewId()
[f444b20]489                    m_name, m_hint, m_handler = item
[52725d6]490                    self._file_menu.Append(id, m_name, m_hint)
[b7c7a1c]491                    wx.EVT_MENU(self, id, m_handler)
[52725d6]492                self._file_menu.AppendSeparator()
[b7c7a1c]493               
[41d466f]494    def _setup_menus(self):
495        """
[d955bf19]496        Set up the application menus
[41d466f]497        """
498        # Menu
[b7c7a1c]499        self._menubar = wx.MenuBar()
[52b8b74]500        self._add_menu_file()
501        self._add_menu_data()
502        self._add_menu_application()
[f036c692]503        self._add_menu_edit()
[c5e84fb]504        self._add_menu_tool()
[7bc88bf]505        self._add_current_plugin_menu()
[52b8b74]506        self._add_menu_window()
[c5e84fb]507        self._add_help_menu()
508        self.SetMenuBar(self._menubar)
509       
[f036c692]510    def _setup_tool_bar(self):
511        """
512        add toolbar to the frame
513        """
514        #set toolbar
515        self._toolbar = GUIToolBar(self, -1)
516        self.SetToolBar(self._toolbar)
[a45037aa]517        self._update_toolbar_helper()
518        #self._on_hide_toolbar(event=None)
519   
520    def _update_toolbar_helper(self):
521        """
522        """
523        application_name = 'No Selected Application'
524        panel_name = 'No Panel on Focus'
525        self._toolbar.update_toolbar(self.panel_on_focus)
[f036c692]526        if self._current_perspective is not None:
[a45037aa]527            application_name = self._current_perspective.sub_menu
528        if self.panel_on_focus is not None:
529            panel_name = self.panel_on_focus.window_caption
530        self._toolbar.update_button(application_name=application_name, 
531                                        panel_name=panel_name)
532        self._toolbar.Realize()
533       
[c5e84fb]534    def _add_menu_tool(self):
535        """
536        Tools menu
537        Go through plug-ins and find tools to populate the tools menu
538        """
539        style = self.__gui_style & GUIFRAME.TOOL_ON
540        if style == GUIFRAME.TOOL_ON:
541            self._tool_menu = None
542            for item in self.plugins:
543                if hasattr(item, "get_tools"):
544                    for tool in item.get_tools():
545                        # Only create a menu if we have at least one tool
546                        if self._tool_menu is None:
547                            self._tool_menu = wx.Menu()
548                        id = wx.NewId()
549                        self._tool_menu.Append(id, tool[0], tool[1])
550                        wx.EVT_MENU(self, id, tool[2])
551            if self._tool_menu is not None:
552                self._menubar.Append(self._tool_menu, '&Tools')
553               
554    def _add_current_plugin_menu(self):
555        """
556        add current plugin menu
[cbf22e5]557        Look for plug-in menus
558        Add available plug-in sub-menus.
[c5e84fb]559        """
[7bc88bf]560        if (self._menubar is None) or (self._current_perspective is None):
[cbf22e5]561            return
[7bc88bf]562        #replace or add a new menu for the current plugin
563        name = 'Others'
564        pos = self._menubar.FindMenu(name)
565        if pos != -1:
566            menu_list = self._current_perspective.populate_menu(self)
567            if menu_list:
568                for (menu, _) in menu_list:
[9a5117a]569                    hidden_menu = self._menubar.Replace(pos, menu, name) 
[7bc88bf]570            else:
571                hidden_menu = self._menubar.Remove(pos)
572            #get the position of the menu when it first added
573            self._plugin_menu_pos = pos
574        else:
575            menu_list = self._current_perspective.populate_menu(self)
576            if menu_list:
577                for (menu, _) in menu_list:
[95f9cc4]578                    if self._applications_menu_pos == -1:
[7bc88bf]579                        self._menubar.Append(menu, name)
580                    else:
[95f9cc4]581                        self._menubar.Insert(self._applications_menu_pos, menu, name)
[7bc88bf]582                 
[c5e84fb]583    def _add_help_menu(self):
584        """
585        add help menu
586        """
[41d466f]587        # Help menu
[c5e84fb]588        self._help_menu = wx.Menu()
[d828481]589        style = self.__gui_style & GUIFRAME.WELCOME_PANEL_ON
590        if style == GUIFRAME.WELCOME_PANEL_ON:
591            # add the welcome panel menu item
592            if self.defaultPanel is not None:
593                id = wx.NewId()
594                self._help_menu.Append(id, '&Welcome', '')
595                self._help_menu.AppendSeparator()
596                wx.EVT_MENU(self, id, self.show_welcome_panel)
[fa452e4]597        # Look for help item in plug-ins
598        for item in self.plugins:
599            if hasattr(item, "help"):
600                id = wx.NewId()
[c5e84fb]601                self._help_menu.Append(id,'&%s help' % item.sub_menu, '')
[fa452e4]602                wx.EVT_MENU(self, id, item.help)
[41d466f]603        if config._do_aboutbox:
604            id = wx.NewId()
[c5e84fb]605            self._help_menu.Append(id,'&About', 'Software information')
[41d466f]606            wx.EVT_MENU(self, id, self._onAbout)
[c5e84fb]607       
[af20f6b]608        # Checking for updates needs major refactoring to work with py2exe
609        # We need to make sure it doesn't hang the application if the server
610        # is not up. We also need to make sure there's a proper executable to
611        # run if we spawn a new background process.
612        #id = wx.NewId()
[c5e84fb]613        #self._help_menu.Append(id,'&Check for update',
[32c0841]614        #'Check for the latest version of %s' % config.__appname__)
[af20f6b]615        #wx.EVT_MENU(self, id, self._check_update)
[c5e84fb]616        self._menubar.Append(self._help_menu, '&Help')
617           
[52b8b74]618    def _add_menu_window(self):
619        """
620        add a menu window to the menu bar
621        Window menu
622        Attach a menu item for each panel in our
623        panel list that also appears in a plug-in.
624       
625        Only add the panel menu if there is only one perspective and
626        it has more than two panels.
627        Note: the first plug-in is always the plotting plug-in.
628        The first application
629        #plug-in is always the second one in the list.
630        """
631        self._window_menu = wx.Menu()
632        if self._plotting_plugin is not None:
[bf4402c3]633            for (menu, name) in self._plotting_plugin.populate_menu(self):
[52b8b74]634                self._window_menu.AppendSubMenu(menu, name)
635        self._menubar.Append(self._window_menu, '&Window')
[c5e84fb]636     
[7a67e075]637        style = self.__gui_style & GUIFRAME.MANAGER_ON
638        if style == GUIFRAME.MANAGER_ON:
[52b8b74]639            id = wx.NewId()
640            self._window_menu.Append(id,'&Data Manager', '')
641            wx.EVT_MENU(self, id, self.show_data_panel)
642           
[4753fc2]643        style = self.__gui_style & GUIFRAME.PLOTTING_ON
644        if style == GUIFRAME.PLOTTING_ON:
645            self._window_menu.AppendSeparator()
646            id = wx.NewId()
647            preferences_menu = wx.Menu()
648            hint = "Plot panels will floating"
649            preferences_menu.Append(id, '&Floating Plot Panel', hint)
650            wx.EVT_MENU(self, id, self.set_plotpanel_floating)
651            id = wx.NewId()
652            hint = "Plot panels will displayed within the frame"
653            preferences_menu.Append(id, '&Fixed Plot Panel', hint)
654            wx.EVT_MENU(self, id, self.set_plotpanel_fixed)
655            id = wx.NewId()
[a45037aa]656            style1 = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
657            if style1 == GUIFRAME.MULTIPLE_APPLICATIONS:
658                id = wx.NewId()
659                self._toolbar_menu = preferences_menu.Append(id,'&Hide Toolbar', '')
660                wx.EVT_MENU(self, id, self._on_hide_toolbar)
[4753fc2]661            self._window_menu.AppendSubMenu(preferences_menu,'&Preferences')
[d828481]662        if self._window_menu.GetMenuItemCount() == 0:
663            pos = self._menubar.FindMenu('Window')
664            self._menubar.Remove(pos)
[7a67e075]665        #wx.EVT_MENU(self, id, self.show_preferences_panel)   
[52b8b74]666        """
667        if len(self.plugins) == 2:
668            plug = self.plugins[1]
669            pers = plug.get_perspective()
670       
671            if len(pers) > 1:
672                self._window_menu = wx.Menu()
673                for item in self.panels:
674                    if item == 'default':
675                        continue
676                    panel = self.panels[item]
677                    if panel.window_name in pers:
678                        self._window_menu.Append(int(item),
679                                                  panel.window_caption,
680                                        "Show %s window" % panel.window_caption)
681                        wx.EVT_MENU(self, int(item), self._on_view)
682                self._menubar.Append(self._window_menu, '&Window')
683                """
684               
685    def _add_menu_application(self):
686        """
687       
688        # Attach a menu item for each defined perspective or application.
689        # Only add the perspective menu if there are more than one perspectives
690        add menu application
691        """
[7a67e075]692        style = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
693        if style == GUIFRAME.MULTIPLE_APPLICATIONS:
[95f9cc4]694            plug_data_count = False
695            plug_no_data_count = False
696            self._applications_menu = wx.Menu()
697            separator = self._applications_menu.AppendSeparator()
[52b8b74]698            for plug in self.plugins:
699                if len(plug.get_perspective()) > 0:
700                    id = wx.NewId()
[95f9cc4]701                    if plug.use_data():
702                        self._applications_menu.InsertCheckItem(0, id, plug.sub_menu,
703                                      "Switch to application: %s" % plug.sub_menu)
704                        plug_data_count = True
705                    else:
706                        plug_no_data_count = True
707                        self._applications_menu.AppendCheckItem(id, plug.sub_menu,
708                                      "Switch to application: %s" % plug.sub_menu)
[52b8b74]709                    wx.EVT_MENU(self, id, plug.on_perspective)
[95f9cc4]710            if not (plug_data_count and  plug_no_data_count):
711                self._applications_menu.RemoveItem(separator)
712            self._menubar.Append(self._applications_menu, '&Applications')
713            self._check_applications_menu()
[52b8b74]714           
715    def _add_menu_file(self):
716        """
717        add menu file
718        """
[d828481]719       
[52b8b74]720         # File menu
[52725d6]721        self._file_menu = wx.Menu()
[d828481]722        style = self.__gui_style & GUIFRAME.DATALOADER_ON
723        if style == GUIFRAME.DATALOADER_ON:
724            # some menu of plugin to be seen under file menu
725            self._populate_file_menu()
726            id = wx.NewId()
727            self._file_menu.Append(id, '&Save Application',
728                                 'Save state of the current active application')
729            wx.EVT_MENU(self, id, self._on_save_application)
730            id = wx.NewId()
731            self._file_menu.Append(id, '&Save Project',
732                                 'Save the state of the whole application')
733            wx.EVT_MENU(self, id, self._on_save_project)
734            self._file_menu.AppendSeparator()
[52725d6]735       
736        id = wx.NewId()
737        self._file_menu.Append(id, '&Quit', 'Exit') 
[52b8b74]738        wx.EVT_MENU(self, id, self.Close)
739        # Add sub menus
[52725d6]740        self._menubar.Append(self._file_menu, '&File')
[52b8b74]741       
[d828481]742    def _add_menu_edit(self):
743        """
744        add menu edit
745        """
746        # Edit Menu
747        self._edit_menu = wx.Menu()
[f036c692]748        self._edit_menu.Append(GUIFRAME_ID.UNDO_ID, '&Undo', 
749                               'Undo the previous action')
750        wx.EVT_MENU(self, GUIFRAME_ID.UNDO_ID, self.on_undo_panel)
751        self._edit_menu.Append(GUIFRAME_ID.REDO_ID, '&Redo', 
752                               'Redo the previous action')
753        wx.EVT_MENU(self, GUIFRAME_ID.REDO_ID, self.on_redo_panel)
[d828481]754        self._edit_menu.AppendSeparator()
[f036c692]755        self._edit_menu.Append(GUIFRAME_ID.BOOKMARK_ID, '&Bookmark', 
756                               'bookmark current panel')
757        wx.EVT_MENU(self, GUIFRAME_ID.BOOKMARK_ID, self.on_bookmark_panel)
758        self._edit_menu.Append(GUIFRAME_ID.SAVE_ID, '&Save As', 
759                               'Save current panel into file')
760        wx.EVT_MENU(self, GUIFRAME_ID.SAVE_ID, self.on_save_panel)
[d828481]761        self._edit_menu.AppendSeparator()
[f036c692]762        self._edit_menu.Append(GUIFRAME_ID.PREVIEW_ID, '&Print Preview',
763                               'Preview current panel')
764        wx.EVT_MENU(self, GUIFRAME_ID.PREVIEW_ID, self.on_preview_panel)
765        self._edit_menu.Append(GUIFRAME_ID.PRINT_ID, '&Print',
766                               'Print current panel')
767        wx.EVT_MENU(self, GUIFRAME_ID.PRINT_ID, self.on_print_panel)
[d828481]768        self._edit_menu.AppendSeparator()
[f036c692]769        self._edit_menu.Append(GUIFRAME_ID.ZOOM_ID, '&Zoom',
770                               'Zoom current panel')
771        wx.EVT_MENU(self, GUIFRAME_ID.ZOOM_ID, self.on_zoom_panel)
772        self._edit_menu.Append(GUIFRAME_ID.ZOOM_IN_ID, '&Zoom In',
773                               'Zoom in current panel')
774        wx.EVT_MENU(self, GUIFRAME_ID.ZOOM_IN_ID, self.on_zoom_in_panel)
775        self._edit_menu.Append(GUIFRAME_ID.ZOOM_OUT_ID, '&Zoom Out', 
776                               'Zoom out current panel')
777        wx.EVT_MENU(self, GUIFRAME_ID.ZOOM_OUT_ID, self.on_zoom_out_panel)
778        self._edit_menu.Append(GUIFRAME_ID.DRAG_ID, '&Drag',
779                               'Drag current panel')
780        wx.EVT_MENU(self, GUIFRAME_ID.DRAG_ID, self.on_drag_panel)
781        self._edit_menu.Append(GUIFRAME_ID.RESET_ID, '&Reset', 
782                               'Reset current panel')
783        wx.EVT_MENU(self, GUIFRAME_ID.RESET_ID, self.on_reset_panel)
784        self._menubar.Append(self._edit_menu,  '&Edit')
785        self.enable_edit_menu()
[d828481]786       
[52b8b74]787    def _add_menu_data(self):
788        """
789        Add menu item item data to menu bar
790        """
791        # Add menu data
792        self._data_menu = wx.Menu()
793        #menu for data files
794        data_file_id = wx.NewId()
795        data_file_hint = "load one or more data in the application"
796        self._data_menu.Append(data_file_id, 
797                         '&Load Data File(s)', data_file_hint)
798        wx.EVT_MENU(self, data_file_id, self._load_data)
[3feed3e]799        style = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
[4753fc2]800        style1 = self.__gui_style & GUIFRAME.DATALOADER_ON
[3feed3e]801        if style == GUIFRAME.MULTIPLE_APPLICATIONS:
[52b8b74]802            #menu for data from folder
803            data_folder_id = wx.NewId()
804            data_folder_hint = "load multiple data in the application"
805            self._data_menu.Append(data_folder_id, 
806                             '&Load Data Folder', data_folder_hint)
807            wx.EVT_MENU(self, data_folder_id, self._load_folder)
808            self._menubar.Append(self._data_menu, '&Data')
[4753fc2]809        elif style1 == GUIFRAME.DATALOADER_ON:
[3feed3e]810            self._menubar.Append(self._data_menu, '&Data')
[52b8b74]811       
812    def _load_data(self, event):
813        """
814        connect menu item load data with the first plugin that can load data
815        """
816        for plug in self.plugins:
817            if plug.can_load_data():
818                plug.load_data(event)
[6db811e]819        style = self.__gui_style & GUIFRAME.MANAGER_ON
820        if style == GUIFRAME.MANAGER_ON:
821            self.show_data_panel(event=None)
822       
[52b8b74]823    def _load_folder(self, event):
824        """
825        connect menu item load data with the first plugin that can load data and
826        folder
827        """
828        for plug in self.plugins:
829            if plug.can_load_data():
830                plug.load_folder(event)
[6db811e]831        style = self.__gui_style & GUIFRAME.MANAGER_ON
832        if style == GUIFRAME.MANAGER_ON:
833            self.show_data_panel(event=None)
[52b8b74]834               
[a45037aa]835    def _on_hide_toolbar(self, event=None):
836        """
837        hide or show toolbar
838        """
839        if self._toolbar is None:
840            return
841        if self._toolbar.IsShown():
842            if self._toolbar_menu is not None:
843                self._toolbar_menu.SetItemLabel('Show Toolbar')
844            self._toolbar.Hide()
845        else:
846            if self._toolbar_menu is not None:
847                self._toolbar_menu.SetItemLabel('Hide Toolbar')
848            self._toolbar.Show()
849        self._toolbar.Realize()
850       
[41d466f]851    def _on_status_event(self, evt):
852        """
[d955bf19]853        Display status message
[41d466f]854        """
[db10f97]855        self.sb.set_status(event=evt)
[dd66fbd]856       
[41d466f]857    def _on_view(self, evt):
858        """
[d955bf19]859        A panel was selected to be shown. If it's not already
860        shown, display it.
861       
862        :param evt: menu event
863       
[41d466f]864        """
865        self.show_panel(evt.GetId())
[c1469ebe]866       
[b28278e]867    def on_close_welcome_panel(self):
[c1469ebe]868        """
[d955bf19]869        Close the welcome panel
[c1469ebe]870        """
[629e8b9]871        if self.defaultPanel is None:
872            return 
[c1469ebe]873        self._mgr.GetPane(self.panels["default"].window_name).Hide()
874        self._mgr.Update()
[b28278e]875        # set a default perspective
876        self.set_default_perspective()
[c1469ebe]877       
878    def show_welcome_panel(self, event):
879        """   
[d955bf19]880        Display the welcome panel
[c1469ebe]881        """
[629e8b9]882        if self.defaultPanel is None:
883            return 
[c1469ebe]884        for id in self.panels.keys():
[c5e84fb]885            if id  ==  'default':
886                # Show default panel
887                if not self._mgr.GetPane(self.panels["default"].window_name).IsShown():
888                    self._mgr.GetPane(self.panels["default"].window_name).Show(True)
889            elif id == "data_panel":
890                flag = self._mgr.GetPane(self.panels["data_panel"].window_name).IsShown()
891                self._mgr.GetPane(self.panels["data_panel"].window_name).Show(flag)
892            else:
893                self._mgr.GetPane(self.panels[id].window_name).IsShown()
[c1469ebe]894                self._mgr.GetPane(self.panels[id].window_name).Hide()
895        self._mgr.Update()
[c5e84fb]896       
[41d466f]897    def show_panel(self, uid):
898        """
[d955bf19]899        Shows the panel with the given id
900       
901        :param uid: unique ID number of the panel to show
902       
[41d466f]903        """
904        ID = str(uid)
905        config.printEVT("show_panel: %s" % ID)
906        if ID in self.panels.keys():
907            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown():
908                self._mgr.GetPane(self.panels[ID].window_name).Show()
[383189f9]909                # Hide default panel
910                self._mgr.GetPane(self.panels["default"].window_name).Hide()
[41d466f]911            self._mgr.Update()
[4e9583c]912   
913    def _on_open(self, event):
[b3644f3]914        """
915        """
[fc2b91a]916        path = self.choose_file()
[4e9583c]917        if path is None:
[700f9b4]918            return
[52725d6]919
[4e9583c]920        if path and os.path.isfile(path):
[32c0841]921            basename  = os.path.basename(path)
922            if  basename.endswith('.svs'):
923                #remove panels for new states
[7a07864]924                for item in self.panels:
925                    try:
926                        self.panels[item].clear_panel()
[32c0841]927                    except:
928                        pass
[7a07864]929                #reset states and plot data
930                for item in STATE_FILE_EXT:
[32c0841]931                    exec "plot_data(self, path,'%s')" % str(item)
932            else:
933                plot_data(self, path)
[aebc4cc]934        if self.defaultPanel is not None and \
935            self._mgr.GetPane(self.panels["default"].window_name).IsShown():
936            self.on_close_welcome_panel()
[b35d3d1]937           
[52725d6]938    def _on_save_application(self, event):
[b35d3d1]939        """
[52725d6]940        save the state of the current active application
[b35d3d1]941        """
942        ## Default file location for save
943        self._default_save_location = os.getcwd()
[52725d6]944        if self._current_perspective is  None:
945            return
946        reader, ext = self._current_perspective.get_extensions()
[b35d3d1]947        path = None
[32c0841]948        dlg = wx.FileDialog(self, "Choose a file",
[52725d6]949                            self._default_save_location, "", ext, wx.SAVE)
[b35d3d1]950        if dlg.ShowModal() == wx.ID_OK:
951            path = dlg.GetPath()
952            self._default_save_location = os.path.dirname(path)
953        else:
954            return None
955        dlg.Destroy()
956        if path is None:
957            return
958        # default cansas xml doc
959        doc = None
[52725d6]960        for panel in self._current_perspective.get_perspective():
961            doc = on_save_helper(doc, reader, panel, path)
962           
963    def _on_save_project(self, event):
964        """
965        save the state of the current active application
966        """
967        ## Default file location for save
968        self._default_save_location = os.getcwd()
969        if self._current_perspective is  None:
970            return
971        reader, ext = self._current_perspective.get_extensions()
972        path = None
973        dlg = wx.FileDialog(self, "Choose a file",
974                            self._default_save_location, "", '.svs', wx.SAVE)
975        if dlg.ShowModal() == wx.ID_OK:
976            path = dlg.GetPath()
977            self._default_save_location = os.path.dirname(path)
978        else:
979            return None
980        dlg.Destroy()
981        if path is None:
982            return
983        # default cansas xml doc
984        doc = None
985        for panel in self.panels.values():
986            doc = self.on_save_helper(doc, reader, panel, path)
987       
988           
989    def on_save_helper(self, doc, reader, panel, path):
990        """
991        Save state into a file
992        """
993        try:
994            data = panel.get_data()
995            state = panel.get_state()
996            if reader is not None:
997                if data is not None:
998                    new_doc = reader.write_toXML(data, state)
999                    if hasattr(doc, "firstChild"):
1000                        child = new_doc.firstChild.firstChild
1001                        doc.firstChild.appendChild(child) 
1002                    else:
1003                        doc = new_doc
1004        except: 
1005            raise
1006            #pass
[b35d3d1]1007        # Write the XML document
1008        if doc != None:
1009            fd = open(path, 'w')
1010            fd.write(doc.toprettyxml())
1011            fd.close()
1012        else:
[52725d6]1013            raise
[32c0841]1014            #print "Nothing to save..."
[52725d6]1015            #raise RuntimeError, "%s is not a SansView (.svs) file..." % path
1016        return doc
[b35d3d1]1017
[b5ca223]1018    def quit_guiframe(self):
1019        """
1020        Pop up message to make sure the user wants to quit the application
1021        """
1022        message = "Do you really want to quit \n"
1023        message += "this application?"
1024        dial = wx.MessageDialog(self, message, 'Question',
1025                           wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
1026        if dial.ShowModal() == wx.ID_YES:
1027            return True
1028        else:
1029            return False   
1030       
[41d466f]1031    def Close(self, event=None):
1032        """
[d955bf19]1033        Quit the application
[41d466f]1034        """
[52725d6]1035        #flag = self.quit_guiframe()
1036        if True:
[ba535a6]1037            wx.Exit()
1038            sys.exit()
[41d466f]1039
1040    def _check_update(self, event=None): 
1041        """
[d955bf19]1042        Check with the deployment server whether a new version
1043        of the application is available.
1044        A thread is started for the connecting with the server. The thread calls
1045        a call-back method when the current version number has been obtained.
[52070a1]1046        """
[d68c655]1047        if hasattr(config, "__update_URL__"):
1048            import version
[32c0841]1049            checker = version.VersionThread(config.__update_URL__,
1050                                            self._process_version,
1051                                            baggage=event==None)
[d68c655]1052            checker.start() 
[52070a1]1053   
1054    def _process_version(self, version, standalone=True):
1055        """
[d955bf19]1056        Call-back method for the process of checking for updates.
1057        This methods is called by a VersionThread object once the current
1058        version number has been obtained. If the check is being done in the
1059        background, the user will not be notified unless there's an update.
1060       
1061        :param version: version string
1062        :param standalone: True of the update is being checked in
1063           the background, False otherwise.
1064           
[52070a1]1065        """
1066        try:
[32c0841]1067            if cmp(version, config.__version__) > 0:
1068                msg = "Version %s is available! See the Help "
1069                msg += "menu to download it." % version
1070                self.SetStatusText(msg)
[52070a1]1071                if not standalone:
1072                    import webbrowser
1073                    webbrowser.open(config.__download_page__)
1074            else:
1075                if not standalone:
[32c0841]1076                    msg = "You have the latest version"
1077                    msg += " of %s" % config.__appname__
1078                    self.SetStatusText(msg)
[41d466f]1079        except:
[32c0841]1080            msg = "guiframe: could not get latest application"
1081            msg += " version number\n  %s" % sys.exc_value
1082            logging.error(msg)
[52070a1]1083            if not standalone:
[32c0841]1084                msg = "Could not connect to the application server."
1085                msg += " Please try again later."
1086                self.SetStatusText(msg)
[52070a1]1087                   
[41d466f]1088    def _onAbout(self, evt):
1089        """
[d955bf19]1090        Pop up the about dialog
1091       
1092        :param evt: menu event
1093       
[41d466f]1094        """
1095        if config._do_aboutbox:
1096            import aboutbox 
1097            dialog = aboutbox.DialogAbout(None, -1, "")
[6ab0ad1]1098            dialog.ShowModal()           
[4e9583c]1099           
[41d466f]1100    def set_manager(self, manager):
1101        """
[d955bf19]1102        Sets the application manager for this frame
1103       
1104        :param manager: frame manager
[41d466f]1105        """
1106        self.app_manager = manager
1107       
1108    def post_init(self):
1109        """
[d955bf19]1110        This initialization method is called after the GUI
1111        has been created and all plug-ins loaded. It calls
1112        the post_init() method of each plug-in (if it exists)
1113        so that final initialization can be done.
[41d466f]1114        """
1115        for item in self.plugins:
1116            if hasattr(item, "post_init"):
1117                item.post_init()
1118       
[b28278e]1119    def set_default_perspective(self):
1120        """
[d955bf19]1121        Choose among the plugin the first plug-in that has
1122        "set_default_perspective" method and its return value is True will be
1123        as a default perspective when the welcome page is closed
[b28278e]1124        """
1125        for item in self.plugins:
1126            if hasattr(item, "set_default_perspective"):
1127                if item.set_default_perspective():
[749eb8a]1128                    item.on_perspective(event=None)
[b28278e]1129                    return 
[f444b20]1130       
[41d466f]1131    def set_perspective(self, panels):
1132        """
[d955bf19]1133        Sets the perspective of the GUI.
1134        Opens all the panels in the list, and closes
1135        all the others.
1136       
1137        :param panels: list of panels
[41d466f]1138        """
1139        for item in self.panels:
1140            # Check whether this is a sticky panel
1141            if hasattr(self.panels[item], "ALWAYS_ON"):
1142                if self.panels[item].ALWAYS_ON:
1143                    continue 
1144            if self.panels[item].window_name in panels:
1145                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
1146                    self._mgr.GetPane(self.panels[item].window_name).Show()
1147            else:
[3feed3e]1148                # always show the data panel if enable
1149                style = self.__gui_style & GUIFRAME.MANAGER_ON
1150                if (style == GUIFRAME.MANAGER_ON) and self.panels[item] == self._data_panel:
1151                    if 'data_panel' in self.panels.keys():
1152                        flag = self._mgr.GetPane(self.panels['data_panel'].window_name).IsShown()
1153                        self._mgr.GetPane(self.panels['data_panel'].window_name).Show(flag)
1154                else:
1155                    if self._mgr.GetPane(self.panels[item].window_name).IsShown():
1156                        self._mgr.GetPane(self.panels[item].window_name).Hide()
[41d466f]1157        self._mgr.Update()
[4e9583c]1158       
[213892bc]1159    def show_data_panel(self, event=None):
[52b8b74]1160        """
[3feed3e]1161        show the data panel
[52b8b74]1162        """
[3feed3e]1163        pane = self._mgr.GetPane(self.panels["data_panel"].window_name)
[213892bc]1164        #if not pane.IsShown():
1165        pane.Show(True)
1166        self._mgr.Update()
[c5e84fb]1167 
[52725d6]1168    def add_data(self, data_list, flag=False):
[f444b20]1169        """
1170        receive a list of data . store them its data manager if possible
1171        determine if data was be plot of send to data perspectives
1172        """
[52b8b74]1173        #send a list of available data to plotting plugin
1174        avalaible_data = []
1175        if self._data_manager is not None:
1176            self._data_manager.add_data(data_list)
1177            avalaible_data = self._data_manager.get_all_data()
1178           
[ec489f5]1179        if True:
[52725d6]1180            #reading a state file
1181            for plug in self.plugins:
1182                plug.on_set_state_helper(event=None)
[3feed3e]1183        style = self.__gui_style & GUIFRAME.MANAGER_ON
1184        if style == GUIFRAME.MANAGER_ON:
1185            if self._data_panel is not None:
[c5e84fb]1186                data_state = self._data_manager.get_selected_data()
1187                self._data_panel.load_data_list(data_state)
[3feed3e]1188                self._mgr.GetPane(self._data_panel.window_name).Show(True)
1189                #wait for button press from the data panel to send data
1190        else:
1191            #automatically send that to the current perspective
1192            style = self.__gui_style & GUIFRAME.SINGLE_APPLICATION
1193            if style == GUIFRAME.SINGLE_APPLICATION:
[c5e84fb]1194                self.set_data(data_list)
1195               
[213892bc]1196    def get_data_from_panel(self, data_id, plot=False,append=False):
[c5e84fb]1197        """
1198        receive a list of data key retreive the data from data manager and set
1199        then to the current perspective
1200        """
[584c4c4]1201        data_dict = self._data_manager.get_by_id(data_id)
1202        data_list = []
1203        for data_state in data_dict.values():
1204            data_list.append(data_state.data)
1205        if plot:
[213892bc]1206            self.plot_data(data_list, append=append)
[584c4c4]1207        else:
1208            #sent data to active application
1209            self.set_data(data_list=data_list)
1210       
[c5e84fb]1211       
1212    def set_data(self, data_list):
1213        """
1214        set data to current perspective
1215        """
1216        if self._current_perspective is not None:
1217            try:
1218                self._current_perspective.set_data(data_list)
1219            except:
1220                msg = str(sys.exc_value)
1221                wx.PostEvent(self, StatusEvent(status=msg, info="error"))
1222        else:
1223            msg = "Guiframe does not have a current perspective"
1224            logging.info(msg)
[3feed3e]1225           
[213892bc]1226    def plot_data(self, data_list, append=False):
[f444b20]1227        """
1228        send a list of data to plot
1229        """
[213892bc]1230        if not data_list:
1231            message = "Please check data to plot or append"
1232            wx.PostEvent(self, StatusEvent(status=message, info='warning'))
1233            return 
[f444b20]1234        for new_plot in data_list:
[213892bc]1235            if append:
[6db811e]1236                if self.panel_on_focus is None or \
1237                    not self.enable_add_data(new_plot):
[213892bc]1238                    message = "cannot append plot. No plot panel on focus!"
1239                    message += "please click on any available plot to set focus"
1240                    wx.PostEvent(self, StatusEvent(status=message, 
1241                                                   info='warning'))
1242                    return 
1243                else:
[d828481]1244                    if self.enable_add_data(new_plot) and \
1245                    hasattr(self.panel_on_focus, 'group_id'):
[213892bc]1246                        new_plot.group_id = self.panel_on_focus.group_id
[f444b20]1247            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
1248                                                  title=str(new_plot.title)))
1249           
[213892bc]1250    def add_theory(self, data_id, theory):
1251        """
1252        """
1253        self._data_manager.append_theory(data_id, theory)
1254        style = self.__gui_style & GUIFRAME.MANAGER_ON
1255        if style == GUIFRAME.MANAGER_ON:
1256            if self._data_panel is not None:
1257                data_state = self._data_manager.get_by_id([data_id])
1258                self._data_panel.load_data_list(data_state)
1259               
1260    def delete_data(self, data_id, theory_id=None, delete_all=True):
1261        """
1262        Delete data state if data_id is provide
1263        delete theory created with data of id data_id if theory_id is provide
1264        if delete all true: delete the all state
1265        else delete theory
1266        """
1267        self._data_manager.delete_data(data_id=data_id, 
1268                                       theory_id=theory_id, 
1269                                       delete_all=delete_all)
[6db811e]1270        for plug in self.plugins:
1271            plug.delete_data(data_id)
1272           
[213892bc]1273       
[f444b20]1274    def set_current_perspective(self, perspective):
1275        """
1276        set the current active perspective
1277        """
[f036c692]1278       
[f444b20]1279        self._current_perspective = perspective
[c5e84fb]1280        name = "No current Application selected"
[cbf22e5]1281        if self._current_perspective is not None:
1282            self._add_current_plugin_menu()
[a45037aa]1283            for panel in self.panels.values():
1284                if hasattr(panel, 'CENTER_PANE') and panel.CENTER_PANE:
1285                    for name in self._current_perspective.get_perspective():
1286                        print "current",name.lower(),panel.window_name.lower(), name == panel.window_name
1287                        if name == panel.window_name:
1288                            panel.on_set_focus(event=None)
1289                            print "panel", name,  panel.window_name,  panel.window_caption
1290                            break
1291                           
[f036c692]1292            name = self._current_perspective.sub_menu
[cbf22e5]1293            if self._data_panel is not None:
1294                self._data_panel.set_active_perspective(name)
[95f9cc4]1295                self._check_applications_menu()
[a45037aa]1296            ##update tool bar
1297            #if self._toolbar is not None:
1298            #    self._update_toolbar_helper()
[95f9cc4]1299               
1300    def _check_applications_menu(self):
1301        """
1302        check the menu of the current application
1303        """
1304        if self._applications_menu is not None:
1305            for menu in self._applications_menu.GetMenuItems():
1306                if self._current_perspective is not None:
1307                    name = self._current_perspective.sub_menu
1308                    if menu.IsCheckable():
1309                        if menu.GetLabel() == name:
1310                            menu.Check(True)
1311                        else:
1312                             menu.Check(False) 
[c5e84fb]1313           
[213892bc]1314    def set_plotpanel_floating(self, event=None):
[7a67e075]1315        """
1316        make the plot panel floatable
1317        """
[0663dfb1]1318        self.__gui_style &= (~GUIFRAME.FIXED_PANEL)
[3feed3e]1319        self.__gui_style |= GUIFRAME.FLOATING_PANEL
1320        for p in self.panels.values():
1321            plot_panel = self._plotting_plugin.plot_panels
1322            for p in self.panels.values():
1323                if p in plot_panel:
1324                    self._popup_floating_panel(p)
1325       
[213892bc]1326    def set_plotpanel_fixed(self, event=None):
[7a67e075]1327        """
1328        make the plot panel fixed
1329        """
[0663dfb1]1330        self.__gui_style &= (~GUIFRAME.FLOATING_PANEL)
[3feed3e]1331        self.__gui_style |= GUIFRAME.FIXED_PANEL
1332        plot_panel = []
1333        if self._plotting_plugin is not None:
1334            plot_panel = self._plotting_plugin.plot_panels
1335            for p in self.panels.values():
1336                if p in plot_panel:
1337                    self._popup_fixed_panel(p)
1338                   
1339    def _popup_fixed_panel(self, p):
1340        """
1341        """
1342        style = self.__gui_style & GUIFRAME.FIXED_PANEL
1343        if style == GUIFRAME.FIXED_PANEL:
1344            self._mgr.GetPane(p.window_name).Floatable()
1345            self._mgr.GetPane(p.window_name).Right()
1346            self._mgr.GetPane(p.window_name).TopDockable(False)
1347            self._mgr.GetPane(p.window_name).BottomDockable(False)
1348            self._mgr.GetPane(p.window_name).LeftDockable(False)
1349            self._mgr.GetPane(p.window_name).RightDockable(True)
1350            flag = self._mgr.GetPane(p.window_name).IsShown()
1351            self._mgr.GetPane(p.window_name).Show(flag)
1352            self._mgr.Update()
1353           
1354    def _popup_floating_panel(self, p):
1355        """
1356        """
1357        style = self.__gui_style &  GUIFRAME.FLOATING_PANEL
1358        if style == GUIFRAME.FLOATING_PANEL: 
1359            self._mgr.GetPane(p.window_name).Floatable(True)
1360            self._mgr.GetPane(p.window_name).Float()
1361            self._mgr.GetPane(p.window_name).Dockable(False)
1362            flag = self._mgr.GetPane(p.window_name).IsShown()
1363            self._mgr.GetPane(p.window_name).Show(flag)
1364            self._mgr.Update()
[213892bc]1365           
1366    def enable_add_data(self, new_plot):
1367        """
1368        Enable append data on a plot panel
1369        """
1370        is_theory = len(self.panel_on_focus.plots) <= 1 and \
1371            self.panel_on_focus.plots.values()[0].__class__.__name__ == "Theory1D"
1372           
1373        is_data2d = hasattr(new_plot, 'data')
1374        is_data1d = self.panel_on_focus.__class__.__name__ == "ModelPanel1D"\
1375            and self.panel_on_focus.group_id is not None
1376        has_meta_data = hasattr(new_plot, 'meta_data')
1377       
1378        #disable_add_data if the data is being recovered from  a saved state file.
1379        is_state_data = False
1380        if has_meta_data:
1381            if 'invstate' in new_plot.meta_data: is_state_data = True
1382            if  'prstate' in new_plot.meta_data: is_state_data = True
1383            if  'fitstate' in new_plot.meta_data: is_state_data = True
1384   
1385        return is_data1d and not is_data2d and not is_theory and not is_state_data
[d828481]1386   
[f036c692]1387    def enable_edit_menu(self):
1388        """
1389        enable menu item under edit menu depending on the panel on focus
1390        """
1391        if self.panel_on_focus is not None and self._edit_menu is not None:
[a45037aa]1392            flag = self.panel_on_focus.get_undo_flag()
[f036c692]1393            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
[a45037aa]1394            flag = self.panel_on_focus.get_redo_flag()
[f036c692]1395            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
[a45037aa]1396            flag = self.panel_on_focus.get_bookmark_flag()
[f036c692]1397            self._edit_menu.Enable(GUIFRAME_ID.BOOKMARK_ID, flag)
[a45037aa]1398            flag = self.panel_on_focus.get_save_flag()
[f036c692]1399            self._edit_menu.Enable(GUIFRAME_ID.SAVE_ID, flag)
[a45037aa]1400            flag = self.panel_on_focus.get_print_flag()
[f036c692]1401            self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
[a45037aa]1402            flag = self.panel_on_focus.get_preview_flag()
[f036c692]1403            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
[a45037aa]1404            flag = self.panel_on_focus.get_zoom_flag()
[f036c692]1405            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_ID, flag)
[a45037aa]1406            flag = self.panel_on_focus.get_zoom_in_flag()
[f036c692]1407            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_IN_ID, flag)
[a45037aa]1408            flag = self.panel_on_focus.get_zoom_out_flag()
[f036c692]1409            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_OUT_ID, flag)
[a45037aa]1410            flag = self.panel_on_focus.get_drag_flag()
[f036c692]1411            self._edit_menu.Enable(GUIFRAME_ID.DRAG_ID, flag)
[a45037aa]1412            flag = self.panel_on_focus.get_reset_flag()
[f036c692]1413            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
1414        else:
1415            flag = False
1416            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
1417            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
1418            self._edit_menu.Enable(GUIFRAME_ID.BOOKMARK_ID, flag)
1419            self._edit_menu.Enable(GUIFRAME_ID.SAVE_ID, flag)
1420            self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
1421            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
1422            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_ID, flag)
1423            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_IN_ID, flag)
1424            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_OUT_ID, flag)
1425            self._edit_menu.Enable(GUIFRAME_ID.DRAG_ID, flag)
1426            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
1427           
[d828481]1428    def on_undo_panel(self, event=None):
1429        """
1430        undo previous action of the last panel on focus if possible
1431        """
[f036c692]1432        if self.panel_on_focus is not None:
1433            self.panel_on_focus.on_undo(event)
1434           
[d828481]1435    def on_redo_panel(self, event=None):
1436        """
1437        redo the last cancel action done on the last panel on focus
1438        """
[f036c692]1439        if self.panel_on_focus is not None:
1440            self.panel_on_focus.on_redo(event)
1441           
[d828481]1442    def on_bookmark_panel(self, event=None):
1443        """
1444        Bookmark available information of the panel on focus
1445        """
[f036c692]1446        if self.panel_on_focus is not None:
1447            self.panel_on_focus.on_bookmark(event)
1448           
[d828481]1449    def on_save_panel(self, event=None):
1450        """
1451        save possible information on the current panel
1452        """
[f036c692]1453        if self.panel_on_focus is not None:
1454            self.panel_on_focus.on_save(event)
1455           
[d828481]1456    def on_preview_panel(self, event=None):
1457        """
1458        preview information on the panel on focus
1459        """
[f036c692]1460        if self.panel_on_focus is not None:
1461            self.panel_on_focus.on_preview(event)
1462           
[d828481]1463    def on_print_panel(self, event=None):
1464        """
1465        print available information on the last panel on focus
1466        """
[f036c692]1467        if self.panel_on_focus is not None:
1468            self.panel_on_focus.on_print(event)
1469           
[d828481]1470    def on_zoom_panel(self, event=None):
1471        """
1472        zoom on the current panel if possible
1473        """
[f036c692]1474        if self.panel_on_focus is not None:
1475            self.panel_on_focus.on_zoom(event)
1476           
[d828481]1477    def on_zoom_in_panel(self, event=None):
1478        """
1479        zoom in of the panel on focus
1480        """
[f036c692]1481        if self.panel_on_focus is not None:
1482            self.panel_on_focus.on_zoom_in(event)
1483           
[d828481]1484    def on_zoom_out_panel(self, event=None):
1485        """
1486        zoom out on the panel on focus
1487        """
[f036c692]1488        if self.panel_on_focus is not None:
1489            self.panel_on_focus.on_zoom_out(event)
1490           
[d828481]1491    def on_drag_panel(self, event=None):
1492        """
1493        drag apply to the panel on focus
1494        """
[f036c692]1495        if self.panel_on_focus is not None:
1496            self.panel_on_focus.on_drag(event)
1497           
[d828481]1498    def on_reset_panel(self, event=None):
1499        """
1500        reset the current panel
1501        """
[f036c692]1502        if self.panel_on_focus is not None:
1503            self.panel_on_focus.on_reset(event)
[3feed3e]1504       
[d828481]1505class DefaultPanel(wx.Panel, PanelBase):
[41d466f]1506    """
[d955bf19]1507    Defines the API for a panels to work with
1508    the GUI manager
[41d466f]1509    """
1510    ## Internal nickname for the window, used by the AUI manager
1511    window_name = "default"
1512    ## Name to appear on the window title bar
1513    window_caption = "Welcome panel"
1514    ## Flag to tell the AUI manager to put this panel in the center pane
1515    CENTER_PANE = True
[d828481]1516   
[41d466f]1517
[4753fc2]1518
[41d466f]1519# Toy application to test this Frame
1520class ViewApp(wx.App):
[d955bf19]1521    """
1522    """
[3385795]1523    SIZE = (GUIFRAME_WIDTH,GUIFRAME_HEIGHT)
1524    TITLE = config.__appname__
1525    PROG_SPLASH_PATH = PROG_SPLASH_SCREEN
[d828481]1526    STYLE = GUIFRAME.SINGLE_APPLICATION
[41d466f]1527    def OnInit(self):
[d955bf19]1528        """
1529        """
[3385795]1530        pos, size = self.window_placement(self.SIZE)
1531        self.frame = ViewerFrame(parent=None, 
1532                                 title=self.TITLE, 
1533                                 pos=pos, 
1534                                 gui_style = self.STYLE,
1535                                 size=size) 
1536         # Display a splash screen on top of the frame.
1537        if len(sys.argv) > 1 and '--time' in sys.argv[1:]:
1538            log_time("Starting to display the splash screen")
1539        if self.PROG_SPLASH_PATH is not None and \
1540            os.path.isfile(self.PROG_SPLASH_PATH):
1541            try:
1542                self.display_splash_screen(parent=self.frame, path=self.PROG_SPLASH_PATH)   
1543            except:
1544                msg = "Cannot display splash screen\n"
1545                msg += str (sys.exc_value)
1546                logging.error(msg)
[41d466f]1547        self.frame.Show(True)
1548
1549        if hasattr(self.frame, 'special'):
1550            self.frame.special.SetCurrent()
1551        self.SetTopWindow(self.frame)
1552        return True
1553   
1554    def set_manager(self, manager):
1555        """
[d955bf19]1556        Sets a reference to the application manager
1557        of the GUI manager (Frame)
[41d466f]1558        """
1559        self.frame.set_manager(manager)
1560       
[278cc25]1561    def build_gui(self):
1562        """
[d955bf19]1563        Build the GUI
[278cc25]1564        """
1565        self.frame.build_gui()
1566        self.frame.post_init()
1567       
[f9e803e]1568    def set_welcome_panel(self, panel_class):
1569        """
[d955bf19]1570        Set the welcome panel
1571       
1572        :param panel_class: class of the welcome panel to be instantiated
1573       
[f9e803e]1574        """
1575        self.frame.set_welcome_panel(panel_class)
1576       
[278cc25]1577    def add_perspective(self, perspective):
1578        """
[d955bf19]1579        Manually add a perspective to the application GUI
[278cc25]1580        """
1581        self.frame.add_perspective(perspective)
[3385795]1582   
1583    def window_placement(self, size):
1584        """
1585        Determines the position and size of the application frame such that it
1586        fits on the user's screen without obstructing (or being obstructed by)
1587        the Windows task bar.  The maximum initial size in pixels is bounded by
1588        WIDTH x HEIGHT.  For most monitors, the application
1589        will be centered on the screen; for very large monitors it will be
1590        placed on the left side of the screen.
1591        """
1592        window_width, window_height = size
1593        screen_size = wx.GetDisplaySize()
1594        window_height = window_height if screen_size[1]>window_height else screen_size[1]-50
1595        window_width  = window_width if screen_size[0]> window_width else screen_size[0]-50
1596        xpos = ypos = 0
1597
1598        # Note that when running Linux and using an Xming (X11) server on a PC
1599        # with a dual  monitor configuration, the reported display size may be
1600        # that of both monitors combined with an incorrect display count of 1.
1601        # To avoid displaying this app across both monitors, we check for
1602        # screen 'too big'.  If so, we assume a smaller width which means the
1603        # application will be placed towards the left hand side of the screen.
1604
1605        _, _, x, y = wx.Display().GetClientArea() # size excludes task bar
1606        if len(sys.argv) > 1 and '--platform' in sys.argv[1:]:
1607            w, h = wx.DisplaySize()  # size includes task bar area
1608            print "*** Reported screen size including taskbar is %d x %d"%(w, h)
1609            print "*** Reported screen size excluding taskbar is %d x %d"%(x, y)
1610
1611        if x > 1920: x = 1280  # display on left side, not centered on screen
1612        if x > window_width:  xpos = (x - window_width)/2
1613        if y > window_height: ypos = (y - window_height)/2
1614
1615        # Return the suggested position and size for the application frame.
1616        return (xpos, ypos), (min(x, window_width), min(y, window_height))
1617   
1618    def display_splash_screen(self, parent, path=PROG_SPLASH_SCREEN):
1619        """Displays the splash screen.  It will exactly cover the main frame."""
1620
1621        # Prepare the picture.  On a 2GHz intel cpu, this takes about a second.
1622        x, y = parent.GetSizeTuple()
1623        image = wx.Image(path, wx.BITMAP_TYPE_PNG)
1624        image.Rescale(x, y, wx.IMAGE_QUALITY_HIGH)
1625        bm = image.ConvertToBitmap()
1626
1627        # Create and show the splash screen.  It will disappear only when the
1628        # program has entered the event loop AND either the timeout has expired
1629        # or the user has left clicked on the screen.  Thus any processing
1630        # performed in this routine (including sleeping) or processing in the
1631        # calling routine (including doing imports) will prevent the splash
1632        # screen from disappearing.
1633        #
1634        # Note that on Linux, the timeout appears to occur immediately in which
1635        # case the splash screen disappears upon entering the event loop.
1636        wx.SplashScreen(bitmap=bm,
1637                        splashStyle=(wx.SPLASH_CENTRE_ON_PARENT|
1638                                     wx.SPLASH_TIMEOUT|
1639                                     wx.STAY_ON_TOP),
1640                        milliseconds=4000,
1641                        parent=parent,
1642                        id=wx.ID_ANY)
1643
1644        # Keep the splash screen up a minimum amount of time for non-Windows
1645        # systems.  This is a workaround for Linux and possibly MacOS that
1646        # appear to ignore the splash screen timeout option.
1647        if '__WXMSW__' not in wx.PlatformInfo:
1648            if len(sys.argv) > 1 and '--time' in sys.argv[1:]:
1649                log_time("Starting sleep of 2 secs")
1650            time.sleep(2)
1651
1652        # A call to wx.Yield does not appear to be required.  If used on
1653        # Windows, the cursor changes from 'busy' to 'ready' before the event
1654        # loop is reached which is not desirable.  On Linux it seems to have
1655        # no effect.
1656        #wx.Yield()
1657
[278cc25]1658       
[41d466f]1659
1660if __name__ == "__main__": 
1661    app = ViewApp(0)
[32c0841]1662    app.MainLoop()
1663
1664             
Note: See TracBrowser for help on using the repository browser.