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

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

Working on cat path for standalone

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