source: sasview/guiframe/gui_manager.py @ f5038c06

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 f5038c06 was 3c44c66, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on guiframe

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