source: sasview/src/sans/guiframe/gui_manager.py @ 34dbaf4

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 34dbaf4 was 34dbaf4, checked in by ajj, 10 years ago

Added options to copy parameters from a single fit panel as tab delimited for pasting into Excel, Igor etc and as a latex table.

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