source: sasview/sansguiframe/src/sans/guiframe/gui_manager.py @ 2c068c7

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 2c068c7 was 2c068c7, checked in by Mathieu Doucet <doucetm@…>, 12 years ago

remove sys.path[0] again because it breaks linux installation

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