source: sasview/guiframe/gui_manager.py @ 0bab10b

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 0bab10b was 18ec684, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on guiframe

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