source: sasview/guiframe/gui_manager.py @ aa4b8379

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

Updated for interactive graphs.

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