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

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

a little better data error control

  • Property mode set to 100644
File size: 137.9 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 != None and data.dx != []:
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        try:
2644            xmin = min(data.x)
2645            ymin = min(data.y)
2646        except:
2647            msg = "Unable to find min/max of \n data named %s"% \
2648                        data.filename 
2649            wx.PostEvent(self, StatusEvent(status=msg,
2650                                       info="error"))
2651            raise ValueError, msg
2652        text = data.__str__() 
2653        text += 'Data Min Max:\n'
2654        text += 'X_min = %s:  X_max = %s\n'% (xmin, max(data.x))
2655        text += 'Y_min = %s:  Y_max = %s\n'% (ymin, max(data.y))
2656        if data.dy != None:
2657            text += 'dY_min = %s:  dY_max = %s\n'% (min(data.dy), max(data.dy))
2658        text += '\nData Points:\n'
2659        x_st = "X"
2660        for index in range(len(data.x)):
2661            if data.dy != None:
2662                dy_val = data.dy[index]
2663            else:
2664                dy_val = 0.0
2665            if data.dx != None:
2666                dx_val = data.dx[index]
2667            else:
2668                dx_val = 0.0
2669            if data.dxl != None:
2670                if index == 0: 
2671                    x_st = "Xl"
2672                dx_val = data.dxl[index]
2673            elif data.dxw != None:
2674                if index == 0: 
2675                    x_st = "Xw"
2676                dx_val = data.dxw[index]
2677           
2678            if index == 0:
2679                text += "<index> \t<X> \t<Y> \t<dY> \t<d%s>\n"% x_st
2680            text += "%s \t%s \t%s \t%s \t%s\n" % (index,
2681                                            data.x[index], 
2682                                            data.y[index],
2683                                            dy_val,
2684                                            dx_val)
2685        from pdfview import TextFrame
2686        frame = TextFrame(None, -1, "Data Info: %s"% data.name, text) 
2687        # put icon
2688        self.put_icon(frame) 
2689        frame.Show(True) 
2690           
2691    def save_data2d(self, data, fname):   
2692        """
2693        Save data2d dialog
2694        """
2695        default_name = fname
2696        wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
2697        dlg = wx.FileDialog(self, "Choose a file",
2698                            self._default_save_location,
2699                            default_name, wildcard , wx.SAVE)
2700       
2701        if dlg.ShowModal() == wx.ID_OK:
2702            path = dlg.GetPath()
2703            # ext_num = 0 for .txt, ext_num = 1 for .xml
2704            # This is MAC Fix
2705            ext_num = dlg.GetFilterIndex()
2706            if ext_num == 0:
2707                format = '.dat'
2708            else:
2709                format = ''
2710            path = os.path.splitext(path)[0] + format
2711            mypath = os.path.basename(path)
2712           
2713            #TODO: This is bad design. The DataLoader is designed
2714            #to recognize extensions.
2715            # It should be a simple matter of calling the .
2716            #save(file, data, '.xml') method
2717            # of the DataLoader.loader.Loader class.
2718            from sans.dataloader.loader import  Loader
2719            #Instantiate a loader
2720            loader = Loader() 
2721
2722            format = ".dat"
2723            if os.path.splitext(mypath)[1].lower() == format:
2724                # Make sure the ext included in the file name
2725                # especially on MAC
2726                fileName = os.path.splitext(path)[0] + format
2727                loader.save(fileName, data, format)
2728            try:
2729                self._default_save_location = os.path.dirname(path)
2730            except:
2731                pass   
2732        dlg.Destroy() 
2733                             
2734    def show_data2d(self, data, name):
2735        """
2736        Show data dialog
2737        """   
2738
2739        wx.PostEvent(self, StatusEvent(status = "Gathering Data2D Info.", 
2740                                       type = 'start' ))
2741        text = data.__str__() 
2742        text += 'Data Min Max:\n'
2743        text += 'I_min = %s\n'% min(data.data)
2744        text += 'I_max = %s\n\n'% max(data.data)
2745        text += 'Data (First 2501) Points:\n'
2746        text += 'Data columns include err(I).\n'
2747        text += 'ASCII data starts here.\n'
2748        text += "<index> \t<Qx> \t<Qy> \t<I> \t<dI> \t<dQparal> \t<dQperp>\n"
2749        di_val = 0.0
2750        dx_val = 0.0
2751        dy_val = 0.0
2752        #mask_val = True
2753        len_data = len(data.qx_data)
2754        for index in xrange(0, len_data):
2755            x_val = data.qx_data[index]
2756            y_val = data.qy_data[index]
2757            i_val = data.data[index]
2758            if data.err_data != None: 
2759                di_val = data.err_data[index]
2760            if data.dqx_data != None: 
2761                dx_val = data.dqx_data[index]
2762            if data.dqy_data != None: 
2763                dy_val = data.dqy_data[index]
2764            #if data.mask != None: mask_val = data.mask[index]
2765 
2766            text += "%s \t%s \t%s \t%s \t%s \t%s \t%s\n" % (index,
2767                                            x_val, 
2768                                            y_val,
2769                                            i_val,
2770                                            di_val,
2771                                            dx_val,
2772                                            dy_val)
2773            # Takes too long time for typical data2d: Break here
2774            if index >= 2500:
2775                text += ".............\n"
2776                break
2777
2778        from pdfview import TextFrame
2779        frame = TextFrame(None, -1, "Data Info: %s"% data.name, text) 
2780        # put icon
2781        self.put_icon(frame)
2782        frame.Show(True) 
2783        wx.PostEvent(self, StatusEvent(status = "Data2D Info Displayed", 
2784                                       type = 'stop' ))
2785                                 
2786    def set_current_perspective(self, perspective):
2787        """
2788        set the current active perspective
2789        """
2790        self._current_perspective = perspective
2791        name = "No current analysis selected"
2792        if self._current_perspective is not None:
2793            self._add_current_plugin_menu()
2794            for panel in self.panels.values():
2795                if hasattr(panel, 'CENTER_PANE') and panel.CENTER_PANE:
2796                    for name in self._current_perspective.get_perspective():
2797                        if name == panel.window_name:
2798                            panel.on_set_focus(event=None)
2799                            break               
2800            name = self._current_perspective.sub_menu
2801            if self._data_panel is not None:
2802                self._data_panel.set_active_perspective(name)
2803                self._check_applications_menu()
2804            #Set the SansView title
2805            self._set_title_name(name)
2806         
2807           
2808    def _set_title_name(self, name):
2809        """
2810        Set the SansView title w/ the current application name
2811       
2812        : param name: application name [string]
2813        """
2814        # Set SanView Window title w/ application anme
2815        title = self.title + "  - " + name + " -"
2816        self.SetTitle(title)
2817           
2818    def _check_applications_menu(self):
2819        """
2820        check the menu of the current application
2821        """
2822        if self._applications_menu is not None:
2823            for menu in self._applications_menu.GetMenuItems():
2824                if self._current_perspective is not None:
2825                    name = self._current_perspective.sub_menu
2826                    if menu.IsCheckable():
2827                        if menu.GetLabel() == name:
2828                            menu.Check(True)
2829                        else:
2830                            menu.Check(False) 
2831           
2832    def set_plotpanel_floating(self, event=None):
2833        """
2834        make the plot panel floatable
2835        """
2836       
2837        self.__gui_style &= (~GUIFRAME.FIXED_PANEL)
2838        self.__gui_style |= GUIFRAME.FLOATING_PANEL
2839        plot_panel = []
2840        id = event.GetId()
2841        menu = self._window_menu.FindItemById(id)
2842        if self._plotting_plugin is not None:
2843            plot_panel = self.plot_panels.values()
2844            for p in plot_panel:
2845                self._popup_floating_panel(p)
2846            menu.Check(True)
2847           
2848    def set_plotpanel_fixed(self, event=None):
2849        """
2850        make the plot panel fixed
2851        """
2852        self.__gui_style &= (~GUIFRAME.FLOATING_PANEL)
2853        self.__gui_style |= GUIFRAME.FIXED_PANEL
2854        plot_panel = []
2855        id = event.GetId()
2856        menu = self._window_menu.FindItemById(id)
2857        if self._plotting_plugin is not None:
2858            plot_panel = self.plot_panels.values()
2859            for p in plot_panel:
2860                self._popup_fixed_panel(p)
2861            menu.Check(True)
2862           
2863    def on_cleanup_dock(self, event=None):     
2864        """
2865        Set Cleanup Dock option
2866        """
2867        if event == None:
2868            return
2869        id = event.GetId()
2870        menu = self._window_menu.FindItemById(id)
2871        Flag = self.cleanup_plots
2872        if not Flag:
2873            menu.Check(True)
2874            self.cleanup_plots = True
2875            msg = "Cleanup-Dock option set to 'ON'."
2876        else:
2877            menu.Check(False)
2878            self.cleanup_plots = False
2879            msg = "Cleanup-Dock option set to 'OFF'."
2880
2881        wx.PostEvent(self, StatusEvent(status= msg))
2882         
2883    def _popup_fixed_panel(self, p):
2884        """
2885        """
2886        style = self.__gui_style & GUIFRAME.FIXED_PANEL
2887        if style == GUIFRAME.FIXED_PANEL:
2888            pane = self._mgr.GetPane(p.window_name)
2889            pane.Dock()
2890            pane.Floatable()
2891            pane.Right()
2892            pane.TopDockable(False)
2893            pane.BottomDockable(False)
2894            pane.LeftDockable(False)
2895            pane.RightDockable(True)
2896            self._mgr.Update()
2897           
2898    def _popup_floating_panel(self, p):
2899        """
2900        """
2901        style = self.__gui_style &  GUIFRAME.FLOATING_PANEL
2902        if style == GUIFRAME.FLOATING_PANEL: 
2903            pane = self._mgr.GetPane(p.window_name)
2904            pane.Floatable(True)
2905            pane.Float()
2906            pane.Dockable(False)
2907            self._mgr.Update()
2908           
2909    def enable_add_data(self, new_plot):
2910        """
2911        Enable append data on a plot panel
2912        """
2913
2914        if self.panel_on_focus not in self._plotting_plugin.plot_panels.values():
2915            return
2916        is_theory = len(self.panel_on_focus.plots) <= 1 and \
2917            self.panel_on_focus.plots.values()[0].__class__.__name__ == "Theory1D"
2918           
2919        is_data2d = hasattr(new_plot, 'data')
2920       
2921        is_data1d = self.panel_on_focus.__class__.__name__ == "ModelPanel1D"\
2922            and self.panel_on_focus.group_id is not None
2923        has_meta_data = hasattr(new_plot, 'meta_data')
2924       
2925        #disable_add_data if the data is being recovered from  a saved state file.
2926        is_state_data = False
2927        if has_meta_data:
2928            if 'invstate' in new_plot.meta_data: 
2929                is_state_data = True
2930            if  'prstate' in new_plot.meta_data: 
2931                is_state_data = True
2932            if  'fitstate' in new_plot.meta_data: 
2933                is_state_data = True
2934   
2935        return is_data1d and not is_data2d and not is_theory and not is_state_data
2936   
2937    def check_multimode(self, perspective=None):
2938        """
2939        Check the perspective have batch mode capablitity
2940        """
2941        if perspective == None or self._data_panel == None:
2942            return
2943        flag = perspective.get_batch_capable()
2944        flag_on = perspective.batch_on
2945        if flag:
2946            self._data_panel.rb_single_mode.SetValue(not flag_on)
2947            self._data_panel.rb_batch_mode.SetValue(flag_on)
2948        else:
2949            self._data_panel.rb_single_mode.SetValue(True)
2950            self._data_panel.rb_batch_mode.SetValue(False)
2951        self._data_panel.rb_single_mode.Enable(flag)
2952        self._data_panel.rb_batch_mode.Enable(flag)
2953               
2954
2955   
2956    def enable_edit_menu(self):
2957        """
2958        enable menu item under edit menu depending on the panel on focus
2959        """
2960        if self.cpanel_on_focus is not None and self._edit_menu is not None:
2961            flag = self.cpanel_on_focus.get_undo_flag()
2962            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
2963            flag = self.cpanel_on_focus.get_redo_flag()
2964            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
2965            flag = self.cpanel_on_focus.get_copy_flag()
2966            self._edit_menu.Enable(GUIFRAME_ID.COPY_ID, flag)
2967            flag = self.cpanel_on_focus.get_paste_flag()
2968            self._edit_menu.Enable(GUIFRAME_ID.PASTE_ID, flag)
2969            #flag = self.cpanel_on_focus.get_print_flag()
2970            #self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
2971            flag = self.cpanel_on_focus.get_preview_flag()
2972            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
2973            flag = self.cpanel_on_focus.get_reset_flag()
2974            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
2975        else:
2976            flag = False
2977            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
2978            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
2979            self._edit_menu.Enable(GUIFRAME_ID.COPY_ID, flag)
2980            self._edit_menu.Enable(GUIFRAME_ID.PASTE_ID, flag)
2981            #self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
2982            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
2983            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
2984           
2985    def on_undo_panel(self, event=None):
2986        """
2987        undo previous action of the last panel on focus if possible
2988        """
2989        if self.cpanel_on_focus is not None:
2990            self.cpanel_on_focus.on_undo(event)
2991           
2992    def on_redo_panel(self, event=None):
2993        """
2994        redo the last cancel action done on the last panel on focus
2995        """
2996        if self.cpanel_on_focus is not None:
2997            self.cpanel_on_focus.on_redo(event)
2998           
2999    def on_copy_panel(self, event=None):
3000        """
3001        copy the last panel on focus if possible
3002        """
3003        if self.cpanel_on_focus is not None:
3004            self.cpanel_on_focus.on_copy(event)
3005           
3006    def on_paste_panel(self, event=None):
3007        """
3008        paste clipboard to the last panel on focus
3009        """
3010        if self.cpanel_on_focus is not None:
3011            self.cpanel_on_focus.on_paste(event)
3012                   
3013    def on_bookmark_panel(self, event=None):
3014        """
3015        bookmark panel
3016        """
3017        if self.cpanel_on_focus is not None:
3018            self.cpanel_on_focus.on_bookmark(event)
3019           
3020    def append_bookmark(self, event=None):
3021        """
3022        Bookmark available information of the panel on focus
3023        """
3024        self._toolbar.append_bookmark(event)
3025           
3026    def on_save_panel(self, event=None):
3027        """
3028        save possible information on the current panel
3029        """
3030        if self.cpanel_on_focus is not None:
3031            self.cpanel_on_focus.on_save(event)
3032           
3033    def on_preview_panel(self, event=None):
3034        """
3035        preview information on the panel on focus
3036        """
3037        if self.cpanel_on_focus is not None:
3038            self.cpanel_on_focus.on_preview(event)
3039           
3040    def on_print_panel(self, event=None):
3041        """
3042        print available information on the last panel on focus
3043        """
3044        if self.cpanel_on_focus is not None:
3045            self.cpanel_on_focus.on_print(event)
3046           
3047    def on_zoom_panel(self, event=None):
3048        """
3049        zoom on the current panel if possible
3050        """
3051        if self.cpanel_on_focus is not None:
3052            self.cpanel_on_focus.on_zoom(event)
3053           
3054    def on_zoom_in_panel(self, event=None):
3055        """
3056        zoom in of the panel on focus
3057        """
3058        if self.cpanel_on_focus is not None:
3059            self.cpanel_on_focus.on_zoom_in(event)
3060           
3061    def on_zoom_out_panel(self, event=None):
3062        """
3063        zoom out on the panel on focus
3064        """
3065        if self.cpanel_on_focus is not None:
3066            self.cpanel_on_focus.on_zoom_out(event)
3067           
3068    def on_drag_panel(self, event=None):
3069        """
3070        drag apply to the panel on focus
3071        """
3072        if self.cpanel_on_focus is not None:
3073            self.cpanel_on_focus.on_drag(event)
3074           
3075    def on_reset_panel(self, event=None):
3076        """
3077        reset the current panel
3078        """
3079        if self.cpanel_on_focus is not None:
3080            self.cpanel_on_focus.on_reset(event)
3081           
3082    def on_change_caption(self, name, old_caption, new_caption):     
3083        """
3084        Change the panel caption
3085       
3086        :param name: window_name of the pane
3087        :param old_caption: current caption [string]
3088        :param new_caption: new caption [string]
3089        """
3090        # wx.aui.AuiPaneInfo
3091        pane_info = self.get_paneinfo(name) 
3092        # update the data_panel.cb_plotpanel
3093        if 'data_panel' in self.panels.keys():
3094            # remove from data_panel combobox
3095            data_panel = self.panels["data_panel"]
3096            if data_panel.cb_plotpanel is not None:
3097                # Check if any panel has the same caption
3098                has_newstring = data_panel.cb_plotpanel.FindString\
3099                                                            (str(new_caption)) 
3100                caption = new_caption
3101                if has_newstring != wx.NOT_FOUND:
3102                    captions = self._get_plotpanel_captions()
3103                    # Append nummber
3104                    inc = 1
3105                    while (1):
3106                        caption = new_caption + '_%s'% str(inc)
3107                        if caption not in captions:
3108                            break
3109                        inc += 1
3110                    # notify to users
3111                    msg = "Found Same Title: Added '_%s'"% str(inc)
3112                    wx.PostEvent(self, StatusEvent(status=msg))
3113                # update data_panel cb
3114                pos = data_panel.cb_plotpanel.FindString(str(old_caption)) 
3115                if pos != wx.NOT_FOUND:
3116                    data_panel.cb_plotpanel.SetString(pos, caption)
3117                    data_panel.cb_plotpanel.SetStringSelection(caption)
3118        # update window Show menu
3119        if self._window_menu != None:
3120            for item in self._window_menu.GetMenuItems():
3121                pos = self._window_menu.FindItem(old_caption)
3122                if self._window_menu.GetLabel(pos) == str(old_caption):
3123                    self._window_menu.SetLabel(pos, caption)
3124                break
3125        # New Caption
3126        pane_info.Caption(caption)
3127        # update aui manager
3128        self._mgr.Update()
3129        return caption
3130       
3131    def get_paneinfo(self, name):
3132        """
3133        Get pane Caption from window_name
3134       
3135        :param name: window_name in AuiPaneInfo
3136        : return: AuiPaneInfo of the name
3137        """
3138        return self._mgr.GetPane(name) 
3139   
3140    def enable_undo(self):
3141        """
3142        enable undo related control
3143        """
3144        if self.cpanel_on_focus is not None:
3145            self._toolbar.enable_undo(self.cpanel_on_focus)
3146           
3147    def enable_redo(self):
3148        """
3149        enable redo
3150        """
3151        if self.cpanel_on_focus is not None:
3152            self._toolbar.enable_redo(self.cpanel_on_focus)
3153           
3154    def enable_copy(self):
3155        """
3156        enable copy related control
3157        """
3158        if self.cpanel_on_focus is not None:
3159            self._toolbar.enable_copy(self.cpanel_on_focus)
3160           
3161    def enable_paste(self):
3162        """
3163        enable paste
3164        """
3165        if self.cpanel_on_focus is not None:
3166            self._toolbar.enable_paste(self.cpanel_on_focus)
3167                       
3168    def enable_bookmark(self):
3169        """
3170        Bookmark
3171        """
3172        if self.cpanel_on_focus is not None:
3173            self._toolbar.enable_bookmark(self.cpanel_on_focus)
3174           
3175    def enable_save(self):
3176        """
3177        save
3178        """
3179        if self.cpanel_on_focus is not None:
3180            self._toolbar.enable_save(self.cpanel_on_focus)
3181           
3182    def enable_preview(self):
3183        """
3184        preview
3185        """
3186        if self.cpanel_on_focus is not None:
3187            self._toolbar.enable_preview(self.cpanel_on_focus)
3188           
3189    def enable_print(self):
3190        """
3191        print
3192        """
3193        if self.cpanel_on_focus is not None:
3194            self._toolbar.enable_print(self.cpanel_on_focus)
3195           
3196    def enable_zoom(self):
3197        """
3198        zoom
3199        """
3200        if self.cpanel_on_focus is not None:
3201            self._toolbar.enable_zoom(self.panel_on_focus)
3202           
3203    def enable_zoom_in(self):
3204        """
3205        zoom in
3206        """
3207        if self.cpanel_on_focus is not None:
3208            self._toolbar.enable_zoom_in(self.panel_on_focus)
3209           
3210    def enable_zoom_out(self):
3211        """
3212        zoom out
3213        """
3214        if self.cpanel_on_focus is not None:
3215            self._toolbar.enable_zoom_out(self.panel_on_focus)
3216           
3217    def enable_drag(self, event=None):
3218        """
3219        drag
3220        """
3221        #if self.cpanel_on_focus is not None:
3222        #    self._toolbar.enable_drag(self.panel_on_focus)
3223           
3224    def enable_reset(self):
3225        """
3226        reset the current panel
3227        """
3228        if self.cpanel_on_focus is not None:
3229            self._toolbar.enable_reset(self.panel_on_focus)
3230
3231    def set_schedule_full_draw(self, panel=None, func='del'):
3232        """
3233        Add/subtract the schedule full draw list with the panel given
3234       
3235        :param panel: plot panel
3236        :param func: append or del [string]
3237        """
3238
3239        # append this panel in the schedule list if not in yet
3240        if func == 'append':
3241            if not panel in self.schedule_full_draw_list:
3242                self.schedule_full_draw_list.append(panel) 
3243        # remove this panel from schedule list
3244        elif func == 'del':
3245            if len(self.schedule_full_draw_list) > 0:
3246                if panel in self.schedule_full_draw_list:
3247                    self.schedule_full_draw_list.remove(panel)
3248
3249        # reset the schdule
3250        if len(self.schedule_full_draw_list) == 0:
3251            self.schedule = False
3252        else:
3253            self.schedule = True   
3254       
3255    def full_draw(self):
3256        """
3257        Draw the panels with axes in the schedule to full dwar list
3258        """
3259        count = len(self.schedule_full_draw_list)
3260        #if not self.schedule:
3261        if count < 1:
3262            self.set_schedule(False)
3263            return
3264        else:
3265            ind = 0
3266            # if any of the panel is shown do full_draw
3267            for panel in self.schedule_full_draw_list:
3268                ind += 1
3269                if self._mgr.GetPane(panel.window_name).IsShown():
3270                    break
3271                # otherwise, return
3272                if ind == count:
3273                    return
3274
3275        #Simple redraw only for a panel shown
3276        def f_draw(panel):
3277            """
3278            Draw A panel in the full dwar list
3279            """
3280            try:
3281                # This checking of GetCapture is to stop redrawing
3282                # while any panel is capture.
3283                if self.GetCapture() == None:
3284                    # draw if possible
3285                    panel.set_resizing(False)
3286                    panel.Show(False)
3287                    panel.draw_plot()
3288                   
3289                    # Check if the panel is not shown
3290                    if not self._mgr.GetPane(panel.window_name).IsShown():
3291                        self._mgr.GetPane(panel.window_name).Hide()
3292                    else:
3293                        panel.Show(True)
3294            except:
3295                pass
3296       
3297        # Draw all panels       
3298        map(f_draw, self.schedule_full_draw_list)
3299       
3300        # Reset the attr 
3301        if len(self.schedule_full_draw_list) == 0:
3302            self.set_schedule(False)
3303        else:
3304            self.set_schedule(True)
3305        # do not update mgr
3306        #self._mgr.Update()
3307       
3308    def set_schedule(self, schedule=False): 
3309        """
3310        Set schedule
3311        """
3312        self.schedule = schedule
3313               
3314    def get_schedule(self): 
3315        """
3316        Get schedule
3317        """
3318        return self.schedule
3319   
3320    def on_set_plot_focus(self, panel):
3321        """
3322        Set focus on a plot panel
3323        """
3324        self.set_plot_unfocus()
3325        panel.on_set_focus(None) 
3326        # set focusing panel
3327        self.panel_on_focus = panel 
3328        self.set_panel_on_focus(None)
3329
3330    def set_plot_unfocus(self): 
3331        """
3332        Un focus all plot panels
3333        """
3334        for plot in self.plot_panels.values():
3335            plot.on_kill_focus(None)
3336   
3337    def get_window_size(self):
3338        """
3339        Get window size
3340       
3341        :return size: tuple
3342        """
3343        width, height = self.GetSizeTuple()
3344        if not IS_WIN:
3345            # Subtract toolbar height to get real window side
3346            if self._toolbar.IsShown():
3347                height -= 45
3348        return (width, height)
3349           
3350    def _onDrawIdle(self, *args, **kwargs):
3351        """
3352        ReDraw with axes
3353        """
3354        try:
3355            # check if it is time to redraw
3356            if self.GetCapture() == None:
3357                # Draw plot, changes resizing too
3358                self.full_draw()
3359        except:
3360            pass
3361           
3362        # restart idle       
3363        self._redraw_idle(*args, **kwargs)
3364
3365           
3366    def _redraw_idle(self, *args, **kwargs):
3367        """
3368        Restart Idle
3369        """
3370        # restart idle   
3371        self.idletimer.Restart(100*TIME_FACTOR, *args, **kwargs)
3372
3373       
3374class DefaultPanel(wx.Panel, PanelBase):
3375    """
3376    Defines the API for a panels to work with
3377    the GUI manager
3378    """
3379    ## Internal nickname for the window, used by the AUI manager
3380    window_name = "default"
3381    ## Name to appear on the window title bar
3382    window_caption = "Welcome panel"
3383    ## Flag to tell the AUI manager to put this panel in the center pane
3384    CENTER_PANE = True
3385    def __init__(self, parent, *args, **kwds):
3386        wx.Panel.__init__(self, parent, *args, **kwds)
3387        PanelBase.__init__(self, parent)
3388   
3389
3390
3391class ViewApp(wx.App):
3392    """
3393    Toy application to test this Frame
3394    """
3395    def OnInit(self):
3396        """
3397        When initialised
3398        """
3399        pos, size, self.is_max = self.window_placement((GUIFRAME_WIDTH, 
3400                                           GUIFRAME_HEIGHT))     
3401        self.frame = ViewerFrame(parent=None, 
3402                             title=APPLICATION_NAME, 
3403                             pos=pos, 
3404                             gui_style = DEFAULT_STYLE,
3405                             size=size)
3406        self.frame.Hide()
3407        self.s_screen = None
3408
3409        try:
3410            self.open_file()
3411        except:
3412            msg = "%s Could not load " % str(APPLICATION_NAME)
3413            msg += "input file from command line.\n"
3414            logging.error(msg)
3415        # Display a splash screen on top of the frame.
3416        try:
3417            if os.path.isfile(SPLASH_SCREEN_PATH):
3418                self.s_screen = self.display_splash_screen(parent=self.frame, 
3419                                        path=SPLASH_SCREEN_PATH)
3420            else:
3421                self.frame.Show()   
3422        except:
3423            if self.s_screen is not None:
3424                self.s_screen.Close()
3425            msg = "Cannot display splash screen\n"
3426            msg += str (sys.exc_value)
3427            logging.error(msg)
3428            self.frame.Show()
3429 
3430        #if hasattr(self.frame, 'special'):
3431        #    self.frame.special.SetCurrent()
3432        self.SetTopWindow(self.frame)
3433 
3434        return True
3435   
3436    def maximize_win(self):
3437        """
3438        Maximize the window after the frame shown
3439        """
3440        if self.is_max:
3441            if self.frame.IsShown():
3442                # Max window size
3443                self.frame.Maximize(self.is_max)
3444
3445    def open_file(self):
3446        """
3447        open a state file at the start of the application
3448        """
3449        input_file = None
3450        if len(sys.argv) >= 2:
3451            cmd = sys.argv[0].lower()
3452            basename  = os.path.basename(cmd)
3453            app_base = str(APPLICATION_NAME).lower()
3454            if os.path.isfile(cmd) or basename.lower() == app_base:
3455                app_py = app_base + '.py'
3456                app_exe = app_base + '.exe'
3457                app_app = app_base + '.app'
3458                if basename.lower() in [app_py, app_exe, app_app, app_base]:
3459                    data_base = sys.argv[1]
3460                    input_file = os.path.normpath(os.path.join(DATAPATH, 
3461                                                               data_base))
3462        if input_file is None:
3463            return
3464        if self.frame is not None:
3465            self.frame.set_input_file(input_file=input_file)
3466         
3467    def clean_plugin_models(self, path): 
3468        """
3469        Delete plugin models  in app folder
3470       
3471        :param path: path of the plugin_models folder in app
3472        """
3473        # do it only the first time app loaded
3474        # delete unused model folder   
3475        model_folder = os.path.join(PATH_APP, path)
3476        if os.path.exists(model_folder) and os.path.isdir(model_folder):
3477            if len(os.listdir(model_folder)) > 0:
3478                try:
3479                    for file in os.listdir(model_folder):
3480                        file_path = os.path.join(model_folder, file)
3481                        if os.path.isfile(file_path):
3482                            os.remove(file_path)
3483                except:
3484                    logging.error("gui_manager.clean_plugin_models:\n  %s" \
3485                                  % sys.exc_value)
3486             
3487    def set_manager(self, manager):
3488        """
3489        Sets a reference to the application manager
3490        of the GUI manager (Frame)
3491        """
3492        self.frame.set_manager(manager)
3493       
3494    def build_gui(self):
3495        """
3496        Build the GUI
3497        """
3498        #try to load file at the start
3499        try:
3500            self.open_file()
3501        except:
3502            raise
3503        self.frame.build_gui()
3504        #if self.s_screen is not None and self.s_screen.IsShown():
3505        #    self.s_screen.Close()
3506       
3507    def set_welcome_panel(self, panel_class):
3508        """
3509        Set the welcome panel
3510       
3511        :param panel_class: class of the welcome panel to be instantiated
3512       
3513        """
3514        self.frame.set_welcome_panel(panel_class)
3515       
3516    def add_perspective(self, perspective):
3517        """
3518        Manually add a perspective to the application GUI
3519        """
3520        self.frame.add_perspective(perspective)
3521   
3522    def window_placement(self, size):
3523        """
3524        Determines the position and size of the application frame such that it
3525        fits on the user's screen without obstructing (or being obstructed by)
3526        the Windows task bar.  The maximum initial size in pixels is bounded by
3527        WIDTH x HEIGHT.  For most monitors, the application
3528        will be centered on the screen; for very large monitors it will be
3529        placed on the left side of the screen.
3530        """
3531        is_maximized = False
3532        # Get size of screen without
3533        for screenCount in range(wx.Display().GetCount()):
3534            screen = wx.Display(screenCount)
3535            if screen.IsPrimary():
3536                displayRect = screen.GetClientArea()
3537                break
3538       
3539        posX, posY, displayWidth, displayHeight = displayRect       
3540        customWidth, customHeight = size
3541       
3542        # If the custom size is default, set 90% of the screen size
3543        if customWidth <= 0 and customHeight <= 0:
3544            if customWidth == 0 and customHeight == 0:
3545                is_maximized = True
3546            customWidth = displayWidth * 0.9
3547            customHeight = displayHeight * 0.9
3548        else:
3549            # If the custom screen is bigger than the
3550            # window screen than make maximum size
3551            if customWidth > displayWidth:
3552                customWidth = displayWidth
3553            if customHeight > displayHeight:
3554                customHeight = displayHeight
3555           
3556        # Note that when running Linux and using an Xming (X11) server on a PC
3557        # with a dual  monitor configuration, the reported display size may be
3558        # that of both monitors combined with an incorrect display count of 1.
3559        # To avoid displaying this app across both monitors, we check for
3560        # screen 'too big'.  If so, we assume a smaller width which means the
3561        # application will be placed towards the left hand side of the screen.
3562       
3563        # If dual screen registered as 1 screen. Make width half.
3564        # MAC just follows the default behavior of pos
3565        if IS_WIN:
3566            if displayWidth > (displayHeight*2):
3567                if (customWidth == displayWidth):
3568                    customWidth = displayWidth/2
3569                # and set the position to be the corner of the screen.
3570                posX = 0
3571                posY = 0
3572               
3573            # Make the position the middle of the screen. (Not 0,0)
3574            else:
3575                posX = (displayWidth - customWidth)/2
3576                posY = (displayHeight - customHeight)/2
3577       
3578        # Return the suggested position and size for the application frame.   
3579        return (posX, posY), (customWidth, customHeight), is_maximized
3580
3581   
3582    def display_splash_screen(self, parent, 
3583                              path=SPLASH_SCREEN_PATH):
3584        """Displays the splash screen.  It will exactly cover the main frame."""
3585       
3586        # Prepare the picture.  On a 2GHz intel cpu, this takes about a second.
3587        image = wx.Image(path, wx.BITMAP_TYPE_PNG)
3588        image.Rescale(SPLASH_SCREEN_WIDTH, 
3589                      SPLASH_SCREEN_HEIGHT, wx.IMAGE_QUALITY_HIGH)
3590        bm = image.ConvertToBitmap()
3591
3592        # Create and show the splash screen.  It will disappear only when the
3593        # program has entered the event loop AND either the timeout has expired
3594        # or the user has left clicked on the screen.  Thus any processing
3595        # performed in this routine (including sleeping) or processing in the
3596        # calling routine (including doing imports) will prevent the splash
3597        # screen from disappearing.
3598        #
3599        # Note that on Linux, the timeout appears to occur immediately in which
3600        # case the splash screen disappears upon entering the event loop.
3601        s_screen = wx.SplashScreen(bitmap=bm,
3602                         splashStyle=(wx.SPLASH_TIMEOUT|
3603                                              wx.SPLASH_CENTRE_ON_SCREEN),
3604                                 style=(wx.SIMPLE_BORDER|
3605                                        wx.FRAME_NO_TASKBAR|
3606                                        wx.STAY_ON_TOP),
3607                                       
3608                        milliseconds=SS_MAX_DISPLAY_TIME,
3609                        parent=parent,
3610                        id=wx.ID_ANY)
3611        from sans.guiframe.gui_statusbar import SPageStatusbar
3612        statusBar = SPageStatusbar(s_screen)
3613        s_screen.SetStatusBar(statusBar)
3614        s_screen.Bind(wx.EVT_CLOSE, self.on_close_splash_screen)
3615        s_screen.Show()
3616        return s_screen
3617       
3618       
3619    def on_close_splash_screen(self, event):
3620        """
3621        When the splash screen is closed.
3622        """
3623        self.frame.Show(True)
3624        event.Skip()
3625        self.maximize_win()
3626
3627if __name__ == "__main__": 
3628    app = ViewApp(0)
3629    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.