source: sasview/guiframe/gui_manager.py @ 213892bc

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

work in data loading guiframe

  • Property mode set to 100644
File size: 48.9 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_name)
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 * 4/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 * 13/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 in 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        self.show_data_panel(event=None)
681        print "_load_data"
682               
683    def _load_folder(self, event):
684        """
685        connect menu item load data with the first plugin that can load data and
686        folder
687        """
688        for plug in self.plugins:
689            if plug.can_load_data():
690                plug.load_folder(event)
691        self.show_data_panel(event=None)
692               
693    def _on_status_event(self, evt):
694        """
695        Display status message
696        """
697        self.sb.set_status(event=evt)
698       
699    def _on_view(self, evt):
700        """
701        A panel was selected to be shown. If it's not already
702        shown, display it.
703       
704        :param evt: menu event
705       
706        """
707        self.show_panel(evt.GetId())
708       
709    def on_close_welcome_panel(self):
710        """
711        Close the welcome panel
712        """
713        if self.defaultPanel is None:
714            return 
715        self._mgr.GetPane(self.panels["default"].window_name).Hide()
716        self._mgr.Update()
717        # set a default perspective
718        self.set_default_perspective()
719       
720    def show_welcome_panel(self, event):
721        """   
722        Display the welcome panel
723        """
724        if self.defaultPanel is None:
725            return 
726        for id in self.panels.keys():
727            if id  ==  'default':
728                # Show default panel
729                if not self._mgr.GetPane(self.panels["default"].window_name).IsShown():
730                    self._mgr.GetPane(self.panels["default"].window_name).Show(True)
731            elif id == "data_panel":
732                flag = self._mgr.GetPane(self.panels["data_panel"].window_name).IsShown()
733                self._mgr.GetPane(self.panels["data_panel"].window_name).Show(flag)
734            else:
735                self._mgr.GetPane(self.panels[id].window_name).IsShown()
736                self._mgr.GetPane(self.panels[id].window_name).Hide()
737        self._mgr.Update()
738       
739    def show_panel(self, uid):
740        """
741        Shows the panel with the given id
742       
743        :param uid: unique ID number of the panel to show
744       
745        """
746        ID = str(uid)
747        config.printEVT("show_panel: %s" % ID)
748        if ID in self.panels.keys():
749            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown():
750                self._mgr.GetPane(self.panels[ID].window_name).Show()
751                # Hide default panel
752                self._mgr.GetPane(self.panels["default"].window_name).Hide()
753            self._mgr.Update()
754   
755    def _on_open(self, event):
756        """
757        """
758        path = self.choose_file()
759        if path is None:
760            return
761       
762        from data_loader import plot_data
763        from sans.perspectives import invariant
764        if path and os.path.isfile(path):
765            basename  = os.path.basename(path)
766            if  basename.endswith('.svs'):
767                #remove panels for new states
768                for item in self.panels:
769                    try:
770                        self.panels[item].clear_panel()
771                    except:
772                        pass
773                #reset states and plot data
774                for item in STATE_FILE_EXT:
775                    exec "plot_data(self, path,'%s')" % str(item)
776            else:
777                plot_data(self, path)
778        if self.defaultPanel is not None and \
779            self._mgr.GetPane(self.panels["default"].window_name).IsShown():
780            self.on_close_welcome_panel()
781           
782    def _on_save(self, event):
783        """
784        Save state into a file
785        """
786        # Ask the user the location of the file to write to.
787       
788        ## Default file location for save
789        self._default_save_location = os.getcwd()
790        path = None
791        dlg = wx.FileDialog(self, "Choose a file",
792                            self._default_save_location, "", "*.svs", wx.SAVE)
793        if dlg.ShowModal() == wx.ID_OK:
794            path = dlg.GetPath()
795            self._default_save_location = os.path.dirname(path)
796        else:
797            return None
798        dlg.Destroy()
799        if path is None:
800            return
801        # default cansas xml doc
802        doc = None
803        for item in self.panels:
804            try:
805                if self.panels[item].window_name == 'Invariant':
806                    data = self.panels[item]._data
807                    if data != None:
808                        state = self.panels[item].state
809                        manager = self.panels[item]._manager
810                        new_doc = manager.state_reader.write_toXML(data, state)
811                        if hasattr(doc, "firstChild"):
812                            child = new_doc.firstChild.firstChild
813                            doc.firstChild.appendChild(child) 
814                        else:
815                            doc = new_doc
816                elif self.panels[item].window_name == 'pr_control':
817                    data = self.panels[item].manager.current_plottable
818                    if data != None:
819                        state = self.panels[item].get_state()
820                        manager = self.panels[item].manager
821                        new_doc = manager.state_reader.write_toXML(data, state)
822                        if hasattr(doc, "firstChild"):
823                            child = new_doc.firstChild.firstChild
824                            doc.firstChild.appendChild(child) 
825                        else:
826                            doc = new_doc
827                elif self.panels[item].window_name == 'Fit panel':
828                    for index in range(self.panels[item].GetPageCount()):
829                        selected_page = self.panels[item].GetPage(index) 
830                        if hasattr(selected_page,"get_data"):
831                            data = selected_page.get_data()
832                            state = selected_page.state
833                            reader = selected_page.manager.state_reader
834                            new_doc = reader.write_toXML(data, state)
835                            if doc != None and hasattr(doc, "firstChild"):
836                                child = new_doc.firstChild.firstChild
837                                doc.firstChild.appendChild(child)
838                            else:
839                                doc = new_doc
840            except: 
841                pass
842        # Write the XML document
843        if doc != None:
844            fd = open(path, 'w')
845            fd.write(doc.toprettyxml())
846            fd.close()
847        else:
848            #print "Nothing to save..."
849            raise RuntimeError, "%s is not a SansView (.svs) file..." % path
850
851    def _onClose(self, event):
852        """
853        Store info to retrieve in xml before closing the application
854        """
855        wx.Exit()
856        sys.exit()
857                 
858    def quit_guiframe(self):
859        """
860        Pop up message to make sure the user wants to quit the application
861        """
862        message = "Do you really want to quit \n"
863        message += "this application?"
864        dial = wx.MessageDialog(self, message, 'Question',
865                           wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
866        if dial.ShowModal() == wx.ID_YES:
867            return True
868        else:
869            return False   
870       
871    def Close(self, event=None):
872        """
873        Quit the application
874        """
875        flag = self.quit_guiframe()
876        if flag:
877            wx.Frame.Close(self)
878            wx.Exit()
879            sys.exit()
880
881    def _check_update(self, event=None): 
882        """
883        Check with the deployment server whether a new version
884        of the application is available.
885        A thread is started for the connecting with the server. The thread calls
886        a call-back method when the current version number has been obtained.
887        """
888        if hasattr(config, "__update_URL__"):
889            import version
890            checker = version.VersionThread(config.__update_URL__,
891                                            self._process_version,
892                                            baggage=event==None)
893            checker.start() 
894   
895    def _process_version(self, version, standalone=True):
896        """
897        Call-back method for the process of checking for updates.
898        This methods is called by a VersionThread object once the current
899        version number has been obtained. If the check is being done in the
900        background, the user will not be notified unless there's an update.
901       
902        :param version: version string
903        :param standalone: True of the update is being checked in
904           the background, False otherwise.
905           
906        """
907        try:
908            if cmp(version, config.__version__) > 0:
909                msg = "Version %s is available! See the Help "
910                msg += "menu to download it." % version
911                self.SetStatusText(msg)
912                if not standalone:
913                    import webbrowser
914                    webbrowser.open(config.__download_page__)
915            else:
916                if not standalone:
917                    msg = "You have the latest version"
918                    msg += " of %s" % config.__appname__
919                    self.SetStatusText(msg)
920        except:
921            msg = "guiframe: could not get latest application"
922            msg += " version number\n  %s" % sys.exc_value
923            logging.error(msg)
924            if not standalone:
925                msg = "Could not connect to the application server."
926                msg += " Please try again later."
927                self.SetStatusText(msg)
928                   
929    def _onAbout(self, evt):
930        """
931        Pop up the about dialog
932       
933        :param evt: menu event
934       
935        """
936        if config._do_aboutbox:
937            import aboutbox 
938            dialog = aboutbox.DialogAbout(None, -1, "")
939            dialog.ShowModal()           
940           
941    def set_manager(self, manager):
942        """
943        Sets the application manager for this frame
944       
945        :param manager: frame manager
946        """
947        self.app_manager = manager
948       
949    def post_init(self):
950        """
951        This initialization method is called after the GUI
952        has been created and all plug-ins loaded. It calls
953        the post_init() method of each plug-in (if it exists)
954        so that final initialization can be done.
955        """
956        for item in self.plugins:
957            if hasattr(item, "post_init"):
958                item.post_init()
959       
960    def set_default_perspective(self):
961        """
962        Choose among the plugin the first plug-in that has
963        "set_default_perspective" method and its return value is True will be
964        as a default perspective when the welcome page is closed
965        """
966        for item in self.plugins:
967            if hasattr(item, "set_default_perspective"):
968                if item.set_default_perspective():
969                    item.on_perspective(event=None)
970                    return 
971       
972    def set_perspective(self, panels):
973        """
974        Sets the perspective of the GUI.
975        Opens all the panels in the list, and closes
976        all the others.
977       
978        :param panels: list of panels
979        """
980       
981        for item in self.panels:
982            # Check whether this is a sticky panel
983            if hasattr(self.panels[item], "ALWAYS_ON"):
984                if self.panels[item].ALWAYS_ON:
985                    continue 
986            if self.panels[item].window_name in panels:
987                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
988                    self._mgr.GetPane(self.panels[item].window_name).Show()
989            else:
990                # always show the data panel if enable
991                style = self.__gui_style & GUIFRAME.MANAGER_ON
992                if (style == GUIFRAME.MANAGER_ON) and self.panels[item] == self._data_panel:
993                    if 'data_panel' in self.panels.keys():
994                        flag = self._mgr.GetPane(self.panels['data_panel'].window_name).IsShown()
995                        self._mgr.GetPane(self.panels['data_panel'].window_name).Show(flag)
996                else:
997                    if self._mgr.GetPane(self.panels[item].window_name).IsShown():
998                        self._mgr.GetPane(self.panels[item].window_name).Hide()
999        self._mgr.Update()
1000       
1001    def choose_file(self, path=None):
1002        """
1003        Functionality that belongs elsewhere
1004        Should add a hook to specify the preferred file type/extension.
1005        """
1006        #TODO: clean this up
1007        from .data_loader import choose_data_file
1008        # Choose a file path
1009        if path == None:
1010            path = choose_data_file(self, self._default_save_location)
1011        if not path == None:
1012            try:
1013                self._default_save_location = os.path.dirname(path)
1014            except:
1015                pass
1016        return path
1017   
1018    def show_data_panel(self, event=None):
1019        """
1020        show the data panel
1021        """
1022        pane = self._mgr.GetPane(self.panels["data_panel"].window_name)
1023        #if not pane.IsShown():
1024        pane.Show(True)
1025        self._mgr.Update()
1026 
1027    def add_data(self, data_list):
1028        """
1029        receive a list of data . store them its data manager if possible
1030        determine if data was be plot of send to data perspectives
1031        """
1032        #send a list of available data to plotting plugin
1033        avalaible_data = []
1034        if self._data_manager is not None:
1035            self._data_manager.add_data(data_list)
1036            avalaible_data = self._data_manager.get_all_data()
1037           
1038        style = self.__gui_style & GUIFRAME.MANAGER_ON
1039        if style == GUIFRAME.MANAGER_ON:
1040            if self._data_panel is not None:
1041                data_state = self._data_manager.get_selected_data()
1042                self._data_panel.load_data_list(data_state)
1043                self._mgr.GetPane(self._data_panel.window_name).Show(True)
1044                #wait for button press from the data panel to send data
1045        else:
1046            #automatically send that to the current perspective
1047            style = self.__gui_style & GUIFRAME.SINGLE_APPLICATION
1048            if style == GUIFRAME.SINGLE_APPLICATION:
1049                self.set_data(data_list)
1050               
1051    def get_data_from_panel(self, data_id, plot=False,append=False):
1052        """
1053        receive a list of data key retreive the data from data manager and set
1054        then to the current perspective
1055        """
1056        data_dict = self._data_manager.get_by_id(data_id)
1057        data_list = []
1058        for data_state in data_dict.values():
1059            data_list.append(data_state.data)
1060        if plot:
1061            self.plot_data(data_list, append=append)
1062        else:
1063            #sent data to active application
1064            self.set_data(data_list=data_list)
1065       
1066       
1067    def set_data(self, data_list):
1068        """
1069        set data to current perspective
1070        """
1071        if self._current_perspective is not None:
1072            try:
1073                self._current_perspective.set_data(data_list)
1074            except:
1075                msg = str(sys.exc_value)
1076                wx.PostEvent(self, StatusEvent(status=msg, info="error"))
1077        else:
1078            msg = "Guiframe does not have a current perspective"
1079            logging.info(msg)
1080           
1081    def plot_data(self, data_list, append=False):
1082        """
1083        send a list of data to plot
1084        """
1085        if not data_list:
1086            message = "Please check data to plot or append"
1087            wx.PostEvent(self, StatusEvent(status=message, info='warning'))
1088            return 
1089        for new_plot in data_list:
1090            if append:
1091                if self.panel_on_focus is None:
1092                    message = "cannot append plot. No plot panel on focus!"
1093                    message += "please click on any available plot to set focus"
1094                    wx.PostEvent(self, StatusEvent(status=message, 
1095                                                   info='warning'))
1096                    return 
1097                else:
1098                    if self.enable_add_data(new_plot):
1099                        new_plot.group_id = self.panel_on_focus.group_id
1100            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
1101                                                  title=str(new_plot.title)))
1102           
1103    def add_theory(self, data_id, theory):
1104        """
1105        """
1106        self._data_manager.append_theory(data_id, theory)
1107        style = self.__gui_style & GUIFRAME.MANAGER_ON
1108        if style == GUIFRAME.MANAGER_ON:
1109            if self._data_panel is not None:
1110                data_state = self._data_manager.get_by_id([data_id])
1111                self._data_panel.load_data_list(data_state)
1112               
1113    def delete_data(self, data_id, theory_id=None, delete_all=True):
1114        """
1115        Delete data state if data_id is provide
1116        delete theory created with data of id data_id if theory_id is provide
1117        if delete all true: delete the all state
1118        else delete theory
1119        """
1120        self._data_manager.delete_data(data_id=data_id, 
1121                                       theory_id=theory_id, 
1122                                       delete_all=delete_all)
1123       
1124    def set_current_perspective(self, perspective):
1125        """
1126        set the current active perspective
1127        """
1128        self._current_perspective = perspective
1129        name = "No current Application selected"
1130        if self._current_perspective is not None and \
1131            self._data_panel is not None:
1132            name = self._current_perspective.sub_menu
1133            self._data_panel.set_active_perspective(name)
1134           
1135    def set_plotpanel_floating(self, event=None):
1136        """
1137        make the plot panel floatable
1138        """
1139        self.__gui_style |= GUIFRAME.FLOATING_PANEL
1140        for p in self.panels.values():
1141            plot_panel = self._plotting_plugin.plot_panels
1142            for p in self.panels.values():
1143                if p in plot_panel:
1144                    self._popup_floating_panel(p)
1145       
1146    def set_plotpanel_fixed(self, event=None):
1147        """
1148        make the plot panel fixed
1149        """
1150        self.__gui_style |= GUIFRAME.FIXED_PANEL
1151        plot_panel = []
1152        if self._plotting_plugin is not None:
1153            plot_panel = self._plotting_plugin.plot_panels
1154            for p in self.panels.values():
1155                if p in plot_panel:
1156                    self._popup_fixed_panel(p)
1157                   
1158    def _popup_fixed_panel(self, p):
1159        """
1160        """
1161        style = self.__gui_style & GUIFRAME.FIXED_PANEL
1162        if style == GUIFRAME.FIXED_PANEL:
1163            self._mgr.GetPane(p.window_name).Floatable()
1164            self._mgr.GetPane(p.window_name).Right()
1165            self._mgr.GetPane(p.window_name).TopDockable(False)
1166            self._mgr.GetPane(p.window_name).BottomDockable(False)
1167            self._mgr.GetPane(p.window_name).LeftDockable(False)
1168            self._mgr.GetPane(p.window_name).RightDockable(True)
1169            flag = self._mgr.GetPane(p.window_name).IsShown()
1170            self._mgr.GetPane(p.window_name).Show(flag)
1171            self._mgr.Update()
1172           
1173    def _popup_floating_panel(self, p):
1174        """
1175        """
1176        style = self.__gui_style &  GUIFRAME.FLOATING_PANEL
1177        if style == GUIFRAME.FLOATING_PANEL: 
1178            self._mgr.GetPane(p.window_name).Floatable(True)
1179            self._mgr.GetPane(p.window_name).Float()
1180            self._mgr.GetPane(p.window_name).Dockable(False)
1181            flag = self._mgr.GetPane(p.window_name).IsShown()
1182            self._mgr.GetPane(p.window_name).Show(flag)
1183            self._mgr.Update()
1184           
1185    def enable_add_data(self, new_plot):
1186        """
1187        Enable append data on a plot panel
1188        """
1189        is_theory = len(self.panel_on_focus.plots) <= 1 and \
1190            self.panel_on_focus.plots.values()[0].__class__.__name__ == "Theory1D"
1191           
1192        is_data2d = hasattr(new_plot, 'data')
1193        is_data1d = self.panel_on_focus.__class__.__name__ == "ModelPanel1D"\
1194            and self.panel_on_focus.group_id is not None
1195        has_meta_data = hasattr(new_plot, 'meta_data')
1196       
1197        #disable_add_data if the data is being recovered from  a saved state file.
1198        is_state_data = False
1199        if has_meta_data:
1200            if 'invstate' in new_plot.meta_data: is_state_data = True
1201            if  'prstate' in new_plot.meta_data: is_state_data = True
1202            if  'fitstate' in new_plot.meta_data: is_state_data = True
1203   
1204        return is_data1d and not is_data2d and not is_theory and not is_state_data
1205       
1206class DefaultPanel(wx.Panel):
1207    """
1208    Defines the API for a panels to work with
1209    the GUI manager
1210    """
1211    ## Internal nickname for the window, used by the AUI manager
1212    window_name = "default"
1213    ## Name to appear on the window title bar
1214    window_caption = "Welcome panel"
1215    ## Flag to tell the AUI manager to put this panel in the center pane
1216    CENTER_PANE = True
1217
1218 
1219# Toy application to test this Frame
1220class ViewApp(wx.App):
1221    """
1222    """
1223    def OnInit(self):
1224        """
1225        """
1226        self.frame = ViewerFrame(None, -1, config.__appname__)   
1227        self.frame.Show(True)
1228
1229        if hasattr(self.frame, 'special'):
1230            self.frame.special.SetCurrent()
1231        self.SetTopWindow(self.frame)
1232        return True
1233   
1234    def set_manager(self, manager):
1235        """
1236        Sets a reference to the application manager
1237        of the GUI manager (Frame)
1238        """
1239        self.frame.set_manager(manager)
1240       
1241    def build_gui(self):
1242        """
1243        Build the GUI
1244        """
1245        self.frame.build_gui()
1246        self.frame.post_init()
1247       
1248    def set_welcome_panel(self, panel_class):
1249        """
1250        Set the welcome panel
1251       
1252        :param panel_class: class of the welcome panel to be instantiated
1253       
1254        """
1255        self.frame.set_welcome_panel(panel_class)
1256       
1257    def add_perspective(self, perspective):
1258        """
1259        Manually add a perspective to the application GUI
1260        """
1261        self.frame.add_perspective(perspective)
1262       
1263
1264if __name__ == "__main__": 
1265    app = ViewApp(0)
1266    app.MainLoop()
1267
1268             
Note: See TracBrowser for help on using the repository browser.