source: sasview/guiframe/gui_manager.py @ 03314e7

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

working save state

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