source: sasview/guiframe/gui_manager.py @ 4e4d3bb

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

working on the bookmark option

  • Property mode set to 100644
File size: 70.1 KB
Line 
1
2################################################################################
3#This software was developed by the University of Tennessee as part of the
4#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
5#project funded by the US National Science Foundation.
6#
7#See the license text in license.txt
8#
9#copyright 2008, University of Tennessee
10################################################################################
11
12
13import wx
14import wx.aui
15import os
16import sys
17import xml
18
19try:
20    # Try to find a local config
21    import imp
22    path = os.getcwd()
23    if(os.path.isfile("%s/%s.py" % (path, 'local_config'))) or \
24        (os.path.isfile("%s/%s.pyc" % (path, 'local_config'))):
25        fObj, path, descr = imp.find_module('local_config', [path])
26        config = imp.load_module('local_config', fObj, path, descr) 
27    else:
28        # Try simply importing local_config
29        import local_config as config
30except:
31    # Didn't find local config, load the default
32    import config
33   
34import warnings
35warnings.simplefilter("ignore")
36
37import logging
38
39from sans.guiframe.events import EVT_STATUS
40from sans.guiframe.events import EVT_APPEND_BOOKMARK
41from sans.guiframe.events import EVT_PANEL_ON_FOCUS
42from sans.guiframe.events import StatusEvent
43from sans.guiframe.events import NewPlotEvent
44from sans.guiframe.gui_style import GUIFRAME
45from sans.guiframe.gui_style import GUIFRAME_ID
46from sans.guiframe.events import NewLoadedDataEvent
47from sans.guiframe.data_panel import DataPanel
48from sans.guiframe.panel_base import PanelBase
49from sans.guiframe.gui_toolbar import GUIToolBar
50from sans.guiframe.dataFitting import Data1D
51from sans.guiframe.dataFitting import Data2D
52from DataLoader.loader import Loader
53
54from DataLoader.loader import Loader
55import DataLoader.data_info as DataInfo
56
57
58PLOPANEL_WIDTH = 400
59PLOPANEL_HEIGTH = 400
60GUIFRAME_WIDTH = 1000
61GUIFRAME_HEIGHT = 800
62PROG_SPLASH_SCREEN = "images/danse_logo.png" 
63EXTENSIONS =  ['.inv', '.fitv', '.prv', '.svs']
64
65class ViewerFrame(wx.Frame):
66    """
67    Main application frame
68    """
69   
70    def __init__(self, parent, title, 
71                 size=(GUIFRAME_WIDTH, GUIFRAME_HEIGHT),
72                 gui_style=GUIFRAME.DEFAULT_STYLE, 
73                 pos=wx.DefaultPosition):
74        """
75        Initialize the Frame object
76        """
77       
78        wx.Frame.__init__(self, parent=parent, title=title, pos=pos,size=size)
79        # Preferred window size
80        self._window_width, self._window_height = size
81        self.__gui_style = gui_style
82       
83        # Logging info
84        logging.basicConfig(level=logging.DEBUG,
85                    format='%(asctime)s %(levelname)s %(message)s',
86                    filename='sans_app.log',
87                    filemode='w')       
88        path = os.path.dirname(__file__)
89        temp_path = os.path.join(path,'images')
90        ico_file = os.path.join(temp_path,'ball.ico')
91        if os.path.isfile(ico_file):
92            self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
93        else:
94            temp_path = os.path.join(os.getcwd(),'images')
95            ico_file = os.path.join(temp_path,'ball.ico')
96            if os.path.isfile(ico_file):
97                self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
98       
99        ## Application manager
100        self.app_manager = None
101        self._mgr = None
102        #add current perpsective
103        self._current_perspective = None
104        self._plotting_plugin = None
105        self._data_plugin = None
106        #Menu bar and item
107        self._menubar = None
108        self._file_menu = None
109        self._data_menu = None
110        self._window_menu = None
111        self._window_menu = None
112        self._help_menu = None
113        self._tool_menu = None
114        self._applications_menu_pos = -1
115        self._applications_menu = None
116        self._edit_menu = None
117        self._toolbar_menu = None
118        self._save_appl_menu = None
119        #tool bar
120        self._toolbar = None
121        ## Find plug-ins
122        # Modify this so that we can specify the directory to look into
123        self.plugins = []
124        #add local plugin
125        self.plugins += self._get_local_plugins()
126        self.plugins += self._find_plugins()
127        ## List of panels
128        self.panels = {}
129
130        # Default locations
131        self._default_save_location = os.getcwd()       
132       
133        # Welcome panel
134        self.defaultPanel = None
135        #panel on focus
136        self.panel_on_focus = None
137        self.loader = Loader()   
138         #data manager
139        from data_manager import DataManager
140        self._data_manager = DataManager()
141        self._data_panel = DataPanel(parent=self)
142        if self.panel_on_focus is not None:
143            self._data_panel.set_panel_on_focus(self.panel_on_focus.window_caption)
144        # Check for update
145        #self._check_update(None)
146        # Register the close event so it calls our own method
147        wx.EVT_CLOSE(self, self.Close)
148        # Register to status events
149        self.Bind(EVT_STATUS, self._on_status_event)
150        #Register add extra data on the same panel event on load
151        self.Bind(EVT_PANEL_ON_FOCUS, self.set_panel_on_focus)
152        self.Bind(EVT_APPEND_BOOKMARK, self.append_bookmark)
153   
154    def get_toolbar(self):
155        """
156        """
157        return self._toolbar
158   
159    def set_panel_on_focus(self, event):
160        """
161        Store reference to the last panel on focus
162        update the toolbar if available
163        update edit menu if available
164        """
165        self.panel_on_focus = event.panel
166        panel_name = 'No panel on focus'
167        application_name = 'No Selected Application'
168        if self.panel_on_focus is not None and self._data_panel is not None:
169            panel_name = self.panel_on_focus.window_caption
170            self._data_panel.set_panel_on_focus(panel_name)
171            #update toolbar
172            self._update_toolbar_helper()
173            #update edit menu
174            self.enable_edit_menu()
175       
176    def build_gui(self):
177        """
178        """
179        # Set up the layout
180        self._setup_layout()
181        # Set up the menu
182        self._setup_menus()
183        # set tool bar
184        self._setup_tool_bar()
185        #self.Fit()
186        #self._check_update(None)
187             
188    def _setup_layout(self):
189        """
190        Set up the layout
191        """
192        # Status bar
193        from gui_statusbar import StatusBar
194        self.sb = StatusBar(self, wx.ID_ANY)
195        self.SetStatusBar(self.sb)
196        # Add panel
197        default_flag = wx.aui.AUI_MGR_DEFAULT#| wx.aui.AUI_MGR_ALLOW_ACTIVE_PANE
198        self._mgr = wx.aui.AuiManager(self, flags=default_flag)
199   
200        # Load panels
201        self._load_panels()
202        self.set_default_perspective()
203        self._mgr.Update()
204       
205    def SetStatusText(self, *args, **kwds):
206        """
207        """
208        number = self.sb.get_msg_position()
209        wx.Frame.SetStatusText(number=number, *args, **kwds)
210       
211    def PopStatusText(self, *args, **kwds):
212        """
213        """
214        field = self.sb.get_msg_position()
215        wx.Frame.PopStatusText(field=field)
216       
217    def PushStatusText(self, *args, **kwds):
218        """
219        """
220        field = self.sb.get_msg_position()
221        wx.Frame.PushStatusText(self, field=field, string=string)
222
223    def add_perspective(self, plugin):
224        """
225        Add a perspective if it doesn't already
226        exist.
227        """
228        is_loaded = False
229        for item in self.plugins:
230            if plugin.__class__ == item.__class__:
231                msg = "Plugin %s already loaded" % plugin.__class__.__name__
232                logging.info(msg)
233                is_loaded = True   
234        if not is_loaded:
235            self.plugins.append(plugin)
236     
237    def _get_local_plugins(self):
238        """
239        get plugins local to guiframe and others
240        """
241        plugins = []
242        #import guiframe local plugins
243        #check if the style contain guiframe.dataloader
244        style1 = self.__gui_style & GUIFRAME.DATALOADER_ON
245        style2 = self.__gui_style & GUIFRAME.PLOTTING_ON
246        if style1 == GUIFRAME.DATALOADER_ON:
247            try:
248                from sans.guiframe.local_perspectives.data_loader import data_loader
249                self._data_plugin = data_loader.Plugin()
250                plugins.append(self._data_plugin)
251            except:
252                msg = "ViewerFrame._get_local_plugins:"
253                msg += "cannot import dataloader plugin.\n %s" % sys.exc_value
254                logging.error(msg)
255        if style2 == GUIFRAME.PLOTTING_ON:
256            try:
257                from sans.guiframe.local_perspectives.plotting import plotting
258                self._plotting_plugin = plotting.Plugin()
259                plugins.append(self._plotting_plugin)
260            except:
261                msg = "ViewerFrame._get_local_plugins:"
262                msg += "cannot import plotting plugin.\n %s" % sys.exc_value
263                logging.error(msg)
264     
265        return plugins
266   
267    def _find_plugins(self, dir="perspectives"):
268        """
269        Find available perspective plug-ins
270       
271        :param dir: directory in which to look for plug-ins
272       
273        :return: list of plug-ins
274       
275        """
276        import imp
277        plugins = []
278        # Go through files in panels directory
279        try:
280            list = os.listdir(dir)
281            ## the default panel is the panel is the last plugin added
282            for item in list:
283                toks = os.path.splitext(os.path.basename(item))
284                name = None
285                if not toks[0] == '__init__':
286                   
287                    if toks[1] == '.py' or toks[1] == '':
288                        name = toks[0]
289               
290                    path = [os.path.abspath(dir)]
291                    file = None
292                    try:
293                        if toks[1] == '':
294                            mod_path = '.'.join([dir, name])
295                            module = __import__(mod_path, globals(),
296                                                locals(), [name])
297                        else:
298                            (file, path, info) = imp.find_module(name, path)
299                            module = imp.load_module( name, file, item, info)
300                        if hasattr(module, "PLUGIN_ID"):
301                            try: 
302                                plug = module.Plugin()
303                                if plug.set_default_perspective():
304                                    self._current_perspective = plug
305                                plugins.append(plug)
306                                msg = "Found plug-in: %s" % module.PLUGIN_ID
307                                logging.info(msg)
308                            except:
309                                msg = "Error accessing PluginPanel"
310                                msg += " in %s\n  %s" % (name, sys.exc_value)
311                                config.printEVT(msg)
312                    except:
313                        print sys.exc_value
314                        msg = "ViewerFrame._find_plugins: %s" % sys.exc_value
315                        logging.error(msg)
316                    finally:
317                        if not file == None:
318                            file.close()
319        except:
320            # Should raise and catch at a higher level and
321            # display error on status bar
322            pass   
323        return plugins
324   
325    def set_welcome_panel(self, panel_class):
326        """
327        Sets the default panel as the given welcome panel
328       
329        :param panel_class: class of the welcome panel to be instantiated
330       
331        """
332        self.defaultPanel = panel_class(self, -1, style=wx.RAISED_BORDER)
333       
334    def _get_panels_size(self, p):
335        """
336        find the proper size of the current panel
337        get the proper panel width and height
338        """
339        panel_height_min = self._window_height
340        panel_width_min = self._window_width
341        style = self.__gui_style & (GUIFRAME.MANAGER_ON)
342        if self._data_panel is not None  and (p == self._data_panel):
343            panel_width_min = self._window_width * 2/25 
344            return panel_width_min, panel_height_min
345        if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
346            style = self.__gui_style & (GUIFRAME.PLOTTING_ON|GUIFRAME.MANAGER_ON)
347            if style == (GUIFRAME.PLOTTING_ON|GUIFRAME.MANAGER_ON):
348                panel_width_min = self._window_width * 17/25 
349            return panel_width_min, panel_height_min
350        return panel_width_min, panel_height_min
351   
352    def _load_panels(self):
353        """
354        Load all panels in the panels directory
355        """
356       
357        # Look for plug-in panels
358        panels = []   
359        for item in self.plugins:
360            if hasattr(item, "get_panels"):
361                ps = item.get_panels(self)
362                panels.extend(ps)
363       
364        # Show a default panel with some help information
365        # It also sets the size of the application windows
366        #TODO: Use this for slpash screen
367        if self.defaultPanel is None:
368            self.defaultPanel = DefaultPanel(self, -1, style=wx.RAISED_BORDER)
369        # add a blank default panel always present
370        self.panels["default"] = self.defaultPanel
371        self._mgr.AddPane(self.defaultPanel, wx.aui.AuiPaneInfo().
372                              Name("default").
373                              Center().
374                              CloseButton(False).
375                              MinimizeButton(False).
376                              # This is where we set the size of
377                              # the application window
378                              BestSize(wx.Size(self._window_width, 
379                                               self._window_height)).
380                              Show())
381        #add data panel
382        self.panels["data_panel"] = self._data_panel
383        w, h = self._get_panels_size(self._data_panel)
384        self._mgr.AddPane(self._data_panel, wx.aui.AuiPaneInfo().
385                              Name(self._data_panel.window_name).
386                              Left().
387                              MinimizeButton().
388                              MinSize(wx.Size(w, h)).
389                              Hide())
390        style = self.__gui_style & GUIFRAME.MANAGER_ON
391        if style != GUIFRAME.MANAGER_ON:
392            self._mgr.GetPane(self.panels["data_panel"].window_name).Hide()
393        else:
394            self._mgr.GetPane(self.panels["data_panel"].window_name).Show()
395           
396        # Add the panels to the AUI manager
397        for panel_class in panels:
398            p = panel_class
399            id = wx.NewId()
400            w, h = self._get_panels_size(p)
401            # Check whether we need to put this panel
402            # in the center pane
403            if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
404                if p.CENTER_PANE:
405                    self.panels[str(id)] = p
406                    self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
407                                          Name(p.window_name).Caption(p.window_caption).
408                                           #CenterPane().
409                                            Center().
410                                            CloseButton(False).
411                                            MinimizeButton(False).
412                                           MinSize(wx.Size(w, h)).
413                                           Hide())
414            else:
415                self.panels[str(id)] = p
416                self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
417                                  Name(p.window_name).Caption(p.window_caption).
418                                  Right().
419                                  Dock().
420                                  TopDockable().
421                                  BottomDockable().
422                                  LeftDockable().
423                                  RightDockable().
424                                  MinimizeButton().
425                                  Hide())       
426     
427    def get_context_menu(self, graph=None):
428        """
429        Get the context menu items made available
430        by the different plug-ins.
431        This function is used by the plotting module
432        """
433        menu_list = []
434        for item in self.plugins:
435            if hasattr(item, "get_context_menu"):
436                menu_list.extend(item.get_context_menu(graph))
437        return menu_list
438       
439    def popup_panel(self, p):
440        """
441        Add a panel object to the AUI manager
442       
443        :param p: panel object to add to the AUI manager
444       
445        :return: ID of the event associated with the new panel [int]
446       
447        """
448        ID = wx.NewId()
449        self.panels[str(ID)] = p
450        count = 0
451        for item in self.panels:
452            if self.panels[item].window_name.startswith(p.window_name): 
453                count += 1
454        windowname = p.window_name
455        caption = p.window_caption
456        if count > 0:
457            windowname += str(count+1)
458            caption += (' '+str(count))
459        p.window_name = windowname
460        p.window_caption = caption
461           
462        style1 = self.__gui_style & GUIFRAME.FIXED_PANEL
463        style2 = self.__gui_style & GUIFRAME.FLOATING_PANEL
464        if style1 == GUIFRAME.FIXED_PANEL:
465            self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
466                              Name(windowname).Caption(caption).
467                              MinimizeButton().
468                              Resizable(True).
469                              # Use a large best size to make sure the AUI
470                              # manager takes all the available space
471                              BestSize(wx.Size(PLOPANEL_WIDTH, PLOPANEL_HEIGTH)))
472            self._popup_fixed_panel(p)
473   
474        elif style2 == GUIFRAME.FLOATING_PANEL:
475            self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
476                              Name(windowname).Caption(caption).
477                              MinimizeButton().
478                              Resizable(True).
479                              # Use a large best size to make sure the AUI
480                              #  manager takes all the available space
481                              BestSize(wx.Size(PLOPANEL_WIDTH, PLOPANEL_HEIGTH)))
482            self._popup_floating_panel(p)
483           
484        pane = self._mgr.GetPane(windowname)
485        self._mgr.MaximizePane(pane)
486        self._mgr.RestoreMaximizedPane()
487        # Register for showing/hiding the panel
488        wx.EVT_MENU(self, ID, self._on_view)
489       
490        self._mgr.Update()
491        return ID
492       
493    def _setup_menus(self):
494        """
495        Set up the application menus
496        """
497        # Menu
498        self._menubar = wx.MenuBar()
499        self._add_menu_file()
500        self._add_menu_data()
501        self._add_menu_application()
502        self._add_menu_edit()
503        self._add_menu_tool()
504        self._add_current_plugin_menu()
505        self._add_menu_window()
506        self._add_help_menu()
507        self.SetMenuBar(self._menubar)
508       
509    def _setup_tool_bar(self):
510        """
511        add toolbar to the frame
512        """
513        #set toolbar
514        self._toolbar = GUIToolBar(self, -1)
515        self.SetToolBar(self._toolbar)
516        self._update_toolbar_helper()
517        #self._on_hide_toolbar(event=None)
518   
519    def _update_toolbar_helper(self):
520        """
521        """
522        application_name = 'No Selected Application'
523        panel_name = 'No Panel on Focus'
524        self._toolbar.update_toolbar(self.panel_on_focus)
525        if self._current_perspective is not None:
526            application_name = self._current_perspective.sub_menu
527        if self.panel_on_focus is not None:
528            panel_name = self.panel_on_focus.window_caption
529        self._toolbar.update_button(application_name=application_name, 
530                                        panel_name=panel_name)
531        self._toolbar.Realize()
532       
533    def _add_menu_tool(self):
534        """
535        Tools menu
536        Go through plug-ins and find tools to populate the tools menu
537        """
538        style = self.__gui_style & GUIFRAME.TOOL_ON
539        if style == GUIFRAME.TOOL_ON:
540            self._tool_menu = None
541            for item in self.plugins:
542                if hasattr(item, "get_tools"):
543                    for tool in item.get_tools():
544                        # Only create a menu if we have at least one tool
545                        if self._tool_menu is None:
546                            self._tool_menu = wx.Menu()
547                        id = wx.NewId()
548                        self._tool_menu.Append(id, tool[0], tool[1])
549                        wx.EVT_MENU(self, id, tool[2])
550            if self._tool_menu is not None:
551                self._menubar.Append(self._tool_menu, '&Tools')
552               
553    def _add_current_plugin_menu(self):
554        """
555        add current plugin menu
556        Look for plug-in menus
557        Add available plug-in sub-menus.
558        """
559        if (self._menubar is None) or (self._current_perspective is None):
560            return
561        #replace or add a new menu for the current plugin
562        name = 'Others'
563        pos = self._menubar.FindMenu(name)
564        if pos != -1:
565            menu_list = self._current_perspective.populate_menu(self)
566            if menu_list:
567                for (menu, _) in menu_list:
568                    hidden_menu = self._menubar.Replace(pos, menu, name) 
569            else:
570                hidden_menu = self._menubar.Remove(pos)
571            #get the position of the menu when it first added
572            self._plugin_menu_pos = pos
573        else:
574            menu_list = self._current_perspective.populate_menu(self)
575            if menu_list:
576                for (menu, _) in menu_list:
577                    if self._applications_menu_pos == -1:
578                        self._menubar.Append(menu, name)
579                    else:
580                        self._menubar.Insert(self._applications_menu_pos, menu, name)
581                 
582    def _add_help_menu(self):
583        """
584        add help menu
585        """
586        # Help menu
587        self._help_menu = wx.Menu()
588        style = self.__gui_style & GUIFRAME.WELCOME_PANEL_ON
589        if style == GUIFRAME.WELCOME_PANEL_ON:
590            # add the welcome panel menu item
591            if self.defaultPanel is not None:
592                id = wx.NewId()
593                self._help_menu.Append(id, '&Welcome', '')
594                self._help_menu.AppendSeparator()
595                wx.EVT_MENU(self, id, self.show_welcome_panel)
596        # Look for help item in plug-ins
597        for item in self.plugins:
598            if hasattr(item, "help"):
599                id = wx.NewId()
600                self._help_menu.Append(id,'&%s help' % item.sub_menu, '')
601                wx.EVT_MENU(self, id, item.help)
602        if config._do_aboutbox:
603            id = wx.NewId()
604            self._help_menu.Append(id,'&About', 'Software information')
605            wx.EVT_MENU(self, id, self._onAbout)
606       
607        # Checking for updates needs major refactoring to work with py2exe
608        # We need to make sure it doesn't hang the application if the server
609        # is not up. We also need to make sure there's a proper executable to
610        # run if we spawn a new background process.
611        #id = wx.NewId()
612        #self._help_menu.Append(id,'&Check for update',
613        #'Check for the latest version of %s' % config.__appname__)
614        #wx.EVT_MENU(self, id, self._check_update)
615        self._menubar.Append(self._help_menu, '&Help')
616           
617    def _add_menu_window(self):
618        """
619        add a menu window to the menu bar
620        Window menu
621        Attach a menu item for each panel in our
622        panel list that also appears in a plug-in.
623       
624        Only add the panel menu if there is only one perspective and
625        it has more than two panels.
626        Note: the first plug-in is always the plotting plug-in.
627        The first application
628        #plug-in is always the second one in the list.
629        """
630        self._window_menu = wx.Menu()
631        if self._plotting_plugin is not None:
632            for (menu, name) in self._plotting_plugin.populate_menu(self):
633                self._window_menu.AppendSubMenu(menu, name)
634        self._menubar.Append(self._window_menu, '&Window')
635     
636        style = self.__gui_style & GUIFRAME.MANAGER_ON
637        if style == GUIFRAME.MANAGER_ON:
638            id = wx.NewId()
639            self._window_menu.Append(id,'&Data Manager', '')
640            wx.EVT_MENU(self, id, self.show_data_panel)
641           
642        style = self.__gui_style & GUIFRAME.PLOTTING_ON
643        if style == GUIFRAME.PLOTTING_ON:
644            self._window_menu.AppendSeparator()
645            id = wx.NewId()
646            preferences_menu = wx.Menu()
647            hint = "Plot panels will floating"
648            preferences_menu.Append(id, '&Floating Plot Panel', hint)
649            wx.EVT_MENU(self, id, self.set_plotpanel_floating)
650            id = wx.NewId()
651            hint = "Plot panels will displayed within the frame"
652            preferences_menu.Append(id, '&Fixed Plot Panel', hint)
653            wx.EVT_MENU(self, id, self.set_plotpanel_fixed)
654            id = wx.NewId()
655            style1 = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
656            if style1 == GUIFRAME.MULTIPLE_APPLICATIONS:
657                id = wx.NewId()
658                self._toolbar_menu = preferences_menu.Append(id,'&Hide Toolbar', '')
659                wx.EVT_MENU(self, id, self._on_hide_toolbar)
660            self._window_menu.AppendSubMenu(preferences_menu,'&Preferences')
661        if self._window_menu.GetMenuItemCount() == 0:
662            pos = self._menubar.FindMenu('Window')
663            self._menubar.Remove(pos)
664        #wx.EVT_MENU(self, id, self.show_preferences_panel)   
665        """
666        if len(self.plugins) == 2:
667            plug = self.plugins[1]
668            pers = plug.get_perspective()
669       
670            if len(pers) > 1:
671                self._window_menu = wx.Menu()
672                for item in self.panels:
673                    if item == 'default':
674                        continue
675                    panel = self.panels[item]
676                    if panel.window_name in pers:
677                        self._window_menu.Append(int(item),
678                                                  panel.window_caption,
679                                        "Show %s window" % panel.window_caption)
680                        wx.EVT_MENU(self, int(item), self._on_view)
681                self._menubar.Append(self._window_menu, '&Window')
682                """
683               
684    def _add_menu_application(self):
685        """
686       
687        # Attach a menu item for each defined perspective or application.
688        # Only add the perspective menu if there are more than one perspectives
689        add menu application
690        """
691        style = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
692        if style == GUIFRAME.MULTIPLE_APPLICATIONS:
693            plug_data_count = False
694            plug_no_data_count = False
695            self._applications_menu = wx.Menu()
696            separator = self._applications_menu.AppendSeparator()
697            for plug in self.plugins:
698                if len(plug.get_perspective()) > 0:
699                    id = wx.NewId()
700                    if plug.use_data():
701                        self._applications_menu.InsertCheckItem(0, id, plug.sub_menu,
702                                      "Switch to application: %s" % plug.sub_menu)
703                        plug_data_count = True
704                    else:
705                        plug_no_data_count = True
706                        self._applications_menu.AppendCheckItem(id, plug.sub_menu,
707                                      "Switch to application: %s" % plug.sub_menu)
708                    wx.EVT_MENU(self, id, plug.on_perspective)
709            if not (plug_data_count and  plug_no_data_count):
710                self._applications_menu.RemoveItem(separator)
711            self._menubar.Append(self._applications_menu, '&Applications')
712            self._check_applications_menu()
713           
714    def _add_menu_file(self):
715        """
716        add menu file
717        """
718       
719         # File menu
720        self._file_menu = wx.Menu()
721        style = self.__gui_style & GUIFRAME.DATALOADER_ON
722        if style == GUIFRAME.DATALOADER_ON:
723            # some menu of plugin to be seen under file menu
724            hint_load_file = "Read state's files and load"
725            hint_load_file += " them into the application"
726            id = wx.NewId()
727            self._save_appl_menu = self._file_menu.Append(id, 
728                                    '&Open State from File', hint_load_file)
729            wx.EVT_MENU(self, id, self._on_open_state)
730            id = wx.NewId()
731            self._save_appl_menu = self._file_menu.Append(id, 
732                                                          '&Save Application',
733                                 'Save state of the current active application')
734            wx.EVT_MENU(self, id, self._on_save_application)
735            id = wx.NewId()
736            self._file_menu.Append(id, '&Save Project',
737                                 'Save the state of the whole application')
738            wx.EVT_MENU(self, id, self._on_save_project)
739            self._file_menu.AppendSeparator()
740       
741        id = wx.NewId()
742        self._file_menu.Append(id, '&Quit', 'Exit') 
743        wx.EVT_MENU(self, id, self.Close)
744        # Add sub menus
745        self._menubar.Append(self._file_menu, '&File')
746       
747    def _add_menu_edit(self):
748        """
749        add menu edit
750        """
751        # Edit Menu
752        self._edit_menu = wx.Menu()
753        self._edit_menu.Append(GUIFRAME_ID.UNDO_ID, '&Undo', 
754                               'Undo the previous action')
755        wx.EVT_MENU(self, GUIFRAME_ID.UNDO_ID, self.on_undo_panel)
756        self._edit_menu.Append(GUIFRAME_ID.REDO_ID, '&Redo', 
757                               'Redo the previous action')
758        wx.EVT_MENU(self, GUIFRAME_ID.REDO_ID, self.on_redo_panel)
759        #self._edit_menu.AppendSeparator()
760        #self._edit_menu.Append(GUIFRAME_ID.BOOKMARK_ID, '&Bookmark',
761        #                       'bookmark current panel')
762        #wx.EVT_MENU(self, GUIFRAME_ID.BOOKMARK_ID, self.append_bookmark)
763        self._edit_menu.Append(GUIFRAME_ID.SAVE_ID, '&Save As', 
764                               'Save current panel into file')
765        wx.EVT_MENU(self, GUIFRAME_ID.SAVE_ID, self.on_save_panel)
766        self._edit_menu.AppendSeparator()
767        self._edit_menu.Append(GUIFRAME_ID.PREVIEW_ID, '&Print Preview',
768                               'Preview current panel')
769        wx.EVT_MENU(self, GUIFRAME_ID.PREVIEW_ID, self.on_preview_panel)
770        self._edit_menu.Append(GUIFRAME_ID.PRINT_ID, '&Print',
771                               'Print current panel')
772        wx.EVT_MENU(self, GUIFRAME_ID.PRINT_ID, self.on_print_panel)
773        self._edit_menu.AppendSeparator()
774        self._edit_menu.Append(GUIFRAME_ID.ZOOM_ID, '&Zoom',
775                               'Zoom current panel')
776        wx.EVT_MENU(self, GUIFRAME_ID.ZOOM_ID, self.on_zoom_panel)
777        self._edit_menu.Append(GUIFRAME_ID.ZOOM_IN_ID, '&Zoom In',
778                               'Zoom in current panel')
779        wx.EVT_MENU(self, GUIFRAME_ID.ZOOM_IN_ID, self.on_zoom_in_panel)
780        self._edit_menu.Append(GUIFRAME_ID.ZOOM_OUT_ID, '&Zoom Out', 
781                               'Zoom out current panel')
782        wx.EVT_MENU(self, GUIFRAME_ID.ZOOM_OUT_ID, self.on_zoom_out_panel)
783        self._edit_menu.Append(GUIFRAME_ID.DRAG_ID, '&Drag',
784                               'Drag current panel')
785        wx.EVT_MENU(self, GUIFRAME_ID.DRAG_ID, self.on_drag_panel)
786        self._edit_menu.Append(GUIFRAME_ID.RESET_ID, '&Reset', 
787                               'Reset current panel')
788        wx.EVT_MENU(self, GUIFRAME_ID.RESET_ID, self.on_reset_panel)
789        self._menubar.Append(self._edit_menu,  '&Edit')
790        self.enable_edit_menu()
791       
792    def get_style(self):
793        """
794        """
795        return  self.__gui_style
796   
797    def _add_menu_data(self):
798        """
799        Add menu item item data to menu bar
800        """
801        if self._data_plugin is not None:
802            menu_list = self._data_plugin.populate_menu(self)
803            if menu_list:
804                for (menu, name) in menu_list:
805                    self._menubar.Append(menu, name)
806           
807    def _on_hide_toolbar(self, event=None):
808        """
809        hide or show toolbar
810        """
811        if self._toolbar is None:
812            return
813        if self._toolbar.IsShown():
814            if self._toolbar_menu is not None:
815                self._toolbar_menu.SetItemLabel('Show Toolbar')
816            self._toolbar.Hide()
817        else:
818            if self._toolbar_menu is not None:
819                self._toolbar_menu.SetItemLabel('Hide Toolbar')
820            self._toolbar.Show()
821        self._toolbar.Realize()
822       
823    def _on_status_event(self, evt):
824        """
825        Display status message
826        """
827        self.sb.set_status(event=evt)
828       
829    def _on_view(self, evt):
830        """
831        A panel was selected to be shown. If it's not already
832        shown, display it.
833       
834        :param evt: menu event
835       
836        """
837        self.show_panel(evt.GetId())
838       
839    def on_close_welcome_panel(self):
840        """
841        Close the welcome panel
842        """
843        if self.defaultPanel is None:
844            return 
845        self._mgr.GetPane(self.panels["default"].window_name).Hide()
846        self._mgr.Update()
847        # set a default perspective
848        self.set_default_perspective()
849       
850    def show_welcome_panel(self, event):
851        """   
852        Display the welcome panel
853        """
854        if self.defaultPanel is None:
855            return 
856        for id in self.panels.keys():
857            if id  ==  'default':
858                # Show default panel
859                if not self._mgr.GetPane(self.panels["default"].window_name).IsShown():
860                    self._mgr.GetPane(self.panels["default"].window_name).Show(True)
861            elif id == "data_panel":
862                flag = self._mgr.GetPane(self.panels["data_panel"].window_name).IsShown()
863                self._mgr.GetPane(self.panels["data_panel"].window_name).Show(flag)
864            else:
865                self._mgr.GetPane(self.panels[id].window_name).IsShown()
866                self._mgr.GetPane(self.panels[id].window_name).Hide()
867        self._mgr.Update()
868       
869    def show_panel(self, uid):
870        """
871        Shows the panel with the given id
872       
873        :param uid: unique ID number of the panel to show
874       
875        """
876        ID = str(uid)
877        config.printEVT("show_panel: %s" % ID)
878        if ID in self.panels.keys():
879            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown():
880                self._mgr.GetPane(self.panels[ID].window_name).Show()
881                # Hide default panel
882                self._mgr.GetPane(self.panels["default"].window_name).Hide()
883            self._mgr.Update()
884   
885    def clear_panel(self):
886        """
887        """
888        for item in self.panels:
889            try:
890                self.panels[item].clear_panel()
891            except:
892                pass
893           
894    def create_gui_data(self, data, path=None):
895        """
896        Receive data from loader and create a data to use for guiframe
897        """
898       
899        if issubclass(DataInfo.Data2D, data.__class__):
900            new_plot = Data2D(image=None, err_image=None) 
901        else: 
902            new_plot = Data1D(x=[], y=[], dx=None, dy=None)
903           
904        new_plot.copy_from_datainfo(data) 
905        data.clone_without_data(clone=new_plot) 
906        #creating a name for data
907        name = ""
908        title = ""
909        file_name = ""
910        if path is not None:
911            file_name = os.path.basename(path)
912        if data.run:
913            name = data.run[0]
914        if name == "":
915            name = file_name
916        name = self._data_manager.rename(name)
917        #find title
918        if data.title.strip():
919            title = data.title
920        if title.strip() == "":
921            title = file_name
922       
923        if new_plot.filename.strip() == "":
924            new_plot.filename = file_name
925       
926        new_plot.name = name
927        new_plot.title = title
928        ## allow to highlight data when plotted
929        new_plot.interactive = True
930        ## when 2 data have the same id override the 1 st plotted
931        new_plot.id = name
932        ##group_id specify on which panel to plot this data
933        new_plot.group_id = name
934        new_plot.is_data = True
935        new_plot.path = path
936        ##post data to plot
937        # plot data
938        return new_plot
939 
940    def get_data(self, path):
941        """
942        """
943        message = ""
944        log_msg = ''
945        output = []
946        error_message = ""
947        basename  = os.path.basename(path)
948        root, extension = os.path.splitext(basename)
949        if extension.lower() not in EXTENSIONS:
950            log_msg = "File Loader cannot "
951            log_msg += "load: %s\n" % str(basename)
952            log_msg += "Try Data opening...."
953            logging.info(log_msg)
954            self.load_complete(output=output, error_message=error_message,
955                   message=log_msg, path=path)   
956            return
957       
958        #reading a state file
959        for plug in self.plugins:
960            reader, ext = plug.get_extensions()
961            if reader is not None:
962                #read the state of the single plugin
963                if extension == ext:
964                    reader.read(path)
965                    return
966                elif extension == '.svs':
967                    reader.read(path)
968       
969        style = self.__gui_style & GUIFRAME.MANAGER_ON
970        if style == GUIFRAME.MANAGER_ON:
971            if self._data_panel is not None:
972                data_state = self._data_manager.get_selected_data()
973                self._data_panel.load_data_list(data_state)
974                self._mgr.GetPane(self._data_panel.window_name).Show(True)
975                       
976    def _on_open_state(self, event):
977        """
978        """
979        path = None
980        if self._default_save_location == None:
981            self._default_save_location = os.getcwd()
982 
983        wlist = ['SansView files (*.svs)|*.svs',
984                  'P(r) files (*.prv)|*.prv',
985                  'Fitting files (*.fitv)|*.fitv',
986                  'Invariant files (*.inv)|*.inv']
987        wlist = '|'.join(wlist)
988        dlg = wx.FileDialog(self, 
989                            "Choose a file", 
990                            self._default_save_location, "",
991                             wlist)
992        if dlg.ShowModal() == wx.ID_OK:
993            path = dlg.GetPath()
994            if path is not None:
995                self._default_save_location = os.path.dirname(path)
996        dlg.Destroy()
997        if path and os.path.isfile(path):
998            basename  = os.path.basename(path)
999            if  basename.endswith('.svs'):
1000                #remove panels for new states
1001                for plug in self.plugins:
1002                    plug.clear_panel()
1003                    self.panel_on_focus = None
1004               
1005            self.get_data(path)
1006               
1007        if self.defaultPanel is not None and \
1008            self._mgr.GetPane(self.panels["default"].window_name).IsShown():
1009            self.on_close_welcome_panel()
1010   
1011    def _on_save_application(self, event):
1012        """
1013        save the state of the current active application
1014        """
1015        if self.panel_on_focus is not None:
1016            self.panel_on_focus.on_save(event)
1017           
1018    def _on_save_project(self, event):
1019        """
1020        save the state of the current active application
1021        """
1022        ## Default file location for save
1023        self._default_save_location = os.getcwd()
1024        if self._current_perspective is  None:
1025            return
1026        reader, ext = self._current_perspective.get_extensions()
1027        path = None
1028        dlg = wx.FileDialog(self, "Save Project file",
1029                            self._default_save_location, "", '.svs', wx.SAVE)
1030        if dlg.ShowModal() == wx.ID_OK:
1031            path = dlg.GetPath()
1032            self._default_save_location = os.path.dirname(path)
1033        else:
1034            return None
1035        dlg.Destroy()
1036        if path is None:
1037            return
1038        # default cansas xml doc
1039        doc = None
1040        for panel in self.panels.values():
1041            doc = self.on_save_helper(doc, reader, panel, path)
1042       
1043           
1044    def on_save_helper(self, doc, reader, panel, path):
1045        """
1046        Save state into a file
1047        """
1048        try:
1049            data = panel.get_data()
1050            state = panel.get_state()
1051            if reader is not None:
1052                if data is not None:
1053                    new_doc = reader.write_toXML(data, state)
1054                    if hasattr(doc, "firstChild"):
1055                        child = new_doc.firstChild.firstChild
1056                        doc.firstChild.appendChild(child) 
1057                    else:
1058                        doc = new_doc
1059        except: 
1060            raise
1061            #pass
1062        # Write the XML document
1063        if doc != None:
1064            fd = open(path, 'w')
1065            fd.write(doc.toprettyxml())
1066            fd.close()
1067        else:
1068            raise
1069            #print "Nothing to save..."
1070            #raise RuntimeError, "%s is not a SansView (.svs) file..." % path
1071        return doc
1072
1073    def quit_guiframe(self):
1074        """
1075        Pop up message to make sure the user wants to quit the application
1076        """
1077        message = "Do you really want to quit \n"
1078        message += "this application?"
1079        dial = wx.MessageDialog(self, message, 'Question',
1080                           wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
1081        if dial.ShowModal() == wx.ID_YES:
1082            return True
1083        else:
1084            return False   
1085       
1086    def Close(self, event=None):
1087        """
1088        Quit the application
1089        """
1090        #flag = self.quit_guiframe()
1091        if True:
1092            wx.Exit()
1093            sys.exit()
1094
1095    def _check_update(self, event=None): 
1096        """
1097        Check with the deployment server whether a new version
1098        of the application is available.
1099        A thread is started for the connecting with the server. The thread calls
1100        a call-back method when the current version number has been obtained.
1101        """
1102        if hasattr(config, "__update_URL__"):
1103            import version
1104            checker = version.VersionThread(config.__update_URL__,
1105                                            self._process_version,
1106                                            baggage=event==None)
1107            checker.start() 
1108   
1109    def _process_version(self, version, standalone=True):
1110        """
1111        Call-back method for the process of checking for updates.
1112        This methods is called by a VersionThread object once the current
1113        version number has been obtained. If the check is being done in the
1114        background, the user will not be notified unless there's an update.
1115       
1116        :param version: version string
1117        :param standalone: True of the update is being checked in
1118           the background, False otherwise.
1119           
1120        """
1121        try:
1122            if cmp(version, config.__version__) > 0:
1123                msg = "Version %s is available! See the Help "
1124                msg += "menu to download it." % version
1125                self.SetStatusText(msg)
1126                if not standalone:
1127                    import webbrowser
1128                    webbrowser.open(config.__download_page__)
1129            else:
1130                if not standalone:
1131                    msg = "You have the latest version"
1132                    msg += " of %s" % config.__appname__
1133                    self.SetStatusText(msg)
1134        except:
1135            msg = "guiframe: could not get latest application"
1136            msg += " version number\n  %s" % sys.exc_value
1137            logging.error(msg)
1138            if not standalone:
1139                msg = "Could not connect to the application server."
1140                msg += " Please try again later."
1141                self.SetStatusText(msg)
1142                   
1143    def _onAbout(self, evt):
1144        """
1145        Pop up the about dialog
1146       
1147        :param evt: menu event
1148       
1149        """
1150        if config._do_aboutbox:
1151            import aboutbox 
1152            dialog = aboutbox.DialogAbout(None, -1, "")
1153            dialog.ShowModal()           
1154           
1155    def set_manager(self, manager):
1156        """
1157        Sets the application manager for this frame
1158       
1159        :param manager: frame manager
1160        """
1161        self.app_manager = manager
1162       
1163    def post_init(self):
1164        """
1165        This initialization method is called after the GUI
1166        has been created and all plug-ins loaded. It calls
1167        the post_init() method of each plug-in (if it exists)
1168        so that final initialization can be done.
1169        """
1170        for item in self.plugins:
1171            if hasattr(item, "post_init"):
1172                item.post_init()
1173       
1174    def set_default_perspective(self):
1175        """
1176        Choose among the plugin the first plug-in that has
1177        "set_default_perspective" method and its return value is True will be
1178        as a default perspective when the welcome page is closed
1179        """
1180        for item in self.plugins:
1181            if hasattr(item, "set_default_perspective"):
1182                if item.set_default_perspective():
1183                    item.on_perspective(event=None)
1184                    return 
1185       
1186    def set_perspective(self, panels):
1187        """
1188        Sets the perspective of the GUI.
1189        Opens all the panels in the list, and closes
1190        all the others.
1191       
1192        :param panels: list of panels
1193        """
1194        for item in self.panels:
1195            # Check whether this is a sticky panel
1196            if hasattr(self.panels[item], "ALWAYS_ON"):
1197                if self.panels[item].ALWAYS_ON:
1198                    continue 
1199            if self.panels[item].window_name in panels:
1200                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
1201                    self._mgr.GetPane(self.panels[item].window_name).Show()
1202            else:
1203                # always show the data panel if enable
1204                style = self.__gui_style & GUIFRAME.MANAGER_ON
1205                if (style == GUIFRAME.MANAGER_ON) and self.panels[item] == self._data_panel:
1206                    if 'data_panel' in self.panels.keys():
1207                        flag = self._mgr.GetPane(self.panels['data_panel'].window_name).IsShown()
1208                        self._mgr.GetPane(self.panels['data_panel'].window_name).Show(flag)
1209                else:
1210                    if self._mgr.GetPane(self.panels[item].window_name).IsShown():
1211                        self._mgr.GetPane(self.panels[item].window_name).Hide()
1212        self._mgr.Update()
1213       
1214    def show_data_panel(self, event=None):
1215        """
1216        show the data panel
1217        """
1218        style = self.__gui_style & GUIFRAME.MANAGER_ON
1219        if style == GUIFRAME.MANAGER_ON:
1220            pane = self._mgr.GetPane(self.panels["data_panel"].window_name)
1221            #if not pane.IsShown():
1222            pane.Show(True)
1223            self._mgr.Update()
1224 
1225    def add_data(self, data_list):
1226        """
1227        receive a list of data . store them its data manager if possible
1228        determine if data was be plot of send to data perspectives
1229        """
1230        #send a list of available data to plotting plugin
1231        avalaible_data = []
1232        if self._data_manager is not None:
1233            self._data_manager.add_data(data_list)
1234            avalaible_data = self._data_manager.get_all_data()
1235
1236        style = self.__gui_style & GUIFRAME.MANAGER_ON
1237        if style == GUIFRAME.MANAGER_ON:
1238            if self._data_panel is not None:
1239                data_state = self._data_manager.get_selected_data()
1240                self._data_panel.load_data_list(data_state)
1241                self._mgr.GetPane(self._data_panel.window_name).Show(True)
1242                #wait for button press from the data panel to send data
1243        else:
1244            #automatically send that to the current perspective
1245            style = self.__gui_style & GUIFRAME.SINGLE_APPLICATION
1246            if style == GUIFRAME.SINGLE_APPLICATION:
1247                self.set_data(data_list)
1248               
1249    def get_data_from_panel(self, data_id, plot=False,append=False):
1250        """
1251        receive a list of data key retreive the data from data manager and set
1252        then to the current perspective
1253        """
1254        data_dict = self._data_manager.get_by_id(data_id)
1255        data_list = []
1256        for data_state in data_dict.values():
1257            data_list.append(data_state.data)
1258        if plot:
1259            self.plot_data(data_list, append=append)
1260        else:
1261            #sent data to active application
1262            self.set_data(data_list=data_list)
1263       
1264       
1265    def set_data(self, data_list):
1266        """
1267        set data to current perspective
1268        """
1269        if self._current_perspective is not None:
1270            try:
1271                self._current_perspective.set_data(data_list)
1272            except:
1273                msg = str(sys.exc_value)
1274                wx.PostEvent(self, StatusEvent(status=msg, info="error"))
1275        else:
1276            msg = "Guiframe does not have a current perspective"
1277            logging.info(msg)
1278           
1279    def plot_data(self, data_list, append=False):
1280        """
1281        send a list of data to plot
1282        """
1283        if not data_list:
1284            message = "Please check data to plot or append"
1285            wx.PostEvent(self, StatusEvent(status=message, info='warning'))
1286            return 
1287        for new_plot in data_list:
1288            if append:
1289                if self.panel_on_focus is None or \
1290                    not self.enable_add_data(new_plot):
1291                    message = "cannot append plot. No plot panel on focus!"
1292                    message += "please click on any available plot to set focus"
1293                    wx.PostEvent(self, StatusEvent(status=message, 
1294                                                   info='warning'))
1295                    return 
1296                else:
1297                    if self.enable_add_data(new_plot) and \
1298                    hasattr(self.panel_on_focus, 'group_id'):
1299                        new_plot.group_id = self.panel_on_focus.group_id
1300            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
1301                                                  title=str(new_plot.title)))
1302           
1303    def add_theory(self, data_id, theory):
1304        """
1305        """
1306        self._data_manager.append_theory(data_id, theory)
1307        style = self.__gui_style & GUIFRAME.MANAGER_ON
1308        if style == GUIFRAME.MANAGER_ON:
1309            if self._data_panel is not None:
1310                data_state = self._data_manager.get_by_id([data_id])
1311                self._data_panel.load_data_list(data_state)
1312               
1313    def delete_data(self, data_id, theory_id=None, delete_all=True):
1314        """
1315        Delete data state if data_id is provide
1316        delete theory created with data of id data_id if theory_id is provide
1317        if delete all true: delete the all state
1318        else delete theory
1319        """
1320        self._data_manager.delete_data(data_id=data_id, 
1321                                       theory_id=theory_id, 
1322                                       delete_all=delete_all)
1323        for plug in self.plugins:
1324            plug.delete_data(data_id)
1325           
1326       
1327    def set_current_perspective(self, perspective):
1328        """
1329        set the current active perspective
1330        """
1331        self._current_perspective = perspective
1332        name = "No current Application selected"
1333        if self._current_perspective is not None:
1334            self._add_current_plugin_menu()
1335            for panel in self.panels.values():
1336                if hasattr(panel, 'CENTER_PANE') and panel.CENTER_PANE:
1337                    for name in self._current_perspective.get_perspective():
1338                        if name == panel.window_name:
1339                            panel.on_set_focus(event=None)
1340                            break
1341                           
1342            name = self._current_perspective.sub_menu
1343            if self._data_panel is not None:
1344                self._data_panel.set_active_perspective(name)
1345                self._check_applications_menu()
1346 
1347    def _check_applications_menu(self):
1348        """
1349        check the menu of the current application
1350        """
1351        if self._applications_menu is not None:
1352            for menu in self._applications_menu.GetMenuItems():
1353                if self._current_perspective is not None:
1354                    name = self._current_perspective.sub_menu
1355                    if menu.IsCheckable():
1356                        if menu.GetLabel() == name:
1357                            menu.Check(True)
1358                        else:
1359                             menu.Check(False) 
1360           
1361    def set_plotpanel_floating(self, event=None):
1362        """
1363        make the plot panel floatable
1364        """
1365        self.__gui_style &= (~GUIFRAME.FIXED_PANEL)
1366        self.__gui_style |= GUIFRAME.FLOATING_PANEL
1367        for p in self.panels.values():
1368            plot_panel = self._plotting_plugin.plot_panels
1369            for p in self.panels.values():
1370                if p in plot_panel:
1371                    self._popup_floating_panel(p)
1372       
1373    def set_plotpanel_fixed(self, event=None):
1374        """
1375        make the plot panel fixed
1376        """
1377        self.__gui_style &= (~GUIFRAME.FLOATING_PANEL)
1378        self.__gui_style |= GUIFRAME.FIXED_PANEL
1379        plot_panel = []
1380        if self._plotting_plugin is not None:
1381            plot_panel = self._plotting_plugin.plot_panels
1382            for p in self.panels.values():
1383                if p in plot_panel:
1384                    self._popup_fixed_panel(p)
1385                   
1386    def _popup_fixed_panel(self, p):
1387        """
1388        """
1389        style = self.__gui_style & GUIFRAME.FIXED_PANEL
1390        if style == GUIFRAME.FIXED_PANEL:
1391            self._mgr.GetPane(p.window_name).Floatable()
1392            self._mgr.GetPane(p.window_name).Right()
1393            self._mgr.GetPane(p.window_name).TopDockable(False)
1394            self._mgr.GetPane(p.window_name).BottomDockable(False)
1395            self._mgr.GetPane(p.window_name).LeftDockable(False)
1396            self._mgr.GetPane(p.window_name).RightDockable(True)
1397            flag = self._mgr.GetPane(p.window_name).IsShown()
1398            self._mgr.GetPane(p.window_name).Show(flag)
1399            self._mgr.Update()
1400           
1401    def _popup_floating_panel(self, p):
1402        """
1403        """
1404        style = self.__gui_style &  GUIFRAME.FLOATING_PANEL
1405        if style == GUIFRAME.FLOATING_PANEL: 
1406            self._mgr.GetPane(p.window_name).Floatable(True)
1407            self._mgr.GetPane(p.window_name).Float()
1408            self._mgr.GetPane(p.window_name).Dockable(False)
1409            flag = self._mgr.GetPane(p.window_name).IsShown()
1410            self._mgr.GetPane(p.window_name).Show(flag)
1411            self._mgr.Update()
1412           
1413    def enable_add_data(self, new_plot):
1414        """
1415        Enable append data on a plot panel
1416        """
1417        is_theory = len(self.panel_on_focus.plots) <= 1 and \
1418            self.panel_on_focus.plots.values()[0].__class__.__name__ == "Theory1D"
1419           
1420        is_data2d = hasattr(new_plot, 'data')
1421        is_data1d = self.panel_on_focus.__class__.__name__ == "ModelPanel1D"\
1422            and self.panel_on_focus.group_id is not None
1423        has_meta_data = hasattr(new_plot, 'meta_data')
1424       
1425        #disable_add_data if the data is being recovered from  a saved state file.
1426        is_state_data = False
1427        if has_meta_data:
1428            if 'invstate' in new_plot.meta_data: is_state_data = True
1429            if  'prstate' in new_plot.meta_data: is_state_data = True
1430            if  'fitstate' in new_plot.meta_data: is_state_data = True
1431   
1432        return is_data1d and not is_data2d and not is_theory and not is_state_data
1433   
1434    def enable_edit_menu(self):
1435        """
1436        enable menu item under edit menu depending on the panel on focus
1437        """
1438        if self.panel_on_focus is not None and self._edit_menu is not None:
1439            flag = self.panel_on_focus.get_undo_flag()
1440            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
1441            flag = self.panel_on_focus.get_redo_flag()
1442            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
1443            #flag = self.panel_on_focus.get_bookmark_flag()
1444            #self._edit_menu.Enable(GUIFRAME_ID.BOOKMARK_ID, flag)
1445            flag = self.panel_on_focus.get_save_flag()
1446            self._edit_menu.Enable(GUIFRAME_ID.SAVE_ID, flag)
1447            flag = self.panel_on_focus.get_print_flag()
1448            self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
1449            flag = self.panel_on_focus.get_preview_flag()
1450            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
1451            flag = self.panel_on_focus.get_zoom_flag()
1452            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_ID, flag)
1453            flag = self.panel_on_focus.get_zoom_in_flag()
1454            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_IN_ID, flag)
1455            flag = self.panel_on_focus.get_zoom_out_flag()
1456            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_OUT_ID, flag)
1457            flag = self.panel_on_focus.get_drag_flag()
1458            self._edit_menu.Enable(GUIFRAME_ID.DRAG_ID, flag)
1459            flag = self.panel_on_focus.get_reset_flag()
1460            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
1461        else:
1462            flag = False
1463            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
1464            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
1465            #self._edit_menu.Enable(GUIFRAME_ID.BOOKMARK_ID, flag)
1466            self._edit_menu.Enable(GUIFRAME_ID.SAVE_ID, flag)
1467            self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
1468            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
1469            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_ID, flag)
1470            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_IN_ID, flag)
1471            self._edit_menu.Enable(GUIFRAME_ID.ZOOM_OUT_ID, flag)
1472            self._edit_menu.Enable(GUIFRAME_ID.DRAG_ID, flag)
1473            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
1474           
1475    def on_undo_panel(self, event=None):
1476        """
1477        undo previous action of the last panel on focus if possible
1478        """
1479        if self.panel_on_focus is not None:
1480            self.panel_on_focus.on_undo(event)
1481           
1482    def on_redo_panel(self, event=None):
1483        """
1484        redo the last cancel action done on the last panel on focus
1485        """
1486        if self.panel_on_focus is not None:
1487            self.panel_on_focus.on_redo(event)
1488           
1489    def on_bookmark_panel(self, event=None):
1490        """
1491        bookmark panel
1492        """
1493        if self.panel_on_focus is not None:
1494            self.panel_on_focus.on_bookmark(event)
1495           
1496    def append_bookmark(self, event=None):
1497        """
1498        Bookmark available information of the panel on focus
1499        """
1500        self._toolbar.append_bookmark(event)
1501           
1502    def on_save_panel(self, event=None):
1503        """
1504        save possible information on the current panel
1505        """
1506        if self.panel_on_focus is not None:
1507            self.panel_on_focus.on_save(event)
1508           
1509    def on_preview_panel(self, event=None):
1510        """
1511        preview information on the panel on focus
1512        """
1513        if self.panel_on_focus is not None:
1514            self.panel_on_focus.on_preview(event)
1515           
1516    def on_print_panel(self, event=None):
1517        """
1518        print available information on the last panel on focus
1519        """
1520        if self.panel_on_focus is not None:
1521            self.panel_on_focus.on_print(event)
1522           
1523    def on_zoom_panel(self, event=None):
1524        """
1525        zoom on the current panel if possible
1526        """
1527        if self.panel_on_focus is not None:
1528            self.panel_on_focus.on_zoom(event)
1529           
1530    def on_zoom_in_panel(self, event=None):
1531        """
1532        zoom in of the panel on focus
1533        """
1534        if self.panel_on_focus is not None:
1535            self.panel_on_focus.on_zoom_in(event)
1536           
1537    def on_zoom_out_panel(self, event=None):
1538        """
1539        zoom out on the panel on focus
1540        """
1541        if self.panel_on_focus is not None:
1542            self.panel_on_focus.on_zoom_out(event)
1543           
1544    def on_drag_panel(self, event=None):
1545        """
1546        drag apply to the panel on focus
1547        """
1548        if self.panel_on_focus is not None:
1549            self.panel_on_focus.on_drag(event)
1550           
1551    def on_reset_panel(self, event=None):
1552        """
1553        reset the current panel
1554        """
1555        if self.panel_on_focus is not None:
1556            self.panel_on_focus.on_reset(event)
1557           
1558    def enable_undo(self):
1559        """
1560        enable undo related control
1561        """
1562        if self.panel_on_focus is not None:
1563            self._toolbar.enable_undo(self.panel_on_focus)
1564           
1565    def enable_redo(self):
1566        """
1567        enable redo
1568        """
1569        if self.panel_on_focus is not None:
1570            self._toolbar.enable_redo(self.panel_on_focus)
1571           
1572    def enable_bookmark(self):
1573        """
1574        Bookmark
1575        """
1576        if self.panel_on_focus is not None:
1577            self._toolbar.enable_bookmark(self.panel_on_focus)
1578           
1579    def enable_save(self):
1580        """
1581        save
1582        """
1583        if self.panel_on_focus is not None:
1584            self._toolbar.enable_save(self.panel_on_focus)
1585           
1586    def enable_preview(self):
1587        """
1588        preview
1589        """
1590        if self.panel_on_focus is not None:
1591            self._toolbar.enable_preview(self.panel_on_focus)
1592           
1593    def enable_print(self):
1594        """
1595        print
1596        """
1597        if self.panel_on_focus is not None:
1598            self._toolbar.enable_print(self.panel_on_focus)
1599           
1600    def enable_zoom(self):
1601        """
1602        zoom
1603        """
1604        if self.panel_on_focus is not None:
1605            self._toolbar.enable_zoom(self.panel_on_focus)
1606           
1607    def enable_zoom_in(self):
1608        """
1609        zoom in
1610        """
1611        if self.panel_on_focus is not None:
1612            self._toolbar.enable_zoom_in(self.panel_on_focus)
1613           
1614    def enable_zoom_out(self):
1615        """
1616        zoom out
1617        """
1618        if self.panel_on_focus is not None:
1619            self._toolbar.enable_zoom_out(self.panel_on_focus)
1620           
1621    def enable_drag(self, event=None):
1622        """
1623        drag
1624        """
1625        if self.panel_on_focus is not None:
1626            self._toolbar.enable_drag(self.panel_on_focus)
1627           
1628    def enable_reset(self):
1629        """
1630        reset the current panel
1631        """
1632        if self.panel_on_focus is not None:
1633            self._toolbar.enable_reset(self.panel_on_focus)
1634       
1635class DefaultPanel(wx.Panel, PanelBase):
1636    """
1637    Defines the API for a panels to work with
1638    the GUI manager
1639    """
1640    ## Internal nickname for the window, used by the AUI manager
1641    window_name = "default"
1642    ## Name to appear on the window title bar
1643    window_caption = "Welcome panel"
1644    ## Flag to tell the AUI manager to put this panel in the center pane
1645    CENTER_PANE = True
1646    def __init__(self, parent, *args, **kwds):
1647        wx.Panel.__init__(self, parent, *args, **kwds)
1648        PanelBase.__init__(self, parent)
1649   
1650
1651
1652# Toy application to test this Frame
1653class ViewApp(wx.App):
1654    """
1655    """
1656    SIZE = (GUIFRAME_WIDTH,GUIFRAME_HEIGHT)
1657    TITLE = config.__appname__
1658    PROG_SPLASH_PATH = PROG_SPLASH_SCREEN
1659    STYLE = GUIFRAME.SINGLE_APPLICATION
1660    def OnInit(self):
1661        """
1662        """
1663        pos, size = self.window_placement(self.SIZE)
1664        self.frame = ViewerFrame(parent=None, 
1665                                 title=self.TITLE, 
1666                                 pos=pos, 
1667                                 gui_style = self.STYLE,
1668                                 size=size) 
1669         # Display a splash screen on top of the frame.
1670        if len(sys.argv) > 1 and '--time' in sys.argv[1:]:
1671            log_time("Starting to display the splash screen")
1672        if self.PROG_SPLASH_PATH is not None and \
1673            os.path.isfile(self.PROG_SPLASH_PATH):
1674            try:
1675                self.display_splash_screen(parent=self.frame, path=self.PROG_SPLASH_PATH)   
1676            except:
1677                msg = "Cannot display splash screen\n"
1678                msg += str (sys.exc_value)
1679                logging.error(msg)
1680        self.frame.Show(True)
1681
1682        if hasattr(self.frame, 'special'):
1683            self.frame.special.SetCurrent()
1684        self.SetTopWindow(self.frame)
1685        return True
1686   
1687    def set_manager(self, manager):
1688        """
1689        Sets a reference to the application manager
1690        of the GUI manager (Frame)
1691        """
1692        self.frame.set_manager(manager)
1693       
1694    def build_gui(self):
1695        """
1696        Build the GUI
1697        """
1698        self.frame.build_gui()
1699        self.frame.post_init()
1700       
1701    def set_welcome_panel(self, panel_class):
1702        """
1703        Set the welcome panel
1704       
1705        :param panel_class: class of the welcome panel to be instantiated
1706       
1707        """
1708        self.frame.set_welcome_panel(panel_class)
1709       
1710    def add_perspective(self, perspective):
1711        """
1712        Manually add a perspective to the application GUI
1713        """
1714        self.frame.add_perspective(perspective)
1715   
1716    def window_placement(self, size):
1717        """
1718        Determines the position and size of the application frame such that it
1719        fits on the user's screen without obstructing (or being obstructed by)
1720        the Windows task bar.  The maximum initial size in pixels is bounded by
1721        WIDTH x HEIGHT.  For most monitors, the application
1722        will be centered on the screen; for very large monitors it will be
1723        placed on the left side of the screen.
1724        """
1725        window_width, window_height = size
1726        screen_size = wx.GetDisplaySize()
1727        window_height = window_height if screen_size[1]>window_height else screen_size[1]-50
1728        window_width  = window_width if screen_size[0]> window_width else screen_size[0]-50
1729        xpos = ypos = 0
1730
1731        # Note that when running Linux and using an Xming (X11) server on a PC
1732        # with a dual  monitor configuration, the reported display size may be
1733        # that of both monitors combined with an incorrect display count of 1.
1734        # To avoid displaying this app across both monitors, we check for
1735        # screen 'too big'.  If so, we assume a smaller width which means the
1736        # application will be placed towards the left hand side of the screen.
1737
1738        _, _, x, y = wx.Display().GetClientArea() # size excludes task bar
1739        if len(sys.argv) > 1 and '--platform' in sys.argv[1:]:
1740            w, h = wx.DisplaySize()  # size includes task bar area
1741        if x > 1920: x = 1280  # display on left side, not centered on screen
1742        if x > window_width:  xpos = (x - window_width)/2
1743        if y > window_height: ypos = (y - window_height)/2
1744
1745        # Return the suggested position and size for the application frame.
1746        return (xpos, ypos), (min(x, window_width), min(y, window_height))
1747   
1748    def display_splash_screen(self, parent, path=PROG_SPLASH_SCREEN):
1749        """Displays the splash screen.  It will exactly cover the main frame."""
1750
1751        # Prepare the picture.  On a 2GHz intel cpu, this takes about a second.
1752        x, y = parent.GetSizeTuple()
1753        image = wx.Image(path, wx.BITMAP_TYPE_PNG)
1754        image.Rescale(x, y, wx.IMAGE_QUALITY_HIGH)
1755        bm = image.ConvertToBitmap()
1756
1757        # Create and show the splash screen.  It will disappear only when the
1758        # program has entered the event loop AND either the timeout has expired
1759        # or the user has left clicked on the screen.  Thus any processing
1760        # performed in this routine (including sleeping) or processing in the
1761        # calling routine (including doing imports) will prevent the splash
1762        # screen from disappearing.
1763        #
1764        # Note that on Linux, the timeout appears to occur immediately in which
1765        # case the splash screen disappears upon entering the event loop.
1766        wx.SplashScreen(bitmap=bm,
1767                        splashStyle=(wx.SPLASH_CENTRE_ON_PARENT|
1768                                     wx.SPLASH_TIMEOUT|
1769                                     wx.STAY_ON_TOP),
1770                        milliseconds=4000,
1771                        parent=parent,
1772                        id=wx.ID_ANY)
1773
1774        # Keep the splash screen up a minimum amount of time for non-Windows
1775        # systems.  This is a workaround for Linux and possibly MacOS that
1776        # appear to ignore the splash screen timeout option.
1777        if '__WXMSW__' not in wx.PlatformInfo:
1778            if len(sys.argv) > 1 and '--time' in sys.argv[1:]:
1779                log_time("Starting sleep of 2 secs")
1780            time.sleep(2)
1781
1782        # A call to wx.Yield does not appear to be required.  If used on
1783        # Windows, the cursor changes from 'busy' to 'ready' before the event
1784        # loop is reached which is not desirable.  On Linux it seems to have
1785        # no effect.
1786        #wx.Yield()
1787
1788       
1789
1790if __name__ == "__main__": 
1791    app = ViewApp(0)
1792    app.MainLoop()
1793
1794             
Note: See TracBrowser for help on using the repository browser.