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

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

minor bug fix

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