source: sasview/guiframe/gui_manager.py @ 6db811e

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

add data loading panel

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