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

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 001b930 was 2fdb870, checked in by Jae Cho <jhjcho@…>, 13 years ago

removed checkUpdate (broken) menu

  • Property mode set to 100644
File size: 122.4 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(self, number=number, *args, **kwds)
701       
702    def PopStatusText(self, *args, **kwds):
703        """
704        """
705        field = self.sb.get_msg_position()
706        wx.Frame.PopStatusText(self, 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       
2088        if hasattr(config, "__update_URL__"):
2089            import version
2090            checker = version.VersionThread2(config.__update_URL__,
2091                                            self._process_version,
2092                                            baggage=event==None)
2093            checker.start() 
2094   
2095    def _process_version(self, version, standalone=True):
2096        """
2097        Call-back method for the process of checking for updates.
2098        This methods is called by a VersionThread object once the current
2099        version number has been obtained. If the check is being done in the
2100        background, the user will not be notified unless there's an update.
2101       
2102        :param version: version string
2103        :param standalone: True of the update is being checked in
2104           the background, False otherwise.
2105           
2106        """
2107        try:
2108            if cmp(version, config.__version__) > 0:
2109                msg = "Version %s is available! See the Help " % str(version)
2110                msg += "menu to download it." 
2111                self.SetStatusText(msg)
2112                if not standalone:
2113                    import webbrowser
2114                    webbrowser.open(config.__download_page__)
2115            else:
2116                if not standalone:
2117                    msg = "You have the latest version"
2118                    msg += " of %s" % str(config.__appname__)
2119                    self.SetStatusText(msg)
2120        except:
2121            msg = "guiframe: could not get latest application"
2122            msg += " version number\n  %s" % sys.exc_value
2123            logging.error(msg)
2124            if not standalone:
2125                msg = "Could not connect to the application server."
2126                msg += " Please try again later."
2127                self.SetStatusText(msg)
2128                   
2129    def _onAbout(self, evt):
2130        """
2131        Pop up the about dialog
2132       
2133        :param evt: menu event
2134       
2135        """
2136        if config._do_aboutbox:
2137            import aboutbox 
2138            dialog = aboutbox.DialogAbout(None, -1, "")
2139            dialog.ShowModal()   
2140                     
2141    def _onTutorial(self, evt):
2142        """
2143        Pop up the tutorial dialog
2144       
2145        :param evt: menu event
2146       
2147        """
2148        if config._do_tutorial:   
2149            path = config.TUTORIAL_PATH
2150            if IS_WIN:
2151                try:
2152                    from sans.guiframe.pdfview import PDFFrame
2153                   
2154                    dialog = PDFFrame(None, -1, "Tutorial", path)
2155                    if hasattr(dialog, "IsIconized"):
2156                        if not dialog.IsIconized():
2157                            try:
2158                                icon = self.GetIcon()
2159                                dialog.SetIcon(icon)
2160                            except:
2161                                pass   
2162                    #self.SetTopWindow(dialog)
2163                    dialog.Show(True) 
2164                except:
2165                    msg = "This feature requires 'Adobe pdf Reader'\n"
2166                    msg += "Please install it first (Free)..."
2167                    wx.MessageBox(msg, 'Error')
2168            else:
2169                try:
2170                    command = "open "
2171                    command += path
2172                    os.system(command)
2173                except:
2174                    msg = "This feature requires 'Preview' Application\n"
2175                    msg += "Please install it first..."
2176                    wx.MessageBox(msg, 'Error')
2177
2178                     
2179    def set_manager(self, manager):
2180        """
2181        Sets the application manager for this frame
2182       
2183        :param manager: frame manager
2184        """
2185        self.app_manager = manager
2186       
2187    def post_init(self):
2188        """
2189        This initialization method is called after the GUI
2190        has been created and all plug-ins loaded. It calls
2191        the post_init() method of each plug-in (if it exists)
2192        so that final initialization can be done.
2193        """
2194        for item in self.plugins:
2195            if hasattr(item, "post_init"):
2196                item.post_init()
2197       
2198    def set_default_perspective(self):
2199        """
2200        Choose among the plugin the first plug-in that has
2201        "set_default_perspective" method and its return value is True will be
2202        as a default perspective when the welcome page is closed
2203        """
2204        for item in self.plugins:
2205            if hasattr(item, "set_default_perspective"):
2206                if item.set_default_perspective():
2207                    item.on_perspective(event=None)
2208                    return 
2209       
2210    def set_perspective(self, panels):
2211        """
2212        Sets the perspective of the GUI.
2213        Opens all the panels in the list, and closes
2214        all the others.
2215       
2216        :param panels: list of panels
2217        """
2218        #style = self.__gui_style & GUIFRAME.TOOLBAR_ON
2219        #if (style == GUIFRAME.TOOLBAR_ON) & (not self._toolbar.IsShown()):
2220        #    self._on_toggle_toolbar()
2221        for item in self.panels:
2222            # Check whether this is a sticky panel
2223            if hasattr(self.panels[item], "ALWAYS_ON"):
2224                if self.panels[item].ALWAYS_ON:
2225                    continue 
2226           
2227            if self.panels[item].window_name in panels:
2228                if not self._mgr.GetPane(self.panels[item].window_name).IsShown():
2229                    self._mgr.GetPane(self.panels[item].window_name).Show()
2230            else:
2231                # always show the data panel if enable
2232                style = self.__gui_style & GUIFRAME.MANAGER_ON
2233                if (style == GUIFRAME.MANAGER_ON) and self.panels[item] == self._data_panel:
2234                    if 'data_panel' in self.panels.keys():
2235                        flag = self._mgr.GetPane(self.panels['data_panel'].window_name).IsShown()
2236                        self._mgr.GetPane(self.panels['data_panel'].window_name).Show(flag)
2237                else:
2238                    if self._mgr.GetPane(self.panels[item].window_name).IsShown():
2239                        self._mgr.GetPane(self.panels[item].window_name).Hide()
2240               
2241        self._mgr.Update()
2242       
2243    def show_data_panel(self, event=None, action=True):
2244        """
2245        show the data panel
2246        """
2247        if self._data_panel_menu == None:
2248            return
2249        label = self._data_panel_menu.GetText()
2250        if label == 'Show Data Explorer':
2251            pane = self._mgr.GetPane(self.panels["data_panel"].window_name)
2252            #if not pane.IsShown():
2253            if action: 
2254                pane.Show(True)
2255                self._mgr.Update()
2256            self.__gui_style = self.__gui_style | GUIFRAME.MANAGER_ON
2257           
2258            self._data_panel_menu.SetText('Hide Data Explorer')
2259        else:
2260            pane = self._mgr.GetPane(self.panels["data_panel"].window_name)
2261            #if not pane.IsShown():
2262            if action:
2263                pane.Show(False)
2264                self._mgr.Update()
2265            self.__gui_style = self.__gui_style & (~GUIFRAME.MANAGER_ON)
2266            self._data_panel_menu.SetText('Show Data Explorer')
2267   
2268    def add_data_helper(self, data_list):
2269        """
2270        """
2271        if self._data_manager is not None:
2272            self._data_manager.add_data(data_list)
2273       
2274    def add_data(self, data_list):
2275        """
2276        receive a dictionary of data from loader
2277        store them its data manager if possible
2278        send to data the current active perspective if the data panel
2279        is not active.
2280        :param data_list: dictionary of data's ID and value Data
2281        """
2282        #Store data into manager
2283        self.add_data_helper(data_list)
2284        # set data in the data panel
2285        if self._data_panel is not None:
2286            data_state = self._data_manager.get_data_state(data_list.keys())
2287            self._data_panel.load_data_list(data_state)
2288        #if the data panel is shown wait for the user to press a button
2289        #to send data to the current perspective. if the panel is not
2290        #show  automatically send the data to the current perspective
2291        style = self.__gui_style & GUIFRAME.MANAGER_ON
2292        if style == GUIFRAME.MANAGER_ON:
2293            #wait for button press from the data panel to set_data
2294            if self._data_panel is not None:
2295                self._mgr.GetPane(self._data_panel.window_name).Show(True)
2296                self._mgr.Update() 
2297        else:
2298            #automatically send that to the current perspective
2299            self.set_data(data_id=data_list.keys())
2300            self.on_close_welcome_panel()
2301       
2302    def set_data(self, data_id, theory_id=None): 
2303        """
2304        set data to current perspective
2305        """
2306        list_data, _ = self._data_manager.get_by_id(data_id)
2307        if self._current_perspective is not None:
2308            if self.cleanup_plots:
2309                for uid, panel in self.plot_panels.iteritems():
2310                    #panel = self.plot_panels[uid]
2311                    window = self._mgr.GetPane(panel.window_name)
2312                    # To hide all docked plot panels when set the data
2313                    if not window.IsFloating():
2314                        self.hide_panel(uid)
2315            self._current_perspective.set_data(list_data.values())
2316            self.on_close_welcome_panel()
2317        else:
2318            msg = "Guiframe does not have a current perspective"
2319            logging.info(msg)
2320           
2321    def set_theory(self, state_id, theory_id=None):
2322        """
2323        """
2324        _, list_theory = self._data_manager.get_by_id(theory_id)
2325        if self._current_perspective is not None:
2326            try:
2327                self._current_perspective.set_theory(list_theory.values())
2328            except:
2329                msg = "Guiframe set_theory: \n" + str(sys.exc_value)
2330                logging.info(msg)
2331                wx.PostEvent(self, StatusEvent(status=msg, info="error"))
2332        else:
2333            msg = "Guiframe does not have a current perspective"
2334            logging.info(msg)
2335           
2336    def plot_data(self,  state_id, data_id=None,
2337                  theory_id=None, append=False):
2338        """
2339        send a list of data to plot
2340        """
2341        total_plot_list = []
2342        data_list, _ = self._data_manager.get_by_id(data_id)
2343        _, temp_list_theory = self._data_manager.get_by_id(theory_id)
2344        total_plot_list = data_list.values()
2345        for item in temp_list_theory.values():
2346            theory_data, theory_state = item
2347            total_plot_list.append(theory_data)
2348        GROUP_ID = wx.NewId()
2349        for new_plot in total_plot_list:
2350            if append:
2351                if self.panel_on_focus is None:
2352                    message = "cannot append plot. No plot panel on focus!"
2353                    message += "please click on any available plot to set focus"
2354                    wx.PostEvent(self, StatusEvent(status=message, 
2355                                                   info='warning'))
2356                    return 
2357                else:
2358                    if self.enable_add_data(new_plot):
2359                        new_plot.group_id = self.panel_on_focus.group_id
2360                    else:
2361                        message = "Only 1D Data can be append to"
2362                        message += " plot panel containing 1D data.\n"
2363                        message += "%s not be appended.\n" %str(new_plot.name)
2364                        message += "try new plot option.\n"
2365                        wx.PostEvent(self, StatusEvent(status=message, 
2366                                                   info='warning'))
2367            else:
2368                if self.cleanup_plots:
2369                    for id, panel in self.plot_panels.iteritems():
2370                        window = self._mgr.GetPane(panel.window_name)
2371                        # To hide all docked plot panels when set the data
2372                        if not window.IsFloating():
2373                            self.hide_panel(id)
2374                #if not append then new plot
2375                from sans.guiframe.dataFitting import Data2D
2376                if issubclass(Data2D, new_plot.__class__):
2377                    #for 2 D always plot in a separated new plot
2378                    new_plot.group_id = wx.NewId()
2379                else:
2380                    # plot all 1D in a new plot
2381                    new_plot.group_id = GROUP_ID
2382            title = "PLOT " + str(new_plot.title)
2383            wx.PostEvent(self, NewPlotEvent(plot=new_plot,
2384                                                  title=title,
2385                                                  group_id = new_plot.group_id))
2386           
2387    def remove_data(self, data_id, theory_id=None):
2388        """
2389        Delete data state if data_id is provide
2390        delete theory created with data of id data_id if theory_id is provide
2391        if delete all true: delete the all state
2392        else delete theory
2393        """
2394        temp = data_id + theory_id
2395        """
2396        value = [plug.is_in_use(temp) for plug in self.plugins]
2397        if len(value) > 0:
2398            print "value"
2399            return
2400            from data_panel import DataDialog
2401            dlg = DataDialog(data_list=data_list, nb_data=MAX_NBR_DATA)
2402            if dlg.ShowModal() == wx.ID_OK:
2403                selected_data_list = dlg.get_data()
2404            dlg.Destroy()
2405        """
2406        for plug in self.plugins:
2407            plug.delete_data(temp)
2408        total_plot_list = []
2409        data_list, _ = self._data_manager.get_by_id(data_id)
2410        _, temp_list_theory = self._data_manager.get_by_id(theory_id)
2411        total_plot_list = data_list.values()
2412        for item in temp_list_theory.values():
2413            theory_data, theory_state = item
2414            total_plot_list.append(theory_data)
2415        for new_plot in total_plot_list:
2416            id = new_plot.id
2417            for group_id in new_plot.list_group_id:
2418                wx.PostEvent(self, NewPlotEvent(id=id,
2419                                                   group_id=group_id,
2420                                                   action='remove'))
2421                #remove res plot: Todo: improve
2422                wx.CallAfter(self._remove_res_plot, id)
2423        self._data_manager.delete_data(data_id=data_id, 
2424                                       theory_id=theory_id)
2425       
2426    def _remove_res_plot(self, id):
2427        """
2428        Try to remove corresponding res plot
2429       
2430        : param id: id of the data
2431        """
2432        try:
2433            wx.PostEvent(self, NewPlotEvent(id=("res"+str(id)),
2434                                           group_id=("res"+str(id)),
2435                                           action='remove'))
2436        except:
2437            pass
2438                         
2439    def set_current_perspective(self, perspective):
2440        """
2441        set the current active perspective
2442        """
2443        self._current_perspective = perspective
2444        name = "No current analysis selected"
2445        if self._current_perspective is not None:
2446            self._add_current_plugin_menu()
2447            for panel in self.panels.values():
2448                if hasattr(panel, 'CENTER_PANE') and panel.CENTER_PANE:
2449                    for name in self._current_perspective.get_perspective():
2450                        if name == panel.window_name:
2451                            panel.on_set_focus(event=None)
2452                            break               
2453            name = self._current_perspective.sub_menu
2454            if self._data_panel is not None:
2455                self._data_panel.set_active_perspective(name)
2456                self._check_applications_menu()
2457            #Set the SansView title
2458            self._set_title_name(name)
2459         
2460           
2461    def _set_title_name(self, name):
2462        """
2463        Set the SansView title w/ the current application name
2464       
2465        : param name: application name [string]
2466        """
2467        # Set SanView Window title w/ application anme
2468        title = self.title + "  - " + name + " -"
2469        self.SetTitle(title)
2470           
2471    def _check_applications_menu(self):
2472        """
2473        check the menu of the current application
2474        """
2475        if self._applications_menu is not None:
2476            for menu in self._applications_menu.GetMenuItems():
2477                if self._current_perspective is not None:
2478                    name = self._current_perspective.sub_menu
2479                    if menu.IsCheckable():
2480                        if menu.GetLabel() == name:
2481                            menu.Check(True)
2482                        else:
2483                             menu.Check(False) 
2484           
2485    def set_plotpanel_floating(self, event=None):
2486        """
2487        make the plot panel floatable
2488        """
2489       
2490        self.__gui_style &= (~GUIFRAME.FIXED_PANEL)
2491        self.__gui_style |= GUIFRAME.FLOATING_PANEL
2492        plot_panel = []
2493        id = event.GetId()
2494        menu = self._window_menu.FindItemById(id)
2495        if self._plotting_plugin is not None:
2496            plot_panel = self.plot_panels.values()
2497            for p in plot_panel:
2498                self._popup_floating_panel(p)
2499            menu.Check(True)
2500           
2501    def set_plotpanel_fixed(self, event=None):
2502        """
2503        make the plot panel fixed
2504        """
2505        self.__gui_style &= (~GUIFRAME.FLOATING_PANEL)
2506        self.__gui_style |= GUIFRAME.FIXED_PANEL
2507        plot_panel = []
2508        id = event.GetId()
2509        menu = self._window_menu.FindItemById(id)
2510        if self._plotting_plugin is not None:
2511            plot_panel = self.plot_panels.values()
2512            for p in plot_panel:
2513                self._popup_fixed_panel(p)
2514            menu.Check(True)
2515           
2516    def on_cleanup_dock(self, event=None):     
2517        """
2518        Set Cleanup Dock option
2519        """
2520        if event == None:
2521            return
2522        id = event.GetId()
2523        menu = self._window_menu.FindItemById(id)
2524        Flag = self.cleanup_plots
2525        if not Flag:
2526            menu.Check(True)
2527            self.cleanup_plots = True
2528            msg = "Cleanup-Dock option set to 'ON'."
2529        else:
2530            menu.Check(False)
2531            self.cleanup_plots = False
2532            msg = "Cleanup-Dock option set to 'OFF'."
2533
2534        wx.PostEvent(self, StatusEvent(status= msg))
2535         
2536    def _popup_fixed_panel(self, p):
2537        """
2538        """
2539        style = self.__gui_style & GUIFRAME.FIXED_PANEL
2540        if style == GUIFRAME.FIXED_PANEL:
2541            self._mgr.GetPane(p.window_name).Dock()
2542            self._mgr.GetPane(p.window_name).Floatable()
2543            self._mgr.GetPane(p.window_name).Right()
2544            self._mgr.GetPane(p.window_name).TopDockable(False)
2545            self._mgr.GetPane(p.window_name).BottomDockable(False)
2546            self._mgr.GetPane(p.window_name).LeftDockable(False)
2547            self._mgr.GetPane(p.window_name).RightDockable(True)
2548            self._mgr.Update()
2549           
2550    def _popup_floating_panel(self, p):
2551        """
2552        """
2553        style = self.__gui_style &  GUIFRAME.FLOATING_PANEL
2554        if style == GUIFRAME.FLOATING_PANEL: 
2555            self._mgr.GetPane(p.window_name).Floatable(True)
2556            self._mgr.GetPane(p.window_name).Float()
2557            self._mgr.GetPane(p.window_name).Dockable(False)
2558            self._mgr.Update()
2559           
2560    def enable_add_data(self, new_plot):
2561        """
2562        Enable append data on a plot panel
2563        """
2564
2565        if self.panel_on_focus not in self._plotting_plugin.plot_panels.values():
2566            return
2567        is_theory = len(self.panel_on_focus.plots) <= 1 and \
2568            self.panel_on_focus.plots.values()[0].__class__.__name__ == "Theory1D"
2569           
2570        is_data2d = hasattr(new_plot, 'data')
2571       
2572        is_data1d = self.panel_on_focus.__class__.__name__ == "ModelPanel1D"\
2573            and self.panel_on_focus.group_id is not None
2574        has_meta_data = hasattr(new_plot, 'meta_data')
2575       
2576        #disable_add_data if the data is being recovered from  a saved state file.
2577        is_state_data = False
2578        if has_meta_data:
2579            if 'invstate' in new_plot.meta_data: is_state_data = True
2580            if  'prstate' in new_plot.meta_data: is_state_data = True
2581            if  'fitstate' in new_plot.meta_data: is_state_data = True
2582   
2583        return is_data1d and not is_data2d and not is_theory and not is_state_data
2584   
2585    def check_multimode(self, perspective=None):
2586        """
2587        Check the perspective have batch mode capablitity
2588        """
2589        if perspective == None or self._data_panel == None:
2590            return
2591        flag = perspective.get_batch_capable()
2592        flag_on = perspective.batch_on
2593        if flag:
2594            self._data_panel.rb_single_mode.SetValue(not flag_on)
2595            self._data_panel.rb_batch_mode.SetValue(flag_on)
2596        else:
2597            self._data_panel.rb_single_mode.SetValue(True)
2598            self._data_panel.rb_batch_mode.SetValue(False)
2599        self._data_panel.rb_single_mode.Enable(flag)
2600        self._data_panel.rb_batch_mode.Enable(flag)
2601               
2602
2603   
2604    def enable_edit_menu(self):
2605        """
2606        enable menu item under edit menu depending on the panel on focus
2607        """
2608        if self.cpanel_on_focus is not None and self._edit_menu is not None:
2609            flag = self.cpanel_on_focus.get_undo_flag()
2610            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
2611            flag = self.cpanel_on_focus.get_redo_flag()
2612            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
2613            flag = self.cpanel_on_focus.get_copy_flag()
2614            self._edit_menu.Enable(GUIFRAME_ID.COPY_ID, flag)
2615            flag = self.cpanel_on_focus.get_paste_flag()
2616            self._edit_menu.Enable(GUIFRAME_ID.PASTE_ID, flag)
2617            #flag = self.cpanel_on_focus.get_print_flag()
2618            #self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
2619            flag = self.cpanel_on_focus.get_preview_flag()
2620            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
2621            flag = self.cpanel_on_focus.get_reset_flag()
2622            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
2623        else:
2624            flag = False
2625            self._edit_menu.Enable(GUIFRAME_ID.UNDO_ID, flag)
2626            self._edit_menu.Enable(GUIFRAME_ID.REDO_ID, flag)
2627            self._edit_menu.Enable(GUIFRAME_ID.COPY_ID, flag)
2628            self._edit_menu.Enable(GUIFRAME_ID.PASTE_ID, flag)
2629            #self._edit_menu.Enable(GUIFRAME_ID.PRINT_ID, flag)
2630            self._edit_menu.Enable(GUIFRAME_ID.PREVIEW_ID, flag)
2631            self._edit_menu.Enable(GUIFRAME_ID.RESET_ID, flag)
2632           
2633    def on_undo_panel(self, event=None):
2634        """
2635        undo previous action of the last panel on focus if possible
2636        """
2637        if self.cpanel_on_focus is not None:
2638            self.cpanel_on_focus.on_undo(event)
2639           
2640    def on_redo_panel(self, event=None):
2641        """
2642        redo the last cancel action done on the last panel on focus
2643        """
2644        if self.cpanel_on_focus is not None:
2645            self.cpanel_on_focus.on_redo(event)
2646           
2647    def on_copy_panel(self, event=None):
2648        """
2649        copy the last panel on focus if possible
2650        """
2651        if self.cpanel_on_focus is not None:
2652            self.cpanel_on_focus.on_copy(event)
2653           
2654    def on_paste_panel(self, event=None):
2655        """
2656        paste clipboard to the last panel on focus
2657        """
2658        if self.cpanel_on_focus is not None:
2659            self.cpanel_on_focus.on_paste(event)
2660                   
2661    def on_bookmark_panel(self, event=None):
2662        """
2663        bookmark panel
2664        """
2665        if self.cpanel_on_focus is not None:
2666            self.cpanel_on_focus.on_bookmark(event)
2667           
2668    def append_bookmark(self, event=None):
2669        """
2670        Bookmark available information of the panel on focus
2671        """
2672        self._toolbar.append_bookmark(event)
2673           
2674    def on_save_panel(self, event=None):
2675        """
2676        save possible information on the current panel
2677        """
2678        if self.cpanel_on_focus is not None:
2679            self.cpanel_on_focus.on_save(event)
2680           
2681    def on_preview_panel(self, event=None):
2682        """
2683        preview information on the panel on focus
2684        """
2685        if self.cpanel_on_focus is not None:
2686            self.cpanel_on_focus.on_preview(event)
2687           
2688    def on_print_panel(self, event=None):
2689        """
2690        print available information on the last panel on focus
2691        """
2692        if self.cpanel_on_focus is not None:
2693            self.cpanel_on_focus.on_print(event)
2694           
2695    def on_zoom_panel(self, event=None):
2696        """
2697        zoom on the current panel if possible
2698        """
2699        if self.cpanel_on_focus is not None:
2700            self.cpanel_on_focus.on_zoom(event)
2701           
2702    def on_zoom_in_panel(self, event=None):
2703        """
2704        zoom in of the panel on focus
2705        """
2706        if self.cpanel_on_focus is not None:
2707            self.cpanel_on_focus.on_zoom_in(event)
2708           
2709    def on_zoom_out_panel(self, event=None):
2710        """
2711        zoom out on the panel on focus
2712        """
2713        if self.cpanel_on_focus is not None:
2714            self.cpanel_on_focus.on_zoom_out(event)
2715           
2716    def on_drag_panel(self, event=None):
2717        """
2718        drag apply to the panel on focus
2719        """
2720        if self.cpanel_on_focus is not None:
2721            self.cpanel_on_focus.on_drag(event)
2722           
2723    def on_reset_panel(self, event=None):
2724        """
2725        reset the current panel
2726        """
2727        if self.cpanel_on_focus is not None:
2728            self.cpanel_on_focus.on_reset(event)
2729           
2730    def on_change_caption(self, name, old_caption, new_caption):     
2731        """
2732        Change the panel caption
2733       
2734        :param name: window_name of the pane
2735        :param old_caption: current caption [string]
2736        :param new_caption: new caption [string]
2737        """
2738        # wx.aui.AuiPaneInfo
2739        pane_info = self.get_paneinfo(name) 
2740        # update the data_panel.cb_plotpanel
2741        if 'data_panel' in self.panels.keys():
2742            # remove from data_panel combobox
2743            data_panel = self.panels["data_panel"]
2744            if data_panel.cb_plotpanel is not None:
2745                # Check if any panel has the same caption
2746                has_newstring = data_panel.cb_plotpanel.FindString\
2747                                                            (str(new_caption)) 
2748                caption = new_caption
2749                if has_newstring != wx.NOT_FOUND:
2750                    captions = self._get_plotpanel_captions()
2751                    # Append nummber
2752                    inc = 1
2753                    while (1):
2754                        caption = new_caption + '_%s'% str(inc)
2755                        if caption not in captions:
2756                            break
2757                        inc += 1
2758                    # notify to users
2759                    msg = "Found Same Title: Added '_%s'"% str(inc)
2760                    wx.PostEvent(self, StatusEvent(status=msg))
2761                # update data_panel cb
2762                pos = data_panel.cb_plotpanel.FindString(str(old_caption)) 
2763                if pos != wx.NOT_FOUND:
2764                    data_panel.cb_plotpanel.SetString(pos, caption)
2765                    data_panel.cb_plotpanel.SetStringSelection(caption)
2766        # update window Show menu
2767        if self._window_menu != None:
2768            for item in self._window_menu.GetMenuItems():
2769                pos = self._window_menu.FindItem(old_caption)
2770                if self._window_menu.GetLabel(pos) == str(old_caption):
2771                    self._window_menu.SetLabel(pos, caption)
2772                break
2773        # New Caption
2774        pane_info.Caption(caption)
2775        # update aui manager
2776        self._mgr.Update()
2777        return caption
2778       
2779    def get_paneinfo(self, name):
2780        """
2781        Get pane Caption from window_name
2782       
2783        :param name: window_name in AuiPaneInfo
2784        : return: AuiPaneInfo of the name
2785        """
2786        return self._mgr.GetPane(name) 
2787   
2788    def enable_undo(self):
2789        """
2790        enable undo related control
2791        """
2792        if self.cpanel_on_focus is not None:
2793            self._toolbar.enable_undo(self.cpanel_on_focus)
2794           
2795    def enable_redo(self):
2796        """
2797        enable redo
2798        """
2799        if self.cpanel_on_focus is not None:
2800            self._toolbar.enable_redo(self.cpanel_on_focus)
2801           
2802    def enable_copy(self):
2803        """
2804        enable copy related control
2805        """
2806        if self.cpanel_on_focus is not None:
2807            self._toolbar.enable_copy(self.cpanel_on_focus)
2808           
2809    def enable_paste(self):
2810        """
2811        enable paste
2812        """
2813        if self.cpanel_on_focus is not None:
2814            self._toolbar.enable_paste(self.cpanel_on_focus)
2815                       
2816    def enable_bookmark(self):
2817        """
2818        Bookmark
2819        """
2820        if self.cpanel_on_focus is not None:
2821            self._toolbar.enable_bookmark(self.cpanel_on_focus)
2822           
2823    def enable_save(self):
2824        """
2825        save
2826        """
2827        if self.cpanel_on_focus is not None:
2828            self._toolbar.enable_save(self.cpanel_on_focus)
2829           
2830    def enable_preview(self):
2831        """
2832        preview
2833        """
2834        if self.cpanel_on_focus is not None:
2835            self._toolbar.enable_preview(self.cpanel_on_focus)
2836           
2837    def enable_print(self):
2838        """
2839        print
2840        """
2841        if self.cpanel_on_focus is not None:
2842            self._toolbar.enable_print(self.cpanel_on_focus)
2843           
2844    def enable_zoom(self):
2845        """
2846        zoom
2847        """
2848        if self.cpanel_on_focus is not None:
2849            self._toolbar.enable_zoom(self.panel_on_focus)
2850           
2851    def enable_zoom_in(self):
2852        """
2853        zoom in
2854        """
2855        if self.cpanel_on_focus is not None:
2856            self._toolbar.enable_zoom_in(self.panel_on_focus)
2857           
2858    def enable_zoom_out(self):
2859        """
2860        zoom out
2861        """
2862        if self.cpanel_on_focus is not None:
2863            self._toolbar.enable_zoom_out(self.panel_on_focus)
2864           
2865    def enable_drag(self, event=None):
2866        """
2867        drag
2868        """
2869        if self.cpanel_on_focus is not None:
2870            self._toolbar.enable_drag(self.panel_on_focus)
2871           
2872    def enable_reset(self):
2873        """
2874        reset the current panel
2875        """
2876        if self.cpanel_on_focus is not None:
2877            self._toolbar.enable_reset(self.panel_on_focus)
2878
2879    def set_schedule_full_draw(self, panel=None, func='del'):
2880        """
2881        Add/subtract the schedule full draw list with the panel given
2882       
2883        :param panel: plot panel
2884        :param func: append or del [string]
2885        """
2886
2887        # append this panel in the schedule list if not in yet
2888        if func == 'append':
2889            if not panel in self.schedule_full_draw_list:
2890                self.schedule_full_draw_list.append(panel) 
2891        # remove this panel from schedule list
2892        elif func == 'del':
2893            if len(self.schedule_full_draw_list) > 0:
2894                if panel in self.schedule_full_draw_list:
2895                    self.schedule_full_draw_list.remove(panel)
2896
2897        # reset the schdule
2898        if len(self.schedule_full_draw_list) == 0:
2899            self.schedule = False
2900        else:
2901            self.schedule = True   
2902       
2903    def full_draw(self):
2904        """
2905        Draw the panels with axes in the schedule to full dwar list
2906        """
2907        count = len(self.schedule_full_draw_list)
2908        #if not self.schedule:
2909        if count < 1:
2910            self.set_schedule(False)
2911            return
2912        else:
2913            ind = 0
2914            # if any of the panel is shown do full_draw
2915            for panel in self.schedule_full_draw_list:
2916                ind += 1
2917                if self._mgr.GetPane(panel.window_name).IsShown():
2918                    break
2919                # otherwise, return
2920                if ind == count:
2921                    return
2922
2923        #Simple redraw only for a panel shown
2924        def f_draw(panel):
2925            """
2926            Draw A panel in the full dwar list
2927            """
2928            try:
2929                # This checking of GetCapture is to stop redrawing
2930                # while any panel is capture.
2931                if self.GetCapture() == None:
2932                    # draw if possible
2933                    panel.set_resizing(False)
2934                    panel.Show(False)
2935                    panel.draw_plot()
2936                   
2937                    # Check if the panel is not shown
2938                    if not self._mgr.GetPane(panel.window_name).IsShown():
2939                        self._mgr.GetPane(panel.window_name).Hide()
2940                    else:
2941                        panel.Show(True)
2942            except:
2943                pass
2944       
2945        # Draw all panels       
2946        map(f_draw, self.schedule_full_draw_list)
2947       
2948        # Reset the attr 
2949        if len(self.schedule_full_draw_list) == 0:
2950            self.set_schedule(False)
2951        else:
2952            self.set_schedule(True)
2953        # do not update mgr
2954        #self._mgr.Update()
2955       
2956    def set_schedule(self, schedule=False): 
2957        """
2958        Set schedule
2959        """
2960        self.schedule = schedule
2961               
2962    def get_schedule(self): 
2963        """
2964        Get schedule
2965        """
2966        return self.schedule
2967   
2968    def on_set_plot_focus(self, panel):
2969        """
2970        Set focus on a plot panel
2971        """
2972        self.set_plot_unfocus()
2973        panel.on_set_focus(None) 
2974        # set focusing panel
2975        self.panel_on_focus = panel 
2976        self.set_panel_on_focus(None)
2977
2978    def set_plot_unfocus(self): 
2979        """
2980        Un focus all plot panels
2981        """
2982        for plot in self.plot_panels.values():
2983            plot.on_kill_focus(None)
2984
2985    def _onDrawIdle(self, *args, **kwargs):
2986        """
2987        ReDraw with axes
2988        """
2989        try:
2990            # check if it is time to redraw
2991            if self.GetCapture() == None:
2992                # Draw plot, changes resizing too
2993                self.full_draw()
2994        except:
2995            pass
2996           
2997        # restart idle       
2998        self._redraw_idle(*args, **kwargs)
2999
3000           
3001    def _redraw_idle(self, *args, **kwargs):
3002        """
3003        Restart Idle
3004        """
3005        # restart idle   
3006        self.idletimer.Restart(55*TIME_FACTOR, *args, **kwargs)
3007
3008       
3009class DefaultPanel(wx.Panel, PanelBase):
3010    """
3011    Defines the API for a panels to work with
3012    the GUI manager
3013    """
3014    ## Internal nickname for the window, used by the AUI manager
3015    window_name = "default"
3016    ## Name to appear on the window title bar
3017    window_caption = "Welcome panel"
3018    ## Flag to tell the AUI manager to put this panel in the center pane
3019    CENTER_PANE = True
3020    def __init__(self, parent, *args, **kwds):
3021        wx.Panel.__init__(self, parent, *args, **kwds)
3022        PanelBase.__init__(self, parent)
3023   
3024
3025
3026# Toy application to test this Frame
3027class ViewApp(wx.App):
3028    """
3029    """
3030    def OnInit(self):
3031        """
3032        """
3033        pos, size = self.window_placement((GUIFRAME_WIDTH, GUIFRAME_HEIGHT))
3034        self.frame = ViewerFrame(parent=None, 
3035                                 title=APPLICATION_NAME, 
3036                                 pos=pos, 
3037                                 gui_style = DEFAULT_STYLE,
3038                                 size=size) 
3039        self.frame.Hide()
3040        self.s_screen = None
3041        temp_path = None
3042        try:
3043            _change_current_dir()
3044        except:
3045            pass
3046        try:
3047            self.open_file()
3048        except:
3049            msg = "%s Could not load " % str(APPLICATION_NAME)
3050            msg += "input file from command line.\n"
3051            logging.error(msg)
3052        # Display a splash screen on top of the frame.
3053        if len(sys.argv) > 1 and '--time' in sys.argv[1:]:
3054            log_time("Starting to display the splash screen")
3055        try:
3056            if os.path.isfile(SPLASH_SCREEN_PATH):
3057                self.s_screen = self.display_splash_screen(parent=self.frame, 
3058                                        path=SPLASH_SCREEN_PATH)
3059            else:
3060                self.frame.Show()   
3061        except:
3062            if self.s_screen is not None:
3063                self.s_screen.Close()
3064            msg = "Cannot display splash screen\n"
3065            msg += str (sys.exc_value)
3066            logging.error(msg)
3067            self.frame.Show()
3068 
3069        if hasattr(self.frame, 'special'):
3070            self.frame.special.SetCurrent()
3071        self.SetTopWindow(self.frame)
3072 
3073        return True
3074
3075    def open_file(self):
3076        """
3077        open a state file at the start of the application
3078        """
3079        input_file = None
3080        if len(sys.argv) >= 2:
3081            cmd = sys.argv[0].lower()
3082            basename  = os.path.basename(cmd)
3083            app_base = str(APPLICATION_NAME).lower()
3084            if os.path.isfile(cmd) or basename.lower() == app_base:
3085                app_py = app_base + '.py'
3086                app_exe = app_base + '.exe'
3087                app_app = app_base + '.app'
3088                if basename.lower() in [app_py, app_exe, app_app, app_base]:
3089                    data_base = sys.argv[1]
3090                    input_file = os.path.normpath(os.path.join(DATAPATH, 
3091                                                               data_base))
3092        if input_file is None:
3093            return
3094        if self.frame is not None:
3095            self.frame.set_input_file(input_file=input_file)
3096         
3097           
3098    def set_manager(self, manager):
3099        """
3100        Sets a reference to the application manager
3101        of the GUI manager (Frame)
3102        """
3103        self.frame.set_manager(manager)
3104       
3105    def build_gui(self):
3106        """
3107        Build the GUI
3108        """
3109        #try to load file at the start
3110        try:
3111            self.open_file()
3112        except:
3113            raise
3114        self.frame.build_gui()
3115        #if self.s_screen is not None and self.s_screen.IsShown():
3116        #    self.s_screen.Close()
3117       
3118    def set_welcome_panel(self, panel_class):
3119        """
3120        Set the welcome panel
3121       
3122        :param panel_class: class of the welcome panel to be instantiated
3123       
3124        """
3125        self.frame.set_welcome_panel(panel_class)
3126       
3127    def add_perspective(self, perspective):
3128        """
3129        Manually add a perspective to the application GUI
3130        """
3131        self.frame.add_perspective(perspective)
3132   
3133    def window_placement(self, size):
3134        """
3135        Determines the position and size of the application frame such that it
3136        fits on the user's screen without obstructing (or being obstructed by)
3137        the Windows task bar.  The maximum initial size in pixels is bounded by
3138        WIDTH x HEIGHT.  For most monitors, the application
3139        will be centered on the screen; for very large monitors it will be
3140        placed on the left side of the screen.
3141        """
3142        window_width, window_height = size
3143        screen_size = wx.GetDisplaySize()
3144        window_height = window_height if screen_size[1]>window_height else screen_size[1]-10
3145        window_width  = window_width if screen_size[0]> window_width else screen_size[0]-10
3146        xpos = ypos = 0
3147
3148        # Note that when running Linux and using an Xming (X11) server on a PC
3149        # with a dual  monitor configuration, the reported display size may be
3150        # that of both monitors combined with an incorrect display count of 1.
3151        # To avoid displaying this app across both monitors, we check for
3152        # screen 'too big'.  If so, we assume a smaller width which means the
3153        # application will be placed towards the left hand side of the screen.
3154
3155        _, _, x, y = wx.Display().GetClientArea() # size excludes task bar
3156        if len(sys.argv) > 1 and '--platform' in sys.argv[1:]:
3157            w, h = wx.DisplaySize()  # size includes task bar area
3158        # display on left side, not centered on screen
3159        if x > 1920 and x > (2*y): x = x / 2 
3160        if x > window_width:  xpos = (x - window_width)/2
3161        if y > window_height: ypos = (y - window_height)/2
3162
3163        # Return the suggested position and size for the application frame.
3164        return (xpos, ypos), (min(x, window_width), min(y, window_height))
3165   
3166    def display_splash_screen(self, parent, 
3167                              path=SPLASH_SCREEN_PATH):
3168        """Displays the splash screen.  It will exactly cover the main frame."""
3169       
3170        # Prepare the picture.  On a 2GHz intel cpu, this takes about a second.
3171        x, y = parent.GetSizeTuple()
3172        image = wx.Image(path, wx.BITMAP_TYPE_PNG)
3173        image.Rescale(SPLASH_SCREEN_WIDTH, 
3174                      SPLASH_SCREEN_HEIGHT, wx.IMAGE_QUALITY_HIGH)
3175        bm = image.ConvertToBitmap()
3176
3177        # Create and show the splash screen.  It will disappear only when the
3178        # program has entered the event loop AND either the timeout has expired
3179        # or the user has left clicked on the screen.  Thus any processing
3180        # performed in this routine (including sleeping) or processing in the
3181        # calling routine (including doing imports) will prevent the splash
3182        # screen from disappearing.
3183        #
3184        # Note that on Linux, the timeout appears to occur immediately in which
3185        # case the splash screen disappears upon entering the event loop.
3186        s_screen = wx.SplashScreen(bitmap=bm,
3187                         splashStyle=(wx.SPLASH_TIMEOUT|
3188                                              wx.SPLASH_CENTRE_ON_SCREEN),
3189                                 style=(wx.SIMPLE_BORDER|
3190                                        wx.FRAME_NO_TASKBAR|
3191                                        wx.STAY_ON_TOP),
3192                                       
3193                        milliseconds=SS_MAX_DISPLAY_TIME,
3194                        parent=parent,
3195                        id=wx.ID_ANY)
3196        from gui_statusbar import SPageStatusbar
3197        statusBar = SPageStatusbar(s_screen)
3198        s_screen.SetStatusBar(statusBar)
3199        s_screen.Bind(wx.EVT_CLOSE, self.on_close_splash_screen)
3200        s_screen.Show()
3201        return s_screen
3202       
3203       
3204    def on_close_splash_screen(self, event):
3205        """
3206        """
3207        self.frame.Show(True)
3208        event.Skip()
3209
3210if __name__ == "__main__": 
3211    app = ViewApp(0)
3212    app.MainLoop()
3213
3214             
Note: See TracBrowser for help on using the repository browser.