[CMF-checkins] SVN: CMF/branches/tseaver-viewification/ Resync with the trunk.

Tres Seaver tseaver at palladion.com
Fri Dec 2 13:15:45 EST 2005


Log message for revision 40498:
  Resync with the trunk.

Changed:
  U   CMF/branches/tseaver-viewification/CHANGES.txt
  U   CMF/branches/tseaver-viewification/CMFActionIcons/DEPENDENCIES.txt
  U   CMF/branches/tseaver-viewification/CMFActionIcons/__init__.py
  U   CMF/branches/tseaver-viewification/CMFActionIcons/exportimport.py
  U   CMF/branches/tseaver-viewification/CMFActionIcons/profiles/actionicons/skins.xml
  U   CMF/branches/tseaver-viewification/CMFCalendar/DEPENDENCIES.txt
  U   CMF/branches/tseaver-viewification/CMFCalendar/__init__.py
  U   CMF/branches/tseaver-viewification/CMFCalendar/profiles/default/skins.xml
  U   CMF/branches/tseaver-viewification/CMFCalendar/profiles/default/typestool.xml
  U   CMF/branches/tseaver-viewification/CMFCalendar/setuphandlers.py
  U   CMF/branches/tseaver-viewification/CMFCore/DEPENDENCIES.txt
  U   CMF/branches/tseaver-viewification/CMFCore/DirectoryView.py
  U   CMF/branches/tseaver-viewification/CMFCore/PortalContent.py
  U   CMF/branches/tseaver-viewification/CMFCore/TypesTool.py
  U   CMF/branches/tseaver-viewification/CMFCore/WorkflowTool.py
  U   CMF/branches/tseaver-viewification/CMFCore/__init__.py
  U   CMF/branches/tseaver-viewification/CMFCore/browser/configure.zcml
  A   CMF/branches/tseaver-viewification/CMFCore/browser/typeinfo.py
  U   CMF/branches/tseaver-viewification/CMFCore/configure.zcml
  D   CMF/branches/tseaver-viewification/CMFCore/dtml/addWorkflow.dtml
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/actions.py
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/cachingpolicymgr.py
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/catalog.py
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/configure.zcml
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/contenttyperegistry.py
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/cookieauth.py
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/mailhost.py
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/properties.py
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/skins.py
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/four/
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/one/
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_actions.py
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_cachingpolicymgr.py
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_catalog.py
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_content.py
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_contenttyperegistry.py
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_cookieauth.py
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_mailhost.py
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_properties.py
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_skins.py
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_typeinfo.py
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_workflow.py
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/three/
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/two/
  U   CMF/branches/tseaver-viewification/CMFCore/exportimport/typeinfo.py
  A   CMF/branches/tseaver-viewification/CMFCore/exportimport/workflow.py
  U   CMF/branches/tseaver-viewification/CMFCore/interfaces/_tools.py
  U   CMF/branches/tseaver-viewification/CMFCore/tests/base/testcase.py
  U   CMF/branches/tseaver-viewification/CMFCore/tests/test_ActionInformation.py
  U   CMF/branches/tseaver-viewification/CMFCore/tests/test_CachingPolicyManager.py
  U   CMF/branches/tseaver-viewification/CMFCore/tests/test_TypesTool.py
  U   CMF/branches/tseaver-viewification/CMFCore/tests/test_WorkflowTool.py
  D   CMF/branches/tseaver-viewification/CMFCore/www/addTypeInfo.zpt
  U   CMF/branches/tseaver-viewification/CMFDefault/DEPENDENCIES.txt
  U   CMF/branches/tseaver-viewification/CMFDefault/MetadataTool.py
  U   CMF/branches/tseaver-viewification/CMFDefault/__init__.py
  U   CMF/branches/tseaver-viewification/CMFDefault/browser/tests/linkviews.txt
  U   CMF/branches/tseaver-viewification/CMFDefault/dtml/metadataElementPolicies.dtml
  U   CMF/branches/tseaver-viewification/CMFDefault/dtml/metadataProperties.dtml
  U   CMF/branches/tseaver-viewification/CMFDefault/factory.py
  U   CMF/branches/tseaver-viewification/CMFDefault/profiles/default/catalog.xml
  U   CMF/branches/tseaver-viewification/CMFDefault/profiles/default/export_steps.xml
  U   CMF/branches/tseaver-viewification/CMFDefault/profiles/default/import_steps.xml
  A   CMF/branches/tseaver-viewification/CMFDefault/profiles/default/skins/
  U   CMF/branches/tseaver-viewification/CMFDefault/profiles/default/skins.xml
  U   CMF/branches/tseaver-viewification/CMFDefault/profiles/default/toolset.xml
  U   CMF/branches/tseaver-viewification/CMFDefault/profiles/default/typestool.xml
  U   CMF/branches/tseaver-viewification/CMFDefault/profiles/default/workflows.xml
  U   CMF/branches/tseaver-viewification/CMFDefault/setuphandlers.py
  U   CMF/branches/tseaver-viewification/CMFDefault/tests/test_DefaultWorkflow.py
  U   CMF/branches/tseaver-viewification/CMFDefault/tests/test_DiscussionReply.py
  U   CMF/branches/tseaver-viewification/CMFDefault/tests/test_Image.py
  U   CMF/branches/tseaver-viewification/CMFDefault/tests/test_MetadataTool.py
  U   CMF/branches/tseaver-viewification/CMFDefault/tests/test_Portal.py
  U   CMF/branches/tseaver-viewification/CMFDefault/tests/test_join.py
  D   CMF/branches/tseaver-viewification/CMFSetup/
  U   CMF/branches/tseaver-viewification/CMFTopic/DEPENDENCIES.txt
  U   CMF/branches/tseaver-viewification/CMFTopic/Topic.py
  U   CMF/branches/tseaver-viewification/CMFTopic/__init__.py
  A   CMF/branches/tseaver-viewification/CMFTopic/configure.zcml
  A   CMF/branches/tseaver-viewification/CMFTopic/exportimport.py
  U   CMF/branches/tseaver-viewification/CMFTopic/profiles/default/skins.xml
  U   CMF/branches/tseaver-viewification/CMFTopic/profiles/default/typestool.xml
  U   CMF/branches/tseaver-viewification/CMFTopic/profiles/default/workflows.xml
  U   CMF/branches/tseaver-viewification/CMFTopic/tests/test_DateC.py
  A   CMF/branches/tseaver-viewification/CMFTopic/tests/test_exportimport.py
  A   CMF/branches/tseaver-viewification/CMFTopic/xml/
  U   CMF/branches/tseaver-viewification/CMFUid/DEPENDENCIES.txt
  U   CMF/branches/tseaver-viewification/CMFUid/__init__.py
  U   CMF/branches/tseaver-viewification/DCWorkflow/DCWorkflow.py
  U   CMF/branches/tseaver-viewification/DCWorkflow/DEPENDENCIES.txt
  D   CMF/branches/tseaver-viewification/DCWorkflow/Default.py
  A   CMF/branches/tseaver-viewification/DCWorkflow/Extensions/
  U   CMF/branches/tseaver-viewification/DCWorkflow/__init__.py
  A   CMF/branches/tseaver-viewification/DCWorkflow/browser/
  A   CMF/branches/tseaver-viewification/DCWorkflow/configure.zcml
  A   CMF/branches/tseaver-viewification/DCWorkflow/exportimport.py
  A   CMF/branches/tseaver-viewification/DCWorkflow/interfaces.py
  A   CMF/branches/tseaver-viewification/DCWorkflow/profiles/
  U   CMF/branches/tseaver-viewification/DCWorkflow/tests/test_DCWorkflow.py
  A   CMF/branches/tseaver-viewification/DCWorkflow/tests/test_exportimport.py
  U   CMF/branches/tseaver-viewification/DCWorkflow/tests/test_guard.py
  U   CMF/branches/tseaver-viewification/DCWorkflow/utils.py
  A   CMF/branches/tseaver-viewification/DCWorkflow/xml/
  U   CMF/branches/tseaver-viewification/GenericSetup/CHANGES.txt
  U   CMF/branches/tseaver-viewification/GenericSetup/DEPENDENCIES.txt
  U   CMF/branches/tseaver-viewification/GenericSetup/MailHost/configure.zcml
  U   CMF/branches/tseaver-viewification/GenericSetup/MailHost/exportimport.py
  U   CMF/branches/tseaver-viewification/GenericSetup/MailHost/tests/test_exportimport.py
  A   CMF/branches/tseaver-viewification/GenericSetup/OFSP/
  U   CMF/branches/tseaver-viewification/GenericSetup/PluginIndexes/tests/test_exportimport.py
  A   CMF/branches/tseaver-viewification/GenericSetup/PythonScripts/
  U   CMF/branches/tseaver-viewification/GenericSetup/ZCTextIndex/tests/test_exportimport.py
  U   CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/configure.zcml
  U   CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/exportimport.py
  U   CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/tests/test_exportimport.py
  U   CMF/branches/tseaver-viewification/GenericSetup/__init__.py
  A   CMF/branches/tseaver-viewification/GenericSetup/bbb/
  A   CMF/branches/tseaver-viewification/GenericSetup/browser/
  U   CMF/branches/tseaver-viewification/GenericSetup/configure.zcml
  U   CMF/branches/tseaver-viewification/GenericSetup/content.py
  U   CMF/branches/tseaver-viewification/GenericSetup/context.py
  U   CMF/branches/tseaver-viewification/GenericSetup/interfaces.py
  U   CMF/branches/tseaver-viewification/GenericSetup/registry.py
  U   CMF/branches/tseaver-viewification/GenericSetup/testing.py
  U   CMF/branches/tseaver-viewification/GenericSetup/tests/common.py
  U   CMF/branches/tseaver-viewification/GenericSetup/tests/test_context.py
  U   CMF/branches/tseaver-viewification/GenericSetup/tests/test_registry.py
  U   CMF/branches/tseaver-viewification/GenericSetup/tool.py
  U   CMF/branches/tseaver-viewification/GenericSetup/utils.py

-=-
Modified: CMF/branches/tseaver-viewification/CHANGES.txt
===================================================================
--- CMF/branches/tseaver-viewification/CHANGES.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CHANGES.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -2,6 +2,29 @@
 
   New Features
 
+    - CMFDefault.MetadataTool:  support arbitrary additional schemas.
+      The "stock" DublinCore-specific API is still accessible, implemented
+      via a special "DCMI" subobject.
+
+    - WorkflowTool and DCWorkflow: Improved add form for workflow objects.
+      Presettings can now be loaded from workflow settings in setup profiles.
+      This replaces the feature that did allow to load presettings from the
+      oldstyle workflow factories registry.
+
+    - WorkflowTool: Switched to generic plug-in mechanism for workflows.
+      Any class registered for IWorkflowDefinition can now be used in the
+      WorkflowTool.
+
+    - DCWorkflow: Added 'revision2' profile.
+      This replaces the hardcoded 'Revision 2' default workflow.
+
+    - CMFActionIcons, CMFCalendar, CMFDefault, CMFTopic, CMFUid:
+      use the new 'for_' argument in GenericSetup's profile registry API
+      to indicate that profiles are intended for CMFCore's ISiteRoot sites.
+
+    - CMFTopic:  added specialized GenericSetup support for topics, to
+      allow capturing criteria in a single XML file.
+
     - CMFDefault and CMFTopic: Split off CMFTopic profile.
       CMFTopic support is now configured by an optional extension profile.
       CMFDefault no longer depends on CMFTopic.
@@ -20,7 +43,7 @@
     - ActionsTool: Improved add form for 'CMF Action' objects.
       Presettings can now be loaded from Action settings in setup profiles.
 
-    - CMFSetup and GenericSetup: Added catalog tool setup handlers.
+    - CMFCore and GenericSetup: Added catalog tool setup handlers.
       This includes node adapters for PluginIndexes, ZCTextIndex and ZCatalog.
       Support for additional indexes can be added by providing INodeExporter
       and INodeImporter adapters. All indexes are cleared by this handler, so
@@ -64,7 +87,7 @@
 
     - Replaced user messages by MassageIDs to improve the i18n support.
 
-    - CMFDefault CMFSetup profile: Added CMF BTree Folder to the list of
+    - CMFDefault GenericSetup profile: Added CMF BTree Folder to the list of
       automatically instantiated types in the types tool.
       (http://www.zope.org/Collectors/CMF/371)
 
@@ -94,9 +117,6 @@
 
   Bug Fixes
 
-    - CMFSetup: fixed empty attribute parsing when an encoding is
-      defined.
-
     - ActionProviderBase: getActionObject did stumble over newstyle Actions.
 
     - CMFCore.exportimport.content:  Ensure that BODYFILE in our "faux"
@@ -140,6 +160,11 @@
 
   Others
 
+    - CMFSetup and GenericSetup: Removed obsolete CMFSetup product.
+      Added __module_aliases__ to support setup tools created with CMFSetup. 
+
+    - DCWorkflow: Removed hardcoded default workflows.
+
     - Workflow: Removed deprecated WorkflowInformation and getActionsFor.
 
     - CMFCore and GenericSetup: Moved mechanisms for content export / import

Modified: CMF/branches/tseaver-viewification/CMFActionIcons/DEPENDENCIES.txt
===================================================================
--- CMF/branches/tseaver-viewification/CMFActionIcons/DEPENDENCIES.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFActionIcons/DEPENDENCIES.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,4 +1,4 @@
-Zope >= 2.8.2
+Zope >= 2.8.5
 Five >= 1.2
 CMFCore
 GenericSetup

Modified: CMF/branches/tseaver-viewification/CMFActionIcons/__init__.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFActionIcons/__init__.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFActionIcons/__init__.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -21,6 +21,7 @@
 try:
     from Products.CMFSetup import EXTENSION
     from Products.CMFSetup import profile_registry
+    from Products.CMFCore.interfaces import ISiteRoot
     has_profile_registry = True
 except ImportError:
     has_profile_registry = False
@@ -44,4 +45,6 @@
                                          'Adds action icon tool / settings.',
                                          'profiles/actionicons',
                                          'CMFActionIcons',
-                                         EXTENSION)
+                                         EXTENSION,
+                                         for_=ISiteRoot,
+                                        )

Modified: CMF/branches/tseaver-viewification/CMFActionIcons/exportimport.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFActionIcons/exportimport.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFActionIcons/exportimport.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -24,11 +24,11 @@
 
 from Products.CMFCore.utils import getToolByName
 
-from Products.CMFSetup.utils import CONVERTER
-from Products.CMFSetup.utils import DEFAULT
-from Products.CMFSetup.utils import ExportConfiguratorBase
-from Products.CMFSetup.utils import ImportConfiguratorBase
-from Products.CMFSetup.utils import KEY
+from Products.GenericSetup.utils import CONVERTER
+from Products.GenericSetup.utils import DEFAULT
+from Products.GenericSetup.utils import ExportConfiguratorBase
+from Products.GenericSetup.utils import ImportConfiguratorBase
+from Products.GenericSetup.utils import KEY
 
 from permissions import ManagePortal
 
@@ -75,6 +75,7 @@
 
     return 'Action icons tool settings exported.'
 
+
 class ActionIconsToolExportConfigurator(ExportConfiguratorBase):
     """ Synthesize XML description of cc properties.
     """
@@ -100,6 +101,7 @@
 
 InitializeClass(ActionIconsToolExportConfigurator)
 
+
 class ActionIconsToolImportConfigurator(ImportConfiguratorBase):
 
     def _getImportMapping(self):
@@ -115,4 +117,7 @@
              },
           }
 
+    def _convertToInteger(self, val):
+        return int(val.strip())
+
 InitializeClass(ActionIconsToolImportConfigurator)

Modified: CMF/branches/tseaver-viewification/CMFActionIcons/profiles/actionicons/skins.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFActionIcons/profiles/actionicons/skins.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFActionIcons/profiles/actionicons/skins.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,8 +1,8 @@
 <?xml version="1.0"?>
-<skins-tool>
- <skin-directory id="actionicons"
-                 directory="CMFActionIcons/skins/actionicons"/>
- <skin-path id="*">
+<object name="portal_skins" meta_type="CMF Skins Tool">
+ <object name="actionicons" meta_type="Filesystem Directory View"
+    directory="CMFActionIcons/skins/actionicons"/>
+ <skin-path name="*">
   <layer name="actionicons" insert-before="zpt_content"/>
  </skin-path>
-</skins-tool>
+</object>

Modified: CMF/branches/tseaver-viewification/CMFCalendar/DEPENDENCIES.txt
===================================================================
--- CMF/branches/tseaver-viewification/CMFCalendar/DEPENDENCIES.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCalendar/DEPENDENCIES.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,4 +1,4 @@
-Zope >= 2.8.2
+Zope >= 2.8.5
 Five >= 1.2
 CMFCore
 CMFDefault

Modified: CMF/branches/tseaver-viewification/CMFCalendar/__init__.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCalendar/__init__.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCalendar/__init__.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -19,6 +19,7 @@
 
 import utils
 from Products.CMFCore import utils
+from Products.CMFCore.interfaces import ISiteRoot
 from Products.CMFCore.DirectoryView import registerDirectory
 from Products.GenericSetup import EXTENSION
 from Products.GenericSetup import profile_registry
@@ -62,4 +63,6 @@
                                      'Adds calendar support.',
                                      'profiles/default',
                                      'CMFCalendar',
-                                     EXTENSION)
+                                     EXTENSION,
+                                     for_=ISiteRoot,
+                                    )

Modified: CMF/branches/tseaver-viewification/CMFCalendar/profiles/default/skins.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFCalendar/profiles/default/skins.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCalendar/profiles/default/skins.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,8 +1,8 @@
 <?xml version="1.0"?>
-<skins-tool>
- <skin-directory id="zpt_calendar"
-                 directory="CMFCalendar/skins/zpt_calendar"/>
- <skin-path id="*">
+<object name="portal_skins" meta_type="CMF Skins Tool">
+ <object name="zpt_calendar" meta_type="Filesystem Directory View"
+    directory="CMFCalendar/skins/zpt_calendar"/>
+ <skin-path name="*">
   <layer name="zpt_calendar" insert-before="zpt_content"/>
  </skin-path>
-</skins-tool>
+</object>

Modified: CMF/branches/tseaver-viewification/CMFCalendar/profiles/default/typestool.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFCalendar/profiles/default/typestool.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCalendar/profiles/default/typestool.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,4 +1,4 @@
 <?xml version="1.0"?>
-<types-tool>
- <type id="Event"/>
-</types-tool>
+<object name="portal_types" meta_type="CMF Types Tool">
+ <object name="Event" meta_type="Factory-based Type Information"/>
+</object>

Modified: CMF/branches/tseaver-viewification/CMFCalendar/setuphandlers.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCalendar/setuphandlers.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCalendar/setuphandlers.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -32,15 +32,19 @@
     # Set up a MetadataTool element policy for events
     try:
         _ = str # MetadataTool ist not aware of MessageIDs
-        mdtool.addElementPolicy(
+        mdtool.DCMI.addElementPolicy(
             element='Subject',
             content_type='Event',
             is_required=0,
             supply_default=0,
             default_value='',
             enforce_vocabulary=0,
-            allowed_vocabulary=(_('Appointment'), _('Convention'),
-                                _('Meeting'), _('Social Event'), _('Work')),
+            allowed_vocabulary=(_('Appointment'),
+                                _('Convention'),
+                                _('Meeting'),
+                                _('Social Event'),
+                                _('Work'),
+                               ),
             REQUEST=None)
     except MetadataError:
         pass

Modified: CMF/branches/tseaver-viewification/CMFCore/DEPENDENCIES.txt
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/DEPENDENCIES.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/DEPENDENCIES.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,3 +1,3 @@
-Zope >= 2.8.2
+Zope >= 2.8.5
 Five >= 1.2
 GenericSetup

Modified: CMF/branches/tseaver-viewification/CMFCore/DirectoryView.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/DirectoryView.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/DirectoryView.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -31,9 +31,11 @@
 from OFS.Folder import Folder
 from OFS.ObjectManager import bad_id
 from zLOG import LOG, ERROR
+from zope.interface import implements
 
 from FSMetadata import FSMetadata
 from FSObject import BadFile
+from interfaces import IDirectoryView
 from permissions import AccessContentsInformation
 from permissions import ManagePortal
 from utils import _dtmldir
@@ -390,15 +392,19 @@
             listFolderHierarchy(subob, subpath, rval, adding_meta_type)
 
 
-class DirectoryView (Persistent):
+class DirectoryView(Persistent):
+
     """ Directory views mount filesystem directories.
     """
+
+    implements(IDirectoryView)
+
     meta_type = 'Filesystem Directory View'
     _dirpath = None
     _properties = None
     _objects = ()
 
-    def __init__(self, id, dirpath, fullname=None, properties=None):
+    def __init__(self, id, dirpath='', fullname=None, properties=None):
         if properties:
             # Since props come from the filesystem, this should be
             # safe.
@@ -424,7 +430,7 @@
             if info is not None:
                 # update the directory view with a corrected path
                 self._dirpath = dirpath
-            else:
+            elif self._dirpath:
                 from warnings import warn
                 warn('DirectoryView %s refers to a non-existing path %s'
                      % (self.id, dirpath), UserWarning)
@@ -443,10 +449,13 @@
 InitializeClass(DirectoryView)
 
 
-class DirectoryViewSurrogate (Folder):
+class DirectoryViewSurrogate(Folder):
+
     """ Folderish DirectoryView.
     """
 
+    implements(IDirectoryView)
+
     meta_type = 'Filesystem Directory View'
     all_meta_types = ()
     _isDirectoryView = 1

Modified: CMF/branches/tseaver-viewification/CMFCore/PortalContent.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/PortalContent.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/PortalContent.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -69,7 +69,6 @@
     # The security for FTP methods aren't set up by default in our
     # superclasses...  :(
     security.declareProtected(FTPAccess, 'manage_FTPstat')
-    security.declareProtected(FTPAccess, 'manage_FTPget')
     security.declareProtected(FTPAccess, 'manage_FTPlist')
 
     def failIfLocked(self):

Modified: CMF/branches/tseaver-viewification/CMFCore/TypesTool.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/TypesTool.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/TypesTool.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -17,7 +17,6 @@
 
 from sys import exc_info
 from warnings import warn
-from xml.dom.minidom import parseString
 
 import Products
 from AccessControl import ClassSecurityInfo
@@ -39,8 +38,6 @@
 def MessageID(val, domain): # XXX performance?
     return MessageFactory(domain)(val)
 
-from Products.GenericSetup.interfaces import INodeImporter
-
 from ActionProviderBase import ActionProviderBase
 from exceptions import AccessControl_Unauthorized
 from exceptions import BadRequest
@@ -68,9 +65,8 @@
 
 class TypeInformation(SimpleItemWithProperties, ActionProviderBase):
 
+    """ Base class for information about a content type.
     """
-    Base class for information about a content type.
-    """
 
     _isTypeInformation = 1
 
@@ -454,14 +450,12 @@
 
 class FactoryTypeInformation(TypeInformation):
 
+    """ Portal content factory.
     """
-    Portal content factory.
-    """
 
     implements(ITypeInformation)
     __implements__ = z2ITypeInformation
 
-    meta_type = 'Factory-based Type Information'
     security = ClassSecurityInfo()
 
     _properties = (TypeInformation._basic_properties + (
@@ -563,14 +557,12 @@
 
 class ScriptableTypeInformation( TypeInformation ):
 
+    """ Invokes a script rather than a factory to create the content.
     """
-    Invokes a script rather than a factory to create the content.
-    """
 
     implements(ITypeInformation)
     __implements__ = z2ITypeInformation
 
-    meta_type = 'Scriptable Type Information'
     security = ClassSecurityInfo()
 
     _properties = (TypeInformation._basic_properties + (
@@ -619,86 +611,6 @@
 InitializeClass( ScriptableTypeInformation )
 
 
-_addTypeInfo_template = PageTemplateFile('addTypeInfo.zpt', _wwwdir)
-
-def manage_addFactoryTIForm(dispatcher, REQUEST):
-    """ Get the add form for factory-based type infos.
-    """
-    template = _addTypeInfo_template.__of__(dispatcher)
-    meta_type = FactoryTypeInformation.meta_type
-    return template(add_meta_type=meta_type,
-                    profiles=_getProfileInfo(dispatcher, meta_type))
-
-def manage_addScriptableTIForm(dispatcher, REQUEST):
-    """ Get the add form for scriptable type infos.
-    """
-    template = _addTypeInfo_template.__of__(dispatcher)
-    meta_type = ScriptableTypeInformation.meta_type
-    return template(add_meta_type=meta_type,
-                    profiles=_getProfileInfo(dispatcher, meta_type))
-
-def _getProfileInfo(dispatcher, meta_type):
-    profiles = []
-    stool = getToolByName(dispatcher, 'portal_setup', None)
-    if stool:
-        for info in stool.listContextInfos():
-            type_ids = []
-            context = stool._getImportContext(info['id'])
-            filenames = context.listDirectory('types')
-            if filenames is None:
-                continue
-            for filename in filenames:
-                body = context.readDataFile(filename, subdir='types')
-                if body is None:
-                    continue
-                root = parseString(body).documentElement
-                if root.getAttribute('meta_type') == meta_type:
-                    type_id = root.getAttribute('name')
-                    type_ids.append(type_id)
-            if not type_ids:
-                continue
-            type_ids.sort()
-            profiles.append({'id': info['id'],
-                             'title': info['title'],
-                             'type_ids': tuple(type_ids)})
-    return tuple(profiles)
-
-def manage_addTypeInfo(dispatcher, add_meta_type, id, settings_id='',
-                       REQUEST=None):
-    """Add a new TypeInformation object of type 'add_meta_type' with ID 'id'.
-    """
-    settings_node = None
-    if settings_id:
-        stool = getToolByName(dispatcher, 'portal_setup', None)
-        if stool:
-            profile_id, type_id = settings_id.split('/')
-            context = stool._getImportContext(profile_id)
-            filenames = context.listDirectory('types')
-            for filename in filenames or ():
-                body = context.readDataFile(filename, subdir='types')
-                if body is not None:
-                    root = parseString(body).documentElement
-                    if root.getAttribute('name') != type_id:
-                        continue
-                    if root.getAttribute('meta_type') == add_meta_type:
-                        settings_node = root
-                        if not id:
-                            id = type_id
-                        break
-    for mt in Products.meta_types:
-        if mt['name'] == add_meta_type:
-            klass = mt['instance']
-            break
-    else:
-        raise ValueError('Meta type %s is not a type class.' % add_meta_type)
-    obj = klass(id)
-    if settings_node:
-        INodeImporter(obj).importNode(settings_node)
-    dispatcher._setObject(id, obj)
-
-    if REQUEST:
-        return dispatcher.manage_main(dispatcher, REQUEST)
-
 allowedTypes = [
     'Script (Python)',
     'Python Method',
@@ -710,9 +622,8 @@
 class TypesTool(UniqueObject, IFAwareObjectManager, Folder,
                 ActionProviderBase):
 
+    """ Provides a configurable registry of portal content types.
     """
-        Provides a configurable registry of portal content types.
-    """
 
     implements(ITypesTool)
     __implements__ = (z2ITypesTool, ActionProviderBase.__implements__)

Modified: CMF/branches/tseaver-viewification/CMFCore/WorkflowTool.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/WorkflowTool.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/WorkflowTool.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -23,9 +23,11 @@
 from Globals import InitializeClass
 from Globals import PersistentMapping
 from OFS.Folder import Folder
+from OFS.ObjectManager import IFAwareObjectManager
 from zope.interface import implements
 
 from ActionProviderBase import ActionProviderBase
+from interfaces import IWorkflowDefinition
 from interfaces import IWorkflowTool
 from interfaces.portal_workflow import portal_workflow as z2IWorkflowTool
 from permissions import ManagePortal
@@ -40,7 +42,8 @@
 _marker = []  # Create a new marker object.
 
 
-class WorkflowTool(UniqueObject, Folder, ActionProviderBase):
+class WorkflowTool(UniqueObject, IFAwareObjectManager, Folder,
+                   ActionProviderBase):
 
     """ Mediator tool, mapping workflow objects
     """
@@ -50,6 +53,7 @@
 
     id = 'portal_workflow'
     meta_type = 'CMF Workflow Tool'
+    _product_interfaces = (IWorkflowDefinition,)
 
     _chains_by_type = None  # PersistentMapping
     _default_chain = ('default_workflow',)
@@ -69,37 +73,6 @@
     security.declareProtected( ManagePortal, 'manage_overview' )
     manage_overview = DTMLFile( 'explainWorkflowTool', _dtmldir )
 
-    _manage_addWorkflowForm = DTMLFile('addWorkflow', _dtmldir)
-
-    security.declareProtected( ManagePortal, 'manage_addWorkflowForm')
-    def manage_addWorkflowForm(self, REQUEST):
-
-        """ Form for adding workflows.
-        """
-        wft = []
-        for key in _workflow_factories.keys():
-            wft.append(key)
-        wft.sort()
-        return self._manage_addWorkflowForm(REQUEST, workflow_types=wft)
-
-    security.declareProtected( ManagePortal, 'manage_addWorkflow')
-    def manage_addWorkflow(self, workflow_type, id, RESPONSE=None):
-
-        """ Adds a workflow from the registered types.
-        """
-        factory = _workflow_factories[workflow_type]
-        ob = factory(id)
-        self._setObject(id, ob)
-        if RESPONSE is not None:
-            RESPONSE.redirect(self.absolute_url() +
-                              '/manage_main?management_view=Contents')
-
-    def all_meta_types(self):
-        return (
-            {'name': 'Workflow',
-             'action': 'manage_addWorkflowForm',
-             'permission': ManagePortal },)
-
     _manage_selectWorkflows = DTMLFile('selectWorkflows', _dtmldir)
 
     security.declareProtected( ManagePortal, 'manage_selectWorkflows')
@@ -426,8 +399,7 @@
         self._default_chain = tuple(ids)
 
     security.declareProtected( ManagePortal, 'setChainForPortalTypes')
-    def setChainForPortalTypes(self, pt_names, chain):
-
+    def setChainForPortalTypes(self, pt_names, chain, verify=True):
         """ Set a chain for a specific portal type.
         """
         cbt = self._chains_by_type
@@ -437,12 +409,12 @@
         if isinstance(chain, basestring):
             chain = [ wf.strip() for wf in chain.split(',') if wf.strip() ]
 
-        ti = self._listTypeInfo()
-        for t in ti:
-            id = t.getId()
-            if id in pt_names:
-                cbt[id] = tuple(chain)
+        ti_ids = [ t.getId() for t in self._listTypeInfo() ]
 
+        for type_id in pt_names:
+            if verify and not (type_id in ti_ids):
+                continue
+            cbt[type_id] = tuple(chain)
 
     security.declareProtected( ManagePortal, 'updateRoleMappings')
     def updateRoleMappings(self, REQUEST=None):
@@ -464,11 +436,11 @@
 
     security.declarePrivate('getWorkflowById')
     def getWorkflowById(self, wf_id):
-
         """ Retrieve a given workflow.
         """
         wf = getattr(self, wf_id, None)
-        if getattr(wf, '_isAWorkflow', 0):
+        if getattr(wf, '_isAWorkflow', False) or \
+                IWorkflowDefinition.providedBy(wf):
             return wf
         else:
             return None
@@ -651,29 +623,3 @@
             ob.reindexObjectSecurity()
 
 InitializeClass(WorkflowTool)
-
-
-_workflow_factories = {}
-
-def _makeWorkflowFactoryKey(factory, id=None, title=None):
-    # The factory should take one argument, id.
-    if id is None:
-        id = getattr(factory, 'id', '') or getattr(factory, 'meta_type', '')
-    if title is None:
-        title = getattr(factory, 'title', '')
-    key = id
-    if title:
-        key = key + ' (%s)' % title
-    return key
-
-def addWorkflowFactory(factory, id=None, title=None):
-    key = _makeWorkflowFactoryKey( factory, id, title )
-    _workflow_factories[key] = factory
-
-def _removeWorkflowFactory( factory, id=None, title=None ):
-    """ Make teardown in unitcase cleaner. """
-    key = _makeWorkflowFactoryKey( factory, id, title )
-    try:
-        del _workflow_factories[key]
-    except KeyError:
-        pass

Modified: CMF/branches/tseaver-viewification/CMFCore/__init__.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/__init__.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/__init__.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -36,7 +36,6 @@
 
 from interfaces import IAction
 from interfaces import IActionCategory
-from interfaces import ITypeInformation
 from permissions import AddPortalFolders
 from permissions import ManagePortal
 
@@ -97,7 +96,7 @@
     utils.initializeBasesPhase2(z_tool_bases, context)
 
     context.registerClass(
-        DirectoryView.DirectoryViewSurrogate,
+        DirectoryView.DirectoryView,
         constructors=(('manage_addDirectoryViewForm',
                        DirectoryView.manage_addDirectoryViewForm),
                       DirectoryView.manage_addDirectoryView,
@@ -143,24 +142,10 @@
         visibility=None,
         interfaces=(IAction,))
 
-    context.registerClass(
-        TypesTool.FactoryTypeInformation,
-        permission=ManagePortal,
-        constructors=(TypesTool.manage_addFactoryTIForm,
-                      TypesTool.manage_addTypeInfo),
-        icon='images/typeinfo.gif',
-        visibility=None,
-        interfaces=(ITypeInformation,))
-
-    context.registerClass(
-        TypesTool.ScriptableTypeInformation,
-        permission=ManagePortal,
-        constructors=(TypesTool.manage_addScriptableTIForm,
-                      TypesTool.manage_addTypeInfo),
-        icon='images/typeinfo.gif',
-        visibility=None,
-        interfaces=(ITypeInformation,))
-
+    utils.registerIcon(TypesTool.FactoryTypeInformation,
+                       'images/typeinfo.gif', globals())
+    utils.registerIcon(TypesTool.ScriptableTypeInformation,
+                       'images/typeinfo.gif', globals())
     utils.registerIcon(FSDTMLMethod.FSDTMLMethod,
                        'images/fsdtml.gif', globals())
     utils.registerIcon(FSPythonScript.FSPythonScript,

Modified: CMF/branches/tseaver-viewification/CMFCore/browser/configure.zcml
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/browser/configure.zcml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/browser/configure.zcml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,9 +1,34 @@
 <configure
-  xmlns="http://namespaces.zope.org/zope"
-  xmlns:browser="http://namespaces.zope.org/browser"
-  i18n_domain="cmf"
-  >
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    xmlns:five="http://namespaces.zope.org/five"
+    i18n_domain="cmf"
+    >
 
+  <five:traversable class="Products.CMFCore.WorkflowTool.WorkflowTool"/>
+
+  <five:traversable class="Products.CMFCore.TypesTool.TypesTool"/>
+
+  <configure package="Products.GenericSetup.browser">
+
+    <browser:page
+        for="zope.app.container.interfaces.IAdding"
+        name="addFactoryTypeInformation.html"
+        template="addWithPresettings.pt"
+        class="Products.CMFCore.browser.typeinfo.FactoryTypeInformationAddView"
+        permission="cmf.ManagePortal"
+        />
+
+    <browser:page
+        for="zope.app.container.interfaces.IAdding"
+        name="addScriptableTypeInformation.html"
+        template="addWithPresettings.pt"
+        class="Products.CMFCore.browser.typeinfo.ScriptableTypeInformationAddView"
+        permission="cmf.ManagePortal"
+        />
+
+  </configure>
+
   <!-- Set up default menus as action categories. -->
   <browser:menu
     id="object"

Copied: CMF/branches/tseaver-viewification/CMFCore/browser/typeinfo.py (from rev 40492, CMF/trunk/CMFCore/browser/typeinfo.py)

Modified: CMF/branches/tseaver-viewification/CMFCore/configure.zcml
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/configure.zcml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/configure.zcml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,12 +1,26 @@
 <configure
-    xmlns="http://namespaces.zope.org/zope">
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:five="http://namespaces.zope.org/five"
+    >
 
-  <include
-      package=".browser"
+  <include package=".browser"/>
+
+  <include package=".exportimport"/>
+
+  <five:registerClass
+      class=".TypesTool.FactoryTypeInformation"
+      meta_type="Factory-based Type Information"
+      addview="addFactoryTypeInformation.html"
+      permission="cmf.ManagePortal"
+      global="False"
       />
 
-  <include
-      package=".exportimport"
+  <five:registerClass
+      class=".TypesTool.ScriptableTypeInformation"
+      meta_type="Scriptable Type Information"
+      addview="addScriptableTypeInformation.html"
+      permission="cmf.ManagePortal"
+      global="False"
       />
 
 </configure>

Deleted: CMF/branches/tseaver-viewification/CMFCore/dtml/addWorkflow.dtml
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/dtml/addWorkflow.dtml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/dtml/addWorkflow.dtml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,44 +0,0 @@
-<dtml-let form_title="'Add workflow'">
-<dtml-var manage_page_header>
-<dtml-var manage_form_title>
-</dtml-let>
-
-<form action="manage_addWorkflow" method="POST">
-<table cellspacing="0" cellpadding="2" border="0">
-  <tr>
-    <td align="left" valign="top">
-    <div class="form-label">
-    Id
-    </div>
-    </td>
-    <td align="left" valign="top">
-    <input type="text" name="id" size="40" />
-    </td>
-  </tr>
-  <tr>
-    <td align="left" valign="top">
-    <div class="form-label">
-    Type
-    </label></div>
-    </td>
-    <td align="left" valign="top">
-    <dtml-in workflow_types>
-      <input type="radio" name="workflow_type" value="&dtml-sequence-item;">
-      &dtml-sequence-item;<br />
-    </dtml-in>
-    </td>
-  </tr>
-  <tr>
-    <td align="left" valign="top">
-    </td>
-    <td align="left" valign="top">
-    <div class="form-element">
-    <input class="form-element" type="submit" name="submit" 
-     value=" Add " /> 
-    </div>
-    </td>
-  </tr>
-</table>
-</form>
-
-<dtml-var manage_page_footer>

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/actions.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/actions.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/actions.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,11 +15,15 @@
 $Id$
 """
 
+from zope.app import zapi
+
+from Products.GenericSetup.interfaces import IBody
 from Products.GenericSetup.interfaces import PURGE, UPDATE
 from Products.GenericSetup.utils import I18NURI
 from Products.GenericSetup.utils import NodeAdapterBase
 from Products.GenericSetup.utils import ObjectManagerHelpers
 from Products.GenericSetup.utils import PropertyManagerHelpers
+from Products.GenericSetup.utils import XMLAdapterBase
 
 from Products.CMFCore.interfaces import IAction
 from Products.CMFCore.interfaces import IActionCategory
@@ -29,6 +33,7 @@
         import ActionProvider as z2IActionProvider
 from Products.CMFCore.utils import getToolByName
 
+_FILENAME = 'actions.xml'
 _SPECIAL_PROVIDERS = ('portal_actions', 'portal_types', 'portal_workflow')
 
 
@@ -84,13 +89,15 @@
         self._initProperties(node, mode)
 
 
-class ActionsToolNodeAdapter(NodeAdapterBase, ObjectManagerHelpers):
+class ActionsToolXMLAdapter(XMLAdapterBase, ObjectManagerHelpers):
 
-    """Node im- and exporter for ActionsTool.
+    """XML im- and exporter for ActionsTool.
     """
 
     __used_for__ = IActionsTool
 
+    _LOGGER_ID = 'actions'
+
     def exportNode(self, doc):
         """Export the object as a DOM node.
         """
@@ -99,6 +106,8 @@
         node.setAttribute('xmlns:i18n', I18NURI)
         node.appendChild(self._extractProviders())
         node.appendChild(self._extractObjects())
+
+        self._logger.info('Actions tool exported.')
         return node
 
     def importNode(self, node, mode=PURGE):
@@ -111,6 +120,8 @@
         self._initObjects(node, mode)
         self._initProviders(node, mode)
 
+        self._logger.info('Actions tool imported.')
+
     def _extractProviders(self):
         fragment = self._doc.createDocumentFragment()
         for provider_id in self.context.listActionProviders():
@@ -222,3 +233,40 @@
             parent.appendChild(newnode)
 
         self._initObjects(fragment, UPDATE)
+
+
+def importActionProviders(context):
+    """Import actions tool.
+    """
+    site = context.getSite()
+    logger = context.getLogger('actions')
+    tool = getToolByName(site, 'portal_actions')
+
+    body = context.readDataFile(_FILENAME)
+    if body is None:
+        logger.info('Nothing to import.')
+        return
+
+    importer = zapi.queryMultiAdapter((tool, context), IBody)
+    if importer is None:
+        logger.warning('Import adapter misssing.')
+        return
+
+    importer.body = body
+
+def exportActionProviders(context):
+    """Export actions tool.
+    """
+    site = context.getSite()
+    logger = context.getLogger('actions')
+    tool = getToolByName(site, 'portal_actions', None)
+    if tool is None:
+        logger.info('Nothing to export.')
+        return
+
+    exporter = zapi.queryMultiAdapter((tool, context), IBody)
+    if exporter is None:
+        logger.warning('Export adapter misssing.')
+        return
+
+    context.writeDataFile(_FILENAME, exporter.body, exporter.mime_type)

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/cachingpolicymgr.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/cachingpolicymgr.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/cachingpolicymgr.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -10,20 +10,27 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Caching policy manager node adapters.
+"""Caching policy manager xml adapters and setup handlers.
 
 $Id$
 """
 
+from zope.app import zapi
+
+from Products.GenericSetup.interfaces import IBody
 from Products.GenericSetup.interfaces import INodeExporter
 from Products.GenericSetup.interfaces import INodeImporter
 from Products.GenericSetup.interfaces import PURGE
 from Products.GenericSetup.utils import NodeAdapterBase
+from Products.GenericSetup.utils import XMLAdapterBase
 
 from Products.CMFCore.interfaces import ICachingPolicy
 from Products.CMFCore.interfaces import ICachingPolicyManager
+from Products.CMFCore.utils import getToolByName
 
+_FILENAME = 'cachingpolicymgr.xml'
 
+
 class CachingPolicyNodeAdapter(NodeAdapterBase):
 
     """Node im- and exporter for CachingPolicy.
@@ -107,19 +114,23 @@
         self.context.__init__(**info)
 
 
-class CachingPolicyManagerNodeAdapter(NodeAdapterBase):
+class CachingPolicyManagerXMLAdapter(XMLAdapterBase):
 
-    """Node im- and exporter for CachingPolicyManager.
+    """XML im- and exporter for CachingPolicyManager.
     """
 
     __used_for__ = ICachingPolicyManager
 
+    _LOGGER_ID = 'cachingpolicies'
+
     def exportNode(self, doc):
         """Export the object as a DOM node.
         """
         self._doc = doc
         node = self._getObjectNode('object')
         node.appendChild(self._extractCachingPolicies())
+
+        self._logger.info('Caching policy manager exported.')
         return node
 
     def importNode(self, node, mode=PURGE):
@@ -130,6 +141,8 @@
 
         self._initCachingPolicies(node, mode)
 
+        self._logger.info('Caching policy manager imported.')
+
     def _extractCachingPolicies(self):
         fragment = self._doc.createDocumentFragment()
         for policy_id, policy in self.context.listPolicies():
@@ -155,3 +168,40 @@
 
             policy = self.context._policies[policy_id]
             INodeImporter(policy).importNode(child, mode)
+
+
+def importCachingPolicyManager(context):
+    """Import caching policy manager settings from an XML file.
+    """
+    site = context.getSite()
+    logger = context.getLogger('cachingpolicies')
+    tool = getToolByName(site, 'caching_policy_manager')
+
+    body = context.readDataFile(_FILENAME)
+    if body is None:
+        logger.info('Nothing to import.')
+        return
+
+    importer = zapi.queryMultiAdapter((tool, context), IBody)
+    if importer is None:
+        logger.warning('Import adapter misssing.')
+        return
+
+    importer.body = body
+
+def exportCachingPolicyManager(context):
+    """Export caching policy manager settings as an XML file.
+    """
+    site = context.getSite()
+    logger = context.getLogger('cachingpolicies')
+    tool = getToolByName(site, 'caching_policy_manager', None)
+    if tool is None:
+        logger.info('Nothing to export.')
+        return
+
+    exporter = zapi.queryMultiAdapter((tool, context), IBody)
+    if exporter is None:
+        logger.warning('Export adapter misssing.')
+        return
+
+    context.writeDataFile(_FILENAME, exporter.body, exporter.mime_type)

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/catalog.py (from rev 40492, CMF/trunk/CMFCore/exportimport/catalog.py)

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/configure.zcml
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/configure.zcml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/configure.zcml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,7 +1,5 @@
 <configure
     xmlns="http://namespaces.zope.org/zope"
-    xmlns:five="http://namespaces.zope.org/five"
-    i18n_domain="cmf"
     >
 
   <adapter
@@ -29,18 +27,13 @@
       />
 
   <adapter
-      factory=".actions.ActionsToolNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeExporter"
-      for="Products.CMFCore.interfaces.IActionsTool"
+      factory=".actions.ActionsToolXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.CMFCore.interfaces.IActionsTool
+           Products.GenericSetup.interfaces.ISetupContext"
       />
 
   <adapter
-      factory=".actions.ActionsToolNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeImporter"
-      for="Products.CMFCore.interfaces.IActionsTool"
-      />
-
-  <adapter
       factory=".cachingpolicymgr.CachingPolicyNodeAdapter"
       provides="Products.GenericSetup.interfaces.INodeExporter"
       for="Products.CMFCore.interfaces.ICachingPolicy"
@@ -53,18 +46,13 @@
       />
 
   <adapter
-      factory=".cachingpolicymgr.CachingPolicyManagerNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeExporter"
-      for="Products.CMFCore.interfaces.ICachingPolicyManager"
+      factory=".cachingpolicymgr.CachingPolicyManagerXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.CMFCore.interfaces.ICachingPolicyManager
+           Products.GenericSetup.interfaces.ISetupContext"
       />
 
   <adapter
-      factory=".cachingpolicymgr.CachingPolicyManagerNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeImporter"
-      for="Products.CMFCore.interfaces.ICachingPolicyManager"
-      />
-
-  <adapter
       factory=".content.StructureFolderWalkingAdapter"
       provides="Products.GenericSetup.interfaces.IFilesystemExporter"
       for="Products.CMFCore.interfaces.IFolderish"
@@ -77,51 +65,64 @@
       />
 
   <adapter
-      factory=".contenttyperegistry.ContentTypeRegistryNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeExporter"
-      for="Products.CMFCore.interfaces.IContentTypeRegistry"
+      factory=".contenttyperegistry.ContentTypeRegistryXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.CMFCore.interfaces.IContentTypeRegistry
+           Products.GenericSetup.interfaces.ISetupContext"
       />
 
   <adapter
-      factory=".contenttyperegistry.ContentTypeRegistryNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeImporter"
-      for="Products.CMFCore.interfaces.IContentTypeRegistry"
+      factory=".cookieauth.CookieCrumblerXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.CMFCore.interfaces.ICookieCrumbler
+           Products.GenericSetup.interfaces.ISetupContext"
       />
 
   <adapter
-      factory=".cookieauth.CookieCrumblerNodeAdapter"
+      factory=".properties.PropertiesXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.CMFCore.interfaces.ISiteRoot
+           Products.GenericSetup.interfaces.ISetupContext"
+      />
+
+  <adapter
+      factory=".skins.DirectoryViewNodeAdapter"
       provides="Products.GenericSetup.interfaces.INodeExporter"
-      for="Products.CMFCore.interfaces.ICookieCrumbler"
+      for="Products.CMFCore.interfaces.IDirectoryView"
       />
 
   <adapter
-      factory=".cookieauth.CookieCrumblerNodeAdapter"
+      factory=".skins.DirectoryViewNodeAdapter"
       provides="Products.GenericSetup.interfaces.INodeImporter"
-      for="Products.CMFCore.interfaces.ICookieCrumbler"
+      for="Products.CMFCore.interfaces.IDirectoryView"
       />
 
   <adapter
-      factory=".properties.PropertiesNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeExporter"
-      for="Products.CMFCore.interfaces.ISiteRoot"
+      factory=".skins.SkinsToolXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.CMFCore.interfaces.ISkinsTool
+           Products.GenericSetup.interfaces.ISetupContext"
       />
 
   <adapter
-      factory=".properties.PropertiesNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeImporter"
-      for="Products.CMFCore.interfaces.ISiteRoot"
+      factory=".typeinfo.TypeInformationXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.CMFCore.interfaces.ITypeInformation
+           Products.GenericSetup.interfaces.ISetupContext"
       />
 
   <adapter
-      factory=".typeinfo.TypeInformationNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeExporter"
-      for="Products.CMFCore.interfaces.ITypeInformation"
+      factory=".typeinfo.TypesToolXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.CMFCore.interfaces.ITypesTool
+           Products.GenericSetup.interfaces.ISetupContext"
       />
 
   <adapter
-      factory=".typeinfo.TypeInformationNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeImporter"
-      for="Products.CMFCore.interfaces.ITypeInformation"
+      factory=".workflow.WorkflowToolXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.CMFCore.interfaces.IWorkflowTool
+           Products.GenericSetup.interfaces.ISetupContext"
       />
 
 </configure>

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/contenttyperegistry.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/contenttyperegistry.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/contenttyperegistry.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -10,30 +10,40 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Content type registry node adapters.
+"""Content type registry xml adapters and setup handlers.
 
 $Id$
 """
 
+from zope.app import zapi
+
+from Products.GenericSetup.interfaces import IBody
 from Products.GenericSetup.interfaces import PURGE
-from Products.GenericSetup.utils import NodeAdapterBase
+from Products.GenericSetup.utils import XMLAdapterBase
 
 from Products.CMFCore.interfaces import IContentTypeRegistry
+from Products.CMFCore.utils import getToolByName
 
+_FILENAME = 'contenttyperegistry.xml'
 
-class ContentTypeRegistryNodeAdapter(NodeAdapterBase):
 
-    """Node im- and exporter for ContentTypeRegistry.
+class ContentTypeRegistryXMLAdapter(XMLAdapterBase):
+
+    """XML im- and exporter for ContentTypeRegistry.
     """
 
     __used_for__ = IContentTypeRegistry
 
+    _LOGGER_ID = 'contenttypes'
+
     def exportNode(self, doc):
         """Export the object as a DOM node.
         """
         self._doc = doc
         node = self._getObjectNode('object')
         node.appendChild(self._extractPredicates())
+
+        self._logger.info('Content type registry exported.')
         return node
 
     def importNode(self, node, mode=PURGE):
@@ -44,6 +54,8 @@
 
         self._initPredicates(node, mode)
 
+        self._logger.info('Content type registry imported.')
+
     def _extractPredicates(self):
         fragment = self._doc.createDocumentFragment()
         for predicate_id, info in self.context.listPredicates():
@@ -97,3 +109,40 @@
         if cracker is not None:
             return cracker(predicate)
         return ()  # XXX:  raise?
+
+
+def importContentTypeRegistry(context):
+    """Import content type registry settings from an XML file.
+    """
+    site = context.getSite()
+    logger = context.getLogger('contenttypes')
+    tool = getToolByName(site, 'content_type_registry')
+
+    body = context.readDataFile(_FILENAME)
+    if body is None:
+        logger.info('Nothing to import.')
+        return
+
+    importer = zapi.queryMultiAdapter((tool, context), IBody)
+    if importer is None:
+        logger.warning('Import adapter misssing.')
+        return
+
+    importer.body = body
+
+def exportContentTypeRegistry(context):
+    """Export content type registry settings as an XML file.
+    """
+    site = context.getSite()
+    logger = context.getLogger('contenttypes')
+    tool = getToolByName(site, 'content_type_registry', None)
+    if tool is None:
+        logger.info('Nothing to export.')
+        return
+
+    exporter = zapi.queryMultiAdapter((tool, context), IBody)
+    if exporter is None:
+        logger.warning('Export adapter misssing.')
+        return
+
+    context.writeDataFile(_FILENAME, exporter.body, exporter.mime_type)

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/cookieauth.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/cookieauth.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/cookieauth.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -10,31 +10,41 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Cookie crumbler node adapters.
+"""Cookie crumbler xml adapters and setup handlers.
 
 $Id$
 """
 
+from zope.app import zapi
+
+from Products.GenericSetup.interfaces import IBody
 from Products.GenericSetup.interfaces import PURGE
-from Products.GenericSetup.utils import NodeAdapterBase
 from Products.GenericSetup.utils import PropertyManagerHelpers
+from Products.GenericSetup.utils import XMLAdapterBase
 
 from Products.CMFCore.interfaces import ICookieCrumbler
+from Products.CMFCore.utils import getToolByName
 
+_FILENAME = 'cookieauth.xml'
 
-class CookieCrumblerNodeAdapter(NodeAdapterBase, PropertyManagerHelpers):
 
-    """Node im- and exporter for CookieCrumbler.
+class CookieCrumblerXMLAdapter(XMLAdapterBase, PropertyManagerHelpers):
+
+    """XML im- and exporter for CookieCrumbler.
     """
 
     __used_for__ = ICookieCrumbler
 
+    _LOGGER_ID = 'cookies'
+
     def exportNode(self, doc):
         """Export the object as a DOM node.
         """
         self._doc = doc
         node = self._getObjectNode('object')
         node.appendChild(self._extractProperties())
+
+        self._logger.info('Cookie crumbler exported.')
         return node
 
     def importNode(self, node, mode=PURGE):
@@ -44,3 +54,42 @@
             self._purgeProperties()
 
         self._initProperties(node, mode)
+
+        self._logger.info('Cookie crumbler imported.')
+
+
+def importCookieCrumbler(context):
+    """Import cookie crumbler settings from an XML file.
+    """
+    site = context.getSite()
+    logger = context.getLogger('cookies')
+    tool = getToolByName(site, 'cookie_authentication')
+
+    body = context.readDataFile(_FILENAME)
+    if body is None:
+        logger.info('Nothing to import.')
+        return
+
+    importer = zapi.queryMultiAdapter((tool, context), IBody)
+    if importer is None:
+        logger.warning('Import adapter misssing.')
+        return
+
+    importer.body = body
+
+def exportCookieCrumbler(context):
+    """Export cookie crumbler settings as an XML file.
+    """
+    site = context.getSite()
+    logger = context.getLogger('cookies')
+    tool = getToolByName(site, 'cookie_authentication', None)
+    if tool is None:
+        logger.info('Nothing to export.')
+        return
+
+    exporter = zapi.queryMultiAdapter((tool, context), IBody)
+    if exporter is None:
+        logger.warning('Export adapter misssing.')
+        return
+
+    context.writeDataFile(_FILENAME, exporter.body, exporter.mime_type)

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/mailhost.py (from rev 40492, CMF/trunk/CMFCore/exportimport/mailhost.py)

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/properties.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/properties.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/properties.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -10,31 +10,40 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Site properties node adapters.
+"""Site properties xml adapters and setup handlers.
 
 $Id$
 """
 
+from zope.app import zapi
+
+from Products.GenericSetup.interfaces import IBody
 from Products.GenericSetup.interfaces import PURGE
-from Products.GenericSetup.utils import NodeAdapterBase
 from Products.GenericSetup.utils import PropertyManagerHelpers
+from Products.GenericSetup.utils import XMLAdapterBase
 
 from Products.CMFCore.interfaces import ISiteRoot
 
+_FILENAME = 'properties.xml'
 
-class PropertiesNodeAdapter(NodeAdapterBase, PropertyManagerHelpers):
 
-    """Node im- and exporter for properties.
+class PropertiesXMLAdapter(XMLAdapterBase, PropertyManagerHelpers):
+
+    """XML im- and exporter for properties.
     """
 
     __used_for__ = ISiteRoot
 
+    _LOGGER_ID = 'properties'
+
     def exportNode(self, doc):
         """Export the object as a DOM node.
         """
         self._doc = doc
         node = self._doc.createElement('site')
         node.appendChild(self._extractProperties())
+
+        self._logger.info('Site properties exported.')
         return node
 
     def importNode(self, node, mode=PURGE):
@@ -44,3 +53,37 @@
             self._purgeProperties()
 
         self._initProperties(node, mode)
+
+        self._logger.info('Site properties imported.')
+
+
+def importSiteProperties(context):
+    """ Import site properties from an XML file.
+    """
+    site = context.getSite()
+    logger = context.getLogger('properties')
+
+    body = context.readDataFile(_FILENAME)
+    if body is None:
+        logger.info('Nothing to import.')
+        return
+
+    importer = zapi.queryMultiAdapter((site, context), IBody)
+    if importer is None:
+        logger.warning('Import adapter misssing.')
+        return
+
+    importer.body = body
+
+def exportSiteProperties(context):
+    """ Export site properties as an XML file.
+    """
+    site = context.getSite()
+    logger = context.getLogger('properties')
+
+    exporter = zapi.queryMultiAdapter((site, context), IBody)
+    if exporter is None:
+        logger.warning('Export adapter misssing.')
+        return
+
+    context.writeDataFile(_FILENAME, exporter.body, exporter.mime_type)

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/skins.py (from rev 40492, CMF/trunk/CMFCore/exportimport/skins.py)

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/four (from rev 40492, CMF/trunk/CMFCore/exportimport/tests/four)

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/one (from rev 40492, CMF/trunk/CMFCore/exportimport/tests/one)

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_actions.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_actions.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_actions.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -20,11 +20,26 @@
 import Zope2
 Zope2.startup()
 
+import Products
+from Acquisition import Implicit
+from Acquisition import aq_parent
+from OFS.Folder import Folder
+from OFS.OrderedFolder import OrderedFolder
+from Products.Five import zcml
+from zope.interface import implements
+
+from Products.CMFCore.ActionProviderBase import ActionProviderBase
+from Products.CMFCore.interfaces import IActionsTool
+from Products.CMFCore.interfaces.portal_actions \
+    import ActionProvider as IActionProvider
 from Products.CMFCore.tests.base.dummy import DummySite
 from Products.CMFCore.tests.base.testcase import PlacelessSetup
+from Products.GenericSetup.testing import BodyAdapterTestCase
 from Products.GenericSetup.testing import NodeAdapterTestCase
+from Products.GenericSetup.tests.common import BaseRegistryTests
+from Products.GenericSetup.tests.common import DummyExportContext
+from Products.GenericSetup.tests.common import DummyImportContext
 
-
 _ACTION_XML = """\
 <object name="foo_action" meta_type="CMF Action">
  <property name="title">Foo</property>
@@ -52,7 +67,8 @@
 </object>
 """
 
-_ACTIONSTOOL_XML = """\
+_ACTIONSTOOL_BODY = """\
+<?xml version="1.0"?>
 <object name="portal_actions" meta_type="CMF Actions Tool"
    xmlns:i18n="http://xml.zope.org/namespaces/i18n">
  <action-provider name="portal_actions"/>
@@ -71,9 +87,166 @@
 </object>
 """
 
+_EMPTY_EXPORT = """\
+<?xml version="1.0"?>
+<object meta_type="CMF Actions Tool" name="portal_actions" \
+xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <action-provider name="portal_actions"/>
+</object>
+"""
 
-class ActionNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+_NORMAL_EXPORT = """\
+<?xml version="1.0"?>
+<object meta_type="CMF Actions Tool" name="portal_actions" \
+xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <action-provider name="portal_actions"/>
+ <action-provider name="portal_foo">
+  <action action_id="foo"
+          title="Foo"
+          url_expr="string:${object_url}/foo"
+          condition_expr="python:1"
+          category="dummy"
+          visible="True"/>
+ </action-provider>
+ <action-provider name="portal_bar">
+  <action action_id="bar"
+          title="Bar"
+          url_expr="string:${object_url}/bar"
+          condition_expr="python:0"
+          category="dummy"
+          visible="False">
+   <permission>Manage portal</permission>
+  </action>
+ </action-provider>
+</object>
+"""
 
+_NEWSYTLE_EXPORT = """\
+<?xml version="1.0"?>
+<object meta_type="CMF Actions Tool" name="portal_actions" \
+xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <action-provider name="portal_actions"/>
+ <object name="dummy" meta_type="CMF Action Category">
+  <property name="title"></property>
+  <object name="foo" meta_type="CMF Action">
+   <property name="title">Foo</property>
+   <property name="description"></property>
+   <property name="url_expr">string:${object_url}/foo</property>
+   <property name="icon_expr"></property>
+   <property name="available_expr">python:1</property>
+   <property name="permissions"></property>
+   <property name="visible">True</property>
+  </object>
+  <object name="bar" meta_type="CMF Action">
+   <property name="title">Bar</property>
+   <property name="description"></property>
+   <property name="url_expr">string:${object_url}/bar</property>
+   <property name="icon_expr"></property>
+   <property name="available_expr">python:0</property>
+   <property name="permissions">
+    <element value="Manage portal"/>
+   </property>
+   <property name="visible">False</property>
+  </object>
+ </object>
+</object>
+"""
+
+_I18N_IMPORT = """\
+<?xml version="1.0"?>
+<object meta_type="CMF Actions Tool" name="portal_actions" \
+xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <action-provider name="portal_actions"/>
+ <object name="dummy" meta_type="CMF Action Category">
+  <property name="title"></property>
+  <object name="foo" meta_type="CMF Action" i18n:domain="foo_domain">
+   <property name="title" i18n:translate="">Foo</property>
+   <property name="description" i18n:translate=""></property>
+   <property name="url_expr">string:${object_url}/foo</property>
+   <property name="icon_expr"></property>
+   <property name="available_expr">python:1</property>
+   <property name="permissions"></property>
+   <property name="visible">True</property>
+  </object>
+ </object>
+</object>
+"""
+
+_INSERT_IMPORT = """\
+<?xml version="1.0"?>
+<actions-tool xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <object name="dummy">
+ <object name="spam" meta_type="CMF Action" insert-before="*">
+  <property name="title">Spam</property>
+  <property name="description"></property>
+  <property name="url_expr">string:${object_url}/spam</property>
+  <property name="icon_expr">string:spam_icon.png</property>
+  <property name="available_expr"></property>
+  <property name="permissions">
+   <element value="View" /></property>
+  <property name="visible">True</property>
+ </object>
+ <object name="foo" insert-after="*">
+  <property name="icon_expr">string:foo_icon.png</property>
+ </object>
+ </object>
+</actions-tool>
+"""
+
+_REMOVE_IMPORT = """\
+<?xml version="1.0"?>
+<actions-tool xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <action-provider id="portal_actions" remove="">
+ </action-provider>
+ <action-provider id="not_existing" remove="">
+ </action-provider>
+ <action-provider id="portal_bar" remove="">
+ </action-provider>
+</actions-tool>
+"""
+
+
+class DummyTool(OrderedFolder, ActionProviderBase):
+
+    __implements__ = IActionProvider
+
+
+class DummyUser(Implicit):
+
+    def getId(self):
+        return 'dummy'
+
+
+class DummyMembershipTool(DummyTool):
+
+    def isAnonymousUser(self):
+        return False
+
+    def getAuthenticatedMember(self):
+        return DummyUser().__of__(aq_parent(self))
+
+
+class DummyActionsTool(DummyTool):
+
+    implements(IActionsTool)
+    id = 'portal_actions'
+    meta_type = 'CMF Actions Tool'
+
+    def __init__(self):
+        self._providers = []
+
+    def addActionProvider(self, provider_name):
+        self._providers.append(provider_name)
+
+    def listActionProviders(self):
+        return self._providers[:]
+
+    def deleteActionProvider(self, provider_name):
+        self._providers = [ x for x in self._providers if x != provider_name ]
+
+
+class ActionNodeAdapterTests(NodeAdapterTestCase):
+
     def _getTargetClass(self):
         from Products.CMFCore.exportimport.actions import ActionNodeAdapter
 
@@ -101,20 +274,17 @@
         self.assertEqual(obj.visible, True)
 
     def setUp(self):
+        import Products.CMFCore.exportimport
         from Products.CMFCore.ActionInformation import Action
-        import Products.CMFCore.exportimport
-        import Products.Five
-        from Products.Five import zcml
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
 
         self._obj = Action('foo_action')
         self._XML = _ACTION_XML
 
 
-class ActionCategoryNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class ActionCategoryNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.CMFCore.exportimport.actions \
@@ -132,26 +302,23 @@
         self.assertEqual(obj.title, '')
 
     def setUp(self):
+        import Products.CMFCore.exportimport
         from Products.CMFCore.ActionInformation import ActionCategory
-        import Products.CMFCore.exportimport
-        import Products.Five
-        from Products.Five import zcml
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
 
         self._obj = ActionCategory('foo_category')
         self._XML = _ACTIONCATEGORY_XML
 
 
-class ActionsToolNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class ActionsToolXMLAdapterTests(BodyAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.CMFCore.exportimport.actions \
-                import ActionsToolNodeAdapter
+                import ActionsToolXMLAdapter
 
-        return ActionsToolNodeAdapter
+        return ActionsToolXMLAdapter
 
     def _populate(self, obj):
         from Products.CMFCore.ActionInformation import Action
@@ -169,26 +336,280 @@
         self.assertEqual(obj.action_providers[0], 'portal_actions')
 
     def setUp(self):
+        import Products.CMFCore.exportimport
         from Products.CMFCore.ActionsTool import ActionsTool
-        import Products.CMFCore.exportimport
-        import Products.Five
-        from Products.Five import zcml
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        BodyAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
 
         site = DummySite('site')
         site._setObject('portal_actions', ActionsTool('portal_actions'))
         self._obj = site.portal_actions
-        self._XML = _ACTIONSTOOL_XML
+        self._BODY = _ACTIONSTOOL_BODY
 
 
+class _ActionSetup(PlacelessSetup, BaseRegistryTests):
+
+    def _initSite(self, foo=2, bar=2):
+        self.root.site = Folder(id='site')
+        site = self.root.site
+        site.portal_membership = DummyMembershipTool()
+
+        site.portal_actions = DummyActionsTool()
+        site.portal_actions.addActionProvider('portal_actions')
+
+        if foo > 0:
+            site.portal_foo = DummyTool()
+
+        if foo > 1:
+            site.portal_foo.addAction(id='foo',
+                                      name='Foo',
+                                      action='foo',
+                                      condition='python:1',
+                                      permission=(),
+                                      category='dummy',
+                                      visible=1)
+            site.portal_actions.addActionProvider('portal_foo')
+
+        if bar > 0:
+            site.portal_bar = DummyTool()
+
+        if bar > 1:
+            site.portal_bar.addAction(id='bar',
+                                      name='Bar',
+                                      action='bar',
+                                      condition='python:0',
+                                      permission=('Manage portal',),
+                                      category='dummy',
+                                      visible=0)
+            site.portal_actions.addActionProvider('portal_bar')
+
+        return site
+
+    def setUp(self):
+        PlacelessSetup.setUp(self)
+        BaseRegistryTests.setUp(self)
+        zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
+
+    def tearDown(self):
+        BaseRegistryTests.tearDown(self)
+        PlacelessSetup.tearDown(self)
+
+
+class exportActionProvidersTests(_ActionSetup):
+
+    def test_unchanged(self):
+        from Products.CMFCore.exportimport.actions \
+                import exportActionProviders
+
+        site = self._initSite(0, 0)
+        context = DummyExportContext(site)
+        exportActionProviders(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'actions.xml')
+        self._compareDOM(text, _EMPTY_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+    def test_normal(self):
+        from Products.CMFCore.exportimport.actions \
+                import exportActionProviders
+
+        site = self._initSite()
+        context = DummyExportContext(site)
+        exportActionProviders(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'actions.xml')
+        self._compareDOM(text, _NORMAL_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+
+class importActionProvidersTests(_ActionSetup):
+
+    def test_empty_default_purge(self):
+        from Products.CMFCore.exportimport.actions \
+                import importActionProviders
+
+        site = self._initSite(2, 0)
+        atool = site.portal_actions
+
+        self.assertEqual(len(atool.listActionProviders()), 2)
+        self.failUnless('portal_foo' in atool.listActionProviders())
+        self.failUnless('portal_actions' in atool.listActionProviders())
+
+        context = DummyImportContext(site)
+        context._files['actions.xml'] = _EMPTY_EXPORT
+        importActionProviders(context)
+
+        self.assertEqual(len(atool.listActionProviders()), 1)
+        self.failIf('portal_foo' in atool.listActionProviders())
+        self.failUnless('portal_actions' in atool.listActionProviders())
+        self.assertEqual(len(atool.objectIds()), 0)
+
+    def test_empty_explicit_purge(self):
+        from Products.CMFCore.exportimport.actions \
+                import importActionProviders
+
+        site = self._initSite(2, 0)
+        atool = site.portal_actions
+
+        self.assertEqual(len(atool.listActionProviders()), 2)
+        self.failUnless('portal_foo' in atool.listActionProviders())
+        self.failUnless('portal_actions' in atool.listActionProviders())
+
+        context = DummyImportContext(site, True)
+        context._files['actions.xml'] = _EMPTY_EXPORT
+        importActionProviders(context)
+
+        self.assertEqual(len(atool.listActionProviders()), 1)
+        self.failIf('portal_foo' in atool.listActionProviders())
+        self.failUnless('portal_actions' in atool.listActionProviders())
+        self.assertEqual(len(atool.objectIds()), 0)
+
+    def test_empty_skip_purge(self):
+        from Products.CMFCore.exportimport.actions \
+                import importActionProviders
+
+        site = self._initSite(2, 0)
+        atool = site.portal_actions
+
+        self.assertEqual(len(atool.listActionProviders()), 2)
+        self.failUnless('portal_foo' in atool.listActionProviders())
+        self.failUnless('portal_actions' in atool.listActionProviders())
+
+        context = DummyImportContext(site, False)
+        context._files['actions.xml'] = _EMPTY_EXPORT
+        importActionProviders(context)
+
+        self.assertEqual(len(atool.listActionProviders()), 2)
+        self.failUnless('portal_foo' in atool.listActionProviders())
+        self.failUnless('portal_actions' in atool.listActionProviders())
+
+    def test_normal(self):
+        from Products.CMFCore.exportimport.actions \
+                import exportActionProviders
+        from Products.CMFCore.exportimport.actions \
+                import importActionProviders
+
+        site = self._initSite(1, 1)
+        atool = site.portal_actions
+        foo = site.portal_foo
+        bar = site.portal_bar
+
+        self.assertEqual(len(atool.listActionProviders()), 1)
+        self.failIf('portal_foo' in atool.listActionProviders())
+        self.failIf(foo.listActions())
+        self.failIf('portal_bar' in atool.listActionProviders())
+        self.failIf(bar.listActions())
+        self.failUnless('portal_actions' in atool.listActionProviders())
+
+        context = DummyImportContext(site)
+        context._files['actions.xml'] = _NORMAL_EXPORT
+        importActionProviders(context)
+
+        self.assertEqual(len(atool.listActionProviders()), 1)
+        self.failIf('portal_foo' in atool.listActionProviders())
+        self.failUnless('portal_actions' in atool.listActionProviders())
+
+        self.assertEqual(len(atool.objectIds()), 1)
+        self.failUnless('dummy' in atool.objectIds())
+        self.assertEqual(len(atool.dummy.objectIds()) , 2)
+        self.failUnless('foo' in atool.dummy.objectIds())
+        self.failUnless('bar' in atool.dummy.objectIds())
+        self.failIf(foo.listActions())
+        self.failIf(bar.listActions())
+
+        # complete the roundtrip
+        context = DummyExportContext(site)
+        exportActionProviders(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'actions.xml')
+        self._compareDOM(text, _NEWSYTLE_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+    def test_i18n(self):
+        from Products.CMFCore.exportimport.actions \
+                import exportActionProviders
+        from Products.CMFCore.exportimport.actions \
+                import importActionProviders
+
+        site = self._initSite(0, 0)
+        atool = site.portal_actions
+
+        context = DummyImportContext(site)
+        context._files['actions.xml'] = _I18N_IMPORT
+        importActionProviders(context)
+
+        self.assertEqual(len(atool.listActionProviders()), 1)
+        self.assertEqual(atool.objectIds(), ['dummy'])
+        self.assertEqual(atool.dummy.objectIds(), ['foo'])
+        self.assertEqual(atool.dummy.foo.i18n_domain, 'foo_domain')
+
+        # complete the roundtrip
+        context = DummyExportContext(site)
+        exportActionProviders(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'actions.xml')
+        self._compareDOM(text, _I18N_IMPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+    def test_insert_skip_purge(self):
+        from Products.CMFCore.exportimport.actions \
+                import importActionProviders
+
+        site = self._initSite(0, 0)
+        atool = site.portal_actions
+
+        context = DummyImportContext(site)
+        context._files['actions.xml'] = _NEWSYTLE_EXPORT
+        importActionProviders(context)
+
+        self.assertEqual(len(atool.listActionProviders()), 1)
+        self.assertEqual(atool.objectIds(), ['dummy'])
+        self.assertEqual(atool.dummy.objectIds(), ['foo', 'bar'])
+        self.assertEqual(atool.dummy.foo.icon_expr, '')
+
+        context = DummyImportContext(site, False)
+        context._files['actions.xml'] = _INSERT_IMPORT
+        importActionProviders(context)
+
+        self.assertEqual(len(atool.listActionProviders()), 1)
+        self.assertEqual(atool.objectIds(), ['dummy'])
+        self.assertEqual(atool.dummy.objectIds(), ['spam', 'bar', 'foo'])
+        self.assertEqual(atool.dummy.foo.icon_expr, 'string:foo_icon.png')
+
+    def test_remove_skip_purge(self):
+        from Products.CMFCore.exportimport.actions \
+                import importActionProviders
+
+        site = self._initSite(2, 2)
+        atool = site.portal_actions
+
+        self.assertEqual(atool.listActionProviders(),
+                          ['portal_actions', 'portal_foo', 'portal_bar'])
+
+        context = DummyImportContext(site, False)
+        context._files['actions.xml'] = _REMOVE_IMPORT
+        importActionProviders(context)
+
+        self.assertEqual(atool.listActionProviders(), ['portal_foo'])
+
+
 def test_suite():
     return unittest.TestSuite((
         unittest.makeSuite(ActionNodeAdapterTests),
         unittest.makeSuite(ActionCategoryNodeAdapterTests),
-        unittest.makeSuite(ActionsToolNodeAdapterTests),
+        unittest.makeSuite(ActionsToolXMLAdapterTests),
+        unittest.makeSuite(exportActionProvidersTests),
+        unittest.makeSuite(importActionProvidersTests),
         ))
 
 if __name__ == '__main__':

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_cachingpolicymgr.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_cachingpolicymgr.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_cachingpolicymgr.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -10,7 +10,7 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Caching policy manager node adapter unit tests.
+"""Caching policy manager xml adapter and setup handler unit tests.
 
 $Id$
 """
@@ -18,9 +18,17 @@
 import unittest
 import Testing
 
-from Products.CMFCore.tests.base.testcase import PlacelessSetup
+import Products
+from OFS.Folder import Folder
+from Products.Five import zcml
+
+from Products.GenericSetup.testing import BodyAdapterTestCase
 from Products.GenericSetup.testing import NodeAdapterTestCase
+from Products.GenericSetup.tests.common import BaseRegistryTests
+from Products.GenericSetup.tests.common import DummyExportContext
+from Products.GenericSetup.tests.common import DummyImportContext
 
+from Products.CMFCore.tests.base.testcase import PlacelessSetup
 
 _CP_XML = """\
 <caching-policy name="foo_policy" enable_304s="False" etag_func=""
@@ -30,7 +38,8 @@
    proxy_revalidate="False" public="False" vary=""/>
 """
 
-_CPM_XML = """\
+_CPM_BODY = """\
+<?xml version="1.0"?>
 <object name="caching_policy_manager" meta_type="CMF Caching Policy Manager">
  <caching-policy name="foo_policy" enable_304s="False" etag_func=""
     last_modified="True" max_age_secs="600" mtime_func="object/modified"
@@ -42,7 +51,7 @@
 """
 
 
-class CachingPolicyNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class CachingPolicyNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.CMFCore.exportimport.cachingpolicymgr \
@@ -51,27 +60,23 @@
         return CachingPolicyNodeAdapter
 
     def setUp(self):
+        import Products.CMFCore.exportimport
         from Products.CMFCore.CachingPolicyManager import CachingPolicy
-        import Products.CMFCore.exportimport
-        import Products.Five
-        from Products.Five import zcml
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
 
         self._obj = CachingPolicy('foo_policy', max_age_secs=0)
         self._XML = _CP_XML
 
 
-class CachingPolicyManagerNodeAdapterTests(PlacelessSetup,
-                                           NodeAdapterTestCase):
+class CachingPolicyManagerXMLAdapterTests(BodyAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.CMFCore.exportimport.cachingpolicymgr \
-                import CachingPolicyManagerNodeAdapter
+                import CachingPolicyManagerXMLAdapter
 
-        return CachingPolicyManagerNodeAdapter
+        return CachingPolicyManagerXMLAdapter
 
     def _populate(self, obj):
         obj.addPolicy('foo_policy',
@@ -79,23 +84,161 @@
                       'object/modified', 600, 0, 0, 0, '', '')
 
     def setUp(self):
+        import Products.CMFCore.exportimport
         from Products.CMFCore.CachingPolicyManager import CachingPolicyManager
-        import Products.CMFCore.exportimport
-        import Products.Five
-        from Products.Five import zcml
 
+        BodyAdapterTestCase.setUp(self)
+        zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
+
+        self._obj = CachingPolicyManager()
+        self._BODY = _CPM_BODY
+
+
+class _CachingPolicyManagerSetup(PlacelessSetup, BaseRegistryTests):
+
+    POLICY_ID = 'policy_id'
+    PREDICATE = "python:object.getId() == 'foo'"
+    MTIME_FUNC = "object/modified"
+    MAX_AGE_SECS = 60
+    VARY = "Test"
+    ETAG_FUNC = "object/getETag"
+    S_MAX_AGE_SECS = 120
+    PRE_CHECK = 42
+    POST_CHECK = 43
+
+    _EMPTY_EXPORT = """\
+<?xml version="1.0"?>
+<object name="caching_policy_manager" meta_type="CMF Caching Policy Manager"/>
+"""
+
+    _WITH_POLICY_EXPORT = """\
+<?xml version="1.0"?>
+<object name="caching_policy_manager" meta_type="CMF Caching Policy Manager">
+ <caching-policy name="%s" enable_304s="True"
+    etag_func="%s" last_modified="False" max_age_secs="%d"
+    mtime_func="%s" must_revalidate="True" no_cache="True"
+    no_store="True" no_transform="True" post_check="%d" pre_check="%d"
+    predicate="%s" private="True"
+    proxy_revalidate="True" public="True" s_max_age_secs="%d" vary="%s"/>
+</object>
+""" % (POLICY_ID, ETAG_FUNC, MAX_AGE_SECS, MTIME_FUNC, POST_CHECK, PRE_CHECK,
+       PREDICATE, S_MAX_AGE_SECS, VARY)
+
+    def _initSite(self, with_policy=False):
+        from Products.CMFCore.CachingPolicyManager import CachingPolicyManager
+
+        self.root.site = Folder(id='site')
+        site = self.root.site
+        mgr = CachingPolicyManager()
+        site._setObject( mgr.getId(), mgr )
+
+        if with_policy:
+            mgr.addPolicy( policy_id=self.POLICY_ID
+                         , predicate=self.PREDICATE
+                         , mtime_func=self.MTIME_FUNC
+                         , max_age_secs=self.MAX_AGE_SECS
+                         , no_cache=True
+                         , no_store=True
+                         , must_revalidate=True
+                         , vary=self.VARY
+                         , etag_func=self.ETAG_FUNC
+                         , s_max_age_secs=self.S_MAX_AGE_SECS
+                         , proxy_revalidate=True
+                         , public=True
+                         , private=True
+                         , no_transform=True
+                         , enable_304s=True
+                         , last_modified=False
+                         , pre_check=self.PRE_CHECK
+                         , post_check=self.POST_CHECK
+                         )
+
+        return site
+
+    def setUp(self):
         PlacelessSetup.setUp(self)
+        BaseRegistryTests.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
         zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
 
-        self._obj = CachingPolicyManager()
-        self._XML = _CPM_XML
+    def tearDown(self):
+        BaseRegistryTests.tearDown(self)
+        PlacelessSetup.tearDown(self)
 
 
+class exportCachingPolicyManagerTests(_CachingPolicyManagerSetup):
+
+    def test_empty(self):
+        from Products.CMFCore.exportimport.cachingpolicymgr \
+                import exportCachingPolicyManager
+
+        site = self._initSite(with_policy=False)
+        context = DummyExportContext(site)
+        exportCachingPolicyManager(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'cachingpolicymgr.xml')
+        self._compareDOM(text, self._EMPTY_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+    def test_with_policy(self):
+        from Products.CMFCore.exportimport.cachingpolicymgr \
+                import exportCachingPolicyManager
+
+        site = self._initSite(with_policy=True)
+        context = DummyExportContext(site)
+        exportCachingPolicyManager(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'cachingpolicymgr.xml')
+        self._compareDOM(text, self._WITH_POLICY_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+
+class importCachingPolicyManagerTests(_CachingPolicyManagerSetup):
+
+    def test_normal(self):
+        from Products.CMFCore.exportimport.cachingpolicymgr \
+                import importCachingPolicyManager
+
+        site = self._initSite(with_policy=False)
+        cpm = site.caching_policy_manager
+        self.assertEqual(len(cpm.listPolicies()), 0)
+
+        context = DummyImportContext(site)
+        context._files['cachingpolicymgr.xml'] = self._WITH_POLICY_EXPORT
+        importCachingPolicyManager(context)
+
+        self.assertEqual(len(cpm.listPolicies()), 1)
+        policy_id, policy = cpm.listPolicies()[0]
+        self.assertEqual(policy.getPolicyId(), self.POLICY_ID)
+        self.assertEqual(policy.getPredicate(), self.PREDICATE)
+        self.assertEqual(policy.getMTimeFunc(), self.MTIME_FUNC)
+        self.assertEqual(policy.getVary(), self.VARY)
+        self.assertEqual(policy.getETagFunc(), self.ETAG_FUNC)
+        self.assertEqual(policy.getMaxAgeSecs(), self.MAX_AGE_SECS)
+        self.assertEqual(policy.getSMaxAgeSecs(), self.S_MAX_AGE_SECS)
+        self.assertEqual(policy.getPreCheck(), self.PRE_CHECK)
+        self.assertEqual(policy.getPostCheck(), self.POST_CHECK)
+        self.assertEqual(policy.getLastModified(), False)
+        self.assertEqual(policy.getNoCache(), True)
+        self.assertEqual(policy.getNoStore(), True)
+        self.assertEqual(policy.getMustRevalidate(), True)
+        self.assertEqual(policy.getProxyRevalidate(), True)
+        self.assertEqual(policy.getNoTransform(), True)
+        self.assertEqual(policy.getPublic(), True)
+        self.assertEqual(policy.getPrivate(), True)
+        self.assertEqual(policy.getEnable304s(), True)
+
+
 def test_suite():
     return unittest.TestSuite((
         unittest.makeSuite(CachingPolicyNodeAdapterTests),
-        unittest.makeSuite(CachingPolicyManagerNodeAdapterTests),
+        unittest.makeSuite(CachingPolicyManagerXMLAdapterTests),
+        unittest.makeSuite(exportCachingPolicyManagerTests),
+        unittest.makeSuite(importCachingPolicyManagerTests),
         ))
 
 if __name__ == '__main__':

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_catalog.py (from rev 40492, CMF/trunk/CMFCore/exportimport/tests/test_catalog.py)

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_content.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_content.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_content.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -26,7 +26,6 @@
 from Products.GenericSetup.tests.common import DummyExportContext
 from Products.GenericSetup.tests.common import DummyImportContext
 
-from conformance import ConformsToIFilesystemExporter
 from conformance import ConformsToIFilesystemImporter
 
 

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_contenttyperegistry.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_contenttyperegistry.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_contenttyperegistry.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -10,7 +10,7 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Content type registry node adapter unit tests.
+"""Content type registry xml adapter and setup handler unit tests.
 
 $Id$
 """
@@ -18,11 +18,26 @@
 import unittest
 import Testing
 
+import Products
+from OFS.Folder import Folder
+from Products.Five import zcml
+
+from Products.GenericSetup.testing import BodyAdapterTestCase
+from Products.GenericSetup.tests.common import BaseRegistryTests
+from Products.GenericSetup.tests.common import DummyExportContext
+from Products.GenericSetup.tests.common import DummyImportContext
+
 from Products.CMFCore.tests.base.testcase import PlacelessSetup
-from Products.GenericSetup.testing import NodeAdapterTestCase
 
+_TEST_PREDICATES = (
+ ('plain_text', 'major_minor', ('text', 'plain,javascript'), 'File'),
+ ('stylesheets', 'extension', ('css,xsl,xslt',), 'Text File'),
+ ('images', 'mimetype_regex', ('image/.*',), 'Image'),
+ ('logfiles', 'name_regex', ('error_log-.*',), 'Log File'),
+)
 
-_CTR_XML = """\
+_CTR_BODY = """\
+<?xml version="1.0"?>
 <object name="content_type_registry" meta_type="Content Type Registry">
  <predicate name="foo_predicate" content_type_name="Foo Type"
     predicate_type="major_minor">
@@ -45,14 +60,13 @@
 """
 
 
-class ContentTypeRegistryNodeAdapterTests(PlacelessSetup,
-                                          NodeAdapterTestCase):
+class ContentTypeRegistryXMLAdapterTests(BodyAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.CMFCore.exportimport.contenttyperegistry \
-                import ContentTypeRegistryNodeAdapter
+                import ContentTypeRegistryXMLAdapter
 
-        return ContentTypeRegistryNodeAdapter
+        return ContentTypeRegistryXMLAdapter
 
     def _populate(self, obj):
         obj.addPredicate('foo_predicate', 'major_minor')
@@ -69,22 +83,176 @@
         obj.assignTypeName('foobar_predicate', 'Foobar Type')
 
     def setUp(self):
+        import Products.CMFCore.exportimport
         from Products.CMFCore.ContentTypeRegistry import ContentTypeRegistry
-        import Products.CMFCore.exportimport
-        import Products.Five
-        from Products.Five import zcml
 
+        BodyAdapterTestCase.setUp(self)
+        zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
+
+        self._obj = ContentTypeRegistry()
+        self._BODY = _CTR_BODY
+
+
+class _ContentTypeRegistrySetup(PlacelessSetup, BaseRegistryTests):
+
+    MAJOR_MINOR_ID = _TEST_PREDICATES[0][0]
+    MAJOR = _TEST_PREDICATES[0][2][0]
+    MINOR = _TEST_PREDICATES[0][2][1]
+    MAJOR_MINOR_TYPENAME = _TEST_PREDICATES[0][3]
+    EXTENSION_ID = _TEST_PREDICATES[1][0]
+    EXTENSIONS = _TEST_PREDICATES[1][2][0]
+    EXTENSION_TYPENAME = _TEST_PREDICATES[1][3]
+    MIMETYPE_REGEX_ID = _TEST_PREDICATES[2][0]
+    MIMETYPE_REGEX = _TEST_PREDICATES[2][2][0]
+    MIMETYPE_REGEX_TYPENAME = _TEST_PREDICATES[2][3]
+    NAME_REGEX_ID = _TEST_PREDICATES[3][0]
+    NAME_REGEX = _TEST_PREDICATES[3][2][0]
+    NAME_REGEX_TYPENAME = _TEST_PREDICATES[3][3]
+
+    _EMPTY_EXPORT = """\
+<?xml version="1.0"?>
+<object name="content_type_registry" meta_type="Content Type Registry"/>
+"""
+
+    _WITH_POLICY_EXPORT = """\
+<?xml version="1.0"?>
+<object name="content_type_registry" meta_type="Content Type Registry">
+ <predicate name="%s" content_type_name="%s"
+    predicate_type="major_minor">
+  <argument value="%s"/>
+  <argument value="%s"/>
+ </predicate>
+ <predicate name="%s" content_type_name="%s"
+    predicate_type="extension">
+  <argument value="%s"/>
+ </predicate>
+ <predicate name="%s" content_type_name="%s"
+    predicate_type="mimetype_regex">
+  <argument value="%s"/>
+ </predicate>
+ <predicate name="%s" content_type_name="%s"
+    predicate_type="name_regex">
+  <argument value="%s"/>
+ </predicate>
+</object>
+""" % (MAJOR_MINOR_ID,
+       MAJOR_MINOR_TYPENAME,
+       MAJOR,
+       MINOR,
+       EXTENSION_ID,
+       EXTENSION_TYPENAME,
+       EXTENSIONS,
+       MIMETYPE_REGEX_ID,
+       MIMETYPE_REGEX_TYPENAME,
+       MIMETYPE_REGEX,
+       NAME_REGEX_ID,
+       NAME_REGEX_TYPENAME,
+       NAME_REGEX,
+      )
+
+    def _initSite(self, mit_predikat=False):
+        from Products.CMFCore.ContentTypeRegistry import ContentTypeRegistry
+
+        self.root.site = Folder(id='site')
+        site = self.root.site
+        ctr = ContentTypeRegistry()
+        site._setObject( ctr.getId(), ctr )
+
+        if mit_predikat:
+            for (predicate_id, predicate_type, edit_args, content_type_name
+                ) in _TEST_PREDICATES:
+                ctr.addPredicate(predicate_id, predicate_type) 
+                predicate = ctr.getPredicate(predicate_id)
+                predicate.edit(*edit_args)
+                ctr.assignTypeName(predicate_id, content_type_name)
+
+        return site
+
+    def setUp(self):
         PlacelessSetup.setUp(self)
+        BaseRegistryTests.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
         zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
 
-        self._obj = ContentTypeRegistry()
-        self._XML = _CTR_XML
+    def tearDown(self):
+        BaseRegistryTests.tearDown(self)
+        PlacelessSetup.tearDown(self)
 
 
+class exportContentTypeRegistryTests(_ContentTypeRegistrySetup):
+
+    def test_empty(self):
+        from Products.CMFCore.exportimport.contenttyperegistry \
+                import exportContentTypeRegistry
+
+        site = self._initSite(mit_predikat=False)
+        context = DummyExportContext(site)
+        exportContentTypeRegistry(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'contenttyperegistry.xml')
+        self._compareDOM(text, self._EMPTY_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+    def test_with_policy(self):
+        from Products.CMFCore.exportimport.contenttyperegistry \
+                import exportContentTypeRegistry
+
+        site = self._initSite(mit_predikat=True)
+        context = DummyExportContext(site)
+        exportContentTypeRegistry(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'contenttyperegistry.xml')
+        self._compareDOM(text, self._WITH_POLICY_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+
+class importContentTypeRegistryTests(_ContentTypeRegistrySetup):
+
+    def test_normal(self):
+        from Products.CMFCore.exportimport.contenttyperegistry \
+                import importContentTypeRegistry
+
+        site = self._initSite(mit_predikat=False)
+        ctr = site.content_type_registry
+        self.assertEqual(len(ctr.listPredicates()), 0)
+
+        context = DummyImportContext(site)
+        context._files['contenttyperegistry.xml'] = self._WITH_POLICY_EXPORT
+        importContentTypeRegistry(context)
+
+        self.assertEqual(len(ctr.listPredicates()), len(_TEST_PREDICATES))
+        predicate_id, (predicate, content_type_name) = ctr.listPredicates()[0]
+        self.assertEqual(predicate_id, self.MAJOR_MINOR_ID)
+        self.assertEqual(predicate.PREDICATE_TYPE, 'major_minor')
+        self.assertEqual(content_type_name, self.MAJOR_MINOR_TYPENAME)
+        self.assertEqual(predicate.major, self.MAJOR.split(','))
+        self.assertEqual(predicate.minor, self.MINOR.split(','))
+        predicate_id, (predicate, content_type_name) = ctr.listPredicates()[1]
+        self.assertEqual(predicate_id, self.EXTENSION_ID)
+        self.assertEqual(predicate.PREDICATE_TYPE, 'extension')
+        self.assertEqual(content_type_name, self.EXTENSION_TYPENAME)
+        self.assertEqual(predicate.extensions, self.EXTENSIONS.split(','))
+        predicate_id, (predicate, content_type_name) = ctr.listPredicates()[2]
+        self.assertEqual(predicate_id, self.MIMETYPE_REGEX_ID)
+        self.assertEqual(predicate.PREDICATE_TYPE, 'mimetype_regex')
+        self.assertEqual(content_type_name, self.MIMETYPE_REGEX_TYPENAME)
+        self.assertEqual(predicate.pattern.pattern, self.MIMETYPE_REGEX)
+        predicate_id, (predicate, content_type_name) = ctr.listPredicates()[3]
+        self.assertEqual(predicate_id, self.NAME_REGEX_ID)
+        self.assertEqual(predicate.PREDICATE_TYPE, 'name_regex')
+        self.assertEqual(content_type_name, self.NAME_REGEX_TYPENAME)
+        self.assertEqual(predicate.pattern.pattern, self.NAME_REGEX)
+
+
 def test_suite():
     return unittest.TestSuite((
-        unittest.makeSuite(ContentTypeRegistryNodeAdapterTests),
+        unittest.makeSuite(ContentTypeRegistryXMLAdapterTests),
+        unittest.makeSuite(exportContentTypeRegistryTests),
+        unittest.makeSuite(importContentTypeRegistryTests),
         ))
 
 if __name__ == '__main__':

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_cookieauth.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_cookieauth.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_cookieauth.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -10,7 +10,7 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Cookie crumbler node adapter unit tests.
+"""Cookie crumbler xml adapter and setup handler unit tests.
 
 $Id$
 """
@@ -18,11 +18,36 @@
 import unittest
 import Testing
 
+import Products
+from OFS.Folder import Folder
+from Products.Five import zcml
+
+from Products.GenericSetup.testing import BodyAdapterTestCase
+from Products.GenericSetup.tests.common import BaseRegistryTests
+from Products.GenericSetup.tests.common import DummyExportContext
+from Products.GenericSetup.tests.common import DummyImportContext
+
+from Products.CMFCore.CookieCrumbler import CookieCrumbler
 from Products.CMFCore.tests.base.testcase import PlacelessSetup
-from Products.GenericSetup.testing import NodeAdapterTestCase
 
+_COOKIECRUMBLER_BODY = """\
+<?xml version="1.0"?>
+<object name="foo_cookiecrumbler" meta_type="Cookie Crumbler">
+ <property name="auth_cookie">__ac</property>
+ <property name="name_cookie">__ac_name</property>
+ <property name="pw_cookie">__ac_password</property>
+ <property name="persist_cookie">__ac_persistent</property>
+ <property name="auto_login_page">login_form</property>
+ <property name="logout_page">logged_out</property>
+ <property name="unauth_page"></property>
+ <property name="local_cookie_path">False</property>
+ <property name="cache_header_value">private</property>
+ <property name="log_username">True</property>
+</object>
+"""
 
-_COOKIECRUMBLER_XML = """\
+_DEFAULT_EXPORT = """\
+<?xml version="1.0"?>
 <object name="foo_cookiecrumbler" meta_type="Cookie Crumbler">
  <property name="auth_cookie">__ac</property>
  <property name="name_cookie">__ac_name</property>
@@ -37,32 +62,135 @@
 </object>
 """
 
+_CHANGED_EXPORT = """\
+<?xml version="1.0"?>
+<object name="foo_cookiecrumbler" meta_type="Cookie Crumbler">
+ <property name="auth_cookie">value1</property>
+ <property name="name_cookie">value3</property>
+ <property name="pw_cookie">value5</property>
+ <property name="persist_cookie">value4</property>
+ <property name="auto_login_page">value6</property>
+ <property name="logout_page">value8</property>
+ <property name="unauth_page">value7</property>
+ <property name="local_cookie_path">True</property>
+ <property name="cache_header_value">value2</property>
+ <property name="log_username">False</property>
+</object>
+"""
 
-class CookieCrumblerNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
 
+class CookieCrumblerXMLAdapterTests(BodyAdapterTestCase):
+
     def _getTargetClass(self):
         from Products.CMFCore.exportimport.cookieauth \
-                import CookieCrumblerNodeAdapter
+                import CookieCrumblerXMLAdapter
 
-        return CookieCrumblerNodeAdapter
+        return CookieCrumblerXMLAdapter
 
     def setUp(self):
+        import Products.CMFCore.exportimport
         from Products.CMFCore.CookieCrumbler import CookieCrumbler
-        import Products.CMFCore.exportimport
-        import Products.Five
-        from Products.Five import zcml
 
+        BodyAdapterTestCase.setUp(self)
+        zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
+
+        self._obj = CookieCrumbler('foo_cookiecrumbler')
+        self._BODY = _COOKIECRUMBLER_BODY
+
+
+class _CookieCrumblerSetup(PlacelessSetup, BaseRegistryTests):
+
+    def _initSite(self, use_changed=False):
+        self.root.site = Folder(id='site')
+        site = self.root.site
+        cc = site.cookie_authentication = CookieCrumbler('foo_cookiecrumbler')
+ 
+        if use_changed:
+            cc.auth_cookie = 'value1'
+            cc.cache_header_value = 'value2'
+            cc.name_cookie = 'value3'
+            cc.log_username = 0
+            cc.persist_cookie = 'value4'
+            cc.pw_cookie = 'value5'
+            cc.local_cookie_path = 1
+            cc.auto_login_page = 'value6'
+            cc.unauth_page = 'value7'
+            cc.logout_page = 'value8'
+
+        return site
+
+    def setUp(self):
         PlacelessSetup.setUp(self)
+        BaseRegistryTests.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
         zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
 
-        self._obj = CookieCrumbler('foo_cookiecrumbler')
-        self._XML = _COOKIECRUMBLER_XML
+    def tearDown(self):
+        BaseRegistryTests.tearDown(self)
+        PlacelessSetup.tearDown(self)
 
 
+class exportCookieCrumblerTests(_CookieCrumblerSetup):
+
+    def test_unchanged(self):
+        from Products.CMFCore.exportimport.cookieauth \
+                import exportCookieCrumbler
+
+        site = self._initSite(use_changed=False)
+        context = DummyExportContext(site)
+        exportCookieCrumbler(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'cookieauth.xml')
+        self._compareDOM(text, _DEFAULT_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+    def test_changed(self):
+        from Products.CMFCore.exportimport.cookieauth \
+                import exportCookieCrumbler
+
+        site = self._initSite(use_changed=True)
+        context = DummyExportContext(site)
+        exportCookieCrumbler(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'cookieauth.xml')
+        self._compareDOM(text, _CHANGED_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+
+class importCookieCrumblerTests(_CookieCrumblerSetup):
+
+    def test_normal(self):
+        from Products.CMFCore.exportimport.cookieauth \
+                import importCookieCrumbler
+
+        site = self._initSite()
+        cc = site.cookie_authentication
+
+        context = DummyImportContext(site)
+        context._files['cookieauth.xml'] = _CHANGED_EXPORT
+        importCookieCrumbler(context)
+
+        self.assertEqual( cc.auth_cookie, 'value1' )
+        self.assertEqual( cc.cache_header_value, 'value2' )
+        self.assertEqual( cc.name_cookie, 'value3' )
+        self.assertEqual( cc.log_username, 0 )
+        self.assertEqual( cc.persist_cookie, 'value4' )
+        self.assertEqual( cc.pw_cookie, 'value5' )
+        self.assertEqual( cc.local_cookie_path, 1 )
+        self.assertEqual( cc.auto_login_page, 'value6' )
+        self.assertEqual( cc.unauth_page, 'value7' )
+        self.assertEqual( cc.logout_page, 'value8' )
+
+
 def test_suite():
     return unittest.TestSuite((
-        unittest.makeSuite(CookieCrumblerNodeAdapterTests),
+        unittest.makeSuite(CookieCrumblerXMLAdapterTests),
+        unittest.makeSuite(exportCookieCrumblerTests),
+        unittest.makeSuite(importCookieCrumblerTests),
         ))
 
 if __name__ == '__main__':

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_mailhost.py (from rev 40492, CMF/trunk/CMFCore/exportimport/tests/test_mailhost.py)

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_properties.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_properties.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_properties.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -10,7 +10,7 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Site properties node adapter unit tests.
+"""Site properties xml adapter and setup handler unit tests.
 
 $Id$
 """
@@ -18,11 +18,17 @@
 import unittest
 import Testing
 
+from Products.Five import zcml
+
+from Products.GenericSetup.testing import BodyAdapterTestCase
+from Products.GenericSetup.tests.common import BaseRegistryTests
+from Products.GenericSetup.tests.common import DummyExportContext
+from Products.GenericSetup.tests.common import DummyImportContext
+
 from Products.CMFCore.tests.base.testcase import PlacelessSetup
-from Products.GenericSetup.testing import NodeAdapterTestCase
 
-
-_PROPERTIES_XML = """\
+_PROPERTIES_BODY = """\
+<?xml version="1.0"?>
 <site>
  <property name="title">Foo</property>
  <property name="foo_string" type="string">foo</property>
@@ -30,14 +36,35 @@
 </site>
 """
 
+_EMPTY_EXPORT = """\
+<?xml version="1.0" ?>
+<site>
+ <property name="title"/>
+</site>
+"""
 
-class PropertiesNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+_NORMAL_EXPORT = """\
+<?xml version="1.0" ?>
+<site>
+ <property name="title"/>
+ <property name="foo" type="string">Foo</property>
+ <property name="bar" type="tokens">
+  <element value="Bar"/>
+ </property>
+ <property name="moo" type="tokens">
+  <element value="Moo"/>
+ </property>
+</site>
+"""
 
+
+class PropertiesXMLAdapterTests(BodyAdapterTestCase):
+
     def _getTargetClass(self):
         from Products.CMFCore.exportimport.properties \
-                import PropertiesNodeAdapter
+                import PropertiesXMLAdapter
 
-        return PropertiesNodeAdapter
+        return PropertiesXMLAdapter
 
     def _populate(self, obj):
         obj._setPropValue('title', 'Foo')
@@ -45,22 +72,166 @@
         obj._setProperty('foo_boolean', False, 'boolean')
 
     def setUp(self):
+        import Products.CMFCore.exportimport
         from Products.CMFCore.PortalObject import PortalObjectBase
+
+        BodyAdapterTestCase.setUp(self)
+        zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
+
+        self._obj = PortalObjectBase('foo_site')
+        self._BODY = _PROPERTIES_BODY
+
+
+class _SitePropertiesSetup(PlacelessSetup, BaseRegistryTests):
+
+    def _initSite(self, foo=2, bar=2):
+        from Products.CMFCore.PortalObject import PortalObjectBase
+
+        self.root.site = PortalObjectBase('foo_site')
+        site = self.root.site
+
+        if foo > 0:
+            site._setProperty('foo', '', 'string')
+        if foo > 1:
+            site._updateProperty('foo', 'Foo')
+
+        if bar > 0:
+            site._setProperty( 'bar', (), 'tokens' )
+            site._setProperty( 'moo', (), 'tokens' )
+        if bar > 1:
+            site._updateProperty( 'bar', ('Bar',) )
+            site.moo = ['Moo']
+
+        return site
+
+    def setUp(self):
         import Products.CMFCore.exportimport
-        import Products.Five
-        from Products.Five import zcml
 
         PlacelessSetup.setUp(self)
+        BaseRegistryTests.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
         zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
 
-        self._obj = PortalObjectBase('foo_site')
-        self._XML = _PROPERTIES_XML
+    def tearDown(self):
+        BaseRegistryTests.tearDown(self)
+        PlacelessSetup.tearDown(self)
 
 
+class exportSitePropertiesTests(_SitePropertiesSetup):
+
+    def test_empty(self):
+        from Products.CMFCore.exportimport.properties \
+                import exportSiteProperties
+
+        site = self._initSite(0, 0)
+        context = DummyExportContext(site)
+        exportSiteProperties(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'properties.xml')
+        self._compareDOM(text, _EMPTY_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+    def test_normal(self):
+        from Products.CMFCore.exportimport.properties \
+                import exportSiteProperties
+
+        site = self._initSite()
+        context = DummyExportContext( site )
+        exportSiteProperties(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'properties.xml')
+        self._compareDOM(text, _NORMAL_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+
+class importSitePropertiesTests(_SitePropertiesSetup):
+
+    def test_empty_default_purge(self):
+        from Products.CMFCore.exportimport.properties \
+                import importSiteProperties
+
+        site = self._initSite()
+
+        self.assertEqual( len( site.propertyIds() ), 4 )
+        self.failUnless( 'foo' in site.propertyIds() )
+        self.assertEqual( site.getProperty('foo'), 'Foo' )
+        self.failUnless( 'bar' in site.propertyIds() )
+        self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+        context = DummyImportContext(site)
+        context._files['properties.xml'] = _EMPTY_EXPORT
+        importSiteProperties(context)
+
+        self.assertEqual( len( site.propertyIds() ), 1 )
+
+    def test_empty_explicit_purge(self):
+        from Products.CMFCore.exportimport.properties \
+                import importSiteProperties
+
+        site = self._initSite()
+
+        self.assertEqual( len( site.propertyIds() ), 4 )
+        self.failUnless( 'foo' in site.propertyIds() )
+        self.assertEqual( site.getProperty('foo'), 'Foo' )
+        self.failUnless( 'bar' in site.propertyIds() )
+        self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+        context = DummyImportContext(site, True)
+        context._files['properties.xml'] = _EMPTY_EXPORT
+        importSiteProperties(context)
+
+        self.assertEqual( len( site.propertyIds() ), 1 )
+
+    def test_empty_skip_purge(self):
+        from Products.CMFCore.exportimport.properties \
+                import importSiteProperties
+
+        site = self._initSite()
+
+        self.assertEqual( len( site.propertyIds() ), 4 )
+        self.failUnless( 'foo' in site.propertyIds() )
+        self.assertEqual( site.getProperty('foo'), 'Foo' )
+        self.failUnless( 'bar' in site.propertyIds() )
+        self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+        context = DummyImportContext(site, False)
+        context._files['properties.xml'] = _EMPTY_EXPORT
+        importSiteProperties(context)
+
+        self.assertEqual( len( site.propertyIds() ), 4 )
+        self.failUnless( 'foo' in site.propertyIds() )
+        self.assertEqual( site.getProperty('foo'), 'Foo' )
+        self.failUnless( 'bar' in site.propertyIds() )
+        self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+    def test_normal(self):
+        from Products.CMFCore.exportimport.properties \
+                import importSiteProperties
+
+        site = self._initSite(0,0)
+
+        self.assertEqual( len( site.propertyIds() ), 1 )
+
+        context = DummyImportContext(site)
+        context._files['properties.xml'] = _NORMAL_EXPORT
+        importSiteProperties(context)
+
+        self.assertEqual( len( site.propertyIds() ), 4 )
+        self.failUnless( 'foo' in site.propertyIds() )
+        self.assertEqual( site.getProperty('foo'), 'Foo' )
+        self.failUnless( 'bar' in site.propertyIds() )
+        self.assertEqual( site.getProperty('bar'), ('Bar',) )
+
+
 def test_suite():
     return unittest.TestSuite((
-        unittest.makeSuite(PropertiesNodeAdapterTests),
+        unittest.makeSuite(PropertiesXMLAdapterTests),
+        unittest.makeSuite(exportSitePropertiesTests),
+        unittest.makeSuite(importSitePropertiesTests),
         ))
 
 if __name__ == '__main__':

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_skins.py (from rev 40492, CMF/trunk/CMFCore/exportimport/tests/test_skins.py)

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_typeinfo.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_typeinfo.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_typeinfo.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -10,21 +10,33 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Types tool node adapter unit tests.
+"""Types tool xml adapter and setup handler unit tests.
 
 $Id$
 """
 
 import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
+import Products
+from OFS.Folder import Folder
+from Products.Five import zcml
+
+from Products.GenericSetup.testing import BodyAdapterTestCase
+from Products.GenericSetup.tests.common import BaseRegistryTests
+from Products.GenericSetup.tests.common import DummyExportContext
+from Products.GenericSetup.tests.common import DummyImportContext
+
+from Products.CMFCore.permissions import View
+from Products.CMFCore.permissions import AccessContentsInformation
+from Products.CMFCore.permissions import ModifyPortalContent
 from Products.CMFCore.tests.base.testcase import PlacelessSetup
-from Products.GenericSetup.testing import NodeAdapterTestCase
+from Products.CMFCore.TypesTool import FactoryTypeInformation
+from Products.CMFCore.TypesTool import ScriptableTypeInformation
+from Products.CMFCore.TypesTool import TypesTool
 
-
-_FTI_XML = """\
+_FTI_BODY = """\
+<?xml version="1.0"?>
 <object name="foo_fti" meta_type="Factory-based Type Information"
    xmlns:i18n="http://xml.zope.org/namespaces/i18n">
  <property name="title"></property>
@@ -46,14 +58,342 @@
 </object>
 """
 
+_TYPESTOOL_BODY = """\
+<?xml version="1.0"?>
+<object name="portal_types" meta_type="CMF Types Tool">
+ <property name="title"></property>
+ <object name="foo_type" meta_type="Factory-based Type Information"/>
+</object>
+"""
 
-class TypeInformationNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+_TI_LIST = ({
+    'id':                    'foo',
+    'title':                 'Foo',
+    'description':           'Foo things',
+    'i18n_domain':           'foo_domain',
+    'content_meta_type':     'Foo Thing',
+    'content_icon':          'foo.png',
+    'product':               'CMFSetup',
+    'factory':               'addFoo',
+    'immediate_view':        'foo_view',
+    'filter_content_types':  False,
+    'allowed_content_types': (),
+    'allow_discussion':      False,
+    'global_allow':          False,
+    'aliases': {'(Default)': 'foo_view',
+                'view':      'foo_view',
+                },
+    'actions': ({'id':     'view',
+                 'name':   'View',
+                 'action': 'string:${object_url}/foo_view',
+                 'permissions': (View,),
+                 },
+                {'id':     'edit',
+                 'name':   'Edit',
+                 'action': 'string:${object_url}/foo_edit_form',
+                 'permissions': (ModifyPortalContent,),
+                 },
+                {'id':     'metadata',
+                 'name':   'Metadata',
+                 'action': 'string:${object_url}/metadata_edit_form',
+                 'permissions': (ModifyPortalContent,),
+                 },
+                ),
+    }, {
+    'id':                    'bar',
+    'title':                 'Bar',
+    'description':           'Bar things',
+    'content_meta_type':     'Bar Thing',
+    'content_icon':          'bar.png',
+    'constructor_path':      'make_bar',
+    'permission':            'Add portal content',
+    'immediate_view':        'bar_view',
+    'filter_content_types':  True,
+    'allowed_content_types': ('foo',),
+    'allow_discussion':      True,
+    'global_allow':          True,
+    'aliases': {'(Default)': 'bar_view',
+                'view':      'bar_view',
+                },
+    'actions': ({'id':     'view',
+                 'name':   'View',
+                 'action': 'string:${object_url}/bar_view',
+                 'permissions': (View,),
+                 },
+                {'id':     'edit',
+                 'name':   'Edit',
+                 'action': 'string:${object_url}/bar_edit_form',
+                 'permissions': (ModifyPortalContent,),
+                 },
+                {'id':     'contents',
+                 'name':   'Contents',
+                 'action': 'string:${object_url}/folder_contents',
+                 'permissions': (AccessContentsInformation,),
+                 },
+                {'id':     'metadata',
+                 'name':   'Metadata',
+                 'action': 'string:${object_url}/metadata_edit_form',
+                 'permissions': (ModifyPortalContent,),
+                 },
+               ),
+    })
 
+_TI_LIST_WITH_FILENAME = []
+
+for original in _TI_LIST:
+    duplicate = original.copy()
+    duplicate['id'] = '%s object' % original['id']
+    _TI_LIST_WITH_FILENAME.append(duplicate)
+
+_EMPTY_TOOL_EXPORT = """\
+<?xml version="1.0"?>
+<object name="portal_types" meta_type="CMF Types Tool">
+ <property name="title"/>
+</object>
+"""
+
+_EMPTY_TOOL_EXPORT_V1 = """\
+<?xml version="1.0"?>
+<types-tool>
+</types-tool>
+"""
+
+_NORMAL_TOOL_EXPORT = """\
+<?xml version="1.0"?>
+<object name="portal_types" meta_type="CMF Types Tool">
+ <property name="title"/>
+ <object name="bar" meta_type="Scriptable Type Information"/>
+ <object name="foo" meta_type="Factory-based Type Information"/>
+</object>
+"""
+
+_NORMAL_TOOL_EXPORT_V1 = """\
+<?xml version="1.0"?>
+<types-tool>
+ <type id="bar" />
+ <type id="foo" />
+</types-tool>
+"""
+
+_FILENAME_EXPORT = """\
+<?xml version="1.0"?>
+<object name="portal_types" meta_type="CMF Types Tool">
+ <property name="title"/>
+ <object name="bar object" meta_type="Scriptable Type Information"/>
+ <object name="foo object" meta_type="Factory-based Type Information"/>
+</object>
+"""
+
+_FILENAME_EXPORT_V1 = """\
+<?xml version="1.0"?>
+<types-tool>
+ <type id="bar object" filename="types/bar_object.xml" />
+ <type id="foo object" filename="types/foo_object.xml" />
+</types-tool>
+"""
+
+_UPDATE_TOOL_IMPORT = """\
+<?xml version="1.0"?>
+<types-tool>
+ <type id="foo"/>
+</types-tool>
+"""
+
+_FOO_OLD_EXPORT = """\
+<?xml version="1.0"?>
+<type-info
+   id="%s"
+   kind="Factory-based Type Information"
+   title="Foo"
+   meta_type="Foo Thing"
+   icon="foo.png"
+   product="CMFSetup"
+   factory="addFoo"
+   immediate_view="foo_view"
+   filter_content_types="False"
+   allow_discussion="False"
+   global_allow="False" >
+  <description>Foo things</description>
+  <aliases>
+   <alias from="(Default)" to="foo_view" />
+   <alias from="view" to="foo_view" />
+  </aliases>
+  <action
+     action_id="view"
+     title="View"
+     url_expr="string:${object_url}/foo_view"
+     condition_expr=""
+     category="object"
+     visible="True">
+   <permission>View</permission>
+  </action>
+  <action
+     action_id="edit"
+     title="Edit"
+     url_expr="string:${object_url}/foo_edit_form"
+     condition_expr=""
+     category="object"
+     visible="True">
+   <permission>Modify portal content</permission>
+  </action>
+  <action
+     action_id="metadata"
+     title="Metadata"
+     url_expr="string:${object_url}/metadata_edit_form"
+     condition_expr=""
+     category="object"
+     visible="True">
+   <permission>Modify portal content</permission>
+  </action>
+</type-info>
+"""
+
+_FOO_EXPORT = """\
+<?xml version="1.0"?>
+<object name="%s" meta_type="Factory-based Type Information"
+   i18n:domain="foo_domain" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <property name="title" i18n:translate="">Foo</property>
+ <property name="description" i18n:translate="">Foo things</property>
+ <property name="content_icon">foo.png</property>
+ <property name="content_meta_type">Foo Thing</property>
+ <property name="product">CMFSetup</property>
+ <property name="factory">addFoo</property>
+ <property name="immediate_view">foo_view</property>
+ <property name="global_allow">False</property>
+ <property name="filter_content_types">False</property>
+ <property name="allowed_content_types"/>
+ <property name="allow_discussion">False</property>
+ <alias from="(Default)" to="foo_view"/>
+ <alias from="view" to="foo_view"/>
+ <action title="View" action_id="view" category="object" condition_expr=""
+    url_expr="string:${object_url}/foo_view" visible="True">
+  <permission value="View"/>
+ </action>
+ <action title="Edit" action_id="edit" category="object" condition_expr=""
+    url_expr="string:${object_url}/foo_edit_form" visible="True">
+  <permission value="Modify portal content"/>
+ </action>
+ <action title="Metadata" action_id="metadata" category="object"
+    condition_expr="" url_expr="string:${object_url}/metadata_edit_form"
+    visible="True">
+  <permission value="Modify portal content"/>
+ </action>
+</object>
+"""
+
+_BAR_OLD_EXPORT = """\
+<?xml version="1.0"?>
+<type-info
+   id="%s"
+   kind="Scriptable Type Information"
+   title="Bar"
+   meta_type="Bar Thing"
+   icon="bar.png"
+   constructor_path="make_bar"
+   permission="Add portal content"
+   immediate_view="bar_view"
+   filter_content_types="True"
+   allow_discussion="True"
+   global_allow="True" >
+  <description>Bar things</description>
+  <allowed_content_type>foo</allowed_content_type>
+  <aliases>
+   <alias from="(Default)" to="bar_view" />
+   <alias from="view" to="bar_view" />
+  </aliases>
+  <action
+     action_id="view"
+     title="View"
+     url_expr="string:${object_url}/bar_view"
+     condition_expr=""
+     category="object"
+     visible="True">
+   <permission>View</permission>
+  </action>
+  <action
+     action_id="edit"
+     title="Edit"
+     url_expr="string:${object_url}/bar_edit_form"
+     condition_expr=""
+     category="object"
+     visible="True">
+   <permission>Modify portal content</permission>
+  </action>
+  <action
+     action_id="contents"
+     title="Contents"
+     url_expr="string:${object_url}/folder_contents"
+     condition_expr=""
+     category="object"
+     visible="True">
+   <permission>Access contents information</permission>
+  </action>
+  <action
+     action_id="metadata"
+     title="Metadata"
+     url_expr="string:${object_url}/metadata_edit_form"
+     condition_expr=""
+     category="object"
+     visible="True">
+   <permission>Modify portal content</permission>
+  </action>
+</type-info>
+"""
+
+_BAR_EXPORT = """\
+<?xml version="1.0"?>
+<object name="%s" meta_type="Scriptable Type Information"
+   xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <property name="title">Bar</property>
+ <property name="description">Bar things</property>
+ <property name="content_icon">bar.png</property>
+ <property name="content_meta_type">Bar Thing</property>
+ <property name="permission">Add portal content</property>
+ <property name="constructor_path">make_bar</property>
+ <property name="immediate_view">bar_view</property>
+ <property name="global_allow">True</property>
+ <property name="filter_content_types">True</property>
+ <property name="allowed_content_types">
+  <element value="foo"/>
+ </property>
+ <property name="allow_discussion">True</property>
+ <alias from="(Default)" to="bar_view"/>
+ <alias from="view" to="bar_view"/>
+ <action title="View" action_id="view" category="object" condition_expr=""
+    url_expr="string:${object_url}/bar_view" visible="True">
+  <permission value="View"/>
+ </action>
+ <action title="Edit" action_id="edit" category="object" condition_expr=""
+    url_expr="string:${object_url}/bar_edit_form" visible="True">
+  <permission value="Modify portal content"/>
+ </action>
+ <action title="Contents" action_id="contents" category="object"
+    condition_expr="" url_expr="string:${object_url}/folder_contents"
+    visible="True">
+  <permission value="Access contents information"/>
+ </action>
+ <action title="Metadata" action_id="metadata" category="object"
+    condition_expr="" url_expr="string:${object_url}/metadata_edit_form"
+    visible="True">
+  <permission value="Modify portal content"/>
+ </action>
+</object>
+"""
+
+_UPDATE_FOO_IMPORT = """\
+<object name="foo">
+ <alias from="spam" to="eggs"/>
+</object>
+"""
+
+
+class TypeInformationXMLAdapterTests(BodyAdapterTestCase):
+
     def _getTargetClass(self):
         from Products.CMFCore.exportimport.typeinfo \
-                import TypeInformationNodeAdapter
+                import TypeInformationXMLAdapter
 
-        return TypeInformationNodeAdapter
+        return TypeInformationXMLAdapter
 
     def _populate(self, obj):
         obj.addAction('foo_action', 'Foo', 'string:${object_url}/foo',
@@ -77,22 +417,288 @@
         self.assertEqual(obj._actions[0].condition.text, 'python:1')
 
     def setUp(self):
+        import Products.CMFCore
         from Products.CMFCore.TypesTool import FactoryTypeInformation
-        import Products.CMFCore.exportimport
-        import Products.Five
-        from Products.Five import zcml
 
+        BodyAdapterTestCase.setUp(self)
+        zcml.load_config('configure.zcml', Products.CMFCore)
+
+        self._obj = FactoryTypeInformation('foo_fti')
+        self._BODY = _FTI_BODY
+
+
+class TypesToolXMLAdapterTests(BodyAdapterTestCase):
+
+    def _getTargetClass(self):
+        from Products.CMFCore.exportimport.typeinfo \
+                import TypesToolXMLAdapter
+
+        return TypesToolXMLAdapter
+
+    def _populate(self, obj):
+        from Products.CMFCore.TypesTool import FactoryTypeInformation
+
+        obj._setObject('foo_type', FactoryTypeInformation('foo_type'))
+
+    def setUp(self):
+        import Products.CMFCore
+        from Products.CMFCore.TypesTool import TypesTool
+
+        BodyAdapterTestCase.setUp(self)
+        zcml.load_config('configure.zcml', Products.CMFCore)
+
+        self._obj = TypesTool()
+        self._BODY = _TYPESTOOL_BODY
+
+
+class _TypeInfoSetup(PlacelessSetup, BaseRegistryTests):
+
+    def _initSite(self, foo=0):
+        self.root.site = Folder(id='site')
+        site = self.root.site
+        ttool = site.portal_types = TypesTool()
+
+        if foo == 1:
+            fti = _TI_LIST[0].copy()
+            ttool._setObject(fti['id'], FactoryTypeInformation(**fti))
+            sti = _TI_LIST[1].copy()
+            ttool._setObject(sti['id'], ScriptableTypeInformation(**sti))
+        elif foo == 2:
+            fti = _TI_LIST_WITH_FILENAME[0].copy()
+            ttool._setObject(fti['id'], FactoryTypeInformation(**fti))
+            sti = _TI_LIST_WITH_FILENAME[1].copy()
+            ttool._setObject(sti['id'], ScriptableTypeInformation(**sti))
+
+        return site
+
+    def setUp(self):
         PlacelessSetup.setUp(self)
+        BaseRegistryTests.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
-        zcml.load_config('configure.zcml', Products.CMFCore.exportimport)
+        zcml.load_config('permissions.zcml', Products.Five)
+        zcml.load_config('configure.zcml', Products.CMFCore)
 
-        self._obj = FactoryTypeInformation('foo_fti')
-        self._XML = _FTI_XML
+    def tearDown(self):
+        BaseRegistryTests.tearDown(self)
+        PlacelessSetup.tearDown(self)
 
 
+class exportTypesToolTests(_TypeInfoSetup):
+
+    def test_empty(self):
+        from Products.CMFCore.exportimport.typeinfo import exportTypesTool
+
+        site = self._initSite()
+        context = DummyExportContext(site)
+        exportTypesTool(context)
+
+        self.assertEqual(len(context._wrote), 1)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'typestool.xml')
+        self._compareDOM(text, _EMPTY_TOOL_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+    def test_normal(self):
+        from Products.CMFCore.exportimport.typeinfo import exportTypesTool
+
+        site = self._initSite(1)
+        context = DummyExportContext(site)
+        exportTypesTool(context)
+
+        self.assertEqual(len(context._wrote), 3)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'typestool.xml')
+        self._compareDOM(text, _NORMAL_TOOL_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+
+        filename, text, content_type = context._wrote[2]
+        self.assertEqual(filename, 'types/bar.xml')
+        self._compareDOM(text, _BAR_EXPORT % 'bar')
+        self.assertEqual(content_type, 'text/xml')
+
+        filename, text, content_type = context._wrote[1]
+        self.assertEqual(filename, 'types/foo.xml')
+        self._compareDOM(text, _FOO_EXPORT % 'foo')
+        self.assertEqual(content_type, 'text/xml')
+
+    def test_with_filenames(self):
+        from Products.CMFCore.exportimport.typeinfo import exportTypesTool
+
+        site = self._initSite(2)
+        context = DummyExportContext(site)
+        exportTypesTool(context)
+
+        self.assertEqual(len(context._wrote), 3)
+        filename, text, content_type = context._wrote[0]
+        self.assertEqual(filename, 'typestool.xml')
+        self._compareDOM(text, _FILENAME_EXPORT)
+        self.assertEqual(content_type, 'text/xml')
+        filename, text, content_type = context._wrote[2]
+        self.assertEqual(filename, 'types/bar_object.xml')
+        self._compareDOM(text, _BAR_EXPORT % 'bar object')
+        self.assertEqual(content_type, 'text/xml')
+        filename, text, content_type = context._wrote[1]
+        self.assertEqual(filename, 'types/foo_object.xml')
+        self._compareDOM(text, _FOO_EXPORT % 'foo object')
+        self.assertEqual(content_type, 'text/xml')
+
+
+class importTypesToolTests(_TypeInfoSetup):
+
+    _EMPTY_TOOL_EXPORT = _EMPTY_TOOL_EXPORT
+    _FILENAME_EXPORT = _FILENAME_EXPORT
+    _NORMAL_TOOL_EXPORT = _NORMAL_TOOL_EXPORT
+
+    def test_empty_default_purge(self):
+        from Products.CMFCore.exportimport.typeinfo import importTypesTool
+
+        site = self._initSite(1)
+        tool = site.portal_types
+
+        self.assertEqual(len(tool.objectIds()), 2)
+
+        context = DummyImportContext(site)
+        context._files['typestool.xml'] = self._EMPTY_TOOL_EXPORT
+        importTypesTool(context)
+
+        self.assertEqual(len(tool.objectIds()), 0)
+
+    def test_empty_explicit_purge(self):
+        from Products.CMFCore.exportimport.typeinfo import importTypesTool
+
+        site = self._initSite(1)
+        tool = site.portal_types
+
+        self.assertEqual(len(tool.objectIds()), 2)
+
+        context = DummyImportContext(site, True)
+        context._files['typestool.xml'] = self._EMPTY_TOOL_EXPORT
+        importTypesTool(context)
+
+        self.assertEqual(len(tool.objectIds()), 0)
+
+    def test_empty_skip_purge(self):
+        from Products.CMFCore.exportimport.typeinfo import importTypesTool
+
+        site = self._initSite(1)
+        tool = site.portal_types
+
+        self.assertEqual(len(tool.objectIds()), 2)
+
+        context = DummyImportContext(site, False)
+        context._files['typestool.xml'] = self._EMPTY_TOOL_EXPORT
+        importTypesTool(context)
+
+        self.assertEqual(len(tool.objectIds()), 2)
+
+    def test_normal(self):
+        from Products.CMFCore.exportimport.typeinfo import importTypesTool
+
+        site = self._initSite()
+        tool = site.portal_types
+
+        self.assertEqual(len(tool.objectIds()), 0)
+
+        context = DummyImportContext(site)
+        context._files['typestool.xml'] = self._NORMAL_TOOL_EXPORT
+        context._files['types/foo.xml'] = _FOO_EXPORT % 'foo'
+        context._files['types/bar.xml'] = _BAR_EXPORT % 'bar'
+        importTypesTool(context)
+
+        self.assertEqual(len(tool.objectIds()), 2)
+        self.failUnless('foo' in tool.objectIds())
+        self.failUnless('bar' in tool.objectIds())
+
+    def test_old_xml(self):
+        from Products.CMFCore.exportimport.typeinfo import exportTypesTool
+        from Products.CMFCore.exportimport.typeinfo import importTypesTool
+
+        site = self._initSite()
+        tool = site.portal_types
+
+        self.assertEqual(len(tool.objectIds()), 0)
+
+        context = DummyImportContext(site)
+        context._files['typestool.xml'] = self._NORMAL_TOOL_EXPORT
+        context._files['types/foo.xml'] = _FOO_OLD_EXPORT % 'foo'
+        context._files['types/bar.xml'] = _BAR_OLD_EXPORT % 'bar'
+        importTypesTool(context)
+
+        self.assertEqual(len(tool.objectIds()), 2)
+        self.failUnless('foo' in tool.objectIds())
+        self.failUnless('bar' in tool.objectIds())
+
+        context = DummyExportContext(site)
+        exportTypesTool(context)
+
+        filename, text, content_type = context._wrote[1]
+        self.assertEqual(filename, 'types/bar.xml')
+        self._compareDOM(text, _BAR_EXPORT % 'bar')
+        self.assertEqual(content_type, 'text/xml')
+
+    def test_with_filenames(self):
+        from Products.CMFCore.exportimport.typeinfo import importTypesTool
+
+        site = self._initSite()
+        tool = site.portal_types
+
+        self.assertEqual(len(tool.objectIds()), 0)
+
+        context = DummyImportContext(site)
+        context._files['typestool.xml'] = self._FILENAME_EXPORT
+        context._files['types/foo_object.xml'] = _FOO_EXPORT % 'foo object'
+        context._files['types/bar_object.xml'] = _BAR_EXPORT % 'bar object'
+        importTypesTool(context)
+
+        self.assertEqual(len(tool.objectIds()), 2)
+        self.failUnless('foo object' in tool.objectIds())
+        self.failUnless('bar object' in tool.objectIds())
+
+    def test_normal_update(self):
+        from Products.CMFCore.exportimport.typeinfo import importTypesTool
+
+        site = self._initSite()
+        tool = site.portal_types
+
+        context = DummyImportContext(site)
+        context._files['typestool.xml'] = self._NORMAL_TOOL_EXPORT
+        context._files['types/foo.xml'] = _FOO_EXPORT % 'foo'
+        context._files['types/bar.xml'] = _BAR_EXPORT % 'bar'
+        importTypesTool(context)
+
+        self.assertEqual(tool.foo.title, 'Foo')
+        self.assertEqual(tool.foo.content_meta_type, 'Foo Thing')
+        self.assertEqual(tool.foo.content_icon, 'foo.png')
+        self.assertEqual(tool.foo.immediate_view, 'foo_view')
+        self.assertEqual(tool.foo._aliases,
+                         {'(Default)': 'foo_view', 'view': 'foo_view'})
+
+        context = DummyImportContext(site, False)
+        context._files['typestool.xml'] = _UPDATE_TOOL_IMPORT
+        context._files['types/foo.xml'] = _UPDATE_FOO_IMPORT
+        importTypesTool(context)
+
+        self.assertEqual(tool.foo.title, 'Foo')
+        self.assertEqual(tool.foo.content_meta_type, 'Foo Thing')
+        self.assertEqual(tool.foo.content_icon, 'foo.png')
+        self.assertEqual(tool.foo.immediate_view, 'foo_view')
+        self.assertEqual(tool.foo._aliases,
+               {'(Default)': 'foo_view', 'view': 'foo_view', 'spam': 'eggs'})
+
+class importTypesToolV1Tests(importTypesToolTests):
+
+    _EMPTY_TOOL_EXPORT = _EMPTY_TOOL_EXPORT_V1
+    _FILENAME_EXPORT = _FILENAME_EXPORT_V1
+    _NORMAL_TOOL_EXPORT = _NORMAL_TOOL_EXPORT_V1
+
+
 def test_suite():
     return unittest.TestSuite((
-        unittest.makeSuite(TypeInformationNodeAdapterTests),
+        unittest.makeSuite(TypeInformationXMLAdapterTests),
+        unittest.makeSuite(TypesToolXMLAdapterTests),
+        unittest.makeSuite(exportTypesToolTests),
+        unittest.makeSuite(importTypesToolTests),
+        unittest.makeSuite(importTypesToolV1Tests),
         ))
 
 if __name__ == '__main__':

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/test_workflow.py (from rev 40492, CMF/trunk/CMFCore/exportimport/tests/test_workflow.py)

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/three (from rev 40492, CMF/trunk/CMFCore/exportimport/tests/three)

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/tests/two (from rev 40492, CMF/trunk/CMFCore/exportimport/tests/two)

Modified: CMF/branches/tseaver-viewification/CMFCore/exportimport/typeinfo.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/exportimport/typeinfo.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/exportimport/typeinfo.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -10,26 +10,41 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Types tool node adapters.
+"""Types tool xml adapters and setup handlers.
 
 $Id$
 """
 
+from xml.dom.minidom import parseString
+
+import Products
+from zope.app import zapi
+
+from Products.GenericSetup.interfaces import IBody
 from Products.GenericSetup.interfaces import PURGE
+from Products.GenericSetup.utils import exportObjects
 from Products.GenericSetup.utils import I18NURI
-from Products.GenericSetup.utils import NodeAdapterBase
+from Products.GenericSetup.utils import importObjects
+from Products.GenericSetup.utils import ObjectManagerHelpers
 from Products.GenericSetup.utils import PropertyManagerHelpers
+from Products.GenericSetup.utils import XMLAdapterBase
 
 from Products.CMFCore.interfaces import ITypeInformation
+from Products.CMFCore.interfaces import ITypesTool
+from Products.CMFCore.utils import getToolByName
 
+_FILENAME = 'typestool.xml'
 
-class TypeInformationNodeAdapter(NodeAdapterBase, PropertyManagerHelpers):
 
-    """Node im- and exporter for TypeInformation.
+class TypeInformationXMLAdapter(XMLAdapterBase, PropertyManagerHelpers):
+
+    """XML im- and exporter for TypeInformation.
     """
 
     __used_for__ = ITypeInformation
 
+    _LOGGER_ID = 'types'
+
     def exportNode(self, doc):
         """Export the object as a DOM node.
         """
@@ -39,6 +54,8 @@
         node.appendChild(self._extractProperties())
         node.appendChild(self._extractAliases())
         node.appendChild(self._extractActions())
+
+        self._logger.info('%r type info exported.' % self.context.getId())
         return node
 
     def importNode(self, node, mode=PURGE):
@@ -54,6 +71,8 @@
         self._initAliases(node, mode)
         self._initActions(node, mode)
 
+        self._logger.info('%r type info imported.' % self.context.getId())
+
     def _extractAliases(self):
         fragment = self._doc.createDocumentFragment()
         aliases = self.context.getMethodAliases().items()
@@ -176,3 +195,103 @@
             permission = node.getAttribute('permission')
             obj._updateProperty('constructor_path', constructor_path)
             obj._updateProperty('permission', permission)
+
+
+class TypesToolXMLAdapter(XMLAdapterBase, ObjectManagerHelpers,
+                          PropertyManagerHelpers):
+
+    """XML im- and exporter for TypesTool.
+    """
+
+    __used_for__ = ITypesTool
+
+    _LOGGER_ID = 'types'
+
+    def exportNode(self, doc):
+        """Export the object as a DOM node.
+        """
+        self._doc = doc
+        node = self._getObjectNode('object')
+        node.appendChild(self._extractProperties())
+        node.appendChild(self._extractObjects())
+
+        self._logger.info('Types tool exported.')
+        return node
+
+    def importNode(self, node, mode=PURGE):
+        """Import the object from the DOM node.
+        """
+        if mode == PURGE:
+            self._purgeProperties()
+            self._purgeObjects()
+
+        self._initProperties(node, mode)
+        self._initObjects(node, mode)
+        self._initBBBObjects(node, mode)
+
+        self._logger.info('Types tool imported.')
+
+    def _initBBBObjects(self, node, mode):
+        for child in node.childNodes:
+            if child.nodeName != 'type':
+                continue
+            parent = self.context
+
+            obj_id = str(child.getAttribute('id'))
+            if obj_id not in parent.objectIds():
+                filename = str(child.getAttribute('filename'))
+                if not filename:
+                    filename = 'types/%s.xml' % obj_id.replace(' ', '_')
+                body = self.environ.readDataFile(filename)
+                if body is None:
+                    break
+                root = parseString(body).documentElement
+                if root.getAttribute('name') != obj_id:
+                    if root.getAttribute('id') != obj_id:
+                        break
+                meta_type = str(root.getAttribute('kind'))
+                if not meta_type:
+                    meta_type = str(root.getAttribute('meta_type'))
+                for mt_info in Products.meta_types:
+                    if mt_info['name'] == meta_type:
+                        parent._setObject(obj_id, mt_info['instance'](obj_id))
+                        break
+
+
+def importTypesTool(context):
+    """Import types tool and content types from XML files.
+    """
+    site = context.getSite()
+    logger = context.getLogger('types')
+    tool = getToolByName(site, 'portal_types')
+
+    body = context.readDataFile(_FILENAME)
+    if body is None:
+        logger.info('Nothing to import.')
+        return
+
+    importer = zapi.queryMultiAdapter((tool, context), IBody)
+    if importer is None:
+        logger.warning('Import adapter misssing.')
+        return
+
+    importer.body = body
+    importObjects(tool, 'types', context)
+
+def exportTypesTool(context):
+    """Export types tool content types as a set of XML files.
+    """
+    site = context.getSite()
+    logger = context.getLogger('types')
+    tool = getToolByName(site, 'portal_types', None)
+    if tool is None:
+        logger.info('Nothing to export.')
+        return
+
+    exporter = zapi.queryMultiAdapter((tool, context), IBody)
+    if exporter is None:
+        logger.warning('Export adapter misssing.')
+        return
+
+    context.writeDataFile(_FILENAME, exporter.body, exporter.mime_type)
+    exportObjects(tool, 'types', context)

Copied: CMF/branches/tseaver-viewification/CMFCore/exportimport/workflow.py (from rev 40492, CMF/trunk/CMFCore/exportimport/workflow.py)

Modified: CMF/branches/tseaver-viewification/CMFCore/interfaces/_tools.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/interfaces/_tools.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/interfaces/_tools.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -911,14 +911,17 @@
             o Must be set to 'portal_metadata'.
             """)
 
+    id = Attribute('id', 'Must be set to "portal_metadata"')
+
     #
-    #   Site-wide queries.
+    #   Site-wide queries, specific to Dublin Core metadata.
     #
     def getFullName(userid):
-        """ Convert an internal userid to a "formal" name, if possible
+        """ Convert an internal userid to a "formal" name.
+        
+        o Convert only if possible, perhaps using the 'portal_membership'
+          tool;  otherwise, return 'userid'.
 
-        o 'userid' is the ID of the user within the user folder.
-
         o Used to map userid's for Creator, Contributor DCMI queries.
         """
 
@@ -927,67 +930,100 @@
         """
 
     #
-    #   Content-specific queries.
+    #   Content-specific queries, for Dublin Core metadata.
     #
-    def listAllowedSubjects(content=None):
+    def listAllowedSubjects(content=None, content_type=None):
         """ List the allowed values of the 'Subject' DCMI element.
 
-        o If 'content' is not None, return only values appropriate for
-          content's type;  otherwise, return "default" values.
+        o 'Subject' elements should be keywords categorizing their resource.
 
-        o 'Subject' elements should be keywords categorizing their resource.
+        o Return only values appropriate for content's type, or all values if
+          both 'content' and 'content_type' are None.
         """
 
-    def listAllowedFormats(content=None):
+    def listAllowedFormats(content=None, content_type=None):
         """ List the allowed values of the 'Format' DCMI element.
 
-        o If 'content' is not None, return only values appropriate for
-          content's type;  otherwise, return "default" values.
+        o These items should be usable as HTTP 'Content-type' values.
 
-        o 'Format' elements should be usable as HTTP 'Content-type' values.
+        o Return only values appropriate for content's type, or all values if
+          both 'content' and 'content_type' are None.
         """
 
-    def listAllowedLanguages(content=None):
+    def listAllowedLanguages(content=None, content_type=None):
         """ List the allowed values of the 'Language' DCMI element.
 
-        o If 'content' is not None, return only values appropriate for
-          content's type;  otherwise, return "default" values.
-
         o 'Language' element values should be suitable for generating
           HTTP headers.
+
+        o Return only values appropriate for content's type, or all values if
+          both 'content' and 'content_type' are None.
         """
 
-    def listAllowedRights(content=None):
+    def listAllowedRights(content=None, content_type=None):
         """ List the allowed values of the 'Rights' DCMI element.
 
-        o If 'content' is not None, return only values appropriate for
-          content's type;  otherwise, return "default" values.
+        o The 'Rights' element describes copyright or other IP declarations
+          pertaining to a resource.
 
-        o The 'Rights' element describes copyright or other IP
-          declarations pertaining to a resource.
+        o Return only values appropriate for content's type, or all values if
+          both 'content' and 'content_type' are None.
         """
 
     #
-    #   Validation policy hooks.
+    #   Content-specific queries, for generic metadata.
     #
-    def setInitialMetadata(content):
-        """ Set default initial values for content metatdata.
+    def listAllowedVocabulary( schema
+                             , element
+                             , content=None
+                             , content_type=None
+                             ):
+        """ List allowed values for a given schema element and content object.
+        
+        o List possible keywords if both 'content' and 'content_type' are None.
         """
 
-    def validateMetadata(content):
-        """ Enforce portal-wide policies about DCMI elements.
+    #
+    #   Schema manipulation
+    #
+    def listSchemas():
+        """ Return a list of (id, schema) tuples enumerating our schema.
+        """
 
-        o Such policy may, e.g., require non-empty title/description, etc.
+    def addSchema( schema_id ):
+        """ Create a new schema with the given ID.
 
-        o Called by the CMF immediately before saving changes to the
-          metadata of an object.
+        o Return the newly-created schema object.
 
-        o XXX:  Note that the default skins / edit methods do *not*
-          call this method;  the choice of when to apply the validation
-          is policy.
+        o Raise KeyError if such a schema already exists.
         """
 
+    def removeSchema( schema_id ):
+        """ Remove an existing schema with the given ID.
 
+        o Raise KeyError if no such schema exists.
+        """
+
+    #
+    #   Validation policy hooks.
+    #
+    def setInitialMetadata(content):
+        """ Set initial values for content metatdata.
+        
+        o Supply any site-specific defaults.
+        """
+
+    def validateMetadata(content):
+        """ Enforce portal-wide policies about metadata.
+        
+        o E.g., policies may require non-empty title/description, etc.
+        
+        o This method may be called by view / workflow code at "appropriate"
+          times, such as immediately before saving changes to the metadata of
+          an object.
+        """
+
+
 #
 #   Site Properties tool interface
 #
@@ -1133,6 +1169,12 @@
 #
 #   Skins tool interfaces
 #
+class IDirectoryView(Interface):
+
+    """ Directory views mount filesystem directories.
+    """
+
+
 class ISkinsContainer(Interface):
 
     """ An object that provides skins.

Modified: CMF/branches/tseaver-viewification/CMFCore/tests/base/testcase.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/tests/base/testcase.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/tests/base/testcase.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -30,6 +30,28 @@
     from zope.app.tests.placelesssetup import setUp as placelessSetUp
     from zope.app.tests.placelesssetup import tearDown as placelessTearDown
 
+_TRAVERSE_ZCML = """
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:five="http://namespaces.zope.org/five"
+    >
+
+  <adapter
+      for="*"
+      factory=".traversable.FiveTraversable"
+      provides="zope.app.traversing.interfaces.ITraversable"
+      />
+
+  <adapter
+      for="*"
+      factory="zope.app.traversing.adapters.Traverser"
+      provides="zope.app.traversing.interfaces.ITraverser"
+      />
+
+</configure>
+"""
+
+
 class LogInterceptor:
 
     _old_log_write = None

Modified: CMF/branches/tseaver-viewification/CMFCore/tests/test_ActionInformation.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/tests/test_ActionInformation.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/tests/test_ActionInformation.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,12 +15,12 @@
 $Id$
 """
 
-from unittest import TestCase, TestSuite, makeSuite, main
+import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
+import Products.Five
 from OFS.Folder import manage_addFolder
+from Products.Five import zcml
 from Products.PythonScripts.PythonScript import manage_addPythonScript
 
 from Products.CMFCore.Expression import createExprContext
@@ -28,11 +28,13 @@
 from Products.CMFCore.tests.base.dummy import DummyContent
 from Products.CMFCore.tests.base.dummy import DummySite
 from Products.CMFCore.tests.base.dummy import DummyTool as DummyMembershipTool
+from Products.CMFCore.tests.base.testcase import _TRAVERSE_ZCML
+from Products.CMFCore.tests.base.testcase import PlacelessSetup
 from Products.CMFCore.tests.base.testcase import SecurityTest
 from Products.CMFCore.tests.base.testcase import TransactionalTest
 
 
-class ActionCategoryTests(TestCase):
+class ActionCategoryTests(unittest.TestCase):
 
     def _makeOne(self, *args, **kw):
         from Products.CMFCore.ActionInformation import ActionCategory
@@ -57,7 +59,7 @@
         self.assertEqual( ac.listActions(), (baz,) )
 
 
-class ActionTests(TestCase):
+class ActionTests(unittest.TestCase):
 
     def _makeOne(self, *args, **kw):
         from Products.CMFCore.ActionInformation import Action
@@ -96,7 +98,7 @@
         self.assertEqual( a.getInfoData(), WANTED )
 
 
-class ActionInfoTests(TestCase):
+class ActionInfoTests(unittest.TestCase):
 
     def _makeOne(self, *args, **kw):
         from Products.CMFCore.ActionInformation import ActionInfo
@@ -287,12 +289,17 @@
         self.assertEqual( ai2['allowed'], True )
 
 
-class ActionInformationTests(TransactionalTest):
+class ActionInformationTests(PlacelessSetup, TransactionalTest):
 
-    def setUp( self ):
+    def setUp(self):
+        import Products.CMFCore
+        PlacelessSetup.setUp(self)
+        TransactionalTest.setUp(self)
+        zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('permissions.zcml', Products.Five)
+        zcml.load_config('configure.zcml', Products.CMFCore)
+        zcml.load_string(_TRAVERSE_ZCML)
 
-        TransactionalTest.setUp( self )
-
         root = self.root
         root._setObject('portal', DummyContent('portal', 'url_portal'))
         portal = self.portal = root.portal
@@ -300,6 +307,10 @@
         self.folder = DummyContent('foo', 'url_foo')
         self.object = DummyContent('bar', 'url_bar')
 
+    def tearDown(self):
+        TransactionalTest.tearDown(self)
+        PlacelessSetup.tearDown(self)
+
     def _makeOne(self, *args, **kw):
         from Products.CMFCore.ActionInformation import ActionInformation
 
@@ -416,13 +427,13 @@
 
 
 def test_suite():
-    return TestSuite((
-        makeSuite(ActionCategoryTests),
-        makeSuite(ActionTests),
-        makeSuite(ActionInfoTests),
-        makeSuite(ActionInfoSecurityTests),
-        makeSuite(ActionInformationTests),
+    return unittest.TestSuite((
+        unittest.makeSuite(ActionCategoryTests),
+        unittest.makeSuite(ActionTests),
+        unittest.makeSuite(ActionInfoTests),
+        unittest.makeSuite(ActionInfoSecurityTests),
+        unittest.makeSuite(ActionInformationTests),
         ))
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Modified: CMF/branches/tseaver-viewification/CMFCore/tests/test_CachingPolicyManager.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/tests/test_CachingPolicyManager.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/tests/test_CachingPolicyManager.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -21,20 +21,22 @@
 import base64
 import os
 
+import Products.Five
 from AccessControl.SecurityManagement import newSecurityManager
 from App.Common import rfc1123_date
 from DateTime.DateTime import DateTime
+from Products.Five import zcml
 
 from Products.CMFCore.FSPageTemplate import FSPageTemplate
 from Products.CMFCore.tests.base.dummy import DummyContent
 from Products.CMFCore.tests.base.dummy import DummySite
 from Products.CMFCore.tests.base.dummy import DummyTool
 from Products.CMFCore.tests.base.dummy import DummyUserFolder
+from Products.CMFCore.tests.base.testcase import _TRAVERSE_ZCML
 from Products.CMFCore.tests.base.testcase import FSDVTest
+from Products.CMFCore.tests.base.testcase import PlacelessSetup
 from Products.CMFCore.tests.base.testcase import RequestTest
-from Products.CMFCore.tests.test_FSPageTemplate import FSPTMaker
 
-
 ACCLARK = DateTime( '2001/01/01' )
 portal_owner = 'portal_owner'
 
@@ -600,13 +602,18 @@
         self.assertEqual( headers[2][1] , 'max-age=86400' )
 
 
-class CachingPolicyManager304Tests(RequestTest, FSDVTest):
+class CachingPolicyManager304Tests(PlacelessSetup, RequestTest, FSDVTest):
 
     def setUp(self):
         from Products.CMFCore import CachingPolicyManager
 
+        PlacelessSetup.setUp(self)
         RequestTest.setUp(self)
         FSDVTest.setUp(self)
+        zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('permissions.zcml', Products.Five)
+        zcml.load_config('configure.zcml', Products.CMFCore)
+        zcml.load_string(_TRAVERSE_ZCML)
 
         now = DateTime()
 
@@ -681,6 +688,7 @@
     def tearDown(self):
         RequestTest.tearDown(self)
         FSDVTest.tearDown(self)
+        PlacelessSetup.tearDown(self)
 
     def _cleanup(self):
         # Clean up request and response

Modified: CMF/branches/tseaver-viewification/CMFCore/tests/test_TypesTool.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/tests/test_TypesTool.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/tests/test_TypesTool.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,18 +15,18 @@
 $Id$
 """
 
-from unittest import TestCase, TestSuite, makeSuite, main
+import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
+import Products
 from AccessControl import Unauthorized
 from AccessControl.SecurityManagement import newSecurityManager
 from AccessControl.SecurityManagement import noSecurityManager
 from AccessControl.SecurityManager import setSecurityPolicy
 from Acquisition import aq_base
+from Products.Five import zcml
 from Products.PythonScripts.PythonScript import PythonScript
-from Products.PythonScripts.standard import url_quote
+from Products.PythonScripts.standard import html_quote
 from webdav.NullResource import NullResource
 
 from Products.CMFCore.ActionInformation import ActionInformation
@@ -38,6 +38,8 @@
 from Products.CMFCore.tests.base.dummy import DummyUserFolder
 from Products.CMFCore.tests.base.security import OmnipotentUser
 from Products.CMFCore.tests.base.security import UserWithRoles
+from Products.CMFCore.tests.base.testcase import _TRAVERSE_ZCML
+from Products.CMFCore.tests.base.testcase import PlacelessSetup
 from Products.CMFCore.tests.base.testcase import SecurityTest
 from Products.CMFCore.tests.base.testcase import WarningInterceptor
 from Products.CMFCore.tests.base.tidata import FTIDATA_ACTIONS
@@ -52,7 +54,7 @@
 from Products.CMFCore.tests.base.tidata import STI_SCRIPT
 
 
-class TypesToolTests(SecurityTest, WarningInterceptor):
+class TypesToolTests(PlacelessSetup, SecurityTest, WarningInterceptor):
 
     def _makeOne(self):
         from Products.CMFCore.TypesTool import TypesTool
@@ -62,7 +64,13 @@
     def setUp( self ):
         from Products.CMFCore.TypesTool import FactoryTypeInformation as FTI
 
+        PlacelessSetup.setUp(self)
         SecurityTest.setUp(self)
+        zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('permissions.zcml', Products.Five)
+        zcml.load_config('configure.zcml', Products.Five.browser)
+        zcml.load_config('configure.zcml', Products.CMFCore)
+        zcml.load_string(_TRAVERSE_ZCML)
 
         self.site = DummySite('site').__of__(self.root)
         self.acl_users = self.site._setObject( 'acl_users', DummyUserFolder() )
@@ -72,6 +80,7 @@
 
     def tearDown(self):
         SecurityTest.tearDown(self)
+        PlacelessSetup.tearDown(self)
         self._free_warning_output()
 
     def test_z2interfaces(self):
@@ -105,9 +114,9 @@
         # so we check for that. If we've got it, something is b0rked.
         for factype in tool.all_meta_types():
             meta_types[factype['name']]=1
-            # The url_quote below is necessary 'cos of the one in
+            # The html_quote below is necessary 'cos of the one in
             # main.dtml. Could be removed once that is gone.
-            act = tool.unrestrictedTraverse(url_quote(factype['action']))
+            act = tool.unrestrictedTraverse(html_quote(factype['action']))
             self.failIf(type(aq_base(act)) is NullResource)
 
         # Check the ones we're expecting are there
@@ -145,7 +154,7 @@
                       'Unauthorized raised' )
 
 
-class TypeInfoTests(TestCase):
+class TypeInfoTests(unittest.TestCase):
 
     def _makeTypesTool(self):
         from Products.CMFCore.TypesTool import TypesTool
@@ -466,7 +475,7 @@
         self.assertEqual( ti.constructor_path, 'foo_add' )
 
 
-class FTIConstructionTests(TestCase):
+class FTIConstructionTests(unittest.TestCase):
 
     def setUp( self ):
         noSecurityManager()
@@ -513,7 +522,7 @@
         self.failIf( ti.isConstructionAllowed( folder ) )
 
 
-class FTIConstructionTests_w_Roles(TestCase):
+class FTIConstructionTests_w_Roles(unittest.TestCase):
 
     def tearDown( self ):
         noSecurityManager()
@@ -616,13 +625,13 @@
 
 
 def test_suite():
-    return TestSuite((
-        makeSuite(TypesToolTests),
-        makeSuite(FTIDataTests),
-        makeSuite(STIDataTests),
-        makeSuite(FTIConstructionTests),
-        makeSuite(FTIConstructionTests_w_Roles),
+    return unittest.TestSuite((
+        unittest.makeSuite(TypesToolTests),
+        unittest.makeSuite(FTIDataTests),
+        unittest.makeSuite(STIDataTests),
+        unittest.makeSuite(FTIConstructionTests),
+        unittest.makeSuite(FTIConstructionTests_w_Roles),
         ))
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Modified: CMF/branches/tseaver-viewification/CMFCore/tests/test_WorkflowTool.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/tests/test_WorkflowTool.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/tests/test_WorkflowTool.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -20,9 +20,7 @@
 
 from OFS.SimpleItem import SimpleItem
 
-from Products.CMFCore.tests.base.testcase import WarningInterceptor
 
-
 class Dummy( SimpleItem ):
 
     def __init__( self, id ):
@@ -131,24 +129,15 @@
         return None
 
 
-class WorkflowToolTests(unittest.TestCase, WarningInterceptor):
+class WorkflowToolTests(unittest.TestCase):
 
-    def setUp( self ):
-        from Products.CMFCore.WorkflowTool import addWorkflowFactory
-        addWorkflowFactory( DummyWorkflow )
-
-    def tearDown( self ):
-        from Products.CMFCore.WorkflowTool import _removeWorkflowFactory
-        _removeWorkflowFactory( DummyWorkflow )
-        self._free_warning_output()
-
     def _makeOne( self, workflow_ids=() ):
         from Products.CMFCore.WorkflowTool import WorkflowTool
 
         tool = WorkflowTool()
 
         for workflow_id in workflow_ids:
-            tool.manage_addWorkflow( DummyWorkflow.meta_type, workflow_id )
+            tool._setObject(workflow_id, DummyWorkflow(workflow_id))
 
         return tool
 

Deleted: CMF/branches/tseaver-viewification/CMFCore/www/addTypeInfo.zpt
===================================================================
--- CMF/branches/tseaver-viewification/CMFCore/www/addTypeInfo.zpt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFCore/www/addTypeInfo.zpt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,47 +0,0 @@
-<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1>
-<h2 tal:define="form_title string:Add ${options/add_meta_type}"
-    tal:replace="structure context/manage_form_title">FORM TITLE</h2>
-
-<p class="form-help">A type information object defines a portal type.</p>
-
-<form action="manage_addTypeInfo" method="post">
-<input type="hidden" name="add_meta_type" value=""
-   tal:attributes="value options/add_meta_type" />
-<table cellspacing="0" cellpadding="2" border="0">
- <tr>
-  <td>
-   <div class="form-label">ID</div>
-  </td>
-  <td>
-   <input type="text" name="id" size="40" />
-  </td>
- </tr>
- <tr tal:condition="options/profiles">
-  <td>
-   <div class="form-label">Presettings</div>
-  </td>
-  <td>
-   <select name="settings_id">
-    <option value="" selected="selected">(None)</option>
-    <optgroup label="PROFILE_TITLE"
-       tal:repeat="profile options/profiles"
-       tal:attributes="label profile/title">
-     <option value="SETTINGS_ID"
-             tal:repeat="type_id profile/type_ids"
-             tal:attributes="value string:${profile/id}/${type_id}"
-             tal:content="type_id">TYPE ID</option></optgroup>
-   </select>
-  </td>
- </tr>
- <tr>
-  <td>
-   &nbsp;
-  </td>
-  <td>
-   <input class="form-element" type="submit" name="submit" value="Add" /> 
-  </td>
- </tr>
-</table>
-</form>
-
-<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1>

Modified: CMF/branches/tseaver-viewification/CMFDefault/DEPENDENCIES.txt
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/DEPENDENCIES.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/DEPENDENCIES.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,4 +1,4 @@
-Zope >= 2.8.2
+Zope >= 2.8.5
 Five >= 1.2
 CMFCore
 GenericSetup

Modified: CMF/branches/tseaver-viewification/CMFDefault/MetadataTool.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/MetadataTool.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/MetadataTool.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -20,6 +20,7 @@
 from Globals import DTMLFile
 from Globals import InitializeClass
 from Globals import PersistentMapping
+from OFS.Folder import Folder
 from OFS.SimpleItem import SimpleItem
 from zope.interface import implements
 
@@ -37,10 +38,8 @@
 
 
 class MetadataElementPolicy( SimpleItem ):
-
+    """ Represent a type-specific policy about a particular metadata element.
     """
-        Represent a type-specific policy about a particular DCMI element.
-    """
 
     security = ClassSecurityInfo()
     #
@@ -77,62 +76,47 @@
     #
     security.declareProtected(View , 'isMultiValued')
     def isMultiValued( self ):
+        """ Can this element hold multiple values?
         """
-            Can this element hold multiple values?
-        """
         return self.is_multi_valued
 
     security.declareProtected(View , 'isRequired')
     def isRequired( self ):
+        """ Must this element be supplied?
         """
-            Must this element be supplied?
-        """
         return self.is_required
 
     security.declareProtected(View , 'supplyDefault')
     def supplyDefault( self ):
+        """ Should the tool supply a default?
         """
-            Should the tool supply a default?
-        """
         return self.supply_default
 
     security.declareProtected(View , 'defaultValue')
     def defaultValue( self ):
+        """ If so, what is the default?
         """
-            If so, what is the default?
-        """
         return self.default_value
 
     security.declareProtected(View , 'enforceVocabulary')
     def enforceVocabulary( self ):
+        """ Should the tool enforce the policy's vocabulary?
         """
-        """
         return self.enforce_vocabulary
 
     security.declareProtected(View , 'allowedVocabulary')
     def allowedVocabulary( self ):
+        """ What are the allowed values?
         """
-        """
         return self.allowed_vocabulary
 
 InitializeClass( MetadataElementPolicy )
 
 
-DEFAULT_ELEMENT_SPECS = ( ( 'Title', 0 )
-                        , ( 'Description', 0 )
-                        , ( 'Subject', 1 )
-                        , ( 'Format', 0 )
-                        , ( 'Language', 0 )
-                        , ( 'Rights', 0 )
-                        )
 
-
 class ElementSpec( SimpleItem ):
-
+    """ Represent all the tool knows about a single metadata element.
     """
-        Represent all the tool knows about a single metadata element.
-    """
-
     security = ClassSecurityInfo()
 
     #
@@ -158,10 +142,10 @@
 
     security.declareProtected(View , 'getPolicy')
     def getPolicy( self, typ=None ):
+        """ Find the policy for this element for objects of the given type.
+        
+        o Return a default, if none found.
         """
-            Find the policy this element for objects whose type
-            object name is 'typ';  return a default, if none found.
-        """
         try:
             return self.policies[ typ ].__of__(self)
         except KeyError:
@@ -169,9 +153,8 @@
 
     security.declareProtected(View , 'listPolicies')
     def listPolicies( self ):
+        """ Return a list of all policies for this element.
         """
-            Return a list of all policies for this element.
-        """
         res = []
         for k, v in self.policies.items():
             res.append((k, v.__of__(self)))
@@ -179,10 +162,8 @@
 
     security.declareProtected(ManagePortal , 'addPolicy')
     def addPolicy( self, typ ):
+        """ Add a policy to this element for objects of the given type.
         """
-            Add a policy to this element for objects whose type
-            object name is 'typ'.
-        """
         if typ is None:
             raise MetadataError, "Can't replace default policy."
 
@@ -193,10 +174,10 @@
 
     security.declareProtected(ManagePortal, 'removePolicy')
     def removePolicy( self, typ ):
+        """ Remove the policy from this element for objects of the given type.
+        
+        o Do *not* remvoe the default, however.
         """
-            Remove the policy from this element for objects whose type
-            object name is 'typ' (*not* the default, however).
-        """
         if typ is None:
             raise MetadataError, "Can't remove default policy."
         del self.policies[ typ ]
@@ -204,90 +185,32 @@
 InitializeClass( ElementSpec )
 
 
-class MetadataTool( UniqueObject, SimpleItem, ActionProviderBase ):
-
-    implements(IMetadataTool)
-    __implements__ = (z2IMetadataTool, ActionProviderBase.__implements__)
-
-    id = 'portal_metadata'
-    meta_type = 'Default Metadata Tool'
-
-    #
-    #   Default values.
-    #
-    publisher           = ''
-    element_specs       = None
-    #initial_values_hook = None
-    #validation_hook     = None
-
+class MetadataSchema( SimpleItem ):
+    """ Describe a metadata schema.
+    """
     security = ClassSecurityInfo()
 
-    def __init__( self
-                , publisher=None
-               #, initial_values_hook=None
-               #, validation_hook=None
-                , element_specs=DEFAULT_ELEMENT_SPECS
-                ):
+    meta_type = 'Metadata Schema'
+    publisher = ''
 
-        self.editProperties( publisher
-                          #, initial_values_hook
-                          #, validation_hook
-                           )
-
+    def __init__( self, id, element_specs=() ):
+        self._setId( id )
         self.element_specs = PersistentMapping()
-
         for name, is_multi_valued in element_specs:
             self.element_specs[ name ] = ElementSpec( is_multi_valued )
 
+
     #
     #   ZMI methods
     #
-    manage_options = ( ActionProviderBase.manage_options +
-                     ( { 'label'      : 'Overview'
-                         , 'action'     : 'manage_overview'
-                         }
-                       , { 'label'      : 'Properties'
-                         , 'action'     : 'propertiesForm'
-                         }
-                       , { 'label'      : 'Elements'
+    manage_options = ( ( { 'label'      : 'Elements'
                          , 'action'     : 'elementPoliciesForm'
                          }
-            # TODO     , { 'label'      : 'Types'
-            #            , 'action'     : 'typesForm'
-            #            }
+                       ,
                        )
                      + SimpleItem.manage_options
                      )
 
-    security.declareProtected(ManagePortal, 'manage_overview')
-    manage_overview = DTMLFile( 'explainMetadataTool', _dtmldir )
-
-    security.declareProtected(ManagePortal, 'propertiesForm')
-    propertiesForm = DTMLFile( 'metadataProperties', _dtmldir )
-
-    security.declareProtected(ManagePortal, 'editProperties')
-    def editProperties( self
-                      , publisher=None
-               # TODO , initial_values_hook=None
-               # TODO , validation_hook=None
-                      , REQUEST=None
-                      ):
-        """
-            Form handler for "tool-wide" properties (including list of
-            metadata elements).
-        """
-        if publisher is not None:
-            self.publisher = publisher
-
-        # TODO self.initial_values_hook = initial_values_hook
-        # TODO self.validation_hook = validation_hook
-
-        if REQUEST is not None:
-            REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
-                                        + '/propertiesForm'
-                                        + '?manage_tabs_message=Tool+updated.'
-                                        )
-
     security.declareProtected(ManagePortal, 'elementPoliciesForm')
     elementPoliciesForm = DTMLFile( 'metadataElementPolicies', _dtmldir )
 
@@ -302,9 +225,8 @@
                         , allowed_vocabulary
                         , REQUEST=None
                         ):
+        """ Add a type-specific policy for one of our elements.
         """
-            Add a type-specific policy for one of our elements.
-        """
         if content_type == '<default>':
             content_type = None
 
@@ -330,9 +252,8 @@
                            , content_type
                            , REQUEST=None
                            ):
+        """ Remvoe a type-specific policy for one of our elements.
         """
-            Remvoe a type-specific policy for one of our elements.
-        """
         if content_type == '<default>':
             content_type = None
 
@@ -356,10 +277,10 @@
                            , allowed_vocabulary
                            , REQUEST=None
                            ):
+        """ Update a policy for one of our elements 
+        
+        o 'content_type' will be '<default>' when we edit the default.
         """
-            Update a policy for one of our elements ('content_type'
-            will be '<default>' when we edit the default).
-        """
         if content_type == '<default>':
             content_type = None
         spec = self.getElementSpec( element )
@@ -383,10 +304,8 @@
     #
     security.declareProtected(ManagePortal, 'listElementSpecs')
     def listElementSpecs( self ):
+        """ Return a list of ElementSpecs representing the elements we manage.
         """
-            Return a list of ElementSpecs representing
-            the elements managed by the tool.
-        """
         res = []
         for k, v in self.element_specs.items():
             res.append((k, v.__of__(self)))
@@ -394,17 +313,14 @@
 
     security.declareProtected(ManagePortal, 'getElementSpec')
     def getElementSpec( self, element ):
+        """ Return an ElementSpec for the given 'element'.
         """
-            Return an ElementSpec representing the tool's knowledge
-            of 'element'.
-        """
         return self.element_specs[ element ].__of__( self )
 
     security.declareProtected(ManagePortal, 'addElementSpec')
     def addElementSpec( self, element, is_multi_valued, REQUEST=None ):
+        """ Add 'element' to our list of managed elements.
         """
-            Add 'element' to our list of managed elements.
-        """
         # Don't replace.
         if self.element_specs.has_key( element ):
            return
@@ -419,9 +335,8 @@
 
     security.declareProtected(ManagePortal, 'removeElementSpec')
     def removeElementSpec( self, element, REQUEST=None ):
+        """ Remove 'element' from our list of managed elements.
         """
-            Remove 'element' from our list of managed elements.
-        """
         del self.element_specs[ element ]
 
         if REQUEST is not None:
@@ -432,122 +347,276 @@
 
     security.declareProtected(ManagePortal, 'listPolicies')
     def listPolicies( self, typ=None ):
+        """ Show all policies for a given content type
+        
+        o If 'typ' is none, return the list of default policies.
         """
-            Show all policies for a given content type, or the default
-            if None.
-        """
         result = []
         for element, spec in self.listElementSpecs():
             result.append( ( element, spec.getPolicy( typ ) ) )
         return result
 
+InitializeClass(MetadataSchema)
+
+
+_DCMI_ELEMENT_SPECS = ( ( 'Title', 0 )
+                      , ( 'Description', 0 )
+                      , ( 'Subject', 1 )
+                      , ( 'Format', 0 )
+                      , ( 'Language', 0 )
+                      , ( 'Rights', 0 )
+                      )
+
+class MetadataTool( UniqueObject, Folder, ActionProviderBase ):
+
+    implements(IMetadataTool)
+    __implements__ = (z2IMetadataTool, ActionProviderBase.__implements__)
+
+    id = 'portal_metadata'
+    meta_type = 'Default Metadata Tool'
+    _actions = ()
+
+    _DCMI = None
+    def _get_DCMI( self ):
+
+        if self._DCMI is None:
+            dcmi = self._DCMI = MetadataSchema( 'DCMI', _DCMI_ELEMENT_SPECS )
+
+            old_specs = getattr( self, 'element_specs', None )
+            if old_specs is not None:
+                del self.element_specs
+                for element_id, old_spec in old_specs.items():
+                    new_spec = dcmi.getElementSpec( element_id )
+                    for typ, policy in old_spec.listPolicies():
+                        if typ is not None:
+                            new_spec.addPolicy( typ )
+                        tp = new_spec.getPolicy( typ )
+                        tp.edit( is_required=policy.isRequired()
+                               , supply_default=policy.supplyDefault()
+                               , default_value=policy.defaultValue()
+                               , enforce_vocabulary=policy.enforceVocabulary()
+                               , allowed_vocabulary=policy.allowedVocabulary()
+                               )
+
+        return self._DCMI
+
+    DCMI = property(_get_DCMI, None)
+
     #
-    #   'portal_metadata' interface
+    #   Default values.
     #
+    publisher           = ''
+
+    security = ClassSecurityInfo()
+
+    def __init__( self, publisher=None ):
+
+        self.editProperties( publisher )
+
+    #
+    #   ZMI methods
+    #
+    manage_options = ( ( { 'label'      : 'Schema'
+                         , 'action'     : 'propertiesForm'
+                         }
+                       , { 'label'      : 'Overview'
+                         , 'action'     : 'manage_overview'
+                         }
+                       )
+                     + Folder.manage_options[:1]
+                     + ActionProviderBase.manage_options +
+                       Folder.manage_options[1:]
+                     )
+
+    security.declareProtected(ManagePortal, 'manage_overview')
+    manage_overview = DTMLFile( 'explainMetadataTool', _dtmldir )
+
+    security.declareProtected(ManagePortal, 'propertiesForm')
+    propertiesForm = DTMLFile( 'metadataProperties', _dtmldir )
+
+    security.declareProtected(ManagePortal, 'editProperties')
+    def editProperties( self
+                      , publisher=None
+                      , REQUEST=None
+                      ):
+        """ Form handler for "tool-wide" properties 
+        """
+        if publisher is not None:
+            self.publisher = publisher
+
+        if REQUEST is not None:
+            REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
+                                        + '/propertiesForm'
+                                        + '?manage_tabs_message=Tool+updated.'
+                                        )
+
+    security.declareProtected(ManagePortal, 'manage_addSchema')
+    def manage_addSchema( self, schema_id, elements, REQUEST ):
+        """ ZMI wrapper around addSchema
+        """
+        massaged = []
+        for element in elements:
+            if isinstance(element, basestring):
+                element = element.split(',')
+                if len( element ) < 2:
+                    element.append(0)
+            massaged.append( element )
+        self.addSchema( schema_id, massaged )
+
+        REQUEST['RESPONSE'].redirect( self.absolute_url()
+                                    + '/propertiesForm'
+                                    + '?manage_tabs_message=Schema+added.'
+                                    )
+
+    security.declareProtected(ManagePortal, 'manage_removeSchemas')
+    def manage_removeSchemas( self, schema_ids, REQUEST ):
+        """ ZMI wrapper around removeSchema
+        """
+        if not schema_ids:
+            raise ValueError, 'No schemas selected!'
+
+        for schema_id in schema_ids:
+            self.removeSchema( schema_id )
+
+        REQUEST['RESPONSE'].redirect( self.absolute_url()
+                                    + '/propertiesForm'
+                                    + '?manage_tabs_message=Schemas+removed.'
+                                    )
+
     security.declarePrivate( 'getFullName' )
     def getFullName( self, userid ):
+        """ See IMetadataTool.
         """
-            Convert an internal userid to a "formal" name, if
-            possible, perhaps using the 'portal_membership' tool.
-
-            Used to map userid's for Creator, Contributor DCMI
-            queries.
-        """
         return userid   # TODO: do lookup here
 
     security.declarePublic( 'getPublisher' )
     def getPublisher( self ):
+        """ See IMetadataTool.
         """
-            Return the "formal" name of the publisher of the
-            portal.
-        """
         return self.publisher
 
-    security.declarePublic( 'listAllowedVocabulary' )
-    def listAllowedVocabulary( self, element, content=None, content_type=None ):
-        """
-            List allowed keywords for a given portal_type, or all
-            possible keywords if none supplied.
-        """
-        spec = self.getElementSpec( element )
-        if content_type is None and content:
-            content_type = content.getPortalTypeName()
-        return spec.getPolicy( content_type ).allowedVocabulary()
-
     security.declarePublic( 'listAllowedSubjects' )
     def listAllowedSubjects( self, content=None, content_type=None ):
+        """ See IMetadataTool.
         """
-            List allowed keywords for a given portal_type, or all
-            possible keywords if none supplied.
-        """
-        return self.listAllowedVocabulary( 'Subject', content, content_type )
+        return self.listAllowedVocabulary( 'DCMI'
+                                         , 'Subject'
+                                         , content
+                                         , content_type
+                                         )
 
     security.declarePublic( 'listAllowedFormats' )
     def listAllowedFormats( self, content=None, content_type=None ):
+        """ See IMetadataTool.
         """
-            List the allowed 'Content-type' values for a particular
-            portal_type, or all possible formats if none supplied.
-        """
-        return self.listAllowedVocabulary( 'Format', content, content_type )
+        return self.listAllowedVocabulary( 'DCMI'
+                                         , 'Format'
+                                         , content
+                                         , content_type
+                                         )
 
     security.declarePublic( 'listAllowedLanguages' )
     def listAllowedLanguages( self, content=None, content_type=None ):
+        """ See IMetadataTool.
         """
-            List the allowed language values.
-        """
-        return self.listAllowedVocabulary( 'Language', content, content_type )
+        return self.listAllowedVocabulary( 'DCMI'
+                                         , 'Language'
+                                         , content
+                                         , content_type
+                                         )
 
     security.declarePublic( 'listAllowedRights' )
     def listAllowedRights( self, content=None, content_type=None ):
+        """ See IMetadata Tool.
         """
-            List the allowed values for a "Rights"
-            selection list;  this gets especially important where
-            syndication is involved.
+        return self.listAllowedVocabulary( 'DCMI'
+                                         , 'Rights'
+                                         , content
+                                         , content_type
+                                         )
+
+    security.declarePublic( 'listAllowedVocabulary' )
+    def listAllowedVocabulary( self
+                             , schema
+                             , element
+                             , content=None
+                             , content_type=None
+                             ):
+        """ See IMetadataTool.
         """
-        return self.listAllowedVocabulary( 'Rights', content, content_type )
+        schema_def = getattr( self, schema )
+        spec = schema_def.getElementSpec( element )
+        if content_type is None and content:
+            content_type = content.getPortalTypeName()
+        return spec.getPolicy( content_type ).allowedVocabulary()
 
+    security.declarePublic( 'listSchemas' )
+    def listSchemas( self ):
+        """ See IMetadataTool.
+        """
+        result = [ ( 'DCMI', self.DCMI ) ]
+        result.extend( self.objectItems( [ MetadataSchema.meta_type ] ) )
+        return result
+
+    security.declareProtected(ModifyPortalContent, 'addSchema')
+    def addSchema( self, schema_id, elements=() ):
+        """ See IMetadataTool.
+        """
+        if schema_id == 'DCMI' or schema_id in self.objectIds():
+            raise KeyError, 'Duplicate schema ID: %s' % schema_id
+
+        schema = MetadataSchema( schema_id, elements )
+        self._setObject( schema_id, schema )
+
+        return self._getOb( schema_id )
+
+    security.declareProtected(ModifyPortalContent, 'removeSchema')
+    def removeSchema( self, schema_id ):
+        """ See IMetadataTool.
+        """
+        if schema_id == 'DCMI' or schema_id not in self.objectIds():
+            raise KeyError, 'Invalid schema ID: %s' % schema_id
+
+        self._delObject( schema_id )
+
     security.declareProtected(ModifyPortalContent, 'setInitialMetadata')
     def setInitialMetadata( self, content ):
+        """ See IMetadataTool.
         """
-            Set initial values for content metatdata, supplying
-            any site-specific defaults.
-        """
-        for element, policy in self.listPolicies(content.getPortalTypeName()):
+        for schema_id, schema in self.listSchemas():
+            for element, policy in schema.listPolicies(
+                                    content.getPortalTypeName()):
 
-            if not getattr( content, element )():
+                if not getattr( content, element )():
 
-                if policy.supplyDefault():
-                    setter = getattr( content, 'set%s' % element )
-                    setter( policy.defaultValue() )
-                elif policy.isRequired():
-                    raise MetadataError, \
-                          'Metadata element %s is required.' % element
+                    if policy.supplyDefault():
+                        setter = getattr( content, 'set%s' % element )
+                        setter( policy.defaultValue() )
+                    elif policy.isRequired():
+                        raise MetadataError, \
+                            'Metadata element %s is required.' % element
 
         # TODO:  Call initial_values_hook, if present
 
     security.declareProtected(View, 'validateMetadata')
     def validateMetadata( self, content ):
+        """ See IMetadataTool.
         """
-            Enforce portal-wide policies about DCI, e.g.,
-            requiring non-empty title/description, etc.  Called
-            by the CMF immediately before saving changes to the
-            metadata of an object.
-        """
-        for element, policy in self.listPolicies(content.getPortalTypeName()):
+        for schema_id, schema in self.listSchemas():
+            for element, policy in schema.listPolicies(
+                                    content.getPortalTypeName()):
 
-            value = getattr( content, element )()
-            if not value and policy.isRequired():
-                raise MetadataError, \
-                        'Metadata element %s is required.' % element
+                value = getattr( content, element )()
+                if not value and policy.isRequired():
+                    raise MetadataError, \
+                            'Metadata element %s is required.' % element
 
-            if value and policy.enforceVocabulary():
-                values = policy.isMultiValued() and value or [ value ]
-                for value in values:
-                    if not value in policy.allowedVocabulary():
-                        raise MetadataError, \
-                        'Value %s is not in allowed vocabulary for ' \
-                        'metadata element %s.' % ( value, element )
+                if value and policy.enforceVocabulary():
+                    values = policy.isMultiValued() and value or [ value ]
+                    for value in values:
+                        if not value in policy.allowedVocabulary():
+                            raise MetadataError, \
+                            'Value %s is not in allowed vocabulary for ' \
+                            'metadata element %s.' % ( value, element )
 
-        # TODO:  Call validation_hook, if present
-
 InitializeClass( MetadataTool )

Modified: CMF/branches/tseaver-viewification/CMFDefault/__init__.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/__init__.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/__init__.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -16,6 +16,7 @@
 """
 
 from Products.CMFCore.DirectoryView import registerDirectory
+from Products.CMFCore.interfaces import ISiteRoot
 from Products.CMFCore.utils import initializeBasesPhase1
 from Products.CMFCore.utils import initializeBasesPhase2
 from Products.CMFCore.utils import ToolInit
@@ -114,14 +115,18 @@
                                      'Profile for a default CMFSite.',
                                      'profiles/default',
                                      'CMFDefault',
-                                     BASE)
+                                     BASE,
+                                     for_=ISiteRoot,
+                                    )
 
     profile_registry.registerProfile('sample_content',
                                      'Sample CMFDefault Content',
                                      'Content for a sample CMFSite.',
                                      'profiles/sample_content',
                                      'CMFDefault',
-                                     EXTENSION)
+                                     EXTENSION,
+                                     for_=ISiteRoot,
+                                    )
 
     context.registerClass( Portal.CMFSite
                          , constructors=(factory.addConfiguredSiteForm,

Modified: CMF/branches/tseaver-viewification/CMFDefault/browser/tests/linkviews.txt
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/browser/tests/linkviews.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/browser/tests/linkviews.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -7,6 +7,8 @@
 First, let's create a "dummy" link class, to avoid dependencies on the
 actual content object.
 
+  >>> from zope.app.tests.placelesssetup import setUp, tearDown
+  >>> setUp()
   >>> from Products.CMFDefault.interfaces import ILink
   >>> class FauxLink:
   ...     def __init__(self, remote_url, title):
@@ -83,3 +85,6 @@
   >>> print response._redirected
   http://example.com/path/to/link/edit.html?portal_status_message=Link%20updated.
 
+And clean up at the end:
+
+  >>> tearDown()

Modified: CMF/branches/tseaver-viewification/CMFDefault/dtml/metadataElementPolicies.dtml
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/dtml/metadataElementPolicies.dtml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/dtml/metadataElementPolicies.dtml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,9 +1,9 @@
 <dtml-var manage_page_header>
 <dtml-var manage_tabs>
 
-<dtml-unless expr="REQUEST.has_key( 'element' )">
-<dtml-call expr="REQUEST.set( 'element', listElementSpecs()[0][0] )">
-</dtml-unless>
+<dtml-let specs=listElementSpecs
+          def_spec="specs and specs[0][0] or None"
+          current="REQUEST.get( 'element', def_spec )">
 
 <h3> Update Element Metadata Policies </h3>
 
@@ -14,7 +14,7 @@
   <td colspan="3"> 
    <dtml-in listElementSpecs>
     <dtml-let key=sequence-key>
-     <dtml-if expr="key == REQUEST[ 'element' ]">
+     <dtml-if expr="key == current">
      &dtml-key;  &nbsp;
      <dtml-else>
       <a href="&dtml-URL;?element=&dtml-key;"> &dtml-key; </a> &nbsp;
@@ -24,14 +24,14 @@
   </td>
  </tr>
 
- <dtml-let spec="getElementSpec( element=REQUEST[ 'element' ] )"
+ <dtml-if def_spec>
+ <dtml-let spec="getElementSpec( element=current )"
            multi="spec.isMultiValued()"
            tokenz="multi and ':tokens' or ''"
  >
 
  <dtml-in expr="spec.listPolicies()" sort>
- <dtml-let element="REQUEST[ 'element']"
-           key=sequence-key
+ <dtml-let key=sequence-key
            typ="key or '<default>'"
            policy=sequence-item
            rqd="policy.isRequired() and 'checked' or ''"
@@ -44,7 +44,7 @@
  >
 
  <form action="&dtml-absolute_url;" method="POST">
- <input type="hidden" name="element" value="&dtml-element;"> 
+ <input type="hidden" name="element" value="&dtml-current;"> 
  <input type="hidden" name="content_type" value="&dtml-typ;"> 
 
  <tr style="background-color: DarkGray; color: DarkBlue">
@@ -110,7 +110,7 @@
  </dtml-in>
 
  <form action="&dtml-absolute_url;" method="POST">
- <input type="hidden" name="element" value="&dtml-element;"> 
+ <input type="hidden" name="element" value="&dtml-current;"> 
 
  <tr style="background-color: DarkGray; color: DarkBlue">
   <th colspan="4"> &lt;new type&gt; </th>
@@ -171,6 +171,9 @@
  </tr>
 
  </dtml-let>
+ </dtml-if>
 </table>
 
+</dtml-let>
+
 <dtml-var manage_page_footer>

Modified: CMF/branches/tseaver-viewification/CMFDefault/dtml/metadataProperties.dtml
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/dtml/metadataProperties.dtml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/dtml/metadataProperties.dtml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -20,54 +20,76 @@
 </table>
 </form>
 
-<h3> Add Metadata Element </h3>
+<h3> Metadata Schemas </h3>
 
-<form action="&dtml-absolute_url;/addElementSpec" method="POST">
-<input type="hidden" name="is_multi_valued:int:default" value="0">
+<form action="&dtml-absolute_url;" method="POST">
 <table>
 
+ <dtml-in listSchemas>
+ <dtml-if sequence-start>
+
  <tr valign="middle">
-  <th width="100" align="right"> Element: </th>
-  <td> <input type="text" name="element" size="20"> </td>
+  <td width="16">
+    <br /> <!-- can't remove DCMI schema! -->
+  </td>
+  <td>
+   <a href="&dtml-absolute_url;/manage_workspace">DCMI</a>
+  </td>
  </tr>
 
+ <dtml-else>
+
  <tr valign="middle">
-  <th width="100" align="right"> Multi-valued? </th>
-  <td> <input type="checkbox" name="is_multi_valued:boolean"> </td>
+  <td>
+   <input type="checkbox" name="schema_ids:list" value="&dtml-sequence-key;" />
+  </td>
+  <td>
+   <a href="&dtml-absolute_url;/manage_workspace"
+   > &dtml-sequence-key; </a>
+  </td>
  </tr>
 
+ </dtml-if>
+ </dtml-in>
+
  <tr valign="middle">
-  <td> <br> </td>
-  <td> <input type="submit" value=" Add "> </td>
+  <td colspan="2">
+    <input type="submit" name="manage_removeSchemas:method"
+        value=" Remove Schemas ">
+  </td>
  </tr>
-
 </table>
-</form>
 
-<h3> Remove Metadata Element </h3>
+<br />
 
-<form action="&dtml-absolute_url;/removeElementSpec" method="POST">
 <table>
 
- <tr valign="middle">
-  <th width="100" align="right"> Element: </th>
-  <td> <dtml-in listElementSpecs>
-       <dtml-if sequence-start>
-       <select name="element">
-       </dtml-if>
-       <option value="&dtml-sequence-key;"> &dtml-sequence-key; </option>
-       <dtml-if sequence-end>
-       </select>
-       </dtml-if>
-       </dtml-in>
+ <tr>
+  <th colspan="2"
+      style="background-color:#CCCCCC; color:#000088">
+   Add a Schema
+  </th>
+ <tr>
+  <th> Schema ID </th>
+  <td>
+    <input type="text" name="schema_id" size="20"><br />
   </td>
  </tr>
 
- <tr valign="middle">
-  <td> <br> </td>
-  <td> <input type="submit" value=" Remove "> </td>
+ <tr>
+  <th> Elements </th>
+  <td>
+    <textarea name="elements:lines" cols="30" rows="10"></textarea>
+  </td>
  </tr>
 
+ <tr>
+  <td> <br /> </td>
+  <td>
+    <input type="submit" name="manage_addSchema:method" value=" Add Schema ">
+  </td>
+ </tr>
+
 </table>
 </form>
 

Modified: CMF/branches/tseaver-viewification/CMFDefault/factory.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/factory.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/factory.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -17,6 +17,7 @@
 
 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
 
+from Products.CMFCore.interfaces import ISiteRoot
 from Products.CMFCore.utils import getToolByName
 from Products.GenericSetup import EXTENSION
 from Products.GenericSetup import profile_registry
@@ -36,7 +37,7 @@
     base_profiles = []
     extension_profiles = []
 
-    for info in profile_registry.listProfileInfo():
+    for info in profile_registry.listProfileInfo(for_=ISiteRoot):
         if info.get('type') == EXTENSION:
             extension_profiles.append(info)
         else:

Modified: CMF/branches/tseaver-viewification/CMFDefault/profiles/default/catalog.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/profiles/default/catalog.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/profiles/default/catalog.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,13 +1,13 @@
 <?xml version="1.0"?>
 <object name="portal_catalog" meta_type="CMF Catalog">
  <property name="title"></property>
- <object name="plaintext_lexicon" meta_type="ZCTextIndex Lexicon">
-  <element name="Whitespace splitter" group="Word Splitter"/>
+ <object name="htmltext_lexicon" meta_type="ZCTextIndex Lexicon">
+  <element name="HTML aware splitter" group="Word Splitter"/>
   <element name="Case Normalizer" group="Case Normalizer"/>
   <element name="Remove listed stop words only" group="Stop Words"/>
  </object>
- <object name="htmltext_lexicon" meta_type="ZCTextIndex Lexicon">
-  <element name="HTML aware splitter" group="Word Splitter"/>
+ <object name="plaintext_lexicon" meta_type="ZCTextIndex Lexicon">
+  <element name="Whitespace splitter" group="Word Splitter"/>
   <element name="Case Normalizer" group="Case Normalizer"/>
   <element name="Remove listed stop words only" group="Stop Words"/>
  </object>

Modified: CMF/branches/tseaver-viewification/CMFDefault/profiles/default/export_steps.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/profiles/default/export_steps.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/profiles/default/export_steps.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,37 +1,37 @@
 <?xml version="1.0"?>
 <export-steps>
  <export-step id="actions"
-              handler="Products.CMFSetup.actions.exportActionProviders"
+              handler="Products.CMFCore.exportimport.actions.exportActionProviders"
               title="Action Providers">
   Export actions tool's action providers and their actions.
  </export-step>
  <export-step id="caching_policy_mgr"
-              handler="Products.CMFSetup.cachingpolicymgr.exportCachingPolicyManager"
+              handler="Products.CMFCore.exportimport.cachingpolicymgr.exportCachingPolicyManager"
               title="Caching Policies">
   Export caching policy manager's policies.
  </export-step>
  <export-step id="catalog"
-              handler="Products.CMFSetup.catalog.exportCatalogTool"
+              handler="Products.CMFCore.exportimport.catalog.exportCatalogTool"
               title="Catalog Tool">
   Export catalog tool's sub-objects, indexes and columns.
  </export-step>
  <export-step id="content_type_registry"
-              handler="Products.CMFSetup.contenttyperegistry.exportContentTypeRegistry"
+              handler="Products.CMFCore.exportimport.contenttyperegistry.exportContentTypeRegistry"
               title="Content Type Registry">
   Export content type registry's predicates / bindings.
  </export-step>
  <export-step id="cookieauth"
-              handler="Products.CMFSetup.cookieauth.exportCookieCrumbler"
+              handler="Products.CMFCore.exportimport.cookieauth.exportCookieCrumbler"
               title="Cookie Authentication">
   Export cookie crumbler settings
  </export-step>
  <export-step id="mailhost"
-              handler="Products.CMFSetup.mailhost.exportMailHost"
+              handler="Products.CMFCore.exportimport.mailhost.exportMailHost"
               title="MailHost">
   Export the mailhost's settings and properties
  </export-step>
  <export-step id="properties"
-              handler="Products.CMFSetup.properties.exportSiteProperties"
+              handler="Products.CMFCore.exportimport.properties.exportSiteProperties"
               title="Site Properties">
   Export site properties.
  </export-step>
@@ -41,7 +41,7 @@
   Export custom roles and non-default role-permission mappings.
  </export-step>
  <export-step id="skins"
-              handler="Products.CMFSetup.skins.exportSkinsTool"
+              handler="Products.CMFCore.exportimport.skins.exportSkinsTool"
               title="Skins Tool">
   Export skins tool's filesystem directory views and skin path definitions.
  </export-step>
@@ -56,12 +56,12 @@
   Export required / forbidden tools.
  </export-step>
  <export-step id="typeinfo"
-              handler="Products.CMFSetup.typeinfo.exportTypesTool"
+              handler="Products.CMFCore.exportimport.typeinfo.exportTypesTool"
               title="Types Tool">
   Export types tool's type information objects.
  </export-step>
  <export-step id="workflows"
-              handler="Products.CMFSetup.workflow.exportWorkflowTool"
+              handler="Products.CMFCore.exportimport.workflow.exportWorkflowTool"
               title="Workflow Tool">
   Export workflow tool's workflow definitions and supporting scripts.
  </export-step>

Modified: CMF/branches/tseaver-viewification/CMFDefault/profiles/default/import_steps.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/profiles/default/import_steps.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/profiles/default/import_steps.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,45 +1,45 @@
 <?xml version="1.0"?>
 <import-steps>
  <import-step id="actions" version="20040630-01"
-              handler="Products.CMFSetup.actions.importActionProviders"
+              handler="Products.CMFCore.exportimport.actions.importActionProviders"
               title="Action Providers">
   <dependency step="toolset"/>
   Import actions tool's action providers and their actions.
  </import-step>
  <import-step id="caching_policy_mgr" version="20051011-01"
-              handler="Products.CMFSetup.cachingpolicymgr.importCachingPolicyManager"
+              handler="Products.CMFCore.exportimport.cachingpolicymgr.importCachingPolicyManager"
               title="Caching Policies">
   <dependency step="toolset"/>
   Import caching policy manager's policies.
  </import-step>
  <import-step id="catalog" version="20050929-01"
-              handler="Products.CMFSetup.catalog.importCatalogTool"
+              handler="Products.CMFCore.exportimport.catalog.importCatalogTool"
               title="Catalog Tool">
   <dependency step="toolset"/>
   Import catalog tool's sub-objects, indexes and columns.
  </import-step>
  <import-step id="content_type_registry"
               version="20051013-01"
-              handler="Products.CMFSetup.contenttyperegistry.importContentTypeRegistry"
+              handler="Products.CMFCore.exportimport.contenttyperegistry.importContentTypeRegistry"
               title="Content Type Registry">
   <dependency step="toolset"/>
   Import content type registry's predicates and bindings.
  </import-step>
  <import-step id="cookie_authentication"
               version="20050903-01"
-              handler="Products.CMFSetup.cookieauth.importCookieCrumbler"
+              handler="Products.CMFCore.exportimport.cookieauth.importCookieCrumbler"
               title="Cookie Authentication">
   <dependency step="toolset"/>
   Import cookie crumbler settings
  </import-step>
  <import-step id="mailhost" version="20050803-01"
-              handler="Products.CMFSetup.mailhost.importMailHost"
+              handler="Products.CMFCore.exportimport.mailhost.importMailHost"
               title="MailHost">
   <dependency step="toolset"/>
   Import mailhost settings
  </import-step>
  <import-step id="properties" version="20041215-01"
-              handler="Products.CMFSetup.properties.importSiteProperties"
+              handler="Products.CMFCore.exportimport.properties.importSiteProperties"
               title="Site Properties">
   Import site properties.
  </import-step>
@@ -49,7 +49,7 @@
   Import custom roles and non-default role-permission mappings.
  </import-step>
  <import-step id="skins" version="20040630-01"
-              handler="Products.CMFSetup.skins.importSkinsTool"
+              handler="Products.CMFCore.exportimport.skins.importSkinsTool"
               title="Skins Tool">
   <dependency step="toolset"/>
   Import skins tool's filesystem directory views and skin path definitions.
@@ -61,7 +61,7 @@
   forbidden ones.
  </import-step>
  <import-step id="typeinfo" version="20040630-01"
-              handler="Products.CMFSetup.typeinfo.importTypesTool"
+              handler="Products.CMFCore.exportimport.typeinfo.importTypesTool"
               title="Types Tool">
   <dependency step="toolset"/>
   Import types tool's type information objects.
@@ -73,10 +73,9 @@
   Import various settings from PortalGenerator.
  </import-step>
  <import-step id="workflow" version="20040630-01"
-              handler="Products.CMFSetup.workflow.importWorkflowTool"
+              handler="Products.CMFCore.exportimport.workflow.importWorkflowTool"
               title="Workflow Tool">
   <dependency step="toolset"/>
-  <dependency step="typeinfo"/>
   Import workflow tool's workflow definitions and supporting scripts.
  </import-step>
 </import-steps>

Copied: CMF/branches/tseaver-viewification/CMFDefault/profiles/default/skins (from rev 40492, CMF/trunk/CMFDefault/profiles/default/skins)

Modified: CMF/branches/tseaver-viewification/CMFDefault/profiles/default/skins.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/profiles/default/skins.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/profiles/default/skins.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,20 +1,21 @@
 <?xml version="1.0"?>
-<skins-tool default_skin="Basic"
-            request_varname="portal_skin" allow_any="0"
-            cookie_persistence="0">
- <skin-directory id="Images"
-                 directory="CMFDefault/skins/Images"/>
- <skin-directory id="zpt_content"
-                 directory="CMFDefault/skins/zpt_content"/>
- <skin-directory id="zpt_control"
-                 directory="CMFDefault/skins/zpt_control"/>
- <skin-directory id="zpt_generic"
-                 directory="CMFDefault/skins/zpt_generic"/>
- <skin-path id="Basic">
+<object name="portal_skins" meta_type="CMF Skins Tool" allow_any="False"
+   cookie_persistence="False" default_skin="Basic"
+   request_varname="portal_skin">
+ <object name="Images" meta_type="Filesystem Directory View"
+    directory="CMFDefault/skins/Images"/>
+ <object name="custom" meta_type="Folder"/>
+ <object name="zpt_content" meta_type="Filesystem Directory View"
+    directory="CMFDefault/skins/zpt_content"/>
+ <object name="zpt_control" meta_type="Filesystem Directory View"
+    directory="CMFDefault/skins/zpt_control"/>
+ <object name="zpt_generic" meta_type="Filesystem Directory View"
+    directory="CMFDefault/skins/zpt_generic"/>
+ <skin-path name="Basic">
   <layer name="custom"/>
   <layer name="zpt_content"/>
   <layer name="zpt_generic"/>
   <layer name="zpt_control"/>
   <layer name="Images"/>
  </skin-path>
-</skins-tool>
+</object>

Modified: CMF/branches/tseaver-viewification/CMFDefault/profiles/default/toolset.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/profiles/default/toolset.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/profiles/default/toolset.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -3,6 +3,8 @@
 
  <required tool_id="MailHost"
            class="Products.MailHost.MailHost.MailHost"/>
+ <required tool_id="acl_users"
+           class="AccessControl.User.UserFolder"/>
  <required tool_id="caching_policy_manager"
            class="Products.CMFCore.CachingPolicyManager.CachingPolicyManager"/>
  <required tool_id="content_type_registry"

Modified: CMF/branches/tseaver-viewification/CMFDefault/profiles/default/typestool.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/profiles/default/typestool.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/profiles/default/typestool.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,14 +1,13 @@
 <?xml version="1.0"?>
-<types-tool>
- <type id="CMF BTree Folder"
-       filename="types/CMF_BTree_Folder.xml"/>
- <type id="Discussion Item"
-       filename="types/Discussion_Item.xml"/>
- <type id="Document"/>
- <type id="Favorite"/>
- <type id="File"/>
- <type id="Folder"/>
- <type id="Image"/>
- <type id="Link"/>
- <type id="News Item" filename="types/News_Item.xml"/>
-</types-tool>
+<object name="portal_types" meta_type="CMF Types Tool">
+ <property name="title"></property>
+ <object name="CMF BTree Folder" meta_type="Factory-based Type Information"/>
+ <object name="Discussion Item" meta_type="Factory-based Type Information"/>
+ <object name="Document" meta_type="Factory-based Type Information"/>
+ <object name="Favorite" meta_type="Factory-based Type Information"/>
+ <object name="File" meta_type="Factory-based Type Information"/>
+ <object name="Folder" meta_type="Factory-based Type Information"/>
+ <object name="Image" meta_type="Factory-based Type Information"/>
+ <object name="Link" meta_type="Factory-based Type Information"/>
+ <object name="News Item" meta_type="Factory-based Type Information"/>
+</object>

Modified: CMF/branches/tseaver-viewification/CMFDefault/profiles/default/workflows.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/profiles/default/workflows.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/profiles/default/workflows.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,17 +1,12 @@
 <?xml version="1.0"?>
-<workflow-tool>
- <workflow workflow_id="default_workflow"
-           meta_type="Workflow"
-           filename="workflows/default_workflow/definition.xml"/>
+<object name="portal_workflow" meta_type="CMF Workflow Tool">
+ <property name="title"></property>
+ <object name="default_workflow" meta_type="Workflow"/>
  <bindings>
   <default>
    <bound-workflow workflow_id="default_workflow"/>
   </default>
-  <type type_id="CMF BTree Folder">
-
-  </type>
-  <type type_id="Folder">
-
-  </type>
+  <type type_id="CMF BTree Folder"/>
+  <type type_id="Folder"/>
  </bindings>
-</workflow-tool>
+</object>

Modified: CMF/branches/tseaver-viewification/CMFDefault/setuphandlers.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/setuphandlers.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/setuphandlers.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,8 +15,6 @@
 $Id$
 """
 
-from Products.CMFCore.utils import getToolByName
-
 from exceptions import BadRequest
 
 
@@ -28,15 +26,10 @@
     """
     site = context.getSite()
 
-    # add custom skin folder
-    stool = getToolByName(site, 'portal_skins')
     try:
-        stool.manage_addProduct['OFSP'].manage_addFolder(id='custom')
+        site.manage_addPortalFolder('Members')
     except BadRequest:
         return 'Various settings: Nothing to import.'
-
-    site.manage_addProduct['OFSP'].manage_addUserFolder()
-    site.manage_addPortalFolder('Members')
     site.Members.manage_addProduct['OFSP'].manage_addDTMLMethod('index_html',
                                         'Member list', '<dtml-return roster>')
 

Modified: CMF/branches/tseaver-viewification/CMFDefault/tests/test_DefaultWorkflow.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/tests/test_DefaultWorkflow.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/tests/test_DefaultWorkflow.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,37 +15,32 @@
 $Id$
 """
 
-from unittest import TestCase, TestSuite, makeSuite, main
+import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
 from Products.CMFCore.tests.base.dummy import DummyContent
 from Products.CMFCore.tests.base.dummy import DummySite
 from Products.CMFCore.tests.base.dummy import DummyTool
 from Products.CMFCore.tests.base.dummy import DummyUserFolder
 
-from Products.CMFCore.WorkflowTool import addWorkflowFactory
 from Products.CMFCore.WorkflowTool import WorkflowTool
 
-from Products.CMFDefault.MembershipTool import MembershipTool
-from Products.CMFDefault.DefaultWorkflow import DefaultWorkflowDefinition
 
-class DefaultWorkflowDefinitionTests(TestCase):
+class DefaultWorkflowDefinitionTests(unittest.TestCase):
 
     def setUp(self):
-
+        from Products.CMFDefault.DefaultWorkflow \
+                import DefaultWorkflowDefinition
         self.site = DummySite('site')
         self.site._setObject('portal_types', DummyTool())
         self.site._setObject('portal_workflow', WorkflowTool())
-        self.site._setObject('portal_membership', MembershipTool())
+        self.site._setObject('portal_membership', DummyTool())
         self.site._setObject('acl_users', DummyUserFolder())
 
-        addWorkflowFactory(DefaultWorkflowDefinition,
-                           id='default_workflow', title='default_workflow')
+        wftool = self.site.portal_workflow
+        wftool._setObject('wf', DefaultWorkflowDefinition('wf'))
+        wftool.setDefaultChain('wf')
 
-        self._constructDummyWorkflow()
-
     def test_z2interfaces(self):
         from Interface.Verify import verifyClass
         from Products.CMFCore.interfaces.portal_workflow \
@@ -63,12 +58,6 @@
 
         verifyClass(IWorkflowDefinition, DefaultWorkflowDefinition)
 
-    def _constructDummyWorkflow(self):
-
-        wftool = self.site.portal_workflow
-        wftool.manage_addWorkflow('default_workflow (default_workflow)', 'wf')
-        wftool.setDefaultChain('wf')
-
     def _getDummyWorkflow(self):
         wftool = self.site.portal_workflow
         return wftool.wf
@@ -92,10 +81,11 @@
 
     # XXX more tests...
 
+
 def test_suite():
-    return TestSuite((
-        makeSuite( DefaultWorkflowDefinitionTests ),
+    return unittest.TestSuite((
+        unittest.makeSuite(DefaultWorkflowDefinitionTests),
         ))
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Modified: CMF/branches/tseaver-viewification/CMFDefault/tests/test_DiscussionReply.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/tests/test_DiscussionReply.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/tests/test_DiscussionReply.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,16 +15,15 @@
 $Id$
 """
 
-from unittest import TestSuite, makeSuite, main
+import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
 import Products
 from AccessControl.SecurityManagement import newSecurityManager
 from AccessControl.SecurityManagement import noSecurityManager
 from Products.Five import zcml
 
+from Products.CMFCore.tests.base.testcase import _TRAVERSE_ZCML
 from Products.CMFCore.tests.base.testcase import PlacelessSetup
 from Products.CMFCore.tests.base.testcase import RequestTest
 
@@ -35,8 +34,11 @@
         PlacelessSetup.setUp(self)
         RequestTest.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('permissions.zcml', Products.Five)
         zcml.load_config('configure.zcml', Products.GenericSetup)
         zcml.load_config('configure.zcml', Products.CMFCore)
+        zcml.load_config('configure.zcml', Products.DCWorkflow)
+        zcml.load_string(_TRAVERSE_ZCML)
         try:
             factory = self.root.manage_addProduct['CMFDefault'].addConfiguredSite
             factory('cmf', 'CMFDefault:default', snapshot=False)
@@ -90,10 +92,10 @@
 
 
 def test_suite():
-    suite = TestSuite()
-    suite.addTest(makeSuite(DiscussionReplyTest))
-    suite.addTest(makeSuite(DiscussionReplyTestMember))
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(DiscussionReplyTest))
+    suite.addTest(unittest.makeSuite(DiscussionReplyTestMember))
     return suite
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Modified: CMF/branches/tseaver-viewification/CMFDefault/tests/test_Image.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/tests/test_Image.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/tests/test_Image.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -100,8 +100,10 @@
         PlacelessSetup.setUp(self)
         RequestTest.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('permissions.zcml', Products.Five)
         zcml.load_config('configure.zcml', Products.GenericSetup)
         zcml.load_config('configure.zcml', Products.CMFCore)
+        zcml.load_config('configure.zcml', Products.DCWorkflow)
         try:
             newSecurityManager(None, UnrestrictedUser('manager', '', ['Manager'], []))
             factory = self.root.manage_addProduct['CMFDefault'].addConfiguredSite

Modified: CMF/branches/tseaver-viewification/CMFDefault/tests/test_MetadataTool.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/tests/test_MetadataTool.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/tests/test_MetadataTool.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -14,118 +14,132 @@
 
 $Id$
 """
-
-from unittest import TestCase, TestSuite, makeSuite, main
+import unittest
 import Testing
 import Zope2
 Zope2.startup()
 
 from Acquisition import aq_base
 
-from Products.CMFDefault.DublinCore import DefaultDublinCoreImpl
-from Products.CMFDefault.exceptions import MetadataError
-from Products.CMFDefault.MetadataTool import DEFAULT_ELEMENT_SPECS
-from Products.CMFDefault.MetadataTool import ElementSpec
-from Products.CMFDefault.MetadataTool import MetadataElementPolicy
-from Products.CMFDefault.MetadataTool import MetadataTool
 
+class TestMetadataElementPolicy( unittest.TestCase ):
 
-class TestMetadataElementPolicy( TestCase ):
+    def _getTargetClass( self ):
+        from Products.CMFDefault.MetadataTool import MetadataElementPolicy
+        return MetadataElementPolicy
 
-    def setUp( self ):
-        self.sv_policy = MetadataElementPolicy( 0 )
-        self.mv_policy = MetadataElementPolicy( 1 )
+    def _makeOne( self, *args, **kw ):
+        return self._getTargetClass()( *args, **kw )
 
-    def tearDown( self ):
-        del self.sv_policy
-        del self.mv_policy
+    def test_empty_single_valued( self ):
+        sv_policy = self._makeOne( 0 )
+        self.failIf( sv_policy.isMultiValued() )
+        self.failIf( sv_policy.isRequired() )
+        self.failIf( sv_policy.supplyDefault() )
+        self.failIf( sv_policy.defaultValue() )
+        self.failIf( sv_policy.enforceVocabulary() )
+        self.failIf( sv_policy.allowedVocabulary() )
 
-    def test_emptySV( self ):
-        assert not self.sv_policy.isMultiValued()
-        assert not self.sv_policy.isRequired()
-        assert not self.sv_policy.supplyDefault()
-        assert not self.sv_policy.defaultValue()
-        assert not self.sv_policy.enforceVocabulary()
-        assert not self.sv_policy.allowedVocabulary()
+    def test_edit_single_valued( self ):
+        sv_policy = self._makeOne( 0 )
+        sv_policy.edit( 1, 1, 'xxx', 0, '' ) 
+        self.failIf( sv_policy.isMultiValued() )
+        self.failUnless( sv_policy.isRequired() )
+        self.failUnless( sv_policy.supplyDefault() )
+        self.assertEquals( sv_policy.defaultValue(), 'xxx' )
+        self.failIf( sv_policy.enforceVocabulary() )
+        self.failIf( sv_policy.allowedVocabulary() )
 
-    def test_editSV( self ):
-        self.sv_policy.edit( 1, 1, 'xxx', 0, '' )
-        assert not self.sv_policy.isMultiValued()
-        assert self.sv_policy.isRequired()
-        assert self.sv_policy.supplyDefault()
-        assert self.sv_policy.defaultValue() == 'xxx'
-        assert not self.sv_policy.enforceVocabulary()
-        assert not self.sv_policy.allowedVocabulary()
+    def test_empty_multi_valued( self ):
+        mv_policy = self._makeOne( 1 )
+        self.failUnless( mv_policy.isMultiValued() )
+        self.failIf( mv_policy.isRequired() )
+        self.failIf( mv_policy.supplyDefault() )
+        self.failIf( mv_policy.defaultValue() )
+        self.failIf( mv_policy.enforceVocabulary() )
+        self.failIf( mv_policy.allowedVocabulary() )
 
-    def test_emptyMV( self ):
-        assert self.mv_policy.isMultiValued()
-        assert not self.mv_policy.isRequired()
-        assert not self.mv_policy.supplyDefault()
-        assert not self.mv_policy.defaultValue()
-        assert not self.mv_policy.enforceVocabulary()
-        assert not self.mv_policy.allowedVocabulary()
+    def test_edit_multi_valued( self ):
+        mv_policy = self._makeOne( 1 )
+        mv_policy.edit( 1, 1, 'xxx', 1, ( 'xxx', 'yyy' ) )
+        self.failUnless( mv_policy.isMultiValued() )
+        self.failUnless( mv_policy.isRequired() )
+        self.failUnless( mv_policy.supplyDefault() )
+        self.assertEqual( mv_policy.defaultValue(), 'xxx' )
+        self.failUnless( mv_policy.enforceVocabulary() )
+        self.assertEqual( len( mv_policy.allowedVocabulary() ), 2 )
+        self.failUnless( 'xxx' in mv_policy.allowedVocabulary() )
+        self.failUnless( 'yyy' in mv_policy.allowedVocabulary() )
 
-    def test_editMV( self ):
-        self.mv_policy.edit( 1, 1, 'xxx', 1, ( 'xxx', 'yyy' ) )
-        assert self.mv_policy.isMultiValued()
-        assert self.mv_policy.isRequired()
-        assert self.mv_policy.supplyDefault()
-        assert self.mv_policy.defaultValue() == 'xxx'
-        assert self.mv_policy.enforceVocabulary()
-        assert len( self.mv_policy.allowedVocabulary() ) == 2
-        assert 'xxx' in self.mv_policy.allowedVocabulary()
-        assert 'yyy' in self.mv_policy.allowedVocabulary()
 
-class TestElementSpec( TestCase ):
+class TestElementSpec( unittest.TestCase ):
 
-    def setUp( self ):
-        self.sv_spec    = ElementSpec( 0 )
-        self.mv_spec    = ElementSpec( 1 )
+    def _getTargetClass( self ):
+        from Products.CMFDefault.MetadataTool import ElementSpec
+        return ElementSpec
 
-    def tearDown( self ):
-        del self.sv_spec
-        del self.mv_spec
+    def _makeOne( self, *args, **kw ):
+        return self._getTargetClass()( *args, **kw )
 
-    def test_empty( self ):
-        assert not self.sv_spec.isMultiValued()
-        assert self.sv_spec.getPolicy() == self.sv_spec.getPolicy( 'XYZ' )
-        policies = self.sv_spec.listPolicies()
-        assert len( policies ) == 1
-        assert policies[0][0] is None
+    def test_empty_single_valued( self ):
+        sv_spec = self._makeOne( 0 )
+        self.failIf( sv_spec.isMultiValued() )
+        self.assertEqual( sv_spec.getPolicy(), sv_spec.getPolicy( 'XYZ' ) )
+        policies = sv_spec.listPolicies()
+        self.assertEqual( len( policies ), 1 )
+        self.assertEqual( policies[0][0], None )
 
-        assert self.mv_spec.isMultiValued()
-        assert self.mv_spec.getPolicy() == self.mv_spec.getPolicy( 'XYZ' )
-        policies = self.mv_spec.listPolicies()
-        assert len( policies ) == 1
-        assert policies[0][0] is None
+    def test_empty_multi_valued( self ):
+        mv_spec = self._makeOne( 1 )
+        self.failUnless( mv_spec.isMultiValued() )
+        self.assertEqual( mv_spec.getPolicy(), mv_spec.getPolicy( 'XYZ' ) )
+        policies = mv_spec.listPolicies()
+        self.assertEqual( len( policies ), 1 )
+        self.assertEqual( policies[0][0], None )
 
 
-class Foo( DefaultDublinCoreImpl ):
 
-    description = title = language = format = rights = ''
-    subject = ()
+class TestMetadataSchema( unittest.TestCase ):
 
-    def __init__( self ):
-        pass # skip DDCI's default values
+    def _getTargetClass( self ):
+        from Products.CMFDefault.MetadataTool import MetadataSchema
+        return MetadataSchema
 
-    def getPortalTypeName( self ):
-        return 'Foo'
+    def _makeOne( self, *args, **kw ):
+        return self._getTargetClass()( *args, **kw )
 
 
-class Bar( Foo ):
+class TestMetadataTool( unittest.TestCase ):
 
-    def getPortalTypeName( self ):
-        return 'Bar'
+    def _getTargetClass( self ):
+        from Products.CMFDefault.MetadataTool import MetadataTool
+        return MetadataTool
 
+    def _makeOne( self, *args, **kw ):
+        return self._getTargetClass()( *args, **kw )
 
-class TestMetadataTool( TestCase ):
+    def _makeTestObjects( self ):
 
-    def setUp( self ):
-        self.tool = MetadataTool()
+        from Products.CMFDefault.DublinCore import DefaultDublinCoreImpl
+        class Foo( DefaultDublinCoreImpl ):
 
-    def tearDown( self ):
-        del self.tool
+            description = title = language = format = rights = ''
+            subject = ()
 
+            def __init__( self ):
+                pass # skip DDCI's default values
+
+            def getPortalTypeName( self ):
+                return 'Foo'
+
+
+        class Bar( Foo ):
+
+            def getPortalTypeName( self ):
+                return 'Bar'
+
+        return Foo(), Bar()
+
     def test_z2interfaces(self):
         from Interface.Verify import verifyClass
         from Products.CMFCore.interfaces.portal_actions \
@@ -133,89 +147,92 @@
         from Products.CMFCore.interfaces.portal_metadata \
                 import portal_metadata as IMetadataTool
 
-        verifyClass(IActionProvider, MetadataTool)
-        verifyClass(IMetadataTool, MetadataTool)
+        verifyClass(IActionProvider, self._getTargetClass())
+        verifyClass(IMetadataTool, self._getTargetClass())
 
     def test_z3interfaces(self):
         from zope.interface.verify import verifyClass
         from Products.CMFCore.interfaces import IActionProvider
         from Products.CMFCore.interfaces import IMetadataTool
 
-        verifyClass(IActionProvider, MetadataTool)
-        verifyClass(IMetadataTool, MetadataTool)
+        verifyClass(IActionProvider, self._getTargetClass())
+        verifyClass(IMetadataTool, self._getTargetClass())
 
     def test_empty( self ):
+        from Products.CMFDefault.MetadataTool import _DCMI_ELEMENT_SPECS
 
-        assert not self.tool.getPublisher()
-        assert self.tool.getFullName( 'foo' ) == 'foo'
+        tool = self._makeOne()
+        self.failIf( tool.getPublisher() )
+        self.assertEqual( tool.getFullName( 'foo' ), 'foo' )
 
-        specs = list( self.tool.listElementSpecs() )
-        defaults = list( DEFAULT_ELEMENT_SPECS )
+        dcmi = tool.DCMI
+        specs = list( dcmi.DCMI.listElementSpecs() )
+        defaults = list( _DCMI_ELEMENT_SPECS )
         specs.sort(); defaults.sort()
 
-        assert len( specs ) == len( defaults )
+        self.assertEqual( len( specs ), len( defaults ) )
         for i in range( len( specs ) ):
-            assert specs[i][0] == defaults[i][0]
-            assert specs[i][1].isMultiValued() == defaults[i][1]
+            self.assertEqual( specs[i][0], defaults[i][0] )
+            self.assertEqual( specs[i][1].isMultiValued(), defaults[i][1] )
             policies = specs[i][1].listPolicies()
-            assert len( policies ) == 1
-            assert policies[0][0] is None
+            self.assertEqual( len( policies ), 1 )
+            self.failUnless( policies[0][0] is None )
 
-        assert not self.tool.getElementSpec( 'Title'        ).isMultiValued()
-        assert not self.tool.getElementSpec( 'Description'  ).isMultiValued()
-        assert     self.tool.getElementSpec( 'Subject'      ).isMultiValued()
-        assert not self.tool.getElementSpec( 'Format'       ).isMultiValued()
-        assert not self.tool.getElementSpec( 'Language'     ).isMultiValued()
-        assert not self.tool.getElementSpec( 'Rights'       ).isMultiValued()
+        self.failIf( dcmi.getElementSpec( 'Title' ).isMultiValued() )
+        self.failIf( dcmi.getElementSpec( 'Description' ).isMultiValued() )
+        self.failUnless( dcmi.getElementSpec( 'Subject' ).isMultiValued() )
+        self.failIf( dcmi.getElementSpec( 'Format' ).isMultiValued() )
+        self.failIf( dcmi.getElementSpec( 'Language' ).isMultiValued() )
+        self.failIf( dcmi.getElementSpec( 'Rights' ).isMultiValued() )
 
         try:
-            dummy = self.tool.getElementSpec( 'Foo' )
+            dummy = dcmi.getElementSpec( 'Foo' )
         except KeyError:
             pass
         else:
-            assert 0, "Expected KeyError"
+            self.failUnless( 0, "Expected KeyError" )
 
-        assert not self.tool.listAllowedSubjects()
-        assert not self.tool.listAllowedFormats()
-        assert not self.tool.listAllowedLanguages()
-        assert not self.tool.listAllowedRights()
+        self.failIf( dcmi.listAllowedSubjects() )
+        self.failIf( dcmi.listAllowedFormats() )
+        self.failIf( dcmi.listAllowedLanguages() )
+        self.failIf( dcmi.listAllowedRights() )
 
-    def test_add( self ):
-        self.tool.addElementSpec( 'Rating', 1 )
-        assert len( self.tool.listElementSpecs() ) \
-            == len( DEFAULT_ELEMENT_SPECS ) + 1
-        rating = self.tool.getElementSpec( 'Rating' )
-        assert rating.isMultiValued()
+    def test_DCMI_addElementSpec( self ):
+        from Products.CMFDefault.MetadataTool import _DCMI_ELEMENT_SPECS
 
-    def test_remove( self ):
-        self.tool.removeElementSpec( 'Rights' )
+        tool = self._makeOne()
+        dcmi = tool.DCMI
+        dcmi.addElementSpec( 'Rating', 1 )
+        self.assertEqual( len( dcmi.listElementSpecs() )
+                        , len( _DCMI_ELEMENT_SPECS ) + 1 )
+        rating = dcmi.getElementSpec( 'Rating' )
+        self.failUnless( rating.isMultiValued() )
 
-        assert len( self.tool.listElementSpecs() ) \
-            == len( DEFAULT_ELEMENT_SPECS ) - 1
+    def test_DCMI_removeElementSpec( self ):
+        from Products.CMFDefault.MetadataTool import _DCMI_ELEMENT_SPECS
 
-        try:
-            dummy = self.tool.getElementSpec( 'Rights' )
-        except KeyError:
-            pass
-        else:
-            assert 0, "Expected KeyError"
+        tool = self._makeOne()
+        dcmi = tool.DCMI
+        dcmi.removeElementSpec( 'Rights' )
 
-        try:
-            self.tool.removeElementSpec( 'Foo' )
-        except KeyError:
-            pass
-        else:
-            assert 0, "Expected KeyError"
+        self.assertEqual( len( dcmi.listElementSpecs() )
+                        , len( _DCMI_ELEMENT_SPECS ) - 1
+                        )
 
+        self.assertRaises( KeyError, dcmi.getElementSpec, 'Rights' )
+        self.assertRaises( KeyError, dcmi.removeElementSpec, 'Foo' )
+
     def test_simplePolicies( self ):
 
-        tSpec = self.tool.getElementSpec( 'Title' )
+        tool = self._makeOne()
+        dcmi = tool.DCMI
+        tSpec = dcmi.getElementSpec( 'Title' )
 
         # Fetch default policy.
         tDef  = tSpec.getPolicy()
-        assert not tDef.isRequired()
-        assert not tDef.supplyDefault()
-        assert not tDef.defaultValue()
+        self.failIf( tDef.isRequired() )
+        self.failIf( tDef.supplyDefault() )
+        self.failIf( tDef.defaultValue() )
 
         # Fetch (default) policy for a type.
         tDoc  = tSpec.getPolicy( 'Document' )
@@ -223,40 +240,42 @@
 
         # Changing default changes policies found from there.
         tDef.edit( 1, 1, 'xyz', 0, () )
-        assert tDef.isRequired()
-        assert tDef.supplyDefault()
-        assert tDef.defaultValue() == 'xyz'
-        assert tDoc.isRequired()
-        assert tDoc.supplyDefault()
-        assert tDoc.defaultValue() == 'xyz'
+        self.failUnless( tDef.isRequired() )
+        self.failUnless( tDef.supplyDefault() )
+        self.assertEqual( tDef.defaultValue(), 'xyz' )
+        self.failUnless( tDoc.isRequired() )
+        self.failUnless( tDoc.supplyDefault() )
+        self.assertEqual( tDoc.defaultValue(), 'xyz' )
 
         tSpec.addPolicy( 'Document' )
-        assert len( tSpec.listPolicies() ) == 2
+        self.assertEqual( len( tSpec.listPolicies() ), 2 )
 
         tDoc  = tSpec.getPolicy( 'Document' )
         self.assertNotEqual(aq_base(tDoc), aq_base(tDef))
-        assert not tDoc.isRequired()
-        assert not tDoc.supplyDefault()
-        assert not tDoc.defaultValue()
+        self.failIf( tDoc.isRequired() )
+        self.failIf( tDoc.supplyDefault() )
+        self.failIf( tDoc.defaultValue() )
 
         tSpec.removePolicy( 'Document' )
         tDoc  = tSpec.getPolicy( 'Document' )
         self.assertEqual(aq_base(tDoc), aq_base(tDef))
-        assert tDoc.isRequired()
-        assert tDoc.supplyDefault()
-        assert tDoc.defaultValue() == 'xyz'
+        self.failUnless( tDoc.isRequired() )
+        self.failUnless( tDoc.supplyDefault() )
+        self.assertEqual( tDoc.defaultValue(), 'xyz' )
 
     def test_multiValuedPolicies( self ):
 
-        sSpec = self.tool.getElementSpec( 'Subject' )
+        tool = self._makeOne()
+        dcmi = tool.DCMI
+        sSpec = dcmi.getElementSpec( 'Subject' )
 
         # Fetch default policy.
         sDef  = sSpec.getPolicy()
-        assert not sDef.isRequired()
-        assert not sDef.supplyDefault()
-        assert not sDef.defaultValue()
-        assert not sDef.enforceVocabulary()
-        assert not sDef.allowedVocabulary()
+        self.failIf( sDef.isRequired() )
+        self.failIf( sDef.supplyDefault() )
+        self.failIf( sDef.defaultValue() )
+        self.failIf( sDef.enforceVocabulary() )
+        self.failIf( sDef.allowedVocabulary() )
 
         # Fetch (default) policy for a type.
         sDoc  = sSpec.getPolicy( 'Document' )
@@ -264,150 +283,266 @@
 
         # Changing default changes policies found from there.
         sDef.edit( 1, 1, 'xyz', 1, ( 'foo', 'bar' ) )
-        assert sDef.isRequired()
-        assert sDef.supplyDefault()
-        assert sDef.defaultValue() == 'xyz'
-        assert sDoc.isRequired()
-        assert sDoc.supplyDefault()
-        assert sDoc.defaultValue() == 'xyz'
-        assert sDef.enforceVocabulary()
-        assert len( sDef.allowedVocabulary() ) == 2
-        assert 'foo' in sDef.allowedVocabulary()
-        assert 'bar' in sDef.allowedVocabulary()
-        assert sDoc.enforceVocabulary()
-        assert len( sDoc.allowedVocabulary() ) == 2
-        assert 'foo' in sDoc.allowedVocabulary()
-        assert 'bar' in sDoc.allowedVocabulary()
+        self.failUnless( sDef.isRequired() )
+        self.failUnless( sDef.supplyDefault() )
+        self.assertEqual( sDef.defaultValue(), 'xyz' )
+        self.failUnless( sDoc.isRequired() )
+        self.failUnless( sDoc.supplyDefault() )
+        self.assertEqual( sDoc.defaultValue(), 'xyz' )
+        self.failUnless( sDef.enforceVocabulary() )
+        self.assertEqual( len( sDef.allowedVocabulary() ), 2 )
+        self.failUnless( 'foo' in sDef.allowedVocabulary() )
+        self.failUnless( 'bar' in sDef.allowedVocabulary() )
+        self.failUnless( sDoc.enforceVocabulary() )
+        self.assertEqual( len( sDoc.allowedVocabulary() ), 2 )
+        self.failUnless( 'foo' in sDoc.allowedVocabulary() )
+        self.failUnless( 'bar' in sDoc.allowedVocabulary() )
 
         sSpec.addPolicy( 'Document' )
-        assert len( sSpec.listPolicies() ) == 2
+        self.assertEqual( len( sSpec.listPolicies() ), 2 )
 
         sDoc  = sSpec.getPolicy( 'Document' )
         self.assertNotEqual(aq_base(sDoc), aq_base(sDef))
-        assert not sDoc.isRequired()
-        assert not sDoc.supplyDefault()
-        assert not sDoc.defaultValue()
-        assert not sDoc.enforceVocabulary()
-        assert not sDoc.allowedVocabulary()
+        self.failIf( sDoc.isRequired() )
+        self.failIf( sDoc.supplyDefault() )
+        self.failIf( sDoc.defaultValue() )
+        self.failIf( sDoc.enforceVocabulary() )
+        self.failIf( sDoc.allowedVocabulary() )
 
         sSpec.removePolicy( 'Document' )
         sDoc  = sSpec.getPolicy( 'Document' )
         self.assertEqual(aq_base(sDoc), aq_base(sDef))
-        assert sDoc.isRequired()
-        assert sDoc.supplyDefault()
-        assert sDoc.defaultValue() == 'xyz'
-        assert sDoc.enforceVocabulary()
-        assert len( sDoc.allowedVocabulary() ) == 2
-        assert 'foo' in sDoc.allowedVocabulary()
-        assert 'bar' in sDoc.allowedVocabulary()
+        self.failUnless( sDoc.isRequired() )
+        self.failUnless( sDoc.supplyDefault() )
+        self.assertEqual( sDoc.defaultValue(), 'xyz' )
+        self.failUnless( sDoc.enforceVocabulary() )
+        self.assertEqual( len( sDoc.allowedVocabulary() ), 2 )
+        self.failUnless( 'foo' in sDoc.allowedVocabulary() )
+        self.failUnless( 'bar' in sDoc.allowedVocabulary() )
 
     def test_vocabularies( self ):
-        fSpec   = self.tool.getElementSpec( 'Format' )
+        tool = self._makeOne()
+        dcmi = tool.DCMI
+        fSpec   = dcmi.getElementSpec( 'Format' )
         fDef    = fSpec.getPolicy()
         formats = ( 'text/plain', 'text/html' )
         fDef.edit( 0, 0, '', 0, ( 'text/plain', 'text/html' ) )
-        assert self.tool.listAllowedFormats() == formats
+        self.assertEqual( tool.listAllowedFormats(), formats )
 
-        foo = Foo()
-        assert self.tool.listAllowedFormats( foo ) == formats
+        foo, bar = self._makeTestObjects()
+
+        self.assertEqual( tool.listAllowedFormats( foo ), formats )
+
         fSpec.addPolicy( 'Foo' )
-        assert not self.tool.listAllowedFormats( foo )
+        self.failIf( tool.listAllowedFormats( foo ) )
+
         foo_formats = ( 'image/jpeg', 'image/gif', 'image/png' )
         fFoo        = fSpec.getPolicy( 'Foo' )
         fFoo.edit( 0, 0, '', 0, foo_formats )
-        assert self.tool.listAllowedFormats( foo ) == foo_formats
+        self.assertEqual( tool.listAllowedFormats( foo ), foo_formats )
 
-    def test_initialValues( self ):
-        foo = Foo()
-        assert not foo.Title()
-        assert not foo.Description()
-        assert not foo.Subject()
-        assert not foo.Format(), foo.Format()
-        assert not foo.Language()
-        assert not foo.Rights()
+    def test_initialValues_defaults( self ):
+        tool = self._makeOne()
+        foo, bar = self._makeTestObjects()
+        self.failIf( foo.Title() )
+        self.failIf( foo.Description() )
+        self.failIf( foo.Subject() )
+        self.failIf( foo.Format(), foo.Format() )
+        self.failIf( foo.Language() )
+        self.failIf( foo.Rights() )
 
-        self.tool.setInitialMetadata( foo )
-        assert not foo.Title()
-        assert not foo.Description()
-        assert not foo.Subject()
-        assert not foo.Format()
-        assert not foo.Language()
-        assert not foo.Rights()
+        tool.setInitialMetadata( foo )
+        self.failIf( foo.Title() )
+        self.failIf( foo.Description() )
+        self.failIf( foo.Subject() )
+        self.failIf( foo.Format() )
+        self.failIf( foo.Language() )
+        self.failIf( foo.Rights() )
 
+    def test_initialValues_implicit( self ):
         # Test default policy.
-        foo     = Foo()
-        fSpec   = self.tool.getElementSpec( 'Format' )
+        tool = self._makeOne()
+        dcmi = tool.DCMI
+        foo, bar = self._makeTestObjects()
+        fSpec   = dcmi.getElementSpec( 'Format' )
         fPolicy = fSpec.getPolicy()
         fPolicy.edit( 0, 1, 'text/plain', 0, () )
-        self.tool.setInitialMetadata( foo )
-        assert not foo.Title()
-        assert not foo.Description()
-        assert not foo.Subject()
-        assert foo.Format() == 'text/plain'
-        assert not foo.Language()
-        assert not foo.Rights()
+        tool.setInitialMetadata( foo )
+        self.failIf( foo.Title() )
+        self.failIf( foo.Description() )
+        self.failIf( foo.Subject() )
+        self.assertEqual( foo.Format(), 'text/plain' )
+        self.failIf( foo.Language() )
+        self.failIf( foo.Rights() )
 
+    def test_initialValues_explicit_raises_if_constraint_fails( self ):
+        from Products.CMFDefault.exceptions import MetadataError
+
         # Test type-specific policy.
-        foo     = Foo()
-        tSpec   = self.tool.getElementSpec( 'Title' )
+        tool = self._makeOne()
+        dcmi = tool.DCMI
+        foo, bar = self._makeTestObjects()
+        tSpec   = dcmi.getElementSpec( 'Title' )
         tSpec.addPolicy( 'Foo' )
         tPolicy = tSpec.getPolicy( foo.getPortalTypeName() )
         tPolicy.edit( 1, 0, '', 0, () )
 
-        try:
-            self.tool.setInitialMetadata( foo )
-        except MetadataError:
-            pass
-        else:
-            assert 0, "Expected MetadataError"
+        self.assertRaises( MetadataError, tool.setInitialMetadata, foo )
 
+    def test_initialValues_explicit_mutliple_types( self ):
+        from Products.CMFDefault.exceptions import MetadataError
+
+        tool = self._makeOne()
+        dcmi = tool.DCMI
+        foo, bar = self._makeTestObjects()
         foo.setTitle( 'Foo title' )
-        self.tool.setInitialMetadata( foo )
-        assert foo.Title() == 'Foo title'
-        assert not foo.Description()
-        assert not foo.Subject()
-        assert foo.Format() == 'text/plain'
-        assert not foo.Language()
-        assert not foo.Rights()
 
+        fSpec   = dcmi.getElementSpec( 'Format' )
+        fSpec.addPolicy( foo.getPortalTypeName() )
+        fPolicy = fSpec.getPolicy( foo.getPortalTypeName() )
+        fPolicy.edit( 0, 1, 'text/plain', 0, () )
+
+        tool.setInitialMetadata( foo )
+        self.assertEqual( foo.Title(), 'Foo title' )
+        self.failIf( foo.Description() )
+        self.failIf( foo.Subject() )
+        self.assertEqual( foo.Format(), 'text/plain' )
+        self.failIf( foo.Language() )
+        self.failIf( foo.Rights() )
+
         #   Ensure Foo's policy doesn't interfere with other types.
-        bar = Bar()
-        self.tool.setInitialMetadata( bar )
-        assert not bar.Title()
-        assert not bar.Description()
-        assert not bar.Subject()
-        assert bar.Format() == 'text/plain'
-        assert not bar.Language()
-        assert not bar.Rights()
+        tool.setInitialMetadata( bar )
+        self.failIf( bar.Title() )
+        self.failIf( bar.Description() )
+        self.failIf( bar.Subject() )
+        self.assertEqual( bar.Format(), '' )
+        self.failIf( bar.Language() )
+        self.failIf( bar.Rights() )
 
     def test_validation( self ):
+        from Products.CMFDefault.exceptions import MetadataError
 
-        foo = Foo()
-        self.tool.setInitialMetadata( foo )
-        self.tool.validateMetadata( foo )
+        tool = self._makeOne()
+        foo, bar = self._makeTestObjects()
+        tool.setInitialMetadata( foo )
+        tool.validateMetadata( foo )
 
-        tSpec   = self.tool.getElementSpec( 'Title' )
+        dcmi = tool.DCMI
+        tSpec   = dcmi.getElementSpec( 'Title' )
         tSpec.addPolicy( 'Foo' )
         tPolicy = tSpec.getPolicy( foo.getPortalTypeName() )
         tPolicy.edit( 1, 0, '', 0, () )
 
-        try:
-            self.tool.validateMetadata( foo )
-        except MetadataError:
-            pass
-        else:
-            assert 0, "Expected MetadataError"
+        self.assertRaises( MetadataError, tool.validateMetadata, foo )
 
         foo.setTitle( 'Foo title' )
-        self.tool.validateMetadata( foo )
+        tool.validateMetadata( foo )
 
+    def test_addSchema_normal( self ):
+        from Products.CMFDefault.MetadataTool import MetadataSchema
 
+        tool = self._makeOne()
+        before = tool.listSchemas()
+        self.assertEqual( len( before ), 1 )
+        self.assertEqual( before[0][0], 'DCMI' )
+        self.failUnless( isinstance( before[0][1], MetadataSchema ) )
+
+        tool.addSchema( 'Arbitrary' )
+
+        after = tool.listSchemas()
+        self.assertEqual( len( after ), 2 )
+        self.assertEqual( after[0][0], 'DCMI' )
+        self.failUnless( isinstance( after[0][1], MetadataSchema ) )
+        self.assertEqual( after[1][0], 'Arbitrary' )
+        self.failUnless( isinstance( after[1][1], MetadataSchema ) )
+
+    def test_addSchema_duplicate( self ):
+        tool = self._makeOne()
+        before = tool.listSchemas()
+        tool.addSchema( 'Arbitrary' )
+        self.assertRaises( KeyError, tool.addSchema, 'Arbitrary' )
+        self.assertRaises( KeyError, tool.addSchema, 'DCMI' )
+
+    def test_removeSchema_normal( self ):
+        tool = self._makeOne()
+        before = tool.listSchemas()
+        self.assertEqual( len( before ), 1 )
+        self.assertEqual( before[0][0], 'DCMI' )
+
+        tool.addSchema( 'Arbitrary' )
+        tool.addSchema( 'Beneficent' )
+        tool.addSchema( 'Grouchy' )
+
+        middle = tool.listSchemas()
+        self.assertEqual( len( middle ), 4 )
+        self.assertEqual( middle[0][0], 'DCMI' )
+        self.assertEqual( middle[1][0], 'Arbitrary' )
+        self.assertEqual( middle[2][0], 'Beneficent' )
+        self.assertEqual( middle[3][0], 'Grouchy' )
+
+        tool.removeSchema( 'Beneficent' )
+
+        after = tool.listSchemas()
+        self.assertEqual( len( after ), 3 )
+        self.assertEqual( after[0][0], 'DCMI' )
+        self.assertEqual( after[1][0], 'Arbitrary' )
+        self.assertEqual( after[2][0], 'Grouchy' )
+
+    def test_removeSchema_invalid( self ):
+        tool = self._makeOne()
+        self.assertRaises( KeyError, tool.removeSchema, 'DCMI' )
+        tool.addSchema( 'Arbitrary' )
+        tool.removeSchema( 'Arbitrary' )
+        self.assertRaises( KeyError, tool.removeSchema, 'Arbitrary' )
+
+    def test_migration( self ):
+        # Test that we forward-migrate old-style DCMI policies.
+        from Products.CMFDefault.MetadataTool import ElementSpec
+        from Products.CMFDefault.MetadataTool import _DCMI_ELEMENT_SPECS
+
+        tool = self._makeOne()
+        tool.element_specs = { 'Title' : ElementSpec( 0 )
+                             , 'Description' : ElementSpec( 0 )
+                             , 'Subject' : ElementSpec( 1 )
+                             , 'Format' : ElementSpec( 0 )
+                             , 'Language' : ElementSpec( 0 )
+                             , 'Rights' : ElementSpec( 0 )
+                             }
+        subj = tool.element_specs[ 'Subject' ]
+        subj.addPolicy( 'Foo' )
+        subj.getPolicy( 'Foo' ).edit( False
+                                    , False
+                                    , None
+                                    , True
+                                    , ( 'bar', 'baz' )
+                                    )
+
+        dcmi = tool.DCMI
+
+        self.assertEqual( dcmi.getId(), 'DCMI' )
+
+        # Accessing the DCMI property converts and clears 'element_specs'
+        self.assertRaises(AttributeError, lambda: tool.element_specs )
+
+        subj2 = dcmi.getElementSpec( 'Subject' )
+        subj_default = subj2.getPolicy( None )
+        subj_foo = subj2.getPolicy( 'Foo' )
+
+        self.assertEqual( subj_foo.isRequired(), False )
+        self.assertEqual( subj_foo.supplyDefault(), False )
+        self.assertEqual( subj_foo.defaultValue(), None )
+        self.assertEqual( subj_foo.enforceVocabulary(), True )
+        self.assertEqual( len( subj_foo.allowedVocabulary() ), 2 )
+        self.failUnless( 'bar' in subj_foo.allowedVocabulary() )
+        self.failUnless( 'baz' in subj_foo.allowedVocabulary() )
+
+
 def test_suite():
-    return TestSuite((
-        makeSuite(TestMetadataElementPolicy),
-        makeSuite(TestElementSpec),
-        makeSuite(TestMetadataTool),
+    return unittest.TestSuite((
+        unittest.makeSuite(TestMetadataElementPolicy),
+        unittest.makeSuite(TestElementSpec),
+        unittest.makeSuite(TestMetadataTool),
         ))
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Modified: CMF/branches/tseaver-viewification/CMFDefault/tests/test_Portal.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/tests/test_Portal.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/tests/test_Portal.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,10 +15,8 @@
 $Id$
 """
 
-from unittest import TestSuite, makeSuite, main
+import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
 import Products
 from Acquisition import aq_base
@@ -51,8 +49,10 @@
         PlacelessSetup.setUp(self)
         SecurityRequestTest.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('permissions.zcml', Products.Five)
         zcml.load_config('configure.zcml', Products.GenericSetup)
         zcml.load_config('configure.zcml', Products.CMFCore)
+        zcml.load_config('configure.zcml', Products.DCWorkflow)
 
     def tearDown(self):
         SecurityRequestTest.tearDown(self)
@@ -207,9 +207,9 @@
 
 
 def test_suite():
-    return TestSuite((
-        makeSuite(CMFSiteTests),
+    return unittest.TestSuite((
+        unittest.makeSuite(CMFSiteTests),
         ))
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Modified: CMF/branches/tseaver-viewification/CMFDefault/tests/test_join.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFDefault/tests/test_join.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFDefault/tests/test_join.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,16 +15,31 @@
 $Id$
 """
 
-from unittest import TestSuite, makeSuite, main
+import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
+import Products
+from Products.Five import zcml
+
+from Products.CMFCore.tests.base.testcase import PlacelessSetup
 from Products.CMFCore.tests.base.testcase import TransactionalTest
 
 
-class MembershipTests( TransactionalTest ):
+class MembershipTests(PlacelessSetup, TransactionalTest):
 
+    def setUp(self):
+        PlacelessSetup.setUp(self)
+        TransactionalTest.setUp(self)
+        zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('permissions.zcml', Products.Five)
+        zcml.load_config('configure.zcml', Products.GenericSetup)
+        zcml.load_config('configure.zcml', Products.CMFCore)
+        zcml.load_config('configure.zcml', Products.DCWorkflow)
+
+    def tearDown(self):
+        TransactionalTest.tearDown(self)
+        PlacelessSetup.tearDown(self)
+
     def _makePortal(self):
         # Create a portal instance suitable for testing
         factory = self.root.manage_addProduct['CMFDefault'].addConfiguredSite
@@ -101,9 +116,9 @@
 
 
 def test_suite():
-    return TestSuite((
-        makeSuite(MembershipTests),
+    return unittest.TestSuite((
+        unittest.makeSuite(MembershipTests),
         ))
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Modified: CMF/branches/tseaver-viewification/CMFTopic/DEPENDENCIES.txt
===================================================================
--- CMF/branches/tseaver-viewification/CMFTopic/DEPENDENCIES.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFTopic/DEPENDENCIES.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,4 +1,4 @@
-Zope >= 2.8.2
+Zope >= 2.8.5
 Five >= 1.2
 CMFCore
 CMFDefault

Modified: CMF/branches/tseaver-viewification/CMFTopic/Topic.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFTopic/Topic.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFTopic/Topic.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -21,12 +21,19 @@
 
 from Products.CMFDefault.SkinnedFolder import SkinnedFolder
 from Products.CMFCore.utils import getToolByName
+from zope.interface import Interface
+from zope.interface import implements
+from zope.interface import implementedBy
 
 from permissions import View
 from permissions import AddTopics
 from permissions import ChangeTopics
 
 
+class ITopic(Interface):
+    """ Marker interface.
+    """
+
 def addTopic( self, id, title='', REQUEST=None ):
     """ Create an empty topic.
     """
@@ -46,7 +53,7 @@
     o Each topic holds a set of zero or more Criteria objects specifying
       the query.
     """
-
+    implements(ITopic, implementedBy(SkinnedFolder))
     meta_type='Portal Topic'
 
     security = ClassSecurityInfo()

Modified: CMF/branches/tseaver-viewification/CMFTopic/__init__.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFTopic/__init__.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFTopic/__init__.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -19,6 +19,7 @@
 
 from ZClasses import createZClassForBase
 
+from Products.CMFCore.interfaces import ISiteRoot
 from Products.CMFCore.utils import ContentInit
 from Products.CMFCore.DirectoryView import registerDirectory
 from Products.GenericSetup import EXTENSION
@@ -64,4 +65,6 @@
                                      'Adds topic portal type.',
                                      'profiles/default',
                                      'CMFTopic',
-                                     EXTENSION)
+                                     EXTENSION,
+                                     for_=ISiteRoot,
+                                    )

Copied: CMF/branches/tseaver-viewification/CMFTopic/configure.zcml (from rev 40492, CMF/trunk/CMFTopic/configure.zcml)

Copied: CMF/branches/tseaver-viewification/CMFTopic/exportimport.py (from rev 40492, CMF/trunk/CMFTopic/exportimport.py)

Modified: CMF/branches/tseaver-viewification/CMFTopic/profiles/default/skins.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFTopic/profiles/default/skins.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFTopic/profiles/default/skins.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,8 +1,8 @@
 <?xml version="1.0"?>
-<skins-tool>
- <skin-directory id="zpt_topic"
-                 directory="CMFTopic/skins/zpt_topic"/>
- <skin-path id="*">
+<object name="portal_skins" meta_type="CMF Skins Tool">
+ <object name="zpt_topic" meta_type="Filesystem Directory View"
+    directory="CMFTopic/skins/zpt_topic"/>
+ <skin-path name="*">
   <layer name="zpt_topic" insert-before="zpt_content"/>
  </skin-path>
-</skins-tool>
+</object>

Modified: CMF/branches/tseaver-viewification/CMFTopic/profiles/default/typestool.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFTopic/profiles/default/typestool.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFTopic/profiles/default/typestool.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,4 +1,4 @@
 <?xml version="1.0"?>
-<types-tool>
- <type id="Topic"/>
-</types-tool>
+<object name="portal_types" meta_type="CMF Types Tool">
+ <object name="Topic" meta_type="Factory-based Type Information"/>
+</object>

Modified: CMF/branches/tseaver-viewification/CMFTopic/profiles/default/workflows.xml
===================================================================
--- CMF/branches/tseaver-viewification/CMFTopic/profiles/default/workflows.xml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFTopic/profiles/default/workflows.xml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,8 +1,6 @@
 <?xml version="1.0"?>
-<workflow-tool>
+<object name="portal_workflow" meta_type="CMF Workflow Tool">
  <bindings>
-  <type type_id="Topic">
-
-  </type>
+  <type type_id="Topic"/>
  </bindings>
-</workflow-tool>
+</object>

Modified: CMF/branches/tseaver-viewification/CMFTopic/tests/test_DateC.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFTopic/tests/test_DateC.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFTopic/tests/test_DateC.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,17 +15,17 @@
 $Id$
 """
 
-from unittest import TestSuite, makeSuite, main
+import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
 import Products
 from DateTime.DateTime import DateTime
+
 from Products.CMFCore.tests.base.testcase import PlacelessSetup
 from Products.CMFCore.tests.base.testcase import RequestTest
 from Products.CMFCore.tests.base.dummy import DummyContent
 from Products.CMFTopic.Topic import Topic
+
 from common import CriterionTestCase
 
 
@@ -165,8 +165,10 @@
         PlacelessSetup.setUp(self)
         RequestTest.setUp(self)
         zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('permissions.zcml', Products.Five)
         zcml.load_config('configure.zcml', Products.GenericSetup)
         zcml.load_config('configure.zcml', Products.CMFCore)
+        zcml.load_config('configure.zcml', Products.DCWorkflow)
 
         factory = self.root.manage_addProduct['CMFDefault'].addConfiguredSite
         factory('site', 'CMFDefault:default', snapshot=False)
@@ -384,10 +386,10 @@
 
 
 def test_suite():
-    return TestSuite((
-        makeSuite(FriendlyDateCriterionTests),
-        makeSuite(FriendlyDateCriterionFunctionalTests),
+    return unittest.TestSuite((
+        unittest.makeSuite(FriendlyDateCriterionTests),
+        unittest.makeSuite(FriendlyDateCriterionFunctionalTests),
         ))
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Copied: CMF/branches/tseaver-viewification/CMFTopic/tests/test_exportimport.py (from rev 40492, CMF/trunk/CMFTopic/tests/test_exportimport.py)

Copied: CMF/branches/tseaver-viewification/CMFTopic/xml (from rev 40492, CMF/trunk/CMFTopic/xml)

Modified: CMF/branches/tseaver-viewification/CMFUid/DEPENDENCIES.txt
===================================================================
--- CMF/branches/tseaver-viewification/CMFUid/DEPENDENCIES.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFUid/DEPENDENCIES.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,4 +1,4 @@
-Zope >= 2.8.2
+Zope >= 2.8.5
 Five >= 1.2
 CMFCore
 GenericSetup

Modified: CMF/branches/tseaver-viewification/CMFUid/__init__.py
===================================================================
--- CMF/branches/tseaver-viewification/CMFUid/__init__.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/CMFUid/__init__.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -18,6 +18,7 @@
 from sys import modules
 
 from Products.CMFCore import utils
+from Products.CMFCore.interfaces import ISiteRoot
 from Products.GenericSetup import EXTENSION
 from Products.GenericSetup import profile_registry
 
@@ -51,4 +52,6 @@
                                      'Adds UID support.',
                                      'profiles/default',
                                      'CMFUid',
-                                     EXTENSION)
+                                     EXTENSION,
+                                     for_=ISiteRoot,
+                                    )

Modified: CMF/branches/tseaver-viewification/DCWorkflow/DCWorkflow.py
===================================================================
--- CMF/branches/tseaver-viewification/DCWorkflow/DCWorkflow.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/DCWorkflow/DCWorkflow.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -35,9 +35,9 @@
 from Products.CMFCore.WorkflowCore import ObjectDeleted
 from Products.CMFCore.WorkflowCore import ObjectMoved
 from Products.CMFCore.WorkflowCore import WorkflowException
-from Products.CMFCore.WorkflowTool import addWorkflowFactory
 
 # DCWorkflow
+from interfaces import IDCWorkflowDefinition
 from permissions import ManagePortal
 from utils import modifyRolesForPermission
 from utils import modifyRolesForGroup
@@ -63,10 +63,9 @@
     UI methods are in WorkflowUIMixin.
     '''
 
-    implements(IWorkflowDefinition)
+    implements(IDCWorkflowDefinition, IWorkflowDefinition)
     __implements__ = z2IWorkflowDefinition
 
-    meta_type = 'Workflow'
     title = 'DC Workflow Definition'
     _isAWorkflow = 1
 
@@ -414,7 +413,7 @@
                     tdef = t
                     break
         return tdef
-        
+
     def _changeStateOf(self, ob, tdef=None, kwargs=None):
         '''
         Changes state.  Can execute multiple transitions if there are
@@ -537,7 +536,3 @@
             return new_sdef
 
 InitializeClass(DCWorkflowDefinition)
-
-
-addWorkflowFactory(DCWorkflowDefinition, id='dc_workflow',
-                   title='Web-configurable workflow')

Modified: CMF/branches/tseaver-viewification/DCWorkflow/DEPENDENCIES.txt
===================================================================
--- CMF/branches/tseaver-viewification/DCWorkflow/DEPENDENCIES.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/DCWorkflow/DEPENDENCIES.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,3 +1,4 @@
-Zope >= 2.8.2
+Zope >= 2.8.5
 Five >= 1.2
 CMFCore
+GenericSetup

Deleted: CMF/branches/tseaver-viewification/DCWorkflow/Default.py
===================================================================
--- CMF/branches/tseaver-viewification/DCWorkflow/Default.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/DCWorkflow/Default.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,321 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (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.
-#
-##############################################################################
-""" Programmatically creates a workflow.
-
-$Id$
-"""
-
-from Products.CMFCore.WorkflowTool import addWorkflowFactory
-
-from DCWorkflow import DCWorkflowDefinition
-from permissions import AccessContentsInformation
-from permissions import ModifyPortalContent
-from permissions import RequestReview
-from permissions import ReviewPortalContent
-from permissions import View
-
-p_access = AccessContentsInformation
-p_modify = ModifyPortalContent
-p_request = RequestReview
-p_review = ReviewPortalContent
-p_view = View
-
-r_anon = 'Anonymous'
-r_manager = 'Manager'
-r_reviewer = 'Reviewer'
-r_owner = 'Owner'
-r_member = 'Member'
-
-
-
-def setupDefaultWorkflowRev2(wf):
-    '''
-    Sets up a DCWorkflow with the addition of a visible state,
-    the show and hide transitions, and corresponding changes.
-    wf is a DCWorkflow instance.
-    '''
-    wf.setProperties(title='CMF default workflow [Revision 2]')
-
-    for s in ('private', 'visible', 'pending', 'published'):
-        wf.states.addState(s)
-    for t in ('publish', 'reject', 'retract', 'submit', 'hide', 'show'):
-        wf.transitions.addTransition(t)
-    for v in ('action', 'actor', 'comments', 'review_history', 'time'):
-        wf.variables.addVariable(v)
-    for l in ('reviewer_queue',):
-        wf.worklists.addWorklist(l)
-    for p in (p_access, p_modify, p_view):
-        wf.addManagedPermission(p)
-
-    wf.states.setInitialState('visible')
-
-    sdef = wf.states['private']
-    sdef.setProperties(
-        title='Visible and editable only by owner',
-        transitions=('show',))
-    sdef.setPermission(p_access, 0, (r_manager, r_owner))
-    sdef.setPermission(p_view, 0, (r_manager, r_owner))
-    sdef.setPermission(p_modify, 0, (r_manager, r_owner))
-
-    sdef = wf.states['pending']
-    sdef.setProperties(
-        title='Waiting for reviewer',
-        transitions=('hide', 'publish', 'reject', 'retract',))
-    sdef.setPermission(p_access, 1, (r_manager, r_owner, r_reviewer))
-    sdef.setPermission(p_view, 1, (r_manager, r_owner, r_reviewer))
-    sdef.setPermission(p_modify, 0, (r_manager, r_reviewer))
-
-    sdef = wf.states['published']
-    sdef.setProperties(
-        title='Public',
-        transitions=('reject', 'retract',))
-    sdef.setPermission(p_access, 1, (r_anon, r_manager))
-    sdef.setPermission(p_view, 1, (r_anon, r_manager))
-    sdef.setPermission(p_modify, 0, (r_manager,))
-
-    sdef = wf.states['visible']
-    sdef.setProperties(
-        title='Visible but not published',
-        transitions=('hide', 'publish', 'submit',))
-    sdef.setPermission(p_access, 1, (r_anon, r_manager, r_reviewer))
-    sdef.setPermission(p_view, 1, (r_anon, r_manager, r_reviewer))
-    sdef.setPermission(p_modify, 0, (r_manager, r_owner))
-
-    tdef = wf.transitions['hide']
-    tdef.setProperties(
-        title='Member makes content private',
-        new_state_id='private',
-        actbox_name='Make private',
-        actbox_url='%(content_url)s/content_hide_form',
-        props={'guard_roles':r_owner})
-
-    tdef = wf.transitions['publish']
-    tdef.setProperties(
-        title='Reviewer publishes content',
-        new_state_id='published',
-        actbox_name='Publish',
-        actbox_url='%(content_url)s/content_publish_form',
-        props={'guard_permissions':p_review})
-
-    tdef = wf.transitions['reject']
-    tdef.setProperties(
-        title='Reviewer rejects submission',
-        new_state_id='visible',
-        actbox_name='Reject',
-        actbox_url='%(content_url)s/content_reject_form',
-        props={'guard_permissions':p_review})
-
-    tdef = wf.transitions['retract']
-    tdef.setProperties(
-        title='Member retracts submission',
-        new_state_id='visible',
-        actbox_name='Retract',
-        actbox_url='%(content_url)s/content_retract_form',
-        props={'guard_permissions':p_request})
-
-    tdef = wf.transitions['show']
-    tdef.setProperties(
-        title='Member makes content visible',
-        new_state_id='visible',
-        actbox_name='Make visible',
-        actbox_url='%(content_url)s/content_show_form',
-        props={'guard_roles':r_owner})
-
-    tdef = wf.transitions['submit']
-    tdef.setProperties(
-        title='Member requests publishing',
-        new_state_id='pending',
-        actbox_name='Submit',
-        actbox_url='%(content_url)s/content_submit_form',
-        props={'guard_permissions':p_request})
-
-    wf.variables.setStateVar('review_state')
-
-    vdef = wf.variables['action']
-    vdef.setProperties(description='The last transition',
-                       default_expr='transition/getId|nothing',
-                       for_status=1, update_always=1)
-
-    vdef = wf.variables['actor']
-    vdef.setProperties(description='The ID of the user who performed '
-                       'the last transition',
-                       default_expr='user/getId',
-                       for_status=1, update_always=1)
-
-    vdef = wf.variables['comments']
-    vdef.setProperties(description='Comments about the last transition',
-                       default_expr="python:state_change.kwargs.get('comment', '')",
-                       for_status=1, update_always=1)
-
-    vdef = wf.variables['review_history']
-    vdef.setProperties(description='Provides access to workflow history',
-                       default_expr="state_change/getHistory",
-                       props={'guard_permissions':
-                              p_request + ';' + p_review})
-
-    vdef = wf.variables['time']
-    vdef.setProperties(description='Time of the last transition',
-                       default_expr="state_change/getDateTime",
-                       for_status=1, update_always=1)
-
-    ldef = wf.worklists['reviewer_queue']
-    ldef.setProperties(description='Reviewer tasks',
-                       actbox_name='Pending (%(count)d)',
-                       actbox_url='%(portal_url)s/search?review_state=pending',
-                       props={'var_match_review_state':'pending',
-                              'guard_permissions':p_review})
-    
-
-def createDefaultWorkflowRev2(id):
-    '''
-    '''
-    ob = DCWorkflowDefinition(id)
-    setupDefaultWorkflowRev2(ob)
-    return ob
-
-addWorkflowFactory(createDefaultWorkflowRev2, id='default_workflow',
-                   title='Web-configurable workflow [Revision 2]')
-
-
-
-
-
-
-
-
-
-def setupDefaultWorkflowClassic(wf):
-    '''
-    Sets up a DCWorkflow as close as possible to the old DefaultWorkflow,
-    with only the private, pending, and published states.
-    wf is a DCWorkflow instance.
-    '''
-    wf.setProperties(title='CMF default workflow [Classic]')
-
-    for s in ('private', 'pending', 'published'):
-        wf.states.addState(s)
-    for t in ('publish', 'reject', 'retract', 'submit'):
-        wf.transitions.addTransition(t)
-    for v in ('action', 'actor', 'comments', 'review_history', 'time'):
-        wf.variables.addVariable(v)
-    for l in ('reviewer_queue',):
-        wf.worklists.addWorklist(l)
-    for p in (p_access, p_modify, p_view):
-        wf.addManagedPermission(p)
-
-    wf.states.setInitialState('private')
-
-    sdef = wf.states['private']
-    sdef.setProperties(
-        title='Non-visible and editable only by owner',
-        transitions=('submit', 'publish',))
-    sdef.setPermission(p_access, 0, (r_manager, r_owner))
-    sdef.setPermission(p_view, 0, (r_manager, r_owner))
-    sdef.setPermission(p_modify, 0, (r_manager, r_owner))
-
-    sdef = wf.states['pending']
-    sdef.setProperties(
-        title='Waiting for reviewer',
-        transitions=('publish', 'reject', 'retract',))
-    sdef.setPermission(p_access, 0, (r_manager, r_owner, r_reviewer))
-    sdef.setPermission(p_view, 0, (r_manager, r_owner, r_reviewer))
-    sdef.setPermission(p_modify, 0, (r_manager, r_reviewer))
-
-    sdef = wf.states['published']
-    sdef.setProperties(
-        title='Public',
-        transitions=('reject', 'retract',))
-    sdef.setPermission(p_access, 1, (r_anon, r_manager))
-    sdef.setPermission(p_view, 1, (r_anon, r_manager))
-    sdef.setPermission(p_modify, 0, (r_manager,))
-
-    tdef = wf.transitions['publish']
-    tdef.setProperties(
-        title='Reviewer publishes content',
-        new_state_id='published',
-        actbox_name='Publish',
-        actbox_url='%(content_url)s/content_publish_form',
-        props={'guard_permissions':p_review})
-
-    tdef = wf.transitions['reject']
-    tdef.setProperties(
-        title='Reviewer rejects submission',
-        new_state_id='private',
-        actbox_name='Reject',
-        actbox_url='%(content_url)s/content_reject_form',
-        props={'guard_permissions':p_review})
-
-    tdef = wf.transitions['retract']
-    tdef.setProperties(
-        title='Member retracts submission',
-        new_state_id='private',
-        actbox_name='Retract',
-        actbox_url='%(content_url)s/content_retract_form',
-        props={'guard_permissions':p_request})
-
-    tdef = wf.transitions['submit']
-    tdef.setProperties(
-        title='Member requests publishing',
-        new_state_id='pending',
-        actbox_name='Submit',
-        actbox_url='%(content_url)s/content_submit_form',
-        props={'guard_permissions':p_request})
-
-    wf.variables.setStateVar('review_state')
-
-    vdef = wf.variables['action']
-    vdef.setProperties(description='The last transition',
-                       default_expr='transition/getId|nothing',
-                       for_status=1, update_always=1)
-
-    vdef = wf.variables['actor']
-    vdef.setProperties(description='The ID of the user who performed '
-                       'the last transition',
-                       default_expr='user/getId',
-                       for_status=1, update_always=1)
-
-    vdef = wf.variables['comments']
-    vdef.setProperties(description='Comments about the last transition',
-                       default_expr="python:state_change.kwargs.get('comment', '')",
-                       for_status=1, update_always=1)
-
-    vdef = wf.variables['review_history']
-    vdef.setProperties(description='Provides access to workflow history',
-                       default_expr="state_change/getHistory",
-                       props={'guard_permissions':
-                              p_request + ';' + p_review})
-
-    vdef = wf.variables['time']
-    vdef.setProperties(description='Time of the last transition',
-                       default_expr="state_change/getDateTime",
-                       for_status=1, update_always=1)
-
-    ldef = wf.worklists['reviewer_queue']
-    ldef.setProperties(description='Reviewer tasks',
-                       actbox_name='Pending (%(count)d)',
-                       actbox_url='%(portal_url)s/search?review_state=pending',
-                       props={'var_match_review_state':'pending',
-                              'guard_permissions':p_review})
-    
-
-
-def createDefaultWorkflowClassic(id):
-    '''
-    '''
-    ob = DCWorkflowDefinition(id)
-    setupDefaultWorkflowClassic(ob)
-    return ob
-
-addWorkflowFactory(createDefaultWorkflowClassic, id='default_workflow',
-                   title='Web-configurable workflow [Classic]')
-

Copied: CMF/branches/tseaver-viewification/DCWorkflow/Extensions (from rev 40492, CMF/trunk/DCWorkflow/Extensions)

Modified: CMF/branches/tseaver-viewification/DCWorkflow/__init__.py
===================================================================
--- CMF/branches/tseaver-viewification/DCWorkflow/__init__.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/DCWorkflow/__init__.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,30 +1,33 @@
 ##############################################################################
 #
 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
-# 
+#
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.1 (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.
-# 
+#
 ##############################################################################
 """ Web-configurable workflow.
 
 $Id$
 """
 
+from Products.CMFCore.interfaces import ISiteRoot
 from Products.CMFCore.utils import registerIcon
+from Products.GenericSetup import EXTENSION
+from Products.GenericSetup import profile_registry
+
 import DCWorkflow, States, Transitions, Variables, Worklists, Scripts
-import Default
 
 
 def initialize(context):
-    
+
     context.registerHelp(directory='help')
     context.registerHelpTitle('DCWorkflow')
-    
+
     registerIcon(DCWorkflow.DCWorkflowDefinition,
                  'images/workflow.gif', globals())
     registerIcon(States.States,
@@ -41,3 +44,11 @@
     Worklists.WorklistDefinition.icon = Worklists.Worklists.icon
     registerIcon(Scripts.Scripts,
                  'images/script.gif', globals())
+
+    profile_registry.registerProfile('revision2',
+                                     'CMF Default Workflow [Revision 2]',
+                                     'Adds revision 2 of default workflow.',
+                                     'profiles/revision2',
+                                     'DCWorkflow',
+                                     EXTENSION,
+                                     for_=ISiteRoot)

Copied: CMF/branches/tseaver-viewification/DCWorkflow/browser (from rev 40492, CMF/trunk/DCWorkflow/browser)

Copied: CMF/branches/tseaver-viewification/DCWorkflow/configure.zcml (from rev 40492, CMF/trunk/DCWorkflow/configure.zcml)

Copied: CMF/branches/tseaver-viewification/DCWorkflow/exportimport.py (from rev 40492, CMF/trunk/DCWorkflow/exportimport.py)

Copied: CMF/branches/tseaver-viewification/DCWorkflow/interfaces.py (from rev 40492, CMF/trunk/DCWorkflow/interfaces.py)

Copied: CMF/branches/tseaver-viewification/DCWorkflow/profiles (from rev 40492, CMF/trunk/DCWorkflow/profiles)

Modified: CMF/branches/tseaver-viewification/DCWorkflow/tests/test_DCWorkflow.py
===================================================================
--- CMF/branches/tseaver-viewification/DCWorkflow/tests/test_DCWorkflow.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/DCWorkflow/tests/test_DCWorkflow.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,27 +15,21 @@
 $Id$
 """
 
-from unittest import TestCase, TestSuite, makeSuite, main
+import unittest
 import Testing
-import Zope2
-Zope2.startup()
 
 from Products.CMFCore.tests.base.dummy import DummyContent
 from Products.CMFCore.tests.base.dummy import DummySite
 from Products.CMFCore.tests.base.dummy import DummyTool
-from Products.CMFCore.WorkflowTool import addWorkflowFactory
 from Products.CMFCore.WorkflowTool import WorkflowTool
 
 
-class DCWorkflowDefinitionTests(TestCase):
+class DCWorkflowDefinitionTests(unittest.TestCase):
 
     def setUp(self):
-        from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
-
         self.site = DummySite('site')
         self.site._setObject( 'portal_types', DummyTool() )
         self.site._setObject( 'portal_workflow', WorkflowTool() )
-        addWorkflowFactory(DCWorkflowDefinition)
         self._constructDummyWorkflow()
 
     def test_z2interfaces(self):
@@ -54,9 +48,10 @@
         verifyClass(IWorkflowDefinition, DCWorkflowDefinition)
 
     def _constructDummyWorkflow(self):
+        from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
 
         wftool = self.site.portal_workflow
-        wftool.manage_addWorkflow('Workflow (DC Workflow Definition)', 'wf')
+        wftool._setObject('wf', DCWorkflowDefinition('wf'))
         wftool.setDefaultChain('wf')
         wf = wftool.wf
 
@@ -128,9 +123,9 @@
 
 
 def test_suite():
-    return TestSuite((
-        makeSuite(DCWorkflowDefinitionTests),
+    return unittest.TestSuite((
+        unittest.makeSuite(DCWorkflowDefinitionTests),
         ))
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Copied: CMF/branches/tseaver-viewification/DCWorkflow/tests/test_exportimport.py (from rev 40492, CMF/trunk/DCWorkflow/tests/test_exportimport.py)

Modified: CMF/branches/tseaver-viewification/DCWorkflow/tests/test_guard.py
===================================================================
--- CMF/branches/tseaver-viewification/DCWorkflow/tests/test_guard.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/DCWorkflow/tests/test_guard.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -15,32 +15,31 @@
 $Id$
 """
 
-from unittest import TestCase, TestSuite, makeSuite, main
+import unittest
+import Testing
 
 from AccessControl import getSecurityManager
 from Products.PageTemplates.TALES import CompilerError
 
+from Products.CMFCore.tests.base.dummy import DummyContent
+from Products.CMFCore.tests.base.dummy import DummySite
+from Products.CMFCore.tests.base.dummy import DummyTool
 from Products.CMFCore.WorkflowTool import WorkflowTool
-from Products.CMFCore.WorkflowTool import addWorkflowFactory
 
 from Products.DCWorkflow.Guard import Guard
 from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
 
-from Products.CMFCore.tests.base.dummy import DummyContent
-from Products.CMFCore.tests.base.dummy import DummySite
-from Products.CMFCore.tests.base.dummy import DummyTool
 
-class TestGuard(TestCase):
+class TestGuard(unittest.TestCase):
 
     def setUp(self):
         self.site = DummySite('site')
         self.site._setObject( 'portal_types', DummyTool() )
         self.site._setObject( 'portal_workflow', WorkflowTool() )
-        addWorkflowFactory(DCWorkflowDefinition)
 
         # Construct a workflow
         wftool = self.site.portal_workflow
-        wftool.manage_addWorkflow('Workflow (DC Workflow Definition)', 'wf')
+        wftool._setObject('wf', DCWorkflowDefinition('wf'))
         wftool.setDefaultChain('wf')
 
     def _getDummyWorkflow(self):
@@ -260,11 +259,11 @@
 
         # XXX more tests with permissions and roles
 
+
 def test_suite():
-    return TestSuite((
-        makeSuite(TestGuard),
+    return unittest.TestSuite((
+        unittest.makeSuite(TestGuard),
         ))
 
 if __name__ == '__main__':
-    main(defaultTest='test_suite')
-
+    unittest.main(defaultTest='test_suite')

Modified: CMF/branches/tseaver-viewification/DCWorkflow/utils.py
===================================================================
--- CMF/branches/tseaver-viewification/DCWorkflow/utils.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/DCWorkflow/utils.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,14 +1,14 @@
 ##############################################################################
 #
 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
-# 
+#
 # This software is subject to the provisions of the Zope Public License,
 # Version 2.1 (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.
-# 
+#
 ##############################################################################
 """ Some common utilities.
 
@@ -16,15 +16,15 @@
 """
 
 import os
+
+from AccessControl.Permission import Permission
+from AccessControl.Role import gather_permissions
 from App.Common import package_home
 
 _dtmldir = os.path.join( package_home( globals() ), 'dtml' )
+_xmldir = os.path.join( package_home( globals() ), 'xml' )
 
-from AccessControl.Role import gather_permissions
-from AccessControl.Permission import Permission
-from Acquisition import aq_base
 
-
 def ac_inherited_permissions(ob, all=0):
     # Get all permissions not defined in ourself that are inherited
     # This will be a sequence of tuples with a name as the first item and

Copied: CMF/branches/tseaver-viewification/DCWorkflow/xml (from rev 40492, CMF/trunk/DCWorkflow/xml)

Modified: CMF/branches/tseaver-viewification/GenericSetup/CHANGES.txt
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/CHANGES.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/CHANGES.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -2,6 +2,12 @@
 
   After GenericSetup 1.0
 
+    - Added 'for_' argument to profile registry operations.
+      A profile may be registered and queried as appropriate to a specific
+      site interface;  the default value, 'None', indicates that the profile
+      is relevant to any site.  Note that this is essentially an adapter
+      lookup;  perhaps we should reimplement it so.
+
     - Forward ported changes from GenericSetup 0.11 and 0.12 (which were
       created in a separate repository).
 

Modified: CMF/branches/tseaver-viewification/GenericSetup/DEPENDENCIES.txt
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/DEPENDENCIES.txt	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/DEPENDENCIES.txt	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1,2 +1,2 @@
-Zope >= 2.8.2
+Zope >= 2.8.5
 Five >= 1.2

Modified: CMF/branches/tseaver-viewification/GenericSetup/MailHost/configure.zcml
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/MailHost/configure.zcml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/MailHost/configure.zcml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -3,15 +3,10 @@
     >
 
   <adapter
-      factory=".exportimport.MailHostNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeExporter"
-      for="Products.MailHost.interfaces.IMailHost"
+      factory=".exportimport.MailHostXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.MailHost.interfaces.IMailHost
+           Products.GenericSetup.interfaces.ISetupContext"
       />
 
-  <adapter
-      factory=".exportimport.MailHostNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeImporter"
-      for="Products.MailHost.interfaces.IMailHost"
-      />
-
 </configure>

Modified: CMF/branches/tseaver-viewification/GenericSetup/MailHost/exportimport.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/MailHost/exportimport.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/MailHost/exportimport.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -16,18 +16,20 @@
 """
 
 from Products.GenericSetup.interfaces import PURGE
-from Products.GenericSetup.utils import NodeAdapterBase
+from Products.GenericSetup.utils import XMLAdapterBase
 
 from Products.MailHost.interfaces import IMailHost
 
 
-class MailHostNodeAdapter(NodeAdapterBase):
+class MailHostXMLAdapter(XMLAdapterBase):
 
-    """Node im- and exporter for MailHost.
+    """XML im- and exporter for MailHost.
     """
 
     __used_for__ = IMailHost
 
+    _LOGGER_ID = 'mailhost'
+
     def exportNode(self, doc):
         """Export the object as a DOM node.
         """
@@ -37,6 +39,8 @@
         node.setAttribute('smtp_port', str(self.context.smtp_port))
         node.setAttribute('smtp_uid', self.context.smtp_uid)
         node.setAttribute('smtp_pwd', self.context.smtp_pwd)
+
+        self._logger.info('Mailhost exported.')
         return node
 
     def importNode(self, node, mode=PURGE):
@@ -46,3 +50,5 @@
         self.context.smtp_port = int(node.getAttribute('smtp_port'))
         self.context.smtp_uid = node.getAttribute('smtp_uid').encode('utf-8')
         self.context.smtp_pwd = node.getAttribute('smtp_pwd').encode('utf-8')
+
+        self._logger.info('Mailhost imported.')

Modified: CMF/branches/tseaver-viewification/GenericSetup/MailHost/tests/test_exportimport.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/MailHost/tests/test_exportimport.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/MailHost/tests/test_exportimport.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -18,22 +18,24 @@
 import unittest
 import Testing
 
-from Products.GenericSetup.testing import NodeAdapterTestCase
-from Products.GenericSetup.testing import PlacelessSetup
+from Products.Five import zcml
 
-_MAILHOST_XML = """\
+from Products.GenericSetup.testing import BodyAdapterTestCase
+
+_MAILHOST_BODY = """\
+<?xml version="1.0"?>
 <object name="foo_mailhost" meta_type="Mail Host" smtp_host="localhost"
    smtp_port="25" smtp_pwd="" smtp_uid=""/>
 """
 
 
-class MailHostNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class MailHostXMLAdapterTests(BodyAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.MailHost.exportimport \
-                import MailHostNodeAdapter
+                import MailHostXMLAdapter
 
-        return MailHostNodeAdapter
+        return MailHostXMLAdapter
 
     def _verifyImport(self, obj):
         self.assertEqual(type(obj.smtp_host), str)
@@ -46,22 +48,19 @@
         self.assertEqual(obj.smtp_uid, '')
 
     def setUp(self):
-        import Products.Five
-        from Products.Five import zcml
         import Products.GenericSetup.MailHost
         from Products.MailHost.MailHost import MailHost
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        BodyAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml', Products.GenericSetup.MailHost)
 
         self._obj = MailHost('foo_mailhost')
-        self._XML = _MAILHOST_XML
+        self._BODY = _MAILHOST_BODY
 
 
 def test_suite():
     return unittest.TestSuite((
-        unittest.makeSuite(MailHostNodeAdapterTests),
+        unittest.makeSuite(MailHostXMLAdapterTests),
         ))
 
 if __name__ == '__main__':

Copied: CMF/branches/tseaver-viewification/GenericSetup/OFSP (from rev 40492, CMF/trunk/GenericSetup/OFSP)

Modified: CMF/branches/tseaver-viewification/GenericSetup/PluginIndexes/tests/test_exportimport.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/PluginIndexes/tests/test_exportimport.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/PluginIndexes/tests/test_exportimport.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -18,13 +18,9 @@
 import unittest
 import Testing
 
-import Products.Five
-import Products.GenericSetup.PluginIndexes
 from Products.Five import zcml
 from Products.GenericSetup.testing import NodeAdapterTestCase
-from Products.GenericSetup.testing import PlacelessSetup
 
-
 _DATE_XML = """\
 <index name="foo_date" meta_type="DateIndex">
  <property name="index_naive_time_as_local">True</property>
@@ -72,7 +68,7 @@
 """
 
 
-class DateIndexNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class DateIndexNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.PluginIndexes.exportimport \
@@ -81,10 +77,10 @@
         return DateIndexNodeAdapter
 
     def setUp(self):
+        import Products.GenericSetup.PluginIndexes
         from Products.PluginIndexes.DateIndex.DateIndex import DateIndex
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml',
                          Products.GenericSetup.PluginIndexes)
 
@@ -92,7 +88,7 @@
         self._XML = _DATE_XML
 
 
-class DateRangeIndexNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class DateRangeIndexNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.PluginIndexes.exportimport \
@@ -104,11 +100,11 @@
         obj._edit('bar', 'baz')
 
     def setUp(self):
+        import Products.GenericSetup.PluginIndexes
         from Products.PluginIndexes.DateRangeIndex.DateRangeIndex \
                 import DateRangeIndex
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml',
                          Products.GenericSetup.PluginIndexes)
 
@@ -116,7 +112,7 @@
         self._XML = _DATERANGE_XML
 
 
-class FieldIndexNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class FieldIndexNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.PluginIndexes.exportimport \
@@ -128,10 +124,10 @@
         obj.indexed_attrs = ('bar',)
 
     def setUp(self):
+        import Products.GenericSetup.PluginIndexes
         from Products.PluginIndexes.FieldIndex.FieldIndex import FieldIndex
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml',
                          Products.GenericSetup.PluginIndexes)
 
@@ -139,7 +135,7 @@
         self._XML = _FIELD_XML
 
 
-class KeywordIndexNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class KeywordIndexNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.PluginIndexes.exportimport \
@@ -151,12 +147,11 @@
         obj.indexed_attrs = ('bar',)
 
     def setUp(self):
+        import Products.GenericSetup.PluginIndexes
         from Products.PluginIndexes.KeywordIndex.KeywordIndex \
                 import KeywordIndex
 
-
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml',
                          Products.GenericSetup.PluginIndexes)
 
@@ -164,7 +159,7 @@
         self._XML = _KEYWORD_XML
 
 
-class PathIndexNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class PathIndexNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.PluginIndexes.exportimport \
@@ -173,11 +168,10 @@
         return PathIndexNodeAdapter
 
     def setUp(self):
+        import Products.GenericSetup.PluginIndexes
         from Products.PluginIndexes.PathIndex.PathIndex import PathIndex
 
-
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml',
                          Products.GenericSetup.PluginIndexes)
 
@@ -185,7 +179,7 @@
         self._XML = _PATH_XML
 
 
-class VocabularyNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class VocabularyNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.PluginIndexes.exportimport \
@@ -194,10 +188,10 @@
         return VocabularyNodeAdapter
 
     def setUp(self):
+        import Products.GenericSetup.PluginIndexes
         from Products.PluginIndexes.TextIndex.Vocabulary import Vocabulary
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml',
                          Products.GenericSetup.PluginIndexes)
 
@@ -208,7 +202,7 @@
         pass
 
 
-class TextIndexNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class TextIndexNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.PluginIndexes.exportimport \
@@ -217,10 +211,10 @@
         return TextIndexNodeAdapter
 
     def setUp(self):
+        import Products.GenericSetup.PluginIndexes
         from Products.PluginIndexes.TextIndex.TextIndex import TextIndex
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml',
                          Products.GenericSetup.PluginIndexes)
 
@@ -231,7 +225,7 @@
         pass
 
 
-class FilteredSetNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class FilteredSetNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.PluginIndexes.exportimport \
@@ -243,11 +237,11 @@
         obj.setExpression('True')
 
     def setUp(self):
+        import Products.GenericSetup.PluginIndexes
         from Products.PluginIndexes.TopicIndex.FilteredSet \
                 import PythonFilteredSet
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml',
                          Products.GenericSetup.PluginIndexes)
 
@@ -255,7 +249,7 @@
         self._XML = _SET_XML
 
 
-class TopicIndexNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class TopicIndexNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.PluginIndexes.exportimport \
@@ -268,10 +262,10 @@
         obj.addFilteredSet('baz', 'PythonFilteredSet', 'False')
 
     def setUp(self):
+        import Products.GenericSetup.PluginIndexes
         from Products.PluginIndexes.TopicIndex.TopicIndex import TopicIndex
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml',
                          Products.GenericSetup.PluginIndexes)
 

Copied: CMF/branches/tseaver-viewification/GenericSetup/PythonScripts (from rev 40492, CMF/trunk/GenericSetup/PythonScripts)

Modified: CMF/branches/tseaver-viewification/GenericSetup/ZCTextIndex/tests/test_exportimport.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/ZCTextIndex/tests/test_exportimport.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/ZCTextIndex/tests/test_exportimport.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -20,23 +20,9 @@
 
 from Acquisition import Implicit
 
-import Products.Five
-import Products.GenericSetup.ZCTextIndex
 from Products.Five import zcml
 from Products.GenericSetup.testing import NodeAdapterTestCase
-from Products.GenericSetup.testing import PlacelessSetup
 
-
-class _extra:
-
-    pass
-
-
-class DummyCatalog(Implicit):
-
-    pass
-
-
 _PLEXICON_XML = """\
 <object name="foo_plexicon" meta_type="ZCTextIndex Lexicon">
  <element name="Whitespace splitter" group="Word Splitter"/>
@@ -54,8 +40,18 @@
 """
 
 
-class ZCLexiconNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class _extra:
 
+    pass
+
+
+class DummyCatalog(Implicit):
+
+    pass
+
+
+class ZCLexiconNodeAdapterTests(NodeAdapterTestCase):
+
     def _getTargetClass(self):
         from Products.GenericSetup.ZCTextIndex.exportimport \
                 import ZCLexiconNodeAdapter
@@ -69,17 +65,17 @@
         obj._pipeline = (Splitter(), CaseNormalizer(), StopWordRemover())
 
     def setUp(self):
+        import Products.GenericSetup.ZCTextIndex
         from Products.ZCTextIndex.ZCTextIndex import PLexicon
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml', Products.GenericSetup.ZCTextIndex)
 
         self._obj = PLexicon('foo_plexicon')
         self._XML = _PLEXICON_XML
 
 
-class ZCTextIndexNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class ZCTextIndexNodeAdapterTests(NodeAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.ZCTextIndex.exportimport \
@@ -88,11 +84,11 @@
         return ZCTextIndexNodeAdapter
 
     def setUp(self):
+        import Products.GenericSetup.ZCTextIndex
         from Products.ZCTextIndex.ZCTextIndex import PLexicon
         from Products.ZCTextIndex.ZCTextIndex import ZCTextIndex
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        NodeAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml', Products.GenericSetup.ZCTextIndex)
 
         catalog = DummyCatalog()

Modified: CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/configure.zcml
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/configure.zcml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/configure.zcml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -3,15 +3,10 @@
     >
 
   <adapter
-      factory=".exportimport.ZCatalogNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeExporter"
-      for="Products.ZCatalog.interfaces.IZCatalog"
+      factory=".exportimport.ZCatalogXMLAdapter"
+      provides="Products.GenericSetup.interfaces.IBody"
+      for="Products.ZCatalog.interfaces.IZCatalog
+           Products.GenericSetup.interfaces.ISetupContext"
       />
 
-  <adapter
-      factory=".exportimport.ZCatalogNodeAdapter"
-      provides="Products.GenericSetup.interfaces.INodeImporter"
-      for="Products.ZCatalog.interfaces.IZCatalog"
-      />
-
 </configure>

Modified: CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/exportimport.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/exportimport.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/exportimport.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -18,9 +18,9 @@
 from Products.GenericSetup.interfaces import INodeExporter
 from Products.GenericSetup.interfaces import INodeImporter
 from Products.GenericSetup.interfaces import PURGE
-from Products.GenericSetup.utils import NodeAdapterBase
 from Products.GenericSetup.utils import ObjectManagerHelpers
 from Products.GenericSetup.utils import PropertyManagerHelpers
+from Products.GenericSetup.utils import XMLAdapterBase
 
 from Products.ZCatalog.interfaces import IZCatalog
 
@@ -30,14 +30,16 @@
     pass
 
 
-class ZCatalogNodeAdapter(NodeAdapterBase, ObjectManagerHelpers,
-                          PropertyManagerHelpers):
+class ZCatalogXMLAdapter(XMLAdapterBase, ObjectManagerHelpers,
+                         PropertyManagerHelpers):
 
-    """Node im- and exporter for ZCatalog.
+    """XML im- and exporter for ZCatalog.
     """
 
     __used_for__ = IZCatalog
 
+    _LOGGER_ID = 'catalog'
+
     def exportNode(self, doc):
         """Export the object as a DOM node.
         """
@@ -47,6 +49,8 @@
         node.appendChild(self._extractObjects())
         node.appendChild(self._extractIndexes())
         node.appendChild(self._extractColumns())
+
+        self._logger.info('Catalog exported.')
         return node
 
     def importNode(self, node, mode=PURGE):
@@ -63,6 +67,8 @@
         self._initIndexes(node, mode)
         self._initColumns(node, mode)
 
+        self._logger.info('Catalog imported.')
+
     def _extractIndexes(self):
         fragment = self._doc.createDocumentFragment()
         indexes = self.context.getIndexObjects()[:]

Modified: CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/tests/test_exportimport.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/tests/test_exportimport.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/ZCatalog/tests/test_exportimport.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -20,20 +20,21 @@
 import Zope2
 Zope2.startup()
 
-import Products
 from Products.Five import zcml
-from Products.GenericSetup.interfaces import INodeExporter
-from Products.GenericSetup.testing import NodeAdapterTestCase
-from Products.GenericSetup.testing import PlacelessSetup
-from Products.GenericSetup.utils import PrettyDocument
+from zope.app import zapi
 
+from Products.GenericSetup.interfaces import IBody
+from Products.GenericSetup.testing import BodyAdapterTestCase
+from Products.GenericSetup.tests.common import DummyExportContext
 
+
 class _extra:
 
     pass
 
 
-_CATALOG_XML = """\
+_CATALOG_BODY = """\
+<?xml version="1.0"?>
 <object name="foo_catalog" meta_type="ZCatalog">
  <property name="title"></property>
  <object name="foo_plexicon" meta_type="ZCTextIndex Lexicon">
@@ -76,13 +77,13 @@
 """
 
 
-class ZCatalogNodeAdapterTests(PlacelessSetup, NodeAdapterTestCase):
+class ZCatalogXMLAdapterTests(BodyAdapterTestCase):
 
     def _getTargetClass(self):
         from Products.GenericSetup.ZCatalog.exportimport \
-                import ZCatalogNodeAdapter
+                import ZCatalogXMLAdapter
 
-        return ZCatalogNodeAdapter
+        return ZCatalogXMLAdapter
 
     def _populate(self, obj):
         from Products.ZCTextIndex.Lexicon import CaseNormalizer
@@ -131,28 +132,29 @@
         obj.addIndex('foo_text', 'TextIndex')
 
     def setUp(self):
+        import Products.GenericSetup
         from Products.ZCatalog.ZCatalog import ZCatalog
 
-        PlacelessSetup.setUp(self)
-        zcml.load_config('meta.zcml', Products.Five)
+        BodyAdapterTestCase.setUp(self)
         zcml.load_config('configure.zcml',
                          Products.GenericSetup.PluginIndexes)
         zcml.load_config('configure.zcml', Products.GenericSetup.ZCatalog)
         zcml.load_config('configure.zcml', Products.GenericSetup.ZCTextIndex)
 
         self._obj = ZCatalog('foo_catalog')
-        self._XML = _CATALOG_XML % ('', '')
+        self._BODY = _CATALOG_BODY % ('', '')
 
-    def test_exportNode_special(self):
+    def test_body_get_special(self):
         self._populate_special(self._obj)
-        node = INodeExporter(self._obj).exportNode(PrettyDocument())
-        self.assertEqual(node.toprettyxml(' '),
-                         _CATALOG_XML % (_VOCABULARY_XML, _TEXT_XML))
+        context = DummyExportContext(None)
+        exporter = zapi.getMultiAdapter((self._obj, context), IBody)
+        self.assertEqual(exporter.body,
+                         _CATALOG_BODY % (_VOCABULARY_XML, _TEXT_XML))
 
 
 def test_suite():
     return unittest.TestSuite((
-        unittest.makeSuite(ZCatalogNodeAdapterTests),
+        unittest.makeSuite(ZCatalogXMLAdapterTests),
         ))
 
 if __name__ == '__main__':

Modified: CMF/branches/tseaver-viewification/GenericSetup/__init__.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/__init__.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/__init__.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -24,3 +24,15 @@
                           interfaces=None,
                           icon='www/tool.png',
                          )
+
+# BBB: for setup tools created with CMF 1.5 if CMFSetup isn't installed
+try:
+    import Products.CMFSetup
+except ImportError:
+    import bbb
+    import bbb.registry
+    import bbb.tool
+
+    __module_aliases__ = (('Products.CMFSetup', bbb),
+                          ('Products.CMFSetup.registry', bbb.registry),
+                          ('Products.CMFSetup.tool', bbb.tool))

Copied: CMF/branches/tseaver-viewification/GenericSetup/bbb (from rev 40492, CMF/trunk/GenericSetup/bbb)

Copied: CMF/branches/tseaver-viewification/GenericSetup/browser (from rev 40492, CMF/trunk/GenericSetup/browser)

Modified: CMF/branches/tseaver-viewification/GenericSetup/configure.zcml
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/configure.zcml	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/configure.zcml	2005-12-02 18:15:45 UTC (rev 40498)
@@ -4,8 +4,12 @@
 
   <include package=".MailHost"/>
 
+  <include package=".OFSP"/>
+
   <include package=".PluginIndexes"/>
 
+  <include package=".PythonScripts"/>
+
   <include package=".ZCatalog"/>
 
   <include package=".ZCTextIndex"/>

Modified: CMF/branches/tseaver-viewification/GenericSetup/content.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/content.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/content.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -139,8 +139,7 @@
                 prop_adapter.put_ini(prop_text)
 
         preserve = import_context.readDataFile('.preserve', subdir)
-        tool_items = [x for x in context.objectItems()
-                        if ISetupTool.providedBy(x[1])]
+        must_preserve = self._mustPreserve()
 
         prior = context.objectIds()
 
@@ -149,7 +148,7 @@
         else:
             preserve = _globtest(preserve, prior)
 
-        preserve.extend([x[0] for x in tool_items])
+        preserve.extend([x[0] for x in must_preserve])
 
         for id in prior:
             if id not in preserve:
@@ -224,6 +223,10 @@
             context._setObject(instance_id, instance) 
 
         return context._getOb(instance_id)
+
+    def _mustPreserve(self):
+        return [x for x in self.context.objectItems()
+                        if ISetupTool.providedBy(x[1])]
  
 
 def _globtest(globpattern, namelist):

Modified: CMF/branches/tseaver-viewification/GenericSetup/context.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/context.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/context.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -420,6 +420,13 @@
 
         """ See IExportContext.
         """
+        if subdir is not None:
+            filename = '/'.join( ( subdir, filename ) )
+
+        sep = filename.rfind('/')
+        if sep != -1:
+            subdir = filename[:sep]
+            filename = filename[sep+1:]
         folder = self._ensureSnapshotsFolder( subdir )
 
         # TODO: switch on content_type
@@ -525,6 +532,13 @@
 
         """ See IImportContext.
         """
+        if subdir is not None:
+            filename = '/'.join( ( subdir, filename ) )
+
+        sep = filename.rfind('/')
+        if sep != -1:
+            subdir = filename[:sep]
+            filename = filename[sep+1:]
         try:
             snapshot = self._getSnapshotFolder( subdir )
             object = snapshot._getOb( filename )

Modified: CMF/branches/tseaver-viewification/GenericSetup/interfaces.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/interfaces.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/interfaces.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -16,8 +16,9 @@
 """
 
 from zope.interface import Interface
+from zope.schema import Text
+from zope.schema import TextLine
 
-
 BASE, EXTENSION = range(1, 3)
 PURGE, UPDATE = range(1, 3)
 
@@ -352,7 +353,7 @@
 
     """ API for profile registry.
     """
-    def getProfileInfo( profile_id ):
+    def getProfileInfo( profile_id, for_=None ):
 
         """ Return a mapping describing a registered filesystem profile.
 
@@ -370,18 +371,36 @@
              relative (None for absolute paths).
 
           'type' -- either BASE or EXTENSION
+        
+        o 'for_', if passed, should be the interface specifying the "site
+            type" for which the profile is relevant, e.g.
+            Products.CMFCore.interfaces.ISiteRoot or
+            Products.PluggableAuthService.interfaces.IPluggableAuthService.
+            If 'None', list all profiles.
         """
 
-    def listProfiles():
+    def listProfiles( for_=None ):
 
         """ Return a list of IDs for registered profiles.
+        
+        o 'for_', if passed, should be the interface specifying the "site
+            type" for which the profile is relevant, e.g.
+            Products.CMFCore.interfaces.ISiteRoot or
+            Products.PluggableAuthService.interfaces.IPluggableAuthService.
+            If 'None', list all profiles.
         """
 
-    def listProfileInfo():
+    def listProfileInfo( for_=None ):
 
         """ Return a list of mappings describing registered profiles.
 
         o See 'getProfileInfo' for a description of the mappings' keys.
+        
+        o 'for_', if passed, should be the interface specifying the "site
+            type" for which the profile is relevant, e.g.
+            Products.CMFCore.interfaces.ISiteRoot or
+            Products.PluggableAuthService.interfaces.IPluggableAuthService.
+            If 'None', list all profiles.
         """
 
     def registerProfile( name
@@ -390,6 +409,7 @@
                        , path
                        , product=None
                        , profile_type=BASE
+                       , for_=None
                        ):
         """ Add a new profile to the registry.
 
@@ -398,6 +418,12 @@
 
         o If 'product' is passed, then 'path' should be interpreted as
           relative to the corresponding product directory.
+        
+        o 'for_', if passed, should be the interface specifying the "site
+          type" for which the profile is relevant, e.g.
+          Products.CMFCore.interfaces.ISiteRoot or
+          Products.PluggableAuthService.interfaces.IPluggableAuthService.
+          If 'None', the profile might be used in any site.
         """
 
 class ISetupTool( Interface ):
@@ -562,6 +588,18 @@
         """
 
 
+class IBody(Interface):
+
+    """Body im- and exporter.
+    """
+
+    body = Text(description=u'Im- and export the object as a file body.')
+
+    mime_type = TextLine(description=u'MIME type of the file body.')
+
+    suffix = TextLine(description=u'Suffix for the file.')
+
+
 class INodeExporter(Interface):
 
     """Node exporter.
@@ -581,6 +619,7 @@
         """Import the object from the DOM node.
         """
 
+
 class IFilesystemExporter(Interface):
     """ Plugin interface for site structure export.
     """

Modified: CMF/branches/tseaver-viewification/GenericSetup/registry.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/registry.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/registry.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -531,26 +531,37 @@
         self.clear()
 
     security.declareProtected( ManagePortal, '' )
-    def getProfileInfo( self, profile_id ):
+    def getProfileInfo( self, profile_id, for_=None ):
 
         """ See IProfileRegistry.
         """
         result = self._profile_info[ profile_id ]
+        if for_ is not None:
+            if not issubclass( for_, result['for'] ):
+                raise KeyError, profile_id
         return result.copy()
 
     security.declareProtected( ManagePortal, 'listProfiles' )
-    def listProfiles( self ):
+    def listProfiles( self, for_=None ):
 
         """ See IProfileRegistry.
         """
-        return tuple( self._profile_ids )
+        result = []
+        for profile_id in self._profile_ids:
+            info = self.getProfileInfo( profile_id )
+            if for_ is None or issubclass( for_, info['for'] ):
+                result.append( profile_id )
+        return tuple( result )
 
     security.declareProtected( ManagePortal, 'listProfileInfo' )
-    def listProfileInfo( self ):
+    def listProfileInfo( self, for_=None ):
 
         """ See IProfileRegistry.
         """
-        return [ self.getProfileInfo( id ) for id in self.listProfiles() ]
+        candidates = [ self.getProfileInfo( id )
+                        for id in self.listProfiles() ]
+        return [ x for x in candidates if for_ is None or x['for'] is None or
+                 issubclass( for_, x['for'] ) ]
 
     security.declareProtected( ManagePortal, 'registerProfile' )
     def registerProfile( self
@@ -560,6 +571,7 @@
                        , path
                        , product=None
                        , profile_type=BASE
+                       , for_=None
                        ):
         """ See IProfileRegistry.
         """
@@ -575,6 +587,7 @@
                , 'path' : path
                , 'product' : product
                , 'type': profile_type
+               , 'for': for_
                }
 
         self._profile_info[ profile_id ] = info

Modified: CMF/branches/tseaver-viewification/GenericSetup/testing.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/testing.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/testing.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -16,12 +16,20 @@
 """
 
 import unittest
+import Testing
+
 from xml.dom.minidom import parseString
 
+import Products.Five
+from Products.Five import zcml
+from zope.app import zapi
 from zope.interface.verify import verifyClass
 
+from interfaces import IBody
 from interfaces import INodeExporter
 from interfaces import INodeImporter
+from tests.common import DummyExportContext
+from tests.common import DummyImportContext
 from utils import PrettyDocument
 
 try:
@@ -30,7 +38,7 @@
     from zope.app.tests.placelesssetup import PlacelessSetup
 
 
-class NodeAdapterTestCase(unittest.TestCase):
+class BodyAdapterTestCase(PlacelessSetup, unittest.TestCase):
 
     def _populate(self, obj):
         pass
@@ -38,7 +46,50 @@
     def _verifyImport(self, obj):
         pass
 
+    def setUp(self):
+        PlacelessSetup.setUp(self)
+        zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('permissions.zcml', Products.Five)
+
+    def tearDown(self):
+        PlacelessSetup.tearDown(self)
+
     def test_z3interfaces(self):
+        verifyClass(IBody, self._getTargetClass())
+
+    def test_body_get(self):
+        self._populate(self._obj)
+        context = DummyExportContext(None)
+        exporter = zapi.getMultiAdapter((self._obj, context), IBody)
+        self.assertEqual(exporter.body, self._BODY)
+
+    def test_body_set(self):
+        context = DummyImportContext(None)
+        importer = zapi.getMultiAdapter((self._obj, context), IBody)
+        importer.body = self._BODY
+        self._verifyImport(self._obj)
+        context = DummyExportContext(None)
+        exporter = zapi.getMultiAdapter((self._obj, context), IBody)
+        self.assertEqual(exporter.body, self._BODY)
+
+
+class NodeAdapterTestCase(PlacelessSetup, unittest.TestCase):
+
+    def _populate(self, obj):
+        pass
+
+    def _verifyImport(self, obj):
+        pass
+
+    def setUp(self):
+        PlacelessSetup.setUp(self)
+        zcml.load_config('meta.zcml', Products.Five)
+        zcml.load_config('permissions.zcml', Products.Five)
+
+    def tearDown(self):
+        PlacelessSetup.tearDown(self)
+
+    def test_z3interfaces(self):
         verifyClass(INodeExporter, self._getTargetClass())
         verifyClass(INodeImporter, self._getTargetClass())
 

Modified: CMF/branches/tseaver-viewification/GenericSetup/tests/common.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/tests/common.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/tests/common.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -21,7 +21,12 @@
 
 from Acquisition import Implicit
 from Testing.ZopeTestCase import ZopeTestCase
+from zope.interface import implements
 
+from Products.GenericSetup.interfaces import IExportContext
+from Products.GenericSetup.interfaces import IImportContext
+
+
 class OmnipotentUser(Implicit):
     """ Omnipotent User for unit testing purposes.
     """
@@ -189,6 +194,8 @@
 
 class DummyExportContext:
 
+    implements(IExportContext)
+
     def __init__( self, site, tool=None ):
         self._site = site
         self._tool = tool
@@ -212,6 +219,8 @@
 
 class DummyImportContext:
 
+    implements(IImportContext)
+
     def __init__( self, site, purge=True, encoding=None, tool=None ):
         self._site = site
         self._tool = tool

Modified: CMF/branches/tseaver-viewification/GenericSetup/tests/test_context.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/tests/test_context.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/tests/test_context.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -1010,6 +1010,9 @@
         self.assertEqual( template.meta_type, DTMLDocument.meta_type )
         self.assertEqual( template.read(), _HTML )
 
+        ctx.writeDataFile( 'sub1/%s2' % FILENAME, _HTML, CONTENT_TYPE)
+        self.assertEqual( len( sub1.objectIds() ), 2 )
+
     def test_writeDataFile_nested_subdirs_html( self ):
 
         from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
@@ -1198,6 +1201,8 @@
                       , subdir=SUBDIR )
 
         self.assertEqual( ctx.readDataFile( FILENAME, SUBDIR ), printable )
+        self.assertEqual( ctx.readDataFile( '%s/%s' % (SUBDIR, FILENAME) ),
+                                            printable )
 
     def test_getLastModified_nonesuch( self ):
 

Modified: CMF/branches/tseaver-viewification/GenericSetup/tests/test_registry.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/tests/test_registry.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/tests/test_registry.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -23,6 +23,7 @@
 from OFS.Folder import Folder
 from Products.GenericSetup.tests.common import BaseRegistryTests
 from Products.GenericSetup import EXTENSION
+from zope.interface import Interface
 
 from conformance import ConformsToIStepRegistry
 from conformance import ConformsToIImportStepRegistry
@@ -1024,6 +1025,16 @@
 </tool-setup>
 """
 
+class ISite(Interface):
+    pass
+
+class IDerivedSite(ISite):
+    pass
+
+class IAnotherSite(Interface):
+    pass
+
+
 class ProfileRegistryTests( BaseRegistryTests
                           , ConformsToIProfileRegistry
                           ):
@@ -1071,21 +1082,86 @@
         self.assertEqual( info[ 'path' ], PATH )
         self.assertEqual( info[ 'product' ], PRODUCT )
         self.assertEqual( info[ 'type' ], PROFILE_TYPE )
+        self.assertEqual( info[ 'for' ], None )
 
     def test_registerProfile_duplicate( self ):
 
-        PROFILE_ID = 'one'
+        NAME = 'one'
         TITLE = 'One'
         DESCRIPTION = 'One profile'
         PATH = '/path/to/one'
 
         registry = self._makeOne()
-        registry.registerProfile( PROFILE_ID, TITLE, DESCRIPTION, PATH )
+        registry.registerProfile( NAME, TITLE, DESCRIPTION, PATH )
         self.assertRaises( KeyError
                          , registry.registerProfile
-                         , PROFILE_ID, TITLE, DESCRIPTION, PATH )
+                         , NAME, TITLE, DESCRIPTION, PATH )
 
 
+    def test_registerProfile_site_type( self ):
+
+        NAME = 'one'
+        TITLE = 'One'
+        DESCRIPTION = 'One profile'
+        PATH = '/path/to/one'
+        PRODUCT = 'TestProduct'
+        PROFILE_ID = 'TestProduct:one'
+        PROFILE_TYPE = EXTENSION
+        FOR = ISite
+        NOT_FOR = IAnotherSite
+        DERIVED_FOR = IDerivedSite
+
+        registry = self._makeOne()
+        registry.registerProfile( NAME
+                                , TITLE
+                                , DESCRIPTION
+                                , PATH
+                                , PRODUCT
+                                , PROFILE_TYPE
+                                , for_=FOR
+                                )
+
+
+        self.assertEqual( len( registry.listProfiles() ), 1 )
+        self.assertEqual( len( registry.listProfiles( for_=FOR ) ), 1 )
+        self.assertEqual( len( registry.listProfiles( for_=DERIVED_FOR ) )
+                        , 1 )
+        self.assertEqual( len( registry.listProfiles( for_=NOT_FOR ) )
+                        , 0 )
+
+        self.assertEqual( len( registry.listProfileInfo() ), 1 )
+        self.assertEqual( len( registry.listProfileInfo( for_=FOR ) ), 1 )
+        self.assertEqual( len( registry.listProfileInfo( for_=DERIVED_FOR ) )
+                        , 1 )
+        self.assertEqual( len( registry.listProfileInfo( for_=NOT_FOR ) )
+                        , 0 )
+
+        # Verify that these lookups succeed...
+        info1 = registry.getProfileInfo( PROFILE_ID )
+        info2 = registry.getProfileInfo( PROFILE_ID, for_=FOR )
+        info3 = registry.getProfileInfo( PROFILE_ID, for_=DERIVED_FOR )
+
+        self.assertEqual(info1, info2)
+        self.assertEqual(info1, info3)
+
+        # ...and that this one fails.
+        self.assertRaises( KeyError
+                         , registry.getProfileInfo
+                         , PROFILE_ID
+                         , for_=NOT_FOR
+                         )
+
+        info = registry.getProfileInfo( PROFILE_ID , for_=FOR )
+
+        self.assertEqual( info[ 'id' ], PROFILE_ID )
+        self.assertEqual( info[ 'title' ], TITLE )
+        self.assertEqual( info[ 'description' ], DESCRIPTION )
+        self.assertEqual( info[ 'path' ], PATH )
+        self.assertEqual( info[ 'product' ], PRODUCT )
+        self.assertEqual( info[ 'type' ], PROFILE_TYPE )
+        self.assertEqual( info[ 'for' ], FOR )
+
+
 def test_suite():
     return unittest.TestSuite((
         unittest.makeSuite( ImportStepRegistryTests ),

Modified: CMF/branches/tseaver-viewification/GenericSetup/tool.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/tool.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/tool.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -160,7 +160,7 @@
         """
         return 'ascii'
 
-    security.declareProtected(ManagePortal, 'getImportContextId')
+    security.declareProtected(ManagePortal, 'getImportContextID')
     def getImportContextID(self):
 
         """ See ISetupTool.
@@ -199,7 +199,7 @@
         """
         return self._toolset_registry
 
-    security.declareProtected(ManagePortal, 'executeStep')
+    security.declareProtected(ManagePortal, 'runImportStep')
     def runImportStep(self, step_id, run_dependencies=True, purge_old=None):
 
         """ See ISetupTool.
@@ -231,7 +231,7 @@
 
         return { 'steps' : steps, 'messages' : messages }
 
-    security.declareProtected(ManagePortal, 'runAllSetupSteps')
+    security.declareProtected(ManagePortal, 'runAllImportSteps')
     def runAllImportSteps(self, purge_old=None):
 
         """ See ISetupTool.

Modified: CMF/branches/tseaver-viewification/GenericSetup/utils.py
===================================================================
--- CMF/branches/tseaver-viewification/GenericSetup/utils.py	2005-12-02 18:03:52 UTC (rev 40497)
+++ CMF/branches/tseaver-viewification/GenericSetup/utils.py	2005-12-02 18:15:45 UTC (rev 40498)
@@ -21,7 +21,7 @@
 from xml.dom.minidom import Document
 from xml.dom.minidom import Element
 from xml.dom.minidom import Node
-from xml.dom.minidom import parseString as domParseString
+from xml.dom.minidom import parseString
 from xml.sax.handler import ContentHandler
 
 import Products
@@ -29,13 +29,22 @@
 from Acquisition import Implicit
 from Globals import InitializeClass
 from Globals import package_home
+try:
+    from OFS.interfaces import IOrderedContainer
+except:
+    #BBB: for Zope 2.8
+    from Products.Five.bbb.OFS_interfaces import IOrderedContainer
 from TAL.TALDefs import attrEscape
+from zope.app import zapi
 from zope.interface import implements
+from zope.interface import providedBy
 
 from exceptions import BadRequest
+from interfaces import IBody
 from interfaces import INodeExporter
 from interfaces import INodeImporter
-from interfaces import PURGE
+from interfaces import ISetupContext
+from interfaces import PURGE, UPDATE
 from permissions import ManagePortal
 
 
@@ -161,7 +170,7 @@
         if reader is not None:
             xml = reader()
 
-        dom = domParseString(xml)
+        dom = parseString(xml)
         root = dom.documentElement
 
         return self._extractNode(root)
@@ -394,6 +403,36 @@
             node.writexml(writer, indent, addindent, newl)
 
 
+class BodyAdapterBase(object):
+
+    """Body im- and exporter base.
+    """
+
+    implements(IBody)
+
+    _LOGGER_ID = ''
+
+    def __init__(self, context, environ):
+        self.context = context
+        self.environ = environ
+        self._logger = environ.getLogger(self._LOGGER_ID)
+
+    def _exportBody(self):
+        """Export the object as a file body.
+        """
+        return ''
+
+    def _importBody(self, body):
+        """Import the object from the file body.
+        """
+
+    body = property(_exportBody, _importBody)
+
+    mime_type = 'text/plain'
+
+    suffix = ''
+
+
 class NodeAdapterBase(object):
 
     """Node im- and exporter base.
@@ -436,6 +475,32 @@
     def _convertToBoolean(self, val):
         return val.lower() in ('true', 'yes', '1')
 
+
+class XMLAdapterBase(BodyAdapterBase, NodeAdapterBase):
+
+    """XML im- and exporter base.
+    """
+
+    def _exportBody(self):
+        """Export the object as a file body.
+        """
+        doc = PrettyDocument()
+        doc.appendChild(self.exportNode(doc))
+        return doc.toprettyxml(' ')
+
+    def _importBody(self, body):
+        """Import the object from the file body.
+        """
+        mode = self.environ.shouldPurge() and PURGE or UPDATE
+        self.importNode(parseString(body).documentElement, mode=mode)
+
+    body = property(_exportBody, _importBody)
+
+    mime_type = 'text/xml'
+
+    suffix = '.xml'
+
+
 class ObjectManagerHelpers(object):
 
     """ObjectManager im- and export helpers.
@@ -443,11 +508,21 @@
 
     def _extractObjects(self):
         fragment = self._doc.createDocumentFragment()
-        for obj in self.context.objectValues():
+        objects = self.context.objectValues()
+        if not IOrderedContainer.providedBy(self.context):
+            objects.sort(lambda x,y: cmp(x.getId(), y.getId()))
+        for obj in objects:
             exporter = INodeExporter(obj, None)
-            if exporter is None:
-                continue
-            fragment.appendChild(exporter.exportNode(self._doc))
+            if exporter:
+                node = exporter.exportNode(self._doc)
+                fragment.appendChild(node)
+            else:
+                adapters = zapi.getService(zapi.servicenames.Adapters)
+                if adapters.lookup((providedBy(obj), ISetupContext), IBody):
+                    node = self._doc.createElement('object')
+                    node.setAttribute('name', obj.getId())
+                    node.setAttribute('meta_type', obj.meta_type)
+                    fragment.appendChild(node)
         return fragment
 
     def _purgeObjects(self):
@@ -470,7 +545,7 @@
                         parent._setObject(obj_id, mt_info['instance'](obj_id))
                         break
                 else:
-                    raise ValueError('unknown meta_type \'%s\'' % obj_id)
+                    raise ValueError('unknown meta_type \'%s\'' % meta_type)
 
             if child.hasAttribute('insert-before'):
                 insert_before = child.getAttribute('insert-before')
@@ -494,7 +569,9 @@
                         pass
 
             obj = getattr(self.context, obj_id)
-            INodeImporter(obj).importNode(child, mode)
+            importer = INodeImporter(obj, None)
+            if importer:
+                importer.importNode(child, mode)
 
 
 class PropertyManagerHelpers(object):
@@ -588,3 +665,36 @@
                 prop_value = self._getNodeText(child).encode('utf-8')
 
             obj._updateProperty(prop_id, prop_value)
+
+
+def exportObjects(parent, parent_path, context):
+    """ Export subobjects recursively.
+    """
+    for obj in parent.objectValues():
+        path = '%s/%s' % (parent_path, obj.getId().replace(' ', '_'))
+
+        exporter = zapi.queryMultiAdapter((obj, context), IBody)
+        if exporter:
+            filename = '%s%s' % (path, exporter.suffix)
+            body = exporter.body
+            if body is not None:
+                context.writeDataFile(filename, body, exporter.mime_type)
+
+        if getattr(obj, 'objectValues', False):
+            exportObjects(obj, path, context)
+
+def importObjects(parent, parent_path, context):
+    """ Import subobjects recursively.
+    """
+    for obj in parent.objectValues():
+        path = '%s/%s' % (parent_path, obj.getId().replace(' ', '_'))
+
+        importer = zapi.queryMultiAdapter((obj, context), IBody)
+        if importer:
+            filename = '%s%s' % (path, importer.suffix)
+            body = context.readDataFile(filename)
+            if body is not None:
+                importer.body = body
+
+        if getattr(obj, 'objectValues', False):
+            importObjects(obj, path, context)



More information about the CMF-checkins mailing list