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

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

bug fix on_tutorial

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