source: sasview/guiframe/gui_manager.py @ d45e7e9

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 d45e7e9 was 83ee3851, checked in by Gervaise Alina <gervyh@…>, 14 years ago

remove copy on data_loader

  • Property mode set to 100644
File size: 34.5 KB
Line 
1
2################################################################################
3#This software was developed by the University of Tennessee as part of the
4#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
5#project funded by the US National Science Foundation.
6#
7#See the license text in license.txt
8#
9#copyright 2008, University of Tennessee
10################################################################################
11
12"""
13How-to build an application using guiframe:
14
151- Write a main application script along the lines of dummyapp.py
162- Write a config script along the lines of config.py, and name it local_config.py
173- Write your plug-ins and place them in a directory called "perspectives".
18    - Look at local_perspectives/plotting for an example of a plug-in.
19    - A plug-in should define a class called Plugin. See abstract class below.
20
21"""
22#TODO: rewrite the status bar monstrosity
23
24import wx
25import wx.aui
26import os, sys
27import xml
28
29try:
30    # Try to find a local config
31    import imp
32    path = os.getcwd()
33    if(os.path.isfile("%s/%s.py" % (path, 'local_config'))) or \
34      (os.path.isfile("%s/%s.pyc" % (path, 'local_config'))):
35            fObj, path, descr = imp.find_module('local_config', [path])
36            config = imp.load_module('local_config', fObj, path, descr) 
37    else:
38        # Try simply importing local_config
39        import local_config as config
40except:
41    # Didn't find local config, load the default
42    import config
43   
44import warnings
45warnings.simplefilter("ignore")
46
47import logging
48from sans.guicomm.events import NewLoadedDataEvent
49from sans.guicomm.events import EVT_STATUS
50from sans.guicomm.events import EVT_NEW_PLOT,EVT_SLICER_PARS_UPDATE
51from sans.guicomm.events import EVT_ADD_MANY_DATA
52
53
54from data_manager import DataManager
55
56def quit_guiframe(parent=None):
57    """
58    Pop up message to make sure the user wants to quit the application
59    """
60    message = "Do you really want to quit \n"
61    message += "this application?"
62    dial = wx.MessageDialog(parent, message, 'Question',
63                       wx.YES_NO|wx.NO_DEFAULT|wx.ICON_QUESTION)
64    if dial.ShowModal() == wx.ID_YES:
65        return True
66    else:
67        return False
68   
69class Plugin:
70    """
71    This class defines the interface for a Plugin class
72    that can be used by the gui_manager.
73   
74    Plug-ins should be placed in a sub-directory called "perspectives".
75    For example, a plug-in called Foo should be place in "perspectives/Foo".
76    That directory contains at least two files:
77        perspectives/Foo/__init.py contains two lines:
78       
79            PLUGIN_ID = "Foo plug-in 1.0"
80            from Foo import *
81           
82        perspectives/Foo/Foo.py contains the definition of the Plugin
83        class for the Foo plug-in. The interface of that Plugin class
84        should follow the interface of the class you are looking at.
85       
86    See dummyapp.py for a plugin example.
87    """
88   
89    def __init__(self, name="Test_plugin"):
90        """
91            Abstract class for gui_manager Plugins.
92        """
93        ## Plug-in name. It will appear on the application menu.
94        self.sub_menu = name     
95       
96        ## Reference to the parent window. Filled by get_panels() below.
97        self.parent = None
98       
99        ## List of panels that you would like to open in AUI windows
100        #  for your plug-in. This defines your plug-in "perspective"
101        self.perspective = []
102       
103       
104    def populate_menu(self, id, parent):
105        """
106        Create and return the list of application menu
107        items for the plug-in.
108       
109        :param id: deprecated. Un-used.
110        :param parent: parent window
111       
112        :return: plug-in menu
113       
114        """
115        return []
116   
117    def get_panels(self, parent):
118        """
119        Create and return the list of wx.Panels for your plug-in.
120        Define the plug-in perspective.
121       
122        Panels should inherit from DefaultPanel defined below,
123        or should present the same interface. They must define
124        "window_caption" and "window_name".
125       
126        :param parent: parent window
127       
128        :return: list of panels
129       
130        """
131        ## Save a reference to the parent
132        self.parent = parent
133       
134        # Return the list of panels
135        return []
136   
137    def get_tools(self):
138        """
139        Returns a set of menu entries for tools
140        """
141        return []
142       
143   
144    def get_context_menu(self, graph=None):
145        """
146        This method is optional.
147   
148        When the context menu of a plot is rendered, the
149        get_context_menu method will be called to give you a
150        chance to add a menu item to the context menu.
151       
152        A ref to a Graph object is passed so that you can
153        investigate the plot content and decide whether you
154        need to add items to the context menu. 
155       
156        This method returns a list of menu items.
157        Each item is itself a list defining the text to
158        appear in the menu, a tool-tip help text, and a
159        call-back method.
160       
161        :param graph: the Graph object to which we attach the context menu
162       
163        :return: a list of menu items with call-back function
164       
165        """
166        return []
167   
168    def get_perspective(self):
169        """
170        Get the list of panel names for this perspective
171        """
172        return self.perspective
173   
174    def on_perspective(self, event):
175        """
176        Call back function for the perspective menu item.
177        We notify the parent window that the perspective
178        has changed.
179       
180        :param event: menu event
181       
182        """
183        self.parent.set_perspective(self.perspective)
184   
185    def post_init(self):
186        """
187        Post initialization call back to close the loose ends
188        """
189        pass
190   
191    def set_default_perspective(self):
192        """
193       Call back method that True to notify the parent that the current plug-in
194       can be set as default  perspective.
195       when returning False, the plug-in is not candidate for an automatic
196       default perspective setting
197        """
198        return False
199
200class ViewerFrame(wx.Frame):
201    """
202    Main application frame
203    """
204    def __init__(self, parent, id, title, window_height=300, window_width=300):
205        """
206        Initialize the Frame object
207        """
208        from local_perspectives.plotting import plotting
209        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, size=(window_width, window_height))
210        # Preferred window size
211        self._window_height = window_height
212        self._window_width  = window_width
213       
214        # Logging info
215        logging.basicConfig(level=logging.DEBUG,
216                    format='%(asctime)s %(levelname)s %(message)s',
217                    filename='sans_app.log',
218                    filemode='w')       
219        path = os.path.dirname(__file__)
220        temp_path= os.path.join(path,'images')
221        ico_file = os.path.join(temp_path,'ball.ico')
222        if os.path.isfile(ico_file):
223            self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
224        else:
225            temp_path= os.path.join(os.getcwd(),'images')
226            ico_file = os.path.join(temp_path,'ball.ico')
227            if os.path.isfile(ico_file):
228                self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
229       
230        ## Application manager
231        self.app_manager = None
232       
233        ## Data Manager
234        self.data_manager = DataManager(parent=self)
235       
236        ## Find plug-ins
237        # Modify this so that we can specify the directory to look into
238        self.plugins =[]
239        self.plugins.append(plotting.Plugin())
240        self.plugins += self._find_plugins()
241     
242        ## List of panels
243        self.panels = {}
244
245        ## Next available ID for wx gui events
246        #TODO:  No longer used - remove all calls to this
247        self.next_id = 20000
248
249        # Default locations
250        self._default_save_location = os.getcwd()       
251
252        # Welcome panel
253        self.defaultPanel = None
254        #panel on focus
255        self.panel_on_focus = None
256        # Check for update
257        #self._check_update(None)
258        ## maximum number of opened files' paths to store
259        self.n_maxfileopen =  2
260        ## number of file open
261        self.n_fileOpen=0
262        ## list of path of open files
263        self.filePathList=[]
264        ## list of open file with name form menu
265        #self._saveOpenData()
266        ## Dictionary of open file where keys are filename  and values are number of copy of data plotted
267        ## using the same loaded file
268        self.indice_load_data={}
269        # Register the close event so it calls our own method
270        wx.EVT_CLOSE(self, self._onClose)
271        # Register to status events
272        self.Bind(EVT_STATUS, self._on_status_event)
273        #Register add extra data on the same panel event on load
274        self.Bind(EVT_ADD_MANY_DATA, self.set_panel_on_focus)
275       
276    def set_panel_on_focus(self, event):
277        """
278        Store reference to the last panel on focus
279        """
280        self.panel_on_focus = event.panel
281       
282    def build_gui(self):
283        """
284        """
285        # Set up the layout
286        self._setup_layout()
287       
288        # Set up the menu
289        self._setup_menus()
290        #self.Fit()
291        #self._check_update(None)
292             
293    def _setup_layout(self):
294        """
295        Set up the layout
296        """
297        # Status bar
298        from statusbar import StatusBar
299        self.sb = StatusBar(self, wx.ID_ANY)
300        self.SetStatusBar(self.sb)
301        # Add panel
302        self._mgr = wx.aui.AuiManager(self)
303        self._mgr.SetDockSizeConstraint(0.5, 0.5) 
304       
305        # Load panels
306        self._load_panels()
307       
308        self._mgr.Update()
309       
310    def SetStatusText(self, *args, **kwds):
311        """
312        """
313        number = self.sb.get_msg_position()
314        wx.Frame.SetStatusText(number=number, *args, **kwds)
315       
316    def PopStatusText(self, *args, **kwds):
317        """
318        """
319        field = self.sb.get_msg_position()
320        wx.Frame.PopStatusText(field=field)
321       
322    def PushStatusText(self, *args, **kwds):
323        """
324        """
325        field = self.sb.get_msg_position()
326        wx.Frame.PushStatusText(self, field=field,string=string)
327
328    def add_perspective(self, plugin):
329        """
330        Add a perspective if it doesn't already
331        exist.
332        """
333        is_loaded = False
334        for item in self.plugins:
335             if plugin.__class__==item.__class__:
336                 print "Plugin %s already loaded" % plugin.__class__.__name__
337                 is_loaded = True
338                 
339        if not is_loaded:
340            self.plugins.append(plugin)
341     
342    def _find_plugins(self, dir="perspectives"):
343        """
344        Find available perspective plug-ins
345       
346        :param dir: directory in which to look for plug-ins
347       
348        :return: list of plug-ins
349       
350        """
351        import imp
352       
353        plugins = []
354        # Go through files in panels directory
355        try:
356            list = os.listdir(dir)
357            ## the default panel is the panel is the last plugin added
358            for item in list:
359                toks = os.path.splitext(os.path.basename(item))
360                name = None
361                if not toks[0] == '__init__':
362                   
363                    if toks[1]=='.py' or toks[1]=='':
364                        name = toks[0]
365               
366                    path = [os.path.abspath(dir)]
367                    file = None
368                    try:
369                        if toks[1]=='':
370                            mod_path = '.'.join([dir, name])
371                            module = __import__(mod_path, globals(), locals(), [name])
372                        else:
373                            (file, path, info) = imp.find_module(name, path)
374                            module = imp.load_module( name, file, item, info )
375                        if hasattr(module, "PLUGIN_ID"):
376                            try:
377                                plugins.append(module.Plugin())
378                                logging.info("Found plug-in: %s" % module.PLUGIN_ID)
379                            except:
380                                config.printEVT("Error accessing PluginPanel in %s\n  %s" % (name, sys.exc_value))
381                       
382                    except:
383                        print sys.exc_value
384                        logging.error("ViewerFrame._find_plugins: %s" % sys.exc_value)
385                    finally:
386                        if not file==None:
387                            file.close()
388        except:
389            # Should raise and catch at a higher level and display error on status bar
390            pass   
391        return plugins
392   
393    def set_welcome_panel(self, panel_class):
394        """
395        Sets the default panel as the given welcome panel
396       
397        :param panel_class: class of the welcome panel to be instantiated
398       
399        """
400        self.defaultPanel = panel_class(self, -1, style=wx.RAISED_BORDER)
401       
402    def _load_panels(self):
403        """
404        Load all panels in the panels directory
405        """
406       
407        # Look for plug-in panels
408        panels = []   
409        for item in self.plugins:
410            if hasattr(item, "get_panels"):
411                ps = item.get_panels(self)
412                panels.extend(ps)
413
414        # Show a default panel with some help information
415        # It also sets the size of the application windows
416        #TODO: Use this for slpash screen
417        if self.defaultPanel is None:
418            self.defaultPanel    = DefaultPanel(self, -1, style=wx.RAISED_BORDER)
419           
420        self.panels["default"] = self.defaultPanel
421       
422        self._mgr.AddPane(self.defaultPanel, wx.aui.AuiPaneInfo().
423                              Name("default").
424                              CenterPane().
425                              # This is where we set the size of the application window
426                              BestSize(wx.Size(self._window_width, self._window_height)).
427                              #MinSize(wx.Size(self._window_width, self._window_height)).
428                              Show())
429     
430
431        # Add the panels to the AUI manager
432        for panel_class in panels:
433            p = panel_class
434            id = wx.NewId()
435           
436            # Check whether we need to put this panel
437            # in the center pane
438            if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
439                if p.CENTER_PANE:
440                    self.panels[str(id)] = p
441                    self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
442                                          Name(p.window_name).Caption(p.window_caption).
443                                          CenterPane().
444                                          #BestSize(wx.Size(550,600)).
445                                          #MinSize(wx.Size(500,500)).
446                                          Hide())
447            else:
448                self.panels[str(id)] = p
449                self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
450                                  Name(p.window_name).Caption(p.window_caption).
451                                  Right().
452                                  Dock().
453                                  TopDockable().
454                                  BottomDockable().
455                                  LeftDockable().
456                                  RightDockable().
457                                  MinimizeButton().
458                                  Hide())
459                                  #BestSize(wx.Size(550,600)))
460                                  #MinSize(wx.Size(500,500)))                 
461     
462    def get_context_menu(self, graph=None):
463        """
464        Get the context menu items made available
465        by the different plug-ins.
466        This function is used by the plotting module
467        """
468        menu_list = []
469        for item in self.plugins:
470            if hasattr(item, "get_context_menu"):
471                menu_list.extend(item.get_context_menu(graph))
472           
473        return menu_list
474       
475    def popup_panel(self, p):
476        """
477        Add a panel object to the AUI manager
478       
479        :param p: panel object to add to the AUI manager
480       
481        :return: ID of the event associated with the new panel [int]
482       
483        """
484        ID = wx.NewId()
485        self.panels[str(ID)] = p
486       
487        count = 0
488        for item in self.panels:
489            if self.panels[item].window_name.startswith(p.window_name): 
490                count += 1
491       
492        windowname = p.window_name
493        caption = p.window_caption
494       
495        if count>0:
496            windowname += str(count+1)
497            caption += (' '+str(count))
498         
499        p.window_name = windowname
500        p.window_caption = caption
501           
502        self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
503                          Name(windowname).Caption(caption).
504                          Floatable().
505                          #Float().
506                          Right().
507                          Dock().
508                          TopDockable().
509                          BottomDockable().
510                          LeftDockable().
511                          RightDockable().
512                          MinimizeButton().
513                          #Hide().
514                          #Show().
515                          Resizable(True).
516                          # Use a large best size to make sure the AUI manager
517                          # takes all the available space
518                          BestSize(wx.Size(400,400)))
519        pane = self._mgr.GetPane(windowname)
520        self._mgr.MaximizePane(pane)
521        self._mgr.RestoreMaximizedPane()
522       
523       
524        # Register for showing/hiding the panel
525       
526        wx.EVT_MENU(self, ID, self._on_view)
527       
528        self._mgr.Update()
529        return ID
530       
531    def _setup_menus(self):
532        """
533        Set up the application menus
534        """
535        # Menu
536        menubar = wx.MenuBar()
537       
538        # File menu
539        self.filemenu = wx.Menu()
540       
541        id = wx.NewId()
542        self.filemenu.Append(id, '&Load Data', 'Load data file into the application')
543        wx.EVT_MENU(self, id, self._on_open)
544        #self.filemenu.AppendSeparator()
545       
546        id = wx.NewId()
547        self.filemenu.Append(id,'&Quit', 'Exit') 
548        wx.EVT_MENU(self, id, self.Close)
549       
550        # Add sub menus
551        menubar.Append(self.filemenu,  '&File')
552       
553        # Window menu
554        # Attach a menu item for each panel in our
555        # panel list that also appears in a plug-in.
556       
557        # Only add the panel menu if there is only one perspective and
558        # it has more than two panels.
559        # Note: the first plug-in is always the plotting plug-in. The first application
560        # plug-in is always the second one in the list.
561        if len(self.plugins)==2:
562            plug = self.plugins[1]
563            pers = plug.get_perspective()
564       
565            if len(pers)>1:
566                viewmenu = wx.Menu()
567                for item in self.panels:
568                    if item == 'default':
569                        continue
570                    panel = self.panels[item]
571                    if panel.window_name in pers:
572                        viewmenu.Append(int(item), panel.window_caption, "Show %s window" % panel.window_caption)
573                        wx.EVT_MENU(self, int(item), self._on_view)
574                menubar.Append(viewmenu, '&Window')
575
576        # Perspective
577        # Attach a menu item for each defined perspective.
578        # Only add the perspective menu if there are more than one perspectives
579        n_perspectives = 0
580        for plug in self.plugins:
581            if len(plug.get_perspective()) > 0:
582                n_perspectives += 1
583       
584        if n_perspectives>1:
585            p_menu = wx.Menu()
586            for plug in self.plugins:
587                if len(plug.get_perspective()) > 0:
588                    id = wx.NewId()
589                    p_menu.Append(id, plug.sub_menu, "Switch to %s perspective" % plug.sub_menu)
590                    wx.EVT_MENU(self, id, plug.on_perspective)
591            menubar.Append(p_menu,   '&Perspective')
592 
593        # Tools menu
594        # Go through plug-ins and find tools to populate the tools menu
595        toolsmenu = None
596        for item in self.plugins:
597            if hasattr(item, "get_tools"):
598                for tool in item.get_tools():
599                    # Only create a menu if we have at least one tool
600                    if toolsmenu is None:
601                        toolsmenu = wx.Menu()
602                    id = wx.NewId()
603                   
604                    toolsmenu.Append(id, tool[0], tool[1])
605                    wx.EVT_MENU(self, id, tool[2])
606        if toolsmenu is not None:
607            menubar.Append(toolsmenu, '&Tools')
608 
609        # Help menu
610        helpmenu = wx.Menu()
611        # add the welcome panel menu item
612        if self.defaultPanel is not None:
613            id = wx.NewId()
614            helpmenu.Append(id,'&Welcome', '')
615            helpmenu.AppendSeparator()
616            wx.EVT_MENU(self, id, self.show_welcome_panel)
617       
618        # Look for help item in plug-ins
619        for item in self.plugins:
620            if hasattr(item, "help"):
621                id = wx.NewId()
622                helpmenu.Append(id,'&%s help' % item.sub_menu, '')
623                wx.EVT_MENU(self, id, item.help)
624       
625        if config._do_aboutbox:
626            id = wx.NewId()
627            helpmenu.Append(id,'&About', 'Software information')
628            wx.EVT_MENU(self, id, self._onAbout)
629           
630        # Checking for updates needs major refactoring to work with py2exe
631        # We need to make sure it doesn't hang the application if the server
632        # is not up. We also need to make sure there's a proper executable to
633        # run if we spawn a new background process.
634        #id = wx.NewId()
635        #helpmenu.Append(id,'&Check for update', 'Check for the latest version of %s' % config.__appname__)
636        #wx.EVT_MENU(self, id, self._check_update)
637       
638        # Look for plug-in menus
639        # Add available plug-in sub-menus.
640        for item in self.plugins:
641            if hasattr(item, "populate_menu"):
642                for (self.next_id, menu, name) in item.populate_menu(self.next_id, self):
643                    menubar.Append(menu, name)
644                   
645        menubar.Append(helpmenu, '&Help')
646        self.SetMenuBar(menubar)
647   
648    def _on_status_event(self, evt):
649        """
650        Display status message
651        """
652        self.sb.set_status(event=evt)
653       
654    def _on_view(self, evt):
655        """
656        A panel was selected to be shown. If it's not already
657        shown, display it.
658       
659        :param evt: menu event
660       
661        """
662        self.show_panel(evt.GetId())
663       
664    def on_close_welcome_panel(self):
665        """
666        Close the welcome panel
667        """
668        if self.defaultPanel is None:
669            return 
670        self._mgr.GetPane(self.panels["default"].window_name).Hide()
671        self._mgr.Update()
672        # set a default perspective
673        self.set_default_perspective()
674       
675    def show_welcome_panel(self, event):
676        """   
677        Display the welcome panel
678        """
679        if self.defaultPanel is None:
680            return 
681        for id in self.panels.keys():
682            if self._mgr.GetPane(self.panels[id].window_name).IsShown():
683                self._mgr.GetPane(self.panels[id].window_name).Hide()
684        # Show default panel
685        if not self._mgr.GetPane(self.panels["default"].window_name).IsShown():
686            self._mgr.GetPane(self.panels["default"].window_name).Show()
687       
688        self._mgr.Update()
689       
690    def show_panel(self, uid):
691        """
692        Shows the panel with the given id
693       
694        :param uid: unique ID number of the panel to show
695       
696        """
697        ID = str(uid)
698        config.printEVT("show_panel: %s" % ID)
699        if ID in self.panels.keys():
700            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown():
701                self._mgr.GetPane(self.panels[ID].window_name).Show()
702                # Hide default panel
703                self._mgr.GetPane(self.panels["default"].window_name).Hide()
704       
705            self._mgr.Update()
706   
707    def set_loaded_data(self, data_list=[]):
708        """
709        Save data and path in to data manager
710        """
711        self.data_manager.set_loaded_data(data_list=data_list)
712       
713    def get_data_manager(self):
714        """
715        return data manager instance
716        """
717        return self.data_manager
718   
719    def _on_open(self, event):
720        """
721        """
722        path = self.choose_file()
723        if path is None:
724            return
725       
726        from data_loader import plot_data
727        if path and os.path.isfile(path):
728            plot_data(self, path)
729        data_list = self.data_manager.get_data()
730       
731        if self.defaultPanel is not None and \
732            self._mgr.GetPane(self.panels["default"].window_name).IsShown():
733            self.on_close_welcome_panel()
734        else:
735            for item in self.panels.keys():
736                # Check whether this is a sticky panel
737                if hasattr(self.panels[item], "ALWAYS_ON"):
738                    if self.panels[item].ALWAYS_ON:
739                        continue 
740                if self._mgr.GetPane(self.panels[item].window_name).IsShown():
741                    self.panels[item].set_data(list=data_list)
742           
743    def _onClose(self, event):
744        """
745        Store info to retrieve in xml before closing the application
746        """
747        try:
748            doc = xml.dom.minidom.Document()
749            main_node = doc.createElement("file Path")
750           
751            doc.appendChild(main_node)
752       
753            for item in self.filePathList:
754                id, menuitem_name , path, title = item
755                pt1 = doc.createElement("File")
756                pt1.setAttribute("name", menuitem_name)
757                pt2 = doc.createElement("path")
758                pt2.appendChild(doc.createTextNode(str(path)))
759                pt1.appendChild(pt2)
760                pt3 = doc.createElement("title")
761                pt3.appendChild(doc.createTextNode(str(title)))
762                pt1.appendChild(pt3)
763               
764                main_node.appendChild(pt1)
765           
766            fd = open("fileOpened.xml",'w')
767            fd.write(doc.toprettyxml())
768            fd.close()
769        except:
770            pass
771       
772        import sys
773        wx.Exit()
774        sys.exit()
775                     
776    def Close(self, event=None):
777        """
778        Quit the application
779        """
780        flag = quit_guiframe(parent=self)
781        if flag:
782            import sys
783            wx.Frame.Close(self)
784            wx.Exit()
785            sys.exit()
786
787    def _check_update(self, event=None): 
788        """
789        Check with the deployment server whether a new version
790        of the application is available.
791        A thread is started for the connecting with the server. The thread calls
792        a call-back method when the current version number has been obtained.
793        """
794        if hasattr(config, "__update_URL__"):
795            import version
796            checker = version.VersionThread(config.__update_URL__, self._process_version, baggage=event==None)
797            checker.start() 
798   
799    def _process_version(self, version, standalone=True):
800        """
801        Call-back method for the process of checking for updates.
802        This methods is called by a VersionThread object once the current
803        version number has been obtained. If the check is being done in the
804        background, the user will not be notified unless there's an update.
805       
806        :param version: version string
807        :param standalone: True of the update is being checked in
808           the background, False otherwise.
809           
810        """
811        try:
812            if cmp(version, config.__version__)>0:
813                self.SetStatusText("Version %s is available! See the Help menu to download it." % version)
814                if not standalone:
815                    import webbrowser
816                    webbrowser.open(config.__download_page__)
817            else:
818                if not standalone:
819                    self.SetStatusText("You have the latest version of %s" % config.__appname__)
820        except:
821            logging.error("guiframe: could not get latest application version number\n  %s" % sys.exc_value)
822            if not standalone:
823                self.SetStatusText("Could not connect to the application server. Please try again later.")
824                   
825       
826    def _onAbout(self, evt):
827        """
828        Pop up the about dialog
829       
830        :param evt: menu event
831       
832        """
833        if config._do_aboutbox:
834            import aboutbox 
835            dialog = aboutbox.DialogAbout(None, -1, "")
836            dialog.ShowModal()           
837           
838    def _onreloaFile(self, event): 
839        """
840        load a data previously opened
841        """
842        from data_loader import plot_data
843        for item in self.filePathList:
844            id, menuitem_name , path, title = item
845            if id == event.GetId():
846                if path and os.path.isfile(path):
847                    plot_data(self, path)
848                    break
849           
850    def set_manager(self, manager):
851        """
852        Sets the application manager for this frame
853       
854        :param manager: frame manager
855        """
856        self.app_manager = manager
857       
858    def post_init(self):
859        """
860        This initialization method is called after the GUI
861        has been created and all plug-ins loaded. It calls
862        the post_init() method of each plug-in (if it exists)
863        so that final initialization can be done.
864        """
865        for item in self.plugins:
866            if hasattr(item, "post_init"):
867                item.post_init()
868       
869    def set_default_perspective(self):
870        """
871        Choose among the plugin the first plug-in that has
872        "set_default_perspective" method and its return value is True will be
873        as a default perspective when the welcome page is closed
874        """
875        for item in self.plugins:
876            if hasattr(item, "set_default_perspective"):
877                if item.set_default_perspective():
878                    item.on_perspective(event=None)
879                    return 
880           
881    def set_perspective(self, panels):
882        """
883        Sets the perspective of the GUI.
884        Opens all the panels in the list, and closes
885        all the others.
886       
887        :param panels: list of panels
888        """
889        for item in self.panels:
890            # Check whether this is a sticky panel
891            if hasattr(self.panels[item], "ALWAYS_ON"):
892                if self.panels[item].ALWAYS_ON:
893                    continue 
894           
895            if self.panels[item].window_name in panels:
896                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
897                    self._mgr.GetPane(self.panels[item].window_name).Show()
898                    list_of_data = self.data_manager.get_data()
899                    self.panels[item].set_data(list=list_of_data)
900            else:
901                if self._mgr.GetPane(self.panels[item].window_name).IsShown():
902                    self._mgr.GetPane(self.panels[item].window_name).Hide()
903                   
904        self._mgr.Update()
905       
906    def choose_file(self, path=None):
907        """
908        Functionality that belongs elsewhere
909        Should add a hook to specify the preferred file type/extension.
910        """
911        #TODO: clean this up
912        from data_loader import choose_data_file
913       
914        # Choose a file path
915        if path==None:
916            path = choose_data_file(self, self._default_save_location)
917           
918        if not path==None:
919            try:
920                self._default_save_location = os.path.dirname(path)
921            except:
922                pass
923        return path
924   
925    def load_ascii_1D(self, path):
926        """
927        """
928        from data_loader import load_ascii_1D
929        return load_ascii_1D(path)
930                 
931class DefaultPanel(wx.Panel):
932    """
933    Defines the API for a panels to work with
934    the GUI manager
935    """
936    ## Internal nickname for the window, used by the AUI manager
937    window_name = "default"
938    ## Name to appear on the window title bar
939    window_caption = "Welcome panel"
940    ## Flag to tell the AUI manager to put this panel in the center pane
941    CENTER_PANE = True
942
943 
944# Toy application to test this Frame
945class ViewApp(wx.App):
946    """
947    """
948    def OnInit(self):
949        """
950        """
951        self.frame = ViewerFrame(None, -1, config.__appname__)   
952        self.frame.Show(True)
953
954        if hasattr(self.frame, 'special'):
955            self.frame.special.SetCurrent()
956        self.SetTopWindow(self.frame)
957        return True
958   
959    def set_manager(self, manager):
960        """
961        Sets a reference to the application manager
962        of the GUI manager (Frame)
963        """
964        self.frame.set_manager(manager)
965       
966    def build_gui(self):
967        """
968        Build the GUI
969        """
970        self.frame.build_gui()
971        self.frame.post_init()
972       
973    def set_welcome_panel(self, panel_class):
974        """
975        Set the welcome panel
976       
977        :param panel_class: class of the welcome panel to be instantiated
978       
979        """
980        self.frame.set_welcome_panel(panel_class)
981       
982    def add_perspective(self, perspective):
983        """
984        Manually add a perspective to the application GUI
985        """
986        self.frame.add_perspective(perspective)
987       
988
989if __name__ == "__main__": 
990    app = ViewApp(0)
991    app.MainLoop()             
Note: See TracBrowser for help on using the repository browser.