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

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

changed batch_on default

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