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
Line 
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
25import warnings
26warnings.simplefilter("ignore")
27
28
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:
223            if self.panels[item].window_name.startswith(p.window_name): 
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       
268        # Add sub menus
269        menubar.Append(filemenu,  '&File')
270       
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       
277        # Only add the panel menu if there is more than one panel
278        n_panels = 0
279        for plug in self.plugins:
280            pers = plug.get_perspective()
281            if len(pers)>0:
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)
299               
300            menubar.Append(viewmenu, '&Panel')
301
302        # Perspective
303        # Attach a menu item for each defined perspective.
304        # Only add the perspective menu if there are more than one perspectves
305        n_perspectives = 0
306        for plug in self.plugins:
307            if len(plug.get_perspective()) > 0:
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')
318 
319        # Help menu
320        helpmenu = wx.Menu()
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       
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       
338       
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()
380                # Hide default panel
381                self._mgr.GetPane(self.panels["default"].window_name).Hide()
382               
383               
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.