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

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 4b5bd73 was 788ff23, checked in by Jae Cho <jhjcho@…>, 14 years ago

edit application menu order

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