source: sasview/guiframe/gui_manager.py @ 8db3904

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

working on guiframe

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