source: sasview/src/sans/guiframe/gui_manager.py @ 51af54b

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 51af54b was 51af54b, checked in by Jeff Krzywon <jeffery.krzywon@…>, 10 years ago

Fixing project save/load and changed up an poorly worded error message.

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