source: sasview/guiframe/gui_manager.py @ 3385795

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

add splascreen and resize the frame at init

  • Property mode set to 100644
File size: 54.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_ADD_MANY_DATA
41from sans.guiframe.events import StatusEvent
42from sans.guiframe.events import NewPlotEvent
43from sans.guiframe.gui_style import *
44from sans.guiframe.events import NewLoadedDataEvent
45from sans.guiframe.data_panel import DataPanel
46
47STATE_FILE_EXT = ['.inv', '.fitv', '.prv']
48DATA_MANAGER = False
49AUTO_PLOT = False
50AUTO_SET_DATA = True
51PLOPANEL_WIDTH = 400
52PLOPANEL_HEIGTH = 400
53GUIFRAME_WIDTH = 1000
54GUIFRAME_HEIGHT = 800
55
56class ViewerFrame(wx.Frame):
57    """
58    Main application frame
59    """
60   
61    def __init__(self, parent, title, 
62                 size=(GUIFRAME_WIDTH,GUIFRAME_HEIGHT),
63                 gui_style=GUIFRAME.DEFAULT_STYLE, 
64                 pos=wx.DefaultPosition):
65        """
66        Initialize the Frame object
67        """
68       
69        wx.Frame.__init__(self, parent=parent, title=title, pos=pos,size=size)
70        # Preferred window size
71        self._window_width, self._window_height = size
72        self.__gui_style = gui_style
73       
74        # Logging info
75        logging.basicConfig(level=logging.DEBUG,
76                    format='%(asctime)s %(levelname)s %(message)s',
77                    filename='sans_app.log',
78                    filemode='w')       
79        path = os.path.dirname(__file__)
80        temp_path = os.path.join(path,'images')
81        ico_file = os.path.join(temp_path,'ball.ico')
82        if os.path.isfile(ico_file):
83            self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
84        else:
85            temp_path = os.path.join(os.getcwd(),'images')
86            ico_file = os.path.join(temp_path,'ball.ico')
87            if os.path.isfile(ico_file):
88                self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
89       
90        ## Application manager
91        self.app_manager = None
92        self._mgr = None
93        #add current perpsective
94        self._current_perspective = None
95        self._plotting_plugin = None
96        self._data_plugin = None
97        #Menu bar and item
98        self._menubar = None
99        self._file_menu = None
100        self._data_menu = None
101        self._window_menu = None
102        self._window_menu = None
103        self._help_menu = None
104        self._tool_menu = None
105        self._plugin_menu_pos = -1
106        ## Find plug-ins
107        # Modify this so that we can specify the directory to look into
108        self.plugins = []
109        #add local plugin
110        self.plugins += self._get_local_plugins()
111        self.plugins += self._find_plugins()
112        ## List of panels
113        self.panels = {}
114
115        # Default locations
116        self._default_save_location = os.getcwd()       
117       
118        # Welcome panel
119        self.defaultPanel = None
120        #panel on focus
121        self.panel_on_focus = None
122         #data manager
123        from data_manager import DataManager
124        self._data_manager = DataManager()
125        self._data_panel = DataPanel(parent=self)
126        if self.panel_on_focus is not None:
127            self._data_panel.set_panel_on_focus(self.panel_on_focus.window_caption)
128        # Check for update
129        #self._check_update(None)
130        # Register the close event so it calls our own method
131        wx.EVT_CLOSE(self, self._onClose)
132        # Register to status events
133        self.Bind(EVT_STATUS, self._on_status_event)
134        #Register add extra data on the same panel event on load
135        self.Bind(EVT_ADD_MANY_DATA, self.set_panel_on_focus)
136       
137    def set_panel_on_focus(self, event):
138        """
139        Store reference to the last panel on focus
140        """
141        self.panel_on_focus = event.panel
142        if self.panel_on_focus is not None and self._data_panel is not None:
143            self._data_panel.set_panel_on_focus(self.panel_on_focus.window_name)
144           
145    def build_gui(self):
146        """
147        """
148        # Set up the layout
149        self._setup_layout()
150       
151        # Set up the menu
152        self._setup_menus()
153        #self.Fit()
154        #self._check_update(None)
155             
156    def _setup_layout(self):
157        """
158        Set up the layout
159        """
160        # Status bar
161        from statusbar import StatusBar
162        self.sb = StatusBar(self, wx.ID_ANY)
163        self.SetStatusBar(self.sb)
164        # Add panel
165        default_flag = wx.aui.AUI_MGR_DEFAULT| wx.aui.AUI_MGR_ALLOW_ACTIVE_PANE
166        self._mgr = wx.aui.AuiManager(self, flags=default_flag)
167   
168        # Load panels
169        self._load_panels()
170        self.set_default_perspective()
171        self._mgr.Update()
172       
173    def SetStatusText(self, *args, **kwds):
174        """
175        """
176        number = self.sb.get_msg_position()
177        wx.Frame.SetStatusText(number=number, *args, **kwds)
178       
179    def PopStatusText(self, *args, **kwds):
180        """
181        """
182        field = self.sb.get_msg_position()
183        wx.Frame.PopStatusText(field=field)
184       
185    def PushStatusText(self, *args, **kwds):
186        """
187        """
188        field = self.sb.get_msg_position()
189        wx.Frame.PushStatusText(self, field=field, string=string)
190
191    def add_perspective(self, plugin):
192        """
193        Add a perspective if it doesn't already
194        exist.
195        """
196        is_loaded = False
197        for item in self.plugins:
198            if plugin.__class__ == item.__class__:
199                msg = "Plugin %s already loaded" % plugin.__class__.__name__
200                logging.info(msg)
201                is_loaded = True   
202        if not is_loaded:
203            self.plugins.append(plugin)
204     
205    def _get_local_plugins(self):
206        """
207        get plugins local to guiframe and others
208        """
209        plugins = []
210        #import guiframe local plugins
211        #check if the style contain guiframe.dataloader
212        style1 = self.__gui_style & GUIFRAME.DATALOADER_ON
213        style2 = self.__gui_style & GUIFRAME.PLOTTING_ON
214        if style1 == GUIFRAME.DATALOADER_ON:
215            try:
216                from sans.guiframe.local_perspectives.data_loader import data_loader
217                self._data_plugin = data_loader.Plugin()
218                plugins.append(self._data_plugin)
219            except:
220                msg = "ViewerFrame._get_local_plugins:"
221                msg += "cannot import dataloader plugin.\n %s" % sys.exc_value
222                logging.error(msg)
223        if style2 == GUIFRAME.PLOTTING_ON:
224            try:
225                from sans.guiframe.local_perspectives.plotting import plotting
226                self._plotting_plugin = plotting.Plugin()
227                plugins.append(self._plotting_plugin)
228            except:
229                msg = "ViewerFrame._get_local_plugins:"
230                msg += "cannot import plotting plugin.\n %s" % sys.exc_value
231                logging.error(msg)
232     
233        return plugins
234   
235    def _find_plugins(self, dir="perspectives"):
236        """
237        Find available perspective plug-ins
238       
239        :param dir: directory in which to look for plug-ins
240       
241        :return: list of plug-ins
242       
243        """
244        import imp
245        plugins = []
246        # Go through files in panels directory
247        try:
248            list = os.listdir(dir)
249            ## the default panel is the panel is the last plugin added
250            for item in list:
251                toks = os.path.splitext(os.path.basename(item))
252                name = None
253                if not toks[0] == '__init__':
254                   
255                    if toks[1] == '.py' or toks[1] == '':
256                        name = toks[0]
257               
258                    path = [os.path.abspath(dir)]
259                    file = None
260                    try:
261                        if toks[1] == '':
262                            mod_path = '.'.join([dir, name])
263                            module = __import__(mod_path, globals(),
264                                                locals(), [name])
265                        else:
266                            (file, path, info) = imp.find_module(name, path)
267                            module = imp.load_module( name, file, item, info)
268                        if hasattr(module, "PLUGIN_ID"):
269                            try: 
270                                plug = module.Plugin()
271                                if plug.set_default_perspective():
272                                    self._current_perspective = plug
273                                plugins.append(plug)
274                                msg = "Found plug-in: %s" % module.PLUGIN_ID
275                                logging.info(msg)
276                            except:
277                                msg = "Error accessing PluginPanel"
278                                msg += " in %s\n  %s" % (name, sys.exc_value)
279                                config.printEVT(msg)
280                    except:
281                        print sys.exc_value
282                        msg = "ViewerFrame._find_plugins: %s" % sys.exc_value
283                        logging.error(msg)
284                    finally:
285                        if not file == None:
286                            file.close()
287        except:
288            # Should raise and catch at a higher level and
289            # display error on status bar
290            pass   
291        return plugins
292   
293    def set_welcome_panel(self, panel_class):
294        """
295        Sets the default panel as the given welcome panel
296       
297        :param panel_class: class of the welcome panel to be instantiated
298       
299        """
300        self.defaultPanel = panel_class(self, -1, style=wx.RAISED_BORDER)
301       
302    def _get_panels_size(self, p):
303        """
304        find the proper size of the current panel
305        get the proper panel width and height
306        """
307        panel_height_min = self._window_height
308        panel_width_min = self._window_width
309        style = self.__gui_style & (GUIFRAME.MANAGER_ON)
310        if self._data_panel is not None  and (p == self._data_panel):
311            panel_width_min = self._window_width * 2/25 
312            return panel_width_min, panel_height_min
313        if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
314            style = self.__gui_style & (GUIFRAME.PLOTTING_ON|GUIFRAME.MANAGER_ON)
315            if style == (GUIFRAME.PLOTTING_ON|GUIFRAME.MANAGER_ON):
316                panel_width_min = self._window_width * 17/25 
317            return panel_width_min, panel_height_min
318        return panel_width_min, panel_height_min
319   
320    def _load_panels(self):
321        """
322        Load all panels in the panels directory
323        """
324       
325        # Look for plug-in panels
326        panels = []   
327        for item in self.plugins:
328            if hasattr(item, "get_panels"):
329                ps = item.get_panels(self)
330                panels.extend(ps)
331       
332        # Show a default panel with some help information
333        # It also sets the size of the application windows
334        #TODO: Use this for slpash screen
335        if self.defaultPanel is None:
336            self.defaultPanel = DefaultPanel(self, -1, style=wx.RAISED_BORDER)
337        # add a blank default panel always present
338        self.panels["default"] = self.defaultPanel
339        self._mgr.AddPane(self.defaultPanel, wx.aui.AuiPaneInfo().
340                              Name("default").
341                              Center().
342                              CloseButton(True).
343                              # This is where we set the size of
344                              # the application window
345                              BestSize(wx.Size(self._window_width, 
346                                               self._window_height)).
347                              Show())
348        #add data panel
349        self.panels["data_panel"] = self._data_panel
350        w, h = self._get_panels_size(self._data_panel)
351        self._mgr.AddPane(self._data_panel, wx.aui.AuiPaneInfo().
352                              Name(self._data_panel.window_name).
353                              Left().
354                              MinimizeButton().
355                              MinSize(wx.Size(w, h)).
356                              Show())
357        style = self.__gui_style & GUIFRAME.MANAGER_ON
358        if style != GUIFRAME.MANAGER_ON:
359            self._mgr.GetPane(self.panels["data_panel"].window_name).Hide()
360           
361        # Add the panels to the AUI manager
362        for panel_class in panels:
363            p = panel_class
364            id = wx.NewId()
365            w, h = self._get_panels_size(p)
366            # Check whether we need to put this panel
367            # in the center pane
368            if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
369                if p.CENTER_PANE:
370                    self.panels[str(id)] = p
371                    self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
372                                          Name(p.window_name).Caption(p.window_caption).
373                                           CenterPane().
374                                           MinSize(wx.Size(w, h)).
375                                           Hide())
376            else:
377                self.panels[str(id)] = p
378                self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
379                                  Name(p.window_name).Caption(p.window_caption).
380                                  Right().
381                                  Dock().
382                                  TopDockable().
383                                  BottomDockable().
384                                  LeftDockable().
385                                  RightDockable().
386                                  MinimizeButton().
387                                  Hide())       
388     
389    def get_context_menu(self, graph=None):
390        """
391        Get the context menu items made available
392        by the different plug-ins.
393        This function is used by the plotting module
394        """
395        menu_list = []
396        for item in self.plugins:
397            if hasattr(item, "get_context_menu"):
398                menu_list.extend(item.get_context_menu(graph))
399        return menu_list
400       
401    def popup_panel(self, p):
402        """
403        Add a panel object to the AUI manager
404       
405        :param p: panel object to add to the AUI manager
406       
407        :return: ID of the event associated with the new panel [int]
408       
409        """
410        ID = wx.NewId()
411        self.panels[str(ID)] = p
412        count = 0
413        for item in self.panels:
414            if self.panels[item].window_name.startswith(p.window_name): 
415                count += 1
416        windowname = p.window_name
417        caption = p.window_caption
418        if count > 0:
419            windowname += str(count+1)
420            caption += (' '+str(count))
421        p.window_name = windowname
422        p.window_caption = caption
423           
424        style1 = self.__gui_style & GUIFRAME.FIXED_PANEL
425        style2 = self.__gui_style & GUIFRAME.FLOATING_PANEL
426        if style1 == GUIFRAME.FIXED_PANEL:
427            self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
428                              Name(windowname).Caption(caption).
429                              MinimizeButton().
430                              Resizable(True).
431                              # Use a large best size to make sure the AUI
432                              # manager takes all the available space
433                              BestSize(wx.Size(PLOPANEL_WIDTH, PLOPANEL_HEIGTH)))
434            self._popup_fixed_panel(p)
435   
436        elif style2 == GUIFRAME.FLOATING_PANEL:
437            self._mgr.AddPane(p, wx.aui.AuiPaneInfo().
438                              Name(windowname).Caption(caption).
439                              MinimizeButton().
440                              Resizable(True).
441                              # Use a large best size to make sure the AUI
442                              #  manager takes all the available space
443                              BestSize(wx.Size(PLOPANEL_WIDTH, PLOPANEL_HEIGTH)))
444            self._popup_floating_panel(p)
445           
446        pane = self._mgr.GetPane(windowname)
447        self._mgr.MaximizePane(pane)
448        self._mgr.RestoreMaximizedPane()
449        # Register for showing/hiding the panel
450        wx.EVT_MENU(self, ID, self._on_view)
451       
452        self._mgr.Update()
453        return ID
454       
455    def _populate_file_menu(self):
456        """
457        Insert menu item under file menu
458        """
459        for plugin in self.plugins:
460            if len(plugin.populate_file_menu()) > 0:
461                for item in plugin.populate_file_menu():
462                    id = wx.NewId()
463                    m_name, m_hint, m_handler = item
464                    self._filemenu.Append(id, m_name, m_hint)
465                    wx.EVT_MENU(self, id, m_handler)
466                self._filemenu.AppendSeparator()
467               
468    def _setup_menus(self):
469        """
470        Set up the application menus
471        """
472        # Menu
473        self._menubar = wx.MenuBar()
474        self._add_menu_file()
475        self._add_menu_data()
476        self._add_menu_application()
477        self._add_menu_tool()
478        self._add_current_plugin_menu()
479        self._add_menu_window()
480        self._add_help_menu()
481        self.SetMenuBar(self._menubar)
482       
483    def _add_menu_tool(self):
484        """
485        Tools menu
486        Go through plug-ins and find tools to populate the tools menu
487        """
488        style = self.__gui_style & GUIFRAME.TOOL_ON
489        if style == GUIFRAME.TOOL_ON:
490            self._tool_menu = None
491            for item in self.plugins:
492                if hasattr(item, "get_tools"):
493                    for tool in item.get_tools():
494                        # Only create a menu if we have at least one tool
495                        if self._tool_menu is None:
496                            self._tool_menu = wx.Menu()
497                        id = wx.NewId()
498                        self._tool_menu.Append(id, tool[0], tool[1])
499                        wx.EVT_MENU(self, id, tool[2])
500            if self._tool_menu is not None:
501                self._menubar.Append(self._tool_menu, '&Tools')
502               
503    def _add_current_plugin_menu(self):
504        """
505        add current plugin menu
506        Look for plug-in menus
507        Add available plug-in sub-menus.
508        """
509        if (self._menubar is None) or (self._current_perspective is None):
510            return
511        #replace or add a new menu for the current plugin
512        name = 'Others'
513        pos = self._menubar.FindMenu(name)
514        if pos != -1:
515            menu_list = self._current_perspective.populate_menu(self)
516            if menu_list:
517                for (menu, _) in menu_list:
518                    hidden_menu = self._menubar.Replace(self._plugin_menu_pos,
519                                                         menu, name) 
520            else:
521                hidden_menu = self._menubar.Remove(pos)
522            #get the position of the menu when it first added
523            self._plugin_menu_pos = pos
524        else:
525            menu_list = self._current_perspective.populate_menu(self)
526            if menu_list:
527                for (menu, _) in menu_list:
528                    if self._plugin_menu_pos == -1:
529                        self._menubar.Append(menu, name)
530                    else:
531                        self._menubar.Insert(self._plugin_menu_pos, menu, name)
532                 
533    def _add_help_menu(self):
534        """
535        add help menu
536        """
537        # Help menu
538        self._help_menu = wx.Menu()
539        # add the welcome panel menu item
540        if self.defaultPanel is not None:
541            id = wx.NewId()
542            self._help_menu.Append(id, '&Welcome', '')
543            self._help_menu.AppendSeparator()
544            wx.EVT_MENU(self, id, self.show_welcome_panel)
545        # Look for help item in plug-ins
546        for item in self.plugins:
547            if hasattr(item, "help"):
548                id = wx.NewId()
549                self._help_menu.Append(id,'&%s help' % item.sub_menu, '')
550                wx.EVT_MENU(self, id, item.help)
551        if config._do_aboutbox:
552            id = wx.NewId()
553            self._help_menu.Append(id,'&About', 'Software information')
554            wx.EVT_MENU(self, id, self._onAbout)
555       
556        # Checking for updates needs major refactoring to work with py2exe
557        # We need to make sure it doesn't hang the application if the server
558        # is not up. We also need to make sure there's a proper executable to
559        # run if we spawn a new background process.
560        #id = wx.NewId()
561        #self._help_menu.Append(id,'&Check for update',
562        #'Check for the latest version of %s' % config.__appname__)
563        #wx.EVT_MENU(self, id, self._check_update)
564        self._menubar.Append(self._help_menu, '&Help')
565           
566    def _add_menu_window(self):
567        """
568        add a menu window to the menu bar
569        Window menu
570        Attach a menu item for each panel in our
571        panel list that also appears in a plug-in.
572       
573        Only add the panel menu if there is only one perspective and
574        it has more than two panels.
575        Note: the first plug-in is always the plotting plug-in.
576        The first application
577        #plug-in is always the second one in the list.
578        """
579        self._window_menu = wx.Menu()
580        if self._plotting_plugin is not None:
581            for (menu, name) in self._plotting_plugin.populate_menu(self):
582                self._window_menu.AppendSubMenu(menu, name)
583        self._window_menu.AppendSeparator()
584        self._menubar.Append(self._window_menu, '&Window')
585     
586        style = self.__gui_style & GUIFRAME.MANAGER_ON
587        if style == GUIFRAME.MANAGER_ON:
588            id = wx.NewId()
589            self._window_menu.Append(id,'&Data Manager', '')
590            wx.EVT_MENU(self, id, self.show_data_panel)
591           
592        id = wx.NewId()
593        preferences_menu = wx.Menu()
594        hint = "Plot panels will floating"
595        preferences_menu.Append(id, '&Floating Plot Panel', hint)
596        wx.EVT_MENU(self, id, self.set_plotpanel_floating)
597        id = wx.NewId()
598        hint = "Plot panels will displayed within the frame"
599        preferences_menu.Append(id, '&Fixed Plot Panel', hint)
600        wx.EVT_MENU(self, id, self.set_plotpanel_fixed)
601        id = wx.NewId()
602        self._window_menu.AppendSubMenu(preferences_menu,'&Preferences')
603        #wx.EVT_MENU(self, id, self.show_preferences_panel)   
604        """
605        if len(self.plugins) == 2:
606            plug = self.plugins[1]
607            pers = plug.get_perspective()
608       
609            if len(pers) > 1:
610                self._window_menu = wx.Menu()
611                for item in self.panels:
612                    if item == 'default':
613                        continue
614                    panel = self.panels[item]
615                    if panel.window_name in pers:
616                        self._window_menu.Append(int(item),
617                                                  panel.window_caption,
618                                        "Show %s window" % panel.window_caption)
619                        wx.EVT_MENU(self, int(item), self._on_view)
620                self._menubar.Append(self._window_menu, '&Window')
621                """
622               
623    def _add_menu_application(self):
624        """
625       
626        # Attach a menu item for each defined perspective or application.
627        # Only add the perspective menu if there are more than one perspectives
628        add menu application
629        """
630        style = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
631        if style == GUIFRAME.MULTIPLE_APPLICATIONS:
632            p_menu = wx.Menu()
633            for plug in self.plugins:
634                if len(plug.get_perspective()) > 0:
635                    id = wx.NewId()
636                    p_menu.Append(id, plug.sub_menu,
637                                  "Switch to application: %s" % plug.sub_menu)
638                    wx.EVT_MENU(self, id, plug.on_perspective)
639            self._menubar.Append(p_menu, '&Applications')
640           
641    def _add_menu_file(self):
642        """
643        add menu file
644        """
645         # File menu
646        self._filemenu = wx.Menu()
647        # some menu of plugin to be seen under file menu
648        self._populate_file_menu()
649        id = wx.NewId()
650        self._filemenu.Append(id, '&Save state into File',
651                             'Save project as a SansView (svs) file')
652        wx.EVT_MENU(self, id, self._on_save)
653        id = wx.NewId()
654        self._filemenu.Append(id, '&Quit', 'Exit') 
655        wx.EVT_MENU(self, id, self.Close)
656        # Add sub menus
657        self._menubar.Append(self._filemenu, '&File')
658       
659    def _add_menu_data(self):
660        """
661        Add menu item item data to menu bar
662        """
663        # Add menu data
664        self._data_menu = wx.Menu()
665        #menu for data files
666        data_file_id = wx.NewId()
667        data_file_hint = "load one or more data in the application"
668        self._data_menu.Append(data_file_id, 
669                         '&Load Data File(s)', data_file_hint)
670        wx.EVT_MENU(self, data_file_id, self._load_data)
671        style = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
672        style1 = self.__gui_style & GUIFRAME.SINGLE_APPLICATION
673        if style == GUIFRAME.MULTIPLE_APPLICATIONS:
674            #menu for data from folder
675            data_folder_id = wx.NewId()
676            data_folder_hint = "load multiple data in the application"
677            self._data_menu.Append(data_folder_id, 
678                             '&Load Data Folder', data_folder_hint)
679            wx.EVT_MENU(self, data_folder_id, self._load_folder)
680            self._menubar.Append(self._data_menu, '&Data')
681        elif style1 == GUIFRAME.SINGLE_APPLICATION:
682            self._menubar.Append(self._data_menu, '&Data')
683       
684    def _load_data(self, event):
685        """
686        connect menu item load data with the first plugin that can load data
687        """
688        for plug in self.plugins:
689            if plug.can_load_data():
690                plug.load_data(event)
691        style = self.__gui_style & GUIFRAME.MANAGER_ON
692        if style == GUIFRAME.MANAGER_ON:
693            self.show_data_panel(event=None)
694       
695    def _load_folder(self, event):
696        """
697        connect menu item load data with the first plugin that can load data and
698        folder
699        """
700        for plug in self.plugins:
701            if plug.can_load_data():
702                plug.load_folder(event)
703        style = self.__gui_style & GUIFRAME.MANAGER_ON
704        if style == GUIFRAME.MANAGER_ON:
705            self.show_data_panel(event=None)
706               
707    def _on_status_event(self, evt):
708        """
709        Display status message
710        """
711        self.sb.set_status(event=evt)
712       
713    def _on_view(self, evt):
714        """
715        A panel was selected to be shown. If it's not already
716        shown, display it.
717       
718        :param evt: menu event
719       
720        """
721        self.show_panel(evt.GetId())
722       
723    def on_close_welcome_panel(self):
724        """
725        Close the welcome panel
726        """
727        if self.defaultPanel is None:
728            return 
729        self._mgr.GetPane(self.panels["default"].window_name).Hide()
730        self._mgr.Update()
731        # set a default perspective
732        self.set_default_perspective()
733       
734    def show_welcome_panel(self, event):
735        """   
736        Display the welcome panel
737        """
738        if self.defaultPanel is None:
739            return 
740        for id in self.panels.keys():
741            if id  ==  'default':
742                # Show default panel
743                if not self._mgr.GetPane(self.panels["default"].window_name).IsShown():
744                    self._mgr.GetPane(self.panels["default"].window_name).Show(True)
745            elif id == "data_panel":
746                flag = self._mgr.GetPane(self.panels["data_panel"].window_name).IsShown()
747                self._mgr.GetPane(self.panels["data_panel"].window_name).Show(flag)
748            else:
749                self._mgr.GetPane(self.panels[id].window_name).IsShown()
750                self._mgr.GetPane(self.panels[id].window_name).Hide()
751        self._mgr.Update()
752       
753    def show_panel(self, uid):
754        """
755        Shows the panel with the given id
756       
757        :param uid: unique ID number of the panel to show
758       
759        """
760        ID = str(uid)
761        config.printEVT("show_panel: %s" % ID)
762        if ID in self.panels.keys():
763            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown():
764                self._mgr.GetPane(self.panels[ID].window_name).Show()
765                # Hide default panel
766                self._mgr.GetPane(self.panels["default"].window_name).Hide()
767            self._mgr.Update()
768   
769    def _on_open(self, event):
770        """
771        """
772        path = self.choose_file()
773        if path is None:
774            return
775       
776        from data_loader import plot_data
777        from sans.perspectives import invariant
778        if path and os.path.isfile(path):
779            basename  = os.path.basename(path)
780            if  basename.endswith('.svs'):
781                #remove panels for new states
782                for item in self.panels:
783                    try:
784                        self.panels[item].clear_panel()
785                    except:
786                        pass
787                #reset states and plot data
788                for item in STATE_FILE_EXT:
789                    exec "plot_data(self, path,'%s')" % str(item)
790            else:
791                plot_data(self, path)
792        if self.defaultPanel is not None and \
793            self._mgr.GetPane(self.panels["default"].window_name).IsShown():
794            self.on_close_welcome_panel()
795           
796    def _on_save(self, event):
797        """
798        Save state into a file
799        """
800        # Ask the user the location of the file to write to.
801       
802        ## Default file location for save
803        self._default_save_location = os.getcwd()
804        path = None
805        dlg = wx.FileDialog(self, "Choose a file",
806                            self._default_save_location, "", "*.svs", wx.SAVE)
807        if dlg.ShowModal() == wx.ID_OK:
808            path = dlg.GetPath()
809            self._default_save_location = os.path.dirname(path)
810        else:
811            return None
812        dlg.Destroy()
813        if path is None:
814            return
815        # default cansas xml doc
816        doc = None
817        for item in self.panels:
818            try:
819                if self.panels[item].window_name == 'Invariant':
820                    data = self.panels[item]._data
821                    if data != None:
822                        state = self.panels[item].state
823                        manager = self.panels[item]._manager
824                        new_doc = manager.state_reader.write_toXML(data, state)
825                        if hasattr(doc, "firstChild"):
826                            child = new_doc.firstChild.firstChild
827                            doc.firstChild.appendChild(child) 
828                        else:
829                            doc = new_doc
830                elif self.panels[item].window_name == 'pr_control':
831                    data = self.panels[item].manager.current_plottable
832                    if data != None:
833                        state = self.panels[item].get_state()
834                        manager = self.panels[item].manager
835                        new_doc = manager.state_reader.write_toXML(data, state)
836                        if hasattr(doc, "firstChild"):
837                            child = new_doc.firstChild.firstChild
838                            doc.firstChild.appendChild(child) 
839                        else:
840                            doc = new_doc
841                elif self.panels[item].window_name == 'Fit panel':
842                    for index in range(self.panels[item].GetPageCount()):
843                        selected_page = self.panels[item].GetPage(index) 
844                        if hasattr(selected_page,"get_data"):
845                            data = selected_page.get_data()
846                            state = selected_page.state
847                            reader = selected_page.manager.state_reader
848                            new_doc = reader.write_toXML(data, state)
849                            if doc != None and hasattr(doc, "firstChild"):
850                                child = new_doc.firstChild.firstChild
851                                doc.firstChild.appendChild(child)
852                            else:
853                                doc = new_doc
854            except: 
855                pass
856        # Write the XML document
857        if doc != None:
858            fd = open(path, 'w')
859            fd.write(doc.toprettyxml())
860            fd.close()
861        else:
862            #print "Nothing to save..."
863            raise RuntimeError, "%s is not a SansView (.svs) file..." % path
864
865    def _onClose(self, event):
866        """
867        Store info to retrieve in xml before closing the application
868        """
869        wx.Exit()
870        sys.exit()
871                 
872    def quit_guiframe(self):
873        """
874        Pop up message to make sure the user wants to quit the application
875        """
876        message = "Do you really want to quit \n"
877        message += "this application?"
878        dial = wx.MessageDialog(self, message, 'Question',
879                           wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
880        if dial.ShowModal() == wx.ID_YES:
881            return True
882        else:
883            return False   
884       
885    def Close(self, event=None):
886        """
887        Quit the application
888        """
889        flag = self.quit_guiframe()
890        if flag:
891            wx.Frame.Close(self)
892            wx.Exit()
893            sys.exit()
894
895    def _check_update(self, event=None): 
896        """
897        Check with the deployment server whether a new version
898        of the application is available.
899        A thread is started for the connecting with the server. The thread calls
900        a call-back method when the current version number has been obtained.
901        """
902        if hasattr(config, "__update_URL__"):
903            import version
904            checker = version.VersionThread(config.__update_URL__,
905                                            self._process_version,
906                                            baggage=event==None)
907            checker.start() 
908   
909    def _process_version(self, version, standalone=True):
910        """
911        Call-back method for the process of checking for updates.
912        This methods is called by a VersionThread object once the current
913        version number has been obtained. If the check is being done in the
914        background, the user will not be notified unless there's an update.
915       
916        :param version: version string
917        :param standalone: True of the update is being checked in
918           the background, False otherwise.
919           
920        """
921        try:
922            if cmp(version, config.__version__) > 0:
923                msg = "Version %s is available! See the Help "
924                msg += "menu to download it." % version
925                self.SetStatusText(msg)
926                if not standalone:
927                    import webbrowser
928                    webbrowser.open(config.__download_page__)
929            else:
930                if not standalone:
931                    msg = "You have the latest version"
932                    msg += " of %s" % config.__appname__
933                    self.SetStatusText(msg)
934        except:
935            msg = "guiframe: could not get latest application"
936            msg += " version number\n  %s" % sys.exc_value
937            logging.error(msg)
938            if not standalone:
939                msg = "Could not connect to the application server."
940                msg += " Please try again later."
941                self.SetStatusText(msg)
942                   
943    def _onAbout(self, evt):
944        """
945        Pop up the about dialog
946       
947        :param evt: menu event
948       
949        """
950        if config._do_aboutbox:
951            import aboutbox 
952            dialog = aboutbox.DialogAbout(None, -1, "")
953            dialog.ShowModal()           
954           
955    def set_manager(self, manager):
956        """
957        Sets the application manager for this frame
958       
959        :param manager: frame manager
960        """
961        self.app_manager = manager
962       
963    def post_init(self):
964        """
965        This initialization method is called after the GUI
966        has been created and all plug-ins loaded. It calls
967        the post_init() method of each plug-in (if it exists)
968        so that final initialization can be done.
969        """
970        for item in self.plugins:
971            if hasattr(item, "post_init"):
972                item.post_init()
973       
974    def set_default_perspective(self):
975        """
976        Choose among the plugin the first plug-in that has
977        "set_default_perspective" method and its return value is True will be
978        as a default perspective when the welcome page is closed
979        """
980        for item in self.plugins:
981            if hasattr(item, "set_default_perspective"):
982                if item.set_default_perspective():
983                    item.on_perspective(event=None)
984                    return 
985       
986    def set_perspective(self, panels):
987        """
988        Sets the perspective of the GUI.
989        Opens all the panels in the list, and closes
990        all the others.
991       
992        :param panels: list of panels
993        """
994        for item in self.panels:
995            # Check whether this is a sticky panel
996            if hasattr(self.panels[item], "ALWAYS_ON"):
997                if self.panels[item].ALWAYS_ON:
998                    continue 
999            if self.panels[item].window_name in panels:
1000                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
1001                    self._mgr.GetPane(self.panels[item].window_name).Show()
1002            else:
1003                # always show the data panel if enable
1004                style = self.__gui_style & GUIFRAME.MANAGER_ON
1005                if (style == GUIFRAME.MANAGER_ON) and self.panels[item] == self._data_panel:
1006                    if 'data_panel' in self.panels.keys():
1007                        flag = self._mgr.GetPane(self.panels['data_panel'].window_name).IsShown()
1008                        self._mgr.GetPane(self.panels['data_panel'].window_name).Show(flag)
1009                else:
1010                    if self._mgr.GetPane(self.panels[item].window_name).IsShown():
1011                        self._mgr.GetPane(self.panels[item].window_name).Hide()
1012        self._mgr.Update()
1013       
1014    def choose_file(self, path=None):
1015        """
1016        Functionality that belongs elsewhere
1017        Should add a hook to specify the preferred file type/extension.
1018        """
1019        #TODO: clean this up
1020        from .data_loader import choose_data_file
1021        # Choose a file path
1022        if path == None:
1023            path = choose_data_file(self, self._default_save_location)
1024        if not path == None:
1025            try:
1026                self._default_save_location = os.path.dirname(path)
1027            except:
1028                pass
1029        return path
1030   
1031    def show_data_panel(self, event=None):
1032        """
1033        show the data panel
1034        """
1035        pane = self._mgr.GetPane(self.panels["data_panel"].window_name)
1036        #if not pane.IsShown():
1037        pane.Show(True)
1038        self._mgr.Update()
1039 
1040    def add_data(self, data_list):
1041        """
1042        receive a list of data . store them its data manager if possible
1043        determine if data was be plot of send to data perspectives
1044        """
1045        #send a list of available data to plotting plugin
1046        avalaible_data = []
1047        if self._data_manager is not None:
1048            self._data_manager.add_data(data_list)
1049            avalaible_data = self._data_manager.get_all_data()
1050           
1051        style = self.__gui_style & GUIFRAME.MANAGER_ON
1052        if style == GUIFRAME.MANAGER_ON:
1053            if self._data_panel is not None:
1054                data_state = self._data_manager.get_selected_data()
1055                self._data_panel.load_data_list(data_state)
1056                self._mgr.GetPane(self._data_panel.window_name).Show(True)
1057                #wait for button press from the data panel to send data
1058        else:
1059            #automatically send that to the current perspective
1060            style = self.__gui_style & GUIFRAME.SINGLE_APPLICATION
1061            if style == GUIFRAME.SINGLE_APPLICATION:
1062                self.set_data(data_list)
1063               
1064    def get_data_from_panel(self, data_id, plot=False,append=False):
1065        """
1066        receive a list of data key retreive the data from data manager and set
1067        then to the current perspective
1068        """
1069        data_dict = self._data_manager.get_by_id(data_id)
1070        data_list = []
1071        for data_state in data_dict.values():
1072            data_list.append(data_state.data)
1073        if plot:
1074            self.plot_data(data_list, append=append)
1075        else:
1076            #sent data to active application
1077            self.set_data(data_list=data_list)
1078       
1079       
1080    def set_data(self, data_list):
1081        """
1082        set data to current perspective
1083        """
1084        if self._current_perspective is not None:
1085            try:
1086                self._current_perspective.set_data(data_list)
1087            except:
1088                msg = str(sys.exc_value)
1089                wx.PostEvent(self, StatusEvent(status=msg, info="error"))
1090        else:
1091            msg = "Guiframe does not have a current perspective"
1092            logging.info(msg)
1093           
1094    def plot_data(self, data_list, append=False):
1095        """
1096        send a list of data to plot
1097        """
1098        if not data_list:
1099            message = "Please check data to plot or append"
1100            wx.PostEvent(self, StatusEvent(status=message, info='warning'))
1101            return 
1102        for new_plot in data_list:
1103            if append:
1104                if self.panel_on_focus is None or \
1105                    not self.enable_add_data(new_plot):
1106                    message = "cannot append plot. No plot panel on focus!"
1107                    message += "please click on any available plot to set focus"
1108                    wx.PostEvent(self, StatusEvent(status=message, 
1109                                                   info='warning'))
1110                    return 
1111                else:
1112                    if self.enable_add_data(new_plot):
1113                        new_plot.group_id = self.panel_on_focus.group_id
1114            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
1115                                                  title=str(new_plot.title)))
1116           
1117    def add_theory(self, data_id, theory):
1118        """
1119        """
1120        self._data_manager.append_theory(data_id, theory)
1121        style = self.__gui_style & GUIFRAME.MANAGER_ON
1122        if style == GUIFRAME.MANAGER_ON:
1123            if self._data_panel is not None:
1124                data_state = self._data_manager.get_by_id([data_id])
1125                self._data_panel.load_data_list(data_state)
1126               
1127    def delete_data(self, data_id, theory_id=None, delete_all=True):
1128        """
1129        Delete data state if data_id is provide
1130        delete theory created with data of id data_id if theory_id is provide
1131        if delete all true: delete the all state
1132        else delete theory
1133        """
1134        self._data_manager.delete_data(data_id=data_id, 
1135                                       theory_id=theory_id, 
1136                                       delete_all=delete_all)
1137        for plug in self.plugins:
1138            plug.delete_data(data_id)
1139           
1140       
1141    def set_current_perspective(self, perspective):
1142        """
1143        set the current active perspective
1144        """
1145        self._current_perspective = perspective
1146        name = "No current Application selected"
1147        if self._current_perspective is not None:
1148            self._add_current_plugin_menu()
1149            if self._data_panel is not None:
1150                name = self._current_perspective.sub_menu
1151                self._data_panel.set_active_perspective(name)
1152           
1153    def set_plotpanel_floating(self, event=None):
1154        """
1155        make the plot panel floatable
1156        """
1157        self.__gui_style &= (~GUIFRAME.FIXED_PANEL)
1158        self.__gui_style |= GUIFRAME.FLOATING_PANEL
1159        for p in self.panels.values():
1160            plot_panel = self._plotting_plugin.plot_panels
1161            for p in self.panels.values():
1162                if p in plot_panel:
1163                    self._popup_floating_panel(p)
1164       
1165    def set_plotpanel_fixed(self, event=None):
1166        """
1167        make the plot panel fixed
1168        """
1169        self.__gui_style &= (~GUIFRAME.FLOATING_PANEL)
1170        self.__gui_style |= GUIFRAME.FIXED_PANEL
1171        plot_panel = []
1172        if self._plotting_plugin is not None:
1173            plot_panel = self._plotting_plugin.plot_panels
1174            for p in self.panels.values():
1175                if p in plot_panel:
1176                    self._popup_fixed_panel(p)
1177                   
1178    def _popup_fixed_panel(self, p):
1179        """
1180        """
1181        style = self.__gui_style & GUIFRAME.FIXED_PANEL
1182        if style == GUIFRAME.FIXED_PANEL:
1183            self._mgr.GetPane(p.window_name).Floatable()
1184            self._mgr.GetPane(p.window_name).Right()
1185            self._mgr.GetPane(p.window_name).TopDockable(False)
1186            self._mgr.GetPane(p.window_name).BottomDockable(False)
1187            self._mgr.GetPane(p.window_name).LeftDockable(False)
1188            self._mgr.GetPane(p.window_name).RightDockable(True)
1189            flag = self._mgr.GetPane(p.window_name).IsShown()
1190            self._mgr.GetPane(p.window_name).Show(flag)
1191            self._mgr.Update()
1192           
1193    def _popup_floating_panel(self, p):
1194        """
1195        """
1196        style = self.__gui_style &  GUIFRAME.FLOATING_PANEL
1197        if style == GUIFRAME.FLOATING_PANEL: 
1198            self._mgr.GetPane(p.window_name).Floatable(True)
1199            self._mgr.GetPane(p.window_name).Float()
1200            self._mgr.GetPane(p.window_name).Dockable(False)
1201            flag = self._mgr.GetPane(p.window_name).IsShown()
1202            self._mgr.GetPane(p.window_name).Show(flag)
1203            self._mgr.Update()
1204           
1205    def enable_add_data(self, new_plot):
1206        """
1207        Enable append data on a plot panel
1208        """
1209        is_theory = len(self.panel_on_focus.plots) <= 1 and \
1210            self.panel_on_focus.plots.values()[0].__class__.__name__ == "Theory1D"
1211           
1212        is_data2d = hasattr(new_plot, 'data')
1213        is_data1d = self.panel_on_focus.__class__.__name__ == "ModelPanel1D"\
1214            and self.panel_on_focus.group_id is not None
1215        has_meta_data = hasattr(new_plot, 'meta_data')
1216       
1217        #disable_add_data if the data is being recovered from  a saved state file.
1218        is_state_data = False
1219        if has_meta_data:
1220            if 'invstate' in new_plot.meta_data: is_state_data = True
1221            if  'prstate' in new_plot.meta_data: is_state_data = True
1222            if  'fitstate' in new_plot.meta_data: is_state_data = True
1223   
1224        return is_data1d and not is_data2d and not is_theory and not is_state_data
1225       
1226class DefaultPanel(wx.Panel):
1227    """
1228    Defines the API for a panels to work with
1229    the GUI manager
1230    """
1231    ## Internal nickname for the window, used by the AUI manager
1232    window_name = "default"
1233    ## Name to appear on the window title bar
1234    window_caption = "Welcome panel"
1235    ## Flag to tell the AUI manager to put this panel in the center pane
1236    CENTER_PANE = True
1237
1238PROG_SPLASH_SCREEN = "images/danse_logo.png" 
1239# Toy application to test this Frame
1240class ViewApp(wx.App):
1241    """
1242    """
1243    SIZE = (GUIFRAME_WIDTH,GUIFRAME_HEIGHT)
1244    TITLE = config.__appname__
1245    PROG_SPLASH_PATH = PROG_SPLASH_SCREEN
1246    STYLE = GUIFRAME.DEFAULT_STYLE
1247    def OnInit(self):
1248        """
1249        """
1250        pos, size = self.window_placement(self.SIZE)
1251        self.frame = ViewerFrame(parent=None, 
1252                                 title=self.TITLE, 
1253                                 pos=pos, 
1254                                 gui_style = self.STYLE,
1255                                 size=size) 
1256         # Display a splash screen on top of the frame.
1257        if len(sys.argv) > 1 and '--time' in sys.argv[1:]:
1258            log_time("Starting to display the splash screen")
1259        if self.PROG_SPLASH_PATH is not None and \
1260            os.path.isfile(self.PROG_SPLASH_PATH):
1261            try:
1262                self.display_splash_screen(parent=self.frame, path=self.PROG_SPLASH_PATH)   
1263            except:
1264                msg = "Cannot display splash screen\n"
1265                msg += str (sys.exc_value)
1266                logging.error(msg)
1267        self.frame.Show(True)
1268
1269        if hasattr(self.frame, 'special'):
1270            self.frame.special.SetCurrent()
1271        self.SetTopWindow(self.frame)
1272        return True
1273   
1274    def set_manager(self, manager):
1275        """
1276        Sets a reference to the application manager
1277        of the GUI manager (Frame)
1278        """
1279        self.frame.set_manager(manager)
1280       
1281    def build_gui(self):
1282        """
1283        Build the GUI
1284        """
1285        self.frame.build_gui()
1286        self.frame.post_init()
1287       
1288    def set_welcome_panel(self, panel_class):
1289        """
1290        Set the welcome panel
1291       
1292        :param panel_class: class of the welcome panel to be instantiated
1293       
1294        """
1295        self.frame.set_welcome_panel(panel_class)
1296       
1297    def add_perspective(self, perspective):
1298        """
1299        Manually add a perspective to the application GUI
1300        """
1301        self.frame.add_perspective(perspective)
1302   
1303    def window_placement(self, size):
1304        """
1305        Determines the position and size of the application frame such that it
1306        fits on the user's screen without obstructing (or being obstructed by)
1307        the Windows task bar.  The maximum initial size in pixels is bounded by
1308        WIDTH x HEIGHT.  For most monitors, the application
1309        will be centered on the screen; for very large monitors it will be
1310        placed on the left side of the screen.
1311        """
1312        window_width, window_height = size
1313        screen_size = wx.GetDisplaySize()
1314        window_height = window_height if screen_size[1]>window_height else screen_size[1]-50
1315        window_width  = window_width if screen_size[0]> window_width else screen_size[0]-50
1316        xpos = ypos = 0
1317
1318        # Note that when running Linux and using an Xming (X11) server on a PC
1319        # with a dual  monitor configuration, the reported display size may be
1320        # that of both monitors combined with an incorrect display count of 1.
1321        # To avoid displaying this app across both monitors, we check for
1322        # screen 'too big'.  If so, we assume a smaller width which means the
1323        # application will be placed towards the left hand side of the screen.
1324
1325        _, _, x, y = wx.Display().GetClientArea() # size excludes task bar
1326        if len(sys.argv) > 1 and '--platform' in sys.argv[1:]:
1327            w, h = wx.DisplaySize()  # size includes task bar area
1328            print "*** Reported screen size including taskbar is %d x %d"%(w, h)
1329            print "*** Reported screen size excluding taskbar is %d x %d"%(x, y)
1330
1331        if x > 1920: x = 1280  # display on left side, not centered on screen
1332        if x > window_width:  xpos = (x - window_width)/2
1333        if y > window_height: ypos = (y - window_height)/2
1334
1335        # Return the suggested position and size for the application frame.
1336        return (xpos, ypos), (min(x, window_width), min(y, window_height))
1337   
1338    def display_splash_screen(self, parent, path=PROG_SPLASH_SCREEN):
1339        """Displays the splash screen.  It will exactly cover the main frame."""
1340
1341        # Prepare the picture.  On a 2GHz intel cpu, this takes about a second.
1342        x, y = parent.GetSizeTuple()
1343        image = wx.Image(path, wx.BITMAP_TYPE_PNG)
1344        image.Rescale(x, y, wx.IMAGE_QUALITY_HIGH)
1345        bm = image.ConvertToBitmap()
1346
1347        # Create and show the splash screen.  It will disappear only when the
1348        # program has entered the event loop AND either the timeout has expired
1349        # or the user has left clicked on the screen.  Thus any processing
1350        # performed in this routine (including sleeping) or processing in the
1351        # calling routine (including doing imports) will prevent the splash
1352        # screen from disappearing.
1353        #
1354        # Note that on Linux, the timeout appears to occur immediately in which
1355        # case the splash screen disappears upon entering the event loop.
1356        wx.SplashScreen(bitmap=bm,
1357                        splashStyle=(wx.SPLASH_CENTRE_ON_PARENT|
1358                                     wx.SPLASH_TIMEOUT|
1359                                     wx.STAY_ON_TOP),
1360                        milliseconds=4000,
1361                        parent=parent,
1362                        id=wx.ID_ANY)
1363
1364        # Keep the splash screen up a minimum amount of time for non-Windows
1365        # systems.  This is a workaround for Linux and possibly MacOS that
1366        # appear to ignore the splash screen timeout option.
1367        if '__WXMSW__' not in wx.PlatformInfo:
1368            if len(sys.argv) > 1 and '--time' in sys.argv[1:]:
1369                log_time("Starting sleep of 2 secs")
1370            time.sleep(2)
1371
1372        # A call to wx.Yield does not appear to be required.  If used on
1373        # Windows, the cursor changes from 'busy' to 'ready' before the event
1374        # loop is reached which is not desirable.  On Linux it seems to have
1375        # no effect.
1376        #wx.Yield()
1377
1378       
1379
1380if __name__ == "__main__": 
1381    app = ViewApp(0)
1382    app.MainLoop()
1383
1384             
Note: See TracBrowser for help on using the repository browser.