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

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

added batch window tip and changed the menu position to the top

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