source: sasview/src/sas/guiframe/gui_manager.py @ f620870

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 f620870 was b9a5f0e, checked in by krzywon, 10 years ago

90% complete with the conversion.

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