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

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

working on pylint score

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