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

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 df7a7e3 was df7a7e3, checked in by Mathieu Doucet <doucetm@…>, 12 years ago

merging category branch

  • Property mode set to 100644
File size: 140.5 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        CategoryManager(self, -1, 'Model Category Manager')
1421
1422    def _on_preference_menu(self, event):     
1423        """
1424        Build a panel to allow to edit Mask
1425        """
1426       
1427        from sans.guiframe.startup_configuration \
1428        import StartupConfiguration as ConfDialog
1429       
1430        self.panel = ConfDialog(parent=self, gui=self.__gui_style)
1431        self.panel.ShowModal()
1432        #wx.PostEvent(self.parent, event)
1433       
1434
1435    def _add_menu_window(self):
1436        """
1437        add a menu window to the menu bar
1438        Window menu
1439        Attach a menu item for each panel in our
1440        panel list that also appears in a plug-in.
1441       
1442        Only add the panel menu if there is only one perspective and
1443        it has more than two panels.
1444        Note: the first plug-in is always the plotting plug-in.
1445        The first application
1446        #plug-in is always the second one in the list.
1447        """
1448        self._window_menu = wx.Menu()
1449        if self._plotting_plugin is not None:
1450            for (menu, name) in self._plotting_plugin.populate_menu(self):
1451                self._window_menu.AppendSubMenu(menu, name)
1452        self._menubar.Append(self._window_menu, '&Graph')
1453
1454        style = self.__gui_style & GUIFRAME.PLOTTING_ON
1455        if style == GUIFRAME.PLOTTING_ON:
1456           
1457            self._window_menu.AppendSeparator()
1458            id = wx.NewId()
1459            hint = "Hide all the graph panels"
1460            self._window_menu.Append(id, '&Hide  All', hint)
1461            wx.EVT_MENU(self, id, self.hide_all_plotpanels)
1462            id = wx.NewId()
1463            hint = "Show all the graph panels"
1464            self._window_menu.Append(id, '&Show All', hint)
1465            wx.EVT_MENU(self, id, self.show_all_plotpanels)
1466           
1467            self._window_menu.AppendSeparator()
1468            id = wx.NewId()
1469            preferences_menu = wx.Menu()
1470            hint = "All plot panels will floating"
1471            preferences_menu.AppendRadioItem(id, '&Float All', hint)
1472            wx.EVT_MENU(self, id, self.set_plotpanel_floating)
1473            style = self.__gui_style & GUIFRAME.FLOATING_PANEL
1474            f_menu = preferences_menu.FindItemById(id)
1475            if style == GUIFRAME.FLOATING_PANEL: 
1476                f_checked = True
1477            else:
1478                f_checked = False
1479            f_menu.Check(f_checked)
1480
1481            id = wx.NewId()
1482            hint = "All plot panels will displayed within the frame"
1483            preferences_menu.AppendRadioItem(id, '&Dock All', hint)
1484            wx.EVT_MENU(self, id, self.set_plotpanel_fixed) 
1485            if not f_checked:
1486                d_menu = preferences_menu.FindItemById(id)
1487                d_menu.Check(True)
1488            preferences_menu.AppendSeparator()
1489            id = wx.NewId()
1490            hint = "Clean up the dock area for plots on new-plot"
1491            preferences_menu.AppendCheckItem(id, '&CleanUp Dock on NewPlot', 
1492                                             hint)
1493            wx.EVT_MENU(self, id, self.on_cleanup_dock)
1494            flag = self.cleanup_plots
1495            if self.cleanup_plots:
1496                c_menu = preferences_menu.FindItemById(id)
1497                c_menu.Check(True) 
1498            self._window_menu.AppendSubMenu(preferences_menu,'&Preferences')
1499        if self._window_menu.GetMenuItemCount() == 0:
1500            pos = self._menubar.FindMenu('Graph')
1501            self._menubar.Remove(pos)
1502        #wx.EVT_MENU(self, id, self.show_preferences_panel)   
1503        #if len(self.plugins) == 2:
1504        #    plug = self.plugins[1]
1505        #    pers = plug.get_perspective()
1506        #
1507        #    if len(pers) > 1:
1508        #        self._window_menu = wx.Menu()
1509        #        for item in self.panels:
1510        #            if item == 'default':
1511        #                continue
1512        #            panel = self.panels[item]
1513        #            if panel.window_name in pers:
1514        #                self._window_menu.Append(int(item),
1515        #                                          panel.window_caption,
1516        #                                "Show %s window" % panel.window_caption)
1517        #                wx.EVT_MENU(self, int(item), self.on_view)
1518        #        self._menubar.Append(self._window_menu, '&Window')
1519
1520               
1521    def _add_menu_application(self):
1522        """
1523        # Attach a menu item for each defined perspective or application.
1524        # Only add the perspective menu if there are more than one perspectives
1525        add menu application
1526        """
1527        #style = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
1528        #if style == GUIFRAME.MULTIPLE_APPLICATIONS:
1529        if self._num_perspectives  > 1:
1530            plug_data_count = False
1531            plug_no_data_count = False
1532            self._applications_menu = wx.Menu()
1533            pos = 0
1534            separator = self._applications_menu.AppendSeparator()
1535            for plug in self.plugins:
1536                if len(plug.get_perspective()) > 0:
1537                    id = wx.NewId()
1538                    if plug.use_data():
1539                       
1540                        self._applications_menu.InsertCheckItem(pos, id, plug.sub_menu,
1541                                      "Switch to analysis: %s" % plug.sub_menu)
1542                        plug_data_count = True
1543                        pos += 1
1544                    else:
1545                        plug_no_data_count = True
1546                        self._applications_menu.AppendCheckItem(id, plug.sub_menu,
1547                                      "Switch to analysis: %s" % plug.sub_menu)
1548                    wx.EVT_MENU(self, id, plug.on_perspective)
1549            #self._applications_menu.
1550            if (not plug_data_count or not plug_no_data_count):
1551                self._applications_menu.RemoveItem(separator)
1552            self._menubar.Append(self._applications_menu, '&Analysis')
1553            self._check_applications_menu()
1554           
1555    def _populate_file_menu(self):
1556        """
1557        Insert menu item under file menu
1558        """
1559        for plugin in self.plugins:
1560            if len(plugin.populate_file_menu()) > 0:
1561                for item in plugin.populate_file_menu():
1562                    m_name, m_hint, m_handler = item
1563                    id = wx.NewId()
1564                    self._file_menu.Append(id, m_name, m_hint)
1565                    wx.EVT_MENU(self, id, m_handler)
1566                self._file_menu.AppendSeparator()
1567               
1568    def _add_menu_file(self):
1569        """
1570        add menu file
1571        """
1572       
1573        # File menu
1574        self._file_menu = wx.Menu()
1575        #append item from plugin under menu file if necessary
1576        self._populate_file_menu()
1577        style1 = self.__gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
1578        if OPEN_SAVE_MENU:
1579            id = wx.NewId()
1580            hint_load_file = "read all analysis states saved previously"
1581            self._save_appl_menu = self._file_menu.Append(id, 
1582                                    '&Open Project', hint_load_file)
1583            wx.EVT_MENU(self, id, self._on_open_state_project)
1584           
1585        if style1 == GUIFRAME.MULTIPLE_APPLICATIONS:
1586            # some menu of plugin to be seen under file menu
1587            hint_load_file = "Read a status files and load"
1588            hint_load_file += " them into the analysis"
1589            id = wx.NewId()
1590            self._save_appl_menu = self._file_menu.Append(id, 
1591                                    '&Open Analysis', hint_load_file)
1592            wx.EVT_MENU(self, id, self._on_open_state_application)
1593        if OPEN_SAVE_MENU:       
1594            self._file_menu.AppendSeparator()
1595            id = wx.NewId()
1596            self._file_menu.Append(id, '&Save Project',
1597                                 'Save the state of the whole analysis')
1598            wx.EVT_MENU(self, id, self._on_save_project)
1599        if style1 == GUIFRAME.MULTIPLE_APPLICATIONS:
1600            #self._file_menu.AppendSeparator()
1601            id = wx.NewId()
1602            self._save_appl_menu = self._file_menu.Append(id, 
1603                                                      '&Save Analysis',
1604                        'Save state of the current active analysis panel')
1605            wx.EVT_MENU(self, id, self._on_save_application)
1606            self._file_menu.AppendSeparator()
1607       
1608        id = wx.NewId()
1609        self._file_menu.Append(id, '&Quit', 'Exit') 
1610        wx.EVT_MENU(self, id, self.Close)
1611        # Add sub menus
1612        self._menubar.Append(self._file_menu, '&File')
1613       
1614    def _add_menu_edit(self):
1615        """
1616        add menu edit
1617        """
1618        if not EDIT_MENU:
1619            return
1620        # Edit Menu
1621        self._edit_menu = wx.Menu()
1622        self._edit_menu.Append(GUIFRAME_ID.UNDO_ID, '&Undo', 
1623                               'Undo the previous action')
1624        wx.EVT_MENU(self, GUIFRAME_ID.UNDO_ID, self.on_undo_panel)
1625        self._edit_menu.Append(GUIFRAME_ID.REDO_ID, '&Redo', 
1626                               'Redo the previous action')
1627        wx.EVT_MENU(self, GUIFRAME_ID.REDO_ID, self.on_redo_panel)
1628        self._edit_menu.AppendSeparator()
1629        self._edit_menu.Append(GUIFRAME_ID.COPY_ID, '&Copy Params', 
1630                               'Copy parameter values')
1631        wx.EVT_MENU(self, GUIFRAME_ID.COPY_ID, self.on_copy_panel)
1632        self._edit_menu.Append(GUIFRAME_ID.PASTE_ID, '&Paste Params', 
1633                               'Paste parameter values')
1634        wx.EVT_MENU(self, GUIFRAME_ID.PASTE_ID, self.on_paste_panel)
1635        self._edit_menu.AppendSeparator()
1636       
1637        self._edit_menu.Append(GUIFRAME_ID.PREVIEW_ID, '&Report Results',
1638                               'Preview current panel')
1639        wx.EVT_MENU(self, GUIFRAME_ID.PREVIEW_ID, self.on_preview_panel)
1640        #self._edit_menu.Append(GUIFRAME_ID.PRINT_ID, '&Print',
1641        #                       'Print current panel')
1642        #wx.EVT_MENU(self, GUIFRAME_ID.PRINT_ID, self.on_print_panel)
1643        self._edit_menu.Append(GUIFRAME_ID.RESET_ID, '&Reset Page', 
1644                               'Reset current panel')
1645        wx.EVT_MENU(self, GUIFRAME_ID.RESET_ID, self.on_reset_panel)
1646   
1647        self._menubar.Append(self._edit_menu,  '&Edit')
1648        self.enable_edit_menu()
1649       
1650    def get_style(self):
1651        """
1652        Return the gui style
1653        """
1654        return  self.__gui_style
1655   
1656    def _add_menu_data(self):
1657        """
1658        Add menu item item data to menu bar
1659        """
1660        if self._data_plugin is not None:
1661            menu_list = self._data_plugin.populate_menu(self)
1662            if menu_list:
1663                for (menu, name) in menu_list:
1664                    self._menubar.Append(menu, name)
1665       
1666                       
1667    def _on_toggle_toolbar(self, event=None):
1668        """
1669        hide or show toolbar
1670        """
1671        if self._toolbar is None:
1672            return
1673        if self._toolbar.IsShown():
1674            if self._toolbar_menu is not None:
1675                self._toolbar_menu.SetItemLabel('Show Toolbar')
1676            self._toolbar.Hide()
1677        else:
1678            if self._toolbar_menu is not None:
1679                self._toolbar_menu.SetItemLabel('Hide Toolbar')
1680            self._toolbar.Show()
1681        self._toolbar.Realize()
1682       
1683    def _on_status_event(self, evt):
1684        """
1685        Display status message
1686        """
1687        # This CallAfter fixes many crashes on MAC.
1688        wx.CallAfter(self.sb.set_status, evt)
1689       
1690    def on_view(self, evt):
1691        """
1692        A panel was selected to be shown. If it's not already
1693        shown, display it.
1694       
1695        :param evt: menu event
1696       
1697        """
1698        panel_id = str(evt.GetId())
1699        self.on_set_plot_focus(self.panels[panel_id])
1700        self.show_panel(evt.GetId(), 'on')     
1701        wx.CallLater(5*TIME_FACTOR, self.set_schedule(True))
1702        self.set_plot_unfocus()
1703       
1704    def on_close_welcome_panel(self):
1705        """
1706        Close the welcome panel
1707        """
1708        if self.defaultPanel is None:
1709            return 
1710        default_panel = self._mgr.GetPane(self.panels["default"].window_name)
1711        if default_panel.IsShown():
1712            default_panel.Hide()
1713            # Recover current perspective
1714            perspective = self._current_perspective
1715            perspective.on_perspective(event=None)
1716            self._mgr.Update()
1717            # Show toolbar
1718            #style = self.__gui_style & GUIFRAME.TOOLBAR_ON
1719            #if (style == GUIFRAME.TOOLBAR_ON) & (not self._toolbar.IsShown()):
1720            #    self._on_toggle_toolbar()
1721           
1722    def show_welcome_panel(self, event):
1723        """   
1724        Display the welcome panel
1725        """
1726        if self.defaultPanel is None:
1727            return 
1728        for id, panel in self.panels.iteritems():
1729            if id  ==  'default':
1730                # Show default panel
1731                if not self._mgr.GetPane(self.panels["default"].window_name).IsShown():
1732                    self._mgr.GetPane(self.panels["default"].window_name).Show(True)
1733            elif id == "data_panel":
1734                flag = self._mgr.GetPane(self.panels["data_panel"].window_name).IsShown()
1735                self._mgr.GetPane(self.panels["data_panel"].window_name).Show(flag)
1736            elif panel not in self.plot_panels.values() :
1737                self._mgr.GetPane(self.panels[id].window_name).IsShown()
1738                self._mgr.GetPane(self.panels[id].window_name).Hide()
1739        #style = self.__gui_style & GUIFRAME.TOOLBAR_ON
1740        #if (style == GUIFRAME.TOOLBAR_ON) & (self._toolbar.IsShown()):
1741        #    #    self._toolbar.Show(True)
1742        #    self._on_toggle_toolbar()
1743
1744        self._mgr.Update()
1745       
1746    def show_panel(self, uid, show=None):
1747        """
1748        Shows the panel with the given id
1749       
1750        :param uid: unique ID number of the panel to show
1751       
1752        """
1753        ID = str(uid)
1754        config.printEVT("show_panel: %s" % ID)
1755        if ID in self.panels.keys():
1756            if not self._mgr.GetPane(self.panels[ID].window_name).IsShown(): 
1757                if show == 'on':
1758                    self._mgr.GetPane(self.panels[ID].window_name).Show()   
1759                elif self.panels[ID].window_caption.split(" ")[0] == \
1760                                                            "Residuals":
1761                    self._mgr.GetPane(self.panels[ID].window_name).Hide()
1762                else:
1763                    self._mgr.GetPane(self.panels[ID].window_name).Show()
1764                # Hide default panel
1765                self._mgr.GetPane(self.panels["default"].window_name).Hide()
1766        self._mgr.Update()     
1767        self._redraw_idle()
1768
1769    def show_all_plotpanels(self, event):
1770        """
1771        Show all plotpanels shown
1772       
1773        :param event: menu event
1774        """
1775        #event.Skip()
1776        any_hidden = False
1777        for id in self.plot_panels.keys():
1778            if self._mgr.GetPane(self.plot_panels[id].window_name).IsShown():
1779                continue
1780            else:
1781                any_hidden = True
1782                self.show_panel(id)
1783        if not any_hidden:
1784            msg = "No hidden graph panel exists."
1785        else:
1786            # Make sure the Checkmenuitem checked: Need this for-loop \
1787            # because the check menu is not responding on floating panel
1788            if IS_WIN:
1789                try:
1790                    for item in self._plotting_plugin.menu.GetMenuItems():
1791                        item.Check(True)
1792                except:
1793                    # MAC is not using checkmenuitem
1794                    pass
1795            msg = "All graph panels are shown."
1796        wx.PostEvent(self, StatusEvent(status=msg))
1797           
1798    def hide_all_plotpanels(self, event):
1799        """
1800        Hide all plotpanels shown
1801       
1802        :param event: menu event
1803        """
1804        #event.Skip()
1805        any_shown = False
1806        for ID in self.plot_panels.keys():
1807            if self._mgr.GetPane(self.plot_panels[ID].window_name).IsShown():
1808                any_shown = True
1809                try:
1810                    self.hide_panel(ID)
1811                except:
1812                    print "hide_panel: No such plot id %s" % ID
1813            else:
1814                continue
1815        if not any_shown:
1816            msg = "No shown graph panel exists."
1817        else:
1818            # Make sure the Checkmenuitem unchecked: Need this for-loop
1819            # because the check menu is not responding on floating panel
1820            if IS_WIN:
1821                try:
1822                    for item in self._plotting_plugin.menu.GetMenuItems():
1823                        item.Check(False)
1824                except:
1825                    # MAC is not using checkmenuitem
1826                    pass
1827            msg = "All graph panels are hidden."
1828        wx.PostEvent(self, StatusEvent(status=msg))
1829                   
1830    def hide_panel(self, uid):
1831        """
1832        hide panel except default panel
1833        """
1834        ID = str(uid)
1835        caption = self.panels[ID].window_caption
1836        config.printEVT("hide_panel: %s" % ID)
1837        if ID in self.panels.keys():
1838            pane = self._mgr.GetPane(self.panels[ID].window_name)
1839            if pane.IsMaximized():
1840                self._mgr.RestoreMaximizedPane()
1841                self.disable_app_menu(self.panels[ID])
1842            if pane.IsShown():
1843                pane.Hide()
1844                item = self._plotting_plugin.menu.FindItemById(uid)
1845                item.Check(False)
1846                if self._data_panel is not None and \
1847                            ID in self.plot_panels.keys():
1848                    self._data_panel.cb_plotpanel.Append(str(caption), 
1849                                                         self.panels[ID])
1850                # Do not Hide default panel here...
1851                #self._mgr.GetPane(self.panels["default"].window_name).Hide()
1852            wx.CallAfter(self._mgr.Update)
1853            self.cpanel_on_focus.SetFocus()
1854               
1855    def delete_panel(self, uid):
1856        """
1857        delete panel given uid
1858        """
1859        ID = str(uid)
1860        config.printEVT("delete_panel: %s" % ID)
1861        try:
1862            caption = self.panels[ID].window_caption
1863        except:
1864            print "delete_panel: No such plot id as %s" % ID
1865            return
1866        if ID in self.panels.keys():
1867            self.panel_on_focus = None
1868            panel = self.panels[ID]
1869            self._mgr.DetachPane(panel)
1870            self._plotting_plugin.delete_panel(panel.group_id)
1871            panel.Hide()
1872            panel.clear()
1873            panel.Close()
1874            if panel in self.schedule_full_draw_list:
1875                self.schedule_full_draw_list.remove(panel) 
1876           
1877            #delete uid number not str(uid)
1878            if ID in self.plot_panels.keys():
1879                del self.plot_panels[ID]
1880            if ID in self.panels.keys():
1881                del self.panels[ID]
1882            #CallAfter: make sure panel is clear before updating mgr
1883            wx.CallAfter(self._mgr.Update)
1884            return 
1885     
1886    def clear_panel(self):
1887        """
1888        Clear the panel
1889        """
1890        for item in self.panels:
1891            try:
1892                self.panels[item].clear_panel()
1893            except:
1894                pass
1895           
1896    def create_gui_data(self, data, path=None):
1897        """
1898        """
1899        return self._data_manager.create_gui_data(data, path)
1900   
1901    def get_data(self, path):
1902        """
1903        """
1904        message = ""
1905        log_msg = ''
1906        output = []
1907        error_message = ""
1908        basename  = os.path.basename(path)
1909        root, extension = os.path.splitext(basename)
1910        if extension.lower() not in EXTENSIONS:
1911            log_msg = "File Loader cannot "
1912            log_msg += "load: %s\n" % str(basename)
1913            log_msg += "Try Data opening...."
1914            logging.info(log_msg)
1915            print log_msg
1916            #self.load_complete(output=output, error_message=error_message,
1917            #       message=log_msg, path=path)   
1918            return
1919       
1920        #reading a state file
1921        for plug in self.plugins:
1922            reader, ext = plug.get_extensions()
1923            if reader is not None:
1924                #read the state of the single plugin
1925                if extension == ext:
1926                    reader.read(path)
1927                    return
1928                elif extension == APPLICATION_STATE_EXTENSION:
1929                    try:
1930                        reader.read(path)
1931                    except:
1932                        msg = "DataLoader Error: Encounted Non-ASCII character"
1933                        msg += "\n(%s)"% sys.exc_value
1934                        wx.PostEvent(self, StatusEvent(status=msg, 
1935                                                info="error", type="stop"))
1936                        return
1937       
1938        style = self.__gui_style & GUIFRAME.MANAGER_ON
1939        if style == GUIFRAME.MANAGER_ON:
1940            if self._data_panel is not None:
1941                #data_state = self._data_manager.get_selected_data()
1942                #self._data_panel.load_data_list(data_state)
1943                self._mgr.GetPane(self._data_panel.window_name).Show(True)
1944     
1945    def load_from_cmd(self,  path):   
1946        """
1947        load data from cmd or application
1948        """ 
1949        if path is None:
1950            return
1951        else:
1952            path = os.path.abspath(path)
1953            if not os.path.isfile(path) and not os.path.isdir(path):
1954                return
1955           
1956            if os.path.isdir(path):
1957                self.load_folder(path)
1958                return
1959
1960        basename  = os.path.basename(path)
1961        root, extension = os.path.splitext(basename)
1962        if extension.lower() not in EXTENSIONS:
1963            self.load_data(path)
1964        else:
1965            self.load_state(path)
1966
1967        self._default_save_location = os.path.dirname(path)
1968
1969    def load_state(self, path):   
1970        """
1971        load data from command line or application
1972        """
1973        if path and (path is not None) and os.path.isfile(path):
1974            basename  = os.path.basename(path)
1975            if APPLICATION_STATE_EXTENSION is not None \
1976                and basename.endswith(APPLICATION_STATE_EXTENSION):
1977                #Hide current plot_panels i
1978                for ID in self.plot_panels.keys():
1979                    panel = self._mgr.GetPane(self.plot_panels[ID].window_name)
1980                    if panel.IsShown():
1981                        panel.Hide()
1982            self.get_data(path)
1983        if self.defaultPanel is not None and \
1984            self._mgr.GetPane(self.panels["default"].window_name).IsShown():
1985            self.on_close_welcome_panel()
1986           
1987    def load_data(self, path):
1988        """
1989        load data from command line
1990        """
1991        if not os.path.isfile(path):
1992            return
1993        basename  = os.path.basename(path)
1994        root, extension = os.path.splitext(basename)
1995        if extension.lower() in EXTENSIONS:
1996            log_msg = "Data Loader cannot "
1997            log_msg += "load: %s\n" % str(path)
1998            log_msg += "Try File opening ...."
1999            print log_msg
2000            return
2001        log_msg = ''
2002        output = {}
2003        error_message = ""
2004        try:
2005            print "Loading Data...:\n" + str(path) + "\n"
2006            temp =  self.loader.load(path)
2007            if temp.__class__.__name__ == "list":
2008                for item in temp:
2009                    data = self.create_gui_data(item, path)
2010                    output[data.id] = data
2011            else:
2012                data = self.create_gui_data(temp, path)
2013                output[data.id] = data
2014           
2015            self.add_data(data_list=output)
2016        except:
2017            error_message = "Error while loading"
2018            error_message += " Data from cmd:\n %s\n" % str(path)
2019            error_message += str(sys.exc_value) + "\n"
2020            print error_message
2021 
2022    def load_folder(self, path):
2023        """
2024        Load entire folder
2025        """   
2026        if not os.path.isdir(path):
2027            return
2028        if self._data_plugin is None:
2029            return
2030        try:
2031            if path is not None:
2032                self._default_save_location = os.path.dirname(path)
2033                file_list = self._data_plugin.get_file_path(path)
2034                self._data_plugin.get_data(file_list)
2035            else:
2036                return 
2037        except:
2038            error_message = "Error while loading"
2039            error_message += " Data folder from cmd:\n %s\n" % str(path)
2040            error_message += str(sys.exc_value) + "\n"
2041            print error_message
2042           
2043    def _on_open_state_application(self, event):
2044        """
2045        """
2046        path = None
2047        if self._default_save_location == None:
2048            self._default_save_location = os.getcwd()
2049       
2050        plug_wlist = self._on_open_state_app_helper()
2051        dlg = wx.FileDialog(self, 
2052                            "Choose a file", 
2053                            self._default_save_location, "",
2054                            plug_wlist)
2055        if dlg.ShowModal() == wx.ID_OK:
2056            path = dlg.GetPath()
2057            if path is not None:
2058                self._default_save_location = os.path.dirname(path)
2059        dlg.Destroy()
2060        self.load_state(path=path) 
2061   
2062    def _on_open_state_app_helper(self):
2063        """
2064        Helps '_on_open_state_application()' to find the extension of
2065        the current perspective/application
2066        """
2067        # No current perspective or no extension attr
2068        if self._current_perspective is None:
2069            return PLUGINS_WLIST
2070        try:
2071            # Find the extension of the perspective
2072            # and get that as 1st item in list
2073            ind = None
2074            app_ext = self._current_perspective._extensions
2075            plug_wlist = config.PLUGINS_WLIST
2076            for ext in set(plug_wlist):
2077                if ext.count(app_ext) > 0:
2078                    ind = ext
2079                    break
2080            # Found the extension
2081            if ind != None:
2082                plug_wlist.remove(ind)
2083                plug_wlist.insert(0, ind)
2084                try:
2085                    plug_wlist = '|'.join(plug_wlist)
2086                except:
2087                    plug_wlist = ''
2088
2089        except:
2090            plug_wlist = PLUGINS_WLIST
2091           
2092        return plug_wlist
2093           
2094    def _on_open_state_project(self, event):
2095        """
2096        """
2097        path = None
2098        if self._default_save_location == None:
2099            self._default_save_location = os.getcwd()
2100       
2101        dlg = wx.FileDialog(self, 
2102                            "Choose a file", 
2103                            self._default_save_location, "",
2104                             APPLICATION_WLIST)
2105        if dlg.ShowModal() == wx.ID_OK:
2106            path = dlg.GetPath()
2107            if path is not None:
2108                self._default_save_location = os.path.dirname(path)
2109        dlg.Destroy()
2110       
2111        #try:   
2112        #    os.popen(path)
2113        #    #self.Close()
2114        #except:
2115        self.load_state(path=path)
2116       
2117    def _on_save_application(self, event):
2118        """
2119        save the state of the current active application
2120        """
2121        if self.cpanel_on_focus is not None:
2122            try:
2123                self.cpanel_on_focus.on_save(event)
2124            except:
2125                msg = "Error occurred while saving: "
2126                msg += "To save, the application panel should have a data set.."
2127                wx.PostEvent(self, StatusEvent(status=msg)) 
2128           
2129    def _on_save_project(self, event):
2130        """
2131        save the state of the SasView as *.svs
2132        """
2133        if self._current_perspective is  None:
2134            return
2135        reader, ext = self._current_perspective.get_extensions()
2136        path = None
2137        extension = '*' + APPLICATION_STATE_EXTENSION
2138        dlg = wx.FileDialog(self, "Save Project file",
2139                            self._default_save_location, "sasview_proj",
2140                             extension, 
2141                             wx.SAVE)
2142        if dlg.ShowModal() == wx.ID_OK:
2143            path = dlg.GetPath()
2144            self._default_save_location = os.path.dirname(path)
2145        else:
2146            return None
2147        dlg.Destroy()
2148        try:
2149            if path is None:
2150                return
2151            # default cansas xml doc
2152            doc = None
2153            for panel in self.panels.values():
2154                temp = panel.save_project(doc)
2155                if temp is not None:
2156                    doc = temp
2157             
2158            # Write the XML document
2159            extens = APPLICATION_STATE_EXTENSION
2160            fName = os.path.splitext(path)[0] + extens
2161            if doc != None:
2162                fd = open(fName, 'w')
2163                fd.write(doc.toprettyxml())
2164                fd.close()
2165            else:
2166                msg = "%s cannot read %s\n" % (str(APPLICATION_NAME), str(path))
2167                logging.error(msg)
2168        except:
2169            msg = "Error occurred while saving: "
2170            msg += "To save, at leat one application panel "
2171            msg += "should have a data set.."
2172            wx.PostEvent(self, StatusEvent(status=msg))   
2173                   
2174    def on_save_helper(self, doc, reader, panel, path):
2175        """
2176        Save state into a file
2177        """
2178        try:
2179            if reader is not None:
2180                # case of a panel with multi-pages
2181                if hasattr(panel, "opened_pages"):
2182                    for uid, page in panel.opened_pages.iteritems():
2183                        data = page.get_data()
2184                        # state must be cloned
2185                        state = page.get_state().clone()
2186                        if data is not None:
2187                            new_doc = reader.write_toXML(data, state)
2188                            if doc != None and hasattr(doc, "firstChild"):
2189                                child = new_doc.firstChild.firstChild
2190                                doc.firstChild.appendChild(child) 
2191                            else:
2192                                doc = new_doc
2193                # case of only a panel
2194                else:
2195                    data = panel.get_data()
2196                    state = panel.get_state()
2197                    if data is not None:
2198                        new_doc = reader.write_toXML(data, state)
2199                        if doc != None and hasattr(doc, "firstChild"):
2200                            child = new_doc.firstChild.firstChild
2201                            doc.firstChild.appendChild(child) 
2202                        else:
2203                            doc = new_doc
2204        except: 
2205            raise
2206            #pass
2207
2208        return doc
2209
2210    def quit_guiframe(self):
2211        """
2212        Pop up message to make sure the user wants to quit the application
2213        """
2214        message = "\nDo you really want to exit this application?        \n\n"
2215        dial = wx.MessageDialog(self, message, 'Confirm Exit',
2216                           wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION)
2217        if dial.ShowModal() == wx.ID_YES:
2218            return True
2219        else:
2220            return False   
2221       
2222    def WindowClose(self, event=None):
2223        """
2224        Quit the application from x icon
2225        """
2226        flag = self.quit_guiframe()
2227        if flag:
2228            self.Close()
2229           
2230    def Close(self, event=None):
2231        """
2232        Quit the application
2233        """
2234        wx.Exit()
2235        sys.exit()
2236           
2237    def _check_update(self, event=None): 
2238        """
2239        Check with the deployment server whether a new version
2240        of the application is available.
2241        A thread is started for the connecting with the server. The thread calls
2242        a call-back method when the current version number has been obtained.
2243        """
2244        try:
2245            f=urllib2.urlopen(config.__update_URL__, 
2246                              timeout=1.0)
2247            content = f.read()
2248        except:
2249            content = "0.0.0"
2250       
2251        version = content.strip()
2252        if len(re.findall('\d+\.\d+\.\d+$', version)) < 0:
2253            content = "0.0.0"
2254        self._process_version(content, standalone=event==None)
2255   
2256    def _process_version(self, version, standalone=True):
2257        """
2258        Call-back method for the process of checking for updates.
2259        This methods is called by a VersionThread object once the current
2260        version number has been obtained. If the check is being done in the
2261        background, the user will not be notified unless there's an update.
2262       
2263        :param version: version string
2264        :param standalone: True of the update is being checked in
2265           the background, False otherwise.
2266           
2267        """
2268        try:
2269            if version == "0.0.0":
2270                msg = "Could not connect to the application server."
2271                msg += " Please try again later."
2272                self.SetStatusText(msg)
2273            elif cmp(version, config.__version__) > 0:
2274                msg = "Version %s is available! " % str(version)
2275                if not standalone:
2276                    import webbrowser
2277                    webbrowser.open(config.__download_page__)
2278                else:
2279                    msg +=  "See the help menu to download it." 
2280                self.SetStatusText(msg)
2281            else:
2282                if not standalone:
2283                    msg = "You have the latest version"
2284                    msg += " of %s" % str(config.__appname__)
2285                    self.SetStatusText(msg)
2286        except:
2287            msg = "guiframe: could not get latest application"
2288            msg += " version number\n  %s" % sys.exc_value
2289            logging.error(msg)
2290            if not standalone:
2291                msg = "Could not connect to the application server."
2292                msg += " Please try again later."
2293                self.SetStatusText(msg)
2294                   
2295    def _onAbout(self, evt):
2296        """
2297        Pop up the about dialog
2298       
2299        :param evt: menu event
2300       
2301        """
2302        if config._do_aboutbox:
2303            import sans.guiframe.aboutbox as AboutBox 
2304            dialog = AboutBox.DialogAbout(None, -1, "")
2305            dialog.ShowModal()   
2306                     
2307    def _onTutorial(self, evt):
2308        """
2309        Pop up the tutorial dialog
2310       
2311        :param evt: menu event
2312       
2313        """
2314        if config._do_tutorial:   
2315            path = config.TUTORIAL_PATH
2316            if IS_WIN:
2317                try:
2318                    from sans.guiframe.pdfview import PDFFrame
2319                    dialog = PDFFrame(None, -1, "Tutorial", path)
2320                    # put icon
2321                    self.put_icon(dialog) 
2322                    dialog.Show(True) 
2323                except:
2324                    print "Error in _onTutorial: %s" % sys.exc_value
2325                    try:
2326                        #in case when the pdf default set other than acrobat
2327                        import ho.pisa as pisa
2328                        pisa.startViewer(path)
2329                    except:
2330                        msg = "This feature requires 'PDF Viewer'\n"
2331                        msg += "Please install it first (Free)..."
2332                        wx.MessageBox(msg, 'Error')
2333            else:
2334                try:
2335                    command = "open '%s'" % path
2336                    os.system(command)
2337                except:
2338                    try:
2339                        #in case when the pdf default set other than preview
2340                        import ho.pisa as pisa
2341                        pisa.startViewer(path)
2342                    except:
2343                        msg = "This feature requires 'Preview' Application\n"
2344                        msg += "Please install it first..."
2345                        wx.MessageBox(msg, 'Error')
2346
2347                     
2348    def set_manager(self, manager):
2349        """
2350        Sets the application manager for this frame
2351       
2352        :param manager: frame manager
2353        """
2354        self.app_manager = manager
2355       
2356    def post_init(self):
2357        """
2358        This initialization method is called after the GUI
2359        has been created and all plug-ins loaded. It calls
2360        the post_init() method of each plug-in (if it exists)
2361        so that final initialization can be done.
2362        """
2363        for item in self.plugins:
2364            if hasattr(item, "post_init"):
2365                item.post_init()
2366       
2367    def set_default_perspective(self):
2368        """
2369        Choose among the plugin the first plug-in that has
2370        "set_default_perspective" method and its return value is True will be
2371        as a default perspective when the welcome page is closed
2372        """
2373        for item in self.plugins:
2374            if hasattr(item, "set_default_perspective"):
2375                if item.set_default_perspective():
2376                    item.on_perspective(event=None)
2377                    return 
2378       
2379    def set_perspective(self, panels):
2380        """
2381        Sets the perspective of the GUI.
2382        Opens all the panels in the list, and closes
2383        all the others.
2384       
2385        :param panels: list of panels
2386        """
2387        #style = self.__gui_style & GUIFRAME.TOOLBAR_ON
2388        #if (style == GUIFRAME.TOOLBAR_ON) & (not self._toolbar.IsShown()):
2389        #    self._on_toggle_toolbar()
2390        for item in self.panels:
2391            # Check whether this is a sticky panel
2392            if hasattr(self.panels[item], "ALWAYS_ON"):
2393                if self.panels[item].ALWAYS_ON:
2394                    continue 
2395           
2396            if self.panels[item].window_name in panels:
2397                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
2398                    self._mgr.GetPane(self.panels[item].window_name).Show()
2399            else:
2400                # always show the data panel if enable
2401                style = self.__gui_style & GUIFRAME.MANAGER_ON
2402                if (style == GUIFRAME.MANAGER_ON) and self.panels[item] == self._data_panel:
2403                    if 'data_panel' in self.panels.keys():
2404                        flag = self._mgr.GetPane(self.panels['data_panel'].window_name).IsShown()
2405                        self._mgr.GetPane(self.panels['data_panel'].window_name).Show(flag)
2406                else:
2407                    if self._mgr.GetPane(self.panels[item].window_name).IsShown():
2408                        self._mgr.GetPane(self.panels[item].window_name).Hide()
2409               
2410        self._mgr.Update()
2411       
2412    def show_data_panel(self, event=None, action=True):
2413        """
2414        show the data panel
2415        """
2416        if self._data_panel_menu == None:
2417            return
2418        label = self._data_panel_menu.GetText()
2419        if label == 'Show Data Explorer':
2420            pane = self._mgr.GetPane(self.panels["data_panel"].window_name)
2421            #if not pane.IsShown():
2422            if action: 
2423                pane.Show(True)
2424                self._mgr.Update()
2425            self.__gui_style = self.__gui_style | GUIFRAME.MANAGER_ON
2426           
2427            self._data_panel_menu.SetText('Hide Data Explorer')
2428        else:
2429            pane = self._mgr.GetPane(self.panels["data_panel"].window_name)
2430            #if not pane.IsShown():
2431            if action:
2432                pane.Show(False)
2433                self._mgr.Update()
2434            self.__gui_style = self.__gui_style & (~GUIFRAME.MANAGER_ON)
2435            self._data_panel_menu.SetText('Show Data Explorer')
2436   
2437    def add_data_helper(self, data_list):
2438        """
2439        """
2440        if self._data_manager is not None:
2441            self._data_manager.add_data(data_list)
2442       
2443    def add_data(self, data_list):
2444        """
2445        receive a dictionary of data from loader
2446        store them its data manager if possible
2447        send to data the current active perspective if the data panel
2448        is not active.
2449        :param data_list: dictionary of data's ID and value Data
2450        """
2451        #Store data into manager
2452        self.add_data_helper(data_list)
2453        # set data in the data panel
2454        if self._data_panel is not None:
2455            data_state = self._data_manager.get_data_state(data_list.keys())
2456            self._data_panel.load_data_list(data_state)
2457        #if the data panel is shown wait for the user to press a button
2458        #to send data to the current perspective. if the panel is not
2459        #show  automatically send the data to the current perspective
2460        style = self.__gui_style & GUIFRAME.MANAGER_ON
2461        if style == GUIFRAME.MANAGER_ON:
2462            #wait for button press from the data panel to set_data
2463            if self._data_panel is not None:
2464                self._mgr.GetPane(self._data_panel.window_name).Show(True)
2465                self._mgr.Update() 
2466        else:
2467            #automatically send that to the current perspective
2468            self.set_data(data_id=data_list.keys())
2469            self.on_close_welcome_panel()
2470       
2471    def set_data(self, data_id, theory_id=None): 
2472        """
2473        set data to current perspective
2474        """
2475        list_data, _ = self._data_manager.get_by_id(data_id)
2476        if self._current_perspective is not None:
2477            if self.cleanup_plots:
2478                for uid, panel in self.plot_panels.iteritems():
2479                    #panel = self.plot_panels[uid]
2480                    window = self._mgr.GetPane(panel.window_name)
2481                    # To hide all docked plot panels when set the data
2482                    if not window.IsFloating():
2483                        self.hide_panel(uid)
2484            self._current_perspective.set_data(list_data.values())
2485            self.on_close_welcome_panel()
2486        else:
2487            msg = "Guiframe does not have a current perspective"
2488            logging.info(msg)
2489           
2490    def set_theory(self, state_id, theory_id=None):
2491        """
2492        """
2493        _, list_theory = self._data_manager.get_by_id(theory_id)
2494        if self._current_perspective is not None:
2495            try:
2496                self._current_perspective.set_theory(list_theory.values())
2497            except:
2498                msg = "Guiframe set_theory: \n" + str(sys.exc_value)
2499                logging.info(msg)
2500                wx.PostEvent(self, StatusEvent(status=msg, info="error"))
2501        else:
2502            msg = "Guiframe does not have a current perspective"
2503            logging.info(msg)
2504           
2505    def plot_data(self,  state_id, data_id=None,
2506                  theory_id=None, append=False):
2507        """
2508        send a list of data to plot
2509        """
2510        total_plot_list = []
2511        data_list, _ = self._data_manager.get_by_id(data_id)
2512        _, temp_list_theory = self._data_manager.get_by_id(theory_id)
2513        total_plot_list = data_list.values()
2514        for item in temp_list_theory.values():
2515            theory_data, theory_state = item
2516            total_plot_list.append(theory_data)
2517        GROUP_ID = wx.NewId()
2518        for new_plot in total_plot_list:
2519            if append:
2520                if self.panel_on_focus is None:
2521                    message = "cannot append plot. No plot panel on focus!"
2522                    message += "please click on any available plot to set focus"
2523                    wx.PostEvent(self, StatusEvent(status=message, 
2524                                                   info='warning'))
2525                    return 
2526                else:
2527                    if self.enable_add_data(new_plot):
2528                        new_plot.group_id = self.panel_on_focus.group_id
2529                    else:
2530                        message = "Only 1D Data can be append to"
2531                        message += " plot panel containing 1D data.\n"
2532                        message += "%s not be appended.\n" %str(new_plot.name)
2533                        message += "try new plot option.\n"
2534                        wx.PostEvent(self, StatusEvent(status=message, 
2535                                                   info='warning'))
2536            else:
2537                if self.cleanup_plots:
2538                    for id, panel in self.plot_panels.iteritems():
2539                        window = self._mgr.GetPane(panel.window_name)
2540                        # To hide all docked plot panels when set the data
2541                        if not window.IsFloating():
2542                            self.hide_panel(id)
2543                #if not append then new plot
2544                from sans.guiframe.dataFitting import Data2D
2545                if issubclass(Data2D, new_plot.__class__):
2546                    #for 2 D always plot in a separated new plot
2547                    new_plot.group_id = wx.NewId()
2548                else:
2549                    # plot all 1D in a new plot
2550                    new_plot.group_id = GROUP_ID
2551            title = "PLOT " + str(new_plot.title)
2552            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
2553                                                  title=title,
2554                                                  group_id = new_plot.group_id))
2555           
2556    def remove_data(self, data_id, theory_id=None):
2557        """
2558        Delete data state if data_id is provide
2559        delete theory created with data of id data_id if theory_id is provide
2560        if delete all true: delete the all state
2561        else delete theory
2562        """
2563        temp = data_id + theory_id
2564        """
2565        value = [plug.is_in_use(temp) for plug in self.plugins]
2566        if len(value) > 0:
2567            print "value"
2568            return
2569            from data_panel import DataDialog
2570            dlg = DataDialog(data_list=data_list, nb_data=MAX_NBR_DATA)
2571            if dlg.ShowModal() == wx.ID_OK:
2572                selected_data_list = dlg.get_data()
2573            dlg.Destroy()
2574        """
2575        for plug in self.plugins:
2576            plug.delete_data(temp)
2577        total_plot_list = []
2578        data_list, _ = self._data_manager.get_by_id(data_id)
2579        _, temp_list_theory = self._data_manager.get_by_id(theory_id)
2580        total_plot_list = data_list.values()
2581        for item in temp_list_theory.values():
2582            theory_data, theory_state = item
2583            total_plot_list.append(theory_data)
2584        for new_plot in total_plot_list:
2585            id = new_plot.id
2586            for group_id in new_plot.list_group_id:
2587                wx.PostEvent(self, NewPlotEvent(id=id,
2588                                                   group_id=group_id,
2589                                                   action='remove'))
2590                #remove res plot: Todo: improve
2591                wx.CallAfter(self._remove_res_plot, id)
2592        self._data_manager.delete_data(data_id=data_id, 
2593                                       theory_id=theory_id)
2594       
2595    def _remove_res_plot(self, id):
2596        """
2597        Try to remove corresponding res plot
2598       
2599        : param id: id of the data
2600        """
2601        try:
2602            wx.PostEvent(self, NewPlotEvent(id=("res"+str(id)),
2603                                           group_id=("res"+str(id)),
2604                                           action='remove'))
2605        except:
2606            pass
2607   
2608    def save_data1d(self, data, fname):
2609        """
2610        Save data dialog
2611        """
2612        default_name = fname
2613        wildcard = "Text files (*.txt)|*.txt|"\
2614                    "CanSAS 1D files(*.xml)|*.xml" 
2615        path = None
2616        dlg = wx.FileDialog(self, "Choose a file",
2617                            self._default_save_location,
2618                            default_name, wildcard , wx.SAVE)
2619       
2620        if dlg.ShowModal() == wx.ID_OK:
2621            path = dlg.GetPath()
2622            # ext_num = 0 for .txt, ext_num = 1 for .xml
2623            # This is MAC Fix
2624            ext_num = dlg.GetFilterIndex()
2625            if ext_num == 0:
2626                format = '.txt'
2627            else:
2628                format = '.xml'
2629            path = os.path.splitext(path)[0] + format
2630            mypath = os.path.basename(path)
2631           
2632            #TODO: This is bad design. The DataLoader is designed
2633            #to recognize extensions.
2634            # It should be a simple matter of calling the .
2635            #save(file, data, '.xml') method
2636            # of the sans.dataloader.loader.Loader class.
2637            from sans.dataloader.loader import  Loader
2638            #Instantiate a loader
2639            loader = Loader() 
2640            format = ".txt"
2641            if os.path.splitext(mypath)[1].lower() == format:
2642                # Make sure the ext included in the file name
2643                # especially on MAC
2644                fName = os.path.splitext(path)[0] + format
2645                self._onsaveTXT(data, fName)
2646            format = ".xml"
2647            if os.path.splitext(mypath)[1].lower() == format:
2648                # Make sure the ext included in the file name
2649                # especially on MAC
2650                fName = os.path.splitext(path)[0] + format
2651                loader.save(fName, data, format)
2652            try:
2653                self._default_save_location = os.path.dirname(path)
2654            except:
2655                pass   
2656        dlg.Destroy()
2657       
2658       
2659    def _onsaveTXT(self, data, path):
2660        """
2661        Save file as txt 
2662        :TODO: Refactor and remove this method. See TODO in _onSave.
2663        """
2664        if not path == None:
2665            out = open(path, 'w')
2666            has_errors = True
2667            if data.dy == None or data.dy == []:
2668                has_errors = False
2669            # Sanity check
2670            if has_errors:
2671                try:
2672                    if len(data.y) != len(data.dy):
2673                        has_errors = False
2674                except:
2675                    has_errors = False
2676            if has_errors:
2677                if data.dx != None and data.dx != []:
2678                    out.write("<X>   <Y>   <dY>   <dX>\n")
2679                else:
2680                    out.write("<X>   <Y>   <dY>\n")
2681            else:
2682                out.write("<X>   <Y>\n")
2683               
2684            for i in range(len(data.x)):
2685                if has_errors:
2686                    if data.dx != None and data.dx != []:
2687                        if  data.dx[i] != None:
2688                            out.write("%g  %g  %g  %g\n" % (data.x[i], 
2689                                                        data.y[i],
2690                                                        data.dy[i],
2691                                                        data.dx[i]))
2692                        else:
2693                            out.write("%g  %g  %g\n" % (data.x[i], 
2694                                                        data.y[i],
2695                                                        data.dy[i]))
2696                    else:
2697                        out.write("%g  %g  %g\n" % (data.x[i], 
2698                                                    data.y[i],
2699                                                    data.dy[i]))
2700                else:
2701                    out.write("%g  %g\n" % (data.x[i], 
2702                                            data.y[i]))
2703            out.close() 
2704                             
2705    def show_data1d(self, data, name):
2706        """
2707        Show data dialog
2708        """   
2709        try:
2710            xmin = min(data.x)
2711            ymin = min(data.y)
2712        except:
2713            msg = "Unable to find min/max of \n data named %s"% \
2714                        data.filename 
2715            wx.PostEvent(self, StatusEvent(status=msg,
2716                                       info="error"))
2717            raise ValueError, msg
2718        text = data.__str__() 
2719        text += 'Data Min Max:\n'
2720        text += 'X_min = %s:  X_max = %s\n'% (xmin, max(data.x))
2721        text += 'Y_min = %s:  Y_max = %s\n'% (ymin, max(data.y))
2722        if data.dy != None:
2723            text += 'dY_min = %s:  dY_max = %s\n'% (min(data.dy), max(data.dy))
2724        text += '\nData Points:\n'
2725        x_st = "X"
2726        for index in range(len(data.x)):
2727            if data.dy != None:
2728                dy_val = data.dy[index]
2729            else:
2730                dy_val = 0.0
2731            if data.dx != None:
2732                dx_val = data.dx[index]
2733            else:
2734                dx_val = 0.0
2735            if data.dxl != None:
2736                if index == 0: 
2737                    x_st = "Xl"
2738                dx_val = data.dxl[index]
2739            elif data.dxw != None:
2740                if index == 0: 
2741                    x_st = "Xw"
2742                dx_val = data.dxw[index]
2743           
2744            if index == 0:
2745                text += "<index> \t<X> \t<Y> \t<dY> \t<d%s>\n"% x_st
2746            text += "%s \t%s \t%s \t%s \t%s\n" % (index,
2747                                            data.x[index], 
2748                                            data.y[index],
2749                                            dy_val,
2750                                            dx_val)
2751        from pdfview import TextFrame
2752        frame = TextFrame(None, -1, "Data Info: %s"% data.name, text) 
2753        # put icon
2754        self.put_icon(frame) 
2755        frame.Show(True) 
2756           
2757    def save_data2d(self, data, fname):   
2758        """
2759        Save data2d dialog
2760        """
2761        default_name = fname
2762        wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
2763        dlg = wx.FileDialog(self, "Choose a file",
2764                            self._default_save_location,
2765                            default_name, wildcard , wx.SAVE)
2766       
2767        if dlg.ShowModal() == wx.ID_OK:
2768            path = dlg.GetPath()
2769            # ext_num = 0 for .txt, ext_num = 1 for .xml
2770            # This is MAC Fix
2771            ext_num = dlg.GetFilterIndex()
2772            if ext_num == 0:
2773                format = '.dat'
2774            else:
2775                format = ''
2776            path = os.path.splitext(path)[0] + format
2777            mypath = os.path.basename(path)
2778           
2779            #TODO: This is bad design. The DataLoader is designed
2780            #to recognize extensions.
2781            # It should be a simple matter of calling the .
2782            #save(file, data, '.xml') method
2783            # of the DataLoader.loader.Loader class.
2784            from sans.dataloader.loader import  Loader
2785            #Instantiate a loader
2786            loader = Loader() 
2787
2788            format = ".dat"
2789            if os.path.splitext(mypath)[1].lower() == format:
2790                # Make sure the ext included in the file name
2791                # especially on MAC
2792                fileName = os.path.splitext(path)[0] + format
2793                loader.save(fileName, data, format)
2794            try:
2795                self._default_save_location = os.path.dirname(path)
2796            except:
2797                pass   
2798        dlg.Destroy() 
2799                             
2800    def show_data2d(self, data, name):
2801        """
2802        Show data dialog
2803        """   
2804
2805        wx.PostEvent(self, StatusEvent(status = "Gathering Data2D Info.", 
2806                                       type = 'start' ))
2807        text = data.__str__() 
2808        text += 'Data Min Max:\n'
2809        text += 'I_min = %s\n'% min(data.data)
2810        text += 'I_max = %s\n\n'% max(data.data)
2811        text += 'Data (First 2501) Points:\n'
2812        text += 'Data columns include err(I).\n'
2813        text += 'ASCII data starts here.\n'
2814        text += "<index> \t<Qx> \t<Qy> \t<I> \t<dI> \t<dQparal> \t<dQperp>\n"
2815        di_val = 0.0
2816        dx_val = 0.0
2817        dy_val = 0.0
2818        #mask_val = True
2819        len_data = len(data.qx_data)
2820        for index in xrange(0, len_data):
2821            x_val = data.qx_data[index]
2822            y_val = data.qy_data[index]
2823            i_val = data.data[index]
2824            if data.err_data != None: 
2825                di_val = data.err_data[index]
2826            if data.dqx_data != None: 
2827                dx_val = data.dqx_data[index]
2828            if data.dqy_data != None: 
2829                dy_val = data.dqy_data[index]
2830            #if data.mask != None: mask_val = data.mask[index]
2831 
2832            text += "%s \t%s \t%s \t%s \t%s \t%s \t%s\n" % (index,
2833                                            x_val, 
2834                                            y_val,
2835                                            i_val,
2836                                            di_val,
2837                                            dx_val,
2838                                            dy_val)
2839            # Takes too long time for typical data2d: Break here
2840            if index >= 2500:
2841                text += ".............\n"
2842                break
2843
2844        from pdfview import TextFrame
2845        frame = TextFrame(None, -1, "Data Info: %s"% data.name, text) 
2846        # put icon
2847        self.put_icon(frame)
2848        frame.Show(True) 
2849        wx.PostEvent(self, StatusEvent(status = "Data2D Info Displayed", 
2850                                       type = 'stop' ))
2851                                 
2852    def set_current_perspective(self, perspective):
2853        """
2854        set the current active perspective
2855        """
2856        self._current_perspective = perspective
2857        name = "No current analysis selected"
2858        if self._current_perspective is not None:
2859            self._add_current_plugin_menu()
2860            for panel in self.panels.values():
2861                if hasattr(panel, 'CENTER_PANE') and panel.CENTER_PANE:
2862                    for name in self._current_perspective.get_perspective():
2863                        if name == panel.window_name:
2864                            panel.on_set_focus(event=None)
2865                            break               
2866            name = self._current_perspective.sub_menu
2867            if self._data_panel is not None:
2868                self._data_panel.set_active_perspective(name)
2869                self._check_applications_menu()
2870            #Set the SasView title
2871            self._set_title_name(name)
2872         
2873           
2874    def _set_title_name(self, name):
2875        """
2876        Set the SasView title w/ the current application name
2877       
2878        : param name: application name [string]
2879        """
2880        # Set SanView Window title w/ application anme
2881        title = self.title + "  - " + name + " -"
2882        self.SetTitle(title)
2883           
2884    def _check_applications_menu(self):
2885        """
2886        check the menu of the current application
2887        """
2888        if self._applications_menu is not None:
2889            for menu in self._applications_menu.GetMenuItems():
2890                if self._current_perspective is not None:
2891                    name = self._current_perspective.sub_menu
2892                    if menu.IsCheckable():
2893                        if menu.GetLabel() == name:
2894                            menu.Check(True)
2895                        else:
2896                            menu.Check(False) 
2897           
2898    def set_plotpanel_floating(self, event=None):
2899        """
2900        make the plot panel floatable
2901        """
2902       
2903        self.__gui_style &= (~GUIFRAME.FIXED_PANEL)
2904        self.__gui_style |= GUIFRAME.FLOATING_PANEL
2905        plot_panel = []
2906        id = event.GetId()
2907        menu = self._window_menu.FindItemById(id)
2908        if self._plotting_plugin is not None:
2909            plot_panel = self.plot_panels.values()
2910            for p in plot_panel:
2911                self._popup_floating_panel(p)
2912            menu.Check(True)
2913           
2914    def set_plotpanel_fixed(self, event=None):
2915        """
2916        make the plot panel fixed
2917        """
2918        self.__gui_style &= (~GUIFRAME.FLOATING_PANEL)
2919        self.__gui_style |= GUIFRAME.FIXED_PANEL
2920        plot_panel = []
2921        id = event.GetId()
2922        menu = self._window_menu.FindItemById(id)
2923        if self._plotting_plugin is not None:
2924            plot_panel = self.plot_panels.values()
2925            for p in plot_panel:
2926                self._popup_fixed_panel(p)
2927            menu.Check(True)
2928           
2929    def on_cleanup_dock(self, event=None):     
2930        """
2931        Set Cleanup Dock option
2932        """
2933        if event == None:
2934            return
2935        id = event.GetId()
2936        menu = self._window_menu.FindItemById(id)
2937        Flag = self.cleanup_plots
2938        if not Flag:
2939            menu.Check(True)
2940            self.cleanup_plots = True
2941            msg = "Cleanup-Dock option set to 'ON'."
2942        else:
2943            menu.Check(False)
2944            self.cleanup_plots = False
2945            msg = "Cleanup-Dock option set to 'OFF'."
2946
2947        wx.PostEvent(self, StatusEvent(status= msg))
2948         
2949    def _popup_fixed_panel(self, p):
2950        """
2951        """
2952        style = self.__gui_style & GUIFRAME.FIXED_PANEL
2953        if style == GUIFRAME.FIXED_PANEL:
2954            pane = self._mgr.GetPane(p.window_name)
2955            pane.Dock()
2956            pane.Floatable()
2957            pane.Right()
2958            pane.TopDockable(False)
2959            pane.BottomDockable(False)
2960            pane.LeftDockable(False)
2961            pane.RightDockable(True)
2962            self._mgr.Update()
2963           
2964    def _popup_floating_panel(self, p):
2965        """
2966        """
2967        style = self.__gui_style &  GUIFRAME.FLOATING_PANEL
2968        if style == GUIFRAME.FLOATING_PANEL: 
2969            pane = self._mgr.GetPane(p.window_name)
2970            pane.Floatable(True)
2971            pane.Float()
2972            pane.Dockable(False)
2973            self._mgr.Update()
2974           
2975    def enable_add_data(self, new_plot):
2976        """
2977        Enable append data on a plot panel
2978        """
2979
2980        if self.panel_on_focus not in self._plotting_plugin.plot_panels.values():
2981            return
2982        is_theory = len(self.panel_on_focus.plots) <= 1 and \
2983            self.panel_on_focus.plots.values()[0].__class__.__name__ == "Theory1D"
2984           
2985        is_data2d = hasattr(new_plot, 'data')
2986       
2987        is_data1d = self.panel_on_focus.__class__.__name__ == "ModelPanel1D"\
2988            and self.panel_on_focus.group_id is not None
2989        has_meta_data = hasattr(new_plot, 'meta_data')
2990       
2991        #disable_add_data if the data is being recovered from  a saved state file.
2992        is_state_data = False
2993        if has_meta_data:
2994            if 'invstate' in new_plot.meta_data: 
2995                is_state_data = True
2996            if  'prstate' in new_plot.meta_data: 
2997                is_state_data = True
2998            if  'fitstate' in new_plot.meta_data: 
2999                is_state_data = True
3000   
3001        return is_data1d and not is_data2d and not is_theory and not is_state_data
3002   
3003    def check_multimode(self, perspective=None):
3004        """
3005        Check the perspective have batch mode capablitity
3006        """
3007        if perspective == None or self._data_panel == None:
3008            return
3009        flag = perspective.get_batch_capable()
3010        flag_on = perspective.batch_on
3011        if flag:
3012            self._data_panel.rb_single_mode.SetValue(not flag_on)
3013            self._data_panel.rb_batch_mode.SetValue(flag_on)
3014        else:
3015            self._data_panel.rb_single_mode.SetValue(True)
3016            self._data_panel.rb_batch_mode.SetValue(False)
3017        self._data_panel.rb_single_mode.Enable(flag)
3018        self._data_panel.rb_batch_mode.Enable(flag)
3019               
3020
3021   
3022    def enable_edit_menu(self):
3023        """
3024        enable menu item under edit menu depending on the panel on focus
3025        """
3026        if self.cpanel_on_focus is not None and self._edit_menu is not None:
3027            flag = self.cpanel_on_focus.get_undo_flag()
3028            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
3029            flag = self.cpanel_on_focus.get_redo_flag()
3030            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
3031            flag = self.cpanel_on_focus.get_copy_flag()
3032            self._edit_menu.Enable(GUIFRAME_ID.COPY_ID, flag)
3033            flag = self.cpanel_on_focus.get_paste_flag()
3034            self._edit_menu.Enable(GUIFRAME_ID.PASTE_ID, flag)
3035            #flag = self.cpanel_on_focus.get_print_flag()
3036            #self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
3037            flag = self.cpanel_on_focus.get_preview_flag()
3038            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
3039            flag = self.cpanel_on_focus.get_reset_flag()
3040            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
3041        else:
3042            flag = False
3043            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
3044            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
3045            self._edit_menu.Enable(GUIFRAME_ID.COPY_ID, flag)
3046            self._edit_menu.Enable(GUIFRAME_ID.PASTE_ID, flag)
3047            #self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
3048            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
3049            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
3050           
3051    def on_undo_panel(self, event=None):
3052        """
3053        undo previous action of the last panel on focus if possible
3054        """
3055        if self.cpanel_on_focus is not None:
3056            self.cpanel_on_focus.on_undo(event)
3057           
3058    def on_redo_panel(self, event=None):
3059        """
3060        redo the last cancel action done on the last panel on focus
3061        """
3062        if self.cpanel_on_focus is not None:
3063            self.cpanel_on_focus.on_redo(event)
3064           
3065    def on_copy_panel(self, event=None):
3066        """
3067        copy the last panel on focus if possible
3068        """
3069        if self.cpanel_on_focus is not None:
3070            self.cpanel_on_focus.on_copy(event)
3071           
3072    def on_paste_panel(self, event=None):
3073        """
3074        paste clipboard to the last panel on focus
3075        """
3076        if self.cpanel_on_focus is not None:
3077            self.cpanel_on_focus.on_paste(event)
3078                   
3079    def on_bookmark_panel(self, event=None):
3080        """
3081        bookmark panel
3082        """
3083        if self.cpanel_on_focus is not None:
3084            self.cpanel_on_focus.on_bookmark(event)
3085           
3086    def append_bookmark(self, event=None):
3087        """
3088        Bookmark available information of the panel on focus
3089        """
3090        self._toolbar.append_bookmark(event)
3091           
3092    def on_save_panel(self, event=None):
3093        """
3094        save possible information on the current panel
3095        """
3096        if self.cpanel_on_focus is not None:
3097            self.cpanel_on_focus.on_save(event)
3098           
3099    def on_preview_panel(self, event=None):
3100        """
3101        preview information on the panel on focus
3102        """
3103        if self.cpanel_on_focus is not None:
3104            self.cpanel_on_focus.on_preview(event)
3105           
3106    def on_print_panel(self, event=None):
3107        """
3108        print available information on the last panel on focus
3109        """
3110        if self.cpanel_on_focus is not None:
3111            self.cpanel_on_focus.on_print(event)
3112           
3113    def on_zoom_panel(self, event=None):
3114        """
3115        zoom on the current panel if possible
3116        """
3117        if self.cpanel_on_focus is not None:
3118            self.cpanel_on_focus.on_zoom(event)
3119           
3120    def on_zoom_in_panel(self, event=None):
3121        """
3122        zoom in of the panel on focus
3123        """
3124        if self.cpanel_on_focus is not None:
3125            self.cpanel_on_focus.on_zoom_in(event)
3126           
3127    def on_zoom_out_panel(self, event=None):
3128        """
3129        zoom out on the panel on focus
3130        """
3131        if self.cpanel_on_focus is not None:
3132            self.cpanel_on_focus.on_zoom_out(event)
3133           
3134    def on_drag_panel(self, event=None):
3135        """
3136        drag apply to the panel on focus
3137        """
3138        if self.cpanel_on_focus is not None:
3139            self.cpanel_on_focus.on_drag(event)
3140           
3141    def on_reset_panel(self, event=None):
3142        """
3143        reset the current panel
3144        """
3145        if self.cpanel_on_focus is not None:
3146            self.cpanel_on_focus.on_reset(event)
3147           
3148    def on_change_caption(self, name, old_caption, new_caption):     
3149        """
3150        Change the panel caption
3151       
3152        :param name: window_name of the pane
3153        :param old_caption: current caption [string]
3154        :param new_caption: new caption [string]
3155        """
3156        # wx.aui.AuiPaneInfo
3157        pane_info = self.get_paneinfo(name) 
3158        # update the data_panel.cb_plotpanel
3159        if 'data_panel' in self.panels.keys():
3160            # remove from data_panel combobox
3161            data_panel = self.panels["data_panel"]
3162            if data_panel.cb_plotpanel is not None:
3163                # Check if any panel has the same caption
3164                has_newstring = data_panel.cb_plotpanel.FindString\
3165                                                            (str(new_caption)) 
3166                caption = new_caption
3167                if has_newstring != wx.NOT_FOUND:
3168                    captions = self._get_plotpanel_captions()
3169                    # Append nummber
3170                    inc = 1
3171                    while (1):
3172                        caption = new_caption + '_%s'% str(inc)
3173                        if caption not in captions:
3174                            break
3175                        inc += 1
3176                    # notify to users
3177                    msg = "Found Same Title: Added '_%s'"% str(inc)
3178                    wx.PostEvent(self, StatusEvent(status=msg))
3179                # update data_panel cb
3180                pos = data_panel.cb_plotpanel.FindString(str(old_caption)) 
3181                if pos != wx.NOT_FOUND:
3182                    data_panel.cb_plotpanel.SetString(pos, caption)
3183                    data_panel.cb_plotpanel.SetStringSelection(caption)
3184        # update window Show menu
3185        if self._window_menu != None:
3186            for item in self._window_menu.GetMenuItems():
3187                pos = self._window_menu.FindItem(old_caption)
3188                if self._window_menu.GetLabel(pos) == str(old_caption):
3189                    self._window_menu.SetLabel(pos, caption)
3190                break
3191        # New Caption
3192        pane_info.Caption(caption)
3193        # update aui manager
3194        self._mgr.Update()
3195        return caption
3196       
3197    def get_paneinfo(self, name):
3198        """
3199        Get pane Caption from window_name
3200       
3201        :param name: window_name in AuiPaneInfo
3202        : return: AuiPaneInfo of the name
3203        """
3204        return self._mgr.GetPane(name) 
3205   
3206    def enable_undo(self):
3207        """
3208        enable undo related control
3209        """
3210        if self.cpanel_on_focus is not None:
3211            self._toolbar.enable_undo(self.cpanel_on_focus)
3212           
3213    def enable_redo(self):
3214        """
3215        enable redo
3216        """
3217        if self.cpanel_on_focus is not None:
3218            self._toolbar.enable_redo(self.cpanel_on_focus)
3219           
3220    def enable_copy(self):
3221        """
3222        enable copy related control
3223        """
3224        if self.cpanel_on_focus is not None:
3225            self._toolbar.enable_copy(self.cpanel_on_focus)
3226           
3227    def enable_paste(self):
3228        """
3229        enable paste
3230        """
3231        if self.cpanel_on_focus is not None:
3232            self._toolbar.enable_paste(self.cpanel_on_focus)
3233                       
3234    def enable_bookmark(self):
3235        """
3236        Bookmark
3237        """
3238        if self.cpanel_on_focus is not None:
3239            self._toolbar.enable_bookmark(self.cpanel_on_focus)
3240           
3241    def enable_save(self):
3242        """
3243        save
3244        """
3245        if self.cpanel_on_focus is not None:
3246            self._toolbar.enable_save(self.cpanel_on_focus)
3247           
3248    def enable_preview(self):
3249        """
3250        preview
3251        """
3252        if self.cpanel_on_focus is not None:
3253            self._toolbar.enable_preview(self.cpanel_on_focus)
3254           
3255    def enable_print(self):
3256        """
3257        print
3258        """
3259        if self.cpanel_on_focus is not None:
3260            self._toolbar.enable_print(self.cpanel_on_focus)
3261           
3262    def enable_zoom(self):
3263        """
3264        zoom
3265        """
3266        if self.cpanel_on_focus is not None:
3267            self._toolbar.enable_zoom(self.panel_on_focus)
3268           
3269    def enable_zoom_in(self):
3270        """
3271        zoom in
3272        """
3273        if self.cpanel_on_focus is not None:
3274            self._toolbar.enable_zoom_in(self.panel_on_focus)
3275           
3276    def enable_zoom_out(self):
3277        """
3278        zoom out
3279        """
3280        if self.cpanel_on_focus is not None:
3281            self._toolbar.enable_zoom_out(self.panel_on_focus)
3282           
3283    def enable_drag(self, event=None):
3284        """
3285        drag
3286        """
3287        #if self.cpanel_on_focus is not None:
3288        #    self._toolbar.enable_drag(self.panel_on_focus)
3289           
3290    def enable_reset(self):
3291        """
3292        reset the current panel
3293        """
3294        if self.cpanel_on_focus is not None:
3295            self._toolbar.enable_reset(self.panel_on_focus)
3296
3297    def set_schedule_full_draw(self, panel=None, func='del'):
3298        """
3299        Add/subtract the schedule full draw list with the panel given
3300       
3301        :param panel: plot panel
3302        :param func: append or del [string]
3303        """
3304
3305        # append this panel in the schedule list if not in yet
3306        if func == 'append':
3307            if not panel in self.schedule_full_draw_list:
3308                self.schedule_full_draw_list.append(panel) 
3309        # remove this panel from schedule list
3310        elif func == 'del':
3311            if len(self.schedule_full_draw_list) > 0:
3312                if panel in self.schedule_full_draw_list:
3313                    self.schedule_full_draw_list.remove(panel)
3314
3315        # reset the schdule
3316        if len(self.schedule_full_draw_list) == 0:
3317            self.schedule = False
3318        else:
3319            self.schedule = True   
3320       
3321    def full_draw(self):
3322        """
3323        Draw the panels with axes in the schedule to full dwar list
3324        """
3325        count = len(self.schedule_full_draw_list)
3326        #if not self.schedule:
3327        if count < 1:
3328            self.set_schedule(False)
3329            return
3330        else:
3331            ind = 0
3332            # if any of the panel is shown do full_draw
3333            for panel in self.schedule_full_draw_list:
3334                ind += 1
3335                if self._mgr.GetPane(panel.window_name).IsShown():
3336                    break
3337                # otherwise, return
3338                if ind == count:
3339                    return
3340
3341        #Simple redraw only for a panel shown
3342        def f_draw(panel):
3343            """
3344            Draw A panel in the full dwar list
3345            """
3346            try:
3347                # This checking of GetCapture is to stop redrawing
3348                # while any panel is capture.
3349                if self.GetCapture() == None:
3350                    # draw if possible
3351                    panel.set_resizing(False)
3352                    panel.Show(False)
3353                    panel.draw_plot()
3354                   
3355                    # Check if the panel is not shown
3356                    if not self._mgr.GetPane(panel.window_name).IsShown():
3357                        self._mgr.GetPane(panel.window_name).Hide()
3358                    else:
3359                        panel.Show(True)
3360            except:
3361                pass
3362       
3363        # Draw all panels       
3364        map(f_draw, self.schedule_full_draw_list)
3365       
3366        # Reset the attr 
3367        if len(self.schedule_full_draw_list) == 0:
3368            self.set_schedule(False)
3369        else:
3370            self.set_schedule(True)
3371        # do not update mgr
3372        #self._mgr.Update()
3373       
3374    def set_schedule(self, schedule=False): 
3375        """
3376        Set schedule
3377        """
3378        self.schedule = schedule
3379               
3380    def get_schedule(self): 
3381        """
3382        Get schedule
3383        """
3384        return self.schedule
3385   
3386    def on_set_plot_focus(self, panel):
3387        """
3388        Set focus on a plot panel
3389        """
3390        self.set_plot_unfocus()
3391        panel.on_set_focus(None) 
3392        # set focusing panel
3393        self.panel_on_focus = panel 
3394        self.set_panel_on_focus(None)
3395
3396    def set_plot_unfocus(self): 
3397        """
3398        Un focus all plot panels
3399        """
3400        for plot in self.plot_panels.values():
3401            plot.on_kill_focus(None)
3402   
3403    def get_window_size(self):
3404        """
3405        Get window size
3406       
3407        :return size: tuple
3408        """
3409        width, height = self.GetSizeTuple()
3410        if not IS_WIN:
3411            # Subtract toolbar height to get real window side
3412            if self._toolbar.IsShown():
3413                height -= 45
3414        return (width, height)
3415           
3416    def _onDrawIdle(self, *args, **kwargs):
3417        """
3418        ReDraw with axes
3419        """
3420        try:
3421            # check if it is time to redraw
3422            if self.GetCapture() == None:
3423                # Draw plot, changes resizing too
3424                self.full_draw()
3425        except:
3426            pass
3427           
3428        # restart idle       
3429        self._redraw_idle(*args, **kwargs)
3430
3431           
3432    def _redraw_idle(self, *args, **kwargs):
3433        """
3434        Restart Idle
3435        """
3436        # restart idle   
3437        self.idletimer.Restart(100*TIME_FACTOR, *args, **kwargs)
3438
3439       
3440class DefaultPanel(wx.Panel, PanelBase):
3441    """
3442    Defines the API for a panels to work with
3443    the GUI manager
3444    """
3445    ## Internal nickname for the window, used by the AUI manager
3446    window_name = "default"
3447    ## Name to appear on the window title bar
3448    window_caption = "Welcome panel"
3449    ## Flag to tell the AUI manager to put this panel in the center pane
3450    CENTER_PANE = True
3451    def __init__(self, parent, *args, **kwds):
3452        wx.Panel.__init__(self, parent, *args, **kwds)
3453        PanelBase.__init__(self, parent)
3454   
3455
3456
3457class ViewApp(wx.App):
3458    """
3459    Toy application to test this Frame
3460    """
3461    def OnInit(self):
3462        """
3463        When initialised
3464        """
3465        pos, size, self.is_max = self.window_placement((GUIFRAME_WIDTH, 
3466                                           GUIFRAME_HEIGHT))     
3467        self.frame = ViewerFrame(parent=None, 
3468                             title=APPLICATION_NAME, 
3469                             pos=pos, 
3470                             gui_style = DEFAULT_STYLE,
3471                             size=size)
3472        self.frame.Hide()
3473        self.s_screen = None
3474
3475        try:
3476            self.open_file()
3477        except:
3478            msg = "%s Could not load " % str(APPLICATION_NAME)
3479            msg += "input file from command line.\n"
3480            logging.error(msg)
3481        # Display a splash screen on top of the frame.
3482        try:
3483            if os.path.isfile(SPLASH_SCREEN_PATH):
3484                self.s_screen = self.display_splash_screen(parent=self.frame, 
3485                                        path=SPLASH_SCREEN_PATH)
3486            else:
3487                self.frame.Show()   
3488        except:
3489            if self.s_screen is not None:
3490                self.s_screen.Close()
3491            msg = "Cannot display splash screen\n"
3492            msg += str (sys.exc_value)
3493            logging.error(msg)
3494            self.frame.Show()
3495 
3496        #if hasattr(self.frame, 'special'):
3497        #    self.frame.special.SetCurrent()
3498        self.SetTopWindow(self.frame)
3499 
3500        return True
3501   
3502    def maximize_win(self):
3503        """
3504        Maximize the window after the frame shown
3505        """
3506        if self.is_max:
3507            if self.frame.IsShown():
3508                # Max window size
3509                self.frame.Maximize(self.is_max)
3510
3511    def open_file(self):
3512        """
3513        open a state file at the start of the application
3514        """
3515        input_file = None
3516        if len(sys.argv) >= 2:
3517            cmd = sys.argv[0].lower()
3518            basename  = os.path.basename(cmd)
3519            app_base = str(APPLICATION_NAME).lower()
3520            if os.path.isfile(cmd) or basename.lower() == app_base:
3521                app_py = app_base + '.py'
3522                app_exe = app_base + '.exe'
3523                app_app = app_base + '.app'
3524                if basename.lower() in [app_py, app_exe, app_app, app_base]:
3525                    data_base = sys.argv[1]
3526                    input_file = os.path.normpath(os.path.join(DATAPATH, 
3527                                                               data_base))
3528        if input_file is None:
3529            return
3530        if self.frame is not None:
3531            self.frame.set_input_file(input_file=input_file)
3532         
3533    def clean_plugin_models(self, path): 
3534        """
3535        Delete plugin models  in app folder
3536       
3537        :param path: path of the plugin_models folder in app
3538        """
3539        # do it only the first time app loaded
3540        # delete unused model folder   
3541        model_folder = os.path.join(PATH_APP, path)
3542        if os.path.exists(model_folder) and os.path.isdir(model_folder):
3543            if len(os.listdir(model_folder)) > 0:
3544                try:
3545                    for file in os.listdir(model_folder):
3546                        file_path = os.path.join(model_folder, file)
3547                        if os.path.isfile(file_path):
3548                            os.remove(file_path)
3549                except:
3550                    logging.error("gui_manager.clean_plugin_models:\n  %s" \
3551                                  % sys.exc_value)
3552             
3553    def set_manager(self, manager):
3554        """
3555        Sets a reference to the application manager
3556        of the GUI manager (Frame)
3557        """
3558        self.frame.set_manager(manager)
3559       
3560    def build_gui(self):
3561        """
3562        Build the GUI
3563        """
3564        #try to load file at the start
3565        try:
3566            self.open_file()
3567        except:
3568            raise
3569        self.frame.build_gui()
3570        #if self.s_screen is not None and self.s_screen.IsShown():
3571        #    self.s_screen.Close()
3572       
3573    def set_welcome_panel(self, panel_class):
3574        """
3575        Set the welcome panel
3576       
3577        :param panel_class: class of the welcome panel to be instantiated
3578       
3579        """
3580        self.frame.set_welcome_panel(panel_class)
3581       
3582    def add_perspective(self, perspective):
3583        """
3584        Manually add a perspective to the application GUI
3585        """
3586        self.frame.add_perspective(perspective)
3587   
3588    def window_placement(self, size):
3589        """
3590        Determines the position and size of the application frame such that it
3591        fits on the user's screen without obstructing (or being obstructed by)
3592        the Windows task bar.  The maximum initial size in pixels is bounded by
3593        WIDTH x HEIGHT.  For most monitors, the application
3594        will be centered on the screen; for very large monitors it will be
3595        placed on the left side of the screen.
3596        """
3597        is_maximized = False
3598        # Get size of screen without
3599        for screenCount in range(wx.Display().GetCount()):
3600            screen = wx.Display(screenCount)
3601            if screen.IsPrimary():
3602                displayRect = screen.GetClientArea()
3603                break
3604       
3605        posX, posY, displayWidth, displayHeight = displayRect       
3606        customWidth, customHeight = size
3607       
3608        # If the custom size is default, set 90% of the screen size
3609        if customWidth <= 0 and customHeight <= 0:
3610            if customWidth == 0 and customHeight == 0:
3611                is_maximized = True
3612            customWidth = displayWidth * 0.9
3613            customHeight = displayHeight * 0.9
3614        else:
3615            # If the custom screen is bigger than the
3616            # window screen than make maximum size
3617            if customWidth > displayWidth:
3618                customWidth = displayWidth
3619            if customHeight > displayHeight:
3620                customHeight = displayHeight
3621           
3622        # Note that when running Linux and using an Xming (X11) server on a PC
3623        # with a dual  monitor configuration, the reported display size may be
3624        # that of both monitors combined with an incorrect display count of 1.
3625        # To avoid displaying this app across both monitors, we check for
3626        # screen 'too big'.  If so, we assume a smaller width which means the
3627        # application will be placed towards the left hand side of the screen.
3628       
3629        # If dual screen registered as 1 screen. Make width half.
3630        # MAC just follows the default behavior of pos
3631        if IS_WIN:
3632            if displayWidth > (displayHeight*2):
3633                if (customWidth == displayWidth):
3634                    customWidth = displayWidth/2
3635                # and set the position to be the corner of the screen.
3636                posX = 0
3637                posY = 0
3638               
3639            # Make the position the middle of the screen. (Not 0,0)
3640            else:
3641                posX = (displayWidth - customWidth)/2
3642                posY = (displayHeight - customHeight)/2
3643       
3644        # Return the suggested position and size for the application frame.   
3645        return (posX, posY), (customWidth, customHeight), is_maximized
3646
3647   
3648    def display_splash_screen(self, parent, 
3649                              path=SPLASH_SCREEN_PATH):
3650        """Displays the splash screen.  It will exactly cover the main frame."""
3651       
3652        # Prepare the picture.  On a 2GHz intel cpu, this takes about a second.
3653        image = wx.Image(path, wx.BITMAP_TYPE_PNG)
3654        image.Rescale(SPLASH_SCREEN_WIDTH, 
3655                      SPLASH_SCREEN_HEIGHT, wx.IMAGE_QUALITY_HIGH)
3656        bm = image.ConvertToBitmap()
3657
3658        # Create and show the splash screen.  It will disappear only when the
3659        # program has entered the event loop AND either the timeout has expired
3660        # or the user has left clicked on the screen.  Thus any processing
3661        # performed in this routine (including sleeping) or processing in the
3662        # calling routine (including doing imports) will prevent the splash
3663        # screen from disappearing.
3664        #
3665        # Note that on Linux, the timeout appears to occur immediately in which
3666        # case the splash screen disappears upon entering the event loop.
3667        s_screen = wx.SplashScreen(bitmap=bm,
3668                         splashStyle=(wx.SPLASH_TIMEOUT|
3669                                              wx.SPLASH_CENTRE_ON_SCREEN),
3670                                 style=(wx.SIMPLE_BORDER|
3671                                        wx.FRAME_NO_TASKBAR|
3672                                        wx.STAY_ON_TOP),
3673                                       
3674                        milliseconds=SS_MAX_DISPLAY_TIME,
3675                        parent=parent,
3676                        id=wx.ID_ANY)
3677        from sans.guiframe.gui_statusbar import SPageStatusbar
3678        statusBar = SPageStatusbar(s_screen)
3679        s_screen.SetStatusBar(statusBar)
3680        s_screen.Bind(wx.EVT_CLOSE, self.on_close_splash_screen)
3681        s_screen.Show()
3682        return s_screen
3683       
3684       
3685    def on_close_splash_screen(self, event):
3686        """
3687        When the splash screen is closed.
3688        """
3689        self.frame.Show(True)
3690        event.Skip()
3691        self.maximize_win()
3692
3693if __name__ == "__main__": 
3694    app = ViewApp(0)
3695    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.