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

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 2365c0b was e9f6979, checked in by Jae Cho <jhjcho@…>, 12 years ago

Now got all the startup path right

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