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
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()
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()
[383189f9]351                # Hide default panel
352                self._mgr.GetPane(self.panels["default"].window_name).Hide()
353               
354               
[41d466f]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.