source: sasview/sansguiframe/src/sans/guiframe/gui_manager.py @ 8f5b34a

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 8f5b34a was cb8a972, checked in by Mathieu Doucet <doucetm@…>, 13 years ago

Re #3 remove fragile directory change

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