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

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 476977b was 592cd678, checked in by Anders Markvardsen <anders.markvardsen@…>, 12 years ago

the corfunc now gets loaded but still does not appear in top menu

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