eggification
[MosaicDocument.git] / Products / MosaicDocument / MosaicBlockInformation.py
diff --git a/Products/MosaicDocument/MosaicBlockInformation.py b/Products/MosaicDocument/MosaicBlockInformation.py
new file mode 100755 (executable)
index 0000000..444c791
--- /dev/null
@@ -0,0 +1,306 @@
+# -*- coding: utf-8 -*-
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+
+from OFS.ObjectManager import ObjectManager
+from OFS.SimpleItem import SimpleItem
+from OFS.PropertyManager import PropertyManager
+from Globals import InitializeClass, DTMLFile
+from Products.CMFCore.TypesTool import FactoryTypeInformation
+from Products.CMFCore.utils import getToolByName
+from types import InstanceType
+import config
+
+from AccessControl import ClassSecurityInfo, Unauthorized
+from Products.CMFCore.permissions import View, ModifyPortalContent, \
+     ManagePortal
+
+
+class RuleError(Exception) :
+    def __init__(self, errorMessage) :
+        self.errorMessage = errorMessage
+
+    def __str__(self) :
+        return self.errorMessage
+
+addMosaicBlockInformationForm = DTMLFile('dtml/addMosaicBlockForm', globals())
+
+def addMosaicBlockInformation(self, id=None, blockType = '', metaFti = None, REQUEST=None) :
+    """Add a MosaicBlock"""
+    if blockType :
+        metaFtis = config.getDefaultBlockMetaFtis()
+        if not metaFtis.has_key(blockType) :
+            raise ValueError, "Unknown block type : %s" % blockType
+        else :
+            blockFti = metaFtis[blockType]
+    elif metaFti :
+        blockFti = metaFti.copy()
+    else :
+        raise AttributeError, """
+        You must specify a default block type or a meta factory type information
+        """
+    if not id :
+        id = blockFti['id']
+    else :
+        blockFti['id'] = id
+
+    mb = MosaicBlockInformation(blockFti)
+    self._setObject(id, mb)
+
+    if REQUEST is not None:
+        REQUEST.RESPONSE.redirect('%s/manage_main' % self.absolute_url())
+    return id
+
+
+class MosaicBlockInformation(ObjectManager, FactoryTypeInformation) :
+    """Base Block"""
+    
+    meta_type = "Mosaic Block Information"
+    
+    isPrincipiaFolderish = 0
+
+    security = ClassSecurityInfo()
+
+    _fti_properties = FactoryTypeInformation._properties
+
+    _properties = (_fti_properties[:5] +
+                   ({'id':'template', 'type': 'string', 'mode':'w',
+                     'label':'Template'},
+                    {'id':'notify_wf', 'type': 'boolean', 'mode':'w',
+                     'label':'Notify Workflow Created'},) +
+                   _fti_properties[5:]
+                   )
+
+
+    manage_slotsForm = DTMLFile('dtml/slotsForm', globals())
+    manage_rulesForm = DTMLFile('dtml/rulesForm', globals())
+    manage_options = (FactoryTypeInformation.manage_options[:1] +
+                      ({'label'    : 'Slots', 'action'   : 'manage_slotsForm'},) +
+                      ({'label'    : 'Rules', 'action'   : 'manage_rulesForm'},) +
+                      FactoryTypeInformation.manage_options[1:]
+                      )
+    
+        
+    def __init__(self, blockFti) :
+        FactoryTypeInformation.__init__(self, **blockFti)
+
+        # init Slots informations
+        for slot in blockFti['slots'] :
+            slotInfo = SlotInfo(slot['id'], slot['type'], slotArgs = slot['args'])
+            self._setObject(slot['id'], slotInfo)
+
+        # init Rules informations
+        for rule in blockFti['rules'] :
+            ruleInfo = RuleInfo(rule['blockType'], rule['maxNbInstance'], rule['allowMove'], rule['mode'])
+            self._setObject(rule['blockType'], ruleInfo)
+                        
+
+    security.declareProtected(ManagePortal, 'manage_addSlot')
+    def manage_addSlot(self, id, type, REQUEST=None) :
+        """Add a slot contruction information"""
+        slotInfo = SlotInfo(id, type)
+        self._setObject(id, slotInfo)
+        if REQUEST :
+            return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
+
+    security.declareProtected(ManagePortal, 'saveSlots')
+    def saveSlots(self, REQUEST=None, **kw) :
+        """Save slots from ZMI form"""
+        # actualy the ':record' casting in an input form create an InstanceType instead of DictType
+        kw.update(REQUEST.form)
+        dicArgsListItems = [ (argKey, kw[argKey]) for argKey in kw.keys() if type(kw[argKey]) == InstanceType ]
+        for key, args in dicArgsListItems :
+            slotToEdit = getattr(self, key)
+            if key != args['id'] :
+                self.manage_renameObject(key, args['id'])
+                slotToEdit.id = args['id']
+            slotToEdit.type = args['type']
+        if REQUEST is not None:
+            return REQUEST.RESPONSE.redirect(REQUEST['URL1'] + '/manage_slotsForm?manage_tabs_message=Saved changes.')
+
+    security.declareProtected(ManagePortal, 'deleteSlots')
+    def deleteSlots(self, slotSelection=None, REQUEST=None) :
+        """Delete slots"""
+        if slotSelection :
+            self.manage_delObjects(ids=slotSelection)
+        if REQUEST :
+            return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
+
+
+
+    security.declareProtected(ManagePortal, 'manage_addSlot')
+    def manage_addRule(self, id, maxNbInstance, allowMove, mode, REQUEST=None) :
+        """Add a rule information"""
+        ruleInfo = RuleInfo(id, maxNbInstance, allowMove, mode)
+        self._setObject(id, ruleInfo)
+        if REQUEST :
+            return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
+
+    security.declareProtected(ManagePortal, 'saveSlots')
+    def saveRules(self, REQUEST=None, **kw) :
+        """Save rules from ZMI form"""
+        # actualy the ':record' casting in an input form create an InstanceType instead of DictType
+        kw.update(REQUEST.form)
+        dicArgsListItems = [ (argKey, kw[argKey]) for argKey in kw.keys() if type(kw[argKey]) == InstanceType ]
+        for key, kwords in dicArgsListItems :
+            ruleToEdit = getattr(self, key)
+            if key != kwords['id'] :
+                self.manage_renameObject(key, kwords['id'])
+                #slotToEdit.id = args['id']
+            kwArgs = {}
+            
+            for k in kwords.keys() : #kwords is an InstanceType not a DictType...
+                kwArgs[k] = kwords[k]
+                
+            ruleToEdit.edit(**kwArgs)
+            
+        if REQUEST is not None:
+            return REQUEST.RESPONSE.redirect(REQUEST['URL1'] + '/manage_rulesForm?manage_tabs_message=Saved changes.')
+
+    security.declareProtected(ManagePortal, 'deleteSlots')
+    def deleteRules(self, ruleSelection=None, REQUEST=None) :
+        """Delete rules"""
+        if ruleSelection :
+            self.manage_delObjects(ids=ruleSelection)
+        if REQUEST :
+            return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
+
+
+    def _checkConstructionRules(self, container) :
+        """Check """        
+        typesTool = getToolByName(self, 'mosaic_tool')
+        container_ti = typesTool.getTypeInfo(container)
+        rules = container_ti.objectValues(['Rule Information',])
+        container_subObjs = container.objectValues()
+
+        if self.getId() in map(lambda x : x.getId(), rules) :
+            maxNbInstance = container_ti._getOb(self.getId()).maxNbInstance
+            if maxNbInstance :
+                if maxNbInstance <= len( [sob for sob in container_subObjs if sob.portal_type == self.getId()])  :
+                    raise RuleError, "It's not allowed to add a new '%s', the quota is exceeded in this block" % \
+                          self.getId()
+                else :
+                    return 1
+            else :
+                return 1 # pas de limitation du nombre d'instance
+        else :
+            raise RuleError, "'%s' block type construction is not authorized in '%s'" % \
+                  (self.getId(), container_ti.getId())
+        
+
+    security.declarePublic('isConstructionAllowed')
+    def isConstructionAllowed ( self, container ):
+        """
+        check factory, permissions and rules
+        """
+        if FactoryTypeInformation.isConstructionAllowed ( self, container ) :
+            typesTool = getToolByName(self, 'mosaic_tool')
+            container_ti = typesTool.getTypeInfo(container)
+            if hasattr(container_ti, '_checkConstructionRules') :
+                try :
+                    return self._checkConstructionRules(container)
+                except RuleError :
+                    return 0
+            return 1
+        else :
+            return 0
+
+        
+    def _getFactoryMethod(self, container, check_security=1):
+        # pas très beau cette surcharge mais
+        # FactoryTypeInformation ne vérifie pas la
+        # possibilité de création par un appel à isConstructionAllowed.
+        
+        if not check_security : return FactoryTypeInformation._getFactoryMethod(self, container)
+        
+        if self.isConstructionAllowed(container) :
+            return FactoryTypeInformation._getFactoryMethod(self, container)
+
+        raise Unauthorized, ('Cannot create %s' % self.getId())        
+    
+    
+    security.declarePrivate('_constructInstance')
+    def _constructInstance(self, container, id, *args, **kw):
+        ob = super(MosaicBlockInformation, self)._constructInstance(container, id, *args, **kw)
+        typesTool = getToolByName(self, 'portal_types')
+        
+        # Add and init slots in block
+        for si in self.objectValues(['Slot Information',]) :
+            kw = {}
+            for key, value in si.propertyItems() :
+                kw[key] = value
+
+            typesTool.constructContent(si.type, ob, si.id, **kw)
+        return ob
+
+
+InitializeClass(MosaicBlockInformation)
+
+def addSlotInfo(dispatcher, id, type, slotArgs) :
+    pass
+
+class SlotInfo(SimpleItem, PropertyManager) :
+    """Encapsulate slot informations"""
+    meta_type="Slot Information"
+    _properties = ()
+    property_extensible_schema__ = 1
+
+    manage_propertiesForm = DTMLFile('dtml/properties', globals())
+    manage_options = PropertyManager.manage_options + SimpleItem.manage_options
+    
+    def __init__(self, id, type, slotArgs={}) :
+        self.id = id
+        self.type = type
+        for argId in slotArgs.keys() :
+            self.manage_addProperty(argId, slotArgs[argId]['value'], slotArgs[argId]['type'])
+            
+InitializeClass(PropertyManager)
+
+
+def addRuleInfo(dispatcher, id, **kw) :
+    pass
+
+class RuleInfo(SimpleItem):
+    """Encapsulate block rule informations"""
+    meta_type = 'Rule Information'
+
+    def __init__(self, id, maxNbInstance,
+                 allowMove, mode,
+                 allowMoveUpAndDown=0,
+                 allowMoveRightAndLeft=0) :
+        self.id = id # actualy Block Type name info
+        self.maxNbInstance = maxNbInstance
+        if allowMove :
+            self.allowMoveUpAndDown = 1
+            self.allowMoveRightAndLeft = 1
+        else :
+            self.allowMoveUpAndDown = allowMoveUpAndDown
+            self.allowMoveRightAndLeft = allowMoveRightAndLeft
+        self.allowMove = allowMove
+        self.mode = mode
+
+    security = ClassSecurityInfo()
+
+    security.declareProtected(ManagePortal, 'edit')
+    def edit(self, **kw) :
+        for key in kw.keys() :
+            if hasattr(self, key) :
+                setattr(self, key, kw[key])
+
+InitializeClass(RuleInfo)