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

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 6e75ed0 was 6e75ed0, checked in by Robert Whitley <robert.whitley@…>, 12 years ago

Refs #36. Delete should be cross button and hide should be a toolbar button.

Clean up some warnings.

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