source: sasview/guiframe/gui_manager.py @ ded62ce

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 ded62ce was af20f6b, checked in by Mathieu Doucet <doucetm@…>, 15 years ago

guiframe: removed version checking

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