source: sasview/sansguiframe/src/sans/guiframe/gui_manager.py @ 386b313

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 386b313 was f84e4c0, checked in by Jae Cho <jhjcho@…>, 12 years ago

main window scrolling fix:WIN

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