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

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

fixed boxsum

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