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

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

Added project/analysis loading/saving msgs.

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