source: sasview/sansguiframe/src/sans/guiframe/gui_manager.py @ ba152f1

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 ba152f1 was ba152f1, checked in by Jae Cho <jhjcho@…>, 11 years ago

main frame fix for mac I

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