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

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

fixed plot symbol custom size dialog: had errors on cancel and invalid values

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