source: sasview/guiframe/gui_manager.py @ 197ea24

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

Only add menu Perspectives and Panels menu items when they contain more than 1 item

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