source: sasview/guiframe/gui_manager.py @ bf4402c3

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 bf4402c3 was bf4402c3, checked in by Gervaise Alina <gervyh@…>, 13 years ago

remove unused code

  • Property mode set to 100644
File size: 49.1 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
13import wx
14import wx.aui
15import os
16import sys
17import xml
18
19try:
20    # Try to find a local config
21    import imp
22    path = os.getcwd()
23    if(os.path.isfile("%s/%s.py" % (path, 'local_config'))) or \
24        (os.path.isfile("%s/%s.pyc" % (path, 'local_config'))):
25        fObj, path, descr = imp.find_module('local_config', [path])
26        config = imp.load_module('local_config', fObj, path, descr) 
27    else:
28        # Try simply importing local_config
29        import local_config as config
30except:
31    # Didn't find local config, load the default
32    import config
33   
34import warnings
35warnings.simplefilter("ignore")
36
37import logging
38
39from sans.guiframe.events import EVT_STATUS
40from sans.guiframe.events import EVT_ADD_MANY_DATA
41from sans.guiframe.events import StatusEvent
42from sans.guiframe.events import NewPlotEvent
43from sans.guiframe.gui_style import *
44from sans.guiframe.events import NewLoadedDataEvent
45from sans.guiframe.data_panel import DataPanel
46
47STATE_FILE_EXT = ['.inv', '.fitv', '.prv']
48DATA_MANAGER = False
49AUTO_PLOT = False
50AUTO_SET_DATA = True
51PLOPANEL_WIDTH = 400
52PLOPANEL_HEIGTH = 400
53
54
55
56class ViewerFrame(wx.Frame):
57    """
58    Main application frame
59    """
60   
61    def __init__(self, parent, id, title, 
62                 window_height=300, window_width=300,
63                 gui_style=GUIFRAME.DEFAULT_STYLE):
64        """
65        Initialize the Frame object
66        """
67       
68        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition,
69                          size=(window_width, window_height))
70        # Preferred window size
71        self._window_height = window_height
72        self._window_width  = window_width
73        self.__gui_style = gui_style
74       
75        # Logging info
76        logging.basicConfig(level=logging.DEBUG,
77                    format='%(asctime)s %(levelname)s %(message)s',
78                    filename='sans_app.log',
79                    filemode='w')       
80        path = os.path.dirname(__file__)
81        temp_path = os.path.join(path,'images')
82        ico_file = os.path.join(temp_path,'ball.ico')
83        if os.path.isfile(ico_file):
84            self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
85        else:
86            temp_path = os.path.join(os.getcwd(),'images')
87            ico_file = os.path.join(temp_path,'ball.ico')
88            if os.path.isfile(ico_file):
89                self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
90       
91        ## Application manager
92        self.app_manager = None
93        self._mgr = None
94        #add current perpsective
95        self._current_perspective = None
96        self._plotting_plugin = None
97        self._data_plugin = None
98        #Menu bar and item
99        self._menubar = None
100        self._file_menu = None
101        self._data_menu = None
102        self._window_menu = None
103        self._window_menu = None
104        self._help_menu = None
105        self._tool_menu = None
106        self._plugin_menu_list = []
107        ## Find plug-ins
108        # Modify this so that we can specify the directory to look into
109        self.plugins = []
110        #add local plugin
111        self.plugins += self._get_local_plugins()
112        self.plugins += self._find_plugins()
113        ## List of panels
114        self.panels = {}
115
116        # Default locations
117        self._default_save_location = os.getcwd()       
118       
119        # Welcome panel
120        self.defaultPanel = None
121        #panel on focus
122        self.panel_on_focus = None
123         #data manager
124        from data_manager import DataManager
125        self._data_manager = DataManager()
126        self._data_panel = DataPanel(parent=self)
127        if self.panel_on_focus is not None:
128            self._data_panel.set_panel_on_focus(self.panel_on_focus.window_caption)
129        # Check for update
130        #self._check_update(None)
131        # Register the close event so it calls our own method
132        wx.EVT_CLOSE(self, self._onClose)
133        # Register to status events
134        self.Bind(EVT_STATUS, self._on_status_event)
135        #Register add extra data on the same panel event on load
136        self.Bind(EVT_ADD_MANY_DATA, self.set_panel_on_focus)
137       
138    def set_panel_on_focus(self, event):
139        """
140        Store reference to the last panel on focus
141        """
142        self.panel_on_focus = event.panel
143        if self.panel_on_focus is not None and self._data_panel is not None:
144            self._data_panel.set_panel_on_focus(self.panel_on_focus.window_name)
145           
146    def build_gui(self):
147        """
148        """
149        # Set up the layout
150        self._setup_layout()
151       
152        # Set up the menu
153        self._setup_menus()
154        #self.Fit()
155        #self._check_update(None)
156             
157    def _setup_layout(self):
158        """
159        Set up the layout
160        """
161        # Status bar
162        from statusbar import StatusBar
163        self.sb = StatusBar(self, wx.ID_ANY)
164        self.SetStatusBar(self.sb)
165        # Add panel
166        default_flag = wx.aui.AUI_MGR_DEFAULT| wx.aui.AUI_MGR_ALLOW_ACTIVE_PANE
167        self._mgr = wx.aui.AuiManager(self, flags=default_flag)
168   
169        # Load panels
170        self._load_panels()
171        self.set_default_perspective()
172        self._mgr.Update()
173       
174    def SetStatusText(self, *args, **kwds):
175        """
176        """
177        number = self.sb.get_msg_position()
178        wx.Frame.SetStatusText(number=number, *args, **kwds)
179       
180    def PopStatusText(self, *args, **kwds):
181        """
182        """
183        field = self.sb.get_msg_position()
184        wx.Frame.PopStatusText(field=field)
185       
186    def PushStatusText(self, *args, **kwds):
187        """
188        """
189        field = self.sb.get_msg_position()
190        wx.Frame.PushStatusText(self, field=field, string=string)
191
192    def add_perspective(self, plugin):
193        """
194        Add a perspective if it doesn't already
195        exist.
196        """
197        is_loaded = False
198        for item in self.plugins:
199            if plugin.__class__ == item.__class__:
200                msg = "Plugin %s already loaded" % plugin.__class__.__name__
201                logging.info(msg)
202                is_loaded = True   
203        if not is_loaded:
204            self.plugins.append(plugin)
205     
206    def _get_local_plugins(self):
207        """
208        get plugins local to guiframe and others
209        """
210        plugins = []
211        #import guiframe local plugins
212        #check if the style contain guiframe.dataloader
213        style1 = self.__gui_style & GUIFRAME.DATALOADER_ON
214        style2 = self.__gui_style & GUIFRAME.PLOTTING_ON
215        if style1 == GUIFRAME.DATALOADER_ON:
216            try:
217                from sans.guiframe.local_perspectives.data_loader import data_loader
218                self._data_plugin = data_loader.Plugin()
219                plugins.append(self._data_plugin)
220            except:
221                msg = "ViewerFrame._get_local_plugins:"
222                msg += "cannot import dataloader plugin.\n %s" % sys.exc_value
223                logging.error(msg)
224        if style2 == GUIFRAME.PLOTTING_ON:
225            try:
226                from sans.guiframe.local_perspectives.plotting import plotting
227                self._plotting_plugin = plotting.Plugin()
228                plugins.append(self._plotting_plugin)
229            except:
230                msg = "ViewerFrame._get_local_plugins:"
231                msg += "cannot import plotting plugin.\n %s" % sys.exc_value
232                logging.error(msg)
233     
234        return plugins
235   
236    def _find_plugins(self, dir="perspectives"):
237        """
238        Find available perspective plug-ins
239       
240        :param dir: directory in which to look for plug-ins
241       
242        :return: list of plug-ins
243       
244        """
245        import imp
246        plugins = []
247        # Go through files in panels directory
248        try:
249            list = os.listdir(dir)
250            ## the default panel is the panel is the last plugin added
251            for item in list:
252                toks = os.path.splitext(os.path.basename(item))
253                name = None
254                if not toks[0] == '__init__':
255                   
256                    if toks[1] == '.py' or toks[1] == '':
257                        name = toks[0]
258               
259                    path = [os.path.abspath(dir)]
260                    file = None
261                    try:
262                        if toks[1] == '':
263                            mod_path = '.'.join([dir, name])
264                            module = __import__(mod_path, globals(),
265                                                locals(), [name])
266                        else:
267                            (file, path, info) = imp.find_module(name, path)
268                            module = imp.load_module( name, file, item, info)
269                        if hasattr(module, "PLUGIN_ID"):
270                            try: 
271                                plug = module.Plugin()
272                                if plug.set_default_perspective():
273                                    self._current_perspective = plug
274                                plugins.append(plug)
275                                msg = "Found plug-in: %s" % module.PLUGIN_ID
276                                logging.info(msg)
277                            except:
278                                msg = "Error accessing PluginPanel"
279                                msg += " in %s\n  %s" % (name, sys.exc_value)
280                                config.printEVT(msg)
281                    except:
282                        print sys.exc_value
283                        msg = "ViewerFrame._find_plugins: %s" % sys.exc_value
284                        logging.error(msg)
285                    finally:
286                        if not file == None:
287                            file.close()
288        except:
289            # Should raise and catch at a higher level and
290            # display error on status bar
291            pass   
292        return plugins
293   
294    def set_welcome_panel(self, panel_class):
295        """
296        Sets the default panel as the given welcome panel
297       
298        :param panel_class: class of the welcome panel to be instantiated
299       
300        """
301        self.defaultPanel = panel_class(self, -1, style=wx.RAISED_BORDER)
302       
303    def _get_panels_size(self, p):
304        """
305        find the proper size of the current panel
306        get the proper panel width and height
307        """
308        panel_height_min = self._window_height
309        panel_width_min = self._window_width
310        style = self.__gui_style & (GUIFRAME.MANAGER_ON)
311        if self._data_panel is not None  and (p == self._data_panel):
312            panel_width_min = self._window_width * 2/25 
313            return panel_width_min, panel_height_min
314        if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
315            style = self.__gui_style & (GUIFRAME.PLOTTING_ON|GUIFRAME.MANAGER_ON)
316            if style == (GUIFRAME.PLOTTING_ON|GUIFRAME.MANAGER_ON):
317                panel_width_min = self._window_width * 17/25 
318            return panel_width_min, panel_height_min
319        return panel_width_min, panel_height_min
320   
321    def _load_panels(self):
322        """
323        Load all panels in the panels directory
324        """
325       
326        # Look for plug-in panels
327        panels = []   
328        for item in self.plugins:
329            if hasattr(item, "get_panels"):
330                ps = item.get_panels(self)
331                panels.extend(ps)
332       
333        # Show a default panel with some help information
334        # It also sets the size of the application windows
335        #TODO: Use this for slpash screen
336        if self.defaultPanel is None:
337            self.defaultPanel = DefaultPanel(self, -1, style=wx.RAISED_BORDER)
338        # add a blank default panel always present
339        self.panels["default"] = self.defaultPanel
340        self._mgr.AddPane(self.defaultPanel, wx.aui.AuiPaneInfo().
341                              Name("default").
342                              Center().
343                              CloseButton(True).
344                              # This is where we set the size of
345                              # the application window
346                              BestSize(wx.Size(self._window_width, 
347                                               self._window_height)).
348                              Show())
349        #add data panel
350        self.panels["data_panel"] = self._data_panel
351        w, h = self._get_panels_size(self._data_panel)
352        self._mgr.AddPane(self._data_panel, wx.aui.AuiPaneInfo().
353                              Name(self._data_panel.window_name).
354                              Left().
355                              MinimizeButton().
356                              MinSize(wx.Size(w, h)).
357                              Show())
358        style = self.__gui_style & GUIFRAME.MANAGER_ON
359        if style != GUIFRAME.MANAGER_ON:
360            self._mgr.GetPane(self.panels["data_panel"].window_name).Hide()
361           
362        # Add the panels to the AUI manager
363        for panel_class in panels:
364            p = panel_class
365            id = wx.NewId()
366            w, h = self._get_panels_size(p)
367            # Check whether we need to put this panel
368            # in the center pane
369            if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
370                if p.CENTER_PANE:
371                    self.panels[str(id)] = p
372                    self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
373                                          Name(p.window_name).Caption(p.window_caption).
374                                           Center().
375                                           CloseButton(True).
376                                           MinSize(wx.Size(w, h)).
377                                           Hide())
378            else:
379                self.panels[str(id)] = p
380                self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
381                                  Name(p.window_name).Caption(p.window_caption).
382                                  Right().
383                                  Dock().
384                                  TopDockable().
385                                  BottomDockable().
386                                  LeftDockable().
387                                  RightDockable().
388                                  MinimizeButton().
389                                  Hide())       
390     
391    def get_context_menu(self, graph=None):
392        """
393        Get the context menu items made available
394        by the different plug-ins.
395        This function is used by the plotting module
396        """
397        menu_list = []
398        for item in self.plugins:
399            if hasattr(item, "get_context_menu"):
400                menu_list.extend(item.get_context_menu(graph))
401        return menu_list
402       
403    def popup_panel(self, p):
404        """
405        Add a panel object to the AUI manager
406       
407        :param p: panel object to add to the AUI manager
408       
409        :return: ID of the event associated with the new panel [int]
410       
411        """
412        ID = wx.NewId()
413        self.panels[str(ID)] = p
414        count = 0
415        for item in self.panels:
416            if self.panels[item].window_name.startswith(p.window_name): 
417                count += 1
418        windowname = p.window_name
419        caption = p.window_caption
420        if count > 0:
421            windowname += str(count+1)
422            caption += (' '+str(count))
423        p.window_name = windowname
424        p.window_caption = caption
425           
426        style1 = self.__gui_style & GUIFRAME.FIXED_PANEL
427        style2 = self.__gui_style & GUIFRAME.FLOATING_PANEL
428        if style1 == GUIFRAME.FIXED_PANEL:
429            self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
430                              Name(windowname).Caption(caption).
431                              MinimizeButton().
432                              Resizable(True).
433                              # Use a large best size to make sure the AUI
434                              # manager takes all the available space
435                              BestSize(wx.Size(PLOPANEL_WIDTH, PLOPANEL_HEIGTH)))
436            self._popup_fixed_panel(p)
437   
438        elif style2 == GUIFRAME.FLOATING_PANEL:
439            self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
440                              Name(windowname).Caption(caption).
441                              MinimizeButton().
442                              Resizable(True).
443                              # Use a large best size to make sure the AUI
444                              #  manager takes all the available space
445                              BestSize(wx.Size(PLOPANEL_WIDTH, PLOPANEL_HEIGTH)))
446            self._popup_floating_panel(p)
447           
448        pane = self._mgr.GetPane(windowname)
449        self._mgr.MaximizePane(pane)
450        self._mgr.RestoreMaximizedPane()
451        # Register for showing/hiding the panel
452        wx.EVT_MENU(self, ID, self._on_view)
453       
454        self._mgr.Update()
455        return ID
456       
457    def _populate_file_menu(self):
458        """
459        Insert menu item under file menu
460        """
461        for plugin in self.plugins:
462            if len(plugin.populate_file_menu()) > 0:
463                for item in plugin.populate_file_menu():
464                    id = wx.NewId()
465                    m_name, m_hint, m_handler = item
466                    self._filemenu.Append(id, m_name, m_hint)
467                    wx.EVT_MENU(self, id, m_handler)
468                self._filemenu.AppendSeparator()
469               
470    def _setup_menus(self):
471        """
472        Set up the application menus
473        """
474        # Menu
475        self._menubar = wx.MenuBar()
476        self._add_menu_file()
477        self._add_menu_data()
478        self._add_menu_application()
479        self._add_current_plugin_menu()
480        self._add_menu_tool()
481        self._add_menu_window()
482        self._add_help_menu()
483        self.SetMenuBar(self._menubar)
484       
485    def _add_menu_tool(self):
486        """
487        Tools menu
488        Go through plug-ins and find tools to populate the tools menu
489        """
490        style = self.__gui_style & GUIFRAME.TOOL_ON
491        if style == GUIFRAME.TOOL_ON:
492            self._tool_menu = None
493            for item in self.plugins:
494                if hasattr(item, "get_tools"):
495                    for tool in item.get_tools():
496                        # Only create a menu if we have at least one tool
497                        if self._tool_menu is None:
498                            self._tool_menu = wx.Menu()
499                        id = wx.NewId()
500                        self._tool_menu.Append(id, tool[0], tool[1])
501                        wx.EVT_MENU(self, id, tool[2])
502            if self._tool_menu is not None:
503                self._menubar.Append(self._tool_menu, '&Tools')
504               
505    def _add_current_plugin_menu(self):
506        """
507        add current plugin menu
508        """
509          # Look for plug-in menus
510        # Add available plug-in sub-menus.
511        for item in self.plugins:
512            if item != self._plotting_plugin:
513                for (menu, name) in \
514                    item.populate_menu(self):
515                    self._menubar.Append(menu, name)
516                   
517    def _add_help_menu(self):
518        """
519        add help menu
520        """
521        # Help menu
522        self._help_menu = wx.Menu()
523        # add the welcome panel menu item
524        if self.defaultPanel is not None:
525            id = wx.NewId()
526            self._help_menu.Append(id, '&Welcome', '')
527            self._help_menu.AppendSeparator()
528            wx.EVT_MENU(self, id, self.show_welcome_panel)
529        # Look for help item in plug-ins
530        for item in self.plugins:
531            if hasattr(item, "help"):
532                id = wx.NewId()
533                self._help_menu.Append(id,'&%s help' % item.sub_menu, '')
534                wx.EVT_MENU(self, id, item.help)
535        if config._do_aboutbox:
536            id = wx.NewId()
537            self._help_menu.Append(id,'&About', 'Software information')
538            wx.EVT_MENU(self, id, self._onAbout)
539       
540        # Checking for updates needs major refactoring to work with py2exe
541        # We need to make sure it doesn't hang the application if the server
542        # is not up. We also need to make sure there's a proper executable to
543        # run if we spawn a new background process.
544        #id = wx.NewId()
545        #self._help_menu.Append(id,'&Check for update',
546        #'Check for the latest version of %s' % config.__appname__)
547        #wx.EVT_MENU(self, id, self._check_update)
548        self._menubar.Append(self._help_menu, '&Help')
549           
550    def _add_menu_window(self):
551        """
552        add a menu window to the menu bar
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.
560        The first application
561        #plug-in is always the second one in the list.
562        """
563        self._window_menu = wx.Menu()
564        if self._plotting_plugin is not None:
565            for (menu, name) in self._plotting_plugin.populate_menu(self):
566                self._window_menu.AppendSubMenu(menu, name)
567        self._window_menu.AppendSeparator()
568        self._menubar.Append(self._window_menu, '&Window')
569     
570        style = self.__gui_style & GUIFRAME.MANAGER_ON
571        if style == GUIFRAME.MANAGER_ON:
572            id = wx.NewId()
573            self._window_menu.Append(id,'&Data Manager', '')
574            wx.EVT_MENU(self, id, self.show_data_panel)
575           
576        id = wx.NewId()
577        preferences_menu = wx.Menu()
578        hint = "Plot panels will floating"
579        preferences_menu.Append(id, '&Floating Plot Panel', hint)
580        wx.EVT_MENU(self, id, self.set_plotpanel_floating)
581        id = wx.NewId()
582        hint = "Plot panels will displayed within the frame"
583        preferences_menu.Append(id, '&Fixed Plot Panel', hint)
584        wx.EVT_MENU(self, id, self.set_plotpanel_fixed)
585        id = wx.NewId()
586        self._window_menu.AppendSubMenu(preferences_menu,'&Preferences')
587        #wx.EVT_MENU(self, id, self.show_preferences_panel)   
588        """
589        if len(self.plugins) == 2:
590            plug = self.plugins[1]
591            pers = plug.get_perspective()
592       
593            if len(pers) > 1:
594                self._window_menu = wx.Menu()
595                for item in self.panels:
596                    if item == 'default':
597                        continue
598                    panel = self.panels[item]
599                    if panel.window_name in pers:
600                        self._window_menu.Append(int(item),
601                                                  panel.window_caption,
602                                        "Show %s window" % panel.window_caption)
603                        wx.EVT_MENU(self, int(item), self._on_view)
604                self._menubar.Append(self._window_menu, '&Window')
605                """
606               
607    def _add_menu_application(self):
608        """
609       
610        # Attach a menu item for each defined perspective or application.
611        # Only add the perspective menu if there are more than one perspectives
612        add menu application
613        """
614        style = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
615        if style == GUIFRAME.MULTIPLE_APPLICATIONS:
616            p_menu = wx.Menu()
617            for plug in self.plugins:
618                if len(plug.get_perspective()) > 0:
619                    id = wx.NewId()
620                    p_menu.Append(id, plug.sub_menu,
621                                  "Switch to application: %s" % plug.sub_menu)
622                    wx.EVT_MENU(self, id, plug.on_perspective)
623            self._menubar.Append(p_menu, '&Applications')
624           
625    def _add_menu_file(self):
626        """
627        add menu file
628        """
629         # File menu
630        self._filemenu = wx.Menu()
631        # some menu of plugin to be seen under file menu
632        self._populate_file_menu()
633        id = wx.NewId()
634        self._filemenu.Append(id, '&Save state into File',
635                             'Save project as a SansView (svs) file')
636        wx.EVT_MENU(self, id, self._on_save)
637        id = wx.NewId()
638        self._filemenu.Append(id, '&Quit', 'Exit') 
639        wx.EVT_MENU(self, id, self.Close)
640        # Add sub menus
641        self._menubar.Append(self._filemenu, '&File')
642       
643    def _add_menu_data(self):
644        """
645        Add menu item item data to menu bar
646        """
647        # Add menu data
648        self._data_menu = wx.Menu()
649        #menu for data files
650        data_file_id = wx.NewId()
651        data_file_hint = "load one or more data in the application"
652        self._data_menu.Append(data_file_id, 
653                         '&Load Data File(s)', data_file_hint)
654        wx.EVT_MENU(self, data_file_id, self._load_data)
655        style = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
656        style1 = self.__gui_style & GUIFRAME.SINGLE_APPLICATION
657        if style == GUIFRAME.MULTIPLE_APPLICATIONS:
658            #menu for data from folder
659            data_folder_id = wx.NewId()
660            data_folder_hint = "load multiple data in the application"
661            self._data_menu.Append(data_folder_id, 
662                             '&Load Data Folder', data_folder_hint)
663            wx.EVT_MENU(self, data_folder_id, self._load_folder)
664            self._menubar.Append(self._data_menu, '&Data')
665        elif style1 == GUIFRAME.SINGLE_APPLICATION:
666            self._menubar.Append(self._data_menu, '&Data')
667       
668    def _load_data(self, event):
669        """
670        connect menu item load data with the first plugin that can load data
671        """
672        for plug in self.plugins:
673            if plug.can_load_data():
674                plug.load_data(event)
675        style = self.__gui_style & GUIFRAME.MANAGER_ON
676        if style == GUIFRAME.MANAGER_ON:
677            self.show_data_panel(event=None)
678       
679    def _load_folder(self, event):
680        """
681        connect menu item load data with the first plugin that can load data and
682        folder
683        """
684        for plug in self.plugins:
685            if plug.can_load_data():
686                plug.load_folder(event)
687        style = self.__gui_style & GUIFRAME.MANAGER_ON
688        if style == GUIFRAME.MANAGER_ON:
689            self.show_data_panel(event=None)
690               
691    def _on_status_event(self, evt):
692        """
693        Display status message
694        """
695        self.sb.set_status(event=evt)
696       
697    def _on_view(self, evt):
698        """
699        A panel was selected to be shown. If it's not already
700        shown, display it.
701       
702        :param evt: menu event
703       
704        """
705        self.show_panel(evt.GetId())
706       
707    def on_close_welcome_panel(self):
708        """
709        Close the welcome panel
710        """
711        if self.defaultPanel is None:
712            return 
713        self._mgr.GetPane(self.panels["default"].window_name).Hide()
714        self._mgr.Update()
715        # set a default perspective
716        self.set_default_perspective()
717       
718    def show_welcome_panel(self, event):
719        """   
720        Display the welcome panel
721        """
722        if self.defaultPanel is None:
723            return 
724        for id in self.panels.keys():
725            if id  ==  'default':
726                # Show default panel
727                if not self._mgr.GetPane(self.panels["default"].window_name).IsShown():
728                    self._mgr.GetPane(self.panels["default"].window_name).Show(True)
729            elif id == "data_panel":
730                flag = self._mgr.GetPane(self.panels["data_panel"].window_name).IsShown()
731                self._mgr.GetPane(self.panels["data_panel"].window_name).Show(flag)
732            else:
733                self._mgr.GetPane(self.panels[id].window_name).IsShown()
734                self._mgr.GetPane(self.panels[id].window_name).Hide()
735        self._mgr.Update()
736       
737    def show_panel(self, uid):
738        """
739        Shows the panel with the given id
740       
741        :param uid: unique ID number of the panel to show
742       
743        """
744        ID = str(uid)
745        config.printEVT("show_panel: %s" % ID)
746        if ID in self.panels.keys():
747            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown():
748                self._mgr.GetPane(self.panels[ID].window_name).Show()
749                # Hide default panel
750                self._mgr.GetPane(self.panels["default"].window_name).Hide()
751            self._mgr.Update()
752   
753    def _on_open(self, event):
754        """
755        """
756        path = self.choose_file()
757        if path is None:
758            return
759       
760        from data_loader import plot_data
761        from sans.perspectives import invariant
762        if path and os.path.isfile(path):
763            basename  = os.path.basename(path)
764            if  basename.endswith('.svs'):
765                #remove panels for new states
766                for item in self.panels:
767                    try:
768                        self.panels[item].clear_panel()
769                    except:
770                        pass
771                #reset states and plot data
772                for item in STATE_FILE_EXT:
773                    exec "plot_data(self, path,'%s')" % str(item)
774            else:
775                plot_data(self, path)
776        if self.defaultPanel is not None and \
777            self._mgr.GetPane(self.panels["default"].window_name).IsShown():
778            self.on_close_welcome_panel()
779           
780    def _on_save(self, event):
781        """
782        Save state into a file
783        """
784        # Ask the user the location of the file to write to.
785       
786        ## Default file location for save
787        self._default_save_location = os.getcwd()
788        path = None
789        dlg = wx.FileDialog(self, "Choose a file",
790                            self._default_save_location, "", "*.svs", wx.SAVE)
791        if dlg.ShowModal() == wx.ID_OK:
792            path = dlg.GetPath()
793            self._default_save_location = os.path.dirname(path)
794        else:
795            return None
796        dlg.Destroy()
797        if path is None:
798            return
799        # default cansas xml doc
800        doc = None
801        for item in self.panels:
802            try:
803                if self.panels[item].window_name == 'Invariant':
804                    data = self.panels[item]._data
805                    if data != None:
806                        state = self.panels[item].state
807                        manager = self.panels[item]._manager
808                        new_doc = manager.state_reader.write_toXML(data, state)
809                        if hasattr(doc, "firstChild"):
810                            child = new_doc.firstChild.firstChild
811                            doc.firstChild.appendChild(child) 
812                        else:
813                            doc = new_doc
814                elif self.panels[item].window_name == 'pr_control':
815                    data = self.panels[item].manager.current_plottable
816                    if data != None:
817                        state = self.panels[item].get_state()
818                        manager = self.panels[item].manager
819                        new_doc = manager.state_reader.write_toXML(data, state)
820                        if hasattr(doc, "firstChild"):
821                            child = new_doc.firstChild.firstChild
822                            doc.firstChild.appendChild(child) 
823                        else:
824                            doc = new_doc
825                elif self.panels[item].window_name == 'Fit panel':
826                    for index in range(self.panels[item].GetPageCount()):
827                        selected_page = self.panels[item].GetPage(index) 
828                        if hasattr(selected_page,"get_data"):
829                            data = selected_page.get_data()
830                            state = selected_page.state
831                            reader = selected_page.manager.state_reader
832                            new_doc = reader.write_toXML(data, state)
833                            if doc != None and hasattr(doc, "firstChild"):
834                                child = new_doc.firstChild.firstChild
835                                doc.firstChild.appendChild(child)
836                            else:
837                                doc = new_doc
838            except: 
839                pass
840        # Write the XML document
841        if doc != None:
842            fd = open(path, 'w')
843            fd.write(doc.toprettyxml())
844            fd.close()
845        else:
846            #print "Nothing to save..."
847            raise RuntimeError, "%s is not a SansView (.svs) file..." % path
848
849    def _onClose(self, event):
850        """
851        Store info to retrieve in xml before closing the application
852        """
853        wx.Exit()
854        sys.exit()
855                 
856    def quit_guiframe(self):
857        """
858        Pop up message to make sure the user wants to quit the application
859        """
860        message = "Do you really want to quit \n"
861        message += "this application?"
862        dial = wx.MessageDialog(self, message, 'Question',
863                           wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
864        if dial.ShowModal() == wx.ID_YES:
865            return True
866        else:
867            return False   
868       
869    def Close(self, event=None):
870        """
871        Quit the application
872        """
873        flag = self.quit_guiframe()
874        if flag:
875            wx.Frame.Close(self)
876            wx.Exit()
877            sys.exit()
878
879    def _check_update(self, event=None): 
880        """
881        Check with the deployment server whether a new version
882        of the application is available.
883        A thread is started for the connecting with the server. The thread calls
884        a call-back method when the current version number has been obtained.
885        """
886        if hasattr(config, "__update_URL__"):
887            import version
888            checker = version.VersionThread(config.__update_URL__,
889                                            self._process_version,
890                                            baggage=event==None)
891            checker.start() 
892   
893    def _process_version(self, version, standalone=True):
894        """
895        Call-back method for the process of checking for updates.
896        This methods is called by a VersionThread object once the current
897        version number has been obtained. If the check is being done in the
898        background, the user will not be notified unless there's an update.
899       
900        :param version: version string
901        :param standalone: True of the update is being checked in
902           the background, False otherwise.
903           
904        """
905        try:
906            if cmp(version, config.__version__) > 0:
907                msg = "Version %s is available! See the Help "
908                msg += "menu to download it." % version
909                self.SetStatusText(msg)
910                if not standalone:
911                    import webbrowser
912                    webbrowser.open(config.__download_page__)
913            else:
914                if not standalone:
915                    msg = "You have the latest version"
916                    msg += " of %s" % config.__appname__
917                    self.SetStatusText(msg)
918        except:
919            msg = "guiframe: could not get latest application"
920            msg += " version number\n  %s" % sys.exc_value
921            logging.error(msg)
922            if not standalone:
923                msg = "Could not connect to the application server."
924                msg += " Please try again later."
925                self.SetStatusText(msg)
926                   
927    def _onAbout(self, evt):
928        """
929        Pop up the about dialog
930       
931        :param evt: menu event
932       
933        """
934        if config._do_aboutbox:
935            import aboutbox 
936            dialog = aboutbox.DialogAbout(None, -1, "")
937            dialog.ShowModal()           
938           
939    def set_manager(self, manager):
940        """
941        Sets the application manager for this frame
942       
943        :param manager: frame manager
944        """
945        self.app_manager = manager
946       
947    def post_init(self):
948        """
949        This initialization method is called after the GUI
950        has been created and all plug-ins loaded. It calls
951        the post_init() method of each plug-in (if it exists)
952        so that final initialization can be done.
953        """
954        for item in self.plugins:
955            if hasattr(item, "post_init"):
956                item.post_init()
957       
958    def set_default_perspective(self):
959        """
960        Choose among the plugin the first plug-in that has
961        "set_default_perspective" method and its return value is True will be
962        as a default perspective when the welcome page is closed
963        """
964        for item in self.plugins:
965            if hasattr(item, "set_default_perspective"):
966                if item.set_default_perspective():
967                    item.on_perspective(event=None)
968                    return 
969       
970    def set_perspective(self, panels):
971        """
972        Sets the perspective of the GUI.
973        Opens all the panels in the list, and closes
974        all the others.
975       
976        :param panels: list of panels
977        """
978       
979        for item in self.panels:
980            # Check whether this is a sticky panel
981            if hasattr(self.panels[item], "ALWAYS_ON"):
982                if self.panels[item].ALWAYS_ON:
983                    continue 
984            if self.panels[item].window_name in panels:
985                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
986                    self._mgr.GetPane(self.panels[item].window_name).Show()
987            else:
988                # always show the data panel if enable
989                style = self.__gui_style & GUIFRAME.MANAGER_ON
990                if (style == GUIFRAME.MANAGER_ON) and self.panels[item] == self._data_panel:
991                    if 'data_panel' in self.panels.keys():
992                        flag = self._mgr.GetPane(self.panels['data_panel'].window_name).IsShown()
993                        self._mgr.GetPane(self.panels['data_panel'].window_name).Show(flag)
994                else:
995                    if self._mgr.GetPane(self.panels[item].window_name).IsShown():
996                        self._mgr.GetPane(self.panels[item].window_name).Hide()
997        self._mgr.Update()
998       
999    def choose_file(self, path=None):
1000        """
1001        Functionality that belongs elsewhere
1002        Should add a hook to specify the preferred file type/extension.
1003        """
1004        #TODO: clean this up
1005        from .data_loader import choose_data_file
1006        # Choose a file path
1007        if path == None:
1008            path = choose_data_file(self, self._default_save_location)
1009        if not path == None:
1010            try:
1011                self._default_save_location = os.path.dirname(path)
1012            except:
1013                pass
1014        return path
1015   
1016    def show_data_panel(self, event=None):
1017        """
1018        show the data panel
1019        """
1020        pane = self._mgr.GetPane(self.panels["data_panel"].window_name)
1021        #if not pane.IsShown():
1022        pane.Show(True)
1023        self._mgr.Update()
1024 
1025    def add_data(self, data_list):
1026        """
1027        receive a list of data . store them its data manager if possible
1028        determine if data was be plot of send to data perspectives
1029        """
1030        #send a list of available data to plotting plugin
1031        avalaible_data = []
1032        if self._data_manager is not None:
1033            self._data_manager.add_data(data_list)
1034            avalaible_data = self._data_manager.get_all_data()
1035           
1036        style = self.__gui_style & GUIFRAME.MANAGER_ON
1037        if style == GUIFRAME.MANAGER_ON:
1038            if self._data_panel is not None:
1039                data_state = self._data_manager.get_selected_data()
1040                self._data_panel.load_data_list(data_state)
1041                self._mgr.GetPane(self._data_panel.window_name).Show(True)
1042                #wait for button press from the data panel to send data
1043        else:
1044            #automatically send that to the current perspective
1045            style = self.__gui_style & GUIFRAME.SINGLE_APPLICATION
1046            if style == GUIFRAME.SINGLE_APPLICATION:
1047                self.set_data(data_list)
1048               
1049    def get_data_from_panel(self, data_id, plot=False,append=False):
1050        """
1051        receive a list of data key retreive the data from data manager and set
1052        then to the current perspective
1053        """
1054        data_dict = self._data_manager.get_by_id(data_id)
1055        data_list = []
1056        for data_state in data_dict.values():
1057            data_list.append(data_state.data)
1058        if plot:
1059            self.plot_data(data_list, append=append)
1060        else:
1061            #sent data to active application
1062            self.set_data(data_list=data_list)
1063       
1064       
1065    def set_data(self, data_list):
1066        """
1067        set data to current perspective
1068        """
1069        if self._current_perspective is not None:
1070            try:
1071                self._current_perspective.set_data(data_list)
1072            except:
1073                msg = str(sys.exc_value)
1074                wx.PostEvent(self, StatusEvent(status=msg, info="error"))
1075        else:
1076            msg = "Guiframe does not have a current perspective"
1077            logging.info(msg)
1078           
1079    def plot_data(self, data_list, append=False):
1080        """
1081        send a list of data to plot
1082        """
1083        if not data_list:
1084            message = "Please check data to plot or append"
1085            wx.PostEvent(self, StatusEvent(status=message, info='warning'))
1086            return 
1087        for new_plot in data_list:
1088            if append:
1089                if self.panel_on_focus is None or \
1090                    not self.enable_add_data(new_plot):
1091                    message = "cannot append plot. No plot panel on focus!"
1092                    message += "please click on any available plot to set focus"
1093                    wx.PostEvent(self, StatusEvent(status=message, 
1094                                                   info='warning'))
1095                    return 
1096                else:
1097                    if self.enable_add_data(new_plot):
1098                        new_plot.group_id = self.panel_on_focus.group_id
1099            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
1100                                                  title=str(new_plot.title)))
1101           
1102    def add_theory(self, data_id, theory):
1103        """
1104        """
1105        self._data_manager.append_theory(data_id, theory)
1106        style = self.__gui_style & GUIFRAME.MANAGER_ON
1107        if style == GUIFRAME.MANAGER_ON:
1108            if self._data_panel is not None:
1109                data_state = self._data_manager.get_by_id([data_id])
1110                self._data_panel.load_data_list(data_state)
1111               
1112    def delete_data(self, data_id, theory_id=None, delete_all=True):
1113        """
1114        Delete data state if data_id is provide
1115        delete theory created with data of id data_id if theory_id is provide
1116        if delete all true: delete the all state
1117        else delete theory
1118        """
1119        self._data_manager.delete_data(data_id=data_id, 
1120                                       theory_id=theory_id, 
1121                                       delete_all=delete_all)
1122        for plug in self.plugins:
1123            plug.delete_data(data_id)
1124           
1125       
1126    def set_current_perspective(self, perspective):
1127        """
1128        set the current active perspective
1129        """
1130        self._current_perspective = perspective
1131        name = "No current Application selected"
1132        if self._current_perspective is not None and \
1133            self._data_panel is not None:
1134            name = self._current_perspective.sub_menu
1135            self._data_panel.set_active_perspective(name)
1136           
1137    def set_plotpanel_floating(self, event=None):
1138        """
1139        make the plot panel floatable
1140        """
1141        self.__gui_style &= (~GUIFRAME.FIXED_PANEL)
1142        self.__gui_style |= GUIFRAME.FLOATING_PANEL
1143        for p in self.panels.values():
1144            plot_panel = self._plotting_plugin.plot_panels
1145            for p in self.panels.values():
1146                if p in plot_panel:
1147                    self._popup_floating_panel(p)
1148       
1149    def set_plotpanel_fixed(self, event=None):
1150        """
1151        make the plot panel fixed
1152        """
1153        self.__gui_style &= (~GUIFRAME.FLOATING_PANEL)
1154        self.__gui_style |= GUIFRAME.FIXED_PANEL
1155        plot_panel = []
1156        if self._plotting_plugin is not None:
1157            plot_panel = self._plotting_plugin.plot_panels
1158            for p in self.panels.values():
1159                if p in plot_panel:
1160                    self._popup_fixed_panel(p)
1161                   
1162    def _popup_fixed_panel(self, p):
1163        """
1164        """
1165        style = self.__gui_style & GUIFRAME.FIXED_PANEL
1166        if style == GUIFRAME.FIXED_PANEL:
1167            self._mgr.GetPane(p.window_name).Floatable()
1168            self._mgr.GetPane(p.window_name).Right()
1169            self._mgr.GetPane(p.window_name).TopDockable(False)
1170            self._mgr.GetPane(p.window_name).BottomDockable(False)
1171            self._mgr.GetPane(p.window_name).LeftDockable(False)
1172            self._mgr.GetPane(p.window_name).RightDockable(True)
1173            flag = self._mgr.GetPane(p.window_name).IsShown()
1174            self._mgr.GetPane(p.window_name).Show(flag)
1175            self._mgr.Update()
1176           
1177    def _popup_floating_panel(self, p):
1178        """
1179        """
1180        style = self.__gui_style &  GUIFRAME.FLOATING_PANEL
1181        if style == GUIFRAME.FLOATING_PANEL: 
1182            self._mgr.GetPane(p.window_name).Floatable(True)
1183            self._mgr.GetPane(p.window_name).Float()
1184            self._mgr.GetPane(p.window_name).Dockable(False)
1185            flag = self._mgr.GetPane(p.window_name).IsShown()
1186            self._mgr.GetPane(p.window_name).Show(flag)
1187            self._mgr.Update()
1188           
1189    def enable_add_data(self, new_plot):
1190        """
1191        Enable append data on a plot panel
1192        """
1193        is_theory = len(self.panel_on_focus.plots) <= 1 and \
1194            self.panel_on_focus.plots.values()[0].__class__.__name__ == "Theory1D"
1195           
1196        is_data2d = hasattr(new_plot, 'data')
1197        is_data1d = self.panel_on_focus.__class__.__name__ == "ModelPanel1D"\
1198            and self.panel_on_focus.group_id is not None
1199        has_meta_data = hasattr(new_plot, 'meta_data')
1200       
1201        #disable_add_data if the data is being recovered from  a saved state file.
1202        is_state_data = False
1203        if has_meta_data:
1204            if 'invstate' in new_plot.meta_data: is_state_data = True
1205            if  'prstate' in new_plot.meta_data: is_state_data = True
1206            if  'fitstate' in new_plot.meta_data: is_state_data = True
1207   
1208        return is_data1d and not is_data2d and not is_theory and not is_state_data
1209       
1210class DefaultPanel(wx.Panel):
1211    """
1212    Defines the API for a panels to work with
1213    the GUI manager
1214    """
1215    ## Internal nickname for the window, used by the AUI manager
1216    window_name = "default"
1217    ## Name to appear on the window title bar
1218    window_caption = "Welcome panel"
1219    ## Flag to tell the AUI manager to put this panel in the center pane
1220    CENTER_PANE = True
1221
1222 
1223# Toy application to test this Frame
1224class ViewApp(wx.App):
1225    """
1226    """
1227    def OnInit(self):
1228        """
1229        """
1230        self.frame = ViewerFrame(None, -1, config.__appname__)   
1231        self.frame.Show(True)
1232
1233        if hasattr(self.frame, 'special'):
1234            self.frame.special.SetCurrent()
1235        self.SetTopWindow(self.frame)
1236        return True
1237   
1238    def set_manager(self, manager):
1239        """
1240        Sets a reference to the application manager
1241        of the GUI manager (Frame)
1242        """
1243        self.frame.set_manager(manager)
1244       
1245    def build_gui(self):
1246        """
1247        Build the GUI
1248        """
1249        self.frame.build_gui()
1250        self.frame.post_init()
1251       
1252    def set_welcome_panel(self, panel_class):
1253        """
1254        Set the welcome panel
1255       
1256        :param panel_class: class of the welcome panel to be instantiated
1257       
1258        """
1259        self.frame.set_welcome_panel(panel_class)
1260       
1261    def add_perspective(self, perspective):
1262        """
1263        Manually add a perspective to the application GUI
1264        """
1265        self.frame.add_perspective(perspective)
1266       
1267
1268if __name__ == "__main__": 
1269    app = ViewApp(0)
1270    app.MainLoop()
1271
1272             
Note: See TracBrowser for help on using the repository browser.