source: sasview/src/sas/sasgui/guiframe/gui_manager.py @ 3fac0df

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.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 3fac0df was 3fac0df, checked in by ajj, 8 years ago

Changing wxID for about menu so it appears under Help. It seems that with the current menu construction and wx3.0 the special menu IDs don't work.

Closes #705

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