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

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

Fixing code style problems

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