source: sasview/guiframe/gui_manager.py @ 691643c

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

make all plugins inheriting from pluginbase in plugin-base.py

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