source: sasview/guiframe/gui_manager.py @ 810f196

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

working on documentation

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