Changeset 1497


Ignore:
Timestamp:
Sep 16, 2014 2:28:31 PM (9 years ago)
Author:
toby
Message:

logging more complete

Location:
branch/logging
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • branch/logging/GSASII.py

    r1477 r1497  
    123123    '''Define the main GSAS-II frame and its associated menu items
    124124    '''
     125    def MenuBinding(self,event):
     126        import log
     127        log.InvokeMenuCommand(event.GetId(),self,event)
     128           
     129    def Bind(self,eventtype,handler,*args,**kwargs):
     130        '''Override the Bind() function so that we can wrap calls that will be logged.
     131        '''
     132        import log
     133        #print 'main frame bind',handler
     134        if eventtype == wx.EVT_MENU and 'id' in kwargs:
     135            menulabels = log.SaveMenuCommand(kwargs['id'],self,handler)
     136            if menulabels:
     137                #print 'intercepting bind for',handler,menulabels,kwargs['id']
     138                wx.Frame.Bind(self,eventtype,self.MenuBinding,*args,**kwargs)
     139                return
     140        wx.Frame.Bind(self,eventtype,handler,*args,**kwargs)     
     141       
    125142   
    126143    def _Add_FileMenuItems(self, parent):
     
    16071624        return # success
    16081625
     1626       
     1627    def _init_Macro(self):
     1628        menu = self.MacroMenu
     1629        self.MacroRecordStatus = menu.Append(
     1630            help='Start or stop recording of menu actions, etc.', id=wx.ID_ANY,
     1631            kind=wx.ITEM_NORMAL,text='Record actions')
     1632        self.MacroRecordStatus.SetText('Stop recording') # debug, start w/logging enabled
     1633        import log
     1634        log.LogOn()           
     1635        def OnMacroRecordStatus(event):
     1636            import log
     1637            if 'actions' in self.MacroRecordStatus.GetText():
     1638                self.MacroRecordStatus.SetText('Stop recording')
     1639                log.LogOn()           
     1640            else:
     1641                self.MacroRecordStatus.SetText('Record actions')
     1642                log.LogOff()
     1643        self.Bind(wx.EVT_MENU, OnMacroRecordStatus, self.MacroRecordStatus)
     1644       
     1645        item = menu.Append(
     1646            help='Show logged commands', id=wx.ID_ANY,
     1647            kind=wx.ITEM_NORMAL,text='Show log')
     1648        def OnShowLog(event):
     1649            import log
     1650            print 70*'='
     1651            print 'List of logged actions'
     1652            for line in log.G2logList:
     1653                if line: print line
     1654            print 70*'='
     1655        self.Bind(wx.EVT_MENU, OnShowLog, item)
     1656
     1657        item = menu.Append(
     1658            help='Save logged commands to file', id=wx.ID_ANY,
     1659            kind=wx.ITEM_NORMAL,text='Save log')
     1660        def OnSaveLog(event):
     1661            import log
     1662            import cPickle
     1663            defnam = os.path.splitext(
     1664                os.path.split(self.GSASprojectfile)[1]
     1665                )[0]+'.gcmd'
     1666            dlg = wx.FileDialog(self,
     1667                'Choose an file to save past actions', '.', defnam,
     1668                'GSAS-II cmd output (*.gcmd)|*.gcmd',
     1669                wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
     1670            dlg.CenterOnParent()
     1671            try:
     1672                if dlg.ShowModal() == wx.ID_OK:
     1673                    filename = dlg.GetPath()
     1674                    # make sure extension is correct
     1675                    filename = os.path.splitext(filename)[0]+'.gcmd'
     1676                else:
     1677                    filename = None
     1678            finally:
     1679                dlg.Destroy()
     1680            if filename:
     1681                fp = open(filename,'wb')
     1682                fp.write(str(len(log.G2logList))+'\n')
     1683                for item in log.G2logList:
     1684                    cPickle.dump(item,fp)
     1685                fp.close()
     1686        self.Bind(wx.EVT_MENU, OnSaveLog, item)
     1687
     1688        item = menu.Append(
     1689            help='Load logged commands from file', id=wx.ID_ANY,
     1690            kind=wx.ITEM_NORMAL,text='Load log')
     1691        def OnLoadLog(event):
     1692            import log
     1693            import cPickle
     1694            defnam = os.path.splitext(
     1695                os.path.split(self.GSASprojectfile)[1]
     1696                )[0]+'.gcmd'
     1697            dlg = wx.FileDialog(self,
     1698                'Choose an file to read saved actions', '.', defnam,
     1699                'GSAS-II cmd output (*.gcmd)|*.gcmd',
     1700                wx.OPEN|wx.CHANGE_DIR)
     1701            dlg.CenterOnParent()
     1702            try:
     1703                if dlg.ShowModal() == wx.ID_OK:
     1704                    filename = dlg.GetPath()
     1705                    # make sure extension is correct
     1706                    filename = os.path.splitext(filename)[0]+'.gcmd'
     1707                else:
     1708                    filename = None
     1709            finally:
     1710                dlg.Destroy()
     1711            if filename and os.path.exists(filename):
     1712                fp = open(filename,'rb')
     1713                lines = fp.readline()
     1714                for i in range(int(lines)):
     1715                    log.G2logList.append(cPickle.load(fp))
     1716                fp.close()
     1717        self.Bind(wx.EVT_MENU, OnLoadLog, item)
     1718
     1719        item = menu.Append(
     1720            help='Replay saved commands', id=wx.ID_ANY,
     1721            kind=wx.ITEM_NORMAL,text='Replay log')
     1722        self.Bind(wx.EVT_MENU, log.ReplayLog, item)
     1723                               
    16091724    def _init_Exports(self,menu):
    16101725        '''Find exporter routines and add them into menus
     
    18141929        self._init_Exports(self.ExportMenu)
    18151930        self._Add_ExportMenuItems(self.ExportMenu)
     1931        self.MacroMenu = wx.Menu(title='')
     1932        menubar.Append(menu=self.MacroMenu, title='Macro')
     1933        self._init_Macro()
    18161934        HelpMenu=G2gd.MyHelp(self,helpType='Data tree',
    18171935            morehelpitems=[('&Tutorials','Tutorials')])
     
    18381956        #
    18391957        self.GSASIIMenu = wx.MenuBar()
     1958        # create a list of all dataframe menus (appended in PrefillDataMenu)
     1959        self.dataMenuBars = [self.GSASIIMenu]
    18401960        self.FillMainMenu(self.GSASIIMenu)
    18411961        self.SetMenuBar(self.GSASIIMenu)
     
    18491969        self.PatternTree = log.G2TreeCtrl(id=wxID_PATTERNTREE,
    18501970            parent=self.mainPanel, pos=wx.Point(0, 0),style=wx.TR_DEFAULT_STYLE )
    1851         self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED,
    1852             self.OnPatternTreeSelChanged, id=wxID_PATTERNTREE)
     1971        self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnPatternTreeSelChanged)
    18531972        self.PatternTree.Bind(wx.EVT_TREE_ITEM_COLLAPSED,
    18541973            self.OnPatternTreeItemCollapsed, id=wxID_PATTERNTREE)
  • branch/logging/GSASIIconstrGUI.py

    r1417 r1497  
    18271827
    18281828    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RigidBodyMenu)
    1829     G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddRigidBody, id=G2gd.wxID_RIGIDBODYADD)   
    1830     G2frame.dataFrame.Bind(wx.EVT_MENU, OnImportRigidBody, id=G2gd.wxID_RIGIDBODYIMPORT)
    1831     G2frame.dataFrame.Bind(wx.EVT_MENU, OnDefineTorsSeq, id=G2gd.wxID_RESIDUETORSSEQ)
     1829    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddRigidBody, id=G2gd.wxID_RIGIDBODYADD)
     1830    # no menu items yet   
     1831    #G2frame.dataFrame.Bind(wx.EVT_MENU, OnImportRigidBody, id=G2gd.wxID_RIGIDBODYIMPORT)
     1832    #G2frame.dataFrame.Bind(wx.EVT_MENU, OnDefineTorsSeq, id=G2gd.wxID_RESIDUETORSSEQ)
    18321833    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
    18331834
  • branch/logging/GSASIIgrid.py

    r1477 r1497  
    152152    wxID_PDFCOMPUTE, wxID_PDFCOMPUTEALL, wxID_PDFADDELEMENT, wxID_PDFDELELEMENT,
    153153] = [wx.NewId() for item in range(7)]
     154
     155[ wxID_MCRON,wxID_MCRLIST,wxID_MCRSAVE,wxID_MCRPLAY,
     156] = [wx.NewId() for item in range(4)]
    154157
    155158VERY_LIGHT_GREY = wx.Colour(235,235,235)
     
    26622665    where the functions to be called are defined.
    26632666    '''
    2664     def Bind(self,*args,**kwargs):
     2667    def Bind(self,eventtype,handler,*args,**kwargs):
    26652668        '''Override the Bind() function: on the Mac the binding is to
    26662669        the main window, so that menus operate with any window on top.
    2667         For other platforms, call the default wx.Frame Bind()
     2670        For other platforms, either wrap calls that will be logged
     2671        or call the default wx.Frame Bind() to bind to the menu item directly.
    26682672        '''
    26692673        if sys.platform == "darwin": # mac
    2670             self.G2frame.Bind(*args,**kwargs)
    2671         else:
    2672             wx.Frame.Bind(self,*args,**kwargs)     
     2674            self.G2frame.Bind(eventtype,handler,*args,**kwargs)
     2675            return
     2676        #print 'DataFrame Bind',eventtype,handler
     2677        if eventtype == wx.EVT_MENU and 'id' in kwargs:
     2678            menulabels = log.SaveMenuCommand(kwargs['id'],self.G2frame,handler)
     2679            if menulabels:
     2680                #print 'intercepting bind for',handler,menulabels,kwargs['id']
     2681                wx.Frame.Bind(self,eventtype,self.G2frame.MenuBinding,*args,**kwargs)
     2682                return
     2683            wx.Frame.Bind(self,eventtype,handler,*args,**kwargs)     
    26732684       
    26742685    def PrefillDataMenu(self,menu,helpType,helpLbl=None,empty=False):
     
    26782689        '''
    26792690        self.datamenu = menu
     2691        self.G2frame.dataMenuBars.append(menu)
    26802692        self.helpType = helpType
    26812693        self.helpLbl = helpLbl
     
    34153427                                    wx.aui.AUI_NB_SCROLL_BUTTONS)
    34163428        if size: self.SetSize(size)
     3429        self.parent = parent
     3430        self.PageChangeHandler = None
     3431        # Note, if needed create a Logging event to paint the window with the initial tab setting here
     3432
     3433    def PageChangeEvent(self,event):
     3434        import log
     3435        G2frame = self.parent.G2frame
     3436        page = event.GetSelection()
     3437        if self.PageChangeHandler:
     3438            if log.LogInfo['Logging']:
     3439                log.G2logList.append(log.TabLogEntry(
     3440                    G2frame.dataFrame.GetTitle(),
     3441                    G2frame.dataDisplay.GetPageText(page)
     3442                ))
     3443            self.PageChangeHandler(event)
     3444           
     3445    def Bind(self,eventtype,handler,*args,**kwargs):
     3446        '''Override the Bind() function so that page change events can be trapped
     3447        '''
     3448        if eventtype == wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED:
     3449            self.PageChangeHandler = handler
     3450            wx.aui.AuiNotebook.Bind(self,eventtype,self.PageChangeEvent)
     3451            return
     3452        wx.aui.AuiNotebook.Bind(self,eventtype,handler,*args,**kwargs)
     3453
     3454           
    34173455                                                     
    34183456    def Clear(self):       
  • branch/logging/GSASIIphsGUI.py

    r1477 r1497  
    31343134        shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
    31353135        SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
    3136         if generalData['doPawley'] and G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results'):
    3137             G2frame.dataFrame.RefineTexture.Enable(True)
    31383136        shAngles = ['omega','chi','phi']
    31393137        if Texture.GetSizer():
     
    52615259       
    52625260    def ChangePage(page):
    5263         # in development: Log Tab Selection
    5264         import log
    5265         log.LogTabPress(G2frame,page)
    52665261        text = G2frame.dataDisplay.GetPageText(page)
    5267 #        print 'Select',page,text
    52685262        if text == 'General':
    52695263            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.DataGeneral)
  • branch/logging/log.py

    r1477 r1497  
    11'Module to provide logging services'
    22import wx
    3 G2loggingData = {}
     3import GSASIIgrid as G2gd
     4MenuBindingLookup = {}
    45G2logList = [None]
     6'Contains a list of logged actions; first item is ignored'
     7LogInfo = {'Logging':False, 'Tree':None}
     8'Contains a dict with values that are needed in the module'
     9
     10debug = True
     11
     12# TODO:
     13### Note: no provinance info for histogram instrument parameters: need to remove insVal etc.
     14
     15# track histograms and phases with relative indices
     16
     17#===========================================================================
     18# objects for logging variables
     19def _l2s(lst,separator='+'):
     20    'Combine a list of objects into a string, with a separator'
     21    s = ''
     22    for i in lst:
     23        if s != '': s += separator
     24        s += '"'+str(i)+'"'
     25    return s
    526
    627class VarLogEntry(object):
     28    'object that tracks changes to a variable'
    729    def __init__(self,treeRefs,indexRefs,value):
    830        self.treeRefs = treeRefs
    931        self.indexRefs = indexRefs
    1032        self.value = value
    11 
    12 def LogVarChange(result,key):
    13     if hasattr(result,'treeRefs'):
    14         lastLog = G2logList[-1]
    15         fullrefs = result.indexRefs+[key]
    16         if type(lastLog) is VarLogEntry:
    17             if lastLog.treeRefs == result.treeRefs and lastLog.indexRefs == fullrefs:
    18                 lastLog.value = result[key]
    19                 print 'update last to ',result[key]
    20                 return
    21         G2logList.append(VarLogEntry(result.treeRefs,fullrefs,result[key]))
    22         print 'treeRefs',result.treeRefs,'indexRefs',fullrefs,'new value=',result[key]
    23     else:
    24         print key,'no provenance'
    25 
    26 class G2TreeCtrl(wx.TreeCtrl):
    27     '''Create a wrapper around the standard TreeCtrl so we can "trap"
    28     various events'''
    29     def __init__(self,parent=None,*args,**kwargs):
    30         super(self.__class__,self).__init__(parent=parent,*args,**kwargs)
    31         G2loggingData['frame'] = parent.GetParent()
    32         G2loggingData['tree'] = self
    33         G2loggingData['root'] = self.root = self.AddRoot('Loaded Data: ')
    34 
    35     def GetItemPyData(self,*args,**kwargs):
    36         data = super(self.__class__,self).GetItemPyData(*args,**kwargs)
    37         item = args[0]
    38         textlist = [self.GetItemText(item)]
    39         parent = self.GetItemParent(item)
    40         while parent:
    41             if parent == G2loggingData['root']: break
    42             textlist.insert(0,self.GetItemText(parent))
    43             parent = self.GetItemParent(parent)
    44         #print 'GetItemPyData from ',textlist,
    45         #data._treeorigin = textlist
    46         #print type(data)
    47         if type(data) is dict:
    48             #print 'dict'
    49             return dictLogged(data,textlist)
    50             #return data
    51         if type(data) is list:
    52             #print 'list'
    53             return listLogged(data,textlist)
    54         if type(data) is tuple:
    55             return listLogged(list(data),textlist)
    56         #print 'other'
    57         return data
    58 
    59 # class loggedDict(object):
    60 #     def __init__(self,dictobj,treeRefs,indexRefs=[]):
    61 #         self.treeRefs = treeRefs
    62 #         self.indexRefs = indexRefs
    63 #         self.obj = dictobj
    64 
    65 #     def __getitem__(self,*args,**kwargs):
    66 #         print 'getitem',args,kwargs,'...',
    67 #         val = self.obj.__getitem__(*args,**kwargs)
    68 # #        if type(val) is dict and len(args) == 1:
    69 # #            print 'dict'
    70 # #            return loggedDict(val,self.treeRefs,self.indexRefs+[args[0]])
    71 # #        elif type(val) is list and len(args) == 1:
    72 # #            print 'list'
    73 # #            return loggedList(val,self.treeRefs,self.indexRefs+[args[0]])
    74 # #        else:
    75 # #            print type(val),val
    76 # #            return val
    77 #         return val
    78 #     def get(self,*args,**kwargs):
    79 #         print 'get',args,kwargs
    80 #         val = self.obj.get(*args,**kwargs)
    81 #         if val is None: return None
    82 #         return self.__getitem__(*args,**kwargs)
    83 #     def __setitem__(self,*args,**kwargs):
    84 #         self.obj.__setitem__(*args,**kwargs)
    85 
    86        
    87 #     def __repr__(self):
    88 #         return "loggedDict with "+str(len(self.obj))+" members; from "+str(self.treeRefs)+" indexed by "+str(self.indexRefs)
    89 
    90 #     def __str__(self):
    91 #         return str(self.obj)
    92 
    93 #     def clear(self,*args,**kwargs):
    94 #         return self.obj.clear(*args,**kwargs)
    95 #     def copy(self,*args,**kwargs):
    96 #         return self.obj.copy(*args,**kwargs)
    97 #     def fromkeys(self,*args,**kwargs):
    98 #         return self.obj.fromkey(*args,**kwargs)
    99 #     def has_key(self,*args,**kwargs):
    100 #         return self.obj.has_key(*args,**kwargs)
    101 #     def items(self,*args,**kwargs):
    102 #         return self.obj.items(*args,**kwargs)
    103 #     def iteritems(self,*args,**kwargs):
    104 #         return self.obj.iteritems(*args,**kwargs)
    105 #     def iterkeys(self,*args,**kwargs):
    106 #         return self.obj.iterkeys(*args,**kwargs)
    107 #     def itervalues(self,*args,**kwargs):
    108 #         return self.obj.itervalues(*args,**kwargs)
    109 #     def keys(self,*args,**kwargs):
    110 #         return self.obj.keys(*args,**kwargs)
    111 #     def pop(self,*args,**kwargs):
    112 #         return self.obj.pop(*args,**kwargs)
    113 #     def popitem(self,*args,**kwargs):
    114 #         return self.obj.popitem(*args,**kwargs)
    115 #     def setdefault(self,*args,**kwargs):
    116 #         return self.obj.setdefault(*args,**kwargs)
    117 #     def update(self,*args,**kwargs):
    118 #         return self.obj.update(*args,**kwargs)
    119 #     def values(self,*args,**kwargs):
    120 #         return self.obj.values(*args,**kwargs)
    121 #     def viewitems(self,*args,**kwargs):
    122 #         return self.obj.viewitems(*args,**kwargs)
    123 #     def viewkeys(self,*args,**kwargs):
    124 #         return self.obj.viewkeys(*args,**kwargs)
    125 #     def viewvalues(self,*args,**kwargs):
    126 #         return self.obj.viewvalues(*args,**kwargs)
    127 
    128    
    129 
    130 # class loggedList(object):
    131 #     def __init__(self,listobj,treeRefs,indexRefs=[]):
    132 #         self.treeRefs = treeRefs
    133 #         self.indexRefs = indexRefs
    134 #         self.obj = listobj
    135 
    136 #     def __getitem__(self,*args,**kwargs):
    137 #         print 'list getitem',args,kwargs,'...',
    138 #         val = self.obj.__getitem__(*args,**kwargs)
    139 #         # if type(val) is dict and len(args) == 1:
    140 #         #     print 'dict'
    141 #         #     return loggedDict(val,self.treeRefs,self.indexRefs+[args[0]])
    142 #         # elif type(val) is list and len(args) == 1:
    143 #         #     print 'list'
    144 #         #     return loggedList(val,self.treeRefs,self.indexRefs+[args[0]])
    145 #         # else:
    146 #         #     print type(val),val
    147 #         #     return val
    148 #         return val
    149 
    150 #     def __len__(self,*args,**kwargs):
    151 #         return self.obj.__len__(*args,**kwargs)
    152 
    153 #     def __setitem__(self,*args,**kwargs):
    154 #         return self.obj.__setitem__(*args,**kwargs)
    155        
    156 #     def __repr__(self):
    157 #         return "loggedList with "+str(len(self.obj))+" members; from "+str(self.treeRefs)+" indexed by "+str(self.indexRefs)
    158 
    159 #     def __str__(self):
    160 #         return str(self.obj)
    161 
    162 ###############
     33        if debug: print 'Logging var change: w/treeRefs',treeRefs,'indexRefs',indexRefs,'new value=',value
     34    def __str__(self):
     35        return 'Variable change: Key(s)= '+_l2s(self.indexRefs)+' to value='+str(self.value)
     36
     37class MenuLogEntry(object):
     38    'object that tracks when a menu command is executed'
     39    def __init__(self,menulabellist):
     40        self.menulabellist = menulabellist
     41        if debug:
     42            t = menulabellist[:]
     43            t.reverse()
     44            l = ''
     45            for item in t:
     46                if l: l += ' -> '
     47                l += item
     48        if debug: print 'Logging menu command: '+l
     49    def __str__(self):
     50        return 'Menu press: From '+_l2s(self.menulabellist,'/')
     51           
     52class TabLogEntry(object):
     53    'Object to track when tabs are pressed in the DataFrame window'
     54    def __init__(self,title,tabname):
     55        self.wintitle = title
     56        self.tablabel = tabname
     57        if debug: print 'Logging tab: "'+tabname+'" on window titled '+title
     58    def __str__(self):
     59        return 'Tab press: Tab='+_l2s([self.tablabel])+' on window labeled '+str(self.wintitle)
     60
     61class TreeLogEntry(object):
     62    'Object to track when tree items are pressed in the main window'
     63    def __init__(self,itemlist):
     64        self.treeItemList = itemlist
     65        if debug: print 'Logging press on tree: "',itemlist
     66    def __str__(self):
     67        return 'Tree item pressed: '+_l2s(self.treeItemList)
     68           
    16369def _wrapper(func):
    16470    def _wrapped(self, *args, **kwargs):
     
    17581
    17682class dictLogged(object):
     83    '''A version of a dict object that tracks the source of the
     84    object back to the location on the G2 tree.
     85    If a list (tuple) or dict are pulled from inside this object
     86    the source information is appended to the provinance tracking
     87    lists.
     88
     89    tuples are converted to lists.
     90    '''
    17791    __metaclass__ = DictMeta
    17892
     
    18397
    18498    def __getitem__(self,key):
    185         #print "logging", key,
    18699        val = self.obj.__getitem__(key)   
    187100        if type(val) is tuple:
    188             print 'Converting to list',key
     101            #if debug: print 'Converting to list',key
    189102            val = list(val)
    190103            self.obj[key] = val
     
    195108            #print 'list'
    196109            return listLogged(val,self.treeRefs,self.indexRefs+[key])
    197         elif type(val) is tuple:
    198             print type(val),val
    199             raise Exception
    200             return val
    201110        else:
    202111            #print type(val)
    203112            return val
    204 #        return val
    205113
    206114    def __str__(self):
     
    216124
    217125class listLogged(object):
     126    '''A version of a list object that tracks the source of the
     127    object back to the location on the G2 tree.
     128    If a list (tuple) or dict are pulled from inside this object
     129    the source information is appended to the provinance tracking
     130    lists.
     131   
     132    tuples are converted to lists.
     133    '''
    218134    __metaclass__ = ListMeta
    219135
     
    224140
    225141    def __getitem__(self,key):
    226         #print "logging", key,
    227142        val = self.obj.__getitem__(key)   
    228143        if type(val) is tuple:
    229             print 'Converting to list',key,
     144            #if debug: print 'Converting to list',key
    230145            val = list(val)
    231146            self.obj[key] = val
     
    236151            #print 'list'
    237152            return listLogged(val,self.treeRefs,self.indexRefs+[key])
    238         elif type(val) is tuple:
    239             print type(val),val
    240             raise Exception
    241153        else:
    242154            #print type(val)
    243155            return val
    244         return self.obj.__getitem__(key)   
    245156
    246157    def __str__(self):
    247158        return self.obj.__str__() + " : " + str(self.treeRefs) + ',' + str(self.indexRefs)
    248 ###############
    249 
    250    
    251 def SimTreeEvent(treekeylist):
    252     # lookup key from list of items
    253     parent = G2loggingData['root']
    254     for txt in treekeylist:
    255         item = GetPatternTreeItemId(G2loggingData['frame'],parent,txt)
    256         if not item:
    257             print 'Not found',txt
     159
     160#===========================================================================
     161class G2TreeCtrl(wx.TreeCtrl):
     162    '''Create a wrapper around the standard TreeCtrl so we can "wrap"
     163    various events.
     164   
     165    This logs when a tree item is selected (in :meth:`onSelectionChanged`)
     166
     167    This also wraps lists and dicts pulled out of the tree to track where
     168    they were retrieved from.
     169    '''
     170    def __init__(self,parent=None,*args,**kwargs):
     171        super(self.__class__,self).__init__(parent=parent,*args,**kwargs)
     172        self.G2frame = parent.GetParent()
     173        self.root = self.AddRoot('Loaded Data: ')
     174        self.SelectionChanged = None
     175        self.repaintAction = None
     176        LogInfo['Tree'] = self
     177
     178    def _getTreeItemsList(self,item):
     179        '''Get the full tree hierarchy from a reference to a tree item.
     180        Note that this effectively hard-codes phase and histogram names in the
     181        returned list. We may want to make these names relative in the future.
     182        '''
     183        textlist = [self.GetItemText(item)]
     184        parent = self.GetItemParent(item)
     185        while parent:
     186            if parent == self.root: break
     187            textlist.insert(0,self.GetItemText(parent))
     188            parent = self.GetItemParent(parent)
     189        return textlist
     190
     191    def onSelectionChanged(self,event):
     192        '''Log each press on a tree item here.
     193        '''
     194        if self.SelectionChanged:
     195            textlist = self._getTreeItemsList(event.GetItem())
     196            if LogInfo['Logging']:
     197                G2logList.append(TreeLogEntry(textlist))
     198            self.SelectionChanged(event)
     199
     200    def Bind(self,eventtype,handler,*args,**kwargs):
     201        '''Override the Bind() function so that page change events can be trapped
     202        '''
     203        if eventtype == wx.EVT_TREE_SEL_CHANGED:
     204            self.SelectionChanged = handler
     205            wx.TreeCtrl.Bind(self,eventtype,self.onSelectionChanged)
    258206            return
    259         else:
    260             parent = item
     207        wx.TreeCtrl.Bind(self,eventtype,handler,*args,**kwargs)
     208
     209    def GetItemPyData(self,*args,**kwargs):
     210        '''Override the standard method to wrap the contents
     211        so that the source can be tracked
     212        '''
     213        data = super(self.__class__,self).GetItemPyData(*args,**kwargs)
     214        textlist = self._getTreeItemsList(args[0])
     215        if type(data) is dict:
     216            return dictLogged(data,textlist)
     217        if type(data) is list:
     218            return listLogged(data,textlist)
     219        if type(data) is tuple: #N.B. tuples get converted to lists
     220            return listLogged(list(data),textlist)
     221        return data
     222
     223    def ClearDataRepaint(self):
     224        self.repaintAction = None
     225
     226    def RepaintDataWindow(self):
     227        item = self.repaintAction
     228        if isinstance(item,TreeLogEntry):
     229            self.SelectItem(self.root) # need to select something else
     230            self.ReplayTreePress(item)
     231        elif isinstance(item,TabLogEntry):
     232            self.ReplayTabPress(item)
     233           
     234    def ReplayLogItem(self,item):
     235        'Execute an action taken from a log file entry'
     236        if isinstance(item,MenuLogEntry):
     237            self.ReplayMenuCommand(item)
     238        elif isinstance(item,TreeLogEntry):
     239            self.ReplayTreePress(item)
     240            self.repaintAction = item
     241        elif isinstance(item,VarLogEntry):
     242            self.ReplayVariableChange(item)
     243        elif isinstance(item,TabLogEntry):
     244            self.ReplayTabPress(item)
     245            self.repaintAction = item
     246        else:
     247            raise Exception("Unknown object in log: "+str(type(item))+": "
     248                            +str(item))
     249       
     250    def ReplayTreePress(self,logitem):
     251        'Perform a Tree press action when read from the log'
     252        parent = self.root
     253        for txt in logitem.treeItemList:
     254            item = G2gd.GetPatternTreeItemId(self.G2frame,parent,txt)
     255            if not item:
     256                print 'Not found',txt
     257                return
     258            else:
     259                parent = item
     260        else:
     261            self.SelectItem(item)
     262               
     263    def ReplayTabPress(self,logitem):
     264        'Perform a Tab press action when read from the log'
     265        wintitle = logitem.wintitle
     266        tabname = logitem.tablabel
     267        if self.G2frame.dataFrame.GetTitle() != wintitle:
     268            print self.G2frame.dataFrame.GetTitle(),' != ',wintitle
     269            raise Exception('tab in wrong window')
     270        for PageNum in range(self.G2frame.dataDisplay.GetPageCount()):
     271            if tabname == self.G2frame.dataDisplay.GetPageText(PageNum):
     272                self.G2frame.dataDisplay.SetSelection(PageNum)
     273                return
     274        else:
     275            print tabname,'not in',[
     276                self.G2frame.dataDisplay.GetPageText(PageNum) for
     277                PageNum in range(self.G2frame.dataDisplay.GetPageCount())]
     278            raise Exception('tab not found')
     279    def ReplayVariableChange(self,logitem):
     280        'Perform a Variable Change action, when read from the log'
     281        parentId = self.root
     282        for treeitem in logitem.treeRefs:
     283            item, cookie = self.GetFirstChild(parentId)
     284            while item:
     285                if self.GetItemText(item) == treeitem:
     286                    parentId = item
     287                    break
     288                else:
     289                    item, cookie = self.GetNextChild(parentId, cookie)
     290            else:
     291                raise Exception("Tree item not found for "+str(logitem))
     292        # get the inner most data array
     293        data = super(self.__class__,self).GetItemPyData(item)
     294        for item in logitem.indexRefs[:-1]:
     295            data = data[item]
     296        # set the value
     297        data[logitem.indexRefs[-1]] = logitem.value
     298    def ReplayMenuCommand(self,logitem):
     299        'Perform a Menu item action when read from the log'
     300        key = ''
     301        for item in logitem.menulabellist:
     302            if key: key += '+'
     303            key += item
     304        if MenuBindingLookup.get(key):
     305            MenuBindingLookup[key](None)
     306        else:
     307            raise Exception('No binding for menu item '+key)       
     308       
     309#===========================================================================
     310# variable tracking
     311def LogVarChange(result,key):
     312    'Called when a variable is changed to log that action'
     313    if not LogInfo['Logging']: return
     314    if hasattr(result,'treeRefs'):
     315        lastLog = G2logList[-1]
     316        fullrefs = result.indexRefs+[key]
     317        if type(lastLog) is VarLogEntry:
     318            if lastLog.treeRefs == result.treeRefs and lastLog.indexRefs == fullrefs:
     319                lastLog.value = result[key]
     320                if debug: print 'update last log to ',result[key]
     321                return
     322        G2logList.append(VarLogEntry(result.treeRefs,fullrefs,result[key]))
    261323    else:
    262         print 'found',G2loggingData['tree'].GetItemText(item)
    263         print item
    264         #code = wx.EVT_TREE_SEL_CHANGED.typeId
    265         #clickEvent = wx.TreeEvent(code, G2loggingData['tree'].GetId())
    266         #print clickEvent
    267         #clickEvent.SetItem(item)
    268         #G2loggingData['tree'].GetEventHandler().ProcessEvent(clickEvent)
    269     G2loggingData['tree'].SelectItem(item)   
    270 def SimTabPress(wintitle,tabname):
    271     if G2loggingData['frame'].dataFrame.GetTitle() != wintitle:
    272             print G2loggingData['frame'].dataFrame.GetTitle(),' != ','Phase Data for CuCr2O4'
    273             raise Exception('tab in wrong window')
    274     for PageNum in range(G2loggingData['frame'].dataDisplay.GetPageCount()):
    275         if tabname == G2loggingData['frame'].dataDisplay.GetPageText(PageNum):
    276             G2loggingData['frame'].dataDisplay.SetSelection(PageNum)
     324        print key,'Error: var change has no provenance info'
     325
     326#===========================================================================
     327# menu command tracking
     328def _getmenuinfo(id,G2frame,handler):
     329    '''Look up the menu/menu-item label tree from a menuitem's Id
     330   
     331    Note that menubars contain multiple menus which contain multiple menuitems.
     332    A menuitem can itself point to a menu and if so that menu can contain
     333    multiple menuitems.
     334
     335    Here we start with the last menuitem and look up the label for that as well
     336    as all parents, which will be found in parent menuitems (if any) and the menubar.
     337   
     338        menuitem    ->  menu ->  menubar
     339           |                          |
     340           |->itemlabel               |-> menulabel
     341           
     342    or
     343
     344        menuitem    ->  (submenu -> menuitem)*(n times) -> menu -> menubar
     345           |                            |                             |
     346           |->itemlabel                 |-> sublabel(s)               |-> menulabel
     347           
     348    :returns: a list containing all the labels (or None)           
     349    '''
     350    # don't worry about help menuitems
     351    if id == wx.ID_ABOUT: return
     352    # get the menu item object by searching through all menubars and then its label
     353    for menubar in G2frame.dataMenuBars:
     354        menuitem = menubar.FindItemById(id)
     355        if menuitem:
     356            #print 'getmenuinfo found',id,menuitem
     357            break
     358    else:
     359        print '****** getmenuinfo failed for id=',id,'binding to=',handler
     360        #raise Exception('debug: getmenuinfo failed')
     361        return
     362    menuLabelList = [menuitem.GetItemLabel()]
     363   
     364    # get the menu where the current item is located
     365    menu = menuitem.GetMenu()
     366    while menu.GetParent(): # is this menu a submenu of a previous menu?
     367        parentmenu = menu.GetParent()
     368        # cycle through the parentmenu until we find the menu
     369        for i in range(parentmenu.GetMenuItemCount()):
     370            if parentmenu.FindItemByPosition(i).GetSubMenu()==menu:
     371                menuLabelList += [parentmenu.FindItemByPosition(i).GetItemLabel()]
     372                break
     373        else:
     374            # menu not found in menu, something is wrong
     375            print 'error tracing menuitem to parent menu',menuLabelList
     376            #raise Exception('debug1: error tracing menuitem')
    277377            return
     378        menu = parentmenu
     379
     380    menubar = menu.MenuBar
     381    for i in range(menubar.GetMenuCount()):
     382        if menubar.GetMenu(i) == menu:
     383            menuLabelList += [menubar.GetMenuLabel(i)]
     384            break
    278385    else:
    279         print tabname,'not in',[
    280             G2loggingData['frame'].dataDisplay.GetPageText(PageNum) for
    281             PageNum in range(G2loggingData['frame'].dataDisplay.GetPageCount())]
    282         raise Exception('tab not found')
    283 def LogTabPress(G2frame,page):
    284     print 'Log page tab'
    285     print G2frame.dataFrame.GetTitle()
    286     print G2frame.dataDisplay.GetPageText(page)
    287        
     386        # menu not found in menubar, something is wrong
     387        print 'error tracing menuitem to menubar',menuLabelList
     388        #raise Exception('debug2: error tracing menuitem')
     389        return
     390    return menuLabelList
     391
     392def SaveMenuCommand(id,G2frame,handler):
     393    '''Creates a table of menu items and their pseudo-bindings
     394    '''
     395    menuLabelList = _getmenuinfo(id,G2frame,handler)
     396    if not menuLabelList: return
     397    key = ''
     398    for item in menuLabelList:
     399        if key: key += '+'
     400        key += item
     401    MenuBindingLookup[key] = handler
     402    return menuLabelList
     403
     404def InvokeMenuCommand(id,G2frame,event):
     405    '''Called when a menu item is used to log the action as well as call the
     406    routine "bind"ed to that menu item
     407    '''
     408    menuLabelList = _getmenuinfo(id,G2frame,None)
     409    key = ''
     410    if menuLabelList:
     411        for item in menuLabelList:
     412            if key: key += '+'
     413            key += item
     414    if key in MenuBindingLookup:
     415        if LogInfo['Logging']:
     416            G2logList.append(MenuLogEntry(menuLabelList))
     417        MenuBindingLookup[key](event)
     418    else:
     419        print 'Error no binding for menu command',menuLabelList,'id=',id
     420        return
     421
     422#===========================================================================
     423# Misc externally callable routines
     424def LogOn():
     425    'Turn On logging of actions'
     426    LogInfo['Logging'] = True
     427
     428def LogOff():
     429    'Turn Off logging of actions'
     430    LogInfo['Logging'] = False
     431
     432def ShowLogStatus():
     433    'Return the logging status'
     434    return LogInfo['Logging']
     435
     436def ReplayLog(event):
     437    'replay the logged actions (needs to be a wx.widget)'
     438    LogOff() # TODO: need to update menu item as well
     439    LogInfo['Tree'].ClearDataRepaint()
     440    print 70*'='
     441    print 'Performing logged actions:'
     442    for item in G2logList:
     443        if item:
     444            print item
     445            LogInfo['Tree'].ReplayLogItem(item)
     446            wx.Yield()
     447    # do repaint here
     448    LogInfo['Tree'].RepaintDataWindow()
     449    print 70*'='
     450   
     451   
     452   
Note: See TracChangeset for help on using the changeset viewer.