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

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

data/theory now can be saved from right-click-context menu in datapanel

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