source: sasview/guiframe/gui_manager.py @ 2e07e8f

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 2e07e8f was 383189f9, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Added plot group ID

  • Property mode set to 100644
File size: 17.6 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
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:
219            if self.panels[item].window_name.startswith(p.window_name): 
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()
297        if config._do_aboutbox:
298            id = wx.NewId()
299            helpmenu.Append(id,'&About', 'Software information')
300            wx.EVT_MENU(self, id, self._onAbout)
301        id = wx.NewId()
302        helpmenu.Append(id,'&Check for update', 'Check for the latest version of %s' % config.__appname__)
303        wx.EVT_MENU(self, id, self._check_update)
304       
305       
306        # Add sub menus
307        menubar.Append(filemenu,  '&File')
308       
309        # Look for plug-in menus
310        # Add available plug-in sub-menus.
311        for item in self.plugins:
312            if hasattr(item, "populate_menu"):
313                for (self.next_id, menu, name) in item.populate_menu(self.next_id, self):
314                    menubar.Append(menu, name)
315       
316
317        menubar.Append(viewmenu, '&Panel')
318        menubar.Append(p_menu,   '&Perspective')
319        menubar.Append(helpmenu, '&Help')
320         
321        self.SetMenuBar(menubar)
322       
323        # Bind handlers       
324        wx.EVT_MENU(self, 101, self.Close)
325       
326    def _on_status_event(self, evt):
327        """
328            Display status message
329        """
330        self.SetStatusText(str(evt.status))
331
332       
333    def _on_view(self, evt):
334        """
335            A panel was selected to be shown. If it's not already
336            shown, display it.
337            @param evt: menu event
338        """
339        self.show_panel(evt.GetId())
340
341    def show_panel(self, uid):
342        """
343            Shows the panel with the given id
344            @param uid: unique ID number of the panel to show
345        """
346        ID = str(uid)
347        config.printEVT("show_panel: %s" % ID)
348        if ID in self.panels.keys():
349            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown():
350                self._mgr.GetPane(self.panels[ID].window_name).Show()
351                # Hide default panel
352                self._mgr.GetPane(self.panels["default"].window_name).Hide()
353               
354               
355            self._mgr.Update()
356       
357
358    def _onClose(self, event):
359        import sys
360        wx.Exit()
361        sys.exit()
362                   
363    def Close(self, event=None):
364        """
365            Quit the application
366        """
367        import sys
368        wx.Frame.Close(self)
369        wx.Exit()
370        sys.exit()
371
372 
373    def _check_update(self, event=None): 
374        """
375            Check with the deployment server whether a new version
376            of the application is available
377        """
378        import urllib
379        try: 
380            h = urllib.urlopen(config.__update_URL__)
381            lines = h.readlines()
382            line = ''
383            if len(lines)>0:
384                line = lines[0]
385               
386                toks = line.lstrip().rstrip().split('.')
387                toks_current = config.__version__.split('.')
388                update_available = False
389                for i in range(len(toks)):
390                    if int(toks[i])>int(toks_current[i]):
391                        update_available = True
392                if update_available:
393                    #print "Version %s is available" % line.rstrip().lstrip()
394                    self.SetStatusText("Version %s is available! See the Help menu to download it." % line.rstrip().lstrip())
395                    if event != None:
396                        import webbrowser
397                        webbrowser.open(config.__download_page__)
398                else:
399                    self.SetStatusText("You have the latest version of %s" % config.__appname__)
400                    #print "Server version = %s"  % line.rstrip().lstrip()
401        except:
402            self.SetStatusText("You have the latest version of %s" % config.__appname__)
403           
404           
405    def _onAbout(self, evt):
406        """
407            Pop up the about dialog
408            @param evt: menu event
409        """
410        if config._do_aboutbox:
411            import aboutbox 
412            dialog = aboutbox.DialogAbout(None, -1, "")
413            dialog.ShowModal()
414           
415    def set_manager(self, manager):
416        """
417            Sets the application manager for this frame
418            @param manager: frame manager
419        """
420        self.app_manager = manager
421       
422    def post_init(self):
423        """
424            This initialization method is called after the GUI
425            has been created and all plug-ins loaded. It calls
426            the post_init() method of each plug-in (if it exists)
427            so that final initialization can be done.
428        """
429        for item in self.plugins:
430            if hasattr(item, "post_init"):
431                item.post_init()
432       
433    def set_perspective(self, panels):
434        """
435            Sets the perspective of the GUI.
436            Opens all the panels in the list, and closes
437            all the others.
438           
439            @param panels: list of panels
440        """
441        print "gui_mng.set_perspective"
442        for item in self.panels:
443            # Check whether this is a sticky panel
444            if hasattr(self.panels[item], "ALWAYS_ON"):
445                if self.panels[item].ALWAYS_ON:
446                    continue 
447           
448            if self.panels[item].window_name in panels:
449                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
450                    self._mgr.GetPane(self.panels[item].window_name).Show()
451            else:
452                if self._mgr.GetPane(self.panels[item].window_name).IsShown():
453                    self._mgr.GetPane(self.panels[item].window_name).Hide()
454                 
455        self._mgr.Update()
456       
457    def choose_file(self):
458        """
459            Functionality that belongs elsewhere
460            Should add a hook to specify the preferred file type/extension.
461        """
462        #TODO: clean this up
463        from data_loader import choose_data_file
464        return choose_data_file(self)
465                 
466class DefaultPanel(wx.Panel):
467    """
468        Defines the API for a panels to work with
469        the GUI manager
470    """
471    ## Internal nickname for the window, used by the AUI manager
472    window_name = "default"
473    ## Name to appear on the window title bar
474    window_caption = "Welcome panel"
475    ## Flag to tell the AUI manager to put this panel in the center pane
476    CENTER_PANE = True
477
478 
479# Toy application to test this Frame
480class ViewApp(wx.App):
481    def OnInit(self):
482        #from gui_manager import ViewerFrame
483        self.frame = ViewerFrame(None, -1, config.__appname__)   
484        self.frame.Show(True)
485
486        if hasattr(self.frame, 'special'):
487            print "Special?", self.frame.special.__class__.__name__
488            self.frame.special.SetCurrent()
489        self.frame.post_init()
490        self.SetTopWindow(self.frame)
491        return True
492   
493    def set_manager(self, manager):
494        """
495            Sets a reference to the application manager
496            of the GUI manager (Frame)
497        """
498        self.frame.set_manager(manager)
499       
500
501if __name__ == "__main__": 
502    app = ViewApp(0)
503    app.MainLoop()             
Note: See TracBrowser for help on using the repository browser.