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

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 dd4344a was dd4344a, checked in by Mathieu Doucet <doucetm@…>, 12 years ago

Log errors instead of just skipping failing code.

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