source: sasview/src/sans/guiframe/gui_manager.py @ 49d019c

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 49d019c was 49d019c, checked in by Mathieu Doucet <doucetm@…>, 10 years ago

Shorten the splash screen timeout. Fix data panel position on OSX.

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