source: sasview/guiframe/gui_manager.py @ 103a0b0

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 103a0b0 was 41d466f, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Initial import.

  • Property mode set to 100644
File size: 17.4 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 == 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            self._mgr.Update()
352       
353
354    def _onClose(self, event):
355        import sys
356        wx.Exit()
357        sys.exit()
358                   
359    def Close(self, event=None):
360        """
361            Quit the application
362        """
363        import sys
364        wx.Frame.Close(self)
365        wx.Exit()
366        sys.exit()
367
368 
369    def _check_update(self, event=None): 
370        """
371            Check with the deployment server whether a new version
372            of the application is available
373        """
374        import urllib
375        try: 
376            h = urllib.urlopen(config.__update_URL__)
377            lines = h.readlines()
378            line = ''
379            if len(lines)>0:
380                line = lines[0]
381               
382                toks = line.lstrip().rstrip().split('.')
383                toks_current = config.__version__.split('.')
384                update_available = False
385                for i in range(len(toks)):
386                    if int(toks[i])>int(toks_current[i]):
387                        update_available = True
388                if update_available:
389                    #print "Version %s is available" % line.rstrip().lstrip()
390                    self.SetStatusText("Version %s is available! See the Help menu to download it." % line.rstrip().lstrip())
391                    if event != None:
392                        import webbrowser
393                        webbrowser.open(config.__download_page__)
394                else:
395                    self.SetStatusText("You have the latest version of %s" % config.__appname__)
396                    #print "Server version = %s"  % line.rstrip().lstrip()
397        except:
398            self.SetStatusText("You have the latest version of %s" % config.__appname__)
399           
400           
401    def _onAbout(self, evt):
402        """
403            Pop up the about dialog
404            @param evt: menu event
405        """
406        if config._do_aboutbox:
407            import aboutbox 
408            dialog = aboutbox.DialogAbout(None, -1, "")
409            dialog.ShowModal()
410           
411    def set_manager(self, manager):
412        """
413            Sets the application manager for this frame
414            @param manager: frame manager
415        """
416        self.app_manager = manager
417       
418    def post_init(self):
419        """
420            This initialization method is called after the GUI
421            has been created and all plug-ins loaded. It calls
422            the post_init() method of each plug-in (if it exists)
423            so that final initialization can be done.
424        """
425        for item in self.plugins:
426            if hasattr(item, "post_init"):
427                item.post_init()
428       
429    def set_perspective(self, panels):
430        """
431            Sets the perspective of the GUI.
432            Opens all the panels in the list, and closes
433            all the others.
434           
435            @param panels: list of panels
436        """
437        print "gui_mng.set_perspective"
438        for item in self.panels:
439            # Check whether this is a sticky panel
440            if hasattr(self.panels[item], "ALWAYS_ON"):
441                if self.panels[item].ALWAYS_ON:
442                    continue 
443           
444            if self.panels[item].window_name in panels:
445                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
446                    self._mgr.GetPane(self.panels[item].window_name).Show()
447            else:
448                if self._mgr.GetPane(self.panels[item].window_name).IsShown():
449                    self._mgr.GetPane(self.panels[item].window_name).Hide()
450                 
451        self._mgr.Update()
452       
453    def choose_file(self):
454        """
455            Functionality that belongs elsewhere
456            Should add a hook to specify the preferred file type/extension.
457        """
458        #TODO: clean this up
459        from data_loader import choose_data_file
460        return choose_data_file(self)
461                 
462class DefaultPanel(wx.Panel):
463    """
464        Defines the API for a panels to work with
465        the GUI manager
466    """
467    ## Internal nickname for the window, used by the AUI manager
468    window_name = "default"
469    ## Name to appear on the window title bar
470    window_caption = "Welcome panel"
471    ## Flag to tell the AUI manager to put this panel in the center pane
472    CENTER_PANE = True
473
474 
475# Toy application to test this Frame
476class ViewApp(wx.App):
477    def OnInit(self):
478        #from gui_manager import ViewerFrame
479        self.frame = ViewerFrame(None, -1, config.__appname__)   
480        self.frame.Show(True)
481
482        if hasattr(self.frame, 'special'):
483            print "Special?", self.frame.special.__class__.__name__
484            self.frame.special.SetCurrent()
485        self.frame.post_init()
486        self.SetTopWindow(self.frame)
487        return True
488   
489    def set_manager(self, manager):
490        """
491            Sets a reference to the application manager
492            of the GUI manager (Frame)
493        """
494        self.frame.set_manager(manager)
495       
496
497if __name__ == "__main__": 
498    app = ViewApp(0)
499    app.MainLoop()             
Note: See TracBrowser for help on using the repository browser.