[Zope3-checkins] CVS: Zope3/src/zope/app/utilities - content.py:1.2 instance.py:1.2 interfaces.py:1.2 mutableschemafield.py:1.2 configure.zcml:1.2 schema.py:1.2

Stephan Richter srichter at cosmos.phy.tufts.edu
Fri Aug 15 21:45:00 EDT 2003


Update of /cvs-repository/Zope3/src/zope/app/utilities
In directory cvs.zope.org:/tmp/cvs-serv20171/app/utilities

Modified Files:
	configure.zcml schema.py 
Added Files:
	content.py instance.py interfaces.py mutableschemafield.py 
Log Message:
Merging dreamcatcher's TTW Schema branch:

1. Fixed Bug in adding that would cause infinite loops when the menu items
   action was not a valif view or factory id.

2. Extended adding to support more complex views. Until now we only 
   supported constructions like "+/AddView=id". Now you are able to say
   "+/AddView/More=id", which means that more information can be carried 
   in the URL. This can be used in many ways, including multi-page adding
   wizards. In my case I needed it to pass in the type of the TTW Schema-
   based Content Component.

3. Added Local Menus. This was a pain in the butt, but I think I got a 
   fairly nice model, where you can create local Menu Services, and Menus
   are simply named utilities. When active they are menus in the menu 
   service. This is very similar to the local interface service and TTW 
   Schema. 

4. Made some modifications to TTW Schema, cleaned up the code and moved
   the browser code and interfaces to the places they belong.

5. Added a Content Component Definition utility component, which takes a
   Schema and creates a content component for it, including permission
   settings and a menu entry. Currently the menu entry is always made to
   a local 'add_content' menu. I will change this and make it actually a
   screen, where the menu and title of the menu item can be chosen by the
   developer. Mmmh, should I add a factory for the definition as well, so
   that the content component is also available via python?

6. Added a Content Component Instance component that represents an 
   instance od a Content Component Definition. You will never directly 
   encounter this component, since it is automatically used by the adding
   code of the Content Component Definition.

7. Cleanups by both dreamcatcher and myself.

That's it. For more details see the branch checkin messages. I now consider
the dreamcatcher-ttwschema-branch closed.


