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

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

changed label of taps and plot default title, and fixed loading text data

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