source: sasview/guiframe/gui_manager.py @ c61228f

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

0.1

  • Property mode set to 100644
File size: 20.3 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()
[cbb2e40]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) 
[278cc25]21    else:
[cbb2e40]22        # Try simply importing local_config
23        import local_config as config
[41d466f]24except:
25    # Didn't find local config, load the default
26    import config
[cbb2e40]27   
[41d466f]28from sans.guicomm.events import EVT_STATUS
29
[adfcab3]30import warnings
31warnings.simplefilter("ignore")
32
33
[41d466f]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__)
[278cc25]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))
[cbb2e40]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))
[41d466f]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
[278cc25]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):
[41d466f]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()
[278cc25]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:
[fd68aa9]110             if plugin.__class__==item.__class__:
[278cc25]111                 print "Plugin %s already loaded" % plugin.__class__.__name__
112                 is_loaded = True
113                 
114        if not is_loaded:
115            self.plugins.append(plugin)
[41d466f]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
[278cc25]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       
[41d466f]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]=='':
[278cc25]151                            f.write("trying to import \n")
[41d466f]152                            mod_path = '.'.join([dir, name])
[278cc25]153                            f.write("mod_path= %s\n" % mod_path)
[41d466f]154                            module = __import__(mod_path, globals(), locals(), [name])
[278cc25]155                            f.write(str(module)+'\n')
[41d466f]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
[278cc25]169                        f.write(str(sys.exc_value)+'\n')
[41d466f]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   
[278cc25]176        f.write(str(plugins)+'\n')
177        f.close()
[41d466f]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:
[383189f9]265            if self.panels[item].window_name.startswith(p.window_name): 
[41d466f]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       
[adfcab3]310        # Add sub menus
311        menubar.Append(filemenu,  '&File')
312       
[41d466f]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       
[adfcab3]319        # Only add the panel menu if there is more than one panel
320        n_panels = 0
[41d466f]321        for plug in self.plugins:
322            pers = plug.get_perspective()
323            if len(pers)>0:
[adfcab3]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)
[41d466f]341               
[adfcab3]342            menubar.Append(viewmenu, '&Panel')
343
[41d466f]344        # Perspective
345        # Attach a menu item for each defined perspective.
[adfcab3]346        # Only add the perspective menu if there are more than one perspectves
347        n_perspectives = 0
[41d466f]348        for plug in self.plugins:
349            if len(plug.get_perspective()) > 0:
[adfcab3]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')
[41d466f]360 
361        # Help menu
362        helpmenu = wx.Menu()
[fa452e4]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       
[41d466f]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       
[adfcab3]380       
[41d466f]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()
[383189f9]422                # Hide default panel
423                self._mgr.GetPane(self.panels["default"].window_name).Hide()
424               
425               
[41d466f]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       
[278cc25]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       
[41d466f]583
584if __name__ == "__main__": 
585    app = ViewApp(0)
586    app.MainLoop()             
Note: See TracBrowser for help on using the repository browser.