=== Zope3/src/zope/app/utilities/content.py 1.1 => 1.2 ===
--- /dev/null	Fri Aug 15 20:44:58 2003
+++ Zope3/src/zope/app/utilities/content.py	Fri Aug 15 20:44:21 2003
@@ -0,0 +1,146 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Content Component Definition and Instance
+
+$Id$
+"""
+__metaclass__ = type
+
+from persistence import Persistent
+from persistence.dict import PersistentDict
+from zope.app import zapi
+from zope.app.interfaces.container import IAdding
+from zope.app.interfaces.utilities.content import \
+     IContentComponentDefinition, IContentComponentInstance
+from zope.app.services.menu import LocalBrowserMenuItem
+from zope.app.services.servicenames import BrowserMenu
+from zope.app.services.utility import UtilityRegistration
+from zope.context import ContextMethod
+from zope.interface import directlyProvides, implements
+from zope.schema import getFields, getFieldsInOrder
+from zope.security.checker import CheckerPublic, Checker, defineChecker
+from zope.security.proxy import trustedRemoveSecurityProxy
+
+
+class ContentComponentDefinition(Persistent):
+
+    implements(IContentComponentDefinition)
+
+    def __init__(self, name=u'', schema=None):
+        self.name = name
+        self.schema = schema
+        self.permissions = PersistentDict()
+
+
+class ContentComponentDefinitionRegistration(UtilityRegistration):
+    """Content Component Registration"""
+
+    menuitem_id = None
+    menu = None
+
+    def activated(self):
+        """Once activated, we have to register the new Content Object with the
+        appropriate menu.
+        """
+        service = zapi.getService(self, BrowserMenu)
+        # XXX: Should use queryInheritedMenu()
+        self.menu = service.queryLocalMenu('add_content')
+        # Creating the menu item
+        # XXX: Should be configurable
+        item = LocalBrowserMenuItem()
+        item.interface = IAdding
+        item.action = 'AddContentComponent/' + self.name
+        item.title = self.name
+        item.permission = 'zope.ManageContent'
+        self.menuitem_id = self.menu.setObject('something', item)
+        component = self.getComponent()
+        component.name = self.name
+    activated = ContextMethod(activated)
+
+    def deactivated(self):
+        """Once activated, we have to unregister the new Content Object with
+        the appropriate menu."""
+        self.menu.__delitem__(self.menuitem_id)
+        self.menu = None
+        self.menuitem_id = None
+        component = self.getComponent()
+        component.name = '<component not activated>'
+    deactivated = ContextMethod(deactivated)
+
+
+class ContentComponentInstance(Persistent):
+
+    implements(IContentComponentInstance)
+
+    def __init__(self, name, schema, schemaPermissions=None):
+        super(ContentComponentInstance, self).__init__()
+
+        # Save the name of the object
+        self.__name__ = name
+
+        # XXX: We really should make a copy of the schema first, so that it
+        #      cannot be changed.
+        self.__schema = schema
+        # Add the new attributes, if there was a schema passed in
+        if schema is not None:
+            for name, field in getFields(schema).items():
+                setattr(self, name, field.default)
+            directlyProvides(self, schema)
+
+            # Build up a Checker rules and store it for later
+            if schemaPermissions is None:
+                schemaPermissions = {}
+            self.__checker_getattr = PersistentDict()
+            self.__checker_setattr = PersistentDict()
+            for name in getFields(schema):
+                get_perm, set_perm = schemaPermissions.get(name, (None, None))
+                self.__checker_getattr[name] = get_perm or CheckerPublic
+                self.__checker_setattr[name] = set_perm or CheckerPublic
+
+            # Always permit our class's public methods
+            self.__checker_getattr['getSchema'] = CheckerPublic
+
+
+    def __setattr__(self, key, value):
+        if (key in ('getSchema',) or
+            key.startswith('_p_') or
+            key.startswith('__') or
+            key.startswith('_ContentComponentInstance__')):
+            return super(ContentComponentInstance, self).__setattr__(key,
+                                                                     value)
+
+        is_schema_field = self.__schema is not None and \
+                          key in getFields(self.__schema).keys()
+
+        if is_schema_field:
+            super(ContentComponentInstance, self).__setattr__(key, value)
+        else:
+            raise AttributeError, 'Attribute not available'
+
+
+    def getSchema(self):
+        return self.__schema
+
+    def __repr__(self):
+        return '<ContentComponentInstance called %s>' %self.__name__
+
+
+def ContentComponentInstanceChecker(instance):
+    """A function that can be registered as a Checker in defineChecker()"""
+    return Checker(instance.__checker_getattr.get,
+                   instance.__checker_setattr.get)
+
+defineChecker(ContentComponentInstance, ContentComponentInstanceChecker)
+
+


=== Zope3/src/zope/app/utilities/instance.py 1.1 => 1.2 ===
--- /dev/null	Fri Aug 15 20:44:58 2003
+++ Zope3/src/zope/app/utilities/instance.py	Fri Aug 15 20:44:21 2003
@@ -0,0 +1,109 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Content Object Instance
+
+$Id$
+"""
+__metaclass__ = type
+
+from persistence import Persistent
+from persistence.dict import PersistentDict
+from zope.app.component.interfacefield import InterfaceField
+from zope.context import ContextMethod
+from zope.interface import directlyProvides, implements, Interface
+from zope.schema import getFields, TextLine
+from zope.security.checker import CheckerPublic, Checker, defineChecker
+
+
+class IContentComponentInstance(Interface):
+    """Interface describing a Conten Object Instance"""
+
+    __name__ = TextLine(
+        title=u"Name of Content Component Type",
+        description=u"""This is the name of the document type.""",
+        required=True)
+
+    __schema__ = InterfaceField(
+        title=u"Schema",
+        description=u"Specifies the schema that characterizes the document.",
+        required=True)
+
+
+class ContentComponentInstance(Persistent):
+
+    implements(IContentComponentInstance)
+
+    def __init__(self, name, schema, schemaPermissions=None):
+        super(ContentComponentInstance, self).__init__()
+
+        # Save the name of the object
+        self.__name__ = name
+
+        # XXX: We really should make a copy of the schema first, so that it
+        #      cannot be changed.
+        self.__schema = schema
+        # Add the new attributes, if there was a schema passed in
+        if schema is not None:
+            for name, field in getFields(schema).items():
+                setattr(self, name, field.default)
+            directlyProvides(self, schema)
+
+            # Build up a Checker rules and store it for later
+            if schemaPermissions is None:
+                schemaPermissions = {}
+            self.__checker_getattr = PersistentDict()
+            self.__checker_setattr = PersistentDict()
+            for name in getFields(schema):
+                get_perm, set_perm = schemaPermissions.get(name, (None, None))
+                self.__checker_getattr[name] = get_perm or CheckerPublic
+                self.__checker_setattr[name] = set_perm or CheckerPublic
+
+            # Always permit our class's public methods
+            self.__checker_getattr['getSchema'] = CheckerPublic
+
+
+    def __setattr__(self, key, value):
+        if (key in ('getSchema',) or
+            key.startswith('_p_') or
+            key.startswith('__') or
+            key.startswith('_ContentComponentInstance__')):
+            return super(ContentComponentInstance, self).__setattr__(key,
+                                                                     value)
+
+        is_schema_field = self.__schema is not None and \
+                          key in getFields(self.__schema).keys()
+
+        if is_schema_field:
+            super(ContentComponentInstance, self).__setattr__(key, value)
+        else:
+            raise AttributeError, 'Attribute not available'
+
+    __setattr__ = ContextMethod(__setattr__)
+
+
+    def getSchema(self):
+        return self.__schema
+
+    def __repr__(self):
+        return '<ContentComponentInstance called %s>' %self.__name__
+
+
+def ContentComponentInstanceChecker(instance):
+    """A function that can be registered as a Checker in defineChecker()"""
+    return Checker(instance.__checker_getattr.get,
+                   instance.__checker_setattr.get)
+
+defineChecker(ContentComponentInstance, ContentComponentInstanceChecker)
+
+


