source: sasview/sansguiframe/src/sans/guiframe/gui_manager.py @ 7d90e55

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 7d90e55 was 7d90e55, checked in by Jae Cho <jhjcho@…>, 11 years ago

still trying to fix scrollpanel on mac

  • Property mode set to 100644
File size: 129.6 KB
Line 
1"""
2    Gui manager: manages the widgets making up an application
3"""
4################################################################################
5#This software was developed by the University of Tennessee as part of the
6#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
7#project funded by the US National Science Foundation.
8#
9#See the license text in license.txtz
10#
11#copyright 2008, University of Tennessee
12################################################################################
13
14
15import wx
16import wx.aui
17import os
18import sys
19import time
20import imp
21import warnings
22import re
23warnings.simplefilter("ignore")
24import logging
25#import urllib2
26import httplib
27
28from sans.guiframe.events import EVT_CATEGORY
29from sans.guiframe.events import EVT_STATUS
30from sans.guiframe.events import EVT_APPEND_BOOKMARK
31from sans.guiframe.events import EVT_PANEL_ON_FOCUS
32from sans.guiframe.events import EVT_NEW_LOAD_DATA
33from sans.guiframe.events import EVT_NEW_COLOR
34from sans.guiframe.events import StatusEvent
35from sans.guiframe.events import NewPlotEvent
36from sans.guiframe.gui_style import GUIFRAME
37from sans.guiframe.gui_style import GUIFRAME_ID
38from sans.guiframe.data_panel import DataPanel
39from sans.guiframe.panel_base import PanelBase
40from sans.guiframe.gui_toolbar import GUIToolBar
41from sans.guiframe.data_processor import GridFrame
42from sans.guiframe.events import EVT_NEW_BATCH
43from sans.guiframe.CategoryManager import CategoryManager
44from sans.dataloader.loader import Loader
45
46def get_app_dir():
47    """
48        The application directory is the one where the default custom_config.py
49        file resides.
50    """
51    # First, try the directory of the executable we are running
52    app_path = sys.path[0]
53    if os.path.isfile(app_path):
54        app_path = os.path.dirname(app_path)
55    if os.path.isfile(os.path.join(app_path, "custom_config.py")):
56        app_path = os.path.abspath(app_path)
57        logging.info("Using application path: %s", app_path)
58        return app_path
59   
60    # Next, try the current working directory
61    if os.path.isfile(os.path.join(os.getcwd(), "custom_config.py")):
62        logging.info("Using application path: %s", os.getcwd())
63        return os.path.abspath(os.getcwd())
64   
65    # Finally, try the directory of the sasview module
66    #TODO: gui_manager will have to know about sasview until we
67    # clean all these module variables and put them into a config class
68    # that can be passed by sasview.py.
69    logging.info(sys.executable)
70    logging.info(str(sys.argv))
71    from sans import sansview as sasview
72    app_path = os.path.dirname(sasview.__file__)
73    logging.info("Using application path: %s", app_path)
74    return app_path
75
76def get_user_directory():
77    """
78        Returns the user's home directory
79    """
80    userdir = os.path.join(os.path.expanduser("~"),".sasview")
81    if not os.path.isdir(userdir):
82        os.makedirs(userdir)
83    return userdir
84   
85def _find_local_config(file, path):
86    """
87        Find configuration file for the current application
88    """   
89    config_module = None
90    fObj = None
91    try:
92        fObj, path_config, descr = imp.find_module(file, [path])
93        config_module = imp.load_module(file, fObj, path_config, descr) 
94    except:
95        pass
96    finally:
97        if fObj is not None:
98            fObj.close()
99    return config_module
100
101# Get APP folder
102PATH_APP = get_app_dir() 
103DATAPATH = PATH_APP
104
105# GUI always starts from the App folder
106#os.chdir(PATH_APP)
107# Read in the local config, which can either be with the main
108# application or in the installation directory
109config = _find_local_config('local_config', PATH_APP)
110if config is None:
111    config = _find_local_config('local_config', os.getcwd())
112    if config is None:
113        # Didn't find local config, load the default
114        import sans.guiframe.config as config
115        logging.info("using default local_config")       
116    else:
117        logging.info("found local_config in %s" % os.getcwd()) 
118else:
119    logging.info("found local_config in %s" % PATH_APP)     
120           
121from sans.guiframe.customdir  import SetupCustom
122c_conf_dir = SetupCustom().setup_dir(PATH_APP)
123custom_config = _find_local_config('custom_config', c_conf_dir)
124if custom_config is None:
125    custom_config = _find_local_config('custom_config', os.getcwd())
126    if custom_config is None:
127        msgConfig = "Custom_config file was not imported"
128        logging.info(msgConfig)
129    else:
130        logging.info("using custom_config in %s" % os.getcwd())
131else:
132    logging.info("using custom_config from %s" % c_conf_dir)
133
134#read some constants from config
135APPLICATION_STATE_EXTENSION = config.APPLICATION_STATE_EXTENSION
136APPLICATION_NAME = config.__appname__
137SPLASH_SCREEN_PATH = config.SPLASH_SCREEN_PATH
138WELCOME_PANEL_ON = config.WELCOME_PANEL_ON
139SPLASH_SCREEN_WIDTH = config.SPLASH_SCREEN_WIDTH
140SPLASH_SCREEN_HEIGHT = config.SPLASH_SCREEN_HEIGHT
141SS_MAX_DISPLAY_TIME = config.SS_MAX_DISPLAY_TIME
142if not WELCOME_PANEL_ON:
143    WELCOME_PANEL_SHOW = False
144else:
145    WELCOME_PANEL_SHOW = True
146try:
147    DATALOADER_SHOW = custom_config.DATALOADER_SHOW
148    TOOLBAR_SHOW = custom_config.TOOLBAR_SHOW
149    FIXED_PANEL = custom_config.FIXED_PANEL
150    if WELCOME_PANEL_ON:
151        WELCOME_PANEL_SHOW = custom_config.WELCOME_PANEL_SHOW
152    PLOPANEL_WIDTH = custom_config.PLOPANEL_WIDTH
153    DATAPANEL_WIDTH = custom_config.DATAPANEL_WIDTH
154    GUIFRAME_WIDTH = custom_config.GUIFRAME_WIDTH
155    GUIFRAME_HEIGHT = custom_config.GUIFRAME_HEIGHT
156    DEFAULT_PERSPECTIVE = custom_config.DEFAULT_PERSPECTIVE
157    CLEANUP_PLOT = custom_config.CLEANUP_PLOT
158    # custom open_path
159    open_folder = custom_config.DEFAULT_OPEN_FOLDER
160    if open_folder != None and os.path.isdir(open_folder):
161        DEFAULT_OPEN_FOLDER = os.path.abspath(open_folder)
162    else:
163        DEFAULT_OPEN_FOLDER = PATH_APP
164except:
165    DATALOADER_SHOW = True
166    TOOLBAR_SHOW = True
167    FIXED_PANEL = True
168    WELCOME_PANEL_SHOW = False
169    PLOPANEL_WIDTH = config.PLOPANEL_WIDTH
170    DATAPANEL_WIDTH = config.DATAPANEL_WIDTH
171    GUIFRAME_WIDTH = config.GUIFRAME_WIDTH
172    GUIFRAME_HEIGHT = config.GUIFRAME_HEIGHT
173    DEFAULT_PERSPECTIVE = None
174    CLEANUP_PLOT = False
175    DEFAULT_OPEN_FOLDER = PATH_APP
176
177DEFAULT_STYLE = config.DEFAULT_STYLE
178
179PLUGIN_STATE_EXTENSIONS =  config.PLUGIN_STATE_EXTENSIONS
180OPEN_SAVE_MENU = config.OPEN_SAVE_PROJECT_MENU
181VIEW_MENU = config.VIEW_MENU
182EDIT_MENU = config.EDIT_MENU
183extension_list = []
184if APPLICATION_STATE_EXTENSION is not None:
185    extension_list.append(APPLICATION_STATE_EXTENSION)
186EXTENSIONS = PLUGIN_STATE_EXTENSIONS + extension_list
187try:
188    PLUGINS_WLIST = '|'.join(config.PLUGINS_WLIST)
189except:
190    PLUGINS_WLIST = ''
191APPLICATION_WLIST = config.APPLICATION_WLIST
192IS_WIN = True
193CLOSE_SHOW = True
194TIME_FACTOR = 2
195NOT_SO_GRAPH_LIST = ["BoxSum"]
196PARENT_STYLE = wx.DEFAULT_FRAME_STYLE
197if sys.platform.count("darwin") > 0:
198    IS_WIN = False
199    TIME_FACTOR = 2
200    PARENT_STYLE = wx.DEFAULT_FRAME_STYLE #| wx.STAY_ON_TOP
201    if int(str(wx.__version__).split('.')[0]) == 2:
202        if int(str(wx.__version__).split('.')[1]) < 9:
203            CLOSE_SHOW = False
204   
205class ViewerFrame(wx.MDIParentFrame):
206    """
207    Main application frame
208    """
209   
210    def __init__(self, parent, title, 
211                 size=(GUIFRAME_WIDTH, GUIFRAME_HEIGHT),
212                 gui_style=DEFAULT_STYLE, 
213                 style=PARENT_STYLE,
214                 pos=wx.DefaultPosition):
215        """
216        Initialize the Frame object
217        """
218
219        wx.MDIParentFrame.__init__(self, parent=parent, title=title, pos=pos, 
220                                   style=style, size=size)
221        # title
222        self.title = title
223        self.__gui_style = gui_style       
224        path = os.path.dirname(__file__)
225        temp_path = os.path.join(path,'images')
226        ico_file = os.path.join(temp_path,'ball.ico')
227        if os.path.isfile(ico_file):
228            self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
229        else:
230            temp_path = os.path.join(os.getcwd(),'images')
231            ico_file = os.path.join(temp_path,'ball.ico')
232            if os.path.isfile(ico_file):
233                self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
234            else:
235                ico_file = os.path.join(os.path.dirname(os.path.sys.path[0]),
236                             'images', 'ball.ico')
237                if os.path.isfile(ico_file):
238                    self.SetIcon(wx.Icon(ico_file, wx.BITMAP_TYPE_ICO))
239        self.path = PATH_APP
240        self.application_name = APPLICATION_NAME
241        ## Application manager
242        self._input_file = None
243        self.app_manager = None
244        self._mgr = None
245        #add current perpsective
246        self._current_perspective = None
247        self._plotting_plugin = None
248        self._data_plugin = None
249        #Menu bar and item
250        self._menubar = None
251        self._file_menu = None
252        self._data_menu = None
253        self._view_menu = None
254        self._window_menu = None
255        self._data_panel_menu = None
256        self._help_menu = None
257        self._tool_menu = None
258        self._applications_menu_pos = -1
259        self._applications_menu_name = None
260        self._applications_menu = None
261        self._edit_menu = None
262        self._toolbar_menu = None
263        self._save_appl_menu = None
264        #tool bar
265        self._toolbar = None
266        # Status bar
267        self.sb = None
268        # number of plugins
269        self._num_perspectives = 0
270        # plot duck cleanup option
271        self.cleanup_plots = CLEANUP_PLOT
272        # (un)-focus color
273        #self.color = '#b3b3b3'
274        ## Find plug-ins
275        # Modify this so that we can specify the directory to look into
276        self.plugins = []
277        #add local plugin
278        self.plugins += self._get_local_plugins()
279        self.plugins += self._find_plugins()
280        ## List of panels
281        self.panels = {}
282        # List of plot panels
283        self.plot_panels = {}
284        # default Graph number fot the plotpanel caption
285        self.graph_num = 0
286
287        # Default locations
288        self._default_save_location = DEFAULT_OPEN_FOLDER       
289        # Welcome panel
290        self.defaultPanel = None
291        #panel on focus
292        self.panel_on_focus = None
293        #control_panel on focus
294        self.cpanel_on_focus = None
295
296        self.loader = Loader()   
297        #data manager
298        self.batch_on = False
299        from sans.guiframe.data_manager import DataManager
300        self._data_manager = DataManager()
301        self._data_panel = None#DataPanel(parent=self)
302        if self.panel_on_focus is not None:
303            self._data_panel.set_panel_on_focus(
304                                self.panel_on_focus.window_caption)
305        # list of plot panels in schedule to full redraw
306        self.schedule = False
307        #self.callback = True
308        self._idle_count = 0
309        self.schedule_full_draw_list = []
310        self.idletimer = wx.CallLater(TIME_FACTOR, self._onDrawIdle)
311       
312        self.batch_frame = GridFrame(parent=self)
313        self.batch_frame.Hide()
314        self.on_batch_selection(event=None)
315        self.add_icon()
316       
317        # Register the close event so it calls our own method
318        wx.EVT_CLOSE(self, self.WindowClose)
319        # Register to status events
320        self.Bind(EVT_STATUS, self._on_status_event)
321        #Register add extra data on the same panel event on load
322        self.Bind(EVT_PANEL_ON_FOCUS, self.set_panel_on_focus)
323        self.Bind(EVT_APPEND_BOOKMARK, self.append_bookmark)
324        self.Bind(EVT_NEW_LOAD_DATA, self.on_load_data)
325        self.Bind(EVT_NEW_BATCH, self.on_batch_selection)
326        self.Bind(EVT_NEW_COLOR, self.on_color_selection)
327        self.Bind(EVT_CATEGORY, self.on_change_categories)
328        self.setup_custom_conf()
329        # Preferred window size
330        self._window_width, self._window_height = size
331       
332    def add_icon(self):
333        """
334        get list of child and attempt to add the default icon
335        """
336       
337        list_children = self.GetChildren() 
338        for frame in list_children:
339            self.put_icon(frame)
340       
341    def put_icon(self, frame): 
342        """
343        Put icon on the tap of a panel
344        """
345        if hasattr(frame, "IsIconized"):
346            if not frame.IsIconized():
347                try:
348                    icon = self.GetIcon()
349                    frame.SetIcon(icon)
350                except:
351                    pass 
352               
353    def get_client_size(self):
354        """
355        return client size tuple
356        """
357        width, height = self.GetClientSizeTuple()
358        height -= 45
359        # Adjust toolbar height
360        toolbar = self.GetToolBar()
361        if toolbar != None:
362            _, tb_h = toolbar.GetSizeTuple()
363            height -= tb_h
364        return width, height
365   
366    def on_change_categories(self, evt):
367        # ILL
368        fitpanel = None
369        for item in self.plugins:
370            if hasattr(item, "get_panels"):
371                if hasattr(item, "fit_panel"):
372                    fitpanel = item.fit_panel
373
374        if fitpanel != None:
375            for i in range(0,fitpanel.GetPageCount()):
376                fitpanel.GetPage(i)._populate_listbox()
377
378
379
380    def on_set_batch_result(self, data_outputs, data_inputs=None,
381                             plugin_name=""):
382        """
383        Display data into a grid in batch mode and show the grid
384        """
385        t = time.localtime(time.time())
386        time_str = time.strftime("%b %d %H;%M of %Y", t)
387        details = "File Generated by %s : %s" % (APPLICATION_NAME,
388                                                     str(plugin_name))
389        details += "on %s.\n" % time_str
390        ext = ".csv"
391        file_name = "Batch_" + str(plugin_name)+ "_" + time_str + ext
392        file_name = self._default_save_location + str(file_name)
393       
394        self.open_with_localapp(file_name=file_name,
395                                details=details,
396                                data_inputs=data_inputs,
397                                    data_outputs=data_outputs)
398     
399   
400    def open_with_localapp(self, data_inputs=None, details="", file_name=None,
401                           data_outputs=None):
402        """
403        Display value of data into the application grid
404        :param data: dictionary of string and list of items
405        """
406        self.batch_frame.set_data(data_inputs=data_inputs, 
407                                  data_outputs=data_outputs,
408                                  details=details,
409                                  file_name=file_name)
410        self.show_batch_frame(None)
411       
412    def on_read_batch_tofile(self, base):
413        """
414        Open a file dialog , extract the file to read and display values
415        into a grid
416        """
417        path = None
418        if self._default_save_location == None:
419            self._default_save_location = os.getcwd()
420        wildcard = "(*.csv; *.txt)|*.csv; *.txt"
421        dlg = wx.FileDialog(base, 
422                            "Choose a file", 
423                            self._default_save_location, "",
424                             wildcard)
425        if dlg.ShowModal() == wx.ID_OK:
426            path = dlg.GetPath()
427            if path is not None:
428                self._default_save_location = os.path.dirname(path)
429        dlg.Destroy()
430        try:
431            self.read_batch_tofile(file_name=path)
432        except:
433            msg = "Error occurred when reading the file; %s\n"% path
434            msg += "%s\n"% sys.exc_value
435            wx.PostEvent(self, StatusEvent(status=msg,
436                                             info="error"))
437           
438    def read_batch_tofile(self, file_name):
439        """
440        Extract value from file name and Display them into a grid
441        """
442        if file_name is None or file_name.strip() == "":
443            return
444        data = {}
445        fd = open(file_name, 'r')
446        _, ext = os.path.splitext(file_name)
447        separator = None
448        if ext.lower() == ".csv":
449            separator = ","
450        buffer = fd.read()
451        lines = buffer.split('\n')
452        fd.close()
453        column_names_line  = ""
454        index = None
455        details = ""
456        for index in range(len(lines)):
457            line = lines[index]
458            line.strip()
459            count = 0
460            if separator == None:
461                line.replace('\t', ' ')
462                #found the first line containing the label
463                col_name_toks = line.split()
464                for item in col_name_toks:
465                    if item.strip() != "":
466                        count += 1
467                    else:
468                        line = " "
469            elif line.find(separator) != -1:
470                if line.count(separator) >= 2:
471                    #found the first line containing the label
472                    col_name_toks = line.split(separator)
473                    for item in col_name_toks:
474                        if item.strip() != "":
475                            count += 1
476            else:
477                details += line
478            if count >= 2:
479                column_names_line = line
480                break 
481           
482        if column_names_line.strip() == "" or index is None:
483            return 
484
485        col_name_toks = column_names_line.split(separator)
486        c_index = 0
487        for col_index in range(len(col_name_toks)):
488            c_name = col_name_toks[col_index]
489            if c_name.strip() != "":
490                # distinguish between column name and value
491                try:
492                    float(c_name)
493                    col_name = "Column %s"% str(col_index + 1)
494                    index_min = index
495                except:
496                    col_name = c_name
497                    index_min = index + 1
498                data[col_name] = [ lines[row].split(separator)[c_index]
499                                for row in range(index_min, len(lines)-1)]
500                c_index += 1
501               
502        self.open_with_localapp(data_outputs=data, data_inputs=None,
503                                file_name=file_name, details=details)
504       
505    def write_batch_tofile(self, data, file_name, details=""):
506        """
507        Helper to write result from batch into cvs file
508        """
509        self._default_save_location = os.path.dirname(file_name)
510        name = os.path.basename(file_name)
511        if data is None or file_name is None or file_name.strip() == "":
512            return
513        _, ext = os.path.splitext(name)
514        try:
515            fd = open(file_name, 'w')
516        except:
517            # On Permission denied: IOError
518            temp_dir = get_user_directory()
519            temp_file_name = os.path.join(temp_dir, name)
520            fd = open(temp_file_name, 'w')
521        separator = "\t"
522        if ext.lower() == ".csv":
523            separator = ","
524        fd.write(str(details))
525        for col_name  in data.keys():
526            fd.write(str(col_name))
527            fd.write(separator)
528        fd.write('\n')
529        max_list = [len(value) for value in data.values()]
530        if len(max_list) == 0:
531            return
532        max_index = max(max_list)
533        index = 0
534        while(index < max_index):
535            for value_list in data.values():
536                if index < len(value_list):
537                    fd.write(str(value_list[index]))
538                    fd.write(separator)
539                else:
540                    fd.write('')
541                    fd.write(separator)
542            fd.write('\n')
543            index += 1
544        fd.close()
545           
546    def open_with_externalapp(self, data, file_name, details=""):
547        """
548        Display data in the another application , by default Excel
549        """
550        if not os.path.exists(file_name):
551            self.write_batch_tofile(data=data, file_name=file_name,
552                                               details=details)
553        try:
554            from win32com.client import Dispatch
555            excel_app = Dispatch('Excel.Application')     
556            wb = excel_app.Workbooks.Open(file_name) 
557            excel_app.Visible = 1
558        except:
559            msg = "Error occured when calling Excel.\n"
560            msg += "Check that Excel installed in this machine or \n"
561            msg += "check that %s really exists.\n" % str(file_name)
562            wx.PostEvent(self, StatusEvent(status=msg,
563                                             info="error"))
564           
565         
566    def on_batch_selection(self, event=None):
567        """
568        :param event: contains parameter enable . when enable is set to True
569        the application is in Batch mode
570        else the application is default mode(single mode)
571        """
572        if event is not None:
573            self.batch_on = event.enable
574        for plug in self.plugins:
575            plug.set_batch_selection(self.batch_on)
576           
577    def on_color_selection(self, event):
578        """
579        :param event: contains parameters for id and color
580        """ 
581        color, id = event.color, event.id
582        for plug in self.plugins:
583            plug.add_color(color, id)
584       
585       
586    def setup_custom_conf(self):
587        """
588        Set up custom configuration if exists
589        """
590        if custom_config == None:
591            return
592       
593        if not FIXED_PANEL:
594            self.__gui_style &= (~GUIFRAME.FIXED_PANEL)
595            self.__gui_style |= GUIFRAME.FLOATING_PANEL
596
597        if not DATALOADER_SHOW:
598            self.__gui_style &= (~GUIFRAME.MANAGER_ON)
599
600        if not TOOLBAR_SHOW:
601            self.__gui_style &= (~GUIFRAME.TOOLBAR_ON)
602
603        if WELCOME_PANEL_SHOW:
604            self.__gui_style |= GUIFRAME.WELCOME_PANEL_ON   
605             
606    def set_custom_default_perspective(self):
607        """
608        Set default starting perspective
609        """
610        if custom_config == None:
611            return
612        for plugin in self.plugins:
613            try:
614                if plugin.sub_menu == DEFAULT_PERSPECTIVE:
615                   
616                    plugin.on_perspective(event=None)
617                    frame = plugin.get_frame()
618                    frame.Show(True)
619                    #self._check_applications_menu()
620                    #break
621                else:
622                    frame = plugin.get_frame()
623                    frame.Show(False) 
624            except:
625                pass 
626        return         
627               
628    def on_load_data(self, event):
629        """
630        received an event to trigger load from data plugin
631        """
632        if self._data_plugin is not None:
633            self._data_plugin.load_data(event)
634           
635    def get_current_perspective(self):
636        """
637        return the current perspective
638        """
639        return self._current_perspective
640
641    def get_save_location(self):
642        """
643        return the _default_save_location
644        """
645        return self._default_save_location
646   
647    def set_input_file(self, input_file):
648        """
649        :param input_file: file to read
650        """
651        self._input_file = input_file
652       
653    def get_data_manager(self):
654        """
655        return the data manager.
656        """
657        return self._data_manager
658   
659    def get_toolbar(self):
660        """
661        return the toolbar.
662        """
663        return self._toolbar
664   
665    def set_panel_on_focus(self, event):
666        """
667        Store reference to the last panel on focus
668        update the toolbar if available
669        update edit menu if available
670        """
671        if event != None:
672            self.panel_on_focus = event.panel
673        if self.panel_on_focus is not None:
674            #Disable save application if the current panel is in batch mode
675            flag = self.panel_on_focus.get_save_flag()
676            if self._save_appl_menu != None:
677                self._save_appl_menu.Enable(flag)
678
679            if self.panel_on_focus not in self.plot_panels.values():
680                for ID in self.panels.keys():
681                    if self.panel_on_focus != self.panels[ID]:
682                        self.panels[ID].on_kill_focus(None)
683
684            if self._data_panel is not None and \
685                            self.panel_on_focus is not None:
686                self.set_panel_on_focus_helper()
687                #update toolbar
688                self._update_toolbar_helper()
689                #update edit menu
690                self.enable_edit_menu()
691
692    def disable_app_menu(self, p_panel=None): 
693        """
694        Disables all menus in the menubar
695        """
696        return
697       
698    def set_panel_on_focus_helper(self):
699        """
700        Helper for panel on focus with data_panel
701        """
702        ID = self.panel_on_focus.uid
703        if self._data_panel != None:
704            self._data_panel.set_panel_on_focus(ID)
705        #update combo
706        if self.panel_on_focus in self.plot_panels.values():
707            combo = self._data_panel.cb_plotpanel
708            combo_title = str(self.panel_on_focus.window_caption)
709            combo.SetStringSelection(combo_title)
710            combo.SetToolTip( wx.ToolTip(combo_title )) 
711        elif self.panel_on_focus != self._data_panel:
712            cpanel = self.panel_on_focus
713            if self.cpanel_on_focus != cpanel:
714                cpanel.on_tap_focus()
715                self.cpanel_on_focus = self.panel_on_focus
716     
717    def reset_bookmark_menu(self, panel):
718        """
719        Reset Bookmark menu list
720       
721        : param panel: a control panel or tap where the bookmark is
722        """
723        cpanel = panel
724        if self._toolbar != None and cpanel._bookmark_flag:
725            for item in  self._toolbar.get_bookmark_items():
726                self._toolbar.remove_bookmark_item(item)
727            self._toolbar.add_bookmark_default()
728            pos = 0
729            for bitem in cpanel.popUpMenu.GetMenuItems():
730                pos += 1
731                if pos < 3:
732                    continue
733                id =  bitem.GetId()
734                label = bitem.GetLabel()
735                self._toolbar.append_bookmark_item(id, label)
736                wx.EVT_MENU(self, id, cpanel._back_to_bookmark)
737            self._toolbar.Realize()
738             
739
740    def build_gui(self):
741        """
742        Build the GUI by setting up the toolbar, menu and layout.
743        """
744        # set tool bar
745        self._setup_tool_bar()
746        # Set up the layout
747        self._setup_layout()
748       
749        # Set up the menu
750        self._setup_menus()
751       
752        try:
753            self.load_from_cmd(self._input_file)
754        except:
755            msg = "%s Cannot load file %s\n" %(str(APPLICATION_NAME), 
756                                             str(self._input_file))
757            msg += str(sys.exc_value) + '\n'
758            print msg
759        if self._data_panel is not None and len(self.plugins) > 0:
760            self._data_panel.fill_cbox_analysis(self.plugins)
761        self.post_init()
762        # Set Custom default
763        self.set_custom_default_perspective()
764        # Set up extra custom tool menu
765        self._setup_extra_custom()
766        self._check_update(None)
767
768    def _setup_extra_custom(self): 
769        """
770        Set up toolbar and welcome view if needed
771        """
772        style = self.__gui_style & GUIFRAME.TOOLBAR_ON
773        if (style == GUIFRAME.TOOLBAR_ON) & (not self._toolbar.IsShown()):
774            self._on_toggle_toolbar() 
775       
776        # Set Custom deafult start page
777        welcome_style = self.__gui_style & GUIFRAME.WELCOME_PANEL_ON
778        if welcome_style == GUIFRAME.WELCOME_PANEL_ON:
779            self.show_welcome_panel(None)
780     
781    def _setup_layout(self):
782        """
783        Set up the layout
784        """
785        # Status bar
786        from sans.guiframe.gui_statusbar import StatusBar
787        self.sb = StatusBar(self, wx.ID_ANY)
788        self.SetStatusBar(self.sb)
789        # Load panels
790        self._load_panels()
791        self.set_default_perspective()
792       
793    def SetStatusText(self, *args, **kwds):
794        """
795        """
796        number = self.sb.get_msg_position()
797        wx.Frame.SetStatusText(self, number=number, *args, **kwds)
798       
799    def PopStatusText(self, *args, **kwds):
800        """
801        """
802        field = self.sb.get_msg_position()
803        wx.Frame.PopStatusText(self, field=field)
804       
805    def PushStatusText(self, *args, **kwds):
806        """
807            FIXME: No message is passed. What is this supposed to do?
808        """
809        field = self.sb.get_msg_position()
810        wx.Frame.PushStatusText(self, field=field, 
811                        string="FIXME: PushStatusText called without text")
812
813    def add_perspective(self, plugin):
814        """
815        Add a perspective if it doesn't already
816        exist.
817        """
818        self._num_perspectives += 1
819        is_loaded = False
820        for item in self.plugins:
821            item.set_batch_selection(self.batch_on)
822            if plugin.__class__ == item.__class__:
823                msg = "Plugin %s already loaded" % plugin.sub_menu
824                logging.info(msg)
825                is_loaded = True 
826        if not is_loaded:
827            self.plugins.append(plugin) 
828            msg = "Plugin %s appended" % plugin.sub_menu
829            logging.info(msg)
830     
831    def _get_local_plugins(self):
832        """
833        get plugins local to guiframe and others
834        """
835        plugins = []
836        #import guiframe local plugins
837        #check if the style contain guiframe.dataloader
838        style1 = self.__gui_style & GUIFRAME.DATALOADER_ON
839        style2 = self.__gui_style & GUIFRAME.PLOTTING_ON
840        if style1 == GUIFRAME.DATALOADER_ON:
841            try:
842                from sans.guiframe.local_perspectives.data_loader import data_loader
843                self._data_plugin = data_loader.Plugin()
844                plugins.append(self._data_plugin)
845            except:
846                msg = "ViewerFrame._get_local_plugins:"
847                msg += "cannot import dataloader plugin.\n %s" % sys.exc_value
848                logging.error(msg)
849        if style2 == GUIFRAME.PLOTTING_ON:
850            try:
851                from sans.guiframe.local_perspectives.plotting import plotting
852                self._plotting_plugin = plotting.Plugin()
853                plugins.append(self._plotting_plugin)
854            except:
855                msg = "ViewerFrame._get_local_plugins:"
856                msg += "cannot import plotting plugin.\n %s" % sys.exc_value
857                logging.error(msg)
858     
859        return plugins
860   
861    def _find_plugins(self, dir="perspectives"):
862        """
863        Find available perspective plug-ins
864       
865        :param dir: directory in which to look for plug-ins
866       
867        :return: list of plug-ins
868       
869        """
870        plugins = []
871        # Go through files in panels directory
872        try:
873            list = os.listdir(dir)
874            ## the default panel is the panel is the last plugin added
875            for item in list:
876                toks = os.path.splitext(os.path.basename(item))
877                name = ''
878                if not toks[0] == '__init__':
879                    if toks[1] == '.py' or toks[1] == '':
880                        name = toks[0]
881                    #check the validity of the module name parsed
882                    #before trying to import it
883                    if name is None or name.strip() == '':
884                        continue
885                    path = [os.path.abspath(dir)]
886                    file = None
887                    try:
888                        if toks[1] == '':
889                            mod_path = '.'.join([dir, name])
890                            module = __import__(mod_path, globals(),
891                                                locals(), [name])
892                        else:
893                            (file, path, info) = imp.find_module(name, path)
894                            module = imp.load_module( name, file, item, info)
895                        if hasattr(module, "PLUGIN_ID"):
896                            try: 
897                                plug = module.Plugin()
898                                if plug.set_default_perspective():
899                                    self._current_perspective = plug
900                                plugins.append(plug)
901                               
902                                msg = "Found plug-in: %s" % module.PLUGIN_ID
903                                logging.info(msg)
904                            except:
905                                msg = "Error accessing PluginPanel"
906                                msg += " in %s\n  %s" % (name, sys.exc_value)
907                                config.printEVT(msg)
908                    except:
909                        msg = "ViewerFrame._find_plugins: %s" % sys.exc_value
910                        logging.error(msg)
911                    finally:
912                        if not file == None:
913                            file.close()
914        except:
915            # Should raise and catch at a higher level and
916            # display error on status bar
917            pass 
918
919        return plugins
920   
921    def set_welcome_panel(self, panel_class):
922        """
923        Sets the default panel as the given welcome panel
924       
925        :param panel_class: class of the welcome panel to be instantiated
926       
927        """
928        win = MDIFrame(self, None, 'None', (100, 200))
929        self.defaultPanel = panel_class(win, -1, style=wx.RAISED_BORDER)
930        win.set_panel(self.defaultPanel)
931        self.defaultPanel.set_frame(win)
932        win.Show(False)
933       
934    def _get_panels_size(self, p):
935        """
936        find the proper size of the current panel
937        get the proper panel width and height
938        """
939        self._window_width, self._window_height = self.get_client_size()
940        ## Default size
941        if DATAPANEL_WIDTH < 0:
942            panel_width = int(self._window_width * 0.25)
943        else:
944            panel_width = DATAPANEL_WIDTH
945        panel_height = int(self._window_height)
946        style = self.__gui_style & (GUIFRAME.MANAGER_ON)
947        if self._data_panel is not None  and (p == self._data_panel):
948            return panel_width, panel_height
949        if hasattr(p, "CENTER_PANE") and p.CENTER_PANE:
950            #style = self.__gui_style & (GUIFRAME.PLOTTING_ON|GUIFRAME.MANAGER_ON)
951            #if style == (GUIFRAME.PLOTTING_ON|GUIFRAME.MANAGER_ON):
952            panel_width = self._window_width * 0.45
953            return panel_width, panel_height
954        elif p == self.defaultPanel:
955            return self._window_width, panel_height
956        #total_width = panel_width + self._window_width - 2.3 * panel_width
957        return panel_width, panel_height
958   
959    def _load_panels(self):
960        """
961        Load all panels in the panels directory
962        """
963        # Look for plug-in panels
964        panels = [] 
965        mac_pos_y = 40 
966        for item in self.plugins:
967            if hasattr(item, "get_panels"):
968                ps = item.get_panels(self)
969                panels.extend(ps)
970       
971        # Show a default panel with some help information
972        # It also sets the size of the application windows
973        #TODO: Use this for splash screen
974        #if self.defaultPanel is None:
975        #    self.defaultPanel = DefaultPanel(self, -1, style=wx.RAISED_BORDER)
976        # add a blank default panel always present
977        self.panels["default"] = self.defaultPanel
978        w, h = self._get_panels_size(self.defaultPanel)
979        frame = self.defaultPanel.get_frame()
980        frame.SetSize((self._window_width, self._window_height))
981        if not IS_WIN:
982            x_pos, _ = frame.GetPositionTuple()
983            frame.SetPosition((x_pos, mac_pos_y + 70))
984        frame.Show(True)
985        #add data panel
986       
987        #w, h = self._get_panels_size(self._data_panel)
988        win = MDIFrame(self, None, 'None', (100, 200))
989        #win.EnableCloseButton(False)
990        data_panel = DataPanel(parent=win,  id=-1)
991        win.set_panel(data_panel)
992        data_panel.set_frame(win)
993        self.panels["data_panel"] = data_panel
994        self._data_panel = data_panel
995        frame = self._data_panel.get_frame()
996        w, h = self._get_panels_size(self._data_panel)
997        frame.SetSize((w, h))
998        style = self.__gui_style & GUIFRAME.MANAGER_ON
999        if style != GUIFRAME.MANAGER_ON:
1000            flag = False
1001        else:
1002            flag = True
1003        if not IS_WIN:
1004            x_pos, _ = win.GetPositionTuple()
1005            frame.SetPosition((x_pos, mac_pos_y + 70))
1006        frame.Show(flag)
1007        d_panel_width = w
1008        # Add the panels to the AUI manager
1009        for panel_class in panels:
1010            frame = panel_class.get_frame()
1011            id = wx.NewId()
1012            # Check whether we need to put this panel
1013            # in the center pane
1014           
1015            if hasattr(panel_class, "CENTER_PANE") and panel_class.CENTER_PANE:
1016                w, h = self._get_panels_size(panel_class)
1017                if panel_class.CENTER_PANE:
1018                    self.panels[str(id)] = panel_class
1019                    _, pos_y = frame.GetPositionTuple()
1020                    frame.SetPosition((d_panel_width, pos_y))
1021                    frame.SetSize((w, h))
1022                    frame.Show(False)
1023            elif panel_class == self._data_panel:
1024                continue
1025            else:
1026                self.panels[str(id)] = panel_class
1027                frame.SetSize((w, h))
1028                frame.Show(False)
1029            if not IS_WIN:
1030                x_pos, _ = frame.GetPositionTuple()
1031                frame.SetPosition((x_pos, mac_pos_y + 70))
1032
1033        if not IS_WIN:
1034            self.SetSize((self._window_width, mac_pos_y))
1035       
1036    def update_data(self, prev_data, new_data):
1037        """
1038        Update the data.
1039        """
1040        prev_id, data_state = self._data_manager.update_data(
1041                              prev_data=prev_data, new_data=new_data)
1042       
1043        self._data_panel.remove_by_id(prev_id)
1044        self._data_panel.load_data_list(data_state)
1045       
1046    def update_theory(self, data_id, theory, state=None):
1047        """
1048        Update the theory
1049        """ 
1050        data_state = self._data_manager.update_theory(data_id=data_id, 
1051                                         theory=theory,
1052                                         state=state) 
1053        wx.CallAfter(self._data_panel.load_data_list, data_state)
1054       
1055    def onfreeze(self, theory_id):
1056        """
1057        """
1058        data_state_list = self._data_manager.freeze(theory_id)
1059        self._data_panel.load_data_list(list=data_state_list)
1060        for data_state in data_state_list.values():
1061            new_plot = data_state.get_data()
1062           
1063            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
1064                                             title=new_plot.title))
1065       
1066    def freeze(self, data_id, theory_id):
1067        """
1068        """
1069        data_state_list = self._data_manager.freeze_theory(data_id=data_id, 
1070                                                theory_id=theory_id)
1071        self._data_panel.load_data_list(list=data_state_list)
1072        for data_state in data_state_list.values():
1073            new_plot = data_state.get_data()
1074            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
1075                                             title=new_plot.title))
1076       
1077    def delete_data(self, data):
1078        """
1079        Delete the data.
1080        """
1081        self._current_perspective.delete_data(data)
1082       
1083   
1084    def get_context_menu(self, plotpanel=None):
1085        """
1086        Get the context menu items made available
1087        by the different plug-ins.
1088        This function is used by the plotting module
1089        """
1090        if plotpanel is None:
1091            return
1092        menu_list = []
1093        for item in self.plugins:
1094            menu_list.extend(item.get_context_menu(plotpanel=plotpanel))
1095        return menu_list
1096       
1097    def get_current_context_menu(self, plotpanel=None):
1098        """
1099        Get the context menu items made available
1100        by the current plug-in.
1101        This function is used by the plotting module
1102        """
1103        if plotpanel is None:
1104            return
1105        menu_list = []
1106        item = self._current_perspective
1107        if item != None:
1108            menu_list.extend(item.get_context_menu(plotpanel=plotpanel))
1109        return menu_list
1110           
1111    def on_panel_close(self, event):
1112        """
1113        Gets called when the close event for a panel runs.
1114        This will check which panel has been closed and
1115        delete it.
1116        """
1117        frame = event.GetEventObject()
1118        #panel = frame.panel
1119        #if panel.IsMaximized():
1120        #    self._mgr.RestoreMaximizedPane()
1121        for ID in self.plot_panels.keys():
1122            if self.plot_panels[ID].window_name == frame.name:
1123                self.disable_app_menu(self.plot_panels[ID])
1124                self.delete_panel(ID)
1125                break
1126        self.cpanel_on_focus.SetFocus()
1127   
1128   
1129    def popup_panel(self, p):
1130        """
1131        Add a panel object to the AUI manager
1132       
1133        :param p: panel object to add to the AUI manager
1134       
1135        :return: ID of the event associated with the new panel [int]
1136       
1137        """
1138        ID = wx.NewId()
1139        self.panels[str(ID)] = p
1140        ## Check and set the size
1141        if PLOPANEL_WIDTH < 0:
1142            p_panel_width = int(self._window_width * 0.45)
1143        else:
1144            p_panel_width = PLOPANEL_WIDTH
1145        p_panel_height = int(p_panel_width * 0.76)
1146        p.frame.SetSize((p_panel_width, p_panel_height))
1147        """
1148        dw, dh = self._get_panels_size(self._data_panel)
1149        dw += p_panel_width
1150        _, dh = self.GetToolBar().GetSizeTuple()
1151        p.frame.SetPosition((dw, -dh))
1152        """
1153        self.graph_num += 1
1154        if p.window_caption.split()[0] in NOT_SO_GRAPH_LIST:
1155            windowcaption = p.window_caption
1156        else:
1157            windowcaption = 'Graph'#p.window_caption
1158        windowname = p.window_name
1159
1160        # Append nummber
1161        captions = self._get_plotpanel_captions()
1162        while (1):
1163            caption = windowcaption + '%s'% str(self.graph_num)
1164            if caption not in captions:
1165                break
1166            self.graph_num += 1
1167            # protection from forever-loop: max num = 1000
1168            if self.graph_num > 1000:
1169                break
1170        if p.window_caption.split()[0] not in NOT_SO_GRAPH_LIST:
1171            p.window_caption = caption
1172        p.window_name = windowname + str(self.graph_num)
1173       
1174        style1 = self.__gui_style & GUIFRAME.FIXED_PANEL
1175        style2 = self.__gui_style & GUIFRAME.FLOATING_PANEL
1176       
1177        p.frame.SetTitle(p.window_caption)
1178        p.frame.name = p.window_name
1179        if not IS_WIN:
1180            p.frame.Center()
1181            x_pos, _ = p.frame.GetPositionTuple()
1182            p.frame.SetPosition((x_pos, 112))
1183        p.frame.Show(True)
1184
1185        # Register for showing/hiding the panel
1186        wx.EVT_MENU(self, ID, self.on_view)
1187        if p not in self.plot_panels.values() and p.group_id != None:
1188            self.plot_panels[ID] = p
1189            if len(self.plot_panels) == 1:
1190                self.panel_on_focus = p
1191                self.set_panel_on_focus(None)
1192            if self._data_panel is not None and \
1193                self._plotting_plugin is not None:
1194                ind = self._data_panel.cb_plotpanel.FindString('None')
1195                if ind != wx.NOT_FOUND:
1196                    self._data_panel.cb_plotpanel.Delete(ind)
1197                if caption not in self._data_panel.cb_plotpanel.GetItems():
1198                    self._data_panel.cb_plotpanel.Append(str(caption), p)
1199        return ID
1200   
1201    def _get_plotpanel_captions(self):
1202        """
1203        Get all the plotpanel cations
1204       
1205        : return: list of captions
1206        """
1207        captions = []
1208        for Id in self.plot_panels.keys():
1209            captions.append(self.plot_panels[Id].window_caption)
1210       
1211        return captions
1212         
1213    def _setup_menus(self):
1214        """
1215        Set up the application menus
1216        """
1217        # Menu
1218        self._menubar = wx.MenuBar()
1219        self._add_menu_file()
1220        self._add_menu_edit()
1221        self._add_menu_view()
1222        #self._add_menu_data()
1223        self._add_menu_application()
1224        self._add_menu_tool()
1225        self._add_current_plugin_menu()
1226        #self._add_menu_window()
1227        self._add_help_menu()
1228        self.SetMenuBar(self._menubar)
1229       
1230    def _setup_tool_bar(self):
1231        """
1232        add toolbar to the frame
1233        """
1234        #set toolbar
1235        self._toolbar = GUIToolBar(self, -1)
1236        self.SetToolBar(self._toolbar)
1237        self._update_toolbar_helper()
1238        self._on_toggle_toolbar(event=None)
1239   
1240    def _update_toolbar_helper(self):
1241        """
1242        Helping to update the toolbar
1243        """
1244        application_name = 'No Selected Analysis'
1245        panel_name = 'No Panel on Focus'
1246        c_panel = self.cpanel_on_focus       
1247        if self._toolbar is  None:
1248            return
1249        if c_panel is not None:
1250            self.reset_bookmark_menu(self.cpanel_on_focus)
1251        if self._current_perspective is not None:
1252            application_name = self._current_perspective.sub_menu
1253        c_panel_state = c_panel
1254        if c_panel is not None:
1255            panel_name = c_panel.window_caption
1256            if not c_panel.IsShownOnScreen():
1257                c_panel_state = None
1258        self._toolbar.update_toolbar(c_panel_state)
1259        self._toolbar.update_button(application_name=application_name, 
1260                                        panel_name=panel_name)
1261        self._toolbar.Realize()
1262       
1263    def _add_menu_tool(self):
1264        """
1265        Tools menu
1266        Go through plug-ins and find tools to populate the tools menu
1267        """
1268        style = self.__gui_style & GUIFRAME.CALCULATOR_ON
1269        if style == GUIFRAME.CALCULATOR_ON:
1270            self._tool_menu = None
1271            for item in self.plugins:
1272                if hasattr(item, "get_tools"):
1273                    for tool in item.get_tools():
1274                        # Only create a menu if we have at least one tool
1275                        if self._tool_menu is None:
1276                            self._tool_menu = wx.Menu()
1277                        if tool[0].lower().count('python') > 0:
1278                            self._tool_menu.AppendSeparator()
1279                        id = wx.NewId()
1280                        self._tool_menu.Append(id, tool[0], tool[1])
1281                        wx.EVT_MENU(self, id, tool[2])
1282            if self._tool_menu is not None:
1283                self._menubar.Append(self._tool_menu, '&Tool')
1284               
1285    def _add_current_plugin_menu(self):
1286        """
1287        add current plugin menu
1288        Look for plug-in menus
1289        Add available plug-in sub-menus.
1290        """
1291        if (self._menubar is None) or (self._current_perspective is None):
1292            return
1293        #replace or add a new menu for the current plugin
1294       
1295        pos = self._menubar.FindMenu(str(self._applications_menu_name))
1296        if pos != -1:
1297            menu_list = self._current_perspective.populate_menu(self)
1298            if menu_list:
1299                for (menu, name) in menu_list:
1300                    hidden_menu = self._menubar.Replace(pos, menu, name) 
1301                    self._applications_menu_name = name
1302                #self._applications_menu_pos = pos
1303            else:
1304                hidden_menu = self._menubar.Remove(pos)
1305                self._applications_menu_name = None
1306            #get the position of the menu when it first added
1307            self._applications_menu_pos = pos
1308           
1309        else:
1310            menu_list = self._current_perspective.populate_menu(self)
1311            if menu_list:
1312                for (menu, name) in menu_list:
1313                    if self._applications_menu_pos == -1:
1314                        self._menubar.Append(menu, name)
1315                    else:
1316                        self._menubar.Insert(self._applications_menu_pos, 
1317                                             menu, name)
1318                    self._applications_menu_name = name
1319                 
1320    def _add_help_menu(self):
1321        """
1322        add help menu
1323        """
1324        # Help menu
1325        self._help_menu = wx.Menu()
1326        style = self.__gui_style & GUIFRAME.WELCOME_PANEL_ON
1327        if style == GUIFRAME.WELCOME_PANEL_ON or custom_config != None:
1328            # add the welcome panel menu item
1329            if config.WELCOME_PANEL_ON and self.defaultPanel is not None:
1330                id = wx.NewId()
1331                self._help_menu.Append(id, '&Welcome', '')
1332                self._help_menu.AppendSeparator()
1333                wx.EVT_MENU(self, id, self.show_welcome_panel)
1334        # Look for help item in plug-ins
1335        for item in self.plugins:
1336            if hasattr(item, "help"):
1337                id = wx.NewId()
1338                self._help_menu.Append(id,'&%s Help' % item.sub_menu, '')
1339                wx.EVT_MENU(self, id, item.help)
1340        if config._do_tutorial and (IS_WIN or sys.platform =='darwin'):
1341            self._help_menu.AppendSeparator()
1342            id = wx.NewId()
1343            self._help_menu.Append(id, '&Tutorial', 'Software tutorial')
1344            wx.EVT_MENU(self, id, self._onTutorial)
1345           
1346        if config._do_aboutbox:
1347            self._help_menu.AppendSeparator()
1348            id = wx.NewId()
1349            self._help_menu.Append(id, '&About', 'Software information')
1350            wx.EVT_MENU(self, id, self._onAbout)
1351       
1352        # Checking for updates
1353        id = wx.NewId()
1354        self._help_menu.Append(id,'&Check for update', 
1355         'Check for the latest version of %s' % config.__appname__)
1356        wx.EVT_MENU(self, id, self._check_update)
1357        self._menubar.Append(self._help_menu, '&Help')
1358           
1359    def _add_menu_view(self):
1360        """
1361        add menu items under view menu
1362        """
1363        if not VIEW_MENU:
1364            return
1365        self._view_menu = wx.Menu()
1366       
1367        id = wx.NewId()
1368        hint = "Display the Grid Window for batch results etc."
1369        self._view_menu.Append(id, '&Show Grid Window', hint) 
1370        wx.EVT_MENU(self, id, self.show_batch_frame)
1371       
1372        self._view_menu.AppendSeparator()
1373        style = self.__gui_style & GUIFRAME.MANAGER_ON
1374        id = wx.NewId()
1375        self._data_panel_menu = self._view_menu.Append(id,
1376                                                '&Show Data Explorer', '')
1377        wx.EVT_MENU(self, id, self.show_data_panel)
1378        if style == GUIFRAME.MANAGER_ON:
1379            self._data_panel_menu.SetText('Hide Data Explorer')
1380        else:
1381            self._data_panel_menu.SetText('Show Data Explorer')
1382 
1383        self._view_menu.AppendSeparator()
1384        id = wx.NewId()
1385        style1 = self.__gui_style & GUIFRAME.TOOLBAR_ON
1386        if style1 == GUIFRAME.TOOLBAR_ON:
1387            self._toolbar_menu = self._view_menu.Append(id, '&Hide Toolbar', '')
1388        else:
1389            self._toolbar_menu = self._view_menu.Append(id, '&Show Toolbar', '')
1390        wx.EVT_MENU(self, id, self._on_toggle_toolbar)
1391
1392        if custom_config != None:
1393            self._view_menu.AppendSeparator()
1394            id = wx.NewId()
1395            hint_ss = "Select the current/default configuration "
1396            hint_ss += "as a startup setting"
1397            preference_menu = self._view_menu.Append(id, 'Startup Setting', 
1398                                                     hint_ss)
1399            wx.EVT_MENU(self, id, self._on_preference_menu)
1400           
1401        id = wx.NewId()
1402        self._view_menu.AppendSeparator()
1403        self._view_menu.Append(id, 'Category Manager', 'Edit model categories')
1404        wx.EVT_MENU(self, id, self._on_category_manager)
1405
1406        self._menubar.Append(self._view_menu, '&View')   
1407         
1408    def show_batch_frame(self, event=None):
1409        """
1410        show the grid of result
1411        """
1412        # Show(False) before Show(True) in order to bring it to the front
1413        self.batch_frame.Show(False)
1414        self.batch_frame.Show(True)
1415   
1416    def  on_category_panel(self, event): 
1417        """
1418        On cat panel
1419        """
1420        self._on_category_manager(event)
1421         
1422    def _on_category_manager(self, event):
1423        """
1424        Category manager frame
1425        """
1426        frame = CategoryManager(self, -1, 'Model Category Manager')
1427        icon = self.GetIcon()
1428        frame.SetIcon(icon)
1429
1430    def _on_preference_menu(self, event):     
1431        """
1432        Build a panel to allow to edit Mask
1433        """
1434       
1435        from sans.guiframe.startup_configuration \
1436        import StartupConfiguration as ConfDialog
1437       
1438        self.panel = ConfDialog(parent=self, gui=self.__gui_style)
1439        self.panel.ShowModal()
1440
1441               
1442    def _add_menu_application(self):
1443        """
1444        # Attach a menu item for each defined perspective or application.
1445        # Only add the perspective menu if there are more than one perspectives
1446        add menu application
1447        """
1448        #style = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
1449        #if style == GUIFRAME.MULTIPLE_APPLICATIONS:
1450        if self._num_perspectives  > 1:
1451            plug_data_count = False
1452            plug_no_data_count = False
1453            self._applications_menu = wx.Menu()
1454            pos = 0
1455            separator = self._applications_menu.AppendSeparator()
1456            for plug in self.plugins:
1457                if len(plug.get_perspective()) > 0:
1458                    id = wx.NewId()
1459                    if plug.use_data():
1460                       
1461                        self._applications_menu.InsertCheckItem(pos, id, plug.sub_menu,
1462                                      "Switch to analysis: %s" % plug.sub_menu)
1463                        plug_data_count = True
1464                        pos += 1
1465                    else:
1466                        plug_no_data_count = True
1467                        self._applications_menu.AppendCheckItem(id, plug.sub_menu,
1468                                      "Switch to analysis: %s" % plug.sub_menu)
1469                    wx.EVT_MENU(self, id, plug.on_perspective)
1470
1471            #self._applications_menu.
1472            if (not plug_data_count or not plug_no_data_count):
1473                self._applications_menu.RemoveItem(separator)
1474            self._menubar.Append(self._applications_menu, '&Analysis')
1475            self._check_applications_menu()
1476           
1477    def _populate_file_menu(self):
1478        """
1479        Insert menu item under file menu
1480        """
1481        for plugin in self.plugins:
1482            if len(plugin.populate_file_menu()) > 0:
1483                for item in plugin.populate_file_menu():
1484                    m_name, m_hint, m_handler = item
1485                    id = wx.NewId()
1486                    self._file_menu.Append(id, m_name, m_hint)
1487                    wx.EVT_MENU(self, id, m_handler)
1488                self._file_menu.AppendSeparator()
1489               
1490    def _add_menu_file(self):
1491        """
1492        add menu file
1493        """
1494       
1495        # File menu
1496        self._file_menu = wx.Menu()
1497        #append item from plugin under menu file if necessary
1498        self._populate_file_menu()
1499        style1 = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
1500        if OPEN_SAVE_MENU:
1501            id = wx.NewId()
1502            hint_load_file = "read all analysis states saved previously"
1503            self._save_appl_menu = self._file_menu.Append(id, 
1504                                    '&Open Project', hint_load_file)
1505            wx.EVT_MENU(self, id, self._on_open_state_project)
1506           
1507        if style1 == GUIFRAME.MULTIPLE_APPLICATIONS:
1508            # some menu of plugin to be seen under file menu
1509            hint_load_file = "Read a status files and load"
1510            hint_load_file += " them into the analysis"
1511            id = wx.NewId()
1512            self._save_appl_menu = self._file_menu.Append(id, 
1513                                    '&Open Analysis', hint_load_file)
1514            wx.EVT_MENU(self, id, self._on_open_state_application)
1515        if OPEN_SAVE_MENU:       
1516            self._file_menu.AppendSeparator()
1517            id = wx.NewId()
1518            self._file_menu.Append(id, '&Save Project',
1519                                 'Save the state of the whole analysis')
1520            wx.EVT_MENU(self, id, self._on_save_project)
1521        if style1 == GUIFRAME.MULTIPLE_APPLICATIONS:
1522            #self._file_menu.AppendSeparator()
1523            id = wx.NewId()
1524            self._save_appl_menu = self._file_menu.Append(id, 
1525                                                      '&Save Analysis',
1526                        'Save state of the current active analysis panel')
1527            wx.EVT_MENU(self, id, self._on_save_application)
1528            self._file_menu.AppendSeparator()
1529       
1530        id = wx.NewId()
1531        self._file_menu.Append(id, '&Quit', 'Exit') 
1532        wx.EVT_MENU(self, id, self.Close)
1533        # Add sub menus
1534        self._menubar.Append(self._file_menu, '&File')
1535       
1536    def _add_menu_edit(self):
1537        """
1538        add menu edit
1539        """
1540        if not EDIT_MENU:
1541            return
1542        # Edit Menu
1543        self._edit_menu = wx.Menu()
1544        self._edit_menu.Append(GUIFRAME_ID.UNDO_ID, '&Undo', 
1545                               'Undo the previous action')
1546        wx.EVT_MENU(self, GUIFRAME_ID.UNDO_ID, self.on_undo_panel)
1547        self._edit_menu.Append(GUIFRAME_ID.REDO_ID, '&Redo', 
1548                               'Redo the previous action')
1549        wx.EVT_MENU(self, GUIFRAME_ID.REDO_ID, self.on_redo_panel)
1550        self._edit_menu.AppendSeparator()
1551        self._edit_menu.Append(GUIFRAME_ID.COPY_ID, '&Copy Params', 
1552                               'Copy parameter values')
1553        wx.EVT_MENU(self, GUIFRAME_ID.COPY_ID, self.on_copy_panel)
1554        self._edit_menu.Append(GUIFRAME_ID.PASTE_ID, '&Paste Params', 
1555                               'Paste parameter values')
1556        wx.EVT_MENU(self, GUIFRAME_ID.PASTE_ID, self.on_paste_panel)
1557        self._edit_menu.AppendSeparator()
1558       
1559        self._edit_menu.Append(GUIFRAME_ID.PREVIEW_ID, '&Report Results',
1560                               'Preview current panel')
1561        wx.EVT_MENU(self, GUIFRAME_ID.PREVIEW_ID, self.on_preview_panel)
1562
1563        self._edit_menu.Append(GUIFRAME_ID.RESET_ID, '&Reset Page', 
1564                               'Reset current panel')
1565        wx.EVT_MENU(self, GUIFRAME_ID.RESET_ID, self.on_reset_panel)
1566   
1567        self._menubar.Append(self._edit_menu,  '&Edit')
1568        self.enable_edit_menu()
1569       
1570    def get_style(self):
1571        """
1572        Return the gui style
1573        """
1574        return  self.__gui_style
1575   
1576    def _add_menu_data(self):
1577        """
1578        Add menu item item data to menu bar
1579        """
1580        if self._data_plugin is not None:
1581            menu_list = self._data_plugin.populate_menu(self)
1582            if menu_list:
1583                for (menu, name) in menu_list:
1584                    self._menubar.Append(menu, name)
1585       
1586                       
1587    def _on_toggle_toolbar(self, event=None):
1588        """
1589        hide or show toolbar
1590        """
1591        if self._toolbar is None:
1592            return
1593        if self._toolbar.IsShown():
1594            if self._toolbar_menu is not None:
1595                self._toolbar_menu.SetItemLabel('Show Toolbar')
1596            self._toolbar.Hide()
1597        else:
1598            if self._toolbar_menu is not None:
1599                self._toolbar_menu.SetItemLabel('Hide Toolbar')
1600            self._toolbar.Show()
1601        self._toolbar.Realize()
1602       
1603    def _on_status_event(self, evt):
1604        """
1605        Display status message
1606        """
1607        # This CallAfter fixes many crashes on MAC.
1608        wx.CallAfter(self.sb.set_status, evt)
1609       
1610    def on_view(self, evt):
1611        """
1612        A panel was selected to be shown. If it's not already
1613        shown, display it.
1614       
1615        :param evt: menu event
1616       
1617        """
1618        panel_id = str(evt.GetId())
1619        self.on_set_plot_focus(self.panels[panel_id])
1620        self.show_panel(evt.GetId(), 'on')     
1621        wx.CallLater(5*TIME_FACTOR, self.set_schedule(True))
1622        self.set_plot_unfocus()
1623 
1624    def show_welcome_panel(self, event):
1625        """   
1626        Display the welcome panel
1627        """
1628        if self.defaultPanel is None:
1629            return 
1630        frame = self.panels['default'].get_frame()
1631        if frame == None:
1632            return
1633        # Show default panel
1634        if not frame.IsShown():
1635            frame.Show(True)
1636           
1637    def on_close_welcome_panel(self):
1638        """
1639        Close the welcome panel
1640        """
1641        if self.defaultPanel is None:
1642            return 
1643        default_panel = self.panels["default"].frame
1644        if default_panel.IsShown():
1645            default_panel.Show(False) 
1646               
1647    def delete_panel(self, uid):
1648        """
1649        delete panel given uid
1650        """
1651        ID = str(uid)
1652        config.printEVT("delete_panel: %s" % ID)
1653        try:
1654            caption = self.panels[ID].window_caption
1655        except:
1656            print "delete_panel: No such plot id as %s" % ID
1657            return
1658        if ID in self.panels.keys():
1659            self.panel_on_focus = None
1660            panel = self.panels[ID]
1661            #self._mgr.DetachPane(panel)
1662            if hasattr(panel, "connect"):
1663                panel.connect.disconnect()
1664            self._plotting_plugin.delete_panel(panel.group_id)
1665            #panel.Hide()
1666            #panel.clear()
1667            #panel.Close()
1668            if panel in self.schedule_full_draw_list:
1669                self.schedule_full_draw_list.remove(panel) 
1670           
1671            #delete uid number not str(uid)
1672            if ID in self.plot_panels.keys():
1673                del self.plot_panels[ID]
1674            if ID in self.panels.keys():
1675                del self.panels[ID]
1676            return 
1677           
1678    def create_gui_data(self, data, path=None):
1679        """
1680        """
1681        return self._data_manager.create_gui_data(data, path)
1682   
1683    def get_data(self, path):
1684        """
1685        """
1686        message = ""
1687        log_msg = ''
1688        output = []
1689        error_message = ""
1690        basename  = os.path.basename(path)
1691        root, extension = os.path.splitext(basename)
1692        if extension.lower() not in EXTENSIONS:
1693            log_msg = "File Loader cannot "
1694            log_msg += "load: %s\n" % str(basename)
1695            log_msg += "Try Data opening...."
1696            logging.info(log_msg)
1697            print log_msg
1698            #self.load_complete(output=output, error_message=error_message,
1699            #       message=log_msg, path=path)   
1700            return
1701       
1702        #reading a state file
1703        for plug in self.plugins:
1704            reader, ext = plug.get_extensions()
1705            if reader is not None:
1706                #read the state of the single plugin
1707                if extension == ext:
1708                    reader.read(path)
1709                    return
1710                elif extension == APPLICATION_STATE_EXTENSION:
1711                    try:
1712                        reader.read(path)
1713                    except:
1714                        msg = "DataLoader Error: Encounted Non-ASCII character"
1715                        msg += "\n(%s)"% sys.exc_value
1716                        wx.PostEvent(self, StatusEvent(status=msg, 
1717                                                info="error", type="stop"))
1718                        return
1719       
1720        style = self.__gui_style & GUIFRAME.MANAGER_ON
1721        if style == GUIFRAME.MANAGER_ON:
1722            if self._data_panel is not None:
1723                self._data_panel.frame.Show(True)
1724     
1725    def load_from_cmd(self,  path):   
1726        """
1727        load data from cmd or application
1728        """ 
1729        if path is None:
1730            return
1731        else:
1732            path = os.path.abspath(path)
1733            if not os.path.isfile(path) and not os.path.isdir(path):
1734                return
1735           
1736            if os.path.isdir(path):
1737                self.load_folder(path)
1738                return
1739
1740        basename  = os.path.basename(path)
1741        root, extension = os.path.splitext(basename)
1742        if extension.lower() not in EXTENSIONS:
1743            self.load_data(path)
1744        else:
1745            self.load_state(path)
1746
1747        self._default_save_location = os.path.dirname(path)
1748       
1749    def show_panel(self, uid, show=None):
1750        """
1751        Shows the panel with the given id
1752       
1753        :param uid: unique ID number of the panel to show
1754       
1755        """
1756        ID = str(uid)
1757        config.printEVT("show_panel: %s" % ID)
1758        if ID in self.panels.keys():
1759            if not self.panels[ID].frame.IsShown(): 
1760                if show == 'on':
1761                    self.panels[ID].frame.Show()   
1762                elif self.panels[ID].window_caption.split(" ")[0] == \
1763                                                            "Residuals":
1764                    self._mgr.GetPane(self.panels[ID].window_name).Hide()
1765                else:
1766                    self._mgr.GetPane(self.panels[ID].window_name).Show()
1767                # Hide default panel
1768                self._mgr.GetPane(self.panels["default"].window_name).Hide()
1769        self._mgr.Update()     
1770        self._redraw_idle()
1771       
1772    def load_state(self, path, is_project=False):   
1773        """
1774        load data from command line or application
1775        """
1776        if path and (path is not None) and os.path.isfile(path):
1777            basename  = os.path.basename(path)
1778            if APPLICATION_STATE_EXTENSION is not None \
1779                and basename.endswith(APPLICATION_STATE_EXTENSION):
1780                if is_project:
1781                    for ID in self.plot_panels.keys():
1782                        panel = self.plot_panels[ID]
1783                        panel.on_close(None)
1784            self.get_data(path)
1785            wx.PostEvent(self, StatusEvent(status="Completed loading."))
1786        else:
1787            wx.PostEvent(self, StatusEvent(status=" "))
1788        #if self.defaultPanel is not None and \
1789        #    self._mgr.GetPane(self.panels["default"].window_name).IsShown():
1790        #    self.on_close_welcome_panel()
1791           
1792    def load_data(self, path):
1793        """
1794        load data from command line
1795        """
1796        if not os.path.isfile(path):
1797            return
1798        basename  = os.path.basename(path)
1799        root, extension = os.path.splitext(basename)
1800        if extension.lower() in EXTENSIONS:
1801            log_msg = "Data Loader cannot "
1802            log_msg += "load: %s\n" % str(path)
1803            log_msg += "Try File opening ...."
1804            print log_msg
1805            return
1806        log_msg = ''
1807        output = {}
1808        error_message = ""
1809        try:
1810            print "Loading Data...:\n" + str(path) + "\n"
1811            temp =  self.loader.load(path)
1812            if temp.__class__.__name__ == "list":
1813                for item in temp:
1814                    data = self.create_gui_data(item, path)
1815                    output[data.id] = data
1816            else:
1817                data = self.create_gui_data(temp, path)
1818                output[data.id] = data
1819           
1820            self.add_data(data_list=output)
1821        except:
1822            error_message = "Error while loading"
1823            error_message += " Data from cmd:\n %s\n" % str(path)
1824            error_message += str(sys.exc_value) + "\n"
1825            print error_message
1826 
1827    def load_folder(self, path):
1828        """
1829        Load entire folder
1830        """   
1831        if not os.path.isdir(path):
1832            return
1833        if self._data_plugin is None:
1834            return
1835        try:
1836            if path is not None:
1837                self._default_save_location = os.path.dirname(path)
1838                file_list = self._data_plugin.get_file_path(path)
1839                self._data_plugin.get_data(file_list)
1840            else:
1841                return 
1842        except:
1843            error_message = "Error while loading"
1844            error_message += " Data folder from cmd:\n %s\n" % str(path)
1845            error_message += str(sys.exc_value) + "\n"
1846            print error_message
1847           
1848    def _on_open_state_application(self, event):
1849        """
1850        """
1851        path = None
1852        if self._default_save_location == None:
1853            self._default_save_location = os.getcwd()
1854        wx.PostEvent(self, StatusEvent(status="Loading Analysis file..."))
1855        plug_wlist = self._on_open_state_app_helper()
1856        dlg = wx.FileDialog(self, 
1857                            "Choose a file", 
1858                            self._default_save_location, "",
1859                            plug_wlist)
1860        if dlg.ShowModal() == wx.ID_OK:
1861            path = dlg.GetPath()
1862            if path is not None:
1863                self._default_save_location = os.path.dirname(path)
1864        dlg.Destroy()
1865        self.load_state(path=path) 
1866   
1867    def _on_open_state_app_helper(self):
1868        """
1869        Helps '_on_open_state_application()' to find the extension of
1870        the current perspective/application
1871        """
1872        # No current perspective or no extension attr
1873        if self._current_perspective is None:
1874            return PLUGINS_WLIST
1875        try:
1876            # Find the extension of the perspective
1877            # and get that as 1st item in list
1878            ind = None
1879            app_ext = self._current_perspective._extensions
1880            plug_wlist = config.PLUGINS_WLIST
1881            for ext in set(plug_wlist):
1882                if ext.count(app_ext) > 0:
1883                    ind = ext
1884                    break
1885            # Found the extension
1886            if ind != None:
1887                plug_wlist.remove(ind)
1888                plug_wlist.insert(0, ind)
1889                try:
1890                    plug_wlist = '|'.join(plug_wlist)
1891                except:
1892                    plug_wlist = ''
1893
1894        except:
1895            plug_wlist = PLUGINS_WLIST
1896           
1897        return plug_wlist
1898           
1899    def _on_open_state_project(self, event):
1900        """
1901        """
1902        path = None
1903        if self._default_save_location == None:
1904            self._default_save_location = os.getcwd()
1905        wx.PostEvent(self, StatusEvent(status="Loading Project file..."))
1906        dlg = wx.FileDialog(self, 
1907                            "Choose a file", 
1908                            self._default_save_location, "",
1909                             APPLICATION_WLIST)
1910        if dlg.ShowModal() == wx.ID_OK:
1911            path = dlg.GetPath()
1912            if path is not None:
1913                self._default_save_location = os.path.dirname(path)
1914        dlg.Destroy()
1915       
1916        #try:   
1917        #    os.popen(path)
1918        #    #self.Close()
1919        #except:
1920       
1921        self.load_state(path=path, is_project=True)
1922       
1923    def _on_save_application(self, event):
1924        """
1925        save the state of the current active application
1926        """
1927        if self.cpanel_on_focus is not None:
1928            try:
1929                wx.PostEvent(self, 
1930                             StatusEvent(status="Saving Analysis file..."))
1931                self.cpanel_on_focus.on_save(event)
1932                wx.PostEvent(self, 
1933                             StatusEvent(status="Completed saving."))
1934            except:
1935                msg = "Error occurred while saving: "
1936                msg += "To save, the application panel should have a data set.."
1937                wx.PostEvent(self, StatusEvent(status=msg)) 
1938           
1939    def _on_save_project(self, event):
1940        """
1941        save the state of the SasView as *.svs
1942        """
1943        if self._current_perspective is  None:
1944            return
1945        wx.PostEvent(self, StatusEvent(status="Saving Project file..."))
1946        reader, ext = self._current_perspective.get_extensions()
1947        path = None
1948        extension = '*' + APPLICATION_STATE_EXTENSION
1949        dlg = wx.FileDialog(self, "Save Project file",
1950                            self._default_save_location, "sasview_proj",
1951                             extension, 
1952                             wx.SAVE)
1953        if dlg.ShowModal() == wx.ID_OK:
1954            path = dlg.GetPath()
1955            self._default_save_location = os.path.dirname(path)
1956        else:
1957            return None
1958        dlg.Destroy()
1959        try:
1960            if path is None:
1961                return
1962            # default cansas xml doc
1963            doc = None
1964            for panel in self.panels.values():
1965                temp = panel.save_project(doc)
1966                if temp is not None:
1967                    doc = temp
1968             
1969            # Write the XML document
1970            extens = APPLICATION_STATE_EXTENSION
1971            fName = os.path.splitext(path)[0] + extens
1972            if doc != None:
1973                fd = open(fName, 'w')
1974                fd.write(doc.toprettyxml())
1975                fd.close()
1976                wx.PostEvent(self, StatusEvent(status="Completed Saving."))
1977            else:
1978                msg = "%s cannot read %s\n" % (str(APPLICATION_NAME), str(path))
1979                logging.error(msg)
1980        except:
1981            msg = "Error occurred while saving: "
1982            msg += "To save, at leat one application panel "
1983            msg += "should have a data set.."
1984            wx.PostEvent(self, StatusEvent(status=msg))   
1985                   
1986    def on_save_helper(self, doc, reader, panel, path):
1987        """
1988        Save state into a file
1989        """
1990        try:
1991            if reader is not None:
1992                # case of a panel with multi-pages
1993                if hasattr(panel, "opened_pages"):
1994                    for uid, page in panel.opened_pages.iteritems():
1995                        data = page.get_data()
1996                        # state must be cloned
1997                        state = page.get_state().clone()
1998                        if data is not None:
1999                            new_doc = reader.write_toXML(data, state)
2000                            if doc != None and hasattr(doc, "firstChild"):
2001                                child = new_doc.firstChild.firstChild
2002                                doc.firstChild.appendChild(child) 
2003                            else:
2004                                doc = new_doc
2005                # case of only a panel
2006                else:
2007                    data = panel.get_data()
2008                    state = panel.get_state()
2009                    if data is not None:
2010                        new_doc = reader.write_toXML(data, state)
2011                        if doc != None and hasattr(doc, "firstChild"):
2012                            child = new_doc.firstChild.firstChild
2013                            doc.firstChild.appendChild(child) 
2014                        else:
2015                            doc = new_doc
2016        except: 
2017            raise
2018            #pass
2019
2020        return doc
2021
2022    def quit_guiframe(self):
2023        """
2024        Pop up message to make sure the user wants to quit the application
2025        """
2026        message = "\nDo you really want to exit this application?        \n\n"
2027        dial = wx.MessageDialog(self, message, 'Confirm Exit',
2028                           wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
2029        if dial.ShowModal() == wx.ID_YES:
2030            return True
2031        else:
2032            return False   
2033       
2034    def WindowClose(self, event=None):
2035        """
2036        Quit the application from x icon
2037        """
2038        flag = self.quit_guiframe()
2039        if flag:
2040            self.Close()
2041           
2042    def Close(self, event=None):
2043        """
2044        Quit the application
2045        """
2046        wx.Exit()
2047        sys.exit()
2048           
2049    def _check_update(self, event=None): 
2050        """
2051        Check with the deployment server whether a new version
2052        of the application is available.
2053        A thread is started for the connecting with the server. The thread calls
2054        a call-back method when the current version number has been obtained.
2055        """
2056        try:
2057            conn = httplib.HTTPConnection(config.__update_URL__[0], 
2058                              timeout=3.0)
2059            conn.request("GET", config.__update_URL__[1])
2060            res = conn.getresponse()
2061            content = res.read()
2062            conn.close()
2063            #f=urllib2.urlopen(config.__update_URL__,
2064            #                  timeout=1.0)
2065            #content = f.read()
2066        except:
2067            content = "0.0.0"
2068       
2069        version = content.strip()
2070        if len(re.findall('\d+\.\d+\.\d+$', version)) < 0:
2071            content = "0.0.0"
2072        self._process_version(content, standalone=event==None)
2073   
2074    def _process_version(self, version, standalone=True):
2075        """
2076        Call-back method for the process of checking for updates.
2077        This methods is called by a VersionThread object once the current
2078        version number has been obtained. If the check is being done in the
2079        background, the user will not be notified unless there's an update.
2080       
2081        :param version: version string
2082        :param standalone: True of the update is being checked in
2083           the background, False otherwise.
2084           
2085        """
2086        try:
2087            if version == "0.0.0":
2088                msg = "Could not connect to the application server."
2089                msg += " Please try again later."
2090                self.SetStatusText(msg)
2091            elif cmp(version, config.__version__) > 0:
2092                msg = "Version %s is available! " % str(version)
2093                if not standalone:
2094                    import webbrowser
2095                    webbrowser.open(config.__download_page__)
2096                else:
2097                    msg +=  "See the help menu to download it." 
2098                self.SetStatusText(msg)
2099            else:
2100                if not standalone:
2101                    msg = "You have the latest version"
2102                    msg += " of %s" % str(config.__appname__)
2103                    self.SetStatusText(msg)
2104        except:
2105            msg = "guiframe: could not get latest application"
2106            msg += " version number\n  %s" % sys.exc_value
2107            logging.error(msg)
2108            if not standalone:
2109                msg = "Could not connect to the application server."
2110                msg += " Please try again later."
2111                self.SetStatusText(msg)
2112                   
2113    def _onAbout(self, evt):
2114        """
2115        Pop up the about dialog
2116       
2117        :param evt: menu event
2118       
2119        """
2120        if config._do_aboutbox:
2121            import sans.guiframe.aboutbox as AboutBox 
2122            dialog = AboutBox.DialogAbout(None, -1, "")
2123            dialog.ShowModal()   
2124                     
2125    def _onTutorial(self, evt):
2126        """
2127        Pop up the tutorial dialog
2128       
2129        :param evt: menu event
2130       
2131        """
2132        if config._do_tutorial:   
2133            path = config.TUTORIAL_PATH
2134            if IS_WIN:
2135                try:
2136                    from sans.guiframe.pdfview import PDFFrame
2137                    dialog = PDFFrame(None, -1, "Tutorial", path)
2138                    # put icon
2139                    self.put_icon(dialog) 
2140                    dialog.Show(True) 
2141                except:
2142                    print "Error in _onTutorial: %s" % sys.exc_value
2143                    try:
2144                        #in case when the pdf default set other than acrobat
2145                        import ho.pisa as pisa
2146                        pisa.startViewer(path)
2147                    except:
2148                        msg = "This feature requires 'PDF Viewer'\n"
2149                        msg += "Please install it first (Free)..."
2150                        wx.MessageBox(msg, 'Error')
2151            else:
2152                try:
2153                    command = "open '%s'" % path
2154                    os.system(command)
2155                except:
2156                    try:
2157                        #in case when the pdf default set other than preview
2158                        import ho.pisa as pisa
2159                        pisa.startViewer(path)
2160                    except:
2161                        msg = "This feature requires 'Preview' Application\n"
2162                        msg += "Please install it first..."
2163                        wx.MessageBox(msg, 'Error')
2164
2165                     
2166    def set_manager(self, manager):
2167        """
2168        Sets the application manager for this frame
2169       
2170        :param manager: frame manager
2171        """
2172        self.app_manager = manager
2173       
2174    def post_init(self):
2175        """
2176        This initialization method is called after the GUI
2177        has been created and all plug-ins loaded. It calls
2178        the post_init() method of each plug-in (if it exists)
2179        so that final initialization can be done.
2180        """
2181        for item in self.plugins:
2182            if hasattr(item, "post_init"):
2183                item.post_init()
2184       
2185    def set_default_perspective(self):
2186        """
2187        Choose among the plugin the first plug-in that has
2188        "set_default_perspective" method and its return value is True will be
2189        as a default perspective when the welcome page is closed
2190        """
2191        for item in self.plugins:
2192            if hasattr(item, "set_default_perspective"):
2193                if item.set_default_perspective():
2194                    item.on_perspective(event=None)
2195                    return 
2196       
2197    def set_perspective(self, panels):
2198        """
2199        Sets the perspective of the GUI.
2200        Opens all the panels in the list, and closes
2201        all the others.
2202       
2203        :param panels: list of panels
2204        """
2205        for item in self.panels.keys():
2206            # Check whether this is a sticky panel
2207            if hasattr(self.panels[item], "ALWAYS_ON"):
2208                if self.panels[item].ALWAYS_ON:
2209                    continue 
2210            if self.panels[item] == None:
2211                continue
2212            if self.panels[item].window_name in panels:
2213                frame = self.panels[item].get_frame()
2214                if not frame.IsShown():
2215                    frame.Show(True)
2216            else:
2217                # always show the data panel if enable
2218                style = self.__gui_style & GUIFRAME.MANAGER_ON
2219                if (style == GUIFRAME.MANAGER_ON) and self.panels[item] == self._data_panel:
2220                    if 'data_panel' in self.panels.keys():
2221                        frame = self.panels['data_panel'].get_frame()
2222                        if frame == None:
2223                            continue
2224                        flag = frame.IsShown()
2225                        frame.Show(flag)
2226                else:
2227                    frame = self.panels[item].get_frame()
2228                    if frame == None:
2229                        continue
2230
2231                    if frame.IsShown():
2232                        frame.Show(False)
2233       
2234    def show_data_panel(self, event=None, action=True):
2235        """
2236        show the data panel
2237        """
2238        if self._data_panel_menu == None:
2239            return
2240        label = self._data_panel_menu.GetText()
2241        pane = self.panels["data_panel"]
2242        frame = pane.get_frame()
2243        if label == 'Show Data Explorer':
2244            #if not pane.IsShown():
2245            if action: 
2246                frame.Show(True)
2247            self.__gui_style = self.__gui_style | GUIFRAME.MANAGER_ON
2248            self._data_panel_menu.SetText('Hide Data Explorer')
2249        else:
2250            if action:
2251                frame.Show(False)
2252            self.__gui_style = self.__gui_style & (~GUIFRAME.MANAGER_ON)
2253            self._data_panel_menu.SetText('Show Data Explorer')
2254
2255    def add_data_helper(self, data_list):
2256        """
2257        """
2258        if self._data_manager is not None:
2259            self._data_manager.add_data(data_list)
2260       
2261    def add_data(self, data_list):
2262        """
2263        receive a dictionary of data from loader
2264        store them its data manager if possible
2265        send to data the current active perspective if the data panel
2266        is not active.
2267        :param data_list: dictionary of data's ID and value Data
2268        """
2269        #Store data into manager
2270        self.add_data_helper(data_list)
2271        # set data in the data panel
2272        if self._data_panel is not None:
2273            data_state = self._data_manager.get_data_state(data_list.keys())
2274            self._data_panel.load_data_list(data_state)
2275        #if the data panel is shown wait for the user to press a button
2276        #to send data to the current perspective. if the panel is not
2277        #show  automatically send the data to the current perspective
2278        style = self.__gui_style & GUIFRAME.MANAGER_ON
2279        if style == GUIFRAME.MANAGER_ON:
2280            #wait for button press from the data panel to set_data
2281            if self._data_panel is not None:
2282                self._data_panel.frame.Show(True)
2283        else:
2284            #automatically send that to the current perspective
2285            self.set_data(data_id=data_list.keys())
2286       
2287    def set_data(self, data_id, theory_id=None): 
2288        """
2289        set data to current perspective
2290        """
2291        list_data, _ = self._data_manager.get_by_id(data_id)
2292        if self._current_perspective is not None:
2293            self._current_perspective.set_data(list_data.values())
2294
2295        else:
2296            msg = "Guiframe does not have a current perspective"
2297            logging.info(msg)
2298           
2299    def set_theory(self, state_id, theory_id=None):
2300        """
2301        """
2302        _, list_theory = self._data_manager.get_by_id(theory_id)
2303        if self._current_perspective is not None:
2304            try:
2305                self._current_perspective.set_theory(list_theory.values())
2306            except:
2307                msg = "Guiframe set_theory: \n" + str(sys.exc_value)
2308                logging.info(msg)
2309                wx.PostEvent(self, StatusEvent(status=msg, info="error"))
2310        else:
2311            msg = "Guiframe does not have a current perspective"
2312            logging.info(msg)
2313           
2314    def plot_data(self,  state_id, data_id=None,
2315                  theory_id=None, append=False):
2316        """
2317        send a list of data to plot
2318        """
2319        total_plot_list = []
2320        data_list, _ = self._data_manager.get_by_id(data_id)
2321        _, temp_list_theory = self._data_manager.get_by_id(theory_id)
2322        total_plot_list = data_list.values()
2323        for item in temp_list_theory.values():
2324            theory_data, theory_state = item
2325            total_plot_list.append(theory_data)
2326        GROUP_ID = wx.NewId()
2327        for new_plot in total_plot_list:
2328            if append:
2329                if self.panel_on_focus is None:
2330                    message = "cannot append plot. No plot panel on focus!"
2331                    message += "please click on any available plot to set focus"
2332                    wx.PostEvent(self, StatusEvent(status=message, 
2333                                                   info='warning'))
2334                    return 
2335                else:
2336                    if self.enable_add_data(new_plot):
2337                        new_plot.group_id = self.panel_on_focus.group_id
2338                    else:
2339                        message = "Only 1D Data can be append to"
2340                        message += " plot panel containing 1D data.\n"
2341                        message += "%s not be appended.\n" %str(new_plot.name)
2342                        message += "try new plot option.\n"
2343                        wx.PostEvent(self, StatusEvent(status=message, 
2344                                                   info='warning'))
2345            else:
2346                #if not append then new plot
2347                from sans.guiframe.dataFitting import Data2D
2348                if issubclass(Data2D, new_plot.__class__):
2349                    #for 2 D always plot in a separated new plot
2350                    new_plot.group_id = wx.NewId()
2351                else:
2352                    # plot all 1D in a new plot
2353                    new_plot.group_id = GROUP_ID
2354            title = "PLOT " + str(new_plot.title)
2355            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
2356                                                  title=title,
2357                                                  group_id = new_plot.group_id))
2358           
2359    def remove_data(self, data_id, theory_id=None):
2360        """
2361        Delete data state if data_id is provide
2362        delete theory created with data of id data_id if theory_id is provide
2363        if delete all true: delete the all state
2364        else delete theory
2365        """
2366        temp = data_id + theory_id
2367        for plug in self.plugins:
2368            plug.delete_data(temp)
2369        total_plot_list = []
2370        data_list, _ = self._data_manager.get_by_id(data_id)
2371        _, temp_list_theory = self._data_manager.get_by_id(theory_id)
2372        total_plot_list = data_list.values()
2373        for item in temp_list_theory.values():
2374            theory_data, theory_state = item
2375            total_plot_list.append(theory_data)
2376        for new_plot in total_plot_list:
2377            id = new_plot.id
2378            for group_id in new_plot.list_group_id:
2379                wx.PostEvent(self, NewPlotEvent(id=id,
2380                                                   group_id=group_id,
2381                                                   action='remove'))
2382                #remove res plot: Todo: improve
2383                wx.CallAfter(self._remove_res_plot, id)
2384        self._data_manager.delete_data(data_id=data_id, 
2385                                       theory_id=theory_id)
2386       
2387    def _remove_res_plot(self, id):
2388        """
2389        Try to remove corresponding res plot
2390       
2391        : param id: id of the data
2392        """
2393        try:
2394            wx.PostEvent(self, NewPlotEvent(id=("res"+str(id)),
2395                                           group_id=("res"+str(id)),
2396                                           action='remove'))
2397        except:
2398            pass
2399   
2400    def save_data1d(self, data, fname):
2401        """
2402        Save data dialog
2403        """
2404        default_name = fname
2405        wildcard = "Text files (*.txt)|*.txt|"\
2406                    "CanSAS 1D files(*.xml)|*.xml" 
2407        path = None
2408        dlg = wx.FileDialog(self, "Choose a file",
2409                            self._default_save_location,
2410                            default_name, wildcard , wx.SAVE)
2411       
2412        if dlg.ShowModal() == wx.ID_OK:
2413            path = dlg.GetPath()
2414            # ext_num = 0 for .txt, ext_num = 1 for .xml
2415            # This is MAC Fix
2416            ext_num = dlg.GetFilterIndex()
2417            if ext_num == 0:
2418                format = '.txt'
2419            else:
2420                format = '.xml'
2421            path = os.path.splitext(path)[0] + format
2422            mypath = os.path.basename(path)
2423           
2424            #TODO: This is bad design. The DataLoader is designed
2425            #to recognize extensions.
2426            # It should be a simple matter of calling the .
2427            #save(file, data, '.xml') method
2428            # of the sans.dataloader.loader.Loader class.
2429            from sans.dataloader.loader import  Loader
2430            #Instantiate a loader
2431            loader = Loader() 
2432            format = ".txt"
2433            if os.path.splitext(mypath)[1].lower() == format:
2434                # Make sure the ext included in the file name
2435                # especially on MAC
2436                fName = os.path.splitext(path)[0] + format
2437                self._onsaveTXT(data, fName)
2438            format = ".xml"
2439            if os.path.splitext(mypath)[1].lower() == format:
2440                # Make sure the ext included in the file name
2441                # especially on MAC
2442                fName = os.path.splitext(path)[0] + format
2443                loader.save(fName, data, format)
2444            try:
2445                self._default_save_location = os.path.dirname(path)
2446            except:
2447                pass   
2448        dlg.Destroy()
2449       
2450       
2451    def _onsaveTXT(self, data, path):
2452        """
2453        Save file as txt 
2454        :TODO: Refactor and remove this method. See TODO in _onSave.
2455        """
2456        if not path == None:
2457            out = open(path, 'w')
2458            has_errors = True
2459            if data.dy == None or data.dy == []:
2460                has_errors = False
2461            # Sanity check
2462            if has_errors:
2463                try:
2464                    if len(data.y) != len(data.dy):
2465                        has_errors = False
2466                except:
2467                    has_errors = False
2468            if has_errors:
2469                if data.dx != None and data.dx != []:
2470                    out.write("<X>   <Y>   <dY>   <dX>\n")
2471                else:
2472                    out.write("<X>   <Y>   <dY>\n")
2473            else:
2474                out.write("<X>   <Y>\n")
2475               
2476            for i in range(len(data.x)):
2477                if has_errors:
2478                    if data.dx != None and data.dx != []:
2479                        if  data.dx[i] != None:
2480                            out.write("%g  %g  %g  %g\n" % (data.x[i], 
2481                                                        data.y[i],
2482                                                        data.dy[i],
2483                                                        data.dx[i]))
2484                        else:
2485                            out.write("%g  %g  %g\n" % (data.x[i], 
2486                                                        data.y[i],
2487                                                        data.dy[i]))
2488                    else:
2489                        out.write("%g  %g  %g\n" % (data.x[i], 
2490                                                    data.y[i],
2491                                                    data.dy[i]))
2492                else:
2493                    out.write("%g  %g\n" % (data.x[i], 
2494                                            data.y[i]))
2495            out.close() 
2496                             
2497    def show_data1d(self, data, name):
2498        """
2499        Show data dialog
2500        """   
2501        try:
2502            xmin = min(data.x)
2503            ymin = min(data.y)
2504        except:
2505            msg = "Unable to find min/max of \n data named %s"% \
2506                        data.filename 
2507            wx.PostEvent(self, StatusEvent(status=msg,
2508                                       info="error"))
2509            raise ValueError, msg
2510        text = data.__str__() 
2511        text += 'Data Min Max:\n'
2512        text += 'X_min = %s:  X_max = %s\n'% (xmin, max(data.x))
2513        text += 'Y_min = %s:  Y_max = %s\n'% (ymin, max(data.y))
2514        if data.dy != None:
2515            text += 'dY_min = %s:  dY_max = %s\n'% (min(data.dy), max(data.dy))
2516        text += '\nData Points:\n'
2517        x_st = "X"
2518        for index in range(len(data.x)):
2519            if data.dy != None:
2520                dy_val = data.dy[index]
2521            else:
2522                dy_val = 0.0
2523            if data.dx != None:
2524                dx_val = data.dx[index]
2525            else:
2526                dx_val = 0.0
2527            if data.dxl != None:
2528                if index == 0: 
2529                    x_st = "Xl"
2530                dx_val = data.dxl[index]
2531            elif data.dxw != None:
2532                if index == 0: 
2533                    x_st = "Xw"
2534                dx_val = data.dxw[index]
2535           
2536            if index == 0:
2537                text += "<index> \t<X> \t<Y> \t<dY> \t<d%s>\n"% x_st
2538            text += "%s \t%s \t%s \t%s \t%s\n" % (index,
2539                                            data.x[index], 
2540                                            data.y[index],
2541                                            dy_val,
2542                                            dx_val)
2543        from pdfview import TextFrame
2544        frame = TextFrame(None, -1, "Data Info: %s"% data.name, text) 
2545        # put icon
2546        self.put_icon(frame) 
2547        frame.Show(True) 
2548           
2549    def save_data2d(self, data, fname):   
2550        """
2551        Save data2d dialog
2552        """
2553        default_name = fname
2554        wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
2555        dlg = wx.FileDialog(self, "Choose a file",
2556                            self._default_save_location,
2557                            default_name, wildcard , wx.SAVE)
2558       
2559        if dlg.ShowModal() == wx.ID_OK:
2560            path = dlg.GetPath()
2561            # ext_num = 0 for .txt, ext_num = 1 for .xml
2562            # This is MAC Fix
2563            ext_num = dlg.GetFilterIndex()
2564            if ext_num == 0:
2565                format = '.dat'
2566            else:
2567                format = ''
2568            path = os.path.splitext(path)[0] + format
2569            mypath = os.path.basename(path)
2570           
2571            #TODO: This is bad design. The DataLoader is designed
2572            #to recognize extensions.
2573            # It should be a simple matter of calling the .
2574            #save(file, data, '.xml') method
2575            # of the DataLoader.loader.Loader class.
2576            from sans.dataloader.loader import  Loader
2577            #Instantiate a loader
2578            loader = Loader() 
2579
2580            format = ".dat"
2581            if os.path.splitext(mypath)[1].lower() == format:
2582                # Make sure the ext included in the file name
2583                # especially on MAC
2584                fileName = os.path.splitext(path)[0] + format
2585                loader.save(fileName, data, format)
2586            try:
2587                self._default_save_location = os.path.dirname(path)
2588            except:
2589                pass   
2590        dlg.Destroy() 
2591                             
2592    def show_data2d(self, data, name):
2593        """
2594        Show data dialog
2595        """   
2596
2597        wx.PostEvent(self, StatusEvent(status = "Gathering Data2D Info.", 
2598                                       type = 'start' ))
2599        text = data.__str__() 
2600        text += 'Data Min Max:\n'
2601        text += 'I_min = %s\n'% min(data.data)
2602        text += 'I_max = %s\n\n'% max(data.data)
2603        text += 'Data (First 2501) Points:\n'
2604        text += 'Data columns include err(I).\n'
2605        text += 'ASCII data starts here.\n'
2606        text += "<index> \t<Qx> \t<Qy> \t<I> \t<dI> \t<dQparal> \t<dQperp>\n"
2607        di_val = 0.0
2608        dx_val = 0.0
2609        dy_val = 0.0
2610        #mask_val = True
2611        len_data = len(data.qx_data)
2612        for index in xrange(0, len_data):
2613            x_val = data.qx_data[index]
2614            y_val = data.qy_data[index]
2615            i_val = data.data[index]
2616            if data.err_data != None: 
2617                di_val = data.err_data[index]
2618            if data.dqx_data != None: 
2619                dx_val = data.dqx_data[index]
2620            if data.dqy_data != None: 
2621                dy_val = data.dqy_data[index]
2622            #if data.mask != None: mask_val = data.mask[index]
2623 
2624            text += "%s \t%s \t%s \t%s \t%s \t%s \t%s\n" % (index,
2625                                            x_val, 
2626                                            y_val,
2627                                            i_val,
2628                                            di_val,
2629                                            dx_val,
2630                                            dy_val)
2631            # Takes too long time for typical data2d: Break here
2632            if index >= 2500:
2633                text += ".............\n"
2634                break
2635
2636        from pdfview import TextFrame
2637        frame = TextFrame(None, -1, "Data Info: %s"% data.name, text) 
2638        # put icon
2639        self.put_icon(frame)
2640        frame.Show(True) 
2641        wx.PostEvent(self, StatusEvent(status = "Data2D Info Displayed", 
2642                                       type = 'stop' ))
2643                                 
2644    def set_current_perspective(self, perspective):
2645        """
2646        set the current active perspective
2647        """
2648        self._current_perspective = perspective
2649        name = "No current analysis selected"
2650        if self._current_perspective is not None:
2651            self._add_current_plugin_menu()
2652            for panel in self.panels.values():
2653                if hasattr(panel, 'CENTER_PANE') and panel.CENTER_PANE:
2654                    for name in self._current_perspective.get_perspective():
2655                        frame = panel.get_frame()
2656                        if frame != None:
2657                            if name == panel.window_name:
2658                                panel.on_set_focus(event=None)
2659                                frame.Show(True)
2660                            else:
2661                                frame.Show(False)
2662                            #break               
2663            name = self._current_perspective.sub_menu
2664            if self._data_panel is not None:
2665                self._data_panel.set_active_perspective(name)
2666                self._check_applications_menu()
2667            #Set the SasView title
2668            self._set_title_name(name)
2669           
2670    def _set_title_name(self, name):
2671        """
2672        Set the SasView title w/ the current application name
2673       
2674        : param name: application name [string]
2675        """
2676        # Set SanView Window title w/ application anme
2677        title = self.title + "  - " + name + " -"
2678        self.SetTitle(title)
2679           
2680    def _check_applications_menu(self):
2681        """
2682        check the menu of the current application
2683        """
2684        if self._applications_menu is not None:
2685            for menu in self._applications_menu.GetMenuItems():
2686                if self._current_perspective is not None:
2687                    name = self._current_perspective.sub_menu
2688                    if menu.IsCheckable():
2689                        if menu.GetLabel() == name:
2690                            menu.Check(True)
2691                        else:
2692                            menu.Check(False) 
2693           
2694    def enable_add_data(self, new_plot):
2695        """
2696        Enable append data on a plot panel
2697        """
2698
2699        if self.panel_on_focus not in self._plotting_plugin.plot_panels.values():
2700            return
2701        is_theory = len(self.panel_on_focus.plots) <= 1 and \
2702            self.panel_on_focus.plots.values()[0].__class__.__name__ == "Theory1D"
2703           
2704        is_data2d = hasattr(new_plot, 'data')
2705       
2706        is_data1d = self.panel_on_focus.__class__.__name__ == "ModelPanel1D"\
2707            and self.panel_on_focus.group_id is not None
2708        has_meta_data = hasattr(new_plot, 'meta_data')
2709       
2710        #disable_add_data if the data is being recovered from  a saved state file.
2711        is_state_data = False
2712        if has_meta_data:
2713            if 'invstate' in new_plot.meta_data: 
2714                is_state_data = True
2715            if  'prstate' in new_plot.meta_data: 
2716                is_state_data = True
2717            if  'fitstate' in new_plot.meta_data: 
2718                is_state_data = True
2719   
2720        return is_data1d and not is_data2d and not is_theory and not is_state_data
2721   
2722    def check_multimode(self, perspective=None):
2723        """
2724        Check the perspective have batch mode capablitity
2725        """
2726        if perspective == None or self._data_panel == None:
2727            return
2728        flag = perspective.get_batch_capable()
2729        flag_on = perspective.batch_on
2730        if flag:
2731            self._data_panel.rb_single_mode.SetValue(not flag_on)
2732            self._data_panel.rb_batch_mode.SetValue(flag_on)
2733        else:
2734            self._data_panel.rb_single_mode.SetValue(True)
2735            self._data_panel.rb_batch_mode.SetValue(False)
2736        self._data_panel.rb_single_mode.Enable(flag)
2737        self._data_panel.rb_batch_mode.Enable(flag)
2738               
2739
2740   
2741    def enable_edit_menu(self):
2742        """
2743        enable menu item under edit menu depending on the panel on focus
2744        """
2745        if self.cpanel_on_focus is not None and self._edit_menu is not None:
2746            flag = self.cpanel_on_focus.get_undo_flag()
2747            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
2748            flag = self.cpanel_on_focus.get_redo_flag()
2749            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
2750            flag = self.cpanel_on_focus.get_copy_flag()
2751            self._edit_menu.Enable(GUIFRAME_ID.COPY_ID, flag)
2752            flag = self.cpanel_on_focus.get_paste_flag()
2753            self._edit_menu.Enable(GUIFRAME_ID.PASTE_ID, flag)
2754            #flag = self.cpanel_on_focus.get_print_flag()
2755            #self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
2756            flag = self.cpanel_on_focus.get_preview_flag()
2757            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
2758            flag = self.cpanel_on_focus.get_reset_flag()
2759            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
2760        else:
2761            flag = False
2762            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
2763            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
2764            self._edit_menu.Enable(GUIFRAME_ID.COPY_ID, flag)
2765            self._edit_menu.Enable(GUIFRAME_ID.PASTE_ID, flag)
2766            #self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
2767            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
2768            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
2769           
2770    def on_undo_panel(self, event=None):
2771        """
2772        undo previous action of the last panel on focus if possible
2773        """
2774        if self.cpanel_on_focus is not None:
2775            self.cpanel_on_focus.on_undo(event)
2776           
2777    def on_redo_panel(self, event=None):
2778        """
2779        redo the last cancel action done on the last panel on focus
2780        """
2781        if self.cpanel_on_focus is not None:
2782            self.cpanel_on_focus.on_redo(event)
2783           
2784    def on_copy_panel(self, event=None):
2785        """
2786        copy the last panel on focus if possible
2787        """
2788        if self.cpanel_on_focus is not None:
2789            self.cpanel_on_focus.on_copy(event)
2790           
2791    def on_paste_panel(self, event=None):
2792        """
2793        paste clipboard to the last panel on focus
2794        """
2795        if self.cpanel_on_focus is not None:
2796            self.cpanel_on_focus.on_paste(event)
2797                   
2798    def on_bookmark_panel(self, event=None):
2799        """
2800        bookmark panel
2801        """
2802        if self.cpanel_on_focus is not None:
2803            self.cpanel_on_focus.on_bookmark(event)
2804           
2805    def append_bookmark(self, event=None):
2806        """
2807        Bookmark available information of the panel on focus
2808        """
2809        self._toolbar.append_bookmark(event)
2810           
2811    def on_save_panel(self, event=None):
2812        """
2813        save possible information on the current panel
2814        """
2815        if self.cpanel_on_focus is not None:
2816            self.cpanel_on_focus.on_save(event)
2817           
2818    def on_preview_panel(self, event=None):
2819        """
2820        preview information on the panel on focus
2821        """
2822        if self.cpanel_on_focus is not None:
2823            self.cpanel_on_focus.on_preview(event)
2824           
2825    def on_print_panel(self, event=None):
2826        """
2827        print available information on the last panel on focus
2828        """
2829        if self.cpanel_on_focus is not None:
2830            self.cpanel_on_focus.on_print(event)
2831           
2832    def on_zoom_panel(self, event=None):
2833        """
2834        zoom on the current panel if possible
2835        """
2836        if self.cpanel_on_focus is not None:
2837            self.cpanel_on_focus.on_zoom(event)
2838           
2839    def on_zoom_in_panel(self, event=None):
2840        """
2841        zoom in of the panel on focus
2842        """
2843        if self.cpanel_on_focus is not None:
2844            self.cpanel_on_focus.on_zoom_in(event)
2845           
2846    def on_zoom_out_panel(self, event=None):
2847        """
2848        zoom out on the panel on focus
2849        """
2850        if self.cpanel_on_focus is not None:
2851            self.cpanel_on_focus.on_zoom_out(event)
2852           
2853    def on_drag_panel(self, event=None):
2854        """
2855        drag apply to the panel on focus
2856        """
2857        if self.cpanel_on_focus is not None:
2858            self.cpanel_on_focus.on_drag(event)
2859           
2860    def on_reset_panel(self, event=None):
2861        """
2862        reset the current panel
2863        """
2864        if self.cpanel_on_focus is not None:
2865            self.cpanel_on_focus.on_reset(event)
2866           
2867    def on_change_caption(self, name, old_caption, new_caption):     
2868        """
2869        Change the panel caption
2870       
2871        :param name: window_name of the pane
2872        :param old_caption: current caption [string]
2873        :param new_caption: new caption [string]
2874        """
2875        # wx.aui.AuiPaneInfo
2876        pane_info = self.get_paneinfo(name) 
2877        # update the data_panel.cb_plotpanel
2878        if 'data_panel' in self.panels.keys():
2879            # remove from data_panel combobox
2880            data_panel = self.panels["data_panel"]
2881            if data_panel.cb_plotpanel is not None:
2882                # Check if any panel has the same caption
2883                has_newstring = data_panel.cb_plotpanel.FindString\
2884                                                            (str(new_caption)) 
2885                caption = new_caption
2886                if has_newstring != wx.NOT_FOUND:
2887                    captions = self._get_plotpanel_captions()
2888                    # Append nummber
2889                    inc = 1
2890                    while (1):
2891                        caption = new_caption + '_%s'% str(inc)
2892                        if caption not in captions:
2893                            break
2894                        inc += 1
2895                    # notify to users
2896                    msg = "Found Same Title: Added '_%s'"% str(inc)
2897                    wx.PostEvent(self, StatusEvent(status=msg))
2898                # update data_panel cb
2899                pos = data_panel.cb_plotpanel.FindString(str(old_caption)) 
2900                if pos != wx.NOT_FOUND:
2901                    data_panel.cb_plotpanel.SetString(pos, caption)
2902                    data_panel.cb_plotpanel.SetStringSelection(caption)
2903        # update window Show menu
2904        if self._window_menu != None:
2905            for item in self._window_menu.GetMenuItems():
2906                pos = self._window_menu.FindItem(old_caption)
2907                if self._window_menu.GetLabel(pos) == str(old_caption):
2908                    self._window_menu.SetLabel(pos, caption)
2909                break
2910        # New Caption
2911        pane_info.Caption(caption)
2912        # update aui manager
2913        self._mgr.Update()
2914        return caption
2915       
2916    def get_paneinfo(self, name):
2917        """
2918        Get pane Caption from window_name
2919       
2920        :param name: window_name in AuiPaneInfo
2921        : return: AuiPaneInfo of the name
2922        """
2923        return None#self._mgr.GetPane(name)
2924   
2925    def enable_undo(self):
2926        """
2927        enable undo related control
2928        """
2929        if self.cpanel_on_focus is not None:
2930            self._toolbar.enable_undo(self.cpanel_on_focus)
2931           
2932    def enable_redo(self):
2933        """
2934        enable redo
2935        """
2936        if self.cpanel_on_focus is not None:
2937            self._toolbar.enable_redo(self.cpanel_on_focus)
2938           
2939    def enable_copy(self):
2940        """
2941        enable copy related control
2942        """
2943        if self.cpanel_on_focus is not None:
2944            self._toolbar.enable_copy(self.cpanel_on_focus)
2945           
2946    def enable_paste(self):
2947        """
2948        enable paste
2949        """
2950        if self.cpanel_on_focus is not None:
2951            self._toolbar.enable_paste(self.cpanel_on_focus)
2952                       
2953    def enable_bookmark(self):
2954        """
2955        Bookmark
2956        """
2957        if self.cpanel_on_focus is not None:
2958            self._toolbar.enable_bookmark(self.cpanel_on_focus)
2959           
2960    def enable_save(self):
2961        """
2962        save
2963        """
2964        if self.cpanel_on_focus is not None:
2965            self._toolbar.enable_save(self.cpanel_on_focus)
2966           
2967    def enable_preview(self):
2968        """
2969        preview
2970        """
2971        if self.cpanel_on_focus is not None:
2972            self._toolbar.enable_preview(self.cpanel_on_focus)
2973           
2974    def enable_print(self):
2975        """
2976        print
2977        """
2978        if self.cpanel_on_focus is not None:
2979            self._toolbar.enable_print(self.cpanel_on_focus)
2980           
2981    def enable_zoom(self):
2982        """
2983        zoom
2984        """
2985        if self.cpanel_on_focus is not None:
2986            self._toolbar.enable_zoom(self.panel_on_focus)
2987           
2988    def enable_zoom_in(self):
2989        """
2990        zoom in
2991        """
2992        if self.cpanel_on_focus is not None:
2993            self._toolbar.enable_zoom_in(self.panel_on_focus)
2994           
2995    def enable_zoom_out(self):
2996        """
2997        zoom out
2998        """
2999        if self.cpanel_on_focus is not None:
3000            self._toolbar.enable_zoom_out(self.panel_on_focus)
3001           
3002    def enable_drag(self, event=None):
3003        """
3004        drag
3005        """
3006        #if self.cpanel_on_focus is not None:
3007        #    self._toolbar.enable_drag(self.panel_on_focus)
3008           
3009    def enable_reset(self):
3010        """
3011        reset the current panel
3012        """
3013        if self.cpanel_on_focus is not None:
3014            self._toolbar.enable_reset(self.panel_on_focus)
3015           
3016    def get_toolbar_height(self):
3017        """
3018        """
3019        size_y = 0
3020        if self.GetToolBar() != None and self.GetToolBar().IsShown():
3021            _, size_y = self.GetToolBar().GetSizeTuple()
3022        return size_y
3023   
3024    def set_schedule_full_draw(self, panel=None, func='del'):
3025        """
3026        Add/subtract the schedule full draw list with the panel given
3027       
3028        :param panel: plot panel
3029        :param func: append or del [string]
3030        """
3031
3032        # append this panel in the schedule list if not in yet
3033        if func == 'append':
3034            if not panel in self.schedule_full_draw_list:
3035                self.schedule_full_draw_list.append(panel) 
3036        # remove this panel from schedule list
3037        elif func == 'del':
3038            if len(self.schedule_full_draw_list) > 0:
3039                if panel in self.schedule_full_draw_list:
3040                    self.schedule_full_draw_list.remove(panel)
3041
3042        # reset the schdule
3043        if len(self.schedule_full_draw_list) == 0:
3044            self.schedule = False
3045        else:
3046            self.schedule = True   
3047       
3048    def full_draw(self):
3049        """
3050        Draw the panels with axes in the schedule to full dwar list
3051        """
3052       
3053        count = len(self.schedule_full_draw_list)
3054        #if not self.schedule:
3055        if count < 1:
3056            self.set_schedule(False)
3057            return
3058
3059        else:
3060            ind = 0
3061            # if any of the panel is shown do full_draw
3062            for panel in self.schedule_full_draw_list:
3063                ind += 1
3064                if panel.frame.IsShown():
3065                    break
3066                # otherwise, return
3067                if ind == count:
3068                    return
3069        #Simple redraw only for a panel shown
3070        def f_draw(panel):
3071            """
3072            Draw A panel in the full dwar list
3073            """
3074            try:
3075                # This checking of GetCapture is to stop redrawing
3076                # while any panel is capture.
3077                frame = panel.frame
3078               
3079                if not frame.GetCapture():
3080                    # draw if possible
3081                    panel.set_resizing(False)
3082                    #panel.Show(True)
3083                    panel.draw_plot()
3084                # Check if the panel is not shown
3085                flag = frame.IsShown()
3086                frame.Show(flag)
3087                   
3088            except:
3089                raise
3090     
3091        # Draw all panels       
3092        #map(f_draw, self.schedule_full_draw_list)
3093        f_draw(self.schedule_full_draw_list[0])
3094        # Reset the attr 
3095        if len(self.schedule_full_draw_list) == 0:
3096            self.set_schedule(False)
3097        else:
3098            self.set_schedule(True)
3099       
3100    def set_schedule(self, schedule=False): 
3101        """
3102        Set schedule
3103        """
3104        self.schedule = schedule
3105               
3106    def get_schedule(self): 
3107        """
3108        Get schedule
3109        """
3110        return self.schedule
3111   
3112    def on_set_plot_focus(self, panel):
3113        """
3114        Set focus on a plot panel
3115        """
3116        if panel == None:
3117            return
3118        self.set_plot_unfocus()
3119        panel.on_set_focus(None) 
3120        # set focusing panel
3121        self.panel_on_focus = panel 
3122        self.set_panel_on_focus(None)
3123
3124    def set_plot_unfocus(self): 
3125        """
3126        Un focus all plot panels
3127        """
3128        for plot in self.plot_panels.values():
3129            plot.on_kill_focus(None)
3130   
3131    def get_window_size(self):
3132        """
3133        Get window size
3134       
3135        :return size: tuple
3136        """
3137        width, height = self.GetSizeTuple()
3138        if not IS_WIN:
3139            # Subtract toolbar height to get real window side
3140            if self._toolbar.IsShown():
3141                height -= 45
3142        return (width, height)
3143           
3144    def _onDrawIdle(self, *args, **kwargs):
3145        """
3146        ReDraw with axes
3147        """
3148        try:
3149            # check if it is time to redraw
3150            if self.GetCapture() == None:
3151                # Draw plot, changes resizing too
3152                self.full_draw()
3153        except:
3154            pass
3155           
3156        # restart idle       
3157        self._redraw_idle(*args, **kwargs)
3158
3159           
3160    def _redraw_idle(self, *args, **kwargs):
3161        """
3162        Restart Idle
3163        """
3164        # restart idle   
3165        self.idletimer.Restart(100*TIME_FACTOR, *args, **kwargs)
3166
3167       
3168class DefaultPanel(wx.Panel, PanelBase):
3169    """
3170    Defines the API for a panels to work with
3171    the GUI manager
3172    """
3173    ## Internal nickname for the window, used by the AUI manager
3174    window_name = "default"
3175    ## Name to appear on the window title bar
3176    window_caption = "Welcome panel"
3177    ## Flag to tell the AUI manager to put this panel in the center pane
3178    CENTER_PANE = True
3179    def __init__(self, parent, *args, **kwds):
3180        wx.Panel.__init__(self, parent, *args, **kwds)
3181        PanelBase.__init__(self, parent)
3182   
3183
3184
3185class ViewApp(wx.App):
3186    """
3187    Toy application to test this Frame
3188    """
3189    def OnInit(self):
3190        """
3191        When initialised
3192        """
3193        pos, size, self.is_max = self.window_placement((GUIFRAME_WIDTH, 
3194                                           GUIFRAME_HEIGHT))     
3195        self.frame = ViewerFrame(parent=None, 
3196                             title=APPLICATION_NAME, 
3197                             pos=pos, 
3198                             gui_style = DEFAULT_STYLE,
3199                             size=size)
3200        self.frame.Hide()
3201        if not IS_WIN:
3202            self.frame.EnableCloseButton(False)
3203        self.s_screen = None
3204
3205        try:
3206            self.open_file()
3207        except:
3208            msg = "%s Could not load " % str(APPLICATION_NAME)
3209            msg += "input file from command line.\n"
3210            logging.error(msg)
3211        # Display a splash screen on top of the frame.
3212        try:
3213            if os.path.isfile(SPLASH_SCREEN_PATH):
3214                self.s_screen = self.display_splash_screen(parent=self.frame, 
3215                                        path=SPLASH_SCREEN_PATH)
3216            else:
3217                self.frame.Show()   
3218        except:
3219            if self.s_screen is not None:
3220                self.s_screen.Close()
3221            msg = "Cannot display splash screen\n"
3222            msg += str (sys.exc_value)
3223            logging.error(msg)
3224            self.frame.Show()
3225 
3226        #if hasattr(self.frame, 'special'):
3227        #    self.frame.special.SetCurrent()
3228        self.SetTopWindow(self.frame)
3229 
3230        return True
3231   
3232    def maximize_win(self):
3233        """
3234        Maximize the window after the frame shown
3235        """
3236        if self.is_max:
3237            if self.frame.IsShown():
3238                # Max window size
3239                self.frame.Maximize(self.is_max)
3240
3241    def open_file(self):
3242        """
3243        open a state file at the start of the application
3244        """
3245        input_file = None
3246        if len(sys.argv) >= 2:
3247            cmd = sys.argv[0].lower()
3248            basename  = os.path.basename(cmd)
3249            app_base = str(APPLICATION_NAME).lower()
3250            if os.path.isfile(cmd) or basename.lower() == app_base:
3251                app_py = app_base + '.py'
3252                app_exe = app_base + '.exe'
3253                app_app = app_base + '.app'
3254                if basename.lower() in [app_py, app_exe, app_app, app_base]:
3255                    data_base = sys.argv[1]
3256                    input_file = os.path.normpath(os.path.join(DATAPATH, 
3257                                                               data_base))
3258        if input_file is None:
3259            return
3260        if self.frame is not None:
3261            self.frame.set_input_file(input_file=input_file)
3262         
3263    def clean_plugin_models(self, path): 
3264        """
3265        Delete plugin models  in app folder
3266       
3267        :param path: path of the plugin_models folder in app
3268        """
3269        # do it only the first time app loaded
3270        # delete unused model folder   
3271        model_folder = os.path.join(PATH_APP, path)
3272        if os.path.exists(model_folder) and os.path.isdir(model_folder):
3273            if len(os.listdir(model_folder)) > 0:
3274                try:
3275                    for file in os.listdir(model_folder):
3276                        file_path = os.path.join(model_folder, file)
3277                        if os.path.isfile(file_path):
3278                            os.remove(file_path)
3279                except:
3280                    logging.error("gui_manager.clean_plugin_models:\n  %s" \
3281                                  % sys.exc_value)
3282             
3283    def set_manager(self, manager):
3284        """
3285        Sets a reference to the application manager
3286        of the GUI manager (Frame)
3287        """
3288        self.frame.set_manager(manager)
3289       
3290    def build_gui(self):
3291        """
3292        Build the GUI
3293        """
3294        #try to load file at the start
3295        try:
3296            self.open_file()
3297        except:
3298            raise
3299        self.frame.build_gui()
3300        #if self.s_screen is not None and self.s_screen.IsShown():
3301        #    self.s_screen.Close()
3302       
3303    def set_welcome_panel(self, panel_class):
3304        """
3305        Set the welcome panel
3306       
3307        :param panel_class: class of the welcome panel to be instantiated
3308       
3309        """
3310        self.frame.set_welcome_panel(panel_class)
3311       
3312    def add_perspective(self, perspective):
3313        """
3314        Manually add a perspective to the application GUI
3315        """
3316        self.frame.add_perspective(perspective)
3317   
3318    def window_placement(self, size):
3319        """
3320        Determines the position and size of the application frame such that it
3321        fits on the user's screen without obstructing (or being obstructed by)
3322        the Windows task bar.  The maximum initial size in pixels is bounded by
3323        WIDTH x HEIGHT.  For most monitors, the application
3324        will be centered on the screen; for very large monitors it will be
3325        placed on the left side of the screen.
3326        """
3327        is_maximized = False
3328        # Get size of screen without
3329        for screenCount in range(wx.Display().GetCount()):
3330            screen = wx.Display(screenCount)
3331            if screen.IsPrimary():
3332                displayRect = screen.GetClientArea()
3333                break
3334       
3335        posX, posY, displayWidth, displayHeight = displayRect       
3336        customWidth, customHeight = size
3337       
3338        # If the custom size is default, set 90% of the screen size
3339        if customWidth <= 0 and customHeight <= 0:
3340            if customWidth == 0 and customHeight == 0:
3341                is_maximized = True
3342            customWidth = displayWidth * 0.9
3343            customHeight = displayHeight * 0.9
3344        else:
3345            # If the custom screen is bigger than the
3346            # window screen than make maximum size
3347            if customWidth > displayWidth:
3348                customWidth = displayWidth
3349            if customHeight > displayHeight:
3350                customHeight = displayHeight
3351           
3352        # Note that when running Linux and using an Xming (X11) server on a PC
3353        # with a dual  monitor configuration, the reported display size may be
3354        # that of both monitors combined with an incorrect display count of 1.
3355        # To avoid displaying this app across both monitors, we check for
3356        # screen 'too big'.  If so, we assume a smaller width which means the
3357        # application will be placed towards the left hand side of the screen.
3358       
3359        # If dual screen registered as 1 screen. Make width half.
3360        # MAC just follows the default behavior of pos
3361        if IS_WIN:
3362            if displayWidth > (displayHeight*2):
3363                if (customWidth == displayWidth):
3364                    customWidth = displayWidth/2
3365                # and set the position to be the corner of the screen.
3366                posX = 0
3367                posY = 0
3368               
3369            # Make the position the middle of the screen. (Not 0,0)
3370            else:
3371                posX = (displayWidth - customWidth)/2
3372                posY = (displayHeight - customHeight)/2
3373        # Return the suggested position and size for the application frame.   
3374        return (posX, posY), (customWidth, customHeight), is_maximized
3375
3376   
3377    def display_splash_screen(self, parent, 
3378                              path=SPLASH_SCREEN_PATH):
3379        """Displays the splash screen.  It will exactly cover the main frame."""
3380       
3381        # Prepare the picture.  On a 2GHz intel cpu, this takes about a second.
3382        image = wx.Image(path, wx.BITMAP_TYPE_PNG)
3383        image.Rescale(SPLASH_SCREEN_WIDTH, 
3384                      SPLASH_SCREEN_HEIGHT, wx.IMAGE_QUALITY_HIGH)
3385        bm = image.ConvertToBitmap()
3386
3387        # Create and show the splash screen.  It will disappear only when the
3388        # program has entered the event loop AND either the timeout has expired
3389        # or the user has left clicked on the screen.  Thus any processing
3390        # performed in this routine (including sleeping) or processing in the
3391        # calling routine (including doing imports) will prevent the splash
3392        # screen from disappearing.
3393        #
3394        # Note that on Linux, the timeout appears to occur immediately in which
3395        # case the splash screen disappears upon entering the event loop.
3396        s_screen = wx.SplashScreen(bitmap=bm,
3397                         splashStyle=(wx.SPLASH_TIMEOUT|
3398                                              wx.SPLASH_CENTRE_ON_SCREEN),
3399                                 style=(wx.SIMPLE_BORDER|
3400                                        wx.FRAME_NO_TASKBAR|
3401                                        wx.FRAME_FLOAT_ON_PARENT),
3402                                       
3403                        milliseconds=SS_MAX_DISPLAY_TIME,
3404                        parent=parent,
3405                        id=wx.ID_ANY)
3406        from sans.guiframe.gui_statusbar import SPageStatusbar
3407        statusBar = SPageStatusbar(s_screen)
3408        s_screen.SetStatusBar(statusBar)
3409        s_screen.Bind(wx.EVT_CLOSE, self.on_close_splash_screen)
3410        s_screen.Show()
3411        return s_screen
3412       
3413       
3414    def on_close_splash_screen(self, event):
3415        """
3416        When the splash screen is closed.
3417        """
3418        self.frame.Show(True)
3419        event.Skip()
3420        self.maximize_win()
3421
3422
3423class MDIFrame(wx.MDIChildFrame):
3424    """
3425    Frame for panels
3426    """
3427    def __init__(self, parent, panel, title="Untitled",
3428                size=(300,200), *args, **kwds):
3429        """
3430        comment
3431        :param parent: parent panel/container
3432        """
3433        kwds['size']= size
3434        kwds['title']= title
3435        # Initialize the Frame object
3436        wx.MDIChildFrame.__init__(self, parent, *args, **kwds)
3437        self.parent = parent
3438        self.name = "Untitled"
3439        self.batch_on = self.parent.batch_on
3440        self.panel = panel
3441        if panel != None:
3442            self.set_panel(panel)
3443        self.Show(False)
3444   
3445    def show_data_panel(self, action):
3446        """
3447        """
3448        self.parent.show_data_panel(action)
3449       
3450    def set_panel(self, panel):
3451        """
3452        """
3453        self.panel = panel
3454        self.name = panel.window_name
3455        self.SetTitle(panel.window_caption)
3456        self.SetHelpText(panel.help_string)
3457        width, height = self.parent._get_panels_size(panel)
3458        if hasattr(panel, "CENTER_PANE") and panel.CENTER_PANE:
3459            width *= 0.6 
3460        self.SetSize((width, height))
3461        self.parent.put_icon(self)
3462        self.Bind(wx.EVT_SET_FOCUS, self.set_panel_focus)
3463        self.Bind(wx.EVT_CLOSE, self.OnClose)
3464        self.Show(False)
3465   
3466    def set_panel_focus(self, event):
3467        """
3468        """
3469        self.panel.SetFocus()
3470        self.parent.panel_on_focus = self.panel
3471        #self.parent.set_panel_on_focus_helper()
3472       
3473    def OnClose(self, event):
3474        """
3475        On Close event
3476        """
3477        self.panel.on_close(event)
3478       
3479if __name__ == "__main__": 
3480    app = ViewApp(0)
3481    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.