source: sasview/guiframe/gui_manager.py @ 0769202

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

working on save state

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