Conservation de l'état de déroulement de l'arborescence (seulement pour le déroulement).
[MosaicDocument.git] / MosaicBlockInformation.py
1 # -*- coding: utf-8 -*-
2 # (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
3 # (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License version 2 as published
7 # by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 # 02111-1307, USA.
18 #
19
20
21 from OFS.ObjectManager import ObjectManager
22 from OFS.SimpleItem import SimpleItem
23 from OFS.PropertyManager import PropertyManager
24 from Globals import InitializeClass, DTMLFile
25 from Products.CMFCore.TypesTool import FactoryTypeInformation
26 from Products.CMFCore.utils import getToolByName
27 from types import InstanceType
28
29 from AccessControl import ClassSecurityInfo, Unauthorized
30 from Products.CMFCore.permissions import View, ModifyPortalContent, \
31 ManagePortal
32
33
34 class RuleError(Exception) :
35 def __init__(self, errorMessage) :
36 self.errorMessage = errorMessage
37
38 def __str__(self) :
39 return self.errorMessage
40
41 addMosaicBlockInformationForm = DTMLFile('dtml/addMosaicBlockForm', globals())
42
43 def addMosaicBlockInformation(self, id=None, blockType = '', metaFti = None, REQUEST=None) :
44 """Add a MosaicBlock"""
45 mosaicTool = self.mosaic_tool
46 if blockType :
47 metaFtis = mosaicTool.getDefaultBlockMetaFtis()
48 if not metaFtis.has_key(blockType) :
49 raise ValueError, "Unknown block type : %s" % blockType
50 else :
51 blockFti = metaFtis[blockType]
52 elif metaFti :
53 blockFti = metaFti.copy()
54 else :
55 raise AttributeError, """
56 You must specify a default block type or a meta factory type information
57 """
58 if not id :
59 id = blockFti['id']
60 else :
61 blockFti['id'] = id
62
63 mb = MosaicBlockInformation(blockFti)
64 self._setObject(id, mb)
65
66 if REQUEST is not None:
67 REQUEST.RESPONSE.redirect('%s/manage_main' % self.absolute_url())
68 return id
69
70
71 class MosaicBlockInformation(ObjectManager, FactoryTypeInformation) :
72 """Base Block"""
73
74 meta_type = "Mosaic Block Information"
75
76 isPrincipiaFolderish = 0
77
78 security = ClassSecurityInfo()
79
80 _fti_properties = FactoryTypeInformation._properties
81
82 _properties = (_fti_properties[:5] +
83 ({'id':'template', 'type': 'string', 'mode':'w',
84 'label':'Template'},
85 {'id':'notify_wf', 'type': 'boolean', 'mode':'w',
86 'label':'Notify Workflow Created'},) +
87 _fti_properties[5:]
88 )
89
90
91 manage_slotsForm = DTMLFile('dtml/slotsForm', globals())
92 manage_rulesForm = DTMLFile('dtml/rulesForm', globals())
93 manage_options = (FactoryTypeInformation.manage_options[:1] +
94 ({'label' : 'Slots', 'action' : 'manage_slotsForm'},) +
95 ({'label' : 'Rules', 'action' : 'manage_rulesForm'},) +
96 FactoryTypeInformation.manage_options[1:]
97 )
98
99
100 def __init__(self, blockFti) :
101 FactoryTypeInformation.__init__(self, **blockFti)
102
103 # init Slots informations
104 for slot in blockFti['slots'] :
105 slotInfo = SlotInfo(slot['id'], slot['type'], slotArgs = slot['args'])
106 self._setObject(slot['id'], slotInfo)
107
108 # init Rules informations
109 for rule in blockFti['rules'] :
110 ruleInfo = RuleInfo(rule['blockType'], rule['maxNbInstance'], rule['allowMove'], rule['mode'])
111 self._setObject(rule['blockType'], ruleInfo)
112
113
114 security.declareProtected(ManagePortal, 'manage_addSlot')
115 def manage_addSlot(self, id, type, REQUEST=None) :
116 """Add a slot contruction information"""
117 slotInfo = SlotInfo(id, type)
118 self._setObject(id, slotInfo)
119 if REQUEST :
120 return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
121
122 security.declareProtected(ManagePortal, 'saveSlots')
123 def saveSlots(self, REQUEST=None, **kw) :
124 """Save slots from ZMI form"""
125 # actualy the ':record' casting in an input form create an InstanceType instead of DictType
126 kw.update(REQUEST.form)
127 dicArgsListItems = [ (argKey, kw[argKey]) for argKey in kw.keys() if type(kw[argKey]) == InstanceType ]
128 for key, args in dicArgsListItems :
129 slotToEdit = getattr(self, key)
130 if key != args['id'] :
131 self.manage_renameObject(key, args['id'])
132 slotToEdit.id = args['id']
133 slotToEdit.type = args['type']
134 if REQUEST is not None:
135 return REQUEST.RESPONSE.redirect(REQUEST['URL1'] + '/manage_slotsForm?manage_tabs_message=Saved changes.')
136
137 security.declareProtected(ManagePortal, 'deleteSlots')
138 def deleteSlots(self, slotSelection=None, REQUEST=None) :
139 """Delete slots"""
140 if slotSelection :
141 self.manage_delObjects(ids=slotSelection)
142 if REQUEST :
143 return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
144
145
146
147 security.declareProtected(ManagePortal, 'manage_addSlot')
148 def manage_addRule(self, id, maxNbInstance, allowMove, mode, REQUEST=None) :
149 """Add a rule information"""
150 ruleInfo = RuleInfo(id, maxNbInstance, allowMove, mode)
151 self._setObject(id, ruleInfo)
152 if REQUEST :
153 return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
154
155 security.declareProtected(ManagePortal, 'saveSlots')
156 def saveRules(self, REQUEST=None, **kw) :
157 """Save rules from ZMI form"""
158 # actualy the ':record' casting in an input form create an InstanceType instead of DictType
159 kw.update(REQUEST.form)
160 dicArgsListItems = [ (argKey, kw[argKey]) for argKey in kw.keys() if type(kw[argKey]) == InstanceType ]
161 for key, kwords in dicArgsListItems :
162 ruleToEdit = getattr(self, key)
163 if key != kwords['id'] :
164 self.manage_renameObject(key, kwords['id'])
165 #slotToEdit.id = args['id']
166 kwArgs = {}
167
168 for k in kwords.keys() : #kwords is an InstanceType not a DictType...
169 kwArgs[k] = kwords[k]
170
171 ruleToEdit.edit(**kwArgs)
172
173 if REQUEST is not None:
174 return REQUEST.RESPONSE.redirect(REQUEST['URL1'] + '/manage_rulesForm?manage_tabs_message=Saved changes.')
175
176 security.declareProtected(ManagePortal, 'deleteSlots')
177 def deleteRules(self, ruleSelection=None, REQUEST=None) :
178 """Delete rules"""
179 if ruleSelection :
180 self.manage_delObjects(ids=ruleSelection)
181 if REQUEST :
182 return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
183
184
185 def _checkConstructionRules(self, container) :
186 """Check """
187 typesTool = getToolByName(self, 'mosaic_tool')
188 container_ti = typesTool.getTypeInfo(container)
189 rules = container_ti.objectValues(['Rule Information',])
190 container_subObjs = container.objectValues()
191
192 if self.getId() in map(lambda x : x.getId(), rules) :
193 maxNbInstance = container_ti._getOb(self.getId()).maxNbInstance
194 if maxNbInstance :
195 if maxNbInstance <= len( [sob for sob in container_subObjs if sob.portal_type == self.getId()]) :
196 raise RuleError, "It's not allowed to add a new '%s', the quota is exceeded in this block" % \
197 self.getId()
198 else :
199 return 1
200 else :
201 return 1 # pas de limitation du nombre d'instance
202 else :
203 raise RuleError, "'%s' block type construction is not authorized in '%s'" % \
204 (self.getId(), container_ti.getId())
205
206
207 security.declarePublic('isConstructionAllowed')
208 def isConstructionAllowed ( self, container ):
209 """
210 check factory, permissions and rules
211 """
212 if FactoryTypeInformation.isConstructionAllowed ( self, container ) :
213 typesTool = getToolByName(self, 'mosaic_tool')
214 container_ti = typesTool.getTypeInfo(container)
215 if hasattr(container_ti, '_checkConstructionRules') :
216 try :
217 return self._checkConstructionRules(container)
218 except RuleError :
219 return 0
220 return 1
221 else :
222 return 0
223
224
225 def _getFactoryMethod(self, container, check_security=1):
226 # pas très beau cette surcharge mais
227 # FactoryTypeInformation ne vérifie pas la
228 # possibilité de création par un appel à isConstructionAllowed.
229
230 if not check_security : return FactoryTypeInformation._getFactoryMethod(self, container)
231
232 if self.isConstructionAllowed(container) :
233 return FactoryTypeInformation._getFactoryMethod(self, container)
234
235 raise Unauthorized, ('Cannot create %s' % self.getId())
236
237
238 security.declarePrivate('_constructInstance')
239 def _constructInstance(self, container, id, *args, **kw):
240 ob = super(MosaicBlockInformation, self)._constructInstance(container, id, *args, **kw)
241 typesTool = getToolByName(self, 'portal_types')
242
243 # Add and init slots in block
244 for si in self.objectValues(['Slot Information',]) :
245 kw = {}
246 for key, value in si.propertyItems() :
247 kw[key] = value
248
249 typesTool.constructContent(si.type, ob, si.id, **kw)
250 return ob
251
252
253 InitializeClass(MosaicBlockInformation)
254
255 def addSlotInfo(dispatcher, id, type, slotArgs) :
256 pass
257
258 class SlotInfo(SimpleItem, PropertyManager) :
259 """Encapsulate slot informations"""
260 meta_type="Slot Information"
261 _properties = ()
262 property_extensible_schema__ = 1
263
264 manage_propertiesForm = DTMLFile('dtml/properties', globals())
265 manage_options = PropertyManager.manage_options + SimpleItem.manage_options
266
267 def __init__(self, id, type, slotArgs={}) :
268 self.id = id
269 self.type = type
270 for argId in slotArgs.keys() :
271 self.manage_addProperty(argId, slotArgs[argId]['value'], slotArgs[argId]['type'])
272
273 InitializeClass(PropertyManager)
274
275
276 def addRuleInfo(dispatcher, id, **kw) :
277 pass
278
279 class RuleInfo(SimpleItem):
280 """Encapsulate block rule informations"""
281 meta_type = 'Rule Information'
282
283 def __init__(self, id, maxNbInstance,
284 allowMove, mode,
285 allowMoveUpAndDown=0,
286 allowMoveRightAndLeft=0) :
287 self.id = id # actualy Block Type name info
288 self.maxNbInstance = maxNbInstance
289 if allowMove :
290 self.allowMoveUpAndDown = 1
291 self.allowMoveRightAndLeft = 1
292 else :
293 self.allowMoveUpAndDown = allowMoveUpAndDown
294 self.allowMoveRightAndLeft = allowMoveRightAndLeft
295 self.allowMove = allowMove
296 self.mode = mode
297
298 security = ClassSecurityInfo()
299
300 security.declareProtected(ManagePortal, 'edit')
301 def edit(self, **kw) :
302 for key in kw.keys() :
303 if hasattr(self, key) :
304 setattr(self, key, kw[key])
305
306 InitializeClass(RuleInfo)