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

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 f53cd30 was f53cd30, checked in by krzywon, 9 years ago

Created and implemented an acknowledgement window that can be accessed
under the Help menu.

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