source: sasview/guiframe/gui_manager.py @ 4378360

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

Initial import.

  • Property mode set to 100644
File size: 17.4 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:
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.