source: sasview/src/sans/guiframe/gui_manager.py @ da6c9847

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 da6c9847 was 4d7e5d5, checked in by Mathieu Doucet <doucetm@…>, 11 years ago

refactor silly if statements

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