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

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

reverted _change_current_dir until we solve the problem with opening sansview/data file from command line

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