source: sasview/guiframe/gui_manager.py @ e6a93df

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

working on freeze

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