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

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 e25d908 was 3ee8a49, checked in by Mathieu Doucet <doucetm@…>, 13 years ago

trying to fix windows installer

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