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

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

more cleanups

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