source: sasview/guiframe/gui_manager.py @ cacbd7d

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 cacbd7d was f444b20, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on guiframe loading

  • Property mode set to 100644
File size: 34.0 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
40from sans.guiframe.events import EVT_ADD_MANY_DATA
41from sans.guiframe.events import StatusEvent
42from sans.guiframe.events import NewPlotEvent
43
[adfcab3]44
[f444b20]45STATE_FILE_EXT = ['.inv', '.fitv', '.prv']
[b5ca223]46
[f444b20]47DATA_MANAGER = False
48AUTO_PLOT = False
49AUTO_SET_DATA = True
[7681bac]50
[41d466f]51class ViewerFrame(wx.Frame):
52    """
[d955bf19]53    Main application frame
[41d466f]54    """
[f444b20]55   
56    def __init__(self, parent, id, title, 
57                 window_height=300, window_width=300):
[41d466f]58        """
[d955bf19]59        Initialize the Frame object
[41d466f]60        """
[b7c7a1c]61       
[32c0841]62        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition,
63                          size=(window_width, window_height))
[d0802c3]64        # Preferred window size
65        self._window_height = window_height
66        self._window_width  = window_width
[41d466f]67       
[fc2b91a]68        # Logging info
69        logging.basicConfig(level=logging.DEBUG,
70                    format='%(asctime)s %(levelname)s %(message)s',
71                    filename='sans_app.log',
72                    filemode='w')       
[c44e7cc]73        path = os.path.dirname(__file__)
[32c0841]74        temp_path = os.path.join(path,'images')
[c44e7cc]75        ico_file = os.path.join(temp_path,'ball.ico')
[278cc25]76        if os.path.isfile(ico_file):
77            self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
[cbb2e40]78        else:
[32c0841]79            temp_path = os.path.join(os.getcwd(),'images')
[c44e7cc]80            ico_file = os.path.join(temp_path,'ball.ico')
[cbb2e40]81            if os.path.isfile(ico_file):
82                self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
[41d466f]83       
84        ## Application manager
85        self.app_manager = None
[32c0841]86        self._mgr = None
[f444b20]87        #data manager
88        from .data_manager import DataManager
89        self.data_manager = DataManager()
90        #add current perpsective
91        self._current_perspective = None
92        #file menu
[32c0841]93        self.file_menu = None
[4e9583c]94       
[41d466f]95        ## Find plug-ins
96        # Modify this so that we can specify the directory to look into
[32c0841]97        self.plugins = []
[b7c7a1c]98        #add local plugin
99     
100        from sans.guiframe.local_perspectives.plotting import plotting
101        from sans.guiframe.local_perspectives.data_loader import data_loader
[41d466f]102        self.plugins.append(plotting.Plugin())
[b7c7a1c]103        self.plugins.append(data_loader.Plugin())
104       
[a88ac04]105        self.plugins += self._find_plugins()
106     
[41d466f]107        ## List of panels
108        self.panels = {}
109
110        ## Next available ID for wx gui events
[2310d69]111        #TODO:  No longer used - remove all calls to this
[41d466f]112        self.next_id = 20000
113
[2310d69]114        # Default locations
115        self._default_save_location = os.getcwd()       
[f444b20]116       
[f9e803e]117        # Welcome panel
118        self.defaultPanel = None
[b91c736]119        #panel on focus
120        self.panel_on_focus = None
[a0d56d5]121        # Check for update
[af20f6b]122        #self._check_update(None)
[278cc25]123        # Register the close event so it calls our own method
124        wx.EVT_CLOSE(self, self._onClose)
125        # Register to status events
126        self.Bind(EVT_STATUS, self._on_status_event)
[b91c736]127        #Register add extra data on the same panel event on load
128        self.Bind(EVT_ADD_MANY_DATA, self.set_panel_on_focus)
129       
130    def set_panel_on_focus(self, event):
131        """
[d955bf19]132        Store reference to the last panel on focus
[b91c736]133        """
134        self.panel_on_focus = event.panel
[0bd2cd8]135       
[278cc25]136    def build_gui(self):
[d955bf19]137        """
138        """
[41d466f]139        # Set up the layout
140        self._setup_layout()
141       
142        # Set up the menu
143        self._setup_menus()
[c9454bb]144        #self.Fit()
[af20f6b]145        #self._check_update(None)
[41d466f]146             
147    def _setup_layout(self):
148        """
[d955bf19]149        Set up the layout
[41d466f]150        """
151        # Status bar
[db10f97]152        from statusbar import StatusBar
153        self.sb = StatusBar(self, wx.ID_ANY)
[dd66fbd]154        self.SetStatusBar(self.sb)
[41d466f]155        # Add panel
156        self._mgr = wx.aui.AuiManager(self)
[c9454bb]157        self._mgr.SetDockSizeConstraint(0.5, 0.5) 
[41d466f]158        # Load panels
159        self._load_panels()
160        self._mgr.Update()
[db10f97]161       
162    def SetStatusText(self, *args, **kwds):
[d955bf19]163        """
164        """
[db10f97]165        number = self.sb.get_msg_position()
166        wx.Frame.SetStatusText(number=number, *args, **kwds)
167       
168    def PopStatusText(self, *args, **kwds):
[d955bf19]169        """
170        """
[db10f97]171        field = self.sb.get_msg_position()
172        wx.Frame.PopStatusText(field=field)
173       
174    def PushStatusText(self, *args, **kwds):
[d955bf19]175        """
176        """
[db10f97]177        field = self.sb.get_msg_position()
[32c0841]178        wx.Frame.PushStatusText(self, field=field, string=string)
[278cc25]179
180    def add_perspective(self, plugin):
181        """
[d955bf19]182        Add a perspective if it doesn't already
183        exist.
[278cc25]184        """
185        is_loaded = False
186        for item in self.plugins:
[32c0841]187            if plugin.__class__ == item.__class__:
[f444b20]188                msg = "Plugin %s already loaded" % plugin.__class__.__name__
189                logging.info(msg)
[32c0841]190                is_loaded = True   
[278cc25]191        if not is_loaded:
192            self.plugins.append(plugin)
[41d466f]193     
194    def _find_plugins(self, dir="perspectives"):
195        """
[d955bf19]196        Find available perspective plug-ins
197       
198        :param dir: directory in which to look for plug-ins
199       
200        :return: list of plug-ins
201       
[41d466f]202        """
203        import imp
204        plugins = []
205        # Go through files in panels directory
206        try:
207            list = os.listdir(dir)
[a88ac04]208            ## the default panel is the panel is the last plugin added
209            for item in list:
[41d466f]210                toks = os.path.splitext(os.path.basename(item))
211                name = None
212                if not toks[0] == '__init__':
213                   
[32c0841]214                    if toks[1] == '.py' or toks[1] == '':
[41d466f]215                        name = toks[0]
216               
217                    path = [os.path.abspath(dir)]
218                    file = None
219                    try:
[32c0841]220                        if toks[1] == '':
[41d466f]221                            mod_path = '.'.join([dir, name])
[32c0841]222                            module = __import__(mod_path, globals(),
223                                                locals(), [name])
[41d466f]224                        else:
225                            (file, path, info) = imp.find_module(name, path)
[32c0841]226                            module = imp.load_module( name, file, item, info)
[41d466f]227                        if hasattr(module, "PLUGIN_ID"):
[f444b20]228                            try: 
229                                plug = module.Plugin()
230                                if plug.set_default_perspective():
231                                    self._current_perspective = plug
232                                plugins.append(plug)
[32c0841]233                                msg = "Found plug-in: %s" % module.PLUGIN_ID
234                                logging.info(msg)
[41d466f]235                            except:
[32c0841]236                                msg = "Error accessing PluginPanel"
237                                msg += " in %s\n  %s" % (name, sys.exc_value)
238                                config.printEVT(msg)
[41d466f]239                    except:
[32c0841]240                        #print sys.exc_value
241                        msg = "ViewerFrame._find_plugins: %s" % sys.exc_value
242                        logging.error(msg)
[41d466f]243                    finally:
[32c0841]244                        if not file == None:
[41d466f]245                            file.close()
246        except:
[32c0841]247            # Should raise and catch at a higher level and
248            # display error on status bar
[41d466f]249            pass   
250        return plugins
251   
[f9e803e]252    def set_welcome_panel(self, panel_class):
253        """
[d955bf19]254        Sets the default panel as the given welcome panel
255       
256        :param panel_class: class of the welcome panel to be instantiated
257       
[f9e803e]258        """
[d955bf19]259        self.defaultPanel = panel_class(self, -1, style=wx.RAISED_BORDER)
[b28278e]260       
[41d466f]261    def _load_panels(self):
262        """
[d955bf19]263        Load all panels in the panels directory
[41d466f]264        """
265       
266        # Look for plug-in panels
[c1469ebe]267        panels = []   
[41d466f]268        for item in self.plugins:
269            if hasattr(item, "get_panels"):
270                ps = item.get_panels(self)
271                panels.extend(ps)
272
273        # Show a default panel with some help information
274        # It also sets the size of the application windows
[c9454bb]275        #TODO: Use this for slpash screen
[f9e803e]276        if self.defaultPanel is None:
[32c0841]277            self.defaultPanel = DefaultPanel(self, -1, style=wx.RAISED_BORDER)
[f9e803e]278           
[41d466f]279        self.panels["default"] = self.defaultPanel
[ca88b2e]280       
[41d466f]281        self._mgr.AddPane(self.defaultPanel, wx.aui.AuiPaneInfo().
282                              Name("default").
283                              CenterPane().
[32c0841]284                              # This is where we set the size of
285                              # the application window
286                              BestSize(wx.Size(self._window_width, 
287                                               self._window_height)).
288                              #MinSize(wx.Size(self._window_width,
289                              #self._window_height)).
[41d466f]290                              Show())
[6d920cd]291     
[41d466f]292        # Add the panels to the AUI manager
293        for panel_class in panels:
294            p = panel_class
295            id = wx.NewId()
296           
297            # Check whether we need to put this panel
298            # in the center pane
[6f59a98]299            if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
[41d466f]300                if p.CENTER_PANE:
301                    self.panels[str(id)] = p
302                    self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
303                                          Name(p.window_name).Caption(p.window_caption).
304                                          CenterPane().
[c9454bb]305                                          #BestSize(wx.Size(550,600)).
306                                          #MinSize(wx.Size(500,500)).
[41d466f]307                                          Hide())
308            else:
309                self.panels[str(id)] = p
310                self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
311                                  Name(p.window_name).Caption(p.window_caption).
312                                  Right().
313                                  Dock().
314                                  TopDockable().
315                                  BottomDockable().
316                                  LeftDockable().
317                                  RightDockable().
318                                  MinimizeButton().
[c9454bb]319                                  Hide())
320                                  #BestSize(wx.Size(550,600)))
321                                  #MinSize(wx.Size(500,500)))                 
[b28278e]322     
[2310d69]323    def get_context_menu(self, graph=None):
[41d466f]324        """
[d955bf19]325        Get the context menu items made available
326        by the different plug-ins.
327        This function is used by the plotting module
[41d466f]328        """
329        menu_list = []
330        for item in self.plugins:
331            if hasattr(item, "get_context_menu"):
[2310d69]332                menu_list.extend(item.get_context_menu(graph))
[41d466f]333        return menu_list
334       
335    def popup_panel(self, p):
336        """
[d955bf19]337        Add a panel object to the AUI manager
338       
339        :param p: panel object to add to the AUI manager
[41d466f]340       
[d955bf19]341        :return: ID of the event associated with the new panel [int]
342       
343        """
[41d466f]344        ID = wx.NewId()
345        self.panels[str(ID)] = p
346       
347        count = 0
348        for item in self.panels:
[383189f9]349            if self.panels[item].window_name.startswith(p.window_name): 
[41d466f]350                count += 1
351        windowname = p.window_name
352        caption = p.window_caption
[32c0841]353        if count > 0:
[41d466f]354            windowname += str(count+1)
355            caption += (' '+str(count))
356        p.window_name = windowname
357        p.window_caption = caption
358           
359        self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
360                          Name(windowname).Caption(caption).
361                          Floatable().
362                          #Float().
363                          Right().
364                          Dock().
365                          TopDockable().
366                          BottomDockable().
367                          LeftDockable().
368                          RightDockable().
369                          MinimizeButton().
370                          #Hide().
371                          #Show().
[c9454bb]372                          Resizable(True).
373                          # Use a large best size to make sure the AUI manager
374                          # takes all the available space
[6ab0ad1]375                          BestSize(wx.Size(400,400)))
[d0802c3]376        pane = self._mgr.GetPane(windowname)
377        self._mgr.MaximizePane(pane)
378        self._mgr.RestoreMaximizedPane()
[41d466f]379        # Register for showing/hiding the panel
380        wx.EVT_MENU(self, ID, self._on_view)
381       
382        self._mgr.Update()
383        return ID
384       
[b7c7a1c]385    def _populate_file_menu(self):
386        """
387        Insert menu item under file menu
388        """
389        for plugin in self.plugins:
390            if len(plugin.populate_file_menu()) > 0:
391                for item in plugin.populate_file_menu():
[df23f90]392                    id = wx.NewId()
[f444b20]393                    m_name, m_hint, m_handler = item
[b7c7a1c]394                    self.filemenu.Append(id, m_name, m_hint)
395                    wx.EVT_MENU(self, id, m_handler)
396                self.filemenu.AppendSeparator()
397               
[41d466f]398    def _setup_menus(self):
399        """
[d955bf19]400        Set up the application menus
[41d466f]401        """
402        # Menu
[b7c7a1c]403        self._menubar = wx.MenuBar()
[41d466f]404        # File menu
[b0eee0f0]405        self.filemenu = wx.Menu()
[fc2b91a]406       
[b7c7a1c]407        # some menu of plugin to be seen under file menu
408        self._populate_file_menu()
[ca88b2e]409        id = wx.NewId()
[f444b20]410        self.filemenu.Append(id, '&Save state into File',
411                             'Save project as a SansView (svs) file')
[b35d3d1]412        wx.EVT_MENU(self, id, self._on_save)
413        #self.filemenu.AppendSeparator()
414       
415        id = wx.NewId()
[32c0841]416        self.filemenu.Append(id, '&Quit', 'Exit') 
[fc2b91a]417        wx.EVT_MENU(self, id, self.Close)
[41d466f]418       
[adfcab3]419        # Add sub menus
[b7c7a1c]420        self._menubar.Append(self.filemenu, '&File')
[adfcab3]421       
[6f59a98]422        # Window menu
[41d466f]423        # Attach a menu item for each panel in our
424        # panel list that also appears in a plug-in.
425       
[6f59a98]426        # Only add the panel menu if there is only one perspective and
427        # it has more than two panels.
[32c0841]428        # Note: the first plug-in is always the plotting plug-in.
429        #The first application
[6f59a98]430        # plug-in is always the second one in the list.
[32c0841]431        if len(self.plugins) == 2:
[6f59a98]432            plug = self.plugins[1]
[41d466f]433            pers = plug.get_perspective()
[0d9dae8]434       
[32c0841]435            if len(pers) > 1:
[6f59a98]436                viewmenu = wx.Menu()
437                for item in self.panels:
438                    if item == 'default':
439                        continue
440                    panel = self.panels[item]
441                    if panel.window_name in pers:
[32c0841]442                        viewmenu.Append(int(item), panel.window_caption,
443                                        "Show %s window" % panel.window_caption)
[6f59a98]444                        wx.EVT_MENU(self, int(item), self._on_view)
[b7c7a1c]445                self._menubar.Append(viewmenu, '&Window')
[adfcab3]446
[41d466f]447        # Perspective
448        # Attach a menu item for each defined perspective.
[d68c655]449        # Only add the perspective menu if there are more than one perspectives
[adfcab3]450        n_perspectives = 0
[41d466f]451        for plug in self.plugins:
452            if len(plug.get_perspective()) > 0:
[adfcab3]453                n_perspectives += 1
454       
[32c0841]455        if n_perspectives > 1:
[adfcab3]456            p_menu = wx.Menu()
457            for plug in self.plugins:
458                if len(plug.get_perspective()) > 0:
459                    id = wx.NewId()
[32c0841]460                    p_menu.Append(id, plug.sub_menu,
461                                  "Switch to %s perspective" % plug.sub_menu)
[adfcab3]462                    wx.EVT_MENU(self, id, plug.on_perspective)
[b7c7a1c]463            self._menubar.Append(p_menu, '&Perspective')
[4e9583c]464 
[d68c655]465        # Tools menu
466        # Go through plug-ins and find tools to populate the tools menu
467        toolsmenu = None
468        for item in self.plugins:
469            if hasattr(item, "get_tools"):
470                for tool in item.get_tools():
471                    # Only create a menu if we have at least one tool
472                    if toolsmenu is None:
473                        toolsmenu = wx.Menu()
474                    id = wx.NewId()
475                    toolsmenu.Append(id, tool[0], tool[1])
476                    wx.EVT_MENU(self, id, tool[2])
477        if toolsmenu is not None:
[b7c7a1c]478            self._menubar.Append(toolsmenu, '&Tools')
[d68c655]479 
[41d466f]480        # Help menu
481        helpmenu = wx.Menu()
[c1469ebe]482        # add the welcome panel menu item
[629e8b9]483        if self.defaultPanel is not None:
484            id = wx.NewId()
[32c0841]485            helpmenu.Append(id, '&Welcome', '')
[629e8b9]486            helpmenu.AppendSeparator()
487            wx.EVT_MENU(self, id, self.show_welcome_panel)
[fa452e4]488        # Look for help item in plug-ins
489        for item in self.plugins:
490            if hasattr(item, "help"):
491                id = wx.NewId()
492                helpmenu.Append(id,'&%s help' % item.sub_menu, '')
493                wx.EVT_MENU(self, id, item.help)
[41d466f]494        if config._do_aboutbox:
495            id = wx.NewId()
496            helpmenu.Append(id,'&About', 'Software information')
497            wx.EVT_MENU(self, id, self._onAbout)
[af20f6b]498           
499        # Checking for updates needs major refactoring to work with py2exe
500        # We need to make sure it doesn't hang the application if the server
501        # is not up. We also need to make sure there's a proper executable to
502        # run if we spawn a new background process.
503        #id = wx.NewId()
[32c0841]504        #helpmenu.Append(id,'&Check for update',
505        #'Check for the latest version of %s' % config.__appname__)
[af20f6b]506        #wx.EVT_MENU(self, id, self._check_update)
[41d466f]507       
508        # Look for plug-in menus
509        # Add available plug-in sub-menus.
510        for item in self.plugins:
511            if hasattr(item, "populate_menu"):
[32c0841]512                for (self.next_id, menu, name) in \
513                    item.populate_menu(self.next_id, self):
[b7c7a1c]514                    self._menubar.Append(menu, name)
[0d9dae8]515                   
[b7c7a1c]516        self._menubar.Append(helpmenu, '&Help')
517        self.SetMenuBar(self._menubar)
[d955bf19]518   
[41d466f]519    def _on_status_event(self, evt):
520        """
[d955bf19]521        Display status message
[41d466f]522        """
[db10f97]523        self.sb.set_status(event=evt)
[dd66fbd]524       
[41d466f]525    def _on_view(self, evt):
526        """
[d955bf19]527        A panel was selected to be shown. If it's not already
528        shown, display it.
529       
530        :param evt: menu event
531       
[41d466f]532        """
533        self.show_panel(evt.GetId())
[c1469ebe]534       
[b28278e]535    def on_close_welcome_panel(self):
[c1469ebe]536        """
[d955bf19]537        Close the welcome panel
[c1469ebe]538        """
[629e8b9]539        if self.defaultPanel is None:
540            return 
[c1469ebe]541        self._mgr.GetPane(self.panels["default"].window_name).Hide()
542        self._mgr.Update()
[b28278e]543        # set a default perspective
544        self.set_default_perspective()
[c1469ebe]545       
546    def show_welcome_panel(self, event):
547        """   
[d955bf19]548        Display the welcome panel
[c1469ebe]549        """
[629e8b9]550        if self.defaultPanel is None:
551            return 
[c1469ebe]552        for id in self.panels.keys():
553            if self._mgr.GetPane(self.panels[id].window_name).IsShown():
554                self._mgr.GetPane(self.panels[id].window_name).Hide()
555        # Show default panel
556        if not self._mgr.GetPane(self.panels["default"].window_name).IsShown():
557            self._mgr.GetPane(self.panels["default"].window_name).Show()
558       
559        self._mgr.Update()
560       
[41d466f]561    def show_panel(self, uid):
562        """
[d955bf19]563        Shows the panel with the given id
564       
565        :param uid: unique ID number of the panel to show
566       
[41d466f]567        """
568        ID = str(uid)
569        config.printEVT("show_panel: %s" % ID)
570        if ID in self.panels.keys():
571            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown():
572                self._mgr.GetPane(self.panels[ID].window_name).Show()
[383189f9]573                # Hide default panel
574                self._mgr.GetPane(self.panels["default"].window_name).Hide()
[41d466f]575            self._mgr.Update()
[4e9583c]576   
577    def _on_open(self, event):
[b3644f3]578        """
579        """
[fc2b91a]580        path = self.choose_file()
[4e9583c]581        if path is None:
[700f9b4]582            return
[b3644f3]583       
[4e9583c]584        from data_loader import plot_data
[9b18735]585        from sans.perspectives import invariant
[4e9583c]586        if path and os.path.isfile(path):
[32c0841]587            basename  = os.path.basename(path)
588            if  basename.endswith('.svs'):
589                #remove panels for new states
[7a07864]590                for item in self.panels:
591                    try:
592                        self.panels[item].clear_panel()
[32c0841]593                    except:
594                        pass
[7a07864]595                #reset states and plot data
596                for item in STATE_FILE_EXT:
[32c0841]597                    exec "plot_data(self, path,'%s')" % str(item)
598            else:
599                plot_data(self, path)
[aebc4cc]600        if self.defaultPanel is not None and \
601            self._mgr.GetPane(self.panels["default"].window_name).IsShown():
602            self.on_close_welcome_panel()
[b35d3d1]603           
604    def _on_save(self, event):
605        """
606        Save state into a file
607        """
608        # Ask the user the location of the file to write to.
609       
610        ## Default file location for save
611        self._default_save_location = os.getcwd()
612        path = None
[32c0841]613        dlg = wx.FileDialog(self, "Choose a file",
614                            self._default_save_location, "", "*.svs", wx.SAVE)
[b35d3d1]615        if dlg.ShowModal() == wx.ID_OK:
616            path = dlg.GetPath()
617            self._default_save_location = os.path.dirname(path)
618        else:
619            return None
620        dlg.Destroy()
621        if path is None:
622            return
623        # default cansas xml doc
624        doc = None
625        for item in self.panels:
626            try:
[7a07864]627                if self.panels[item].window_name == 'Invariant':
628                    data = self.panels[item]._data
629                    if data != None:
630                        state = self.panels[item].state
[32c0841]631                        manager = self.panels[item]._manager
632                        new_doc = manager.state_reader.write_toXML(data, state)
[7a07864]633                        if hasattr(doc, "firstChild"):
[32c0841]634                            child = new_doc.firstChild.firstChild
635                            doc.firstChild.appendChild(child) 
[7a07864]636                        else:
637                            doc = new_doc
638                elif self.panels[item].window_name == 'pr_control':
639                    data = self.panels[item].manager.current_plottable
640                    if data != None:
641                        state = self.panels[item].get_state()
[32c0841]642                        manager = self.panels[item].manager
643                        new_doc = manager.state_reader.write_toXML(data, state)
[7a07864]644                        if hasattr(doc, "firstChild"):
[32c0841]645                            child = new_doc.firstChild.firstChild
646                            doc.firstChild.appendChild(child) 
[7a07864]647                        else:
648                            doc = new_doc
649                elif self.panels[item].window_name == 'Fit panel':
650                    for index in range(self.panels[item].GetPageCount()):
651                        selected_page = self.panels[item].GetPage(index) 
652                        if hasattr(selected_page,"get_data"):
653                            data = selected_page.get_data()
654                            state = selected_page.state
[32c0841]655                            reader = selected_page.manager.state_reader
656                            new_doc = reader.write_toXML(data, state)
[7a07864]657                            if doc != None and hasattr(doc, "firstChild"):
[32c0841]658                                child = new_doc.firstChild.firstChild
659                                doc.firstChild.appendChild(child)
[028a0e8]660                            else:
[7a07864]661                                doc = new_doc
[b35d3d1]662            except: 
663                pass
664        # Write the XML document
665        if doc != None:
666            fd = open(path, 'w')
667            fd.write(doc.toprettyxml())
668            fd.close()
669        else:
[32c0841]670            #print "Nothing to save..."
[b35d3d1]671            raise RuntimeError, "%s is not a SansView (.svs) file..." % path
672
[41d466f]673    def _onClose(self, event):
[b0eee0f0]674        """
[d955bf19]675        Store info to retrieve in xml before closing the application
[b0eee0f0]676        """
[41d466f]677        wx.Exit()
678        sys.exit()
[b5ca223]679                 
680    def quit_guiframe(self):
681        """
682        Pop up message to make sure the user wants to quit the application
683        """
684        message = "Do you really want to quit \n"
685        message += "this application?"
686        dial = wx.MessageDialog(self, message, 'Question',
687                           wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
688        if dial.ShowModal() == wx.ID_YES:
689            return True
690        else:
691            return False   
692       
[41d466f]693    def Close(self, event=None):
694        """
[d955bf19]695        Quit the application
[41d466f]696        """
[b5ca223]697        flag = self.quit_guiframe()
[ba535a6]698        if flag:
699            wx.Frame.Close(self)
700            wx.Exit()
701            sys.exit()
[41d466f]702
703    def _check_update(self, event=None): 
704        """
[d955bf19]705        Check with the deployment server whether a new version
706        of the application is available.
707        A thread is started for the connecting with the server. The thread calls
708        a call-back method when the current version number has been obtained.
[52070a1]709        """
[d68c655]710        if hasattr(config, "__update_URL__"):
711            import version
[32c0841]712            checker = version.VersionThread(config.__update_URL__,
713                                            self._process_version,
714                                            baggage=event==None)
[d68c655]715            checker.start() 
[52070a1]716   
717    def _process_version(self, version, standalone=True):
718        """
[d955bf19]719        Call-back method for the process of checking for updates.
720        This methods is called by a VersionThread object once the current
721        version number has been obtained. If the check is being done in the
722        background, the user will not be notified unless there's an update.
723       
724        :param version: version string
725        :param standalone: True of the update is being checked in
726           the background, False otherwise.
727           
[52070a1]728        """
729        try:
[32c0841]730            if cmp(version, config.__version__) > 0:
731                msg = "Version %s is available! See the Help "
732                msg += "menu to download it." % version
733                self.SetStatusText(msg)
[52070a1]734                if not standalone:
735                    import webbrowser
736                    webbrowser.open(config.__download_page__)
737            else:
738                if not standalone:
[32c0841]739                    msg = "You have the latest version"
740                    msg += " of %s" % config.__appname__
741                    self.SetStatusText(msg)
[41d466f]742        except:
[32c0841]743            msg = "guiframe: could not get latest application"
744            msg += " version number\n  %s" % sys.exc_value
745            logging.error(msg)
[52070a1]746            if not standalone:
[32c0841]747                msg = "Could not connect to the application server."
748                msg += " Please try again later."
749                self.SetStatusText(msg)
[52070a1]750                   
[41d466f]751    def _onAbout(self, evt):
752        """
[d955bf19]753        Pop up the about dialog
754       
755        :param evt: menu event
756       
[41d466f]757        """
758        if config._do_aboutbox:
759            import aboutbox 
760            dialog = aboutbox.DialogAbout(None, -1, "")
[6ab0ad1]761            dialog.ShowModal()           
[4e9583c]762           
[41d466f]763    def set_manager(self, manager):
764        """
[d955bf19]765        Sets the application manager for this frame
766       
767        :param manager: frame manager
[41d466f]768        """
769        self.app_manager = manager
770       
771    def post_init(self):
772        """
[d955bf19]773        This initialization method is called after the GUI
774        has been created and all plug-ins loaded. It calls
775        the post_init() method of each plug-in (if it exists)
776        so that final initialization can be done.
[41d466f]777        """
778        for item in self.plugins:
779            if hasattr(item, "post_init"):
780                item.post_init()
781       
[b28278e]782    def set_default_perspective(self):
783        """
[d955bf19]784        Choose among the plugin the first plug-in that has
785        "set_default_perspective" method and its return value is True will be
786        as a default perspective when the welcome page is closed
[b28278e]787        """
788        for item in self.plugins:
789            if hasattr(item, "set_default_perspective"):
790                if item.set_default_perspective():
791                    item.on_perspective(event=None)
[f444b20]792                    self._current_perspective = item
[b28278e]793                    return 
[f444b20]794       
[41d466f]795    def set_perspective(self, panels):
796        """
[d955bf19]797        Sets the perspective of the GUI.
798        Opens all the panels in the list, and closes
799        all the others.
800       
801        :param panels: list of panels
[41d466f]802        """
[f444b20]803       
[41d466f]804        for item in self.panels:
805            # Check whether this is a sticky panel
806            if hasattr(self.panels[item], "ALWAYS_ON"):
807                if self.panels[item].ALWAYS_ON:
808                    continue 
809            if self.panels[item].window_name in panels:
810                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
811                    self._mgr.GetPane(self.panels[item].window_name).Show()
812            else:
813                if self._mgr.GetPane(self.panels[item].window_name).IsShown():
814                    self._mgr.GetPane(self.panels[item].window_name).Hide()
815        self._mgr.Update()
[4e9583c]816       
817    def choose_file(self, path=None):
[41d466f]818        """
[d955bf19]819        Functionality that belongs elsewhere
820        Should add a hook to specify the preferred file type/extension.
[41d466f]821        """
[4e9583c]822        #TODO: clean this up
[32c0841]823        from .data_loader import choose_data_file
[8068b52]824        # Choose a file path
[32c0841]825        if path == None:
[4e9583c]826            path = choose_data_file(self, self._default_save_location)
[32c0841]827        if not path == None:
[2310d69]828            try:
[4e9583c]829                self._default_save_location = os.path.dirname(path)
[2310d69]830            except:
[83ee3851]831                pass
[2310d69]832        return path
[f444b20]833   
834    def add_data(self, data_list):
835        """
836        receive a list of data . store them its data manager if possible
837        determine if data was be plot of send to data perspectives
838        """
839        self.data_manager.add_data(data_list)
840        if AUTO_SET_DATA:
841            if self._current_perspective is not None:
842                try:
843                    self._current_perspective.set_data(data_list)
844                except:
845                    raise
846                    #msg = str(sys.exc_value)
847                    #wx.PostEvent(self, StatusEvent(status=msg,
848                    #                          info="error"))
849            else:
850                msg = "Guiframe does not have a current perspective"
851                logging.info(msg)
852        if DATA_MANAGER:
853            print "will show data panel"
854        if AUTO_PLOT:
855            self.plot_data(data_list)
856           
857    def plot_data(self, data_list):
858        """
859        send a list of data to plot
860        """
861        for new_plot in data_list:
862            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
863                                                  title=str(new_plot.title)))
864           
865    def set_current_perspective(self, perspective):
866        """
867        set the current active perspective
868        """
869        self._current_perspective = perspective
[b7c7a1c]870
[41d466f]871class DefaultPanel(wx.Panel):
872    """
[d955bf19]873    Defines the API for a panels to work with
874    the GUI manager
[41d466f]875    """
876    ## Internal nickname for the window, used by the AUI manager
877    window_name = "default"
878    ## Name to appear on the window title bar
879    window_caption = "Welcome panel"
880    ## Flag to tell the AUI manager to put this panel in the center pane
881    CENTER_PANE = True
882
883 
884# Toy application to test this Frame
885class ViewApp(wx.App):
[d955bf19]886    """
887    """
[41d466f]888    def OnInit(self):
[d955bf19]889        """
890        """
[41d466f]891        self.frame = ViewerFrame(None, -1, config.__appname__)   
892        self.frame.Show(True)
893
894        if hasattr(self.frame, 'special'):
895            self.frame.special.SetCurrent()
896        self.SetTopWindow(self.frame)
897        return True
898   
899    def set_manager(self, manager):
900        """
[d955bf19]901        Sets a reference to the application manager
902        of the GUI manager (Frame)
[41d466f]903        """
904        self.frame.set_manager(manager)
905       
[278cc25]906    def build_gui(self):
907        """
[d955bf19]908        Build the GUI
[278cc25]909        """
910        self.frame.build_gui()
911        self.frame.post_init()
912       
[f9e803e]913    def set_welcome_panel(self, panel_class):
914        """
[d955bf19]915        Set the welcome panel
916       
917        :param panel_class: class of the welcome panel to be instantiated
918       
[f9e803e]919        """
920        self.frame.set_welcome_panel(panel_class)
921       
[278cc25]922    def add_perspective(self, perspective):
923        """
[d955bf19]924        Manually add a perspective to the application GUI
[278cc25]925        """
926        self.frame.add_perspective(perspective)
927       
[41d466f]928
929if __name__ == "__main__": 
930    app = ViewApp(0)
[32c0841]931    app.MainLoop()
932
933             
Note: See TracBrowser for help on using the repository browser.