source: sasview/guiframe/gui_manager.py @ cbb2e40

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

0.1

  • Property mode set to 100644
File size: 20.3 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, 'local_config'))) or \
18      (os.path.isfile("%s/%s.pyc" % (path, 'local_config'))):
19            fObj, path, descr = imp.find_module('local_config', [path])
20            config = imp.load_module('local_config', fObj, path, descr) 
21    else:
22        # Try simply importing local_config
23        import local_config as config
24except:
25    # Didn't find local config, load the default
26    import config
27   
28from sans.guicomm.events import EVT_STATUS
29
30import warnings
31warnings.simplefilter("ignore")
32
33
34class ViewerFrame(wx.Frame):
35    """
36        Main application frame
37    """
38    def __init__(self, parent, id, title):
39        """
40            Initialize the Frame object
41        """
42        from local_perspectives.plotting import plotting
43        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, size=(1000, 1000))
44       
45        path = os.path.dirname(__file__)
46        ico_file = os.path.join(path,'images/ball.ico')
47        if os.path.isfile(ico_file):
48            self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
49        else:
50            ico_file = os.path.join(os.getcwd(),'images/ball.ico')
51            if os.path.isfile(ico_file):
52                self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
53       
54        ## Application manager
55        self.app_manager = None
56       
57        ## Find plug-ins
58        # Modify this so that we can specify the directory to look into
59        self.plugins = self._find_plugins()
60        self.plugins.append(plotting.Plugin())
61
62        ## List of panels
63        self.panels = {}
64
65        ## Next available ID for wx gui events
66        self.next_id = 20000
67
68        ## Default welcome panel
69        self.defaultPanel    = DefaultPanel(self, -1, style=wx.RAISED_BORDER)
70
71        # self.build_gui()
72       
73        # Register the close event so it calls our own method
74        wx.EVT_CLOSE(self, self._onClose)
75        # Register to status events
76        self.Bind(EVT_STATUS, self._on_status_event)
77             
78    def build_gui(self):
79        # Set up the layout
80        self._setup_layout()
81       
82        # Set up the menu
83        self._setup_menus()
84       
85        self.Fit()
86             
87    def _setup_layout(self):
88        """
89            Set up the layout
90        """
91        # Status bar
92        self.sb = self.CreateStatusBar()
93        self.SetStatusText("")
94       
95        # Add panel
96        self._mgr = wx.aui.AuiManager(self)
97       
98        # Load panels
99        self._load_panels()
100       
101        self._mgr.Update()
102
103    def add_perspective(self, plugin):
104        """
105            Add a perspective if it doesn't already
106            exist.
107        """
108        is_loaded = False
109        for item in self.plugins:
110             if plugin.__class__==item.__class__:
111                 print "Plugin %s already loaded" % plugin.__class__.__name__
112                 is_loaded = True
113                 
114        if not is_loaded:
115            self.plugins.append(plugin)
116     
117    def _find_plugins(self, dir="perspectives"):
118        """
119            Find available perspective plug-ins
120            @param dir: directory in which to look for plug-ins
121            @return: list of plug-ins
122        """
123        import imp
124        print "Looking for plug-ins in %s" % dir
125        # List of plug-in objects
126       
127        #path_exe = os.getcwd()
128        #path_plugs = os.path.join(path_exe, dir)
129        f = open("load.log",'w') 
130        f.write(os.getcwd()+'\n\n')
131        #f.write(str(os.listdir(dir))+'\n')
132       
133       
134        plugins = []
135        # Go through files in panels directory
136        try:
137            list = os.listdir(dir)
138            for item in list:
139                print item
140                toks = os.path.splitext(os.path.basename(item))
141                name = None
142                if not toks[0] == '__init__':
143                   
144                    if toks[1]=='.py' or toks[1]=='':
145                        name = toks[0]
146               
147                    path = [os.path.abspath(dir)]
148                    file = None
149                    try:
150                        if toks[1]=='':
151                            f.write("trying to import \n")
152                            mod_path = '.'.join([dir, name])
153                            f.write("mod_path= %s\n" % mod_path)
154                            module = __import__(mod_path, globals(), locals(), [name])
155                            f.write(str(module)+'\n')
156                        else:
157                            (file, path, info) = imp.find_module(name, path)
158                            print path
159                            module = imp.load_module( name, file, item, info )
160                        if hasattr(module, "PLUGIN_ID"):
161                            try:
162                                plugins.append(module.Plugin())
163                                print "Found plug-in: %s" % module.PLUGIN_ID
164                            except:
165                                config.printEVT("Error accessing PluginPanel in %s\n  %s" % (name, sys.exc_value))
166                       
167                    except:
168                        print sys.exc_value
169                        f.write(str(sys.exc_value)+'\n')
170                    finally:
171                        if not file==None:
172                            file.close()
173        except:
174            # Should raise and catch at a higher level and display error on status bar
175            pass   
176        f.write(str(plugins)+'\n')
177        f.close()
178        return plugins
179   
180       
181     
182    def _load_panels(self):
183        """
184            Load all panels in the panels directory
185        """
186       
187        # Look for plug-in panels
188        panels = []       
189        for item in self.plugins:
190            if hasattr(item, "get_panels"):
191                ps = item.get_panels(self)
192                panels.extend(ps)
193
194        # Show a default panel with some help information
195        # It also sets the size of the application windows
196        self.panels["default"] = self.defaultPanel
197        self._mgr.AddPane(self.defaultPanel, wx.aui.AuiPaneInfo().
198                              Name("default").
199                              CenterPane().
200                              BestSize(wx.Size(900,800)).
201                              MinSize(wx.Size(900,800)).
202                              Show())
203
204        # Add the panels to the AUI manager
205        for panel_class in panels:
206            p = panel_class
207            id = wx.NewId()
208           
209            # Check whether we need to put this panel
210            # in the center pane
211            if hasattr(p, "CENTER_PANE"):
212                if p.CENTER_PANE:
213                    self.panels[str(id)] = p
214                    self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
215                                          Name(p.window_name).Caption(p.window_caption).
216                                          CenterPane().
217                                          BestSize(wx.Size(600,600)).
218                                          MinSize(wx.Size(600,600)).
219                                          Hide())
220               
221            else:
222                self.panels[str(id)] = p
223                self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
224                                  Name(p.window_name).Caption(p.window_caption).
225                                  #Floatable().
226                                  #Float().
227                                  Right().
228                                  Dock().
229                                  TopDockable().
230                                  BottomDockable().
231                                  LeftDockable().
232                                  RightDockable().
233                                  MinimizeButton().
234                                  Hide().
235                                  #Show().
236                                  BestSize(wx.Size(400,400)).
237                                  MinSize(wx.Size(100,100)))
238               
239       
240    def get_context_menu(self):
241        """
242            Get the context menu items made available
243            by the different plug-ins.
244            This function is used by the plotting module
245        """
246        menu_list = []
247        for item in self.plugins:
248            if hasattr(item, "get_context_menu"):
249                menu_list.extend(item.get_context_menu())
250           
251        return menu_list
252       
253    def popup_panel(self, p):
254        """
255            Add a panel object to the AUI manager
256            @param p: panel object to add to the AUI manager
257            @return: ID of the event associated with the new panel [int]
258        """
259       
260        ID = wx.NewId()
261        self.panels[str(ID)] = p
262       
263        count = 0
264        for item in self.panels:
265            if self.panels[item].window_name.startswith(p.window_name): 
266                count += 1
267               
268        windowname = p.window_name
269        caption = p.window_caption
270        if count>0:
271            windowname += str(count+1)
272            caption += (' '+str(count))
273           
274        p.window_name = windowname
275        p.window_caption = caption
276           
277        self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
278                          Name(windowname).Caption(caption).
279                          Floatable().
280                          #Float().
281                          Right().
282                          Dock().
283                          TopDockable().
284                          BottomDockable().
285                          LeftDockable().
286                          RightDockable().
287                          MinimizeButton().
288                          #Hide().
289                          #Show().
290                          BestSize(wx.Size(400,400)).
291                          MinSize(wx.Size(200,200)))
292       
293        # Register for showing/hiding the panel
294        wx.EVT_MENU(self, ID, self._on_view)
295       
296        self._mgr.Update()
297        return ID
298       
299    def _setup_menus(self):
300        """
301            Set up the application menus
302        """
303        # Menu
304        menubar = wx.MenuBar()
305       
306        # File menu
307        filemenu = wx.Menu()
308        filemenu.Append(101,'&Quit', 'Exit') 
309       
310        # Add sub menus
311        menubar.Append(filemenu,  '&File')
312       
313        # Plot menu
314        # Attach a menu item for each panel in our
315        # panel list that also appears in a plug-in.
316        # TODO: clean this up. We should just identify
317        # plug-in panels and add them all.
318       
319        # Only add the panel menu if there is more than one panel
320        n_panels = 0
321        for plug in self.plugins:
322            pers = plug.get_perspective()
323            if len(pers)>0:
324                n_panels += 1
325       
326        if n_panels>1:
327            viewmenu = wx.Menu()
328            for plug in self.plugins:
329                plugmenu = wx.Menu()
330                pers = plug.get_perspective()
331                if len(pers)>0:
332                    for item in self.panels:
333                        if item == 'default':
334                            continue
335                        panel = self.panels[item]
336                        if panel.window_name in pers:
337                            plugmenu.Append(int(item), panel.window_caption, "Show %s window" % panel.window_caption)
338                            wx.EVT_MENU(self, int(item), self._on_view)
339                   
340                    viewmenu.AppendMenu(wx.NewId(), plug.sub_menu, plugmenu, plug.sub_menu)
341               
342            menubar.Append(viewmenu, '&Panel')
343
344        # Perspective
345        # Attach a menu item for each defined perspective.
346        # Only add the perspective menu if there are more than one perspectves
347        n_perspectives = 0
348        for plug in self.plugins:
349            if len(plug.get_perspective()) > 0:
350                n_perspectives += 1
351       
352        if n_perspectives>1:
353            p_menu = wx.Menu()
354            for plug in self.plugins:
355                if len(plug.get_perspective()) > 0:
356                    id = wx.NewId()
357                    p_menu.Append(id, plug.sub_menu, "Switch to %s perspective" % plug.sub_menu)
358                    wx.EVT_MENU(self, id, plug.on_perspective)
359            menubar.Append(p_menu,   '&Perspective')
360 
361        # Help menu
362        helpmenu = wx.Menu()
363
364        # Look for help item in plug-ins
365        for item in self.plugins:
366            if hasattr(item, "help"):
367                id = wx.NewId()
368                helpmenu.Append(id,'&%s help' % item.sub_menu, '')
369                wx.EVT_MENU(self, id, item.help)
370       
371        if config._do_aboutbox:
372            id = wx.NewId()
373            helpmenu.Append(id,'&About', 'Software information')
374            wx.EVT_MENU(self, id, self._onAbout)
375        id = wx.NewId()
376        helpmenu.Append(id,'&Check for update', 'Check for the latest version of %s' % config.__appname__)
377        wx.EVT_MENU(self, id, self._check_update)
378       
379       
380       
381       
382        # Look for plug-in menus
383        # Add available plug-in sub-menus.
384        for item in self.plugins:
385            if hasattr(item, "populate_menu"):
386                for (self.next_id, menu, name) in item.populate_menu(self.next_id, self):
387                    menubar.Append(menu, name)
388       
389
390        menubar.Append(helpmenu, '&Help')
391         
392        self.SetMenuBar(menubar)
393       
394        # Bind handlers       
395        wx.EVT_MENU(self, 101, self.Close)
396       
397    def _on_status_event(self, evt):
398        """
399            Display status message
400        """
401        self.SetStatusText(str(evt.status))
402
403       
404    def _on_view(self, evt):
405        """
406            A panel was selected to be shown. If it's not already
407            shown, display it.
408            @param evt: menu event
409        """
410        self.show_panel(evt.GetId())
411
412    def show_panel(self, uid):
413        """
414            Shows the panel with the given id
415            @param uid: unique ID number of the panel to show
416        """
417        ID = str(uid)
418        config.printEVT("show_panel: %s" % ID)
419        if ID in self.panels.keys():
420            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown():
421                self._mgr.GetPane(self.panels[ID].window_name).Show()
422                # Hide default panel
423                self._mgr.GetPane(self.panels["default"].window_name).Hide()
424               
425               
426            self._mgr.Update()
427       
428
429    def _onClose(self, event):
430        import sys
431        wx.Exit()
432        sys.exit()
433                   
434    def Close(self, event=None):
435        """
436            Quit the application
437        """
438        import sys
439        wx.Frame.Close(self)
440        wx.Exit()
441        sys.exit()
442
443 
444    def _check_update(self, event=None): 
445        """
446            Check with the deployment server whether a new version
447            of the application is available
448        """
449        import urllib
450        try: 
451            h = urllib.urlopen(config.__update_URL__)
452            lines = h.readlines()
453            line = ''
454            if len(lines)>0:
455                line = lines[0]
456               
457                toks = line.lstrip().rstrip().split('.')
458                toks_current = config.__version__.split('.')
459                update_available = False
460                for i in range(len(toks)):
461                    if int(toks[i])>int(toks_current[i]):
462                        update_available = True
463                if update_available:
464                    #print "Version %s is available" % line.rstrip().lstrip()
465                    self.SetStatusText("Version %s is available! See the Help menu to download it." % line.rstrip().lstrip())
466                    if event != None:
467                        import webbrowser
468                        webbrowser.open(config.__download_page__)
469                else:
470                    self.SetStatusText("You have the latest version of %s" % config.__appname__)
471                    #print "Server version = %s"  % line.rstrip().lstrip()
472        except:
473            self.SetStatusText("You have the latest version of %s" % config.__appname__)
474           
475           
476    def _onAbout(self, evt):
477        """
478            Pop up the about dialog
479            @param evt: menu event
480        """
481        if config._do_aboutbox:
482            import aboutbox 
483            dialog = aboutbox.DialogAbout(None, -1, "")
484            dialog.ShowModal()
485           
486    def set_manager(self, manager):
487        """
488            Sets the application manager for this frame
489            @param manager: frame manager
490        """
491        self.app_manager = manager
492       
493    def post_init(self):
494        """
495            This initialization method is called after the GUI
496            has been created and all plug-ins loaded. It calls
497            the post_init() method of each plug-in (if it exists)
498            so that final initialization can be done.
499        """
500        for item in self.plugins:
501            if hasattr(item, "post_init"):
502                item.post_init()
503       
504    def set_perspective(self, panels):
505        """
506            Sets the perspective of the GUI.
507            Opens all the panels in the list, and closes
508            all the others.
509           
510            @param panels: list of panels
511        """
512        print "gui_mng.set_perspective"
513        for item in self.panels:
514            # Check whether this is a sticky panel
515            if hasattr(self.panels[item], "ALWAYS_ON"):
516                if self.panels[item].ALWAYS_ON:
517                    continue 
518           
519            if self.panels[item].window_name in panels:
520                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
521                    self._mgr.GetPane(self.panels[item].window_name).Show()
522            else:
523                if self._mgr.GetPane(self.panels[item].window_name).IsShown():
524                    self._mgr.GetPane(self.panels[item].window_name).Hide()
525                 
526        self._mgr.Update()
527       
528    def choose_file(self):
529        """
530            Functionality that belongs elsewhere
531            Should add a hook to specify the preferred file type/extension.
532        """
533        #TODO: clean this up
534        from data_loader import choose_data_file
535        return choose_data_file(self)
536                 
537class DefaultPanel(wx.Panel):
538    """
539        Defines the API for a panels to work with
540        the GUI manager
541    """
542    ## Internal nickname for the window, used by the AUI manager
543    window_name = "default"
544    ## Name to appear on the window title bar
545    window_caption = "Welcome panel"
546    ## Flag to tell the AUI manager to put this panel in the center pane
547    CENTER_PANE = True
548
549 
550# Toy application to test this Frame
551class ViewApp(wx.App):
552    def OnInit(self):
553        #from gui_manager import ViewerFrame
554        self.frame = ViewerFrame(None, -1, config.__appname__)   
555        self.frame.Show(True)
556
557        if hasattr(self.frame, 'special'):
558            print "Special?", self.frame.special.__class__.__name__
559            self.frame.special.SetCurrent()
560        self.SetTopWindow(self.frame)
561        return True
562   
563    def set_manager(self, manager):
564        """
565            Sets a reference to the application manager
566            of the GUI manager (Frame)
567        """
568        self.frame.set_manager(manager)
569       
570    def build_gui(self):
571        """
572            Build the GUI
573        """
574        self.frame.build_gui()
575        self.frame.post_init()
576       
577    def add_perspective(self, perspective):
578        """
579            Manually add a perspective to the application GUI
580        """
581        self.frame.add_perspective(perspective)
582       
583
584if __name__ == "__main__": 
585    app = ViewApp(0)
586    app.MainLoop()             
Note: See TracBrowser for help on using the repository browser.