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

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

copied custom_conf file to .sansview too.

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