source: sasview/guiframe/gui_manager.py @ 0954398

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 0954398 was fa452e4, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Added help menu entry for plug-ins and updated requirements

  • Property mode set to 100644
File size: 17.9 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
9"""
10import wx
11import wx.aui
12import os, sys
13try:
14    # Try to find a local config
15    import imp
16    path = os.getcwd()
17    if(os.path.isfile("%s/%s.py" % (path, 'config'))):
18            fObj, path, descr = imp.find_module('config', [path])
19            config = imp.load_module('config', fObj, path, descr)     
20except:
21    # Didn't find local config, load the default
22    import config
23from sans.guicomm.events import EVT_STATUS
24
25class ViewerFrame(wx.Frame):
26    """
27        Main application frame
28    """
29    def __init__(self, parent, id, title):
30        """
31            Initialize the Frame object
32        """
33        from local_perspectives.plotting import plotting
34        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, size=(1000, 1000))
35       
36        path = os.path.dirname(__file__)
37        self.SetIcon(wx.Icon(os.path.join(path,'images/ball.ico'), wx.BITMAP_TYPE_ICO))
38       
39        ## Application manager
40        self.app_manager = None
41       
42        ## Find plug-ins
43        # Modify this so that we can specify the directory to look into
44        self.plugins = self._find_plugins()
45        self.plugins.append(plotting.Plugin())
46
47        ## List of panels
48        self.panels = {}
49
50        ## Next available ID for wx gui events
51        self.next_id = 20000
52
53        ## Default welcome panel
54        self.defaultPanel    = DefaultPanel(self, -1, style=wx.RAISED_BORDER)
55
56        # Set up the layout
57        self._setup_layout()
58       
59        # Set up the menu
60        self._setup_menus()
61       
62        self.Fit()
63       
64        # Register the close event so it calls our own method
65        wx.EVT_CLOSE(self, self._onClose)
66        # Register to status events
67        self.Bind(EVT_STATUS, self._on_status_event)
68             
69    def _setup_layout(self):
70        """
71            Set up the layout
72        """
73        # Status bar
74        self.sb = self.CreateStatusBar()
75        self.SetStatusText("")
76       
77        # Add panel
78        self._mgr = wx.aui.AuiManager(self)
79       
80        # Load panels
81        self._load_panels()
82       
83        self._mgr.Update()
84     
85    def _find_plugins(self, dir="perspectives"):
86        """
87            Find available perspective plug-ins
88            @param dir: directory in which to look for plug-ins
89            @return: list of plug-ins
90        """
91        import imp
92        print "Looking for plug-ins in %s" % dir
93        # List of plug-in objects
94        plugins = []
95        # Go through files in panels directory
96        try:
97            list = os.listdir(dir)
98            for item in list:
99                print item
100                toks = os.path.splitext(os.path.basename(item))
101                name = None
102                if not toks[0] == '__init__':
103                   
104                    if toks[1]=='.py' or toks[1]=='':
105                        name = toks[0]
106               
107                    path = [os.path.abspath(dir)]
108                    file = None
109                    try:
110                        if toks[1]=='':
111                            mod_path = '.'.join([dir, name])
112                            module = __import__(mod_path, globals(), locals(), [name])
113                        else:
114                            (file, path, info) = imp.find_module(name, path)
115                            print path
116                            module = imp.load_module( name, file, item, info )
117                        if hasattr(module, "PLUGIN_ID"):
118                            try:
119                                plugins.append(module.Plugin())
120                                print "Found plug-in: %s" % module.PLUGIN_ID
121                            except:
122                                config.printEVT("Error accessing PluginPanel in %s\n  %s" % (name, sys.exc_value))
123                       
124                    except:
125                        print sys.exc_value
126                    finally:
127                        if not file==None:
128                            file.close()
129        except:
130            # Should raise and catch at a higher level and display error on status bar
131            pass   
132        return plugins
133   
134       
135     
136    def _load_panels(self):
137        """
138            Load all panels in the panels directory
139        """
140       
141        # Look for plug-in panels
142        panels = []       
143        for item in self.plugins:
144            if hasattr(item, "get_panels"):
145                ps = item.get_panels(self)
146                panels.extend(ps)
147
148        # Show a default panel with some help information
149        # It also sets the size of the application windows
150        self.panels["default"] = self.defaultPanel
151        self._mgr.AddPane(self.defaultPanel, wx.aui.AuiPaneInfo().
152                              Name("default").
153                              CenterPane().
154                              BestSize(wx.Size(900,800)).
155                              MinSize(wx.Size(900,800)).
156                              Show())
157
158        # Add the panels to the AUI manager
159        for panel_class in panels:
160            p = panel_class
161            id = wx.NewId()
162           
163            # Check whether we need to put this panel
164            # in the center pane
165            if hasattr(p, "CENTER_PANE"):
166                if p.CENTER_PANE:
167                    self.panels[str(id)] = p
168                    self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
169                                          Name(p.window_name).Caption(p.window_caption).
170                                          CenterPane().
171                                          BestSize(wx.Size(600,600)).
172                                          MinSize(wx.Size(600,600)).
173                                          Hide())
174               
175            else:
176                self.panels[str(id)] = p
177                self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
178                                  Name(p.window_name).Caption(p.window_caption).
179                                  #Floatable().
180                                  #Float().
181                                  Right().
182                                  Dock().
183                                  TopDockable().
184                                  BottomDockable().
185                                  LeftDockable().
186                                  RightDockable().
187                                  MinimizeButton().
188                                  Hide().
189                                  #Show().
190                                  BestSize(wx.Size(400,400)).
191                                  MinSize(wx.Size(100,100)))
192               
193       
194    def get_context_menu(self):
195        """
196            Get the context menu items made available
197            by the different plug-ins.
198            This function is used by the plotting module
199        """
200        menu_list = []
201        for item in self.plugins:
202            if hasattr(item, "get_context_menu"):
203                menu_list.extend(item.get_context_menu())
204           
205        return menu_list
206       
207    def popup_panel(self, p):
208        """
209            Add a panel object to the AUI manager
210            @param p: panel object to add to the AUI manager
211            @return: ID of the event associated with the new panel [int]
212        """
213       
214        ID = wx.NewId()
215        self.panels[str(ID)] = p
216       
217        count = 0
218        for item in self.panels:
[383189f9]219            if self.panels[item].window_name.startswith(p.window_name): 
[41d466f]220                count += 1
221               
222        windowname = p.window_name
223        caption = p.window_caption
224        if count>0:
225            windowname += str(count+1)
226            caption += (' '+str(count))
227           
228        p.window_name = windowname
229        p.window_caption = caption
230           
231        self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
232                          Name(windowname).Caption(caption).
233                          Floatable().
234                          #Float().
235                          Right().
236                          Dock().
237                          TopDockable().
238                          BottomDockable().
239                          LeftDockable().
240                          RightDockable().
241                          MinimizeButton().
242                          #Hide().
243                          #Show().
244                          BestSize(wx.Size(400,400)).
245                          MinSize(wx.Size(200,200)))
246       
247        # Register for showing/hiding the panel
248        wx.EVT_MENU(self, ID, self._on_view)
249       
250        self._mgr.Update()
251        return ID
252       
253    def _setup_menus(self):
254        """
255            Set up the application menus
256        """
257        # Menu
258        menubar = wx.MenuBar()
259       
260        # File menu
261        filemenu = wx.Menu()
262        filemenu.Append(101,'&Quit', 'Exit') 
263       
264        # Plot menu
265        # Attach a menu item for each panel in our
266        # panel list that also appears in a plug-in.
267        # TODO: clean this up. We should just identify
268        # plug-in panels and add them all.
269        viewmenu = wx.Menu()
270       
271        for plug in self.plugins:
272            plugmenu = wx.Menu()
273            pers = plug.get_perspective()
274            if len(pers)>0:
275                for item in self.panels:
276                    if item == 'default':
277                        continue
278                    panel = self.panels[item]
279                    if panel.window_name in pers:
280                        plugmenu.Append(int(item), panel.window_caption, "Show %s window" % panel.window_caption)
281                        wx.EVT_MENU(self, int(item), self._on_view)
282               
283                viewmenu.AppendMenu(wx.NewId(), plug.sub_menu, plugmenu, plug.sub_menu)
284           
285        # Perspective
286        # Attach a menu item for each defined perspective.
287        p_menu = wx.Menu()
288       
289        for plug in self.plugins:
290            if len(plug.get_perspective()) > 0:
291                id = wx.NewId()
292                p_menu.Append(id, plug.sub_menu, "Switch to %s perspective" % plug.sub_menu)
293                wx.EVT_MENU(self, id, plug.on_perspective)
294 
295        # Help menu
296        helpmenu = wx.Menu()
[fa452e4]297
298        # Look for help item in plug-ins
299        for item in self.plugins:
300            if hasattr(item, "help"):
301                id = wx.NewId()
302                helpmenu.Append(id,'&%s help' % item.sub_menu, '')
303                wx.EVT_MENU(self, id, item.help)
304       
[41d466f]305        if config._do_aboutbox:
306            id = wx.NewId()
307            helpmenu.Append(id,'&About', 'Software information')
308            wx.EVT_MENU(self, id, self._onAbout)
309        id = wx.NewId()
310        helpmenu.Append(id,'&Check for update', 'Check for the latest version of %s' % config.__appname__)
311        wx.EVT_MENU(self, id, self._check_update)
312       
313       
314        # Add sub menus
315        menubar.Append(filemenu,  '&File')
316       
317        # Look for plug-in menus
318        # Add available plug-in sub-menus.
319        for item in self.plugins:
320            if hasattr(item, "populate_menu"):
321                for (self.next_id, menu, name) in item.populate_menu(self.next_id, self):
322                    menubar.Append(menu, name)
323       
324
325        menubar.Append(viewmenu, '&Panel')
326        menubar.Append(p_menu,   '&Perspective')
327        menubar.Append(helpmenu, '&Help')
328         
329        self.SetMenuBar(menubar)
330       
331        # Bind handlers       
332        wx.EVT_MENU(self, 101, self.Close)
333       
334    def _on_status_event(self, evt):
335        """
336            Display status message
337        """
338        self.SetStatusText(str(evt.status))
339
340       
341    def _on_view(self, evt):
342        """
343            A panel was selected to be shown. If it's not already
344            shown, display it.
345            @param evt: menu event
346        """
347        self.show_panel(evt.GetId())
348
349    def show_panel(self, uid):
350        """
351            Shows the panel with the given id
352            @param uid: unique ID number of the panel to show
353        """
354        ID = str(uid)
355        config.printEVT("show_panel: %s" % ID)
356        if ID in self.panels.keys():
357            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown():
358                self._mgr.GetPane(self.panels[ID].window_name).Show()
[383189f9]359                # Hide default panel
360                self._mgr.GetPane(self.panels["default"].window_name).Hide()
361               
362               
[41d466f]363            self._mgr.Update()
364       
365
366    def _onClose(self, event):
367        import sys
368        wx.Exit()
369        sys.exit()
370                   
371    def Close(self, event=None):
372        """
373            Quit the application
374        """
375        import sys
376        wx.Frame.Close(self)
377        wx.Exit()
378        sys.exit()
379
380 
381    def _check_update(self, event=None): 
382        """
383            Check with the deployment server whether a new version
384            of the application is available
385        """
386        import urllib
387        try: 
388            h = urllib.urlopen(config.__update_URL__)
389            lines = h.readlines()
390            line = ''
391            if len(lines)>0:
392                line = lines[0]
393               
394                toks = line.lstrip().rstrip().split('.')
395                toks_current = config.__version__.split('.')
396                update_available = False
397                for i in range(len(toks)):
398                    if int(toks[i])>int(toks_current[i]):
399                        update_available = True
400                if update_available:
401                    #print "Version %s is available" % line.rstrip().lstrip()
402                    self.SetStatusText("Version %s is available! See the Help menu to download it." % line.rstrip().lstrip())
403                    if event != None:
404                        import webbrowser
405                        webbrowser.open(config.__download_page__)
406                else:
407                    self.SetStatusText("You have the latest version of %s" % config.__appname__)
408                    #print "Server version = %s"  % line.rstrip().lstrip()
409        except:
410            self.SetStatusText("You have the latest version of %s" % config.__appname__)
411           
412           
413    def _onAbout(self, evt):
414        """
415            Pop up the about dialog
416            @param evt: menu event
417        """
418        if config._do_aboutbox:
419            import aboutbox 
420            dialog = aboutbox.DialogAbout(None, -1, "")
421            dialog.ShowModal()
422           
423    def set_manager(self, manager):
424        """
425            Sets the application manager for this frame
426            @param manager: frame manager
427        """
428        self.app_manager = manager
429       
430    def post_init(self):
431        """
432            This initialization method is called after the GUI
433            has been created and all plug-ins loaded. It calls
434            the post_init() method of each plug-in (if it exists)
435            so that final initialization can be done.
436        """
437        for item in self.plugins:
438            if hasattr(item, "post_init"):
439                item.post_init()
440       
441    def set_perspective(self, panels):
442        """
443            Sets the perspective of the GUI.
444            Opens all the panels in the list, and closes
445            all the others.
446           
447            @param panels: list of panels
448        """
449        print "gui_mng.set_perspective"
450        for item in self.panels:
451            # Check whether this is a sticky panel
452            if hasattr(self.panels[item], "ALWAYS_ON"):
453                if self.panels[item].ALWAYS_ON:
454                    continue 
455           
456            if self.panels[item].window_name in panels:
457                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
458                    self._mgr.GetPane(self.panels[item].window_name).Show()
459            else:
460                if self._mgr.GetPane(self.panels[item].window_name).IsShown():
461                    self._mgr.GetPane(self.panels[item].window_name).Hide()
462                 
463        self._mgr.Update()
464       
465    def choose_file(self):
466        """
467            Functionality that belongs elsewhere
468            Should add a hook to specify the preferred file type/extension.
469        """
470        #TODO: clean this up
471        from data_loader import choose_data_file
472        return choose_data_file(self)
473                 
474class DefaultPanel(wx.Panel):
475    """
476        Defines the API for a panels to work with
477        the GUI manager
478    """
479    ## Internal nickname for the window, used by the AUI manager
480    window_name = "default"
481    ## Name to appear on the window title bar
482    window_caption = "Welcome panel"
483    ## Flag to tell the AUI manager to put this panel in the center pane
484    CENTER_PANE = True
485
486 
487# Toy application to test this Frame
488class ViewApp(wx.App):
489    def OnInit(self):
490        #from gui_manager import ViewerFrame
491        self.frame = ViewerFrame(None, -1, config.__appname__)   
492        self.frame.Show(True)
493
494        if hasattr(self.frame, 'special'):
495            print "Special?", self.frame.special.__class__.__name__
496            self.frame.special.SetCurrent()
497        self.frame.post_init()
498        self.SetTopWindow(self.frame)
499        return True
500   
501    def set_manager(self, manager):
502        """
503            Sets a reference to the application manager
504            of the GUI manager (Frame)
505        """
506        self.frame.set_manager(manager)
507       
508
509if __name__ == "__main__": 
510    app = ViewApp(0)
511    app.MainLoop()             
Note: See TracBrowser for help on using the repository browser.