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

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

trying to fix datapanel close buton on mac

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