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

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

Added showing "DataInfor?" from data panel as well as from plot

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