Bugfix.
[Plinn.git] / HistoryAdapters.py
1 # -*- coding: utf-8 -*-
2 #######################################################################################
3 # Plinn - http://plinn.org #
4 # Copyright (C) 2005-2009 BenoƮt PIN <benoit.pin@ensmp.fr> #
5 # #
6 # This program is free software; you can redistribute it and/or #
7 # modify it under the terms of the GNU General Public License #
8 # as published by the Free Software Foundation; either version 2 #
9 # of the License, or (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program; if not, write to the Free Software #
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #
19 #######################################################################################
20 """
21 Adapters to plug specific contentish interfaces to historycal interface.
22
23
24
25 """
26
27 from Globals import InitializeClass
28 from AccessControl import ClassSecurityInfo
29 from Products.CMFCore.permissions import ModifyPortalContent
30 from permissions import ViewHistory
31 from difflib import SequenceMatcher
32 from ContentHistory import ContentHistory
33 from types import UnicodeType
34 from htmlentitydefs import name2codepoint
35 from cgi import escape
36 import re
37
38 rent = re.compile(r"&(?P<entName>[A-Za-z]+);")
39
40 class DocumentHistory(ContentHistory) :
41
42 security = ClassSecurityInfo()
43
44 security.declareProtected(ViewHistory, 'compare')
45 def compare(self, leftkey, rightkey):
46 leftRev, leftDate = self.getHistoricalRevisionByKey(leftkey)
47 rightRev, rightDate = self.getHistoricalRevisionByKey(rightkey)
48
49 left = leftRev.EditableBody()
50 right = rightRev.EditableBody()
51
52 infos = {'diff' : html_ready_diff(left, right)
53 ,'leftDate' : leftDate
54 ,'rightDate' : rightDate
55 ,'structure' : False}
56 return infos
57
58 security.declareProtected(ModifyPortalContent, 'restore')
59 def restore(self, key):
60 rev = self.getHistoricalRevisionByKey(key)[0]
61 self._content.edit(rev.Format(), rev.EditableBody())
62
63
64 InitializeClass(DocumentHistory)
65
66 class FolderishHistory(ContentHistory) :
67
68 security = ClassSecurityInfo()
69
70 security.declareProtected(ViewHistory, 'compare')
71 def compare(self, leftkey, rightkey):
72 leftRev, leftDate = self.getHistoricalRevisionByKey(leftkey)
73 rightRev, rightDate = self.getHistoricalRevisionByKey(rightkey)
74
75 leftIds = leftRev.objectIds()
76 leftTitleAndIds = []
77 for id in leftIds :
78 title = leftRev[id].Title()
79 if title != id :
80 leftTitleAndIds.append('%s (%s)' % (id, title))
81 else :
82 leftTitleAndIds.append('%s' % id)
83 left = '\n'.join(leftTitleAndIds)
84
85 rightIds = rightRev.objectIds()
86 rightTitleAndIds = []
87 for id in rightIds :
88 title = rightRev[id].Title()
89 if title != id :
90 rightTitleAndIds.append('%s (%s)' % (id, title))
91 else :
92 rightTitleAndIds.append('%s' % id)
93 right = '\n'.join(rightTitleAndIds)
94
95 infos = {'diff' : html_ready_diff(left, right)
96 ,'leftDate' : leftDate
97 ,'rightDate' : rightDate
98 ,'structure' : True}
99 return infos
100
101
102 security.declareProtected(ModifyPortalContent, 'restore')
103 def restore(self, key):
104 pass
105
106 InitializeClass(FolderishHistory)
107
108
109
110
111 InitializeClass(FolderishHistory)
112
113 def html_ready_diff(left, right, n=3) :
114 if isinstance(left, UnicodeType) :
115 left = left.encode('utf-8')
116 if isinstance(right, UnicodeType) :
117 right = right.encode('utf-8')
118 left = rent.sub(convertEnt, left)
119 right = rent.sub(convertEnt, right)
120 sm = SequenceMatcher()
121 leftLines = left.splitlines()
122 rightLines = right.splitlines()
123 sm.set_seqs(leftLines, rightLines)
124
125 groups = []
126 for i, group in enumerate(sm.get_grouped_opcodes(n)) :
127 groups.append([])
128 infos = groups[i]
129 for tag, i1, i2, j1, j2 in group :
130 info = {'tag' : tag
131 ,'left' : '\n'.join(leftLines[i1:i2])
132 ,'right' : '\n'.join(rightLines[j1:j2])}
133 infos.append(info)
134 return groups
135
136 def convertEnt(m):
137 """convert html entity to utf-8 encoded character
138 """
139 return unichr(name2codepoint.get(m.group('entName'), 32)).encode('utf-8')