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

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

changed sansview name to sansview (gui only)

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