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

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

added max/min button in plotpanels

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