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

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

added data operation tool

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