Back to index

plone3  3.1.7
CMFDiffTool.py
Go to the documentation of this file.
00001 """CMFDiffTool.py
00002 
00003    Calculate differences between content objects
00004 """
00005 
00006 from zope.interface import implements
00007 
00008 from Acquisition import aq_base
00009 from AccessControl import ClassSecurityInfo
00010 from Globals import InitializeClass
00011 from OFS.SimpleItem import SimpleItem
00012 from Products.CMFCore.permissions import ManagePortal
00013 from Products.CMFCore.utils import registerToolInterface
00014 from Products.CMFCore.utils import UniqueObject
00015 from Products.CMFDiffTool.interfaces.portal_diff import portal_diff as IDiffToolZ2
00016 from Products.CMFDiffTool.interfaces import IDiffTool
00017 from Products.CMFDiffTool.ChangeSet import BaseChangeSet
00018 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
00019 
00020 
00021 class CMFDiffTool(UniqueObject, SimpleItem):
00022     """ """
00023 
00024     id = 'portal_diff'
00025     meta_type = 'CMF Diff Tool'
00026 
00027     security = ClassSecurityInfo()
00028 
00029     manage_options=(( {'label':'Configure', 'action':'manage_difftypes'},
00030                       {'label':'Overview', 'action':'manage_overview'},
00031                       ) + SimpleItem.manage_options
00032                     )
00033 
00034     __implements__ = (IDiffToolZ2)
00035     implements(IDiffTool)
00036 
00037     ## Internal attributes
00038     _difftypes = {}
00039 
00040     def __init__(self):
00041         self._pt_diffs = {}
00042 
00043     security.declareProtected(ManagePortal, 'manage_difftypes')
00044     manage_difftypes = PageTemplateFile('zpt/editCMFDiffTool', globals() )
00045 
00046 
00047     def manage_editDiffFields(self, updates, REQUEST=None):
00048         """Edit the portal type fields"""
00049 
00050         # Clear the old values
00051         del self._pt_diffs
00052         self._pt_diffs = {}
00053         for r in updates:
00054             if r.get('delete', None):
00055                 continue
00056             self.setDiffField(r.pt_name, r.field, r.diff)
00057 
00058         self._p_changed = 1
00059         
00060         if REQUEST:
00061             return self.manage_difftypes(manage_tabs_message="Diff mappings updated")
00062 
00063 
00064     security.declareProtected(ManagePortal, 'listDiffTypes')
00065     def manage_addDiffField(self, pt_name, field, diff, REQUEST=None):
00066         """Add a new diff field from the ZMI"""
00067         self.setDiffField(pt_name, field, diff)
00068         if REQUEST:
00069             return self.manage_difftypes(manage_tabs_message="Field added")
00070         
00071         
00072     def setDiffField(self, pt_name, field, diff):
00073         """Set the diff type for 'field' on the portal type 'pt_name' to 'diff'"""
00074         if pt_name not in self.portal_types.listContentTypes():
00075             raise 'BadRequest', "Error: invalid portal type"
00076 
00077         elif not field:
00078             raise 'BadRequest', "Error: no field specified"
00079 
00080         elif diff not in self.listDiffTypes():
00081             raise 'BadRequest', "Error: invalid diff type"
00082 
00083         else:
00084             self._pt_diffs.setdefault(pt_name, {})[field] = diff
00085             self._p_changed = 1
00086 
00087 
00088     ## Interface fulfillment ##
00089     security.declareProtected(ManagePortal, 'listDiffTypes')
00090     def listDiffTypes(self):
00091         """List the names of the registered difference types"""
00092         return self._difftypes.keys()
00093 
00094     security.declareProtected(ManagePortal, 'getDiffType')
00095     def getDiffType(self, diff):
00096         """Return a class corresponding to the specified diff type.
00097         Instances of the class will implement the IDifference
00098         interface"""
00099         return self._difftypes.get(diff, None)
00100 
00101     security.declareProtected(ManagePortal, 'setDiffForPortalType')
00102     def setDiffForPortalType(self, pt_name, mapping):
00103         """Set the difference type(self, s) for the specific portal type
00104 
00105         mapping is a dictionary where each key is an attribute or
00106         method on the given portal type, and the value is the name of
00107         a difference type."""
00108         # FIXME: Do some error checking
00109         self._pt_diffs[pt_name] = mapping.copy()
00110         self._p_changed = 1
00111 
00112     security.declareProtected(ManagePortal, 'getDiffForPortalType')
00113     def getDiffForPortalType(self, pt_name):
00114         """Returns a dictionary where each key is an attribute or
00115         method on the given portal type, and the value is the name of
00116         a difference type."""
00117         # Return a copy so we don't have to worry about the user changing it
00118         return self._pt_diffs.get(pt_name, {}).copy()
00119 
00120     security.declarePublic('computeDiff')
00121     def computeDiff(self, ob1, ob2, id1=None, id2=None):
00122         """Compute the differences between two objects and return the
00123         results as a list.  Each object in the list will implement the
00124         IDifference interface"""
00125 
00126         # Try to get the portal type from obj1 first.  If that fails, use obj2
00127         pt_name = ''
00128         try:
00129             pt_name = aq_base(ob1).portal_type
00130         except AttributeError:
00131             try:
00132                 pt_name = aq_base(ob2).portal_type
00133             except AttributeError:
00134                 pass
00135 
00136         diff_map = self._pt_diffs.get(pt_name, {})
00137 
00138         diffs = []
00139         for field, klass_name in diff_map.items():
00140             klass = self._difftypes[klass_name]
00141             f_diff = klass(ob1, ob2, field, id1=id1, id2=id2)
00142             # handle compound diff types
00143             if hasattr(f_diff, '__getitem__'):
00144                 diffs.extend(f_diff)
00145             else:
00146                 diffs.append(f_diff)
00147         return diffs
00148 
00149     security.declarePublic('createChangeSet')
00150     def createChangeSet(self, ob1, ob2, id1=None, id2=None):
00151         """Returns a ChangeSet object that represents the differences
00152         between ob1 and ob2 (ie. ob2 - ob1) ."""
00153         # FIXME: Pick a better ID
00154         cs = BaseChangeSet('Changes').__of__(self)
00155         cs.computeDiff(ob1, ob2, id1=id1, id2=id2)
00156         return aq_base(cs)
00157 
00158 
00159 def registerDiffType(klass):
00160     """Register a class for computing differences.
00161 
00162     Instances of the class must implement the IDifference
00163     interface."""
00164 
00165     CMFDiffTool._difftypes[klass.meta_type] = klass
00166 
00167 def unregisterDiffType(klass):
00168     """Register a class for computing differences.
00169 
00170     Instances of the class must implement the IDifference
00171     interface."""
00172 
00173     del CMFDiffTool._difftypes[klass.meta_type]
00174 
00175 
00176 InitializeClass(CMFDiffTool)
00177 registerToolInterface('portal_diff', IDiffTool)