source: sasview/src/sans/guiframe/gui_manager.py @ f7bead2

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

Re #212 Fix default-view dialog.

  • Property mode set to 100644
File size: 130.0 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)
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        if wx.VERSION_STRING >= '3.0.0.0':
981            mac_pos_y = 85
982        else:
983            mac_pos_y = 40
984        for item in self.plugins:
985            if hasattr(item, "get_panels"):
986                ps = item.get_panels(self)
987                panels.extend(ps)
988       
989        # Show a default panel with some help information
990        # It also sets the size of the application windows
991        #TODO: Use this for splash screen
992        #if self.defaultPanel is None:
993        #    self.defaultPanel = DefaultPanel(self, -1, style=wx.RAISED_BORDER)
994        # add a blank default panel always present
995        self.panels["default"] = self.defaultPanel
996        w, h = self._get_panels_size(self.defaultPanel)
997        frame = self.defaultPanel.get_frame()
998        frame.SetSize((self._window_width, self._window_height))
999        size_t_bar = 70
1000        if not IS_WIN:
1001            x_pos, _ = frame.GetPositionTuple()
1002            if IS_LINUX:
1003                size_t_bar = 115
1004            frame.SetPosition((x_pos, mac_pos_y + size_t_bar))
1005        frame.Show(True)
1006        #add data panel
1007        win = MDIFrame(self, None, 'None', (100, 200))
1008        data_panel = DataPanel(parent=win,  id=-1)
1009        win.set_panel(data_panel)
1010        self.panels["data_panel"] = data_panel
1011        self._data_panel = data_panel
1012        w, h = self._get_panels_size(self._data_panel)
1013        win.SetSize((w, h))
1014        style = self.__gui_style & GUIFRAME.MANAGER_ON
1015        if style != GUIFRAME.MANAGER_ON:
1016            flag = False
1017        else:
1018            flag = True
1019        if not IS_WIN:
1020            x_pos, _ = win.GetPositionTuple()
1021            win.SetPosition((x_pos, mac_pos_y + size_t_bar))
1022        win.Show(flag)
1023        d_panel_width = w
1024        # Add the panels to the AUI manager
1025        for panel_class in panels:
1026            frame = panel_class.get_frame()
1027            id = wx.NewId()
1028            # Check whether we need to put this panel
1029            # in the center pane
1030           
1031            if hasattr(panel_class, "CENTER_PANE") and panel_class.CENTER_PANE:
1032                w, h = self._get_panels_size(panel_class)
1033                if panel_class.CENTER_PANE:
1034                    self.panels[str(id)] = panel_class
1035                    _, pos_y = frame.GetPositionTuple()
1036                    frame.SetPosition((d_panel_width + 1, pos_y))
1037                    frame.SetSize((w, h))
1038                    frame.Show(False)
1039            elif panel_class == self._data_panel:
1040                panel_class.frame.Show(flag)
1041                continue
1042            else:
1043                self.panels[str(id)] = panel_class
1044                frame.SetSize((w, h))
1045                frame.Show(False)
1046            if not IS_WIN:
1047                x_pos, _ = frame.GetPositionTuple()
1048                frame.SetPosition((x_pos, mac_pos_y + size_t_bar))
1049
1050        if not IS_WIN:
1051            win_height = mac_pos_y
1052            if IS_LINUX:
1053                if wx.VERSION_STRING >= '3.0.0.0':
1054                    win_height = mac_pos_y + 10
1055                else:
1056                    win_height = mac_pos_y + 55
1057                self.SetMaxSize((-1, win_height))
1058            else:
1059                self.SetSize((self._window_width, win_height))
1060       
1061    def update_data(self, prev_data, new_data):
1062        """
1063        Update the data.
1064        """
1065        prev_id, data_state = self._data_manager.update_data(
1066                              prev_data=prev_data, new_data=new_data)
1067       
1068        self._data_panel.remove_by_id(prev_id)
1069        self._data_panel.load_data_list(data_state)
1070       
1071    def update_theory(self, data_id, theory, state=None):
1072        """
1073        Update the theory
1074        """ 
1075        data_state = self._data_manager.update_theory(data_id=data_id, 
1076                                         theory=theory,
1077                                         state=state) 
1078        wx.CallAfter(self._data_panel.load_data_list, data_state)
1079       
1080    def onfreeze(self, theory_id):
1081        """
1082        """
1083        data_state_list = self._data_manager.freeze(theory_id)
1084        self._data_panel.load_data_list(list=data_state_list)
1085        for data_state in data_state_list.values():
1086            new_plot = data_state.get_data()
1087           
1088            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
1089                                             title=new_plot.title))
1090       
1091    def freeze(self, data_id, theory_id):
1092        """
1093        """
1094        data_state_list = self._data_manager.freeze_theory(data_id=data_id, 
1095                                                theory_id=theory_id)
1096        self._data_panel.load_data_list(list=data_state_list)
1097        for data_state in data_state_list.values():
1098            new_plot = data_state.get_data()
1099            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
1100                                             title=new_plot.title))
1101       
1102    def delete_data(self, data):
1103        """
1104        Delete the data.
1105        """
1106        self._current_perspective.delete_data(data)
1107       
1108   
1109    def get_context_menu(self, plotpanel=None):
1110        """
1111        Get the context menu items made available
1112        by the different plug-ins.
1113        This function is used by the plotting module
1114        """
1115        if plotpanel is None:
1116            return
1117        menu_list = []
1118        for item in self.plugins:
1119            menu_list.extend(item.get_context_menu(plotpanel=plotpanel))
1120        return menu_list
1121       
1122    def get_current_context_menu(self, plotpanel=None):
1123        """
1124        Get the context menu items made available
1125        by the current plug-in.
1126        This function is used by the plotting module
1127        """
1128        if plotpanel is None:
1129            return
1130        menu_list = []
1131        item = self._current_perspective
1132        if item != None:
1133            menu_list.extend(item.get_context_menu(plotpanel=plotpanel))
1134        return menu_list
1135           
1136    def on_panel_close(self, event):
1137        """
1138        Gets called when the close event for a panel runs.
1139        This will check which panel has been closed and
1140        delete it.
1141        """
1142        frame = event.GetEventObject()
1143        for ID in self.plot_panels.keys():
1144            if self.plot_panels[ID].window_name == frame.name:
1145                self.disable_app_menu(self.plot_panels[ID])
1146                self.delete_panel(ID)
1147                break
1148        self.cpanel_on_focus.SetFocus()
1149   
1150   
1151    def popup_panel(self, p):
1152        """
1153        Add a panel object to the AUI manager
1154       
1155        :param p: panel object to add to the AUI manager
1156       
1157        :return: ID of the event associated with the new panel [int]
1158       
1159        """
1160        ID = wx.NewId()
1161        self.panels[str(ID)] = p
1162        ## Check and set the size
1163        if PLOPANEL_WIDTH < 0:
1164            p_panel_width = int(self._window_width * 0.45)
1165        else:
1166            p_panel_width = PLOPANEL_WIDTH
1167        p_panel_height = int(p_panel_width * 0.76)
1168        p.frame.SetSize((p_panel_width, p_panel_height))
1169        self.graph_num += 1
1170        if p.window_caption.split()[0] in NOT_SO_GRAPH_LIST:
1171            windowcaption = p.window_caption
1172        else:
1173            windowcaption = 'Graph'
1174        windowname = p.window_name
1175
1176        # Append nummber
1177        captions = self._get_plotpanel_captions()
1178        while (1):
1179            caption = windowcaption + '%s'% str(self.graph_num)
1180            if caption not in captions:
1181                break
1182            self.graph_num += 1
1183            # protection from forever-loop: max num = 1000
1184            if self.graph_num > 1000:
1185                break
1186        if p.window_caption.split()[0] not in NOT_SO_GRAPH_LIST:
1187            p.window_caption = caption
1188        p.window_name = windowname + str(self.graph_num)
1189       
1190        p.frame.SetTitle(p.window_caption)
1191        p.frame.name = p.window_name
1192        if not IS_WIN:
1193            p.frame.Center()
1194            x_pos, _ = p.frame.GetPositionTuple()
1195            p.frame.SetPosition((x_pos, 112))
1196        p.frame.Show(True)
1197
1198        # Register for showing/hiding the panel
1199        wx.EVT_MENU(self, ID, self.on_view)
1200        if p not in self.plot_panels.values() and p.group_id != None:
1201            self.plot_panels[ID] = p
1202            if len(self.plot_panels) == 1:
1203                self.panel_on_focus = p
1204                self.set_panel_on_focus(None)
1205            if self._data_panel is not None and \
1206                self._plotting_plugin is not None:
1207                ind = self._data_panel.cb_plotpanel.FindString('None')
1208                if ind != wx.NOT_FOUND:
1209                    self._data_panel.cb_plotpanel.Delete(ind)
1210                if caption not in self._data_panel.cb_plotpanel.GetItems():
1211                    self._data_panel.cb_plotpanel.Append(str(caption), p)
1212        return ID
1213   
1214    def _get_plotpanel_captions(self):
1215        """
1216        Get all the plotpanel cations
1217       
1218        : return: list of captions
1219        """
1220        captions = []
1221        for Id in self.plot_panels.keys():
1222            captions.append(self.plot_panels[Id].window_caption)
1223       
1224        return captions
1225         
1226    def _setup_menus(self):
1227        """
1228        Set up the application menus
1229        """
1230        # Menu
1231        self._menubar = wx.MenuBar()
1232        self._add_menu_file()
1233        self._add_menu_edit()
1234        self._add_menu_view()
1235        #self._add_menu_data()
1236        self._add_menu_application()
1237        self._add_menu_tool()
1238        self._add_current_plugin_menu()
1239        #self._add_menu_window()
1240        self._add_help_menu()
1241        self.SetMenuBar(self._menubar)
1242       
1243    def _setup_tool_bar(self):
1244        """
1245        add toolbar to the frame
1246        """
1247        self._toolbar = GUIToolBar(self)
1248        # The legacy code doesn't work well for wx 3.0
1249        # but the old code produces better results with wx 2.8
1250        if wx.VERSION_STRING >= '3.0.0.0':
1251            sizer = wx.BoxSizer(wx.VERTICAL)
1252            sizer.Add(self._toolbar, 0, wx.EXPAND)
1253            self.SetSizer(sizer)
1254        else:
1255            self.SetToolBar(self._toolbar)
1256        self._update_toolbar_helper()
1257        self._on_toggle_toolbar(event=None)
1258   
1259    def _update_toolbar_helper(self):
1260        """
1261        Helping to update the toolbar
1262        """
1263        application_name = 'No Selected Analysis'
1264        panel_name = 'No Panel on Focus'
1265        c_panel = self.cpanel_on_focus       
1266        if self._toolbar is  None:
1267            return
1268        if c_panel is not None:
1269            self.reset_bookmark_menu(self.cpanel_on_focus)
1270        if self._current_perspective is not None:
1271            application_name = self._current_perspective.sub_menu
1272        c_panel_state = c_panel
1273        if c_panel is not None:
1274            panel_name = c_panel.window_caption
1275            if not c_panel.IsShownOnScreen():
1276                c_panel_state = None
1277        self._toolbar.update_toolbar(c_panel_state)
1278        self._toolbar.update_button(application_name=application_name, 
1279                                        panel_name=panel_name)
1280        self._toolbar.Realize()
1281       
1282    def _add_menu_tool(self):
1283        """
1284        Tools menu
1285        Go through plug-ins and find tools to populate the tools menu
1286        """
1287        style = self.__gui_style & GUIFRAME.CALCULATOR_ON
1288        if style == GUIFRAME.CALCULATOR_ON:
1289            self._tool_menu = None
1290            for item in self.plugins:
1291                if hasattr(item, "get_tools"):
1292                    for tool in item.get_tools():
1293                        # Only create a menu if we have at least one tool
1294                        if self._tool_menu is None:
1295                            self._tool_menu = wx.Menu()
1296                        if tool[0].lower().count('python') > 0:
1297                            self._tool_menu.AppendSeparator()
1298                        id = wx.NewId()
1299                        self._tool_menu.Append(id, tool[0], tool[1])
1300                        wx.EVT_MENU(self, id, tool[2])
1301            if self._tool_menu is not None:
1302                self._menubar.Append(self._tool_menu, '&Tool')
1303               
1304    def _add_current_plugin_menu(self):
1305        """
1306        add current plugin menu
1307        Look for plug-in menus
1308        Add available plug-in sub-menus.
1309        """
1310        if (self._menubar is None) or (self._current_perspective is None):
1311            return
1312        #replace or add a new menu for the current plugin
1313       
1314        pos = self._menubar.FindMenu(str(self._applications_menu_name))
1315        if pos != -1:
1316            menu_list = self._current_perspective.populate_menu(self)
1317            if menu_list:
1318                for (menu, name) in menu_list:
1319                    hidden_menu = self._menubar.Replace(pos, menu, name) 
1320                    self._applications_menu_name = name
1321                #self._applications_menu_pos = pos
1322            else:
1323                hidden_menu = self._menubar.Remove(pos)
1324                self._applications_menu_name = None
1325            #get the position of the menu when it first added
1326            self._applications_menu_pos = pos
1327           
1328        else:
1329            menu_list = self._current_perspective.populate_menu(self)
1330            if menu_list:
1331                for (menu, name) in menu_list:
1332                    if self._applications_menu_pos == -1:
1333                        self._menubar.Append(menu, name)
1334                    else:
1335                        self._menubar.Insert(self._applications_menu_pos, 
1336                                             menu, name)
1337                    self._applications_menu_name = name
1338                 
1339    def _add_help_menu(self):
1340        """
1341        add help menu
1342        """
1343        # Help menu
1344        self._help_menu = wx.Menu()
1345        style = self.__gui_style & GUIFRAME.WELCOME_PANEL_ON
1346        if style == GUIFRAME.WELCOME_PANEL_ON or custom_config != None:
1347            # add the welcome panel menu item
1348            if config.WELCOME_PANEL_ON and self.defaultPanel is not None:
1349                id = wx.NewId()
1350                self._help_menu.Append(id, '&Welcome', '')
1351                self._help_menu.AppendSeparator()
1352                wx.EVT_MENU(self, id, self.show_welcome_panel)
1353        # Look for help item in plug-ins
1354        for item in self.plugins:
1355            if hasattr(item, "help"):
1356                id = wx.NewId()
1357                self._help_menu.Append(id,'&%s Help' % item.sub_menu, '')
1358                wx.EVT_MENU(self, id, item.help)
1359        if config._do_tutorial and (IS_WIN or sys.platform =='darwin'):
1360            self._help_menu.AppendSeparator()
1361            id = wx.NewId()
1362            self._help_menu.Append(id, '&Tutorial', 'Software tutorial')
1363            wx.EVT_MENU(self, id, self._onTutorial)
1364           
1365        if config._do_aboutbox:
1366            self._help_menu.AppendSeparator()
1367            id = wx.NewId()
1368            self._help_menu.Append(id, '&About', 'Software information')
1369            wx.EVT_MENU(self, id, self._onAbout)
1370       
1371        # Checking for updates
1372        id = wx.NewId()
1373        self._help_menu.Append(id,'&Check for update', 
1374         'Check for the latest version of %s' % config.__appname__)
1375        wx.EVT_MENU(self, id, self._check_update)
1376        self._menubar.Append(self._help_menu, '&Help')
1377           
1378    def _add_menu_view(self):
1379        """
1380        add menu items under view menu
1381        """
1382        if not VIEW_MENU:
1383            return
1384        self._view_menu = wx.Menu()
1385       
1386        id = wx.NewId()
1387        hint = "Display the Grid Window for batch results etc."
1388        self._view_menu.Append(id, '&Show Grid Window', hint) 
1389        wx.EVT_MENU(self, id, self.show_batch_frame)
1390       
1391        self._view_menu.AppendSeparator()
1392        style = self.__gui_style & GUIFRAME.MANAGER_ON
1393        id = wx.NewId()
1394        self._data_panel_menu = self._view_menu.Append(id,
1395                                                '&Show Data Explorer', '')
1396        wx.EVT_MENU(self, id, self.show_data_panel)
1397        if style == GUIFRAME.MANAGER_ON:
1398            self._data_panel_menu.SetText('Hide Data Explorer')
1399        else:
1400            self._data_panel_menu.SetText('Show Data Explorer')
1401 
1402        self._view_menu.AppendSeparator()
1403        id = wx.NewId()
1404        style1 = self.__gui_style & GUIFRAME.TOOLBAR_ON
1405        if style1 == GUIFRAME.TOOLBAR_ON:
1406            self._toolbar_menu = self._view_menu.Append(id, '&Hide Toolbar', '')
1407        else:
1408            self._toolbar_menu = self._view_menu.Append(id, '&Show Toolbar', '')
1409        wx.EVT_MENU(self, id, self._on_toggle_toolbar)
1410
1411        if custom_config != None:
1412            self._view_menu.AppendSeparator()
1413            id = wx.NewId()
1414            hint_ss = "Select the current/default configuration "
1415            hint_ss += "as a startup setting"
1416            preference_menu = self._view_menu.Append(id, 'Startup Setting', 
1417                                                     hint_ss)
1418            wx.EVT_MENU(self, id, self._on_preference_menu)
1419           
1420        id = wx.NewId()
1421        self._view_menu.AppendSeparator()
1422        self._view_menu.Append(id, 'Category Manager', 'Edit model categories')
1423        wx.EVT_MENU(self, id, self._on_category_manager)
1424
1425        self._menubar.Append(self._view_menu, '&View')   
1426         
1427    def show_batch_frame(self, event=None):
1428        """
1429        show the grid of result
1430        """
1431        # Show(False) before Show(True) in order to bring it to the front
1432        self.batch_frame.Show(False)
1433        self.batch_frame.Show(True)
1434   
1435    def  on_category_panel(self, event): 
1436        """
1437        On cat panel
1438        """
1439        self._on_category_manager(event)
1440         
1441    def _on_category_manager(self, event):
1442        """
1443        Category manager frame
1444        """
1445        frame = CategoryManager(self, -1, 'Model Category Manager')
1446        icon = self.GetIcon()
1447        frame.SetIcon(icon)
1448
1449    def _on_preference_menu(self, event):     
1450        """
1451        Build a panel to allow to edit Mask
1452        """
1453        from sans.guiframe.startup_configuration \
1454        import StartupConfiguration as ConfDialog
1455       
1456        dialog = ConfDialog(parent=self, gui=self.__gui_style)
1457        result = dialog.ShowModal()
1458        if result == wx.ID_OK:
1459            dialog.write_custom_config()
1460            # post event for info
1461            wx.PostEvent(self, StatusEvent(status="Wrote custom configuration", info='info'))
1462        dialog.Destroy()
1463       
1464    def _add_menu_application(self):
1465        """
1466        # Attach a menu item for each defined perspective or application.
1467        # Only add the perspective menu if there are more than one perspectives
1468        add menu application
1469        """
1470        if self._num_perspectives  > 1:
1471            plug_data_count = False
1472            plug_no_data_count = False
1473            self._applications_menu = wx.Menu()
1474            pos = 0
1475            separator = self._applications_menu.AppendSeparator()
1476            for plug in self.plugins:
1477                if len(plug.get_perspective()) > 0:
1478                    id = wx.NewId()
1479                    if plug.use_data():
1480                       
1481                        self._applications_menu.InsertCheckItem(pos, id, plug.sub_menu,
1482                                      "Switch to analysis: %s" % plug.sub_menu)
1483                        plug_data_count = True
1484                        pos += 1
1485                    else:
1486                        plug_no_data_count = True
1487                        self._applications_menu.AppendCheckItem(id, plug.sub_menu,
1488                                      "Switch to analysis: %s" % plug.sub_menu)
1489                    wx.EVT_MENU(self, id, plug.on_perspective)
1490
1491            if (not plug_data_count or not plug_no_data_count):
1492                self._applications_menu.RemoveItem(separator)
1493            self._menubar.Append(self._applications_menu, '&Analysis')
1494            self._check_applications_menu()
1495           
1496    def _populate_file_menu(self):
1497        """
1498        Insert menu item under file menu
1499        """
1500        for plugin in self.plugins:
1501            if len(plugin.populate_file_menu()) > 0:
1502                for item in plugin.populate_file_menu():
1503                    m_name, m_hint, m_handler = item
1504                    id = wx.NewId()
1505                    self._file_menu.Append(id, m_name, m_hint)
1506                    wx.EVT_MENU(self, id, m_handler)
1507                self._file_menu.AppendSeparator()
1508               
1509    def _add_menu_file(self):
1510        """
1511        add menu file
1512        """
1513       
1514        # File menu
1515        self._file_menu = wx.Menu()
1516        #append item from plugin under menu file if necessary
1517        self._populate_file_menu()
1518        style1 = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
1519        if OPEN_SAVE_MENU:
1520            id = wx.NewId()
1521            hint_load_file = "read all analysis states saved previously"
1522            self._save_appl_menu = self._file_menu.Append(id, 
1523                                    '&Open Project', hint_load_file)
1524            wx.EVT_MENU(self, id, self._on_open_state_project)
1525           
1526        if style1 == GUIFRAME.MULTIPLE_APPLICATIONS:
1527            # some menu of plugin to be seen under file menu
1528            hint_load_file = "Read a status files and load"
1529            hint_load_file += " them into the analysis"
1530            id = wx.NewId()
1531            self._save_appl_menu = self._file_menu.Append(id, 
1532                                    '&Open Analysis', hint_load_file)
1533            wx.EVT_MENU(self, id, self._on_open_state_application)
1534        if OPEN_SAVE_MENU:       
1535            self._file_menu.AppendSeparator()
1536            id = wx.NewId()
1537            self._file_menu.Append(id, '&Save Project',
1538                                 'Save the state of the whole analysis')
1539            wx.EVT_MENU(self, id, self._on_save_project)
1540        if style1 == GUIFRAME.MULTIPLE_APPLICATIONS:
1541            id = wx.NewId()
1542            self._save_appl_menu = self._file_menu.Append(id, 
1543                                                      '&Save Analysis',
1544                        'Save state of the current active analysis panel')
1545            wx.EVT_MENU(self, id, self._on_save_application)
1546            self._file_menu.AppendSeparator()
1547       
1548        id = wx.NewId()
1549        self._file_menu.Append(id, '&Quit', 'Exit') 
1550        wx.EVT_MENU(self, id, self.Close)
1551        # Add sub menus
1552        self._menubar.Append(self._file_menu, '&File')
1553       
1554    def _add_menu_edit(self):
1555        """
1556        add menu edit
1557        """
1558        if not EDIT_MENU:
1559            return
1560        # Edit Menu
1561        self._edit_menu = wx.Menu()
1562        self._edit_menu.Append(GUIFRAME_ID.UNDO_ID, '&Undo', 
1563                               'Undo the previous action')
1564        wx.EVT_MENU(self, GUIFRAME_ID.UNDO_ID, self.on_undo_panel)
1565        self._edit_menu.Append(GUIFRAME_ID.REDO_ID, '&Redo', 
1566                               'Redo the previous action')
1567        wx.EVT_MENU(self, GUIFRAME_ID.REDO_ID, self.on_redo_panel)
1568        self._edit_menu.AppendSeparator()
1569        self._edit_menu.Append(GUIFRAME_ID.COPY_ID, '&Copy Params', 
1570                               'Copy parameter values')
1571        wx.EVT_MENU(self, GUIFRAME_ID.COPY_ID, self.on_copy_panel)
1572        self._edit_menu.Append(GUIFRAME_ID.PASTE_ID, '&Paste Params', 
1573                               'Paste parameter values')
1574        wx.EVT_MENU(self, GUIFRAME_ID.PASTE_ID, self.on_paste_panel)
1575
1576        self._edit_menu.AppendSeparator()
1577
1578        self._edit_menu_copyas = wx.Menu()
1579        #Sub menu for Copy As...
1580        self._edit_menu_copyas.Append(GUIFRAME_ID.COPYEX_ID, 'Copy current tab to Excel',
1581                               'Copy parameter values in tabular format')
1582        wx.EVT_MENU(self, GUIFRAME_ID.COPYEX_ID, self.on_copy_panel)
1583
1584        self._edit_menu_copyas.Append(GUIFRAME_ID.COPYLAT_ID, 'Copy current tab to LaTeX',
1585                               'Copy parameter values in tabular format')
1586        wx.EVT_MENU(self, GUIFRAME_ID.COPYLAT_ID, self.on_copy_panel)
1587
1588
1589        self._edit_menu.AppendMenu(GUIFRAME_ID.COPYAS_ID, 'Copy Params as...', self._edit_menu_copyas,
1590                               'Copy parameter values in various formats')
1591
1592
1593        self._edit_menu.AppendSeparator()
1594       
1595        self._edit_menu.Append(GUIFRAME_ID.PREVIEW_ID, '&Report Results',
1596                               'Preview current panel')
1597        wx.EVT_MENU(self, GUIFRAME_ID.PREVIEW_ID, self.on_preview_panel)
1598
1599        self._edit_menu.Append(GUIFRAME_ID.RESET_ID, '&Reset Page', 
1600                               'Reset current panel')
1601        wx.EVT_MENU(self, GUIFRAME_ID.RESET_ID, self.on_reset_panel)
1602   
1603        self._menubar.Append(self._edit_menu,  '&Edit')
1604        self.enable_edit_menu()
1605       
1606    def get_style(self):
1607        """
1608        Return the gui style
1609        """
1610        return  self.__gui_style
1611   
1612    def _add_menu_data(self):
1613        """
1614        Add menu item item data to menu bar
1615        """
1616        if self._data_plugin is not None:
1617            menu_list = self._data_plugin.populate_menu(self)
1618            if menu_list:
1619                for (menu, name) in menu_list:
1620                    self._menubar.Append(menu, name)
1621       
1622                       
1623    def _on_toggle_toolbar(self, event=None):
1624        """
1625        hide or show toolbar
1626        """
1627        if self._toolbar is None:
1628            return
1629        if self._toolbar.IsShown():
1630            if self._toolbar_menu is not None:
1631                self._toolbar_menu.SetItemLabel('Show Toolbar')
1632            self._toolbar.Hide()
1633        else:
1634            if self._toolbar_menu is not None:
1635                self._toolbar_menu.SetItemLabel('Hide Toolbar')
1636            self._toolbar.Show()
1637        self._toolbar.Realize()
1638       
1639    def _on_status_event(self, evt):
1640        """
1641        Display status message
1642        """
1643        # This CallAfter fixes many crashes on MAC.
1644        wx.CallAfter(self.sb.set_status, evt)
1645       
1646    def on_view(self, evt):
1647        """
1648        A panel was selected to be shown. If it's not already
1649        shown, display it.
1650       
1651        :param evt: menu event
1652       
1653        """
1654        panel_id = str(evt.GetId())
1655        self.on_set_plot_focus(self.panels[panel_id])
1656        self.show_panel(evt.GetId(), 'on')     
1657        wx.CallLater(5*TIME_FACTOR, self.set_schedule(True))
1658        self.set_plot_unfocus()
1659 
1660    def show_welcome_panel(self, event):
1661        """   
1662        Display the welcome panel
1663        """
1664        if self.defaultPanel is None:
1665            return 
1666        frame = self.panels['default'].get_frame()
1667        if frame == None:
1668            return
1669        # Show default panel
1670        if not frame.IsShown():
1671            frame.Show(True)
1672           
1673    def on_close_welcome_panel(self):
1674        """
1675        Close the welcome panel
1676        """
1677        if self.defaultPanel is None:
1678            return 
1679        default_panel = self.panels["default"].frame
1680        if default_panel.IsShown():
1681            default_panel.Show(False) 
1682               
1683    def delete_panel(self, uid):
1684        """
1685        delete panel given uid
1686        """
1687        ID = str(uid)
1688        config.printEVT("delete_panel: %s" % ID)
1689        try:
1690            caption = self.panels[ID].window_caption
1691        except:
1692            print "delete_panel: No such plot id as %s" % ID
1693            return
1694        if ID in self.panels.keys():
1695            self.panel_on_focus = None
1696            panel = self.panels[ID]
1697
1698            if hasattr(panel, "connect"):
1699                panel.connect.disconnect()
1700            self._plotting_plugin.delete_panel(panel.group_id)
1701
1702            if panel in self.schedule_full_draw_list:
1703                self.schedule_full_draw_list.remove(panel) 
1704           
1705            #delete uid number not str(uid)
1706            if ID in self.plot_panels.keys():
1707                del self.plot_panels[ID]
1708            if ID in self.panels.keys():
1709                del self.panels[ID]
1710            return 
1711           
1712    def create_gui_data(self, data, path=None):
1713        """
1714        """
1715        return self._data_manager.create_gui_data(data, path)
1716   
1717    def get_data(self, path):
1718        """
1719        """
1720        message = ""
1721        log_msg = ''
1722        output = []
1723        error_message = ""
1724        basename  = os.path.basename(path)
1725        root, extension = os.path.splitext(basename)
1726        if extension.lower() not in EXTENSIONS:
1727            log_msg = "File Loader cannot "
1728            log_msg += "load: %s\n" % str(basename)
1729            log_msg += "Try Data opening...."
1730            logging.info(log_msg)
1731            print log_msg
1732            #self.load_complete(output=output, error_message=error_message,
1733            #       message=log_msg, path=path)   
1734            return
1735       
1736        #reading a state file
1737        for plug in self.plugins:
1738            reader, ext = plug.get_extensions()
1739            if reader is not None:
1740                #read the state of the single plugin
1741                if extension == ext:
1742                    reader.read(path)
1743                    return
1744                elif extension == APPLICATION_STATE_EXTENSION:
1745                    try:
1746                        reader.read(path)
1747                    except:
1748                        msg = "DataLoader Error: Encounted Non-ASCII character"
1749                        msg += "\n(%s)"% sys.exc_value
1750                        wx.PostEvent(self, StatusEvent(status=msg, 
1751                                                info="error", type="stop"))
1752                        return
1753       
1754        style = self.__gui_style & GUIFRAME.MANAGER_ON
1755        if style == GUIFRAME.MANAGER_ON:
1756            if self._data_panel is not None:
1757                self._data_panel.frame.Show(True)
1758     
1759    def load_from_cmd(self,  path):   
1760        """
1761        load data from cmd or application
1762        """ 
1763        if path is None:
1764            return
1765        else:
1766            path = os.path.abspath(path)
1767            if not os.path.isfile(path) and not os.path.isdir(path):
1768                return
1769           
1770            if os.path.isdir(path):
1771                self.load_folder(path)
1772                return
1773
1774        basename  = os.path.basename(path)
1775        root, extension = os.path.splitext(basename)
1776        if extension.lower() not in EXTENSIONS:
1777            self.load_data(path)
1778        else:
1779            self.load_state(path)
1780
1781        self._default_save_location = os.path.dirname(path)
1782       
1783    def show_panel(self, uid, show=None):
1784        """
1785        Shows the panel with the given id
1786       
1787        :param uid: unique ID number of the panel to show
1788       
1789        """
1790        #Not implemeted
1791        return
1792       
1793    def load_state(self, path, is_project=False):   
1794        """
1795        load data from command line or application
1796        """
1797        if path and (path is not None) and os.path.isfile(path):
1798            basename  = os.path.basename(path)
1799            if APPLICATION_STATE_EXTENSION is not None \
1800                and basename.endswith(APPLICATION_STATE_EXTENSION):
1801                if is_project:
1802                    for ID in self.plot_panels.keys():
1803                        panel = self.plot_panels[ID]
1804                        panel.on_close(None)
1805            self.get_data(path)
1806            wx.PostEvent(self, StatusEvent(status="Completed loading."))
1807        else:
1808            wx.PostEvent(self, StatusEvent(status=" "))
1809           
1810    def load_data(self, path):
1811        """
1812        load data from command line
1813        """
1814        if not os.path.isfile(path):
1815            return
1816        basename  = os.path.basename(path)
1817        root, extension = os.path.splitext(basename)
1818        if extension.lower() in EXTENSIONS:
1819            log_msg = "Data Loader cannot "
1820            log_msg += "load: %s\n" % str(path)
1821            log_msg += "Try File opening ...."
1822            print log_msg
1823            return
1824        log_msg = ''
1825        output = {}
1826        error_message = ""
1827        try:
1828            print "Loading Data...:\n" + str(path) + "\n"
1829            temp =  self.loader.load(path)
1830            if temp.__class__.__name__ == "list":
1831                for item in temp:
1832                    data = self.create_gui_data(item, path)
1833                    output[data.id] = data
1834            else:
1835                data = self.create_gui_data(temp, path)
1836                output[data.id] = data
1837           
1838            self.add_data(data_list=output)
1839        except:
1840            error_message = "Error while loading"
1841            error_message += " Data from cmd:\n %s\n" % str(path)
1842            error_message += str(sys.exc_value) + "\n"
1843            print error_message
1844 
1845    def load_folder(self, path):
1846        """
1847        Load entire folder
1848        """   
1849        if not os.path.isdir(path):
1850            return
1851        if self._data_plugin is None:
1852            return
1853        try:
1854            if path is not None:
1855                self._default_save_location = os.path.dirname(path)
1856                file_list = self._data_plugin.get_file_path(path)
1857                self._data_plugin.get_data(file_list)
1858            else:
1859                return 
1860        except:
1861            error_message = "Error while loading"
1862            error_message += " Data folder from cmd:\n %s\n" % str(path)
1863            error_message += str(sys.exc_value) + "\n"
1864            print error_message
1865           
1866    def _on_open_state_application(self, event):
1867        """
1868        """
1869        path = None
1870        if self._default_save_location == None:
1871            self._default_save_location = os.getcwd()
1872        wx.PostEvent(self, StatusEvent(status="Loading Analysis file..."))
1873        plug_wlist = self._on_open_state_app_helper()
1874        dlg = wx.FileDialog(self, 
1875                            "Choose a file", 
1876                            self._default_save_location, "",
1877                            plug_wlist)
1878        if dlg.ShowModal() == wx.ID_OK:
1879            path = dlg.GetPath()
1880            if path is not None:
1881                self._default_save_location = os.path.dirname(path)
1882        dlg.Destroy()
1883        self.load_state(path=path) 
1884   
1885    def _on_open_state_app_helper(self):
1886        """
1887        Helps '_on_open_state_application()' to find the extension of
1888        the current perspective/application
1889        """
1890        # No current perspective or no extension attr
1891        if self._current_perspective is None:
1892            return PLUGINS_WLIST
1893        try:
1894            # Find the extension of the perspective
1895            # and get that as 1st item in list
1896            ind = None
1897            app_ext = self._current_perspective._extensions
1898            plug_wlist = config.PLUGINS_WLIST
1899            for ext in set(plug_wlist):
1900                if ext.count(app_ext) > 0:
1901                    ind = ext
1902                    break
1903            # Found the extension
1904            if ind != None:
1905                plug_wlist.remove(ind)
1906                plug_wlist.insert(0, ind)
1907                try:
1908                    plug_wlist = '|'.join(plug_wlist)
1909                except:
1910                    plug_wlist = ''
1911
1912        except:
1913            plug_wlist = PLUGINS_WLIST
1914           
1915        return plug_wlist
1916           
1917    def _on_open_state_project(self, event):
1918        """
1919        """
1920        path = None
1921        if self._default_save_location == None:
1922            self._default_save_location = os.getcwd()
1923        wx.PostEvent(self, StatusEvent(status="Loading Project file..."))
1924        dlg = wx.FileDialog(self, 
1925                            "Choose a file", 
1926                            self._default_save_location, "",
1927                             APPLICATION_WLIST)
1928        if dlg.ShowModal() == wx.ID_OK:
1929            path = dlg.GetPath()
1930            if path is not None:
1931                self._default_save_location = os.path.dirname(path)
1932        dlg.Destroy()
1933       
1934        self.load_state(path=path, is_project=True)
1935       
1936    def _on_save_application(self, event):
1937        """
1938        save the state of the current active application
1939        """
1940        if self.cpanel_on_focus is not None:
1941            try:
1942                wx.PostEvent(self, 
1943                             StatusEvent(status="Saving Analysis file..."))
1944                self.cpanel_on_focus.on_save(event)
1945                wx.PostEvent(self, 
1946                             StatusEvent(status="Completed saving."))
1947            except:
1948                msg = "Error occurred while saving: "
1949                msg += "To save, the application panel should have a data set.."
1950                wx.PostEvent(self, StatusEvent(status=msg)) 
1951           
1952    def _on_save_project(self, event):
1953        """
1954        save the state of the SasView as *.svs
1955        """
1956        if self._current_perspective is  None:
1957            return
1958        wx.PostEvent(self, StatusEvent(status="Saving Project file..."))
1959        reader, ext = self._current_perspective.get_extensions()
1960        path = None
1961        extension = '*' + APPLICATION_STATE_EXTENSION
1962        dlg = wx.FileDialog(self, "Save Project file",
1963                            self._default_save_location, "sasview_proj",
1964                             extension, 
1965                             wx.SAVE)
1966        if dlg.ShowModal() == wx.ID_OK:
1967            path = dlg.GetPath()
1968            self._default_save_location = os.path.dirname(path)
1969        else:
1970            return None
1971        dlg.Destroy()
1972        try:
1973            if path is None:
1974                return
1975            # default cansas xml doc
1976            doc = None
1977            for panel in self.panels.values():
1978                temp = panel.save_project(doc)
1979                if temp is not None:
1980                    doc = temp
1981             
1982            # Write the XML document
1983            extens = APPLICATION_STATE_EXTENSION
1984            fName = os.path.splitext(path)[0] + extens
1985            if doc != None:
1986                fd = open(fName, 'w')
1987                fd.write(doc.toprettyxml())
1988                fd.close()
1989                wx.PostEvent(self, StatusEvent(status="Completed Saving."))
1990            else:
1991                msg = "%s cannot read %s\n" % (str(APPLICATION_NAME), str(path))
1992                logging.error(msg)
1993        except:
1994            msg = "Error occurred while saving: "
1995            msg += "To save, at leat one application panel "
1996            msg += "should have a data set.."
1997            wx.PostEvent(self, StatusEvent(status=msg))   
1998                   
1999    def on_save_helper(self, doc, reader, panel, path):
2000        """
2001        Save state into a file
2002        """
2003        try:
2004            if reader is not None:
2005                # case of a panel with multi-pages
2006                if hasattr(panel, "opened_pages"):
2007                    for uid, page in panel.opened_pages.iteritems():
2008                        data = page.get_data()
2009                        # state must be cloned
2010                        state = page.get_state().clone()
2011                        if data is not None:
2012                            new_doc = reader.write_toXML(data, state)
2013                            if doc != None and hasattr(doc, "firstChild"):
2014                                child = new_doc.firstChild.firstChild
2015                                doc.firstChild.appendChild(child) 
2016                            else:
2017                                doc = new_doc
2018                # case of only a panel
2019                else:
2020                    data = panel.get_data()
2021                    state = panel.get_state()
2022                    if data is not None:
2023                        new_doc = reader.write_toXML(data, state)
2024                        if doc != None and hasattr(doc, "firstChild"):
2025                            child = new_doc.firstChild.firstChild
2026                            doc.firstChild.appendChild(child) 
2027                        else:
2028                            doc = new_doc
2029        except: 
2030            raise
2031            #pass
2032
2033        return doc
2034
2035    def quit_guiframe(self):
2036        """
2037        Pop up message to make sure the user wants to quit the application
2038        """
2039        message = "\nDo you really want to exit this application?        \n\n"
2040        dial = wx.MessageDialog(self, message, 'Confirm Exit',
2041                           wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
2042        if dial.ShowModal() == wx.ID_YES:
2043            return True
2044        else:
2045            return False   
2046       
2047    def WindowClose(self, event=None):
2048        """
2049        Quit the application from x icon
2050        """
2051        flag = self.quit_guiframe()
2052        if flag:
2053            _pylab_helpers.Gcf.figs = {}
2054            self.Close()
2055           
2056    def Close(self, event=None):
2057        """
2058        Quit the application
2059        """
2060        wx.Exit()
2061        sys.exit()
2062           
2063    def _check_update(self, event=None): 
2064        """
2065        Check with the deployment server whether a new version
2066        of the application is available.
2067        A thread is started for the connecting with the server. The thread calls
2068        a call-back method when the current version number has been obtained.
2069        """
2070        try:
2071            conn = httplib.HTTPConnection(config.__update_URL__[0], 
2072                              timeout=3.0)
2073            conn.request("GET", config.__update_URL__[1])
2074            res = conn.getresponse()
2075            content = res.read()
2076            conn.close()
2077        except:
2078            content = "0.0.0"
2079       
2080        version = content.strip()
2081        if len(re.findall('\d+\.\d+\.\d+$', version)) < 0:
2082            content = "0.0.0"
2083        self._process_version(content, standalone=event==None)
2084   
2085    def _process_version(self, version, standalone=True):
2086        """
2087        Call-back method for the process of checking for updates.
2088        This methods is called by a VersionThread object once the current
2089        version number has been obtained. If the check is being done in the
2090        background, the user will not be notified unless there's an update.
2091       
2092        :param version: version string
2093        :param standalone: True of the update is being checked in
2094           the background, False otherwise.
2095           
2096        """
2097        try:
2098            if version == "0.0.0":
2099                msg = "Could not connect to the application server."
2100                msg += " Please try again later."
2101                self.SetStatusText(msg)
2102            elif cmp(version, config.__version__) > 0:
2103                msg = "Version %s is available! " % str(version)
2104                if not standalone:
2105                    import webbrowser
2106                    webbrowser.open(config.__download_page__)
2107                else:
2108                    msg +=  "See the help menu to download it." 
2109                self.SetStatusText(msg)
2110            else:
2111                if not standalone:
2112                    msg = "You have the latest version"
2113                    msg += " of %s" % str(config.__appname__)
2114                    self.SetStatusText(msg)
2115        except:
2116            msg = "guiframe: could not get latest application"
2117            msg += " version number\n  %s" % sys.exc_value
2118            logging.error(msg)
2119            if not standalone:
2120                msg = "Could not connect to the application server."
2121                msg += " Please try again later."
2122                self.SetStatusText(msg)
2123                   
2124    def _onAbout(self, evt):
2125        """
2126        Pop up the about dialog
2127       
2128        :param evt: menu event
2129       
2130        """
2131        if config._do_aboutbox:
2132            import sans.guiframe.aboutbox as AboutBox 
2133            dialog = AboutBox.DialogAbout(None, -1, "")
2134            dialog.ShowModal()   
2135                     
2136    def _onTutorial(self, evt):
2137        """
2138        Pop up the tutorial dialog
2139       
2140        :param evt: menu event
2141       
2142        """
2143        if config._do_tutorial:   
2144            path = config.TUTORIAL_PATH
2145            if IS_WIN:
2146                try:
2147                    from sans.guiframe.pdfview import PDFFrame
2148                    dialog = PDFFrame(None, -1, "Tutorial", path)
2149                    # put icon
2150                    self.put_icon(dialog) 
2151                    dialog.Show(True) 
2152                except:
2153                    print "Error in _onTutorial: %s" % sys.exc_value
2154                    try:
2155                        #in case when the pdf default set other than acrobat
2156                        import ho.pisa as pisa
2157                        pisa.startViewer(path)
2158                    except:
2159                        msg = "This feature requires 'PDF Viewer'\n"
2160                        msg += "Please install it first (Free)..."
2161                        wx.MessageBox(msg, 'Error')
2162            else:
2163                try:
2164                    command = "open '%s'" % path
2165                    os.system(command)
2166                except:
2167                    try:
2168                        #in case when the pdf default set other than preview
2169                        import ho.pisa as pisa
2170                        pisa.startViewer(path)
2171                    except:
2172                        msg = "This feature requires 'Preview' Application\n"
2173                        msg += "Please install it first..."
2174                        wx.MessageBox(msg, 'Error')
2175
2176                     
2177    def set_manager(self, manager):
2178        """
2179        Sets the application manager for this frame
2180       
2181        :param manager: frame manager
2182        """
2183        self.app_manager = manager
2184       
2185    def post_init(self):
2186        """
2187        This initialization method is called after the GUI
2188        has been created and all plug-ins loaded. It calls
2189        the post_init() method of each plug-in (if it exists)
2190        so that final initialization can be done.
2191        """
2192        for item in self.plugins:
2193            if hasattr(item, "post_init"):
2194                item.post_init()
2195       
2196    def set_default_perspective(self):
2197        """
2198        Choose among the plugin the first plug-in that has
2199        "set_default_perspective" method and its return value is True will be
2200        as a default perspective when the welcome page is closed
2201        """
2202        for item in self.plugins:
2203            if hasattr(item, "set_default_perspective"):
2204                if item.set_default_perspective():
2205                    item.on_perspective(event=None)
2206                    return 
2207       
2208    def set_perspective(self, panels):
2209        """
2210        Sets the perspective of the GUI.
2211        Opens all the panels in the list, and closes
2212        all the others.
2213       
2214        :param panels: list of panels
2215        """
2216        for item in self.panels.keys():
2217            # Check whether this is a sticky panel
2218            if hasattr(self.panels[item], "ALWAYS_ON"):
2219                if self.panels[item].ALWAYS_ON:
2220                    continue 
2221            if self.panels[item] == None:
2222                continue
2223            if self.panels[item].window_name in panels:
2224                frame = self.panels[item].get_frame()
2225                if not frame.IsShown():
2226                    frame.Show(True)
2227            else:
2228                # always show the data panel if enable
2229                style = self.__gui_style & GUIFRAME.MANAGER_ON
2230                if (style == GUIFRAME.MANAGER_ON) and self.panels[item] == self._data_panel:
2231                    if 'data_panel' in self.panels.keys():
2232                        frame = self.panels['data_panel'].get_frame()
2233                        if frame == None:
2234                            continue
2235                        flag = frame.IsShown()
2236                        frame.Show(flag)
2237                else:
2238                    frame = self.panels[item].get_frame()
2239                    if frame == None:
2240                        continue
2241
2242                    if frame.IsShown():
2243                        frame.Show(False)
2244       
2245    def show_data_panel(self, event=None, action=True):
2246        """
2247        show the data panel
2248        """
2249        if self._data_panel_menu == None:
2250            return
2251        label = self._data_panel_menu.GetText()
2252        pane = self.panels["data_panel"]
2253        frame = pane.get_frame()
2254        if label == 'Show Data Explorer':
2255            if action: 
2256                frame.Show(True)
2257            self.__gui_style = self.__gui_style | GUIFRAME.MANAGER_ON
2258            self._data_panel_menu.SetText('Hide Data Explorer')
2259        else:
2260            if action:
2261                frame.Show(False)
2262            self.__gui_style = self.__gui_style & (~GUIFRAME.MANAGER_ON)
2263            self._data_panel_menu.SetText('Show Data Explorer')
2264
2265    def add_data_helper(self, data_list):
2266        """
2267        """
2268        if self._data_manager is not None:
2269            self._data_manager.add_data(data_list)
2270       
2271    def add_data(self, data_list):
2272        """
2273        receive a dictionary of data from loader
2274        store them its data manager if possible
2275        send to data the current active perspective if the data panel
2276        is not active.
2277        :param data_list: dictionary of data's ID and value Data
2278        """
2279        #Store data into manager
2280        self.add_data_helper(data_list)
2281        # set data in the data panel
2282        if self._data_panel is not None:
2283            data_state = self._data_manager.get_data_state(data_list.keys())
2284            self._data_panel.load_data_list(data_state)
2285        #if the data panel is shown wait for the user to press a button
2286        #to send data to the current perspective. if the panel is not
2287        #show  automatically send the data to the current perspective
2288        style = self.__gui_style & GUIFRAME.MANAGER_ON
2289        if style == GUIFRAME.MANAGER_ON:
2290            #wait for button press from the data panel to set_data
2291            if self._data_panel is not None:
2292                self._data_panel.frame.Show(True)
2293        else:
2294            #automatically send that to the current perspective
2295            self.set_data(data_id=data_list.keys())
2296       
2297    def set_data(self, data_id, theory_id=None): 
2298        """
2299        set data to current perspective
2300        """
2301        list_data, _ = self._data_manager.get_by_id(data_id)
2302        if self._current_perspective is not None:
2303            self._current_perspective.set_data(list_data.values())
2304
2305        else:
2306            msg = "Guiframe does not have a current perspective"
2307            logging.info(msg)
2308           
2309    def set_theory(self, state_id, theory_id=None):
2310        """
2311        """
2312        _, list_theory = self._data_manager.get_by_id(theory_id)
2313        if self._current_perspective is not None:
2314            try:
2315                self._current_perspective.set_theory(list_theory.values())
2316            except:
2317                msg = "Guiframe set_theory: \n" + str(sys.exc_value)
2318                logging.info(msg)
2319                wx.PostEvent(self, StatusEvent(status=msg, info="error"))
2320        else:
2321            msg = "Guiframe does not have a current perspective"
2322            logging.info(msg)
2323           
2324    def plot_data(self,  state_id, data_id=None,
2325                  theory_id=None, append=False):
2326        """
2327        send a list of data to plot
2328        """
2329        total_plot_list = []
2330        data_list, _ = self._data_manager.get_by_id(data_id)
2331        _, temp_list_theory = self._data_manager.get_by_id(theory_id)
2332        total_plot_list = data_list.values()
2333        for item in temp_list_theory.values():
2334            theory_data, theory_state = item
2335            total_plot_list.append(theory_data)
2336        GROUP_ID = wx.NewId()
2337        for new_plot in total_plot_list:
2338            if append:
2339                if self.panel_on_focus is None:
2340                    message = "cannot append plot. No plot panel on focus!"
2341                    message += "please click on any available plot to set focus"
2342                    wx.PostEvent(self, StatusEvent(status=message, 
2343                                                   info='warning'))
2344                    return 
2345                else:
2346                    if self.enable_add_data(new_plot):
2347                        new_plot.group_id = self.panel_on_focus.group_id
2348                    else:
2349                        message = "Only 1D Data can be append to"
2350                        message += " plot panel containing 1D data.\n"
2351                        message += "%s not be appended.\n" %str(new_plot.name)
2352                        message += "try new plot option.\n"
2353                        wx.PostEvent(self, StatusEvent(status=message, 
2354                                                   info='warning'))
2355            else:
2356                #if not append then new plot
2357                from sans.guiframe.dataFitting import Data2D
2358                if issubclass(Data2D, new_plot.__class__):
2359                    #for 2 D always plot in a separated new plot
2360                    new_plot.group_id = wx.NewId()
2361                else:
2362                    # plot all 1D in a new plot
2363                    new_plot.group_id = GROUP_ID
2364            title = "PLOT " + str(new_plot.title)
2365            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
2366                                                  title=title,
2367                                                  group_id = new_plot.group_id))
2368           
2369    def remove_data(self, data_id, theory_id=None):
2370        """
2371        Delete data state if data_id is provide
2372        delete theory created with data of id data_id if theory_id is provide
2373        if delete all true: delete the all state
2374        else delete theory
2375        """
2376        temp = data_id + theory_id
2377        for plug in self.plugins:
2378            plug.delete_data(temp)
2379        total_plot_list = []
2380        data_list, _ = self._data_manager.get_by_id(data_id)
2381        _, temp_list_theory = self._data_manager.get_by_id(theory_id)
2382        total_plot_list = data_list.values()
2383        for item in temp_list_theory.values():
2384            theory_data, theory_state = item
2385            total_plot_list.append(theory_data)
2386        for new_plot in total_plot_list:
2387            id = new_plot.id
2388            for group_id in new_plot.list_group_id:
2389                wx.PostEvent(self, NewPlotEvent(id=id,
2390                                                   group_id=group_id,
2391                                                   action='remove'))
2392                #remove res plot: Todo: improve
2393                wx.CallAfter(self._remove_res_plot, id)
2394        self._data_manager.delete_data(data_id=data_id, 
2395                                       theory_id=theory_id)
2396       
2397    def _remove_res_plot(self, id):
2398        """
2399        Try to remove corresponding res plot
2400       
2401        : param id: id of the data
2402        """
2403        try:
2404            wx.PostEvent(self, NewPlotEvent(id=("res"+str(id)),
2405                                           group_id=("res"+str(id)),
2406                                           action='remove'))
2407        except:
2408            pass
2409   
2410    def save_data1d(self, data, fname):
2411        """
2412        Save data dialog
2413        """
2414        default_name = fname
2415        wildcard = "Text files (*.txt)|*.txt|"\
2416                    "CanSAS 1D files(*.xml)|*.xml" 
2417        path = None
2418        dlg = wx.FileDialog(self, "Choose a file",
2419                            self._default_save_location,
2420                            default_name, wildcard , wx.SAVE)
2421       
2422        if dlg.ShowModal() == wx.ID_OK:
2423            path = dlg.GetPath()
2424            # ext_num = 0 for .txt, ext_num = 1 for .xml
2425            # This is MAC Fix
2426            ext_num = dlg.GetFilterIndex()
2427            if ext_num == 0:
2428                format = '.txt'
2429            else:
2430                format = '.xml'
2431            path = os.path.splitext(path)[0] + format
2432            mypath = os.path.basename(path)
2433           
2434            #TODO: This is bad design. The DataLoader is designed
2435            #to recognize extensions.
2436            # It should be a simple matter of calling the .
2437            #save(file, data, '.xml') method
2438            # of the sans.dataloader.loader.Loader class.
2439            from sans.dataloader.loader import  Loader
2440            #Instantiate a loader
2441            loader = Loader() 
2442            format = ".txt"
2443            if os.path.splitext(mypath)[1].lower() == format:
2444                # Make sure the ext included in the file name
2445                # especially on MAC
2446                fName = os.path.splitext(path)[0] + format
2447                self._onsaveTXT(data, fName)
2448            format = ".xml"
2449            if os.path.splitext(mypath)[1].lower() == format:
2450                # Make sure the ext included in the file name
2451                # especially on MAC
2452                fName = os.path.splitext(path)[0] + format
2453                loader.save(fName, data, format)
2454            try:
2455                self._default_save_location = os.path.dirname(path)
2456            except:
2457                pass   
2458        dlg.Destroy()
2459       
2460       
2461    def _onsaveTXT(self, data, path):
2462        """
2463        Save file as txt 
2464        :TODO: Refactor and remove this method. See TODO in _onSave.
2465        """
2466        if not path == None:
2467            out = open(path, 'w')
2468            has_errors = True
2469            if data.dy == None or data.dy == []:
2470                has_errors = False
2471            # Sanity check
2472            if has_errors:
2473                try:
2474                    if len(data.y) != len(data.dy):
2475                        has_errors = False
2476                except:
2477                    has_errors = False
2478            if has_errors:
2479                if data.dx != None and data.dx != []:
2480                    out.write("<X>   <Y>   <dY>   <dX>\n")
2481                else:
2482                    out.write("<X>   <Y>   <dY>\n")
2483            else:
2484                out.write("<X>   <Y>\n")
2485               
2486            for i in range(len(data.x)):
2487                if has_errors:
2488                    if data.dx != None and data.dx != []:
2489                        if  data.dx[i] != None:
2490                            out.write("%g  %g  %g  %g\n" % (data.x[i], 
2491                                                        data.y[i],
2492                                                        data.dy[i],
2493                                                        data.dx[i]))
2494                        else:
2495                            out.write("%g  %g  %g\n" % (data.x[i], 
2496                                                        data.y[i],
2497                                                        data.dy[i]))
2498                    else:
2499                        out.write("%g  %g  %g\n" % (data.x[i], 
2500                                                    data.y[i],
2501                                                    data.dy[i]))
2502                else:
2503                    out.write("%g  %g\n" % (data.x[i], 
2504                                            data.y[i]))
2505            out.close() 
2506                             
2507    def show_data1d(self, data, name):
2508        """
2509        Show data dialog
2510        """   
2511        try:
2512            xmin = min(data.x)
2513            ymin = min(data.y)
2514        except:
2515            msg = "Unable to find min/max of \n data named %s"% \
2516                        data.filename 
2517            wx.PostEvent(self, StatusEvent(status=msg,
2518                                       info="error"))
2519            raise ValueError, msg
2520        ## text = str(data)
2521        text = data.__str__()
2522        text += 'Data Min Max:\n'
2523        text += 'X_min = %s:  X_max = %s\n'% (xmin, max(data.x))
2524        text += 'Y_min = %s:  Y_max = %s\n'% (ymin, max(data.y))
2525        if data.dy != None:
2526            text += 'dY_min = %s:  dY_max = %s\n'% (min(data.dy), max(data.dy))
2527        text += '\nData Points:\n'
2528        x_st = "X"
2529        for index in range(len(data.x)):
2530            if data.dy != None and len(data.dy) > index:
2531                dy_val = data.dy[index]
2532            else:
2533                dy_val = 0.0
2534            if data.dx != None and len(data.dx) > index:
2535                dx_val = data.dx[index]
2536            else:
2537                dx_val = 0.0
2538            if data.dxl != None and len(data.dxl) > index:
2539                if index == 0: 
2540                    x_st = "Xl"
2541                dx_val = data.dxl[index]
2542            elif data.dxw != None and len(data.dxw) > index:
2543                if index == 0: 
2544                    x_st = "Xw"
2545                dx_val = data.dxw[index]
2546           
2547            if index == 0:
2548                text += "<index> \t<X> \t<Y> \t<dY> \t<d%s>\n"% x_st
2549            text += "%s \t%s \t%s \t%s \t%s\n" % (index,
2550                                            data.x[index], 
2551                                            data.y[index],
2552                                            dy_val,
2553                                            dx_val)
2554        from pdfview import TextFrame
2555        frame = TextFrame(None, -1, "Data Info: %s"% data.name, text) 
2556        # put icon
2557        self.put_icon(frame) 
2558        frame.Show(True) 
2559           
2560    def save_data2d(self, data, fname):   
2561        """
2562        Save data2d dialog
2563        """
2564        default_name = fname
2565        wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
2566        dlg = wx.FileDialog(self, "Choose a file",
2567                            self._default_save_location,
2568                            default_name, wildcard , wx.SAVE)
2569       
2570        if dlg.ShowModal() == wx.ID_OK:
2571            path = dlg.GetPath()
2572            # ext_num = 0 for .txt, ext_num = 1 for .xml
2573            # This is MAC Fix
2574            ext_num = dlg.GetFilterIndex()
2575            if ext_num == 0:
2576                format = '.dat'
2577            else:
2578                format = ''
2579            path = os.path.splitext(path)[0] + format
2580            mypath = os.path.basename(path)
2581           
2582            #TODO: This is bad design. The DataLoader is designed
2583            #to recognize extensions.
2584            # It should be a simple matter of calling the .
2585            #save(file, data, '.xml') method
2586            # of the DataLoader.loader.Loader class.
2587            from sans.dataloader.loader import  Loader
2588            #Instantiate a loader
2589            loader = Loader() 
2590
2591            format = ".dat"
2592            if os.path.splitext(mypath)[1].lower() == format:
2593                # Make sure the ext included in the file name
2594                # especially on MAC
2595                fileName = os.path.splitext(path)[0] + format
2596                loader.save(fileName, data, format)
2597            try:
2598                self._default_save_location = os.path.dirname(path)
2599            except:
2600                pass   
2601        dlg.Destroy() 
2602                             
2603    def show_data2d(self, data, name):
2604        """
2605        Show data dialog
2606        """   
2607
2608        wx.PostEvent(self, StatusEvent(status = "Gathering Data2D Info.", 
2609                                       type = 'start' ))
2610        text = data.__str__() 
2611        text += 'Data Min Max:\n'
2612        text += 'I_min = %s\n'% min(data.data)
2613        text += 'I_max = %s\n\n'% max(data.data)
2614        text += 'Data (First 2501) Points:\n'
2615        text += 'Data columns include err(I).\n'
2616        text += 'ASCII data starts here.\n'
2617        text += "<index> \t<Qx> \t<Qy> \t<I> \t<dI> \t<dQparal> \t<dQperp>\n"
2618        di_val = 0.0
2619        dx_val = 0.0
2620        dy_val = 0.0
2621        #mask_val = True
2622        len_data = len(data.qx_data)
2623        for index in xrange(0, len_data):
2624            x_val = data.qx_data[index]
2625            y_val = data.qy_data[index]
2626            i_val = data.data[index]
2627            if data.err_data != None: 
2628                di_val = data.err_data[index]
2629            if data.dqx_data != None: 
2630                dx_val = data.dqx_data[index]
2631            if data.dqy_data != None: 
2632                dy_val = data.dqy_data[index]
2633 
2634            text += "%s \t%s \t%s \t%s \t%s \t%s \t%s\n" % (index,
2635                                            x_val, 
2636                                            y_val,
2637                                            i_val,
2638                                            di_val,
2639                                            dx_val,
2640                                            dy_val)
2641            # Takes too long time for typical data2d: Break here
2642            if index >= 2500:
2643                text += ".............\n"
2644                break
2645
2646        from pdfview import TextFrame
2647        frame = TextFrame(None, -1, "Data Info: %s"% data.name, text) 
2648        # put icon
2649        self.put_icon(frame)
2650        frame.Show(True) 
2651        wx.PostEvent(self, StatusEvent(status = "Data2D Info Displayed", 
2652                                       type = 'stop' ))
2653                                 
2654    def set_current_perspective(self, perspective):
2655        """
2656        set the current active perspective
2657        """
2658        self._current_perspective = perspective
2659        name = "No current analysis selected"
2660        if self._current_perspective is not None:
2661            self._add_current_plugin_menu()
2662            for panel in self.panels.values():
2663                if hasattr(panel, 'CENTER_PANE') and panel.CENTER_PANE:
2664                    for name in self._current_perspective.get_perspective():
2665                        frame = panel.get_frame()
2666                        if frame != None:
2667                            if name == panel.window_name:
2668                                panel.on_set_focus(event=None)
2669                                frame.Show(True)
2670                            else:
2671                                frame.Show(False)
2672                            #break               
2673            name = self._current_perspective.sub_menu
2674            if self._data_panel is not None:
2675                self._data_panel.set_active_perspective(name)
2676                self._check_applications_menu()
2677            #Set the SasView title
2678            self._set_title_name(name)
2679           
2680    def _set_title_name(self, name):
2681        """
2682        Set the SasView title w/ the current application name
2683       
2684        : param name: application name [string]
2685        """
2686        # Set SanView Window title w/ application anme
2687        title = self.title + "  - " + name + " -"
2688        self.SetTitle(title)
2689           
2690    def _check_applications_menu(self):
2691        """
2692        check the menu of the current application
2693        """
2694        if self._applications_menu is not None:
2695            for menu in self._applications_menu.GetMenuItems():
2696                if self._current_perspective is not None:
2697                    name = self._current_perspective.sub_menu
2698                    if menu.IsCheckable():
2699                        if menu.GetLabel() == name:
2700                            menu.Check(True)
2701                        else:
2702                            menu.Check(False) 
2703           
2704    def enable_add_data(self, new_plot):
2705        """
2706        Enable append data on a plot panel
2707        """
2708
2709        if self.panel_on_focus not in self._plotting_plugin.plot_panels.values():
2710            return
2711        is_theory = len(self.panel_on_focus.plots) <= 1 and \
2712            self.panel_on_focus.plots.values()[0].__class__.__name__ == "Theory1D"
2713           
2714        is_data2d = hasattr(new_plot, 'data')
2715       
2716        is_data1d = self.panel_on_focus.__class__.__name__ == "ModelPanel1D"\
2717            and self.panel_on_focus.group_id is not None
2718        has_meta_data = hasattr(new_plot, 'meta_data')
2719       
2720        #disable_add_data if the data is being recovered from  a saved state file.
2721        is_state_data = False
2722        if has_meta_data:
2723            if 'invstate' in new_plot.meta_data: 
2724                is_state_data = True
2725            if  'prstate' in new_plot.meta_data: 
2726                is_state_data = True
2727            if  'fitstate' in new_plot.meta_data: 
2728                is_state_data = True
2729   
2730        return is_data1d and not is_data2d and not is_theory and not is_state_data
2731   
2732    def check_multimode(self, perspective=None):
2733        """
2734        Check the perspective have batch mode capablitity
2735        """
2736        if perspective == None or self._data_panel == None:
2737            return
2738        flag = perspective.get_batch_capable()
2739        flag_on = perspective.batch_on
2740        if flag:
2741            self._data_panel.rb_single_mode.SetValue(not flag_on)
2742            self._data_panel.rb_batch_mode.SetValue(flag_on)
2743        else:
2744            self._data_panel.rb_single_mode.SetValue(True)
2745            self._data_panel.rb_batch_mode.SetValue(False)
2746        self._data_panel.rb_single_mode.Enable(flag)
2747        self._data_panel.rb_batch_mode.Enable(flag)
2748               
2749
2750   
2751    def enable_edit_menu(self):
2752        """
2753        enable menu item under edit menu depending on the panel on focus
2754        """
2755        if self.cpanel_on_focus is not None and self._edit_menu is not None:
2756            flag = self.cpanel_on_focus.get_undo_flag()
2757            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
2758            flag = self.cpanel_on_focus.get_redo_flag()
2759            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
2760            flag = self.cpanel_on_focus.get_copy_flag()
2761            self._edit_menu.Enable(GUIFRAME_ID.COPY_ID, flag)
2762            flag = self.cpanel_on_focus.get_paste_flag()
2763            self._edit_menu.Enable(GUIFRAME_ID.PASTE_ID, flag)
2764
2765            #Copy menu
2766            flag = self.cpanel_on_focus.get_copy_flag()
2767            #self._edit_menu.ENABLE(GUIFRAME_ID.COPYAS_ID,flag)
2768            self._edit_menu_copyas.Enable(GUIFRAME_ID.COPYEX_ID, flag)
2769            self._edit_menu_copyas.Enable(GUIFRAME_ID.COPYLAT_ID, flag)
2770
2771            flag = self.cpanel_on_focus.get_preview_flag()
2772            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
2773            flag = self.cpanel_on_focus.get_reset_flag()
2774            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
2775        else:
2776            flag = False
2777            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
2778            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
2779            self._edit_menu.Enable(GUIFRAME_ID.COPY_ID, flag)
2780            self._edit_menu.Enable(GUIFRAME_ID.PASTE_ID, flag)
2781            #self._edit_menu.Enable(GUIFRAME_ID.COPYEX_ID, flag)
2782            #self._edit_menu.Enable(GUIFRAME_ID.COPYLAT_ID, flag)
2783            #self._edit_menu.Enable(GUIFRAME_ID.COPYAS_ID, flag)
2784            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
2785            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
2786           
2787    def on_undo_panel(self, event=None):
2788        """
2789        undo previous action of the last panel on focus if possible
2790        """
2791        if self.cpanel_on_focus is not None:
2792            self.cpanel_on_focus.on_undo(event)
2793           
2794    def on_redo_panel(self, event=None):
2795        """
2796        redo the last cancel action done on the last panel on focus
2797        """
2798        if self.cpanel_on_focus is not None:
2799            self.cpanel_on_focus.on_redo(event)
2800           
2801    def on_copy_panel(self, event=None):
2802        """
2803        copy the last panel on focus if possible
2804        """
2805        if self.cpanel_on_focus is not None:
2806            self.cpanel_on_focus.on_copy(event)
2807           
2808    def on_paste_panel(self, event=None):
2809        """
2810        paste clipboard to the last panel on focus
2811        """
2812        if self.cpanel_on_focus is not None:
2813            self.cpanel_on_focus.on_paste(event)
2814                   
2815    def on_bookmark_panel(self, event=None):
2816        """
2817        bookmark panel
2818        """
2819        if self.cpanel_on_focus is not None:
2820            self.cpanel_on_focus.on_bookmark(event)
2821           
2822    def append_bookmark(self, event=None):
2823        """
2824        Bookmark available information of the panel on focus
2825        """
2826        self._toolbar.append_bookmark(event)
2827           
2828    def on_save_panel(self, event=None):
2829        """
2830        save possible information on the current panel
2831        """
2832        if self.cpanel_on_focus is not None:
2833            self.cpanel_on_focus.on_save(event)
2834           
2835    def on_preview_panel(self, event=None):
2836        """
2837        preview information on the panel on focus
2838        """
2839        if self.cpanel_on_focus is not None:
2840            self.cpanel_on_focus.on_preview(event)
2841           
2842    def on_print_panel(self, event=None):
2843        """
2844        print available information on the last panel on focus
2845        """
2846        if self.cpanel_on_focus is not None:
2847            self.cpanel_on_focus.on_print(event)
2848           
2849    def on_zoom_panel(self, event=None):
2850        """
2851        zoom on the current panel if possible
2852        """
2853        if self.cpanel_on_focus is not None:
2854            self.cpanel_on_focus.on_zoom(event)
2855           
2856    def on_zoom_in_panel(self, event=None):
2857        """
2858        zoom in of the panel on focus
2859        """
2860        if self.cpanel_on_focus is not None:
2861            self.cpanel_on_focus.on_zoom_in(event)
2862           
2863    def on_zoom_out_panel(self, event=None):
2864        """
2865        zoom out on the panel on focus
2866        """
2867        if self.cpanel_on_focus is not None:
2868            self.cpanel_on_focus.on_zoom_out(event)
2869           
2870    def on_drag_panel(self, event=None):
2871        """
2872        drag apply to the panel on focus
2873        """
2874        if self.cpanel_on_focus is not None:
2875            self.cpanel_on_focus.on_drag(event)
2876           
2877    def on_reset_panel(self, event=None):
2878        """
2879        reset the current panel
2880        """
2881        if self.cpanel_on_focus is not None:
2882            self.cpanel_on_focus.on_reset(event)
2883           
2884    def on_change_caption(self, name, old_caption, new_caption):     
2885        """
2886        Change the panel caption
2887       
2888        :param name: window_name of the pane
2889        :param old_caption: current caption [string]
2890        :param new_caption: new caption [string]
2891        """
2892        # wx.aui.AuiPaneInfo
2893        pane_info = self.get_paneinfo(old_caption) 
2894        # update the data_panel.cb_plotpanel
2895        if 'data_panel' in self.panels.keys():
2896            # remove from data_panel combobox
2897            data_panel = self.panels["data_panel"]
2898            if data_panel.cb_plotpanel is not None:
2899                # Check if any panel has the same caption
2900                has_newstring = data_panel.cb_plotpanel.FindString\
2901                                                            (str(new_caption)) 
2902                caption = new_caption
2903                if has_newstring != wx.NOT_FOUND:
2904                    captions = self._get_plotpanel_captions()
2905                    # Append nummber
2906                    inc = 1
2907                    while (1):
2908                        caption = new_caption + '_%s'% str(inc)
2909                        if caption not in captions:
2910                            break
2911                        inc += 1
2912                    # notify to users
2913                    msg = "Found Same Title: Added '_%s'"% str(inc)
2914                    wx.PostEvent(self, StatusEvent(status=msg))
2915                # update data_panel cb
2916                pos = data_panel.cb_plotpanel.FindString(str(old_caption)) 
2917                if pos != wx.NOT_FOUND:
2918                    data_panel.cb_plotpanel.SetString(pos, caption)
2919                    data_panel.cb_plotpanel.SetStringSelection(caption)
2920        # update window Show menu
2921        if self._window_menu != None:
2922            for item in self._window_menu.GetMenuItems():
2923                pos = self._window_menu.FindItem(old_caption)
2924                if self._window_menu.GetLabel(pos) == str(old_caption):
2925                    self._window_menu.SetLabel(pos, caption)
2926                break
2927        # New Caption
2928        pane_info.SetTitle(caption)
2929        return caption
2930       
2931    def get_paneinfo(self, name):
2932        """
2933        Get pane Caption from window_name
2934       
2935        :param name: window_name in AuiPaneInfo
2936        : return: AuiPaneInfo of the name
2937        """
2938        for panel in self.plot_panels.values():
2939            if panel.frame.GetTitle() == name:
2940                return panel.frame
2941        return None
2942   
2943    def enable_undo(self):
2944        """
2945        enable undo related control
2946        """
2947        if self.cpanel_on_focus is not None:
2948            self._toolbar.enable_undo(self.cpanel_on_focus)
2949           
2950    def enable_redo(self):
2951        """
2952        enable redo
2953        """
2954        if self.cpanel_on_focus is not None:
2955            self._toolbar.enable_redo(self.cpanel_on_focus)
2956           
2957    def enable_copy(self):
2958        """
2959        enable copy related control
2960        """
2961        if self.cpanel_on_focus is not None:
2962            self._toolbar.enable_copy(self.cpanel_on_focus)
2963           
2964    def enable_paste(self):
2965        """
2966        enable paste
2967        """
2968        if self.cpanel_on_focus is not None:
2969            self._toolbar.enable_paste(self.cpanel_on_focus)
2970                       
2971    def enable_bookmark(self):
2972        """
2973        Bookmark
2974        """
2975        if self.cpanel_on_focus is not None:
2976            self._toolbar.enable_bookmark(self.cpanel_on_focus)
2977           
2978    def enable_save(self):
2979        """
2980        save
2981        """
2982        if self.cpanel_on_focus is not None:
2983            self._toolbar.enable_save(self.cpanel_on_focus)
2984           
2985    def enable_preview(self):
2986        """
2987        preview
2988        """
2989        if self.cpanel_on_focus is not None:
2990            self._toolbar.enable_preview(self.cpanel_on_focus)
2991           
2992    def enable_print(self):
2993        """
2994        print
2995        """
2996        if self.cpanel_on_focus is not None:
2997            self._toolbar.enable_print(self.cpanel_on_focus)
2998           
2999    def enable_zoom(self):
3000        """
3001        zoom
3002        """
3003        if self.cpanel_on_focus is not None:
3004            self._toolbar.enable_zoom(self.panel_on_focus)
3005           
3006    def enable_zoom_in(self):
3007        """
3008        zoom in
3009        """
3010        if self.cpanel_on_focus is not None:
3011            self._toolbar.enable_zoom_in(self.panel_on_focus)
3012           
3013    def enable_zoom_out(self):
3014        """
3015        zoom out
3016        """
3017        if self.cpanel_on_focus is not None:
3018            self._toolbar.enable_zoom_out(self.panel_on_focus)
3019           
3020    def enable_drag(self, event=None):
3021        """
3022        drag
3023        """
3024        #Not implemeted
3025           
3026    def enable_reset(self):
3027        """
3028        reset the current panel
3029        """
3030        if self.cpanel_on_focus is not None:
3031            self._toolbar.enable_reset(self.panel_on_focus)
3032           
3033    def get_toolbar_height(self):
3034        """
3035        """
3036        size_y = 0
3037        if self.GetToolBar() != None and self.GetToolBar().IsShown():
3038            if not IS_LINUX:
3039                _, size_y = self.GetToolBar().GetSizeTuple()
3040        return size_y
3041   
3042    def set_schedule_full_draw(self, panel=None, func='del'):
3043        """
3044        Add/subtract the schedule full draw list with the panel given
3045       
3046        :param panel: plot panel
3047        :param func: append or del [string]
3048        """
3049
3050        # append this panel in the schedule list if not in yet
3051        if func == 'append':
3052            if not panel in self.schedule_full_draw_list:
3053                self.schedule_full_draw_list.append(panel) 
3054        # remove this panel from schedule list
3055        elif func == 'del':
3056            if len(self.schedule_full_draw_list) > 0:
3057                if panel in self.schedule_full_draw_list:
3058                    self.schedule_full_draw_list.remove(panel)
3059
3060        # reset the schdule
3061        if len(self.schedule_full_draw_list) == 0:
3062            self.schedule = False
3063        else:
3064            self.schedule = True   
3065       
3066    def full_draw(self):
3067        """
3068        Draw the panels with axes in the schedule to full dwar list
3069        """
3070       
3071        count = len(self.schedule_full_draw_list)
3072        #if not self.schedule:
3073        if count < 1:
3074            self.set_schedule(False)
3075            return
3076
3077        else:
3078            ind = 0
3079            # if any of the panel is shown do full_draw
3080            for panel in self.schedule_full_draw_list:
3081                ind += 1
3082                if panel.frame.IsShown():
3083                    break
3084                # otherwise, return
3085                if ind == count:
3086                    return
3087        #Simple redraw only for a panel shown
3088        def f_draw(panel):
3089            """
3090            Draw A panel in the full draw list
3091            """
3092            try:
3093                # This checking of GetCapture is to stop redrawing
3094                # while any panel is capture.
3095                frame = panel.frame
3096               
3097                if not frame.GetCapture():
3098                    # draw if possible
3099                    panel.set_resizing(False)
3100                    #panel.Show(True)
3101                    panel.draw_plot()
3102                # Check if the panel is not shown
3103                flag = frame.IsShown()
3104                frame.Show(flag) 
3105            except:
3106                pass
3107     
3108        # Draw all panels
3109        if count == 1:
3110            f_draw(self.schedule_full_draw_list[0]) 
3111        else:
3112            map(f_draw, self.schedule_full_draw_list)
3113        # Reset the attr 
3114        if len(self.schedule_full_draw_list) == 0:
3115            self.set_schedule(False)
3116        else:
3117            self.set_schedule(True)
3118       
3119    def set_schedule(self, schedule=False): 
3120        """
3121        Set schedule
3122        """
3123        self.schedule = schedule
3124               
3125    def get_schedule(self): 
3126        """
3127        Get schedule
3128        """
3129        return self.schedule
3130   
3131    def on_set_plot_focus(self, panel):
3132        """
3133        Set focus on a plot panel
3134        """
3135        if panel == None:
3136            return
3137        #self.set_plot_unfocus()
3138        panel.on_set_focus(None) 
3139        # set focusing panel
3140        self.panel_on_focus = panel 
3141        self.set_panel_on_focus(None)
3142
3143    def set_plot_unfocus(self): 
3144        """
3145        Un focus all plot panels
3146        """
3147        for plot in self.plot_panels.values():
3148            plot.on_kill_focus(None)
3149   
3150    def get_window_size(self):
3151        """
3152        Get window size
3153       
3154        :return size: tuple
3155        """
3156        width, height = self.GetSizeTuple()
3157        if not IS_WIN:
3158            # Subtract toolbar height to get real window side
3159            if self._toolbar.IsShown():
3160                height -= 45
3161        return (width, height)
3162           
3163    def _onDrawIdle(self, *args, **kwargs):
3164        """
3165        ReDraw with axes
3166        """
3167        try:
3168            # check if it is time to redraw
3169            if self.GetCapture() == None:
3170                # Draw plot, changes resizing too
3171                self.full_draw()
3172        except:
3173            pass
3174           
3175        # restart idle       
3176        self._redraw_idle(*args, **kwargs)
3177
3178           
3179    def _redraw_idle(self, *args, **kwargs):
3180        """
3181        Restart Idle
3182        """
3183        # restart idle   
3184        self.idletimer.Restart(100*TIME_FACTOR, *args, **kwargs)
3185
3186       
3187class DefaultPanel(wx.Panel, PanelBase):
3188    """
3189    Defines the API for a panels to work with
3190    the GUI manager
3191    """
3192    ## Internal nickname for the window, used by the AUI manager
3193    window_name = "default"
3194    ## Name to appear on the window title bar
3195    window_caption = "Welcome panel"
3196    ## Flag to tell the AUI manager to put this panel in the center pane
3197    CENTER_PANE = True
3198    def __init__(self, parent, *args, **kwds):
3199        wx.Panel.__init__(self, parent, *args, **kwds)
3200        PanelBase.__init__(self, parent)
3201   
3202
3203
3204class ViewApp(wx.App):
3205    """
3206    Toy application to test this Frame
3207    """
3208    def OnInit(self):
3209        """
3210        When initialised
3211        """
3212        pos, size, self.is_max = self.window_placement((GUIFRAME_WIDTH, 
3213                                           GUIFRAME_HEIGHT))     
3214        self.frame = ViewerFrame(parent=None, 
3215                             title=APPLICATION_NAME, 
3216                             pos=pos, 
3217                             gui_style = DEFAULT_STYLE,
3218                             size=size)
3219        self.frame.Hide()
3220        if not IS_WIN:
3221            self.frame.EnableCloseButton(False)
3222        self.s_screen = None
3223
3224        try:
3225            self.open_file()
3226        except:
3227            msg = "%s Could not load " % str(APPLICATION_NAME)
3228            msg += "input file from command line.\n"
3229            logging.error(msg)
3230        # Display a splash screen on top of the frame.
3231        try:
3232            if os.path.isfile(SPLASH_SCREEN_PATH):
3233                self.s_screen = self.display_splash_screen(parent=self.frame, 
3234                                        path=SPLASH_SCREEN_PATH)
3235            else:
3236                self.frame.Show()   
3237        except:
3238            if self.s_screen is not None:
3239                self.s_screen.Close()
3240            msg = "Cannot display splash screen\n"
3241            msg += str (sys.exc_value)
3242            logging.error(msg)
3243            self.frame.Show()
3244
3245        self.SetTopWindow(self.frame)
3246 
3247        return True
3248   
3249    def maximize_win(self):
3250        """
3251        Maximize the window after the frame shown
3252        """
3253        if self.is_max:
3254            if self.frame.IsShown():
3255                # Max window size
3256                self.frame.Maximize(self.is_max)
3257
3258    def open_file(self):
3259        """
3260        open a state file at the start of the application
3261        """
3262        input_file = None
3263        if len(sys.argv) >= 2:
3264            cmd = sys.argv[0].lower()
3265            basename  = os.path.basename(cmd)
3266            app_base = str(APPLICATION_NAME).lower()
3267            if os.path.isfile(cmd) or basename.lower() == app_base:
3268                app_py = app_base + '.py'
3269                app_exe = app_base + '.exe'
3270                app_app = app_base + '.app'
3271                if basename.lower() in [app_py, app_exe, app_app, app_base]:
3272                    data_base = sys.argv[1]
3273                    input_file = os.path.normpath(os.path.join(DATAPATH, 
3274                                                               data_base))
3275        if input_file is None:
3276            return
3277        if self.frame is not None:
3278            self.frame.set_input_file(input_file=input_file)
3279         
3280    def clean_plugin_models(self, path): 
3281        """
3282        Delete plugin models  in app folder
3283       
3284        :param path: path of the plugin_models folder in app
3285        """
3286        # do it only the first time app loaded
3287        # delete unused model folder   
3288        model_folder = os.path.join(PATH_APP, path)
3289        if os.path.exists(model_folder) and os.path.isdir(model_folder):
3290            if len(os.listdir(model_folder)) > 0:
3291                try:
3292                    for file in os.listdir(model_folder):
3293                        file_path = os.path.join(model_folder, file)
3294                        if os.path.isfile(file_path):
3295                            os.remove(file_path)
3296                except:
3297                    logging.error("gui_manager.clean_plugin_models:\n  %s" \
3298                                  % sys.exc_value)
3299             
3300    def set_manager(self, manager):
3301        """
3302        Sets a reference to the application manager
3303        of the GUI manager (Frame)
3304        """
3305        self.frame.set_manager(manager)
3306       
3307    def build_gui(self):
3308        """
3309        Build the GUI
3310        """
3311        #try to load file at the start
3312        try:
3313            self.open_file()
3314        except:
3315            raise
3316        self.frame.build_gui()
3317       
3318    def set_welcome_panel(self, panel_class):
3319        """
3320        Set the welcome panel
3321       
3322        :param panel_class: class of the welcome panel to be instantiated
3323       
3324        """
3325        self.frame.set_welcome_panel(panel_class)
3326       
3327    def add_perspective(self, perspective):
3328        """
3329        Manually add a perspective to the application GUI
3330        """
3331        self.frame.add_perspective(perspective)
3332   
3333    def window_placement(self, size):
3334        """
3335        Determines the position and size of the application frame such that it
3336        fits on the user's screen without obstructing (or being obstructed by)
3337        the Windows task bar.  The maximum initial size in pixels is bounded by
3338        WIDTH x HEIGHT.  For most monitors, the application
3339        will be centered on the screen; for very large monitors it will be
3340        placed on the left side of the screen.
3341        """
3342        is_maximized = False
3343        # Get size of screen without
3344        for screenCount in range(wx.Display().GetCount()):
3345            screen = wx.Display(screenCount)
3346            if screen.IsPrimary():
3347                displayRect = screen.GetClientArea()
3348                break
3349       
3350        posX, posY, displayWidth, displayHeight = displayRect       
3351        customWidth, customHeight = size
3352       
3353        # If the custom size is default, set 90% of the screen size
3354        if customWidth <= 0 and customHeight <= 0:
3355            if customWidth == 0 and customHeight == 0:
3356                is_maximized = True
3357            customWidth = displayWidth * 0.9
3358            customHeight = displayHeight * 0.9
3359        else:
3360            # If the custom screen is bigger than the
3361            # window screen than make maximum size
3362            if customWidth > displayWidth:
3363                customWidth = displayWidth
3364            if customHeight > displayHeight:
3365                customHeight = displayHeight
3366           
3367        # Note that when running Linux and using an Xming (X11) server on a PC
3368        # with a dual  monitor configuration, the reported display size may be
3369        # that of both monitors combined with an incorrect display count of 1.
3370        # To avoid displaying this app across both monitors, we check for
3371        # screen 'too big'.  If so, we assume a smaller width which means the
3372        # application will be placed towards the left hand side of the screen.
3373       
3374        # If dual screen registered as 1 screen. Make width half.
3375        # MAC just follows the default behavior of pos
3376        if IS_WIN:
3377            if displayWidth > (displayHeight*2):
3378                if (customWidth == displayWidth):
3379                    customWidth = displayWidth/2
3380                # and set the position to be the corner of the screen.
3381                posX = 0
3382                posY = 0
3383               
3384            # Make the position the middle of the screen. (Not 0,0)
3385            else:
3386                posX = (displayWidth - customWidth)/2
3387                posY = (displayHeight - customHeight)/2
3388        # Return the suggested position and size for the application frame.   
3389        return (posX, posY), (customWidth, customHeight), is_maximized
3390
3391   
3392    def display_splash_screen(self, parent, 
3393                              path=SPLASH_SCREEN_PATH):
3394        """Displays the splash screen.  It will exactly cover the main frame."""
3395       
3396        # Prepare the picture.  On a 2GHz intel cpu, this takes about a second.
3397        image = wx.Image(path, wx.BITMAP_TYPE_PNG)
3398        image.Rescale(SPLASH_SCREEN_WIDTH, 
3399                      SPLASH_SCREEN_HEIGHT, wx.IMAGE_QUALITY_HIGH)
3400        bm = image.ConvertToBitmap()
3401
3402        # Create and show the splash screen.  It will disappear only when the
3403        # program has entered the event loop AND either the timeout has expired
3404        # or the user has left clicked on the screen.  Thus any processing
3405        # performed in this routine (including sleeping) or processing in the
3406        # calling routine (including doing imports) will prevent the splash
3407        # screen from disappearing.
3408        #
3409        # Note that on Linux, the timeout appears to occur immediately in which
3410        # case the splash screen disappears upon entering the event loop.
3411        s_screen = wx.SplashScreen(bitmap=bm,
3412                         splashStyle=(wx.SPLASH_TIMEOUT|
3413                                              wx.SPLASH_CENTRE_ON_SCREEN),
3414                                 style=(wx.SIMPLE_BORDER|
3415                                        wx.FRAME_NO_TASKBAR|
3416                                        wx.FRAME_FLOAT_ON_PARENT),
3417                                       
3418                        milliseconds=SS_MAX_DISPLAY_TIME,
3419                        parent=parent,
3420                        id=wx.ID_ANY)
3421        from sans.guiframe.gui_statusbar import SPageStatusbar
3422        statusBar = SPageStatusbar(s_screen)
3423        s_screen.SetStatusBar(statusBar)
3424        s_screen.Bind(wx.EVT_CLOSE, self.on_close_splash_screen)
3425        s_screen.Show()
3426        return s_screen
3427       
3428       
3429    def on_close_splash_screen(self, event):
3430        """
3431        When the splash screen is closed.
3432        """
3433        self.frame.Show(True)
3434        event.Skip()
3435        self.maximize_win()
3436
3437
3438class MDIFrame(CHILD_FRAME):
3439    """
3440    Frame for panels
3441    """
3442    def __init__(self, parent, panel, title="Untitled",
3443                size=(300,200), *args, **kwds):
3444        """
3445        comment
3446        :param parent: parent panel/container
3447        """
3448        kwds['size']= size
3449        kwds['title']= title
3450        kwds['style'] = MDI_STYLE
3451        # Initialize the Frame object
3452        CHILD_FRAME.__init__(self, parent, *args, **kwds)
3453        self.parent = parent
3454        self.name = "Untitled"
3455        self.batch_on = self.parent.batch_on
3456        self.panel = panel
3457        if panel != None:
3458            self.set_panel(panel)
3459        self.Show(False)
3460   
3461    def show_data_panel(self, action):
3462        """
3463        """
3464        self.parent.show_data_panel(action)
3465       
3466    def set_panel(self, panel):
3467        """
3468        """
3469        self.panel = panel
3470        self.name = panel.window_name
3471        self.SetTitle(panel.window_caption)
3472        self.SetHelpText(panel.help_string)
3473        width, height = self.parent._get_panels_size(panel)
3474        if hasattr(panel, "CENTER_PANE") and panel.CENTER_PANE:
3475            width *= 0.6 
3476        self.SetSize((width, height))
3477        self.parent.put_icon(self)
3478        self.Bind(wx.EVT_SET_FOCUS, self.set_panel_focus)
3479        self.Bind(wx.EVT_CLOSE, self.OnClose)
3480        self.Show(False)
3481   
3482    def set_panel_focus(self, event):
3483        """
3484        """
3485        if self.parent.panel_on_focus != self.panel:
3486            self.panel.SetFocus()
3487            self.parent.panel_on_focus = self.panel
3488       
3489    def OnClose(self, event):
3490        """
3491        On Close event
3492        """
3493        self.panel.on_close(event)
3494       
3495if __name__ == "__main__": 
3496    app = ViewApp(0)
3497    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.