=== Zope3/src/zope/app/utilities/interfaces.py 1.1 => 1.2 ===
--- /dev/null	Fri Aug 15 20:44:59 2003
+++ Zope3/src/zope/app/utilities/interfaces.py	Fri Aug 15 20:44:21 2003
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Special Mutable Schema interfaces.
+
+$Id$
+"""
+from zope.interface import Interface
+from zope.app.utilities.mutableschemafield \
+     import MutableSchemaField, MutableSchemasField
+
+class IMutableSchemaContent(Interface):
+    """An interface for content that can choose a mutable schema
+    to be used for it"""
+
+    mutableschema = MutableSchemaField(
+        title=u"Mutable Schema to use",
+        description=u"""Mutable Schema to use as additional fields for """
+                    """this content type""")
+
+class IMutableSchemasContent(Interface):
+    """An interface for content that can choose a mutable schema
+    to be used for it"""
+
+    mutableschemas = MutableSchemasField(
+        title=u"Mutable Schemas to use",
+        description=u"""Mutable Schemas to use as additional fields for """
+                    """this content type""")


=== Zope3/src/zope/app/utilities/mutableschemafield.py 1.1 => 1.2 ===
--- /dev/null	Fri Aug 15 20:44:59 2003
+++ Zope3/src/zope/app/utilities/mutableschemafield.py	Fri Aug 15 20:44:21 2003
@@ -0,0 +1,92 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Defines fields that are used in mutable schemas.
+
+$Id$
+"""
+
+from zope.schema import Enumerated, Field, Tuple
+from zope.interface import Interface, implements
+from zope.interface.interfaces import IInterface
+from zope.interface import providedBy
+from zope.schema.interfaces import ValidationError
+from zope.app.interfaces.utilities.schema import IMutableSchemaField, \
+     IMutableSchemasField, IMutableSchema
+from zope.app.component.interfacefield import InterfaceField, InterfacesField
+
+class MutableSchemaField(InterfaceField):
+
+    __doc__ = IMutableSchemaField.__doc__
+    implements(IMutableSchemaField)
+    basetype = None
+
+    def __init__(self, basetype=IMutableSchema, *args, **kw):
+        # XXX Workaround for None indicating a missing value
+        if basetype is None:
+            kw['required'] = False
+        super(MutableSchemaField, self).__init__(basetype=basetype,
+                                                 *args, **kw)
+
+    def _validate(self, value):
+        basetype = self.basetype
+
+        if value is None and basetype is None:
+            return
+
+        if basetype is None:
+            basetype = IMutableSchema
+
+        if not IInterface.isImplementedBy(value):
+            raise ValidationError("Not an interface", value)
+
+        if basetype in providedBy(value):
+            return
+
+        if not value.extends(basetype, 0):
+            raise ValidationError("Does not extend", value, basetype)
+
+
+class MutableSchemasField(InterfacesField):
+
+    __doc__ = IMutableSchemasField.__doc__
+    implements(IMutableSchemasField)
+    basetype = None
+
+    def __init__(self, basetype=IMutableSchema, default=(), *args, **kw):
+        # XXX Workaround for None indicating a missing value
+        if basetype is None:
+            kw['required'] = False
+        super(MutableSchemasField, self).__init__(basetype=basetype,
+                                                  default=default, *args, **kw)
+
+    def _validate(self, value):
+        basetype = self.basetype
+
+        if value is () and basetype is None:
+            return
+
+        if basetype is None:
+            basetype = IMutableSchema
+
+        for v in value:
+            if not IInterface.isImplementedBy(v):
+                raise ValidationError("Not an interface", v)
+
+        for v in value:
+            if basetype in providedBy(v):
+                return
+
+        for v in value:
+            if not v.extends(basetype, 0):
+                raise ValidationError("Does not extend", v, basetype)


=== Zope3/src/zope/app/utilities/configure.zcml 1.1 => 1.2 ===
--- Zope3/src/zope/app/utilities/configure.zcml:1.1	Thu Aug  7 16:41:57 2003
+++ Zope3/src/zope/app/utilities/configure.zcml	Fri Aug 15 20:44:21 2003
@@ -1,17 +1,50 @@
-<configure
-  xmlns="http://namespaces.zope.org/zope"
-  xmlns:browser="http://namespaces.zope.org/browser">
+<configure xmlns="http://namespaces.zope.org/zope">
 
-  <content
-    class=".schema.SchemaUtility">
+<!-- Mutable Schema -->
+
+  <content class=".schema.SchemaUtility">
 
     <factory
+        permission="zope.ManageServices"
+        title="Mutable Schema"
+        description="A Persistent Schema that can be edited through the web"/>
+
+    <implements
+        interface="zope.app.interfaces.services.utility.ILocalUtility" />
+
+    <implements
+        interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
+
+    <require
+        permission="zope.ManageServices"
+        interface="zope.app.interfaces.utilities.schema.IMutableSchema" />
+
+    <require
+        permission="zope.ManageServices"
+        interface="zope.app.interfaces.utilities.schema.ISchemaUtility"
+        set_schema="zope.app.interfaces.utilities.schema.ISchemaUtility" />
+
+  </content>
+
+  <content class=".schema.SchemaRegistration">
+    <require
       permission="zope.ManageServices"
-      title="Persistent Schema Utility"
-      description="A Persistent Schema that can be edited through the web"
-      />
+      interface="zope.app.interfaces.services.utility.IUtilityRegistration
+                 zope.app.interfaces.container.IAddNotifiable
+                 zope.app.interfaces.container.IDeleteNotifiable"
+      set_schema="zope.app.interfaces.services.utility.IUtilityRegistration" />
+  </content>
 
-    <allow attributes="__name__" />
+
+<!-- Content Component Definition -->
+
+  <content class=".content.ContentComponentDefinition">
+
+    <factory
+      id="utility.ContentComponentDefinition"
+      permission="zope.ManageServices"
+      title="Content Component Definition"
+      description="A Persistent Content Component Definition" />
 
     <implements
       interface="zope.app.interfaces.services.utility.ILocalUtility" />
@@ -21,30 +54,30 @@
 
     <require
       permission="zope.ManageServices"
-      interface="zope.app.interfaces.schemagen.ISchemaSpec"
-      />
+      interface="
+          zope.app.interfaces.utilities.content.IContentComponentDefinition"
+      set_schema="
+          zope.app.interfaces.utilities.content.IContentComponentDefinition" />
 
   </content>
 
 
-  <!-- Menu entry for "add component" menu -->
-  <browser:menuItem
-      for="zope.app.interfaces.container.IAdding"
-      menu="add_component"
-      action="zope.app.utilities.schema.SchemaUtility"
-      title="Persistent Schema Utility"
-      description="A Persistent Schema that can be edited through the web"
+  <content class=".content.ContentComponentDefinitionRegistration">
+    <require
       permission="zope.ManageServices"
+      interface="zope.app.interfaces.services.utility.IUtilityRegistration
+                 zope.app.interfaces.container.IAddNotifiable
+                 zope.app.interfaces.container.IDeleteNotifiable"
+      set_schema="zope.app.interfaces.services.utility.IUtilityRegistration"
       />
+  </content>
+
+<!-- Content Component Instance -->
+
+  <content class=".content.ContentComponentInstance">
+    <implements
+      interface="zope.app.interfaces.annotation.IAttributeAnnotatable" />
+  </content>
 
-  <!-- Menu entry for "add utility" menu -->
-  <browser:menuItem
-      for="zope.app.interfaces.container.IAdding"
-      menu="add_utility"
-      action="zope.app.utilities.schema.SchemaUtility"
-      title="Persistent Schema Utility"
-      description="A Persistent Schema that can be edited through the web"
-      permission="zope.ManageServices"
-      />
 
 </configure>


=== Zope3/src/zope/app/utilities/schema.py 1.1 => 1.2 ===
--- Zope3/src/zope/app/utilities/schema.py:1.1	Thu Aug  7 16:41:57 2003
+++ Zope3/src/zope/app/utilities/schema.py	Fri Aug 15 20:44:21 2003
@@ -1,24 +1,65 @@
-from zope.interface import implements
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""TTW Schema (as Utility)
+
+$Id$
+"""
+from persistence.dict import PersistentDict
+from zope.app import zapi
+from zope.app.introspector import nameToInterface, interfaceToName
+from zope.app.browser.container.adding import Adding
+from zope.app.i18n import ZopeMessageIDFactory as _
+from zope.app.utilities.interfaces import IMutableSchemaContent
+from zope.app.interfaces.utilities.schema import \
+     ISchemaAdding, IMutableSchema, ISchemaUtility
 from zope.app.services.interface import PersistentInterfaceClass
-from zope.app.interfaces.utilities import IMutableSchema
+from zope.app.services.interface import PersistentInterface
+from zope.app.services.utility import UtilityRegistration
+from zope.context import ContextMethod
+from zope.interface import implements
+from zope.interface import directlyProvides, directlyProvidedBy
+from zope.proxy import removeAllProxies
 from zope.schema import getFieldsInOrder, getFieldNamesInOrder
+from zope.component.exceptions import ComponentLookupError
+
 
 class SchemaUtility(PersistentInterfaceClass):
 
-    implements(IMutableSchema)
+    implements(IMutableSchema, ISchemaUtility)
+
+    def __init__(self):
+        super(SchemaUtility, self).__init__('', (PersistentInterface,))
+        self.schemaPermissions = PersistentDict()
+
+    def setName(self, name):
+        """See zope.app.interfaces.utilities.IMutableSchema"""
+        self.__name__ = name
 
     def addField(self, name, field):
-        """Add a field to schema.
-        """
-        fields = getFieldNamesInOrder(self)
-        if name in fields:
+        """See zope.app.interfaces.utilities.IMutableSchema"""
+        fields = getFieldsInOrder(self)
+        field_names = [n for n, f in fields]
+        fields = [f for n, f in fields]
+        if name in field_names:
             raise KeyError, "Field %s already exists." % name
+        if fields:
+            field.order = fields[-1].order + 1
         self._setField(name, field)
         self._p_changed = 1
 
     def removeField(self, name):
-        """Remove field from schema.
-        """
+        """See zope.app.interfaces.utilities.IMutableSchema"""
         fields = getFieldNamesInOrder(self)
         if name not in fields:
             raise KeyError, "Field %s does not exists." % name
@@ -26,8 +67,7 @@
         self._p_changed = 1
 
     def renameField(self, orig_name, target_name):
-        """Rename field.
-        """
+        """See zope.app.interfaces.utilities.IMutableSchema"""
         fields = getFieldNamesInOrder(self)
         if orig_name not in fields:
             raise KeyError, "Field %s does not exists." % orig_name
@@ -39,8 +79,7 @@
         self._p_changed = 1
 
     def insertField(self, name, field, position):
-        """Insert a field at position.
-        """
+        """See zope.app.interfaces.utilities.IMutableSchema"""
         fields = getFieldsInOrder(self)
         field_names = [n for n, f in fields]
         fields = [f for n, f in fields]
@@ -58,8 +97,7 @@
         self._p_changed = 1
 
     def moveField(self, name, position):
-        """Move field to position.
-        """
+        """See zope.app.interfaces.utilities.IMutableSchema"""
         fields = getFieldsInOrder(self)
         field_names = [n for n, f in fields]
         fields = [f for n, f in fields]
@@ -78,7 +116,66 @@
         return self._InterfaceClass__attrs[name]
 
     def _setField(self, name, field):
+        if not field.__name__:
+            field.__name__ = name
         self._InterfaceClass__attrs[name] = field
 
     def _delField(self, name):
         del self._InterfaceClass__attrs[name]
+
+
+class SchemaAdding(Adding):
+
+    implements(ISchemaAdding)
+
+    menu_id = "add_schema_field"
+
+    def add(self, content):
+        name = self.contentName
+        container = zapi.getAdapter(self.context, IMutableSchema)
+        container.addField(name, content)
+        return zapi.ContextWrapper(content, container, name=name)
+
+    def nextURL(self):
+        """See zope.app.interfaces.container.IAdding"""
+        return (str(zapi.getView(self.context, "absolute_url", self.request))
+                + '/@@editschema.html')
+
+
+class SchemaRegistration(UtilityRegistration):
+    """Schema Registration
+
+    We have a custom registration here, since we want active registrations to
+    set the name of the schema.
+    """
+
+    def activated(self):
+        schema = self.getComponent()
+        schema.setName(self.name)
+    activated = ContextMethod(activated)
+
+    def deactivated(self):
+        schema = self.getComponent()
+        schema.setName('<schema not activated>')
+    deactivated = ContextMethod(deactivated)
+
+class MutableSchemaContent:
+
+    implements(IMutableSchemaContent)
+
+    schema_id = None
+    zapi.ContextAwareDescriptors()
+
+    def _set_schema(self, iface):
+        directlyProvides(self, iface)
+        self.schema_id = interfaceToName(self, iface)
+
+    def _get_schema(self):
+        provided = list(directlyProvidedBy(self))
+        schema = self.schema_id and \
+                 nameToInterface(self, self.schema_id) or None
+        if not schema in provided and schema is not None:
+            directlyProvides(self, schema)
+        return schema or provided and provided[0] or None
+
+    mutableschema = property(_get_schema, _set_schema)




More information about the Zope3-Checkins mailing list