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

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

tracking missing ID plots

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