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

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 bce8148 was 70ecd530, checked in by Gervaise Alina <gervyh@…>, 13 years ago

minor cchange to allow sphinx build

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