Skip to content

/ Zope / gocept svn checkins / Archive / 2005 / 2005-06 / SVN: r3034 - in AlphaFlow/trunk/doc/examples/MusicReview: . Extensions workflows

[ << ] [ >> ]

[ SVN: r2996 - Formulon/tags/Formulon-0_3_6-release ... ] [ SVN: r3058 - CMFLinkChecker/trunk / Christian ... ]

SVN: r3034 - in AlphaFlow/trunk/doc/examples/MusicReview: . Extensions workflows
Christian Theune <ct(at)gocept.com>
2005-06-21 09:33:35 [ FULL ]
Author: ctheune
Date: Tue Jun 21 09:35:09 2005
New Revision: 3034

Added:
   AlphaFlow/trunk/doc/examples/MusicReview/interfaces.py
   AlphaFlow/trunk/doc/examples/MusicReview/musicreview.py
      - copied, changed from r3030,
AlphaFlow/trunk/doc/examples/MusicReview/dummycontent.py
   AlphaFlow/trunk/doc/examples/MusicReview/version.txt
   AlphaFlow/trunk/doc/examples/MusicReview/workflows/review.alf
      - copied, changed from r3030,
AlphaFlow/trunk/doc/examples/MusicReview/workflows/task.alf
Removed:
   AlphaFlow/trunk/doc/examples/MusicReview/dummycontent.py
   AlphaFlow/trunk/doc/examples/MusicReview/workflows/task.alf
Modified:
   AlphaFlow/trunk/doc/examples/MusicReview/Extensions/Install.py
   AlphaFlow/trunk/doc/examples/MusicReview/__init__.py
   AlphaFlow/trunk/doc/examples/MusicReview/config.py
Log:
 - more or less working example for a workflow application


Modified: AlphaFlow/trunk/doc/examples/MusicReview/Extensions/Install.py
==============================================================================
--- AlphaFlow/trunk/doc/examples/MusicReview/Extensions/Install.py	(original)
+++ AlphaFlow/trunk/doc/examples/MusicReview/Extensions/Install.py	Tue Jun 21
09:35:09 2005
(at)(at) -1,21 +1,5 (at)(at)
-# AlphaFlowDemo - demonstration of using AlphaFlow
-#
-# Copyright 2004-2005 gocept gmbh & co. kg
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#
+# Copyright (c) 2005 gocept gmbh & co. kg
+# See also LICENSE.txt
 # $Id$
 """Installer"""
 
(at)(at) -27,7 +11,7 (at)(at)
 from Products.Archetypes.Extensions.utils import installTypes
 
 # Project imports
-from Products.AlphaFlowDemo import config
+from Products.MusicReview import config
 
 
 
(at)(at) -41,9 +25,3 (at)(at)
     print >>out, "Successfully installed %s." % config.PROJECTNAME
     return out.getvalue()
 
-
-def uninstall(self):
-    out = StringIO()
-    print >>out, 'Uninstalling...'
-
-    return out.getvalue()

Modified: AlphaFlow/trunk/doc/examples/MusicReview/__init__.py
==============================================================================
--- AlphaFlow/trunk/doc/examples/MusicReview/__init__.py	(original)
+++ AlphaFlow/trunk/doc/examples/MusicReview/__init__.py	Tue Jun 21 09:35:09
2005
(at)(at) -3,28 +3,20 (at)(at)
 # $Id$
 """Zope initialization code"""
 
-# Plone imports
+from Products.Archetypes.public import listTypes, process_types
 from Products.CMFCore.utils import ContentInit
-from Products.Archetypes.public import process_types, listTypes
-from Products.ATContentTypes.interfaces.IATTopic import \
-    IATTopic, IATTopicCriterion
-
-# Project imports
-from Products.AlphaFlowDemo.config import \
-    PROJECTNAME, ADD_CONTENT_PERMISSION, ADD_TOPIC_PERMISSION
-
-
-
-def initialize_content(context):
-    from Products.AlphaFlowDemo import dummycontent
-    from Products.ATContentTypes import initialize as initialize_atcontent
-    from types import FunctionType
-    # Call ATCT initialization with our globals/context, this registers
-    # our types just like their types
-    init = FunctionType(initialize_atcontent.func_code, globals())
-    init(context)
-
+from Products.MusicReview import config, musicreview 
 
 
 def initialize(context):
-    initialize_content(context)
+    listOfTypes = listTypes(config.PROJECTNAME)
+    content_types, constructors, ftis = process_types(
+        listOfTypes,
+        config.PROJECTNAME)
+    ContentInit(
+        config.PROJECTNAME + ' Content',
+        content_types = tuple(content_types),
+        permission = config.ADD_CONTENT_PERMISSION,
+        extra_constructors = tuple(constructors),
+        fti = ftis,
+        ).initialize(context)

Modified: AlphaFlow/trunk/doc/examples/MusicReview/config.py
==============================================================================
--- AlphaFlow/trunk/doc/examples/MusicReview/config.py	(original)
+++ AlphaFlow/trunk/doc/examples/MusicReview/config.py	Tue Jun 21 09:35:09 2005
(at)(at) -2,8 +2,38 (at)(at)
 # See also LICENSE.txt
 # $Id$
 
-PROJECTNAME = 'AlphaFlowDemo'
+from Products.CMFCore import CMFCorePermissions
+from Products.Archetypes import public as atapi
+PROJECTNAME = 'MusicReview'
+ADD_CONTENT_PERMISSION = CMFCorePermissions.AddPortalContent
 
-from Products.ATContentTypes import Permissions
-ADD_CONTENT_PERMISSION = Permissions.ADD_CONTENT_PERMISSION
-ADD_TOPIC_PERMISSION = Permissions.ADD_TOPIC_PERMISSION
+ratingVocabulary = atapi.DisplayList([
+                    (1, "1"),
+                    (2, "2"),
+                    (3, "3"),
+                    (4, "4"),
+                    (5, "5")
+                    ])
+
+
+genreVocabulary =  \
+    ["Acid", "Acid Jazz", "Acid Punk", "Alternative", 
+     "AlternRock", "Ambient", "Bass", "Blues", "Cabaret", 
+     "Christian Rap", "Classical", "Classic Rock", "Comedy",
+     "Country", "Cult", "Dance", "Darkwave", "Death Metal", 
+     "Disco", "Dream", "Electronic", "Ethnic", "Eurodance", 
+     "Euro-Techno", "Funk", "Fusion", "Game", "Gangsta", 
+     "Gospel", "Gothic", "Grunge", "Hard Rock", "Hip-Hop", 
+     "House", "Industrial", "Instrumental", 
+     "Instrumental Pop", "Instrumental Rock", "Jazz", 
+     "Jazz+Funk", "Jungle", "Lo-Fi", "Meditative", "Metal", 
+     "Musical", "Native American", "New Age", "New Wave", 
+     "Noise", "Oldies", "Other", "Polka", "Pop", "Pop-Folk", 
+     "Pop/Funk", "Pranks", "Psychadelic", "Punk", "Rap", 
+     "Rave", "R&B", "Reggae", "Retro", "Rock", "Rock & Roll",
+     "Showtunes", "Ska", "Soul", "Sound Clip", "Soundtrack", 
+     "Southern Rock", "Space", "Techno", "Techno-Industrial",
+     "Top 40", "Trailer", "Trance", "Tribal", "Trip-Hop", 
+     "Vocal", ]
+
+genreVocabulary = atapi.DisplayList(zip(genreVocabulary, genreVocabulary))

Added: AlphaFlow/trunk/doc/examples/MusicReview/interfaces.py
==============================================================================
--- (empty file)
+++ AlphaFlow/trunk/doc/examples/MusicReview/interfaces.py	Tue Jun 21 09:35:09
2005
(at)(at) -0,0 +1,22 (at)(at)
+# Copyright (c) 2005 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id: dummycontent.py 3030 2005-06-20 11:13:24Z ctheune $
+
+from Products.Archetypes import public as atapi
+
+from Products.MusicReview import config
+
+musicReviewSchema = atapi.BaseSchema + \
+        atapi.Schema((
+    atapi.FloatField("price"),
+    atapi.IntegerField("year"),
+    atapi.StringField("genre",
+                    vocabulary=config.genreVocabulary,
+                    widget=atapi.SelectionWidget(label="Genre")),
+    atapi.TextField("review",
+                    widget=atapi.TextAreaWidget(label="Review")),
+    atapi.IntegerField("rating",
+                    vocabulary=config.ratingVocabulary,
+                    widget=atapi.SelectionWidget(label="Rating")),
+    ))
+

Copied: AlphaFlow/trunk/doc/examples/MusicReview/musicreview.py (from r3030,
AlphaFlow/trunk/doc/examples/MusicReview/dummycontent.py)
==============================================================================
--- AlphaFlow/trunk/doc/examples/MusicReview/dummycontent.py	(original)
+++ AlphaFlow/trunk/doc/examples/MusicReview/musicreview.py	Tue Jun 21 09:35:09
2005
(at)(at) -1,7 +1,7 (at)(at)
-# Copyright (c) 2004-2005 gocept gmbh & co. kg
+# Copyright (c) 2005 gocept gmbh & co. kg
 # See also LICENSE.txt
 # $Id$
-"""Demonstration how to implement a content type with AlphaFlow
+"""Module containing the MusicReview content class.
 """
 
 # Plone imports
(at)(at) -9,26 +9,17 (at)(at)
 
 # Project imports
 from Products.AlphaFlow.workflowedobject import AlphaFlowed
-from Products.AlphaFlowDemo import config
+from Products.MusicReview import config, interfaces
 
+class MusicReview(AlphaFlowed, atapi.BaseContent):
+    """The MusicReview content class."""
 
-
-class DummyContent(AlphaFlowed, atapi.BaseContent):
+    portal_type = archetype_name = meta_type = 'MusicReview'
 
-    portal_type = archetype_name = meta_type = 'DummyContent'
     __implements__ = (atapi.BaseContent.__implements__ +
         AlphaFlowed.__implements__)
 
+    schema = interfaces.musicReviewSchema
 
-
-class DummyFolder(AlphaFlowed, atapi.BaseFolder):
-
-    portal_type = archetype_name = meta_type = 'DummyFolder'
-    __implements__ = (atapi.BaseFolder.__implements__ + 
-        AlphaFlowed.__implements__)
-
-
-
-atapi.registerType(DummyContent, config.PROJECTNAME)
-atapi.registerType(DummyFolder, config.PROJECTNAME)
 
+atapi.registerType(MusicReview)

Added: AlphaFlow/trunk/doc/examples/MusicReview/version.txt
==============================================================================
--- (empty file)
+++ AlphaFlow/trunk/doc/examples/MusicReview/version.txt	Tue Jun 21 09:35:09
2005
(at)(at) -0,0 +1 (at)(at)
+1.0

Copied: AlphaFlow/trunk/doc/examples/MusicReview/workflows/review.alf (from
r3030, AlphaFlow/trunk/doc/examples/MusicReview/workflows/task.alf)
==============================================================================
--- AlphaFlow/trunk/doc/examples/MusicReview/workflows/task.alf	(original)
+++ AlphaFlow/trunk/doc/examples/MusicReview/workflows/review.alf	Tue Jun 21
09:35:09 2005
(at)(at) -1,39 +1,43 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow id="task"
-          title="Demo: Assigning a task"
-          description="A member is assigned the task of editing the
-                       content object. This is one of the simplest
-                       possible AlphaFlow workflows."
-          startActivity="give_to_assignee"
-          onlyAllowRoles="Manager,Reviewer,Member">
-
-    <permission-change id="give_to_assignee"
-                       title="Make object editable by assignee"
-                       continue_activity="edit_object">
-
-        <permission id="Modify portal content"
-                    acquire="False"
-                    roles="Manager,Owner,Assignee" />
-
-    </permission-change>
-
-    <task id="edit_object"
-          title="Edit the content object"
-          completion_activity="take_from_assignee">
-
-        <assignees kind="possible"
-                   roles="Member" />
-
-    </task>
-
-    <permission-change id="take_from_assignee"
-                       title="Make object read-only for assignee">
-
-        <permission id="Modify portal content"
-                    acquire="True"
-                    roles="Manager,Owner" />
-
-    </permission-change>
+<workflow id="review"
+          title="Create a new music review"
+          description="A new music review is requested and reviewed."
+          startActivity="configure, dc_private"
+          onlyAllowRoles="Manager Reviewer">
+
+          <configuration
+              id="configure"
+              title="Select author"
+              configures="write_review"
+              continue_activity="write_review"
+              >
+                <assignees kind="actual"
expression="python:[object.owner_info()['id']]"/>
+          </configuration>
+          
+          <task id="write_review"
+              title="Write a music review"
+              completion_activity="review_review dc_pending"
+              content_roles="Editor"
+              >
+              <assignees kind="possible" roles="Member" />
+          </task>
+
+    <decision id="review_review"
+        decision_notice=""
+        title="Check review for spelling and bad language."
+        accept_activity="dc_public"
+        reject_activity="write_review"
+        decision_modus="all_yes">
+        <assignees kind="actual"
expression="python:[object.owner_info()['id']]"/>
+    </decision>
+
+    <dcworkflow id="dc_private" status="private"
+        title="Label as private"/>
+    <dcworkflow id="dc_pending" status="pending"
+        title="Label as pending"/>
+    
+    <dcworkflow id="dc_public" status="public"
+        title="Label as public"/>
 
 </workflow>

SVN: r3041 - in AlphaFlow/trunk: . activities adapters tests tests/workflows
Michael Howitz <mh(at)gocept.com>
2005-06-21 17:34:50 [ FULL ]
Author: mac
Date: Tue Jun 21 17:35:57 2005
New Revision: 3041

Modified:
   AlphaFlow/trunk/activities/gates.py
   AlphaFlow/trunk/activities/interfaces.py
   AlphaFlow/trunk/activities/review.py
   AlphaFlow/trunk/activities/task.py
   AlphaFlow/trunk/activity.py
   AlphaFlow/trunk/adapters/activitiesadapter.py
   AlphaFlow/trunk/interfaces.py
   AlphaFlow/trunk/process.py
   AlphaFlow/trunk/tests/test_definition.py
   AlphaFlow/trunk/tests/test_editor.py
   AlphaFlow/trunk/tests/workflows/cachetest.alf
   AlphaFlow/trunk/tests/workflows/catalog_security.alf
   AlphaFlow/trunk/tests/workflows/condition.alf
   AlphaFlow/trunk/tests/workflows/configuration_all.alf
   AlphaFlow/trunk/tests/workflows/decision.alf
   AlphaFlow/trunk/tests/workflows/email.alf
   AlphaFlow/trunk/tests/workflows/expression_assign.alf
   AlphaFlow/trunk/tests/workflows/expressionn_assign.alf
   AlphaFlow/trunk/tests/workflows/getviewurl.alf
   AlphaFlow/trunk/tests/workflows/multi_review.alf
   AlphaFlow/trunk/tests/workflows/multi_review_with_config.alf
   AlphaFlow/trunk/tests/workflows/routing_example.alf
   AlphaFlow/trunk/tests/workflows/task.alf
Log:
zwischenstand xml export fuer roman

Modified: AlphaFlow/trunk/activities/gates.py
==============================================================================
--- AlphaFlow/trunk/activities/gates.py	(original)
+++ AlphaFlow/trunk/activities/gates.py	Tue Jun 21 17:35:57 2005
(at)(at) -8,12 +8,13 (at)(at)
 from Products.AlphaFlow.workitem import registerWorkItem, BaseWorkItem
 from Products.AlphaFlow.activity import registerActivity,
BaseAutomaticActivity
 from Products.AlphaFlow.exception import ConfigurationError
-from Products.AlphaFlow.interfaces import IDaemonActivity
+from Products.AlphaFlow.interfaces import IDaemonActivity, IGateActivity
 
 
 class GateActivity(BaseAutomaticActivity):
 
-    __implements__ = BaseAutomaticActivity.__implements__ + (IDaemonActivity,)
+    __implements__ = BaseAutomaticActivity.__implements__ + (IDaemonActivity,
+                                                             IGateActivity)
 
     meta_type = "AlphaFlow Gate Activity"
     activity_type = "gate"

Modified: AlphaFlow/trunk/activities/interfaces.py
==============================================================================
--- AlphaFlow/trunk/activities/interfaces.py	(original)
+++ AlphaFlow/trunk/activities/interfaces.py	Tue Jun 21 17:35:57 2005
(at)(at) -175,6 +175,9 (at)(at)
 class IRoutingWorkItem(IWorkItem):
     """a Routing workitem"""
 
+class IGateActivity(IAutomaticActivity):
+    """Gate to support routing mechanisms."""
+
 class IConfigurationActivity(IAssignableActivity):
     """configuration activity
 
(at)(at) -189,6 +192,7 (at)(at)
     """WorkItem simulating DC Workflow state changes"""
 
 
+
 ### Deprecated stuff
 
 

Modified: AlphaFlow/trunk/activities/review.py
==============================================================================
--- AlphaFlow/trunk/activities/review.py	(original)
+++ AlphaFlow/trunk/activities/review.py	Tue Jun 21 17:35:57 2005
(at)(at) -23,8 +23,12 (at)(at)
 from Products.AlphaFlow.action import Action
 
 
+ # deprecated, use DecisionActivity instead
 class ReviewActivity(BaseAssignableActivity):
-    """assignable review / user based"""
+    """assignable review / user based
+
+    DEPRECATED, use DecisionActivity instead
+    """
 
     __implements__ = (IReviewActivity,) +
BaseAssignableActivity.__implements__
 
(at)(at) -96,7 +100,7 (at)(at)
                     'label':'on accept'})
         return acts
 
-
+ # deprecated, use DecisionActivity instead
 class RolebasedReviewActivity(ReviewActivity):
 
     activity_type = 'rolebased-review'
(at)(at) -104,6 +108,7 (at)(at)
 
 
 
+ # deprecated, use DecisionActivity instead
 class ReviewWorkItem(BaseAssignableWorkItem):
 
     __implements__ = (IReviewWorkItem,) +
BaseAssignableWorkItem.__implements__
(at)(at) -231,6 +236,7 (at)(at)
 
 
 
+# deprecated, use DecisionActivity instead
 class RolebasedReviewWorkItem(ReviewWorkItem):
     
     activity_type = 'rolebased-review'
(at)(at) -288,4 +294,3 (at)(at)
 
 registerWorkItem(ReviewWorkItem)
 registerWorkItem(RolebasedReviewWorkItem)
-

Modified: AlphaFlow/trunk/activities/task.py
==============================================================================
--- AlphaFlow/trunk/activities/task.py	(original)
+++ AlphaFlow/trunk/activities/task.py	Tue Jun 21 17:35:57 2005
(at)(at) -18,6 +18,7 (at)(at)
     registerActivity, BaseAssignableActivity
 from Products.AlphaFlow import config, utils
 from Products.AlphaFlow.action import Action
+from Products.AlphaFlow.exception import ConfigurationError
 
 
 class TaskActivity(BaseAssignableActivity):
(at)(at) -61,7 +62,9 (at)(at)
                
utils.flexSplit(node.getAttribute("completion_activity").encode("ascii"))
             )
         if node.hasAttribute("assignees"):
-            self.assignees = node.getAttribute("assignees")
+            raise ConfigurationError, \
+                  "The assignees attribute is deprecated, use assignees tag
instead!"
+#            self.assignees = node.getAttribute("assignees")
 
     def graphGetPossibleChildren(self):
         """Return a list of possible following activities. (List of ids)"""

Modified: AlphaFlow/trunk/activity.py
==============================================================================
--- AlphaFlow/trunk/activity.py	(original)
+++ AlphaFlow/trunk/activity.py	Tue Jun 21 17:35:57 2005
(at)(at) -44,7 +44,7 (at)(at)
         has = node.hasAttribute
         get = node.getAttribute
         if has("title"):
-            self.title = get('title').encode("utf-8")
+            self.title = get('title')#.encode("utf-8")
         if has("sort"):
             pri = get('sort')
             try:
(at)(at) -93,10 +93,6 (at)(at)
         xml = adapter.getXML()
         return xml
 
-    def getProperties(self):
-        """returns the properties of the activity"""
-        adapter = getActivitiesAdapter(self)
-        return adapter.getProperties()
 
 InitializeClass(BaseActivity)
 
(at)(at) -245,7 +241,7 (at)(at)
     security.declarePrivate('_parse_assignee')
     def _parse_assignee(self, assignee):
         """helper for configureFromDOMNode
-        """
+       """
         has = assignee.hasAttribute
         get = assignee.getAttribute
 

Modified: AlphaFlow/trunk/adapters/activitiesadapter.py
==============================================================================
--- AlphaFlow/trunk/adapters/activitiesadapter.py	(original)
+++ AlphaFlow/trunk/adapters/activitiesadapter.py	Tue Jun 21 17:35:57 2005
(at)(at) -4,173 +4,298 (at)(at)
 
 # python imports
 from types import TupleType, StringType
+from xml.dom import minidom
 
 # sibling imports
-from Products.AlphaFlow.interfaces import ITaskActivity,\
-    IDecisionActivity, IAlarmActivity, IDCWorkFlowActivity
+from Products.AlphaFlow import interfaces
 from Products.AlphaFlow.adapters import adapter
 
+
+#####################
+# abstract activities
+
 class ActivityAdapter(adapter.Adapter):
     """Baseclass for all activity adapters."""
 
-    # properties in activity (source in XML-File/request.form, attribute on
activity)
-    _properties = (('id', None), # id is handled separately
-                   ('title', 'title'), )
+    # properties in activity (attribute name in XML-File,
+    #                         attribute name on activity,
+    #                         default if not evaluates to False)
+    _simple_properties = (('id', None, False), # id is handled separately
+                          ('title', 'title', False),
+                          ('sort', 'sortPriority', False),
+                          ('nonEditableFields', 'nonEditableFields', False),
+                          ('startActivity', 'startActivity', False),
+                          )
+    
+    def writeDOM(self, node):
+        """Get the activity as XML-MiniDom.
+
+        node ... node or document
+        Returns the created activity node
+        """
+        if hasattr(node, 'ownerDocument') and node.ownerDocument is not None:
+            doc = node.ownerDocument # node inside
+        else:
+            doc = node # Document itself
+        activity =
node.appendChild(doc.createElement(self.context.activity_type))
+        self._writeSimplePropertiesToDOM(activity)
+        self._writeComplexPropertiesToDOM(activity)
+        return activity
+
+    def getXML(self):
+        """Get the activity as string XML document."""
+        doc = minidom.Document()
+        self.writeDOM(doc)
+        return doc.toxml()
 
 
-    def changeProperties(self, form):
-        """Change the property values of the activity.
+    def _writeComplexPropertiesToDOM(self, node):
+        """Write properties not in self._simple_properties to given dom
node."""
+        pass
 
-        form ... dict {'prop-name': prop-value}
-        """
-        for src, dest in self._properties:
-            if src == 'id':
-                continue
-            setattr(self.context, dest, form.get(src,
-                                                 getattr(self.context, dest)))
-
-    def getProperties(self):
-        """Get properties of activity as a dict."""
-        res = {}
-        for dict_key, attr_name in self._properties:
-            if dict_key == 'id':
+
+    def _writeSimplePropertiesToDOM(self, node):
+        """Write self._simple_properties to given dom node."""
+        for xml_attr, python_attr, default in self._simple_properties:
+            if xml_attr == 'id':
                 value = self.context.getId()
             else:
-                value = getattr(self.context, attr_name)
-            if value is not None:
-                res[dict_key] = value
-        return res
-    
+                value = getattr(self.context, python_attr)
+            if (default and value != default) or \
+                   (not default and value):
+                node.setAttribute(xml_attr, self._convertToXML(value))
+
+
+    def _convertToXML(self, value):
+        """Convert a value to XML notation."""
+        if isinstance(value, basestring):
+            return value
+        elif isinstance(value, tuple) or isinstance(value, list):
+            return ' '.join(value)
+        elif isinstance(value, int):
+            return str(value)
+        raise ValueError, "Don't know how to handle '%s'." % value
+        
 
        
 class BaseAutomaticActivityAdapter(ActivityAdapter):
 
-    _properties = ActivityAdapter._properties + \
-                  (('continue_activity', 'continue_activity'),
-                   )
+    _simple_properties = ActivityAdapter._simple_properties + \
+                         (('continue_activity', 'continue_activity', False),
+                          )
 
 
 class BaseAssignableActivityAdapter(ActivityAdapter):
 
-    _properties = ActivityAdapter._properties + \
-                  (('roles', 'roles'),
-                   ('kind', 'assigneesKind'),
-                   ('expression', 'assigneesExpression'),
-                   )
+    _simple_properties = ActivityAdapter._simple_properties + \
+                         (('view_url_expr',
+                           'viewUrlExpression',
+                           'string:${content/absolute_url}/view'),
+                          ('content_roles', 'contentRoles', False)
+                          )
+
+    def _writeComplexPropertiesToDOM(self, node):
+        """Write properties not in self._simple_properties to given dom
node."""
+        BaseAssignableActivityAdapter.inheritedAttribute(
+            '_writeComplexPropertiesToDOM')(self, node)
+        if self.context.assigneesKind == "possible" and self.context.roles ==
():
+            return # no assignees tag on default behavior
+        el = node.ownerDocument.createElement('assignees')
+        assignees = node.appendChild(el)
+        data = (('kind', 'assigneesKind'),
+                ('roles', 'roles'),
+                ('expression', 'assigneesExpression'),
+                )
+        for xml_attr, python_attr in data:
+            value = getattr(self.context, python_attr)
+            if value is not None:
+                assignees.setAttribute(xml_attr, self._convertToXML(value))
+
+
+class BaseTalesActivityAdapter(BaseAutomaticActivityAdapter):
+
+    _simple_properties = ActivityAdapter._simple_properties + \
+                         (('expression', 'expression', False),
+                          )
+
 
+#####################
+# concrete activities
 
-class BaseTalesActivityAdapter(ActivityAdapter):
 
-    _properties = ActivityAdapter._properties + \
-                  (('expression', 'expression'),
-                   )
 
-class TaskActivityAdapter(ActivityAdapter):
 
-    _properties = ActivityAdapter._properties + \
-                  (('title', 'title'),
-                   ('roles', 'roles'),
-                   ('completion_activity', 'completion_activity'))
+class TaskActivityAdapter(BaseAssignableActivityAdapter):
+
+    _simple_properties = ActivityAdapter._simple_properties + \
+                         (('completion_activity', 'completion_activity',
False),
+                          )
        
-class DecisionActivityAdapter(BaseAssignableActivityAdapter):
 
-    _properties = BaseAssignableActivityAdapter._properties + \
-                  (('roles', 'roles'),
-                   ('decision_notice', 'decision_notice'),
-                   ('decision_modus', 'decision_modus'))
-                   
-    
-    def changeProperties(self, form):
-        """changes properties on activities"""
-        DecisionActivityAdapter.inheritedAttribute('changeProperties')(self,
form)
-        childs = self.context.acquireProcess().listActivityIds()
-        tuples = ['reject_activity', 'accept_activity']
-        
-        for t in tuples:
-            act = form.get(t, getattr(self.context, t))
-               
-            if type(act) is TupleType:
-                for a in act:
-                    if a not in childs:
-                        return 
-            
-            if type(act) is StringType and\
-               act in childs:
-               act = (act,)
-            
-            setattr(self.context, t, act)
-
-
-    def getProperties(self):
-        result =
DecisionActivityAdapter.inheritedAttribute('getProperties')(self)
-        properties = ['reject_activity',
-                      'accept_activity']
-        for prop in properties:
-            result[prop] = getattr(self.context, prop)
+class RoutingActivityAdapter(ActivityAdapter):
 
-        return result
+    def _writeComplexPropertiesToDOM(self, node):
+        RoutingActivityAdapter.inheritedAttribute(
+            '_writeComplexPropertiesToDOM')(self, node)
+        process = self.context.acquireProcess()
+        for activity_id in self.context.routes + self.context.gates:
+            adapter = getActivitiesAdapter(process[activity_id])
+            adapter.writeDOM(node)
+
+class RecursionActivityAdapter(BaseAutomaticActivityAdapter):
+
+    _simple_properties = BaseAutomaticActivityAdapter._simple_properties + \
+                         (('recursion_activity', 'recursion_activity', False),
+                          ('break_activities', 'break_activities', False),
+                          ('optional_recursion', 'optional_recursion', 1),
+                          )
+
+class PermissionActivityAdapter(BaseAutomaticActivityAdapter):
+
+    def _writeComplexPropertiesToDOM(self, node):
+        PermissionActivityAdapter.inheritedAttribute(
+            '_writeComplexPropertiesToDOM')(self, node)
+        doc = node.ownerDocument
+        perm_attrs = (('id', 'permission'),
+                      ('roles', 'roles'),
+                      ('acquire', 'acquire'),
+                      )
+        for permObj in self.context.permissions:
+            perm = node.appendChild(doc.createElement('permission'))
+            for xml_attr, py_attr in perm_attrs:
+                perm.setAttribute(xml_attr,
+                                  self._convertToXML(getattr(permObj,
+                                                             py_attr)))
+
+class NTaskActivityAdapter(BaseAssignableActivityAdapter):
+
+    def _writeComplexPropertiesToDOM(self, node):
+        NTaskActivityAdapter.inheritedAttribute(
+            '_writeComplexPropertiesToDOM')(self, node)
+        doc = node.ownerDocument
+        exit_attrs = (('id', 'id'),
+                      ('title', 'title'),
+                      ('activities', 'activities'),
+                      )
+        for exitObj in self.context.exits:
+            exit_node = node.appendChild(doc.createElement('exit'))
+            for xml_attr, py_attr in exit_attrs:
+                exit_node.setAttribute(xml_attr,
+                                       self._convertToXML(getattr(exitObj,
+                                                                  py_attr)))
+
+class EMailActivityAdapter(BaseAutomaticActivityAdapter):
+
+    _simple_properties = BaseAutomaticActivityAdapter._simple_properties + \
+                         (('template', 'template', False),
+                          ('mailSubject',
+                           'mailSubject',
+                           'AlphaFlow notification message'),
+                          )
+    def _writeComplexPropertiesToDOM(self, node):
+        EMailActivityAdapter.inheritedAttribute(
+            '_writeComplexPropertiesToDOM')(self, node)
+        doc = node.ownerDocument
+        for recObj in self.context.getRecipientModes():
+            rec_node = node.appendChild(doc.createElement('recipient'))
+            mode_name = recObj.mode_name
+            rec_node.setAttribute('type', mode_name)
+            if mode_name == 'actual_role':
+                rec_node.setAttribute('roles',
+                                      self._convertToXML(recObj.roles))
 
-    def getXML(self):
-        element = "<decision\n"
-        assignees_tag = "><assignees\n"
-        properties = self.getProperties()
         
-        for key, val in properties.items():
-            if key in ['kind', 'roles']:
-                assignees_tag += """\t%s="%s"\n""" %(key, val)
-            else:
-                element += """\t%s="%s"\n""" %(key, val)
+class GateActivityAdapter(BaseAutomaticActivityAdapter):
+
+    _simple_properties = BaseAutomaticActivityAdapter._simple_properties + \
+                         (('mode', 'mode', False),
+                          )
+
         
-        element += '%s />' % assignees_tag
-        element += '</decision>'
-        return element
-
-class AlarmActivityAdapter(ActivityAdapter):
-    pass
-# XXX untested!
-#     def changeProperties(self, form):
-#         from Products.PageTemplates.Expressions import getEngine
-#         expr = form.get('expression', self.context.expression)
-#         engine = getEngine()
-#         expr = engine.compile(expr)
-#         context = engine.getContext()
-#         try:
-#             context.evaluate(expr)
-#         except KeyError:
-#             return
-#         self.context.expression = expr
-#         self._changePropertiesHelper(form)
-       
+class DecisionActivityAdapter(BaseAssignableActivityAdapter):
 
+    _simple_properties = BaseAssignableActivityAdapter._simple_properties + \
+                         (('decision_notice', 'decision_notice', False),
+                          ('decision_modus', 'decision_modus', False),
+                          ('reject_activity', 'reject_activity', False),
+                          ('accept_activity', 'accept_activity', False),
+                          )
+                   
 class DCWorkFlowActivityAdapter(BaseAutomaticActivityAdapter):
 
-# XXX what's that? 
-#     def changePropertiesHelper(self, form):
-#         self._changePropertiesHelper(form)
-#         newstatus = form.get('status', self.context.status)
-#         if newstatus in self.context.status_options:
-#             self.context.status = newstatus
-
-    _properties = BaseAutomaticActivityAdapter._properties + \
-                  (('status', 'status'),
-                   )
-                   
+    _simple_properties = BaseAutomaticActivityAdapter._simple_properties + \
+                         (('status', 'status', False),
+                          )
+
+class ConfigurationActivityAdapter(BaseAssignableActivityAdapter):
+
+    _simple_properties = BaseAssignableActivityAdapter._simple_properties + \
+                         (('continue_activity', 'continue_activity', False),
+                          )
+
+    def _writeComplexPropertiesToDOM(self, node):
+        ConfigurationActivityAdapter.inheritedAttribute(
+            '_writeComplexPropertiesToDOM')(self, node)
+        if self.context.configures is None: # marker for "all"
+            node.setAttribute('configures_all', 'true')
+        else:
+            node.setAttribute('configures',
+                              self._convertToXML(self.context.configures))
+
+class ConditionActivityAdapter(BaseTalesActivityAdapter):
+
+    _simple_properties = BaseTalesActivityAdapter._simple_properties + \
+                         (('continue_activity', 'continue_activity', False),
+                          )
+    
+# deprected
+class ReviewActivityAdapter(BaseAssignableActivityAdapter):
+
+    _simple_properties = BaseAssignableActivityAdapter._simple_properties + \
+                         (('review_notice', 'review_notice', False),
+                          ('reject_activity', 'reject_activity', False),
+                          ('accept_activity', 'accept_activity', False),
+                          )
 
-    def getXML(self):
-        properties = self.getProperties()
-        return """<dcworkflow id="%s" status="%s" />"""\
-                %(properties['id'], properties['status'])
         
         
 def getActivitiesAdapter(context):
-    if ITaskActivity.isImplementedBy(context):
-        return TaskActivityAdapter(context).__of__(context)
-    
-    if IDecisionActivity.isImplementedBy(context):
-        return DecisionActivityAdapter(context).__of__(context)
-
-    if IAlarmActivity.isImplementedBy(context):
-        return AlarmActivityAdapter(context).__of__(context)
+    if interfaces.ITaskActivity.isImplementedBy(context):
+        a = TaskActivityAdapter
+    elif interfaces.IRoutingActivity.isImplementedBy(context):
+        a = RoutingActivityAdapter
+    elif interfaces.IPermissionActivity.isImplementedBy(context):
+        a = PermissionActivityAdapter
+    elif interfaces.INTaskActivity.isImplementedBy(context):
+        a = NTaskActivityAdapter
+    elif interfaces.IEMailActivity.isImplementedBy(context):
+        a = EMailActivityAdapter
+    elif interfaces.IGateActivity.isImplementedBy(context):
+        a = GateActivityAdapter
+    elif interfaces.IExpressionActivity.isImplementedBy(context):
+        a = BaseTalesActivityAdapter # ExpressionActivity is alike
BaseTalesActivity
+    elif interfaces.IDecisionActivity.isImplementedBy(context):
+        a = DecisionActivityAdapter
+    elif interfaces.IDCWorkFlowActivity.isImplementedBy(context):
+        a = DCWorkFlowActivityAdapter
+    elif interfaces.IConfigurationActivity.isImplementedBy(context):
+        a = ConfigurationActivityAdapter
+    elif interfaces.IConditionActivity.isImplementedBy(context):
+        a = ConditionActivityAdapter
+    elif interfaces.IAlarmActivity.isImplementedBy(context):
+        a = BaseTalesActivityAdapter # AlarmActivity is alike
BaseTalesActivity
+    elif interfaces.IReviewActivity.isImplementedBy(context):
+        a = ReviewActivityAdapter # deprecated
+    # recursion
+    elif interfaces.IDaemonActivity.isImplementedBy(context):
+        a = RecursionActivityAdapter
+    # versioning
+    elif interfaces.IAutomaticActivity.isImplementedBy(context):
+        a =  BaseAutomaticActivityAdapter
+    else:
+        a = None
+
+    if a is not None:
+        return a(context).__of__(context)
+    raise ValueError, "No adapter for %s" % context
     
-    if IDCWorkFlowActivity.isImplementedBy(context):
-        return DCWorkFlowActivityAdapter(context).__of__(context)

Modified: AlphaFlow/trunk/interfaces.py
==============================================================================
--- AlphaFlow/trunk/interfaces.py	(original)
+++ AlphaFlow/trunk/interfaces.py	Tue Jun 21 17:35:57 2005
(at)(at) -252,14 +252,18 (at)(at)
             format
             REQUEST
         """
+    def changeProcessProperties(REQUEST):
+        """changes the workflow properties"""
+
     def getProcessDOM():
         """returns XML for self as dom node"""
     
     def getProcessXML(REQUEST=None):
-        """returns XML as a string containing editor information"""
+        """Returns XML as a string containing editor information"""
+
+    def exportAsXML():
+        """Exports process as XML-String."""
 
-    def changeProcessProperties(REQUEST):
-        """changes the workflow properties"""
 
 class IActivity(IDOMConfigurable):
     """A workflow activity.

Modified: AlphaFlow/trunk/process.py
==============================================================================
--- AlphaFlow/trunk/process.py	(original)
+++ AlphaFlow/trunk/process.py	Tue Jun 21 17:35:57 2005
(at)(at) -23,6 +23,7 (at)(at)
 from Products.AlphaFlow.activity import \
     listActivities, getActivity
 from Products.AlphaFlow.adapters.renderableadapter import getRenderableAdapter
+from Products.AlphaFlow.adapters.activitiesadapter import getActivitiesAdapter
 
 manage_addProcessForm=PageTemplateFile('www/addProcess', globals())
 def manage_addProcess(self, id, REQUEST=None):
(at)(at) -128,23 +129,40 (at)(at)
             activity = self.addActivity(act_id, act_type)
             activity.configureFromDOMNode(act_node)
             
+    security.declareProtected(config.EDIT_WORKFLOW, "getGraph")
+    def renderGraph(self, **kwargs):
+        """returns the rendered Graph
+         pass additional keyword arguments for 
+            
+            contenttype
+            format
+            REQUEST
+        """
+        adapter = getRenderableAdapter(self)
+        return adapter.renderGraph(**kwargs)
+
+
     security.declareProtected(config.MANAGE_WORKFLOW, 'getProcessDOM')
     def getProcessDOM(self):
         """returns XML for self as dom node"""
         xmlstr = "<workflow></workflow>"
-        start_activities = ",".join(self.startActivity)
-        roles = ",".join(self.roles)
+        start_activities = " ".join(self.startActivity)
+        roles = " ".join(self.roles)
+
+        attr_map = (('title', self.title),
+                    ('startActivity', start_activities),
+                    ('description', self.description),
+                    ('onlyAllowRoles', roles),
+                    )
         
         dom = minidom.parseString(xmlstr)
-        dom.documentElement.setAttribute('title', self.title)
-        dom.documentElement.setAttribute('startActivity',
-                                         start_activities)
-        dom.documentElement.setAttribute('description',
-                                         self.description)
-        dom.documentElement.setAttribute('onlyAllowRoles', roles)
+        for attr, value in attr_map:
+            if value:
+                dom.documentElement.setAttribute(attr, value)
         
         return dom 
     
+
     security.declareProtected(config.MANAGE_WORKFLOW, 'getProcessXML')
     def getProcessXML(self, REQUEST=None):
         """returns XML as a string containing editor information"""
(at)(at) -159,6 +177,27 (at)(at)
         
         return dom.toxml()
 
+    security.declareProtected(config.MANAGE_WORKFLOW, 'exportAsXML')
+    def exportAsXML(self):
+        """Exports process as XML-String."""
+        doc = self.getProcessDOM()
+        workflow = doc.getElementsByTagName('workflow')[0]
+        for activitiy in self.objectValues():
+            act_adapt = getActivitiesAdapter(activitiy)
+            if act_adapt is None:
+                continue # no adapter found
+            act_dom = act_adapt.writeDOM(workflow)
+        # remove activites which are inside routing activities and outside,
too
+        routes = doc.getElementsByTagName('route')
+        inside_routes = []
+        for route in routes:
+            for child in route.childNodes:
+                inside_routes.append(child.getAttribute('id'))
+        for node in workflow.childNodes[:]:
+            if node.getAttribute('id') in inside_routes:
+                workflow.removeChild(node)
+        return doc.toxml()
+            
     security.declareProtected(config.MANAGE_WORKFLOW,
                               'changeProcessProperties')
     def changeProcessProperties(self, REQUEST):
(at)(at) -182,17 +221,5 (at)(at)
     def _set_allowed_roles_restriction(self, roles):
         roles = tuple(roles)  # do not acquire
         utils.modifyRolesForPermission(self, config.INIT_PROCESS, roles)
-    
-    security.declareProtected(config.EDIT_WORKFLOW, "getGraph")
-    def renderGraph(self, **kwargs):
-        """returns the rendered Graph
-         pass additional keyword arguments for 
-            
-            contenttype
-            format
-            REQUEST
-        """
-        adapter = getRenderableAdapter(self)
-        return adapter.renderGraph(**kwargs)
 
 InitializeClass(Process)

Modified: AlphaFlow/trunk/tests/test_definition.py
==============================================================================
--- AlphaFlow/trunk/tests/test_definition.py	(original)
+++ AlphaFlow/trunk/tests/test_definition.py	Tue Jun 21 17:35:57 2005
(at)(at) -10,6 +10,7 (at)(at)
 from random import shuffle
 from StringIO import StringIO
 from tempfile import mktemp
+from xml.dom import minidom
 
 from Testing import ZopeTestCase
 
(at)(at) -38,6 +39,7 (at)(at)
 from Products.AlphaFlow.action import Action
 from Products.AlphaFlow.activities.review import ReviewWorkItem,
ReviewActivity
 from Products.AlphaFlow.utils import flexSplit
+from Products.AlphaFlow.exception import ConfigurationError
 
 _chars = 'abcdefghijklmnopqrstuvwxyz'
 _ids_used = {}
(at)(at) -67,12 +69,13 (at)(at)
                           (IWorkItem, BaseWorkItem),
                           (IAutomaticWorkItem, BaseAutomaticWorkItem),
                           (IAction, Action),
+                          (IProcess, Process),
                           (IReviewActivity, ReviewActivity),
                           (IReviewWorkItem, ReviewWorkItem)] + \
-            [ (IActivity, getActivity(act_id))
-               for act_id in listActivities() ] + \
-            [ (IWorkItem, getWorkItemClass(wi_id))
-              for wi_id in listWorkItems() ]
+                          [(IActivity, getActivity(act_id))
+                           for act_id in listActivities() ] + \
+                          [(IWorkItem, getWorkItemClass(wi_id))
+                           for wi_id in listWorkItems()]
    
     
     def test_xml_import(self):
(at)(at) -80,6 +83,66 (at)(at)
         portal = self.getPortal()
         alf = getToolByName(portal, "workflow_manager")
         test = alf.getProcess('test')
+
+    def test_xml_export(self):
+        def _find_in_dom(dom, tagname, id):
+            for tag in dom.getElementsByTagName(tagname):
+                if tag.getAttribute('id') == id:
+                    return tag
+        portal = self.getPortal()
+        alf = getToolByName(portal, "workflow_manager")
+        wf_dir = os.path.join(os.path.dirname(__file__), "workflows")
+
+        for wf_name in os.listdir(wf_dir):
+            if not wf_name.endswith('.alf'):
+                continue
+            wf_file = file(os.path.join(wf_dir, wf_name))
+            try:
+                alf.importWorkflowFromXML("test", wf_file)
+            except ConfigurationError:
+                alf.deleteProcess('test')
+                continue
+            wf_file.seek(0)
+            test = alf.getProcess('test')
+            print wf_name
+            test.exportAsXML().encode('utf8')
+            got_dom = minidom.parseString(str(test.exportAsXML()))
+            exp_dom = minidom.parseString(wf_file.read())
+            got_elems = got_dom.getElementsByTagName("*")
+            exp_elems = exp_dom.getElementsByTagName("*")
+            self.assertEqual(len(exp_elems),
+                             len(got_elems),
+                             "%s: exp: %s\ngot: %s" % (wf_name, exp_elems,
got_elems))
+            for got_tag in got_dom.getElementsByTagName("*"):
+                exp_tag = _find_in_dom(exp_dom, got_tag.nodeName,
+                                       got_tag.getAttribute('id'))
+                if exp_tag is None:
+                    import pdb; pdb.set_trace() #############################
+                self.failIf(exp_tag is None)
+                self.assertEqual(exp_tag.parentNode.nodeName,
+                                 got_tag.parentNode.nodeName)
+                if exp_tag.parentNode.ownerDocument is not None: # no Document
+                    self.assertEqual(exp_tag.parentNode.getAttribute('id'),
+                                     got_tag.parentNode.getAttribute('id'))
+                else:
+                    self.failUnless(got_tag.parentNode.ownerDocument is None)
+                self.assertEqual(len(exp_tag.attributes),
+                                 len(got_tag.attributes),
+                                 "%s: exp: %s\ngot: %s" % (wf_name,
+                                                          
exp_tag.attributes.items(),
+                                                          
got_tag.attributes.items())
+                                 )
+                                 
+                got_attribs_keys = got_tag.attributes.keys()
+                exp_attribs_keys = exp_tag.attributes.keys()
+                got_attribs_keys.sort()
+                exp_attribs_keys.sort()
+                self.assertEqual(exp_attribs_keys, got_attribs_keys)
+                for key in got_attribs_keys:
+                    self.assertEqual(exp_tag.getAttribute(key),
+                                     got_tag.getAttribute(key))
+            alf.deleteProcess('test')
+        
         
     def test_definition(self):
         # Creates a simple workflow

Modified: AlphaFlow/trunk/tests/test_editor.py
==============================================================================
--- AlphaFlow/trunk/tests/test_editor.py	(original)
+++ AlphaFlow/trunk/tests/test_editor.py	Tue Jun 21 17:35:57 2005
(at)(at) -27,7 +27,7 (at)(at)
 class AlphaFlowEditorTest(AlphaFlowTestCase):
 
     interfaces_to_test = [(IAlphaFlowEditor, AlphaFlowEditor),
-                          (IProcess, Process)]
+                          ]
 
     def _import_wf(self, wfpath):
         portal = self.getPortal()
(at)(at) -60,104 +60,6 (at)(at)
         # now
         self.assert_(gif.startswith('GIF89'))
     
-    def test_editTaskActivity(self):
-        prop = {'roles':"Manager",
-                'completion_activity':'notify',
-                'title':'Neu benachrichtigen'}
-        self._import_wf("workflows/alarm_review.alf")
-        portal = self.getPortal()
-        editor = getToolByName(portal, 'workflow_editor')
-        task = editor.processes.test.edit_ticket
-        adapter = getActivitiesAdapter(task)
-        adapter.changeProperties(prop)
-        
-        self.assert_(task.title == prop['title'])
-        self.assert_(prop['completion_activity'] in
-                     task.completion_activity)
-        self.assert_(prop['roles'] in task.roles)
-
-    def test_editDecisionActivity(self):
-        prop = {'decision_notice':'test decision notice',
-                'reject_activity':'deci_n',
-                'accept_activity':'private',
-                'decision_modus':'all_yes',
-                'title':'My decision'}
-        self._import_wf("workflows/decision.alf")
-        portal = self.getPortal()
-        editor = getToolByName(portal, 'workflow_editor')
-        decision = editor.processes.test.deci_1
-        adapter = getActivitiesAdapter(decision)
-        adapter.changeProperties(prop)
-       
-        self.assert_(prop['decision_notice'] == decision.decision_notice)
-        self.assert_(prop['decision_modus'] in decision.decision_modus)
-        self.assert_(prop['reject_activity'] in decision.reject_activity)
-        self.assert_(prop['accept_activity'] in decision.accept_activity)
-        self.assert_(prop['title'] == decision.title)
-        self.assert_(prop['decision_modus'] == decision.decision_modus)
-
-        propnew = {'reject_activity':('deci_n', 'private')}
-        adapter.changeProperties(propnew)
-        self.assert_(prop['decision_notice'] == decision.decision_notice)
-        self.assert_(prop['decision_modus'] in decision.decision_modus)
-        self.assert_(propnew['reject_activity'] == decision.reject_activity)
-        self.assert_(prop['accept_activity'] in decision.accept_activity)
-        self.assert_(prop['title'] == decision.title)
-        self.assert_(prop['decision_modus'] == decision.decision_modus)
-
-        adapter.changeProperties({'reject_activity':('deci_n',
-                                                     'garbage')})
-        self.assert_(propnew['reject_activity'] == decision.reject_activity)
-        
-    def test_getProperties(self):
-        """correct activity properties test"""
-        self._import_wf("workflows/decision.alf")
-        portal = self.getPortal()
-        editor = getToolByName(portal, 'workflow_editor')
-        activities = editor.processes.test.objectValues()
-        
-        for act in activities:
-            properties = act.getProperties()
-            if properties['id'] == 'deci_1':
-                expected = {'id':'deci_1',
-                            'title':'',
-                            'decision_notice':'first yes counts',
-                            'accept_activity':('deci_n',),
-                            'reject_activity':('private',),
-                            'decision_modus':'first_yes',
-                            'kind':'actual',
-                            'roles': ('Reviewer',)}
-                self.assertEqual(len(expected), len(properties),
-                                 "properties has not the expected length!")
-                self.assert_(expected == properties)
-            
-            if properties['id'] == 'deci_n':
-                expected = {'id':'deci_n',
-                            'title':'',
-                            'decision_notice':'all yes counting',
-                            'accept_activity':('public',),
-                            'reject_activity':('private',),
-                            'decision_modus':'all_yes',
-                            'kind':'actual',
-                            'roles': ('Editor','Reviewer')}
-                self.assertEqual(len(expected), len(properties),
-                                 "properties has not the expected length!")
-                self.assert_(expected == properties)
-
-            if properties['id'] == 'private':
-                self.assert_({'id':'private',
-                              'title':'',
-                              'continue_activity': (), 
-                              'status':'private'} ==
-                             properties)
-            
-            if properties['id'] == 'public':
-                self.assert_({'id':'public',
-                              'title':'',
-                              'continue_activity':(),
-                              'status':'public'} ==
-                             properties)
-
                  
     # XML export tests    
     def test_decision_getXML(self):
(at)(at) -166,8 +68,8 (at)(at)
         editor = getToolByName(portal, 'workflow_editor')
         decision_expected = {'id':'deci_n',
                              'decision_notice':'all yes counting',
-                             'accept_activity':"('public',)",
-                             'reject_activity':"('private',)",
+                             'accept_activity':"public",
+                             'reject_activity':"private",
                              'decision_modus':'all_yes',
                              'title': '',
                              }
(at)(at) -175,6 +77,7 (at)(at)
         xml = minidom.parseString(xml)
 
         el = xml.getElementsByTagName('decision')[0]
+        
         self.assertEqual(len(el.attributes), len(decision_expected), 
                          "The 'decision' element has not the amount of"\
                          " expected attributes.")
(at)(at) -183,7 +86,7 (at)(at)
                          "expected property %s not an xml attribute!" %prop)
         
         assignees_expected = {'kind':'actual',
-                              'roles':"('Editor', 'Reviewer')"}
+                              'roles':"Editor Reviewer"}
         el = xml.getElementsByTagName('assignees')[0]
         self.assertEqual(len(el.attributes.values()), len(assignees_expected),

                          "The 'assignees' element has not the amount of"\

Modified: AlphaFlow/trunk/tests/workflows/cachetest.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/cachetest.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/cachetest.alf	Tue Jun 21 17:35:57 2005
(at)(at) -1,9 +1,8 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
+<workflow
     startActivity="write_document"
-    description=""
-    onlyAllowRoles="Manager,Reviewer">
+    onlyAllowRoles="Manager Reviewer">
 
     <!-- Write the document -->
     <task id="write_document" title="Dokument schreiben" sort="1"

Modified: AlphaFlow/trunk/tests/workflows/catalog_security.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/catalog_security.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/catalog_security.alf	Tue Jun 21 17:35:57
2005
(at)(at) -1,4 +1,4 (at)(at)
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
 
 <workflow title=""  
     startActivity="recursion,make_private"

Modified: AlphaFlow/trunk/tests/workflows/condition.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/condition.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/condition.alf	Tue Jun 21 17:35:57 2005
(at)(at) -1,8 +1,7 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
+<workflow 
     startActivity="cond_ac_1"
-    description=""
     onlyAllowRoles="Manager,Reviewer,Member">
   
     <condition id="cond_ac_1"

Modified: AlphaFlow/trunk/tests/workflows/configuration_all.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/configuration_all.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/configuration_all.alf	Tue Jun 21 17:35:57
2005
(at)(at) -1,6 +1,6 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-  <workflow title=""  
+  <workflow
     startActivity="assign_task"
     description="Test of configuration activity"
     onlyAllowRoles="Manager,Reviewer,Member">

Modified: AlphaFlow/trunk/tests/workflows/decision.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/decision.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/decision.alf	Tue Jun 21 17:35:57 2005
(at)(at) -1,8 +1,7 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
+<workflow 
   startActivity="deci_1"
-  description=""
   onlyAllowRoles="Manager,Reviewer,Member">
   
   <decision id="deci_1"

Modified: AlphaFlow/trunk/tests/workflows/email.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/email.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/email.alf	Tue Jun 21 17:35:57 2005
(at)(at) -1,8 +1,7 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
-    startActivity="email1"
-    description="">
+<workflow
+    startActivity="email1">
 
     <email id="email1" title="Email versenden" sort="1"
         template="default_email"

Modified: AlphaFlow/trunk/tests/workflows/expression_assign.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/expression_assign.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/expression_assign.alf	Tue Jun 21 17:35:57
2005
(at)(at) -3,7 +3,7 (at)(at)
 <workflow title=""  
     startActivity="write_document"
     description=""
-    onlyAllowRoles="Manager,Reviewer">
+    onlyAllowRoles="Manager Reviewer">
 
     <!-- Write the document -->
     <task id="write_document" title="Dokument schreiben" sort="1"

Modified: AlphaFlow/trunk/tests/workflows/expressionn_assign.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/expressionn_assign.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/expressionn_assign.alf	Tue Jun 21 17:35:57
2005
(at)(at) -12,7 +12,7 (at)(at)
         expression="object/test_assignees" />
     </task>
 
-    <dcworkflow id="dc_publish" title="" status="published"/>
+    <dcworkflow id="dc_publish" title="Publish" status="published"/>
 
     
 </workflow>

Modified: AlphaFlow/trunk/tests/workflows/getviewurl.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/getviewurl.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/getviewurl.alf	Tue Jun 21 17:35:57 2005
(at)(at) -1,8 +1,7 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
-    startActivity="do_this do_that"
-    description="">
+<workflow 
+    startActivity="do_this do_that">
   
     <task id="do_this"
       view_url_expr="string:${content/absolute_url}/edit"

Modified: AlphaFlow/trunk/tests/workflows/multi_review.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/multi_review.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/multi_review.alf	Tue Jun 21 17:35:57 2005
(at)(at) -1,4 +1,4 (at)(at)
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
 
 <workflow id="multi_review"
           title=""

Modified: AlphaFlow/trunk/tests/workflows/multi_review_with_config.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/multi_review_with_config.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/multi_review_with_config.alf	Tue Jun 21
17:35:57 2005
(at)(at) -77,7 +77,7 (at)(at)
 
     <!-- reviewer -->
     <review id="review_document1"
-            title="Dokument prüfen"
+            title="Dokument prüfen"
             sort="2"
             review_notice="Bitte auf inhaltliche Ausgestaltung achten."
             reject_activity="make_private"
(at)(at) -90,7 +90,7 (at)(at)
 
     <!-- chief editor -->
     <rolebased-review id="review_document2"
-                      title="Dokument prüfen (verantwortlicher Redakteur)"
+                      title="Dokument prüfen (verantwortlicher Redakteur)"
                       sort="3"
                       review_notice="Bitte auf formelle Kriterien achten."
                       reject_activity="make_private"
(at)(at) -103,7 +103,7 (at)(at)
 
     <!-- Publish the document -->
     <permission-change id="publish"
-                       title="Öffentliche Rechte setzen"
+                       title="Öffentliche Rechte setzen"
                        continue_activity="dc_publish">
 
         <permission id="Access contents information"

Modified: AlphaFlow/trunk/tests/workflows/routing_example.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/routing_example.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/routing_example.alf	Tue Jun 21 17:35:57
2005
(at)(at) -1,7 +1,7 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow id="routing_example"
-          title=""  
+<workflow
+          title="routing_example"
           description=""
           startActivity="review"
           onlyAllowRoles="Manager,Reviewer">

Modified: AlphaFlow/trunk/tests/workflows/task.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/task.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/task.alf	Tue Jun 21 17:35:57 2005
(at)(at) -3,7 +3,7 (at)(at)
 <workflow title="Testworkflow"  
     startActivity="edit"
     description="Blubb"
-    onlyAllowRoles="Manager,Reviewer,Member">
+    onlyAllowRoles="Manager Reviewer Member">
   
     <task id="edit"
       title="Dokument bearbeiten" sort="1"

SVN: r3043 - in AlphaFlow/trunk/editor/views: ecmascript panels
Roman Joost <rj(at)gocept.com>
2005-06-22 08:37:36 [ FULL ]
Author: roman
Date: Wed Jun 22 08:39:10 2005
New Revision: 3043

Modified:
   AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml
   AlphaFlow/trunk/editor/views/panels/attributes.pt
   AlphaFlow/trunk/editor/views/panels/messages.pt
   AlphaFlow/trunk/editor/views/panels/toolbox.pt
Log:
- Changed behaviour of the editor a bit: Only the toolbox is now
  unfolded, other panels are folded. A panel is automatically unfolded
  if eg. an item needs to be displayed in the panel.


Modified: AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml	Wed Jun 22 08:39:10
2005
(at)(at) -22,6 +22,20 (at)(at)
     
     this.init = function() {
         this.base_url = this.getBaseURI()
+        var panelbox = document.getElementById('Panels')
+        var buttons = panelbox.getElementsByTagName('a')
+        
+        for ( i=0; i<buttons.length; i++ ) {
+            if (buttons[i].hasAttributes('class')) {
+                var cssclass = buttons[i].getAttribute('class')
+                if (cssclass == 'foldbutton')
+                    addEventHandler(buttons[i], 
+                                    'click', 
+                                    this.foldingHandler,
+                                    this)
+            }
+        }
+        
         this.initialize_events()
     }
     
(at)(at) -62,6 +76,25 (at)(at)
         request.send(null);
     }
     
+    // (un-) folds a panel element after the user clicked on the button
+    this.foldingHandler = function(ev) {
+        var button = ev.target
+        this.foldSwitch(button)
+    }
+    
+    this.foldSwitch = function(button) {
+        var element = button.parentNode.parentNode
+        if (!element.hasAttributes('class'))
+            return 
+        
+        var attribute = element.getAttribute('class')
+        if (attribute == 'panel folded')
+          element.setAttribute('class', 'panel unfolded')
+        else
+          element.setAttribute('class', 'panel folded')
+    
+    }
+    
     // methods which handling onreadystatechange events
     this._handleXML = function(object) {
         if (this.readyState == 4) {

Modified: AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml	Wed Jun 22 08:39:10
2005
(at)(at) -26,4 +26,5 (at)(at)
         this.document.location.href=url
     }
 }
+
 // Editor

Modified: AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml	Wed Jun 22 08:39:10
2005
(at)(at) -52,18 +52,6 (at)(at)
     }
 }
 
-
-// (un-) folds a panel element
-function unfold(id){
-    var element = document.getElementById(id)
-    var attribute = element.getAttribute('class')
-    
-    if (attribute == 'panel folded')
-      element.setAttribute('class', 'panel unfolded')
-    else
-      element.setAttribute('class', 'panel folded')
-}
-
 function debug(where, what) {
     where.appendChild(document.createTextNode(what))
 }

Modified: AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml	Wed Jun 22
08:39:10 2005
(at)(at) -1,9 +1,11 (at)(at)
-function MessageDialog() 
+function MessageDialog(ed) 
 {
     this.activity_id = "";
     this.handledTips = new List();
     this.xslt = "renderHTMLTooltip.xsl"
     this.document = document
+    // lets use true for 'folded' and false for 'unfolded'
+    this.fold_status = true
     this.init()
 }
 MessageDialog.prototype = new BaseWindow();
(at)(at) -74,6 +76,20 (at)(at)
     this.displayToolTip()
 }
 
+MessageDialog.prototype.unfoldPanel = function() {
+    if (!this.fold_status)
+        return
+
+    var panel = this.document.getElementById('Messages')
+    var links = panel.getElementsByTagName('a')
+    for ( i=0; i<links.length; i++ ) {
+      if ( links[i].hasAttributes('class') ) {
+        if ( links[i].getAttribute('class') == 'foldbutton' )
+          this.foldSwitch(links[i])
+      }
+    }
+}
+
 // displays the HTMLTooltip in the footer
 MessageDialog.prototype.displayToolTip = function () {
     //var footer = document.getElementById('Footer')
(at)(at) -96,6 +112,9 (at)(at)
             display_element.removeChild(old)
             this.handledTips.array.pop()
         }
+        // check if the message box is folded and unfold it if it is
+        this.unfoldPanel()
+
         // if the message box don't have any messages displayed, append
         // a message, otherwise insert before the first message
         var node = this.html.firstChild

Modified: AlphaFlow/trunk/editor/views/panels/attributes.pt
==============================================================================
--- AlphaFlow/trunk/editor/views/panels/attributes.pt	(original)
+++ AlphaFlow/trunk/editor/views/panels/attributes.pt	Wed Jun 22 08:39:10 2005
(at)(at) -1,25 +1,12 (at)(at)
-<div class="panel folded"
+<div id="Properties"
+     class="panel folded"
      metal:define-macro="main">
   <h4>
-    <!-- currently disabled 
-    <a title="unfold" href="javascript:unfold();">
-       <img tal:attributes="src here/images/arrow-unfold.png/absolute_url" 
-            alt="unfold" />
-    </a> -->
+    <a title="unfold" href="#" class="foldbutton">
+    </a>
     Properties 
   </h4>
-  
+  <hr /> 
   <span>
-    <div tal:condition="act">
-      
-      <h4>Attributes for <span tal:replace="act/title_or_id"
/></h4>
-      <form action="changeProperties"
-                  method="POST">
-        
-        <span metal:define-slot="attributes" />
-        
-        <input type="submit" value="Modify" />
-      </form>
-    </div>
   </span>
 </div>

Modified: AlphaFlow/trunk/editor/views/panels/messages.pt
==============================================================================
--- AlphaFlow/trunk/editor/views/panels/messages.pt	(original)
+++ AlphaFlow/trunk/editor/views/panels/messages.pt	Wed Jun 22 08:39:10 2005
(at)(at) -1,8 +1,8 (at)(at)
 <div id="Messages"
-     class="panel unfolded"
+     class="panel folded"
      metal:define-macro="main">
   <h4>
-     <a title="fold" href="javascript:unfold('Messages');"
class="foldbutton"> </a>
+     <a title="fold" href="#" class="foldbutton"> </a>
     Messages 
   </h4>
   <hr />

Modified: AlphaFlow/trunk/editor/views/panels/toolbox.pt
==============================================================================
--- AlphaFlow/trunk/editor/views/panels/toolbox.pt	(original)
+++ AlphaFlow/trunk/editor/views/panels/toolbox.pt	Wed Jun 22 08:39:10 2005
(at)(at) -2,7 +2,7 (at)(at)
      id="Toolbox"
      metal:define-macro="main">
   <h4>
-    <a title="unfold" href="javascript:unfold('Toolbox');"
+    <a title="unfold" href="#"
        class="foldbutton">
     </a>
     Toolbox

SVN: r3044 - AlphaFlow/trunk/tests/workflows
Michael Howitz <mh(at)gocept.com>
2005-06-22 10:09:05 [ FULL ]
Author: mac
Date: Wed Jun 22 10:10:35 2005
New Revision: 3044

Modified:
   AlphaFlow/trunk/tests/workflows/actual_assignees.alf
   AlphaFlow/trunk/tests/workflows/alarm_review.alf
   AlphaFlow/trunk/tests/workflows/before_start.alf
   AlphaFlow/trunk/tests/workflows/cachetest_multi.alf
   AlphaFlow/trunk/tests/workflows/catalog_security.alf
   AlphaFlow/trunk/tests/workflows/condition.alf
   AlphaFlow/trunk/tests/workflows/configuration.alf
   AlphaFlow/trunk/tests/workflows/configuration_all.alf
   AlphaFlow/trunk/tests/workflows/decision.alf
   AlphaFlow/trunk/tests/workflows/expression_assign.alf
   AlphaFlow/trunk/tests/workflows/expressionn_assign.alf
   AlphaFlow/trunk/tests/workflows/instance_transaction.alf
   AlphaFlow/trunk/tests/workflows/multi_review.alf
   AlphaFlow/trunk/tests/workflows/multi_review_with_config.alf
   AlphaFlow/trunk/tests/workflows/ntask.alf
   AlphaFlow/trunk/tests/workflows/routing_example.alf
   AlphaFlow/trunk/tests/workflows/security_fullProcess.alf
   AlphaFlow/trunk/tests/workflows/task.alf
   AlphaFlow/trunk/tests/workflows/task_no_edit.alf
Log:
made workflows sane


Modified: AlphaFlow/trunk/tests/workflows/actual_assignees.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/actual_assignees.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/actual_assignees.alf	Wed Jun 22 10:10:35
2005
(at)(at) -1,9 +1,8 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
+<workflow
     startActivity="write_document"
-    description=""
-    onlyAllowRoles="Manager,Reviewer">
+    onlyAllowRoles="Manager Reviewer">
 
     <!-- Write the document -->
     <task id="write_document" title="Dokument schreiben" sort="1"
(at)(at) -13,7 +12,7 (at)(at)
 
     </task>
     
-    <dcworkflow id="dc_publish" title="" status="published"/>
+    <dcworkflow id="dc_publish" status="published"/>
 
     
 </workflow>

Modified: AlphaFlow/trunk/tests/workflows/alarm_review.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/alarm_review.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/alarm_review.alf	Wed Jun 22 10:10:35 2005
(at)(at) -1,10 +1,7 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow id="alarm_review"
-          title=""   
-          description=""
-          startActivity="edit_ticket,deadline"
-          onlyAllowRoles="Manager,Reviewer,Member">
+<workflow startActivity="edit_ticket deadline"
+          onlyAllowRoles="Manager Reviewer Member">
   
     <task id="edit_ticket"
           title="Ticket bearbeiten"
(at)(at) -17,15 +14,12 (at)(at)
            continue_activity="notify" />
 
     <dcworkflow id="notify"
-                title=""
                 status="pending" />
     
     <dcworkflow id="private"
-                title=""
                 status="private" />
 
     <dcworkflow id="public"
-                title=""
                 status="published" />
 
 </workflow>

Modified: AlphaFlow/trunk/tests/workflows/before_start.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/before_start.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/before_start.alf	Wed Jun 22 10:10:35 2005
(at)(at) -1,6 +1,6 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-  <workflow title=""  
+  <workflow 
     startActivity="some-task expression-test"
     description="Test sibilng"
     onlyAllowRoles="Manager Reviewer Member">

Modified: AlphaFlow/trunk/tests/workflows/cachetest_multi.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/cachetest_multi.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/cachetest_multi.alf	Wed Jun 22 10:10:35
2005
(at)(at) -1,9 +1,8 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
+<workflow
     startActivity="write_document write_document2"
-    description=""
-    onlyAllowRoles="Manager,Reviewer">
+    onlyAllowRoles="Manager Reviewer">
 
     <!-- Write the document -->
     <task id="write_document" title="Dokument schreiben" sort="1"

Modified: AlphaFlow/trunk/tests/workflows/catalog_security.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/catalog_security.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/catalog_security.alf	Wed Jun 22 10:10:35
2005
(at)(at) -1,18 +1,17 (at)(at)
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
-    startActivity="recursion,make_private"
-    description=""
-    onlyAllowRoles="Manager,Reviewer">
+<workflow   
+    startActivity="recursion make_private"
+    onlyAllowRoles="Manager Reviewer">
 
     <!-- Permissions for "private" state -->
-    <permission-change id="make_private" title="Autor-Rechte setzen"
continue_activity="write_document,dc_private">
-        <permission id="Access contents information" acquire="False"
roles="Manager,Owner,ProcessUser"/>
-        <permission id="Modify portal content" acquire="False"
roles="Manager,Owner,ProcessUser"/>
+    <permission-change id="make_private" title="Autor-Rechte setzen"
continue_activity="write_document dc_private">
+        <permission id="Access contents information" acquire="False"
roles="Manager Owner ProcessUser"/>
+        <permission id="Modify portal content" acquire="False"
roles="Manager Owner ProcessUser"/>
         <permission id="View" acquire="False" roles="Manager Owner
ProcessUser"/>
     </permission-change>
 
-    <dcworkflow id="dc_private" title="" status="private"/>
+    <dcworkflow id="dc_private" status="private"/>
 
     <!-- Write the document -->
     <task id="write_document" title="Dokument schreiben" sort="1"
(at)(at) -26,12 +25,12 (at)(at)
         if there are any questions, though he gets no work item yet.
     -->
     <permission-change id="make_review1" title="Review-Rechte setzen" 
-      continue_activity="review_document1,dc_pending">
-        <permission id="Access contents information" acquire="True"
roles="Manager,Owner,Reviewer,ChiefEditor,ProcessUser"/>
-        <permission id="Modify portal content" acquire="False"
roles="Manager,Reviewer,ChiefEditor,ProcessUser"/>
-        <permission id="View" acquire="False"
roles="Manager,Owner,Reviewer,ChiefEditor,ProcessUser"/>
+      continue_activity="review_document1 dc_pending">
+        <permission id="Access contents information" acquire="True"
roles="Manager Owner Reviewer ChiefEditor ProcessUser"/>
+        <permission id="Modify portal content" acquire="False"
roles="Manager Reviewer ChiefEditor ProcessUser"/>
+        <permission id="View" acquire="False" roles="Manager Owner Reviewer
ChiefEditor ProcessUser"/>
     </permission-change>
-    <dcworkflow id="dc_pending" title="" status="pending"/>
+    <dcworkflow id="dc_pending" status="pending"/>
 
     <!-- reviewer -->
     <review id="review_document1" title="Dokument prüfen" sort="2"
(at)(at) -53,16 +52,15 (at)(at)
 
     <!-- Publish the document -->
     <permission-change id="publish" title="Öffentliche Rechte setzen"
continue_activity="dc_publish">
-        <permission id="Access contents information" acquire="True"
roles="Anonymous,Manager"/>
+        <permission id="Access contents information" acquire="True"
roles="Anonymous Manager"/>
         <permission id="Modify portal content" acquire="False"
roles="Manager"/>
-        <permission id="View" acquire="False"
roles="Anonymous,Manager"/>
+        <permission id="View" acquire="False" roles="Anonymous
Manager"/>
     </permission-change>
 
-    <dcworkflow id="dc_publish" title="" status="published"/>
+    <dcworkflow id="dc_publish" status="published"/>
 
     <recursion id="recursion"
-        recursion_activity="publish,make_private,make_review1"
-        block_activities="write_document,review_document1,review_document2"
-        optional_recursion="1"/>
+        recursion_activity="publish make_private make_review1"
+        break_activities="write_document review_document1 review_document2"
/>
     
 </workflow>

Modified: AlphaFlow/trunk/tests/workflows/condition.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/condition.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/condition.alf	Wed Jun 22 10:10:35 2005
(at)(at) -2,7 +2,7 (at)(at)
 
 <workflow 
     startActivity="cond_ac_1"
-    onlyAllowRoles="Manager,Reviewer,Member">
+    onlyAllowRoles="Manager Reviewer Member">
   
     <condition id="cond_ac_1"
                expression="python:['cond_ac_2']"

Modified: AlphaFlow/trunk/tests/workflows/configuration.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/configuration.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/configuration.alf	Wed Jun 22 10:10:35 2005
(at)(at) -1,6 +1,6 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-  <workflow title=""  
+  <workflow
     startActivity="assign_task"
     description="Test of configuration activity"
     onlyAllowRoles="Manager Reviewer Member">

Modified: AlphaFlow/trunk/tests/workflows/configuration_all.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/configuration_all.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/configuration_all.alf	Wed Jun 22 10:10:35
2005
(at)(at) -3,7 +3,7 (at)(at)
   <workflow
     startActivity="assign_task"
     description="Test of configuration activity"
-    onlyAllowRoles="Manager,Reviewer,Member">
+    onlyAllowRoles="Manager Reviewer Member">
 
     <configuration id="assign_task"
       configures_all="true"
(at)(at) -24,4 +24,4 (at)(at)
       <assignees kind="possible" roles="Reviewer" />
     </task>
 
-</workflow>
+</workflow>
\ No newline at end of file

Modified: AlphaFlow/trunk/tests/workflows/decision.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/decision.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/decision.alf	Wed Jun 22 10:10:35 2005
(at)(at) -2,7 +2,7 (at)(at)
 
 <workflow 
   startActivity="deci_1"
-  onlyAllowRoles="Manager,Reviewer,Member">
+  onlyAllowRoles="Manager Reviewer Member">
   
   <decision id="deci_1"
     decision_notice="first yes counts"

Modified: AlphaFlow/trunk/tests/workflows/expression_assign.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/expression_assign.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/expression_assign.alf	Wed Jun 22 10:10:35
2005
(at)(at) -1,8 +1,7 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
+<workflow  
     startActivity="write_document"
-    description=""
     onlyAllowRoles="Manager Reviewer">
 
     <!-- Write the document -->
(at)(at) -13,7 +12,7 (at)(at)
 
     </task>
     
-    <dcworkflow id="dc_publish" title="" status="published"/>
+    <dcworkflow id="dc_publish" status="published"/>
 
     
 </workflow>

Modified: AlphaFlow/trunk/tests/workflows/expressionn_assign.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/expressionn_assign.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/expressionn_assign.alf	Wed Jun 22 10:10:35
2005
(at)(at) -1,9 +1,8 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
+<workflow
     startActivity="write_document"
-    description=""
-    onlyAllowRoles="Manager,Reviewer">
+    onlyAllowRoles="Manager Reviewer">
 
     <!-- Write the document -->
     <task id="write_document" title="Dokument schreiben" sort="1"

Modified: AlphaFlow/trunk/tests/workflows/instance_transaction.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/instance_transaction.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/instance_transaction.alf	Wed Jun 22
10:10:35 2005
(at)(at) -1,9 +1,8 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow title=""  
+<workflow
     startActivity="write_document"
-    description=""
-    onlyAllowRoles="Manager,Reviewer">
+    onlyAllowRoles="Manager Reviewer">
 
     <!-- Write the document -->
     <task id="write_document" title="Dokument schreiben" sort="1"
(at)(at) -13,7 +12,7 (at)(at)
 
     </task>
     
-    <dcworkflow id="dc_publish" title="" status="published"/>
+    <dcworkflow id="dc_publish" status="published"/>
 
     
 </workflow>

Modified: AlphaFlow/trunk/tests/workflows/multi_review.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/multi_review.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/multi_review.alf	Wed Jun 22 10:10:35 2005
(at)(at) -1,32 +1,29 (at)(at)
 <?xml version="1.0" encoding="utf-8"?>
 
-<workflow id="multi_review"
-          title=""
-          description=""
-          startActivity="recursion,make_private"
-          onlyAllowRoles="Manager,Reviewer">
+<workflow title="multi_review"
+          startActivity="recursion make_private"
+          onlyAllowRoles="Manager Reviewer">
 
     <!-- Permissions for "private" state -->
     <permission-change id="make_private"
                        title="Autor-Rechte setzen"
-                       continue_activity="write_document,dc_private">
+                       continue_activity="write_document dc_private">
 
       <permission id="Access contents information"
                   acquire="False"
-                  roles="Manager,Owner" />
+                  roles="Manager Owner" />
 
       <permission id="Modify portal content"
                   acquire="False"
-                  roles="Manager,Owner" />
+                  roles="Manager Owner" />
 
       <permission id="View"
                   acquire="False"
-                  roles="Manager,Owner" />
+                  roles="Manager Owner" />
 
     </permission-change>
 
     <dcworkflow id="dc_private"
-                title=""
                 status="private" />
 
     <!-- Write the document -->
(at)(at) -48,24 +45,23 (at)(at)
     -->
     <permission-change id="make_review1"
                        title="Review-Rechte setzen"
-                       continue_activity="review_document1,dc_pending">
+                       continue_activity="review_document1 dc_pending">
 
       <permission id="Access contents information"
                   acquire="True"
-                  roles="Manager,Owner,Reviewer,ChiefEditor" />
+                  roles="Manager Owner Reviewer ChiefEditor" />
 
       <permission id="Modify portal content"
                   acquire="False"
-                  roles="Manager,Reviewer,ChiefEditor" />
+                  roles="Manager Reviewer ChiefEditor" />
 
       <permission id="View"
                   acquire="False"
-                  roles="Manager,Owner,Reviewer,ChiefEditor" />
+                  roles="Manager Owner Reviewer ChiefEditor" />
 
     </permission-change>
 
     <dcworkflow id="dc_pending"
-                title=""
                 status="pending" />
 
     <!-- reviewer -->
(at)(at) -101,7 +97,7 (at)(at)
 
         <permission id="Access contents information"
                     acquire="True"
-                    roles="Anonymous,Manager" />
+                    roles="Anonymous Manager" />
 
         <permission id="Modify portal content"
                     acquire="False"
(at)(at) -109,17 +105,15 (at)(at)
 
         <permission id="View"
                     acquire="False"
-                    roles="Anonymous,Manager" />
+                    roles="Anonymous Manager" />
 
     </permission-change>
 
     <dcworkflow id="dc_publish"
-                title=""
                 status="published" />
 
     <recursion id="recursion"
-               recursion_activity="publish,make_private,make_review1"
-              
block_activities="write_document,review_document1,review_document2"
-               optional_recursion="1" />
+               recursion_activity="publish make_private make_review1"
+               break_activities="write_document review_document1
review_document2" />
 
 </workflow>

Modified: AlphaFlow/trunk/tests/workflows/multi_review_with_config.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/multi_review_with_config.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/multi_review_with_config.alf	Wed Jun 22
10:10:35 2005
(at)(at) -1,10 +1,8 (at)(at)
 <?xml version="1.0" encoding="iso-8859-1"?>
 
-<workflow id="multi_review"
-          title=""
-          description=""
+<workflow title="multi_review"
           startActivity="config_at_start"
-          onlyAllowRoles="Manager,Reviewer">
+          onlyAllowRoles="Manager Reviewer">
 
 
     <configuration id="config_at_start"
(at)(at) -17,24 +15,23 (at)(at)
     <!-- Permissions for "private" state -->
     <permission-change id="make_private"
                        title="Autor-Rechte setzen"
-                       continue_activity="write_document,dc_private">
+                       continue_activity="write_document dc_private">
 
       <permission id="Access contents information"
                   acquire="False"
-                  roles="Manager,Owner" />
+                  roles="Manager Owner" />
 
       <permission id="Modify portal content"
                   acquire="False"
-                  roles="Manager,Owner" />
+                  roles="Manager Owner" />
 
       <permission id="View"
                   acquire="False"
-                  roles="Manager,Owner" />
+                  roles="Manager Owner" />
 
     </permission-change>
 
     <dcworkflow id="dc_private"
-                title=""
                 status="private" />
 
     <!-- Write the document -->
(at)(at) -55,24 +52,23 (at)(at)
     -->
     <permission-change id="make_review1"
                        title="Review-Rechte setzen"
-                       continue_activity="review_document1,dc_pending">
+                       continue_activity="review_document1 dc_pending">
 
       <permission id="Access contents information"
                   acquire="True"
-                  roles="Manager,Owner,Reviewer,ChiefEditor" />
+                  roles="Manager Owner Reviewer ChiefEditor" />
 
       <permission id="Modify portal content"
                   acquire="False"
-                  roles="Manager,Reviewer,ChiefEditor" />
+                  roles="Manager Reviewer ChiefEditor" />
 
       <permission id="View"
                   acquire="False"
-                  roles="Manager,Owner,Reviewer,ChiefEditor" />
+                  roles="Manager Owner Reviewer ChiefEditor" />
 
     </permission-change>
 
     <dcworkflow id="dc_pending"
-                title=""
                 status="pending" />
 
     <!-- reviewer -->
(at)(at) -108,7 +104,7 (at)(at)
 
         <permission id="Access contents information"
                     acquire="True"
-                    roles="Anonymous,Manager" />
+                    roles="Anonymous Manager" />
 
         <permission id="Modify portal content"
                     acquire="False"
(at)(at) -116,17 +112,15 (at)(at)
 
         <permission id="View"
                     acquire="False"
-                    roles="Anonymous,Manager" />
+                    roles="Anonymous Manager" />
 
     </permission-change>
 
     <dcworkflow id="dc_publish"
-                title=""
                 status="published" />
 
     <recursion id="recursion"
-               recursion_activity="publish,make_private,make_review1"
-              
block_activities="write_document,review_document1,review_document2"
-               optional_recursion="1" />
+               recursion_activity="publish make_private make_review1"
+               break_activities="write_document review_document1
review_document2" />
 
 </workflow>

Modified: AlphaFlow/trunk/tests/workflows/ntask.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/ntask.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/ntask.alf	Wed Jun 22 10:10:35 2005
(at)(at) -3,7 +3,7 (at)(at)
 <workflow title="Testworkflow"  
     startActivity="edit"
     description="Blubb"
-    onlyAllowRoles="Manager,Reviewer,Member">
+    onlyAllowRoles="Manager Reviewer Member">
   
     <ntask id="edit"
         title="Dokument bearbeiten" sort="1">

Modified: AlphaFlow/trunk/tests/workflows/routing_example.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/routing_example.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/routing_example.alf	Wed Jun 22 10:10:35
2005
(at)(at) -2,9 +2,8 (at)(at)
 
 <workflow
           title="routing_example"
-          description=""
           startActivity="review"
-          onlyAllowRoles="Manager,Reviewer">
+          onlyAllowRoles="Manager Reviewer">
 
   <route id="review"
          title="Decisions by Marketing, Medical and Legal Departments">
(at)(at) -22,7 +21,6 (at)(at)
                       accept_activity="accept" />
 
     <dcworkflow id="visible"
-        title=""
         status="visible"
         continue_activity="review_medical"/>
                   
(at)(at) -44,11 +42,9 (at)(at)
                       reject_activity="reject"
                       accept_activity="accept" />
   <dcworkflow id="private"
-              title=""
               status="private" />
 
   <dcworkflow id="public"
-              title=""
               status="published" />
 
 </workflow>

Modified: AlphaFlow/trunk/tests/workflows/security_fullProcess.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/security_fullProcess.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/security_fullProcess.alf	Wed Jun 22
10:10:35 2005
(at)(at) -1,8 +1,6 (at)(at)
-<?xml version="1.0" encoding="iso-8859-1"?>
+<?xml version="1.0" encoding="utf-8"?>
 
-<workflow id="multi_review"
-          title=""
-          description=""
+<workflow title="multi_review"
           startActivity="config_wf"
           onlyAllowRoles="Manager Reviewer">
 
(at)(at) -15,24 +13,23 (at)(at)
     <!-- Permissions for "private" state -->
     <permission-change id="make_private"
                        title="Autor-Rechte setzen"
-                       continue_activity="write_document,dc_private">
+                       continue_activity="write_document dc_private">
 
       <permission id="Access contents information"
                   acquire="False"
-                  roles="Manager,Owner" />
+                  roles="Manager Owner" />
 
       <permission id="Modify portal content"
                   acquire="False"
-                  roles="Manager,Owner" />
+                  roles="Manager Owner" />
 
       <permission id="View"
                   acquire="False"
-                  roles="Manager,Owner" />
+                  roles="Manager Owner" />
 
     </permission-change>
 
     <dcworkflow id="dc_private"
-                title=""
                 status="private" />
 
     <!-- Write the document -->
(at)(at) -53,24 +50,23 (at)(at)
     -->
     <permission-change id="make_review1"
                        title="Review-Rechte setzen"
-                       continue_activity="review_document1,dc_pending">
+                       continue_activity="review_document1 dc_pending">
 
       <permission id="Access contents information"
                   acquire="True"
-                  roles="Manager,Owner,Reviewer,ChiefEditor" />
+                  roles="Manager Owner Reviewer ChiefEditor" />
 
       <permission id="Modify portal content"
                   acquire="False"
-                  roles="Manager,Reviewer,ChiefEditor" />
+                  roles="Manager Reviewer ChiefEditor" />
 
       <permission id="View"
                   acquire="False"
-                  roles="Manager,Owner,Reviewer,ChiefEditor" />
+                  roles="Manager Owner Reviewer ChiefEditor" />
 
     </permission-change>
 
     <dcworkflow id="dc_pending"
-                title=""
                 status="pending" />
 
     <!-- reviewer -->
(at)(at) -106,7 +102,7 (at)(at)
 
         <permission id="Access contents information"
                     acquire="True"
-                    roles="Anonymous,Manager" />
+                    roles="Anonymous Manager" />
 
         <permission id="Modify portal content"
                     acquire="False"
(at)(at) -114,17 +110,15 (at)(at)
 
         <permission id="View"
                     acquire="False"
-                    roles="Anonymous,Manager" />
+                    roles="Anonymous Manager" />
 
     </permission-change>
 
     <dcworkflow id="dc_publish"
-                title=""
                 status="published" />
 
     <recursion id="recursion"
-               recursion_activity="publish,make_private,make_review1"
-              
block_activities="write_document,review_document1,review_document2"
-               optional_recursion="1" />
+               recursion_activity="publish make_private make_review1"
+               break_activities="write_document review_document1
review_document2" />
 
 </workflow>

Modified: AlphaFlow/trunk/tests/workflows/task.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/task.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/task.alf	Wed Jun 22 10:10:35 2005
(at)(at) -7,7 +7,7 (at)(at)
   
     <task id="edit"
       title="Dokument bearbeiten" sort="1"
-      continue_activity="public">
+      completion_activity="public">
       <assignees kind="actual" expression="object/Creator" />
 
     </task>

Modified: AlphaFlow/trunk/tests/workflows/task_no_edit.alf
==============================================================================
--- AlphaFlow/trunk/tests/workflows/task_no_edit.alf	(original)
+++ AlphaFlow/trunk/tests/workflows/task_no_edit.alf	Wed Jun 22 10:10:35 2005
(at)(at) -3,12 +3,12 (at)(at)
 <workflow title="Testworkflow"  
     startActivity="edit"
     description="Blubb"
-    onlyAllowRoles="Manager,Reviewer,Member">
+    onlyAllowRoles="Manager Reviewer Member">
   
     <task id="edit"
         title="Dokument bearbeiten" sort="1"
         nonEditableFields="task"
-        continue_activity="public">
+        completion_activity="public">
         <assignees kind="actual" expression="object/Creator" />
     </task>

SVN: r3051 - in AlphaFlow/trunk/editor/views: . ecmascript
Roman Joost <rj(at)gocept.com>
2005-06-22 10:54:06 [ FULL ]
Author: roman
Date: Wed Jun 22 10:55:44 2005
New Revision: 3051

Added:
   AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl
Modified:
   AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml
Log:
- new XSLT for rendering activity properties form
- minor fixes in ecmascripts


Modified: AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml	Wed Jun 22 10:55:44
2005
(at)(at) -104,7 +104,7 (at)(at)
             
             // first check for parsing errors
             if (xml.parseError == 0) {
-                object.responseXML = xml 
+                object.responseXML = xml
                 // call render Tooltip for XML-> HTML transformation
                 object.renderXML2HTML()
             }

Modified: AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml	Wed Jun 22 10:55:44
2005
(at)(at) -14,7 +14,7 (at)(at)
 
 // initalize the event handlers
 Editor.prototype.initialize_events = function() {
-    addEventHandler(this.canvas, 'click', this.backToHome, this)
+    //addEventHandler(this.canvas, 'click', this.backToHome, this)
 } 
 
 // if the user clicks on our canvas during editing of the activities

Modified: AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml	Wed Jun 22
10:55:44 2005
(at)(at) -86,6 +86,7 (at)(at)
       if ( links[i].hasAttributes('class') ) {
         if ( links[i].getAttribute('class') == 'foldbutton' )
           this.foldSwitch(links[i])
+          this.fold_status = false
       }
     }
 }

Added: AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl
==============================================================================
--- (empty file)
+++ AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl	Wed Jun 22 10:55:44
2005
(at)(at) -0,0 +1,172 (at)(at)
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<xsl:stylesheet version="1.0"
+                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:editor="http://www.gocept.com/alf/editor"
+                xmlns="http://www.w3.org/1999/xhtml">
+  <xsl:output method="xml" 
+                version="1.0"
+                encoding="UTF-8"
+                indent="yes" />
+  
+  <xsl:attribute-set name="inputs">
+    <xsl:attribute name="type">text</xsl:attribute>
+    <xsl:attribute name="value">
+      <xsl:value-of select="$value" />
+    </xsl:attribute>
+    <xsl:attribute name="name">
+      <xsl:value-of select="$name" />
+    </xsl:attribute>
+  </xsl:attribute-set>
+  
+  <xsl:template match="//*">
+    <div id="ActivityProperties">
+        <!-- this approach seems a bit awkward to me, but works at least
+        -->
+      <h1>Properties for
+       <xsl:if test="string-length(//(at)id) > 0">
+          <xsl:value-of select="//(at)id" /> 
+        </xsl:if>
+        <xsl:if test="string-length(//(at)title) > 0">
+          "<xsl:value-of select="//(at)title" />"
+        </xsl:if>
+      </h1>
+      <xsl:for-each select="/*/descendant-or-self::node()">
+        <xsl:apply-templates select="(at)*" />
+      </xsl:for-each>
+      <a href="#"
+         id="changeProperties"
+         title="change properties">
+        change properties     
+      </a>
+    </div>
+  </xsl:template>
+
+  <!-- attribute matches -->
+  <xsl:template match="//(at)decision_notice">
+    <b><xsl:value-of select="name()" />:</b>
+    <xsl:call-template name="textarea">
+      <xsl:with-param name="value" select="//(at)decision_notice" />
+      <xsl:with-param name="name">decision_notice</xsl:with-param>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="//(at)roles">
+    <b><xsl:value-of select="name()" />:</b>
+    <xsl:call-template name="textarea">
+      <xsl:with-param name="value" select="//(at)roles" />
+      <xsl:with-param name="name">roles</xsl:with-param>
+    </xsl:call-template>
+  </xsl:template>
+  <xsl:template match="//(at)accept_activity">
+    <b><xsl:value-of select="name()" />:</b>
+    <p>
+      <select name="accept_activity" size="5">
+        <xsl:call-template name="option">
+          <xsl:with-param name="str"
select="//(at)editor:availableActivities"
+          />
+          <xsl:with-param name="selected" select="//(at)accept_activity"
/>
+        </xsl:call-template> 
+      </select>
+    </p>
+  </xsl:template>
+
+  <xsl:template match="//(at)reject_activity">
+    <b><xsl:value-of select="name()" />:</b>
+    <p>
+      <select name="reject_activity" size="5">
+        <xsl:call-template name="option">
+          <xsl:with-param name="str"
select="//(at)editor:availableActivities"
+          />
+          <xsl:with-param name="selected" select="//(at)reject_activity"
/>
+        </xsl:call-template> 
+      </select>
+    </p>
+  </xsl:template>
+
+  <xsl:template match="//(at)decision_modus">
+    <b><xsl:value-of select="name()" />:</b>
+    <p>
+      <select name="reject_activity" size="5">
+        <xsl:call-template name="option">
+          <xsl:with-param name="str" select="//(at)editor:availableModi"
+          />
+          <xsl:with-param name="selected" select="//(at)decision_modus"
/>
+        </xsl:call-template> 
+      </select>
+    </p>
+  </xsl:template>
+ 
+  <!-- catches everything else of attributes -->
+  <xsl:template match="(at)*">
+    <b><xsl:value-of select="name()" />:</b>
+    <xsl:call-template name="input">
+      <xsl:with-param name="value" select="." />
+      <xsl:with-param name="name">
+        <xsl:value-of select="name()" />
+      </xsl:with-param>
+    </xsl:call-template>
+  </xsl:template>
+
+  <!-- don't care about them -->
+  <xsl:template match="//(at)editor:*" />
+
+  <!-- widgets -->
+  <xsl:template name="input">
+    <xsl:param name="value" />
+    <xsl:param name="name" />
+    <p>
+      <xsl:element name="input" use-attribute-sets="inputs" />
+    </p>
+  </xsl:template>
+  
+  <xsl:template name="textarea">
+    <xsl:param name="value" />
+    <xsl:param name="name" />
+    <textarea>
+      <xsl:attribute name="name">
+        <xsl:value-of select="$name" />
+      </xsl:attribute>
+      <xsl:value-of select="$value" />
+    </textarea>
+  </xsl:template>
+
+  <!-- split a comma seperated list and render for each item a HTML tag
+  like <option>foo</option> -->
+  <xsl:template name="option">
+    <xsl:param name="str" />
+    <xsl:param name="selected" />
+    
+    <xsl:choose>
+      <xsl:when test="contains($str, ',') ">
+        <option>
+          <xsl:if test="substring-before($str, ',') = $selected">
+            <xsl:attribute name="selected">true</xsl:attribute>
+          </xsl:if>
+          <xsl:attribute name="name">
+            <xsl:value-of select="substring-before($str, ',')" />
+          </xsl:attribute>
+          <xsl:value-of select="substring-before($str, ',')" />
+        </option>
+        <xsl:call-template name="option">
+          <xsl:with-param name="str"
+                        select="substring-after($str, ',')" />
+          <xsl:with-param name="selected" select="$selected" />
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:if test="string-length($str) > 0">
+          <option>
+            <xsl:if test="$str = $selected">
+              <xsl:attribute name="selected">true</xsl:attribute>
+            </xsl:if>
+            <xsl:attribute name="name">
+              <xsl:value-of select="$str" />
+            </xsl:attribute>
+            <xsl:value-of select="$str" />
+          </option>
+        </xsl:if>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+</xsl:stylesheet>

SVN: r3055 - AlphaFlow/trunk/tests/workflows
Michael Howitz <mh(at)gocept.com>
2005-06-22 11:41:36 [ FULL ]
Author: mac
Date: Wed Jun 22 11:43:09 2005
New Revision: 3055

Removed:
   AlphaFlow/trunk/tests/workflows/expressionn_assign.alf
Log:
removed unused workflow

SVN: r3070 - in AlphaFlow/trunk/editor/views: . ecmascript panels
Roman Joost <rj(at)gocept.com>
2005-06-22 14:05:06 [ FULL ]
Author: roman
Date: Wed Jun 22 14:06:29 2005
New Revision: 3070

Modified:
   AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/test_editor.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/tests.pt
   AlphaFlow/trunk/editor/views/panels/attributes.pt
   AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl
   AlphaFlow/trunk/editor/views/style.css
Log:
- added activity_dialog, which currently shows a form for editing the
  activity properties


Modified: AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml	Wed Jun 22
14:06:29 2005
(at)(at) -1,8 +1,9 (at)(at)
 function ActivityDialog() 
 {
     this.activity_id = "";
-    this.xslt = "renderHTMLTooltip.xsl"
+    this.xslt = "renderPropertiesForm.xsl"
     this.document = document
+    this.displayed_form = new Dictionary()
     this.init()
 }
 ActivityDialog.prototype = new BaseWindow();
(at)(at) -19,6 +20,27 (at)(at)
     }
 } 
 
+/* XXX duplicated code, should be factored out in future */
+// returns the activity id from the given HTML object which should
+// be the hovered SVG ellipse element
+ActivityDialog.prototype.getActivityId = function(element) {
+    return element.parentNode.getAttribute('id')
+}
+// returns true if the given element is a shape which characterizes
+// our activity
+ActivityDialog.prototype.isNodeShape = function(element) {
+    var g = element.parentNode
+    var type = null
+    
+    if (g.hasAttributes('class')) {
+        type = g.getAttribute('class')
+        if (type == 'node')
+            return 1
+    } else {
+        return 0
+    }
+}
+
 // produces an activity properties form in the properties panel after
 // the user clicked an activity shape
 ActivityDialog.prototype.createActivityForm = function(event) {   
(at)(at) -34,6 +56,17 (at)(at)
 // handler which calls this.displayToolTip after the HTML is
 // rendered
 ActivityDialog.prototype.afterRenderedHTML = function() {
-    alert('hurz')
+    this.createPropertyForm()
+}
+
+ActivityDialog.prototype.createPropertyForm = function() {
+    var panel = this.document.getElementById('Properties')
+    var container = panel.getElementsByTagName('span')[0]
+    
+    if (!this.displayed_form.hasKey(this.activity_id) || 
+        this.displayed_form.array.length < 1) {
+        container.appendChild(this.html.documentElement)
+        this.displayed_form.set(this.activity_id, this.html) 
+    }
 }
 // ActivityDialog

Modified: AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/base.js.dtml	Wed Jun 22 14:06:29
2005
(at)(at) -47,7 +47,7 (at)(at)
     */
     this.getXMLFromURL = function(url) {
         // puzzle the request URL together
-        var url = url 
+        var url = url
         var request = new XMLHttpRequest()
         request.open("GET", url, true)
         var callback = new ContextFixer(this._handleXML,
(at)(at) -60,7 +60,6 (at)(at)
     // method which is called after the rendering of the HTML is
     // finished
     this.afterRenderedHTML = function() {
-        alert('falsch')
     }
 
     this.renderXML2HTML = function() {

Modified: AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/editor.js.dtml	Wed Jun 22 14:06:29
2005
(at)(at) -2,6 +2,7 (at)(at)
     var ed = new Editor()
     var ms_dialog = new MessageDialog()
     var wp_window = new WorkflowProperties()
+    var activity_dialog = new ActivityDialog()
 }
 
 function Editor() 

Modified: AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml	Wed Jun 22 14:06:29
2005
(at)(at) -52,7 +52,53 (at)(at)
     }
 }
 
-function debug(where, what) {
-    where.appendChild(document.createTextNode(what))
+// simple dictionary like object
+function Dictionary()
+{
+    this.array = new Array()
+
+    this.set = function(key, value) {
+        var key = key
+        var value = value
+
+        // urks - that sucks
+        // create a tuple like array
+        var pair = new Array()
+        pair[0] = key
+        pair[1] = value
+        this.array.push(pair)
+    }
+
+    this.keys = function() {
+        var result = new Array()
+        for ( i=0; i<this.array.length; i++ ) {
+            var pair = this.array[i]
+            result.push(pair[0])
+        }
+        return result
+    }
+
+    this.get = function(key) {
+        var key = key
+        
+        for ( i=0; i<this.array.length; i++ ) {
+            if ( key == this.array[i][0] )
+                return this.array[i][1]
+        }
+    }
+
+    this.hasKey = function(key) {
+        var key = key
+
+        for ( i=0; i<this.array.length; i++ ) {
+            if ( key == this.array[i][0] )
+                return 1
+        }
+        return 0
+    }
+
 }
 
+function debug(what) {
+   
document.getElementById('Graph').appendChild(document.createTextNode(what))
+}

Modified: AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml	Wed Jun 22
14:06:29 2005
(at)(at) -17,7 +17,7 (at)(at)
     for(i=0; i<groups.length; i++) {
         var g = groups[i]
        if (g.getAttribute('class') == 'node') {
-            addEventHandler(g, 'mouseover', this.createTooltip, this)
+            //addEventHandler(g, 'mouseover', this.createTooltip, this)
         }
     }
 } 
(at)(at) -25,13 +25,13 (at)(at)
 // returns the activity id from the given HTML object which should
 // be the hovered SVG ellipse element
 MessageDialog.prototype.getActivityId = function(element) {
-    return element.parentNode.parentNode.getAttribute('id')
+    return element.parentNode.getAttribute('id')
 }
 
 // returns true if the given element is a shape which characterizes
 // our activity
 MessageDialog.prototype.isNodeShape = function(element) {
-    var g = element.parentNode.parentNode
+    var g = element.parentNode
     var type = null
     
     if (g.hasAttributes('class')) {

Modified: AlphaFlow/trunk/editor/views/ecmascript/test_editor.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/test_editor.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/test_editor.js.dtml	Wed Jun 22
14:06:29 2005
(at)(at) -3,7 +3,7 (at)(at)
    
     this.setUp = function() {
         this.editor = new Editor()
-        this.editor.event_initialize()
+        this.editor.initialize_events()
         this.debug_el = document.getElementById('debugoutput')
     }
 
(at)(at) -28,5 +28,22 (at)(at)
 
 
 };
-
 EditorTestCase.prototype = new TestCase;
+
+function DictionaryTestCase() {
+    this.name = "DictionaryTestCase"
+
+    this.setUp = function() {
+        this.dict = new Dictionary()
+    }
+
+    this.test_get = function() {
+        this.dict.set(1, 'foo')
+        this.dict.set('name', 'value')
+        this.dict.set('foo', 'bar')
+
+        this.assert_(this.dict.get('foo') == 'bar')
+    }
+
+};
+DictionaryTestCase.prototype = new TestCase;

Modified: AlphaFlow/trunk/editor/views/ecmascript/tests.pt
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/tests.pt	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/tests.pt	Wed Jun 22 14:06:29 2005
(at)(at) -5,18 +5,25 (at)(at)
   lang="en">
   <metal:block fill-slot="ecmascripts">
     <script type="text/javascript" src="ecmaunit.js"> </script>
+    <script type="text/javascript" src="helper.js"> </script>
     <script type="text/javascript" src="test_editor.js"> </script>
     <script type="text/javascript">
       //<![CDATA[
-    function runTests() {
-        var testcase = new EditorTestCase();
+    function runallTests() {
+        /*var testcase = new EditorTestCase();
         var placeholder = document.getElementById('placeholder1');
         testcase.initialize(new HTMLReporter(placeholder));
-        testcase.runTests();
+        testcase.runTests();*/
+        
+        var dicttest = new DictionaryTestCase();
+        var placeholder = document.getElementById('placeholder2');
+        dicttest.initialize(new HTMLReporter(placeholder));
+        dicttest.runTests();
 
         placeholder = document.getElementById('result');
         var testsuite = new TestSuite(new HTMLReporter(placeholder));
         testsuite.registerTest(EditorTestCase);
+        testsuite.registerTest(DictionaryTestCase);
         testsuite.runSuite();
     };
 //]]>
(at)(at) -24,11 +31,14 (at)(at)
   </metal:block>
 <body>  
   <div metal:fill-slot="debug">
-    <h3>editor test</h3>
     <p>Some of them fail, if you don't use a SVG enabled
Mozilla.</p>
+    <h3>editor test</h3>
     <div id="placeholder1"> </div>
+    
+    <h3>dictionary test</h3>
+    <div id="placeholder2"> </div>
     <p>
-      <a href="javascript:runTests()" title="run all tests">
+      <a href="javascript:runallTests()" title="run all tests">
         run all tests
       </a>
     </p>

Modified: AlphaFlow/trunk/editor/views/panels/attributes.pt
==============================================================================
--- AlphaFlow/trunk/editor/views/panels/attributes.pt	(original)
+++ AlphaFlow/trunk/editor/views/panels/attributes.pt	Wed Jun 22 14:06:29 2005
(at)(at) -1,5 +1,5 (at)(at)
 <div id="Properties"
-     class="panel folded"
+     class="panel unfolded"
      metal:define-macro="main">
   <h4>
     <a title="unfold" href="#" class="foldbutton">
(at)(at) -8,5 +8,6 (at)(at)
   </h4>
   <hr /> 
   <span>
+
   </span>
 </div>

Modified: AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl
==============================================================================
--- AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl	(original)
+++ AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl	Wed Jun 22 14:06:29
2005
(at)(at) -12,10 +12,10 (at)(at)
   <xsl:attribute-set name="inputs">
     <xsl:attribute name="type">text</xsl:attribute>
     <xsl:attribute name="value">
-      <xsl:value-of select="$value" />
+      <xsl:value-of select="." />
     </xsl:attribute>
     <xsl:attribute name="name">
-      <xsl:value-of select="$name" />
+      <xsl:value-of select="node()" />
     </xsl:attribute>
   </xsl:attribute-set>
   
(at)(at) -101,10 +101,6 (at)(at)
   <xsl:template match="(at)*">
     <b><xsl:value-of select="name()" />:</b>
     <xsl:call-template name="input">
-      <xsl:with-param name="value" select="." />
-      <xsl:with-param name="name">
-        <xsl:value-of select="name()" />
-      </xsl:with-param>
     </xsl:call-template>
   </xsl:template>
 
(at)(at) -113,8 +109,6 (at)(at)
 
   <!-- widgets -->
   <xsl:template name="input">
-    <xsl:param name="value" />
-    <xsl:param name="name" />
     <p>
       <xsl:element name="input" use-attribute-sets="inputs" />
     </p>

Modified: AlphaFlow/trunk/editor/views/style.css
==============================================================================
--- AlphaFlow/trunk/editor/views/style.css	(original)
+++ AlphaFlow/trunk/editor/views/style.css	Wed Jun 22 14:06:29 2005
(at)(at) -76,6 +76,7 (at)(at)
   color: white;
 }
 
+/* editor itself*/
 #Menu {
   height: 2.5em;
   background-color: #63777f;
(at)(at) -263,6 +264,7 (at)(at)
   border-bottom: 1px solid #919fa5;
 }
 
+/* Messages panel */
 #Panels #Messages.unfolded {
   min-height: 20em;
 }
(at)(at) -301,6 +303,29 (at)(at)
   visibility: hidden;
 }
 
+/* Properties panel */
+#ActivityProperties {
+  font-size: 0.7em;
+  color: white;
+}
+#ActivityProperties h1 {
+  font-size: 0.8em;
+  color: white;
+  margin: 0;
+}
+
+#ActivityProperties input[type="text"],
+#ActivityProperties textarea,
+#ActivityProperties select {
+  width: 100%;
+  border: 1px inset #455359;
+}
+
+#ActivityProperties p {
+  margin-top: 0;
+  display: block;
+  padding: 0 0.4em;
+}
 /* SVG styles */
 .nodisplay {
   display: none;

SVN: r3073 - in AlphaFlow/trunk/tests: . workflows
Michael Howitz <mh(at)gocept.com>
2005-06-22 15:14:00 [ FULL ]
Author: mac
Date: Wed Jun 22 15:15:36 2005
New Revision: 3073

Added:
   AlphaFlow/trunk/tests/test_expression.py   (contents, props changed)
   AlphaFlow/trunk/tests/workflows/expression.alf
Log:
added tests for expression activity


Added: AlphaFlow/trunk/tests/test_expression.py
==============================================================================
--- (empty file)
+++ AlphaFlow/trunk/tests/test_expression.py	Wed Jun 22 15:15:36 2005
(at)(at) -0,0 +1,70 (at)(at)
+# Copyright (c) 2005 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id$
+
+import common
+import unittest
+
+from DateTime import DateTime
+from Testing import ZopeTestCase
+
+from Products.CMFCore.utils import getToolByName
+
+from Products.AlphaFlow.tests.AlphaFlowTestCase import AlphaFlowTestCase
+from Products.AlphaFlow.interfaces import \
+     IExpressionActivity, IExpressionWorkItem
+from Products.AlphaFlow.activities.expression import \
+     ExpressionActivity, ExpressionWorkItem
+
+class ExpressionTest(AlphaFlowTestCase):
+
+    interfaces_to_test = [
+        (IExpressionWorkItem, ExpressionWorkItem),
+        (IExpressionActivity, ExpressionActivity)
+        ]
+    
+    def _init_object(self):
+        portal = self.getPortal()
+        self._create_test_users()
+        self.loginAsPortalOwner()
+        self._import_wf('workflows/expression.alf')
+
+        wftool = getToolByName(portal, 'workflow_manager')
+
+        self.login("author")
+        mtool = getToolByName(portal, 'portal_membership')
+        home = mtool.getPersonalFolder("author")
+        # Create object for instanciation of this process
+        home.createObject("testdocument", "DummyContent")
+
+        # Initialize the process
+        doc = home.testdocument
+        doc.assignProcess(doc.getSuitableProcesses()[0].getId())
+        return doc
+        
+    def test_definition(self):
+        portal = self.getPortal()
+        wftool = getToolByName(portal, 'workflow_manager')
+        doc = self._init_object()
+
+        # props not existing
+
+        self.assertRaises(AttributeError,
+                          getattr, doc, "asdf_asdf_prop_hjkl")
+        instance = doc.getInstance()
+        instance.start("testing")
+        self.assertEquals(instance.state, "active")
+        self.assertEqual(2, doc.asdf_asdf_prop_hjkl)
+        wis = instance.getWorkItems()
+        # only the task is left
+        self.assertEquals(len(wis), 1)
+        
+    
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(ExpressionTest))
+    return suite 
+
+if __name__ == '__main__':
+    framework()
+

Added: AlphaFlow/trunk/tests/workflows/expression.alf
==============================================================================
--- (empty file)
+++ AlphaFlow/trunk/tests/workflows/expression.alf	Wed Jun 22 15:15:36 2005
(at)(at) -0,0 +1,18 (at)(at)
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<workflow  
+    startActivity="test2"
+    onlyAllowRoles="Manager Member">
+
+    <expression id="test2" 
+                expression="python:object.set('asdf_asdf_prop_hjkl', 2)"
+                continue_activity="test3" />
+
+    <!-- check for TALES contexts -->
+    <expression id="test3"
+                expression="python: workitem != object and activity != portal"
+                continue_activity="end" />
+    <task id="end" />
+
+    
+</workflow>

SVN: r3076 - in AlphaFlow/trunk/editor/views: . ecmascript
Roman Joost <rj(at)gocept.com>
2005-06-23 08:49:58 [ FULL ]
Author: roman
Date: Thu Jun 23 08:45:16 2005
New Revision: 3076

Modified:
   AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml
   AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl
Log:
- minor changes in renderPropertiesForm, which should create an HTML
  structure which I can easily parse and xmlize to the same structure I
  received
- added XMLWriter to helper.js.dtml



Modified: AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml	Thu Jun 23
08:45:16 2005
(at)(at) -69,4 +69,14 (at)(at)
         this.displayed_form.set(this.activity_id, this.html) 
     }
 }
+
+// (at)attributes is a dictionary
+ActivityDialog.prototype.serializeActivity = function(name, content,
attributes) {
+    var name = name
+    var content = content
+    var attributes = attributes
+    var xmlwriter = XMLWriter(name, content, attributes)
+
+    return xmlwriter.elementNL()
+}
 // ActivityDialog

Modified: AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml	Thu Jun 23 08:45:16
2005
(at)(at) -56,6 +56,7 (at)(at)
 function Dictionary()
 {
     this.array = new Array()
+    this.length = this.array.length
 
     this.set = function(key, value) {
         var key = key
(at)(at) -77,6 +78,15 (at)(at)
         }
         return result
     }
+    
+    this.items = function() {
+        var result = new Array()
+        for ( i=0; i<this.array.length; i++ ) {
+            var pair = this.array[i]
+            result.push(pair)
+        }
+        return result
+    }
 
     this.get = function(key) {
         var key = key
(at)(at) -99,6 +109,81 (at)(at)
 
 }
 
+// simple XML writer based on the XML Hack #95 from hacks.oreilly.com
+function XMLWriter(this.name, this.content, this.attributes)
+{
+    this.name = name
+    this.content = content
+    this.attributes = attributes
+    
+    // attributes is a dictionary object
+    this.element = function() {
+        var xml
+        var attrstr = ''
+
+        if (this.attributes)
+            attrstr = formatAttributes(this.attributes)
+            
+        if (!this.content)
+            xml = '<' + this.name + attrstr + '/>'
+        else
+            xml = '<' + this.name + attrstr + '>' + this.content +
'</' +
+                 this.name + '>'
+
+        return xml
+    }
+
+    // creates an element tag with a newline appended
+    this.elementNL = function() {
+        return this.element() + '\n'
+    }
+
+    this.formatAttributes = function(attributes) {
+        var APOS = "'"; QUOTE = '"'
+        var ESCAPED_QUOTE = { }
+        ESCAPED_QUOTE[QUOTE] = '&quot;'
+        ESCAPED_QUOTE[APOS] = '&apos;'
+        
+        var value
+        var apos_pos, quot_pos
+        var use_quote, escape, quote_to_escape
+        var attr_str
+        var re
+        var result = ''
+
+        for (var attr in attributes) {
+            value = attributes.get(attr)
+
+            // find quote marks
+            apos_pos = value.indexOf(APOS)
+            quot_pos = value.indexOf(QUOTE)
+
+            // determine the quote type
+            if (apos_pos == -1 && quot_pos == -1) {
+                attr_str = ' ' + attr + "='" + value + "'"
+                result += attr_str
+                continue
+            }
+
+            // prefer double quotes
+            if (quot_pos != -1 && quot_pos < apos_pos)
+                use_quote = QUOTE
+            else
+                use_quote = APOS
+            
+
+            // figure kind of quotes to escape
+            escape = ESCAPED_QUOTE[use_quote]
+
+            re = new RegExp(use_quote, 'g')
+            attr_str = ' ' + att + '=' + use_quote +
+                value.replace(re, escape) + use_quote
+            result += attr_str
+        }
+    return result
+    }
+}
+
 function debug(what) {
    
document.getElementById('Graph').appendChild(document.createTextNode(what))
 }

Modified: AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl
==============================================================================
--- AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl	(original)
+++ AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl	Thu Jun 23 08:45:16
2005
(at)(at) -32,7 +32,14 (at)(at)
         </xsl:if>
       </h1>
       <xsl:for-each select="/*/descendant-or-self::node()">
-        <xsl:apply-templates select="(at)*" />
+        <xsl:if test="string-length(name()) > 0">
+          <span>
+            <xsl:attribute name="class">
+              <xsl:value-of select="name()" />
+            </xsl:attribute>
+            <xsl:apply-templates select="(at)*" />
+          </span>
+        </xsl:if>
       </xsl:for-each>
       <a href="#"
          id="changeProperties"

SVN: r3082 - in AlphaFlow/trunk/editor/views: . ecmascript
Roman Joost <rj(at)gocept.com>
2005-06-23 14:18:29 [ FULL ]
Author: roman
Date: Thu Jun 23 14:13:51 2005
New Revision: 3082

Modified:
   AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml
   AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml
   AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl
Log:
- added PropertiesCollector and XMLWriter on Ecmascript client side
- minor bugfixes for the XSLT


Modified: AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/activity_dialog.js.dtml	Thu Jun 23
14:13:51 2005
(at)(at) -11,6 +11,7 (at)(at)
 // initalize the event handlers
 ActivityDialog.prototype.initialize_events = function() {
     var groups = this.document.getElementsByTagName('g')
+    var changebutton = this.document.getElementById('changeProperties')
     
     for(i=0; i<groups.length; i++) {
         var g = groups[i]
(at)(at) -18,6 +19,7 (at)(at)
             addEventHandler(g, 'click', this.createActivityForm, this)
         }
     }
+    addEventHandler(changebutton, 'click', this.collectProperties, this)
 } 
 
 /* XXX duplicated code, should be factored out in future */
(at)(at) -70,13 +72,135 (at)(at)
     }
 }
 
-// (at)attributes is a dictionary
-ActivityDialog.prototype.serializeActivity = function(name, content,
attributes) {
-    var name = name
-    var content = content
-    var attributes = attributes
-    var xmlwriter = XMLWriter(name, content, attributes)
+// parse the properties panel and save all the key value pairs in our
+// dictionary, so we can build the XML out of it
+ActivityDialog.prototype.collectProperties = function() {
+    var panel = this.document.getElementById('Properties')
+    var collector = new PropertiesCollector(panel)
+   
+    var xml = this.serializeActivity(collector.properties)
+    debug(xml)
+}
 
+// (at)attributes is a dictionary
+ActivityDialog.prototype.serializeActivity = function(properties) {
+    var xmlwriter = new XMLWriter(properties)
     return xmlwriter.elementNL()
 }
 // ActivityDialog
+
+
+function PropertiesCollector(panel)
+{
+    this.panel = panel
+    this.properties = new Dictionary()
+   
+    // iterate over each form element in the panel and collect the items
+    // XXX maybe we could build something like a treewalker in the
+    // future
+    this.collectProperties = function() {
+        var sections = this.getPanelSections()
+        var elements = new Array()
+        
+        elements.push('select')
+        elements.push('input')
+        elements.push('textarea')
+        
+        // the following is a quick, ugly hack and will go away in
+        // the future
+        for ( var i in sections ) {
+            var temp = new Array()
+            for ( var j in elements ) {
+                var els = sections[i].getElementsByTagName(elements[j])
+            
+                for ( k=0; k<els.length; k++ ) {
+                    pair = this.collectItem(els[k])
+                    temp.push(pair)    
+                }
+            }
+            this.properties.set(sections[i].getAttribute('class'), temp)
+        }
+    }
+    
+    // The panel is rendered with span elements. Each span element has a
+    // class attribute, which indicates a tag name in ALF. This is
+    // needed, because we need to create the same XML we first got from
+    // the server to configure the activity. This method returns the
+    // names from each span element as an array
+    this.getPanelSections = function() {
+        var sections = new Array()
+        var spans = this.panel.getElementsByTagName('span')
+
+        for ( i=0; i<spans.length; i++) {
+            if ( spans[i].hasAttributes('class') )
+                sections.unshift(spans[i])
+        }
+        return sections
+    }
+    
+    // collects a (key, value) pair from a form element 
+    // eg. 
+    // <b>decision_notice:</b>
+    // <textarea name="decision_notice">first yes
counts</textarea>
+    // will result in
+    // 'decision_notice':'first yes counts'
+    this.collectItem = function(form_element) {
+        var form_element = form_element
+        var key = ""
+        var value = ""
+        var pair = new Array()
+
+        if (!form_element.hasAttributes('name'))
+            return
+        
+        key = form_element.getAttribute('name')
+
+        switch(form_element.nodeName) {
+            case "input":
+                value = this.getValueFromInput(form_element)
+                break;
+            case "textarea":
+                value = this.getValueFromTextarea(form_element)
+                break;
+            case "select":
+                value = this.getValueFromSelect(form_element)
+                break;
+            default:
+                value = ""
+                break;
+        }
+        
+        pair[0] = key
+        pair[1] = value
+        return pair
+    }
+
+    this.getValueFromTextarea = function(textarea) {
+        var textnode = textarea.firstChild
+
+        if (textnode.nodeType == 3) {
+            return textnode.nodeValue
+        }
+    }
+
+    this.getValueFromSelect = function(select) {
+        var select = select
+        var values = new Array()
+
+        for ( i=0; i<select.childNodes.length; i++ ) {
+            var child = select.childNodes[i]
+            if (child.nodeType == 1 &&
+                child.nodeName == "option" &&
+                child.selected)
+                values.push(child.getAttribute('name'))
+        }
+        
+        return values.join(",")
+    }
+
+    this.getValueFromInput = function(input) {
+        return input.getAttribute('value')
+    }
+
+    this.collectProperties()
+}

Modified: AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/helper.js.dtml	Thu Jun 23 14:13:51
2005
(at)(at) -68,6 +68,7 (at)(at)
         pair[0] = key
         pair[1] = value
         this.array.push(pair)
+        this.length = this.array.length
     }
 
     this.keys = function() {
(at)(at) -110,49 +111,33 (at)(at)
 }
 
 // simple XML writer based on the XML Hack #95 from hacks.oreilly.com
-function XMLWriter(this.name, this.content, this.attributes)
+function XMLWriter(properties)
 {
-    this.name = name
-    this.content = content
-    this.attributes = attributes
+    this.properties = properties
+    this.keys = properties.keys()
     
-    // attributes is a dictionary object
-    this.element = function() {
-        var xml
-        var attrstr = ''
-
-        if (this.attributes)
-            attrstr = formatAttributes(this.attributes)
-            
-        if (!this.content)
-            xml = '<' + this.name + attrstr + '/>'
-        else
-            xml = '<' + this.name + attrstr + '>' + this.content +
'</' +
-                 this.name + '>'
-
-        return xml
-    }
-
-    // creates an element tag with a newline appended
-    this.elementNL = function() {
-        return this.element() + '\n'
-    }
-
     this.formatAttributes = function(attributes) {
         var APOS = "'"; QUOTE = '"'
         var ESCAPED_QUOTE = { }
         ESCAPED_QUOTE[QUOTE] = '&quot;'
         ESCAPED_QUOTE[APOS] = '&apos;'
-        
-        var value
+       
+        var value, key, pair
         var apos_pos, quot_pos
         var use_quote, escape, quote_to_escape
         var attr_str
         var re
         var result = ''
-
-        for (var attr in attributes) {
-            value = attributes.get(attr)
+        
+        for ( i=0; i<attributes.length; i++) {
+            pair = attributes[i]
+            attr = pair[0]
+            value = pair[1]
+            
+            // continue if attr is empty, because printing an attribute
+            // with no key doesn't make any sense
+            if (!attr)
+                continue
 
             // find quote marks
             apos_pos = value.indexOf(APOS)
(at)(at) -182,6 +167,38 (at)(at)
         }
     return result
     }
+
+    
+    // attributes is a dictionary object
+    this.element = function(name, attributes) {
+        var xml
+        var attrstr = ''
+        
+        if ( attributes )
+            attrstr = this.formatAttributes( attributes )
+        
+        if ( this.keys.length == 0 ) {
+            xml = '<' + name + attrstr + '/>'
+        } else {
+            
+            if ( this.keys.length > 0 ) {
+                var nextname = this.keys.pop()
+                var nextattributes = this.properties.get( nextname )
+                var content = this.element( nextname, nextattributes )
+                xml = '<' + name + attrstr + '>' + content + '</' +
name + '>'
+            }
+        }
+        
+        return xml
+    }
+
+    // creates an element tag with a newline appended
+    this.elementNL = function() {
+        name = this.keys.pop()
+        attributes = this.properties.get(name)
+        return this.element(name, attributes) + '\n'
+    }
+
 }
 
 function debug(what) {

Modified: AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml
==============================================================================
--- AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml	(original)
+++ AlphaFlow/trunk/editor/views/ecmascript/message_dialog.js.dtml	Thu Jun 23
14:13:51 2005
(at)(at) -17,7 +17,7 (at)(at)
     for(i=0; i<groups.length; i++) {
         var g = groups[i]
        if (g.getAttribute('class') == 'node') {
-            //addEventHandler(g, 'mouseover', this.createTooltip, this)
+            addEventHandler(g, 'mouseover', this.createTooltip, this)
         }
     }
 } 

Modified: AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl
==============================================================================
--- AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl	(original)
+++ AlphaFlow/trunk/editor/views/renderPropertiesForm.xsl	Thu Jun 23 14:13:51
2005
(at)(at) -15,7 +15,7 (at)(at)
       <xsl:value-of select="." />
     </xsl:attribute>
     <xsl:attribute name="name">
-      <xsl:value-of select="node()" />
+      <xsl:value-of select="name()" />
     </xsl:attribute>
   </xsl:attribute-set>
   
(at)(at) -71,6 +71,7 (at)(at)
       <xsl:call-template name="select">
         <xsl:with-param name="key"
select="//(at)editor:availableActivities" />
         <xsl:with-param name="selected" select="//(at)accept_activity"
/>
+        <xsl:with-param name="multiple">yes</xsl:with-param>
       </xsl:call-template>
     </p>
   </xsl:template>
(at)(at) -81,6 +82,7 (at)(at)
       <xsl:call-template name="select">
         <xsl:with-param name="key"
select="//(at)editor:availableActivities" />
         <xsl:with-param name="selected" select="//(at)reject_activity"
/>
+        <xsl:with-param name="multiple">yes</xsl:with-param>
       </xsl:call-template>
     </p>
   </xsl:template>
(at)(at) -131,11 +133,15 (at)(at)
   <xsl:template name="select">
     <xsl:param name="key" />
     <xsl:param name="selected" />
+    <xsl:param name="multiple">false</xsl:param>
     <p>
       <select size="5">
         <xsl:attribute name="name">
           <xsl:value-of select="name()" />
         </xsl:attribute>
+        <xsl:attribute name="multiple">
+          <xsl:value-of select="$multiple" />
+        </xsl:attribute>
         <xsl:call-template name="option">
           <xsl:with-param name="str" select="$key"
           />

SVN: r3099 - in AlphaFlow/trunk: . activities editor tests tests/workflows
Michael Howitz <mh(at)gocept.com>
2005-06-27 15:30:37 [ FULL ]
Author: mac
Date: Mon Jun 27 15:24:52 2005
New Revision: 3099

Added:
   AlphaFlow/trunk/registry.py   (contents, props changed)
   AlphaFlow/trunk/tests/test_registry.py   (contents, props changed)
   AlphaFlow/trunk/tests/workflows/invalid_permission.alf
Modified:
   AlphaFlow/trunk/activities/alarm.py
   AlphaFlow/trunk/activities/condition.py
   AlphaFlow/trunk/activities/configuration.py
   AlphaFlow/trunk/activities/dcworkflow.py
   AlphaFlow/trunk/activities/decision.py
   AlphaFlow/trunk/activities/expression.py
   AlphaFlow/trunk/activities/gates.py
   AlphaFlow/trunk/activities/interfaces.py
   AlphaFlow/trunk/activities/notify.py
   AlphaFlow/trunk/activities/ntask.py
   AlphaFlow/trunk/activities/permission.py
   AlphaFlow/trunk/activities/recursion.py
   AlphaFlow/trunk/activities/review.py
   AlphaFlow/trunk/activities/routing.py
   AlphaFlow/trunk/activities/task.py
   AlphaFlow/trunk/activity.py
   AlphaFlow/trunk/editor/editor.py
   AlphaFlow/trunk/importexport.py
   AlphaFlow/trunk/interfaces.py
   AlphaFlow/trunk/process.py
   AlphaFlow/trunk/processmanager.py
   AlphaFlow/trunk/tests/test_definition.py
   AlphaFlow/trunk/tests/test_email.py
   AlphaFlow/trunk/tests/test_security.py
   AlphaFlow/trunk/utils.py
   AlphaFlow/trunk/workflowattr.py
Log:
- made registries fully flagged objects as instances of Registry class
- xml-import is done using the WorkflowAttributes and the DOMImporter class


Modified: AlphaFlow/trunk/activities/alarm.py
==============================================================================
--- AlphaFlow/trunk/activities/alarm.py	(original)
+++ AlphaFlow/trunk/activities/alarm.py	Mon Jun 27 15:24:52 2005
(at)(at) -21,9 +21,6 (at)(at)
     activity_type = nodeName = "alarm"
     icon = "alarm"
 
-    error_string = "TALES expression required which " \
-                   "should return a DateTime object, in %r."
-
 
 class AlarmWorkItem(BaseTalesWorkItem):
 

Modified: AlphaFlow/trunk/activities/condition.py
==============================================================================
--- AlphaFlow/trunk/activities/condition.py	(original)
+++ AlphaFlow/trunk/activities/condition.py	Mon Jun 27 15:24:52 2005
(at)(at) -16,7 +16,7 (at)(at)
 from Products.AlphaFlow.workitem import registerWorkItem, BaseTalesWorkItem
 from Products.AlphaFlow.activity import registerActivity, BaseTalesActivity
 from Products.AlphaFlow.interfaces import IConditionActivity,
IConditionWorkItem
-from Products.AlphaFlow import utils, config
+from Products.AlphaFlow import config
 from Products.AlphaFlow.workflowattr import WorkflowAttribute
 
 
(at)(at) -31,18 +31,16 (at)(at)
 
     attributes = BaseTalesActivity.attributes + (
         WorkflowAttribute('continue_activity', 'continue_activity', (),
-                          'Activities that can follow this automatic
activity.'
-                          ), # XXX required
+                          'Activities that can follow this automatic
activity.',
+                          required=True, encoding='ascii', datatype=tuple,
+                          ),
         WorkflowAttribute('expression', 'expression', '',
-                          'TALES expression which returns list of activities '
-                          'for continuation (must be in continue_activity)!',
+                          'TALES expression: Returns list of activities for '
+                          'continuation (which must be in
continue_activity!)',
                           importHandler=None, # done by BaseTalesActivity
                           exportHandler=None),
         )
 
-    error_string = "TALES expression required which must return a list of " \
-                   "WorkItem activity_types (in %r)"
-
 
     security.declareProtected(config.MANAGE_WORKFLOW,
                               "graphGetPossibleChildren")
(at)(at) -53,28 +51,15 (at)(at)
             acts.append({'id':act,
                          'label':'condition'})
         return acts
-
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        BaseTalesActivity.configureFromDOMNode(self, node)
-
-        if not node.hasAttribute("continue_activity"):
-            raise ConfigurationError, self.error_string % self.activity_type
-        self.continue_activity =
utils.flexSplit(node.getAttribute("continue_activity").encode('ascii'))
-
-
     
 
 class ConditionWorkItem(BaseTalesWorkItem):
 
-    activity_type  = "condition"
-    security = ClassSecurityInfo()
-
-    
     __implements__ = BaseTalesWorkItem.__implements__ + \
                      (IConditionWorkItem, )
+    security = ClassSecurityInfo()
 
-
+    activity_type  = "condition"
 
     ######################
     # ITalesWorkItem

Modified: AlphaFlow/trunk/activities/configuration.py
==============================================================================
--- AlphaFlow/trunk/activities/configuration.py	(original)
+++ AlphaFlow/trunk/activities/configuration.py	Mon Jun 27 15:24:52 2005
(at)(at) -6,17 +6,13 (at)(at)
 # Zope imports
 from AccessControl import ClassSecurityInfo
 
-# Plone/AT imports
-from Products.CMFCore.utils import getToolByName
-from Products.Archetypes import public as atapi
-
 # Sibling imports
 from Products.AlphaFlow.interfaces import \
      IConfigurationActivity, IConfigurationWorkItem
 from Products.AlphaFlow.workitem import \
     registerWorkItem, BaseAssignableWorkItem, Group
 from Products.AlphaFlow.activity import registerActivity,
BaseAssignableActivity
-from Products.AlphaFlow import utils, config
+from Products.AlphaFlow import config
 from Products.AlphaFlow.exception import ConfigurationError
 from Products.AlphaFlow.action import Action
 from Products.AlphaFlow.workflowattr import WorkflowAttribute
(at)(at) -33,39 +29,27 (at)(at)
     icon = "configuration"
 
     attributes = BaseAssignableActivity.attributes + (
+        # viewUrlExpression overwrites existing viewUrlExpression
         WorkflowAttribute('viewUrlExpression', 'view_url_expr',
                           'string:${content/absolute_url}/af_edit_workitem?'
                           'workitem=${workitem/getId}&action=configure',
                           '(TALES expression) URL to "view" a  workitem, '
                           'e.g. "Edit document" points to the edit-tab'),
         WorkflowAttribute('continue_activity', 'continue_activity', (),
-                          'Activity to start after completion.'),
-        WorkflowAttribute('configures', '', (),
+                          'Activity to start after completion.',
+                          encoding='ascii', datatype=tuple),
+        WorkflowAttribute('', 'configures_all', None,
+                          'Set to true to configure all activities.',
+                          importHandler=None, # done by _attr_*_configure
+                          exportHandler=None),
+        WorkflowAttribute('configures', 'configures', (),
                           'Other activities which are configured by this '
                           'activity or None as marker for all activities.',
-                          importHandler='attrImport_configure',
+                          encoding='ascii', datatype=tuple,
+                          importHandler='_attr_import_configure',
                           exportHandler='_attr_export_configure'),
         )
     
- 
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        ConfigurationActivity.inheritedAttribute(
-            'configureFromDOMNode')(self, node)
-
-        if node.hasAttribute("continue_activity"):
-            self.continue_activity = tuple(
-                utils.flexSplit(node.getAttribute(
-                "continue_activity").encode("ascii")))
-
-        if node.hasAttribute('configures_all'):
-            self.configures = None  # marker for "all"
-        elif node.hasAttribute('configures'):
-            self.configures = tuple(utils.flexSplit(node.getAttribute(
-                "configures").encode("ascii")))
-        else:
-            raise ConfigurationError, \
-                  "Attribute configures or configures_all needed."
 
     def graphGetPossibleChildren(self):
         "Return a list of possible following activities. (List of ids)"
(at)(at) -87,8 +71,19 (at)(at)
         if self.configures is None: # marker for "all"
             node.setAttribute('configures_all', convert_to_xml(True))
         else:
-            node.setAttribute('configures',
-                              convert_to_xml(self.configures))
+            self._attr_export_simple(attr, node)
+
+
+    def _attr_import_configure(self, attr, node):
+        if node.hasAttribute('configures_all'):
+            setattr(self, attr.classAttr, None) # None is marker for "all"
+        elif node.hasAttribute('configures'):
+            self._attr_import_simple(attr, node)
+        else:
+            raise ConfigurationError, \
+                  "%r: Attribute configures or configures_all needed." % (
+                self.nodeName,)
+
 
 
 class ConfigurationWorkItem(BaseAssignableWorkItem):

Modified: AlphaFlow/trunk/activities/dcworkflow.py
==============================================================================
--- AlphaFlow/trunk/activities/dcworkflow.py	(original)
+++ AlphaFlow/trunk/activities/dcworkflow.py	Mon Jun 27 15:24:52 2005
(at)(at) -29,22 +29,14 (at)(at)
 
     attributes = BaseAutomaticActivity.attributes + (
         WorkflowAttribute('status', 'status', '',
-                          'Status which is set as DCWorkFlow status.'),
+                          'Status which is set as DCWorkFlow status.',
+                          required=True, encoding='ascii', datatype=str),
         )
 
     _properties = BaseAutomaticActivity._properties + \
         ({'id': 'status', 'type': 'text', 'mode': 'w'},
          )
-    
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        BaseAutomaticActivity.configureFromDOMNode(self, node)
-    
-        if not node.hasAttribute("status"):
-            raise ConfigurationError, "Status required in %r" % (
-                self.activity_type, )
-        self.status = node.getAttribute("status").encode("ascii")
-           
+
 
 class DCWorkFlowWorkItem(BaseAutomaticWorkItem):
 

Modified: AlphaFlow/trunk/activities/decision.py
==============================================================================
--- AlphaFlow/trunk/activities/decision.py	(original)
+++ AlphaFlow/trunk/activities/decision.py	Mon Jun 27 15:24:52 2005
(at)(at) -6,17 +6,15 (at)(at)
 # Zope imports
 from AccessControl import ClassSecurityInfo, getSecurityManager
 
-# # Plone/AT imports
-# from Products.CMFCore.utils import getToolByName
+# Plone/AT imports
 from Products.Archetypes import public as atapi
 
-# # Sibling imports
+# Sibling imports
 from Products.AlphaFlow.interfaces import IDecisionActivity, IDecisionWorkItem
 from Products.AlphaFlow.workitem import BaseAssignableWorkItem,
registerWorkItem
 from Products.AlphaFlow.activity import BaseAssignableActivity,
registerActivity
-from Products.AlphaFlow import config, utils
+from Products.AlphaFlow import config
 from Products.AlphaFlow.action import Action
-from Products.AlphaFlow.exception import ConfigurationError
 from Products.AlphaFlow.workflowattr import WorkflowAttribute
 
 
(at)(at) -34,18 +32,23 (at)(at)
     activity_type = nodeName = "decision"
     icon = "decision"
 
+    known_decision_modi = ['first_yes', 'all_yes']
+
     attributes = BaseAssignableActivity.attributes + (
         WorkflowAttribute('decision_notice', 'decision_notice', '',
                           'Describing the task for the decision.'),
         WorkflowAttribute('decision_modus', 'decision_modus', '',
-                          'One of ["first_yes", "all_yes"]'),
+                          'One of self.known_decision_modi',
+                          required=True,
+                          vocabulary=known_decision_modi),
         WorkflowAttribute('reject_activity', 'reject_activity', (),
-                          'Activity if result is "no".'),
+                          'Activity if result is "no".',
+                          encoding='ascii', datatype=tuple),
         WorkflowAttribute('accept_activity', 'accept_activity', (),
-                          'Activity if result is "yes".'),
+                          'Activity if result is "yes".',
+                          encoding='ascii', datatype=tuple),
         )
 
-    known_decision_modi = ['first_yes', 'all_yes']
 
     configurationSchema = BaseAssignableActivity.configurationSchema.copy()
     # gets modified by __init__!
(at)(at) -75,29 +78,6 (at)(at)
         """Return a list of possible following activities. (List of ids)"""
         return self.reject_activity + self.accept_activity
 
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        DecisionActivity.inheritedAttribute('configureFromDOMNode')(self,
node)
-        has = node.hasAttribute
-        get = node.getAttribute
-        if has("decision_notice"):
-            self.decision_notice = get("decision_notice")
-        if has("reject_activity"):
-            self.reject_activity = tuple(
-                utils.flexSplit(get("reject_activity").encode("ascii"))
-            )
-        if has("accept_activity"):
-            self.accept_activity = tuple(
-                utils.flexSplit(get("accept_activity").encode("ascii"))
-            )
-        if not has("decision_modus"):
-            raise ConfigurationError, "Attribute decision_modus has to be set"
-        self.decision_modus = get("decision_modus")
-        if self.decision_modus not in self.known_decision_modi:
-            raise ConfigurationError, "Attribute decision_modus value needs
to"\
-                  " be in %s" % self.known_decision_modi
-        
-            
 
     def graphGetPossibleChildren(self):
         """Return a list of possible following activities. (List of ids)"""

Modified: AlphaFlow/trunk/activities/expression.py
==============================================================================
--- AlphaFlow/trunk/activities/expression.py	(original)
+++ AlphaFlow/trunk/activities/expression.py	Mon Jun 27 15:24:52 2005
(at)(at) -40,22 +40,15 (at)(at)
     # XXX change this on migration to BaseTalesActivity as base class
     attributes = BaseAutomaticActivity.attributes + (
         WorkflowAttribute('expression', 'expression', '',
-                          'Expression to be called.'),                        
 
+                          'Expression to be called.',
+                          required=True, encoding='ascii', datatype=str),
         )
         
     _properties = BaseAutomaticActivity._properties + \
         ({'id': 'expression', 'type': 'string', 'mode': 'w'},
          )
 
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        BaseAutomaticActivity.configureFromDOMNode(self, node)
-    
-        if not node.hasAttribute("expression"):
-            raise ConfigurationError, "expression required in %r" % (
-                self.activity_type)
-        self.expression = node.getAttribute("expression").encode("ascii")
-           
+
 
 class ExpressionWorkItem(BaseAutomaticWorkItem):
 

Modified: AlphaFlow/trunk/activities/gates.py
==============================================================================
--- AlphaFlow/trunk/activities/gates.py	(original)
+++ AlphaFlow/trunk/activities/gates.py	Mon Jun 27 15:24:52 2005
(at)(at) -20,32 +20,26 (at)(at)
     activity_type = nodeName = "gate"
     icon = "gate"
 
+    # Multimerge is like "OR" (trigger on each)
+    # Discriminate is like "XOR" (trigger on first, ignore others)
+    # Synchronize is like "AND" (trigger once when all completed)
+    mode_types = ('multi-merge', 'discriminate', 'synchronizing-merge')
+
+
     attributes = BaseAutomaticActivity.attributes + (
         WorkflowAttribute('mode', 'mode', '',
-                          'Mode the gate works, values see self.mode_types'),
+                          'Mode the gate works, values see self.mode_types',
+                          required=True, encoding='ascii', datatype=str,
+                          vocabulary=mode_types),
         )
 
-    mode_types = ('multi-merge', 'discriminate', 'synchronizing-merge')
+
 
     _properties = BaseAutomaticActivity._properties + \
         ({'id': 'mode', 'type': 'selection', 'mode': 'w',
           'select_variable': 'mode_types'},
          )
 
-    # Discriminate is like "XOR" (trigger on first, ignore others)
-    # Multimerge is like "OR" (trigger on each)
-    # Synchronize is like "AND" (trigger once when all completed)
-
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        GateActivity.inheritedAttribute('configureFromDOMNode')(self, node)
-        if not node.hasAttribute("mode"):
-            raise ConfigurationError, "Mode required in %r" % (
-                    self.activity_type, )
-        self.mode = node.getAttribute('mode').encode("ascii")
-        if self.mode not in self.mode_types:
-            raise ConfigurationError, "Mode must be one of %s for %r" % (
-                    self.mode_types, self.activity_type)
 
 
 class GateWorkItem(BaseWorkItem):

Modified: AlphaFlow/trunk/activities/interfaces.py
==============================================================================
--- AlphaFlow/trunk/activities/interfaces.py	(original)
+++ AlphaFlow/trunk/activities/interfaces.py	Mon Jun 27 15:24:52 2005
(at)(at) -94,7 +94,7 (at)(at)
     this workflow."""
 
     def getRecipientModes():
-        """Return list of IEMailRecipientMode instances."""
+        """Return list of IEMailRecipientMode instances (possible
recipents)."""
 
 
 class IEMailWorkItem(IAutomaticWorkItem):

Modified: AlphaFlow/trunk/activities/notify.py
==============================================================================
--- AlphaFlow/trunk/activities/notify.py	(original)
+++ AlphaFlow/trunk/activities/notify.py	Mon Jun 27 15:24:52 2005
(at)(at) -1,6 +1,6 (at)(at)
 # Copyright (c) 2004-2005 gocept gmbh & co. kg
 # See also LICENSE.txt
-# notify.py,v 1.3 2005/02/23 12:48:50 zagy Exp
+# $Id$
 """Implement the email activities.
 """
 
(at)(at) -25,10 +25,30 (at)(at)
 from Products.AlphaFlow.interfaces import \
         IEMailActivity, IEMailWorkItem, IEMailRecipientMode
 from Products.AlphaFlow.workflowattr import \
-     WorkflowAttribute, InitializeWorkflowAttributes
-from Products.AlphaFlow.importexport import DOMExporter
+     WorkflowAttribute, InitializeWorkflowAttributes, findAttrInAttributes
+from Products.AlphaFlow.importexport import DOMExporter, DOMImporter
+from Products.AlphaFlow.registry import Registry
 
 
+class EMailRegistry(Registry):
+    """Registry for email recipents."""
+
+    def getFromDOMNode(self, node):
+        """Get a class object from data given in DOM-Node.
+
+        node.getAttribute('mode_name') is used as key.
+        """
+        if node.nodeName != AbstractRecipent.nodeName:
+            raise KeyError, 'Only recipent modes in this registry'
+        return self.get(node.getAttribute('type'))
+
+
+#################################
+# Registry for all recipent modes
+# Registry keys should be class.mode_name
+notify_registry = EMailRegistry()
+
+
 class EMailActivity(BaseAutomaticActivity):
 
     __implements__ = BaseAutomaticActivity.__implements__ + \
(at)(at) -41,57 +61,30 (at)(at)
     attributes = BaseAutomaticActivity.attributes + (
         WorkflowAttribute('template', 'template', '',
                           'ID of a DTML-Method-Object being available from '
-                          'portal root.'),
+                          'portal root.',
+                          required=True, encoding='ascii', datatype=str),
         WorkflowAttribute('mailSubject', 'mailSubject',
                           'AlphaFlow notification message',
-                          'Static subject line for the mails sent.'),
+                          'Static subject line for the mails sent.',
+                          required=True),
         WorkflowAttribute('recipientModes', '', (),
-                          'One of ["owner", "next_assignees", "actual_role"] '
-                          'who will get the email.',
-                          importHandler="attrImport_email",
+                          'Who will get the email. (possible values see'
+                          'default of mode_name in subclasses of '
+                          'AbstractRecipent)',
+                          required=True, datatype=tuple,
+                          importHandler="_attr_import_email",
                           exportHandler="_attr_export_email"),
         )
 
-    # XXX this is error prone because on new recipent_mode this gets forgotten
-    # XXX to update. should use getRecipientModes!
-    possible_recipients = ['owner', 'next_assignees', 'actual_role']
-
     _properties = BaseAutomaticActivity._properties + \
         ({'id': 'template', 'type': 'string', 'mode': 'w',},
-         {'id': 'recipient', 'type': 'selection', 'mode': 'w',
-          'select_variable': 'possible_recipients'},
+         {'id': 'recipient', 'type': 'string', 'mode': 'w',},
          {'id': 'mailSubject', 'type': 'ustring', 'mode': 'w'},
          )
-    
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        global recipient_modes
-        BaseAutomaticActivity.configureFromDOMNode(self, node)
-    
-        if not node.hasAttribute("template"):
-            raise ConfigurationError, "template required in %r" % (
-                self.activity_type, )
-        self.template = node.getAttribute("template").encode("ascii")
-
-        if not node.hasAttribute("mailSubject"):
-            raise ConfigurationError, "mailSubject required in %r" % (
-                self.activity_type, )
-        self.mailSubject = node.getAttribute("mailSubject")
-
-        modes = []
-        for recipient in node.getElementsByTagName("recipient"):
-            mode_name = recipient.getAttribute("type").encode("ascii")
-            mode = recipient_modes[mode_name]()
-            mode.configureFromDOMNode(recipient)
-            modes.append(mode)
 
-        if len(modes) == 0:
-            raise ConfigurationError, "No recipients specified in %r" % self
-        
-        self.recipientModes = tuple(modes)
 
     def getRecipientModes(self):
-        """Return list of IEMailRecipientMode instances."""
+        "Return list of IEMailRecipientMode instances (possible recipents)."
         return self.recipientModes
 
     #########
(at)(at) -100,7 +93,15 (at)(at)
     def _attr_export_email(self, attr, node):
         for mode in self.recipientModes:
             mode.writeDOM(node)
-            
+
+    def _attr_import_email(self, attr, node):
+        global notify_registry
+        
+        modes = self.createAndConfigureChildNodes(node, notify_registry)
+        if len(modes) == 0:
+            raise ConfigurationError, "No recipients specified in %r" % self
+        self.recipientModes = attr.datatype(modes)
+
 
 
 class EMailWorkItem(BaseAutomaticWorkItem):
(at)(at) -188,7 +189,9 (at)(at)
                 email)
 
 
-class AbstractRecipent(Persistent, DOMExporter):
+
+
+class AbstractRecipent(Persistent, DOMExporter, DOMImporter):
     """Abstract recipient class."""
 
     __implements__ = (IEMailRecipientMode, )
(at)(at) -196,10 +199,6 (at)(at)
     nodeName = "recipient"
     attributes = ()
 
-    def configureFromDOMNode(self, node):
-        """Configures the activity from the given DOM node."""
-        pass
-
 
 
 class RecipientOwner(AbstractRecipent):
(at)(at) -245,21 +244,14 (at)(at)
 class RecipientActualRole(AbstractRecipent):
     """Recipient mode for notifying users with one of the given roles."""
     
-    attributes = (WorkflowAttribute('mode_name', 'type', 'actual_role',
-                                    'Identifier for a specific mode.',
-                                    importHandler=None),
-                  WorkflowAttribute('roles', 'roles', (),
-                                    'Members with this roles get an e-mail.'),
-                  )
-
-    def configureFromDOMNode(self, node):
-        """Configures the activity from the given DOM node."""
-        roles = node.getAttribute("roles").encode("ascii")
-        if len(roles) == 0:
-            raise ConfigurationError, "roles attribute of %s is empty" % \
-                    node.getParentNode().getAttribute("id")
-        
-        self.roles = tuple(flexSplit(roles))
+    attributes = (
+        WorkflowAttribute('mode_name', 'type', 'actual_role',
+                          'Identifier for a specific mode.',
+                          importHandler=None),
+        WorkflowAttribute('roles', 'roles', (),
+                          'Members with this roles get an e-mail.',
+                          required=True, encoding="ascii", datatype=tuple),
+        )
 
     def getRecipientsForWorkItem(self, wi):
         """Returns list of users with at least one of the given roles."""
(at)(at) -272,18 +264,19 (at)(at)
 
         return relevant
 
-recipient_modes = {}
 
-def registerEMailRecipientMode(mode):
-    global recipient_modes
-    recipient_modes[mode.mode_name] = mode
+
+def registerRecipentMode(mode):
+    global notify_registry
+    InitializeWorkflowAttributes(mode,
+                                 findAttrInAttributes(mode,
+                                                      'mode_name').default,
+                                 registry=notify_registry)
+    
 
 # register the stuff
 registerActivity(EMailActivity)
 registerWorkItem(EMailWorkItem)
-InitializeWorkflowAttributes(RecipientOwner)
-InitializeWorkflowAttributes(RecipientNextAssignees)
-InitializeWorkflowAttributes(RecipientActualRole)
-registerEMailRecipientMode(RecipientOwner)
-registerEMailRecipientMode(RecipientNextAssignees)
-registerEMailRecipientMode(RecipientActualRole)
+registerRecipentMode(RecipientOwner)
+registerRecipentMode(RecipientNextAssignees)
+registerRecipentMode(RecipientActualRole)

Modified: AlphaFlow/trunk/activities/ntask.py
==============================================================================
--- AlphaFlow/trunk/activities/ntask.py	(original)
+++ AlphaFlow/trunk/activities/ntask.py	Mon Jun 27 15:24:52 2005
(at)(at) -1,6 +1,6 (at)(at)
 # Copyright (c) 2005 gocept gmbh & co. kg
 # See also LICENSE.txt
-# ntask.py,v 1.12.2.1 2005/05/02 10:08:51 zagy Exp
+# $Id$
 """NTask activity and work item."""
 
 # Zope imports
(at)(at) -19,28 +19,26 (at)(at)
 from Products.AlphaFlow.exception import ConfigurationError
 from Products.AlphaFlow.action import Action
 from Products.AlphaFlow.workflowattr import \
-     WorkflowAttribute, InitializeWorkflowAttributes
-from Products.AlphaFlow.importexport import DOMExporter
+     WorkflowAttribute, InitializeWorkflowAttributes, \
+     workflow_attributes_registry
+from Products.AlphaFlow.importexport import DOMExporter, DOMImporter
 
-class Exit(Persistent, DOMExporter):
+class Exit(Persistent, DOMExporter, DOMImporter):
 
     __implements__ = (IExit, )
 
     nodeName = "exit"
     attributes = (
         WorkflowAttribute('id', 'id', None,
-                          'Id of the exit.'),
+                          'Id of the exit.',
+                          encoding="ascii", datatype=str),
         WorkflowAttribute('title', 'title', None,
                           'Title of the exit.'),
         WorkflowAttribute('activities', 'activities', (),
-                          'Continue activities if this exit gets chosen.'),
+                          'Continue activities if this exit gets chosen.',
+                          encoding='ascii', datatype=tuple),
         )
     
-    def __init__(self, id, title, activities):
-        self.id = id
-        self.title = title
-        self.activities = activities
-
 
 
 
(at)(at) -55,7 +53,8 (at)(at)
     attributes = BaseAssignableActivity.attributes + (
         WorkflowAttribute('exits', '', (),
                           'Tuple of IExit objects',
-                          importHandler="attrImport_ntask",
+                          datatype=tuple,
+                          importHandler="_attr_import_ntask",
                           exportHandler="_attr_export_ntask"),
         )
     
(at)(at) -70,22 +69,6 (at)(at)
                 )),
         )) + BaseAssignableActivity.configurationSchema
 
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        NTaskActivity.inheritedAttribute('configureFromDOMNode')(self, node)
-
-        exit_ids = []
-        exits = []
-        for exit in node.getElementsByTagName("exit"):
-            id = exit.getAttribute('id').encode('ascii')
-            if id in exit_ids:
-                raise ConfigurationError, "Double exit id: %s" % id
-            title = exit.getAttribute('title')
-            activities = utils.flexSplit(
-                    exit.getAttribute('activities').encode('ascii'))
-            exits.append(Exit(id, title, activities))
-            exit_ids.append(id)
-        self.exits = tuple(exits)
 
     def getPossibleChildren(self):
         """Return a list of possible following activities. (List of ids)"""
(at)(at) -113,6 +96,18 (at)(at)
         for exit in getattr(self, attr.classAttr):
             exit.writeDOM(node)
 
+    def _attr_import_ntask(self, attr, node):
+        "Import exits."
+        exits = self.createAndConfigureChildNodes(node,
+                                                 
workflow_attributes_registry)
+        exit_ids = [x.id for x in exits]
+        for exit_id in exit_ids[:]:
+            exit_ids.remove(exit_id)
+            if exit_id in exit_ids:
+                raise ConfigurationError, "Double exit id: %s" % exit_id
+        setattr(self, attr.classAttr, attr.datatype(exits))
+
+
 
 class NTaskWorkItem(BaseAssignableWorkItem):
 
(at)(at) -180,6 +175,6 (at)(at)
 
 
 # register the stuff
-InitializeWorkflowAttributes(Exit)
+InitializeWorkflowAttributes(Exit, Exit.nodeName)
 registerActivity(NTaskActivity)
 registerWorkItem(NTaskWorkItem)

Modified: AlphaFlow/trunk/activities/permission.py
==============================================================================
--- AlphaFlow/trunk/activities/permission.py	(original)
+++ AlphaFlow/trunk/activities/permission.py	Mon Jun 27 15:24:52 2005
(at)(at) -17,43 +17,40 (at)(at)
         IPermissionActivity, IPermissionWorkItem, IPermissionSetting
 from Products.AlphaFlow.workitem import registerWorkItem,
BaseAutomaticWorkItem
 from Products.AlphaFlow.activity import registerActivity,
BaseAutomaticActivity
-from Products.AlphaFlow.utils import \
-    modifyRolesForPermission, makeBoolFromUnicode, flexSplit
+from Products.AlphaFlow.utils import modifyRolesForPermission
 from Products.AlphaFlow.workflowattr import \
-     WorkflowAttribute, InitializeWorkflowAttributes
+     WorkflowAttribute, InitializeWorkflowAttributes, \
+     workflow_attributes_registry
 from Products.AlphaFlow.exception import ConfigurationError
 from Products.AlphaFlow import config
-from Products.AlphaFlow.importexport import DOMExporter
+from Products.AlphaFlow.importexport import DOMExporter, DOMImporter
 
-class PermissionSetting(DOMExporter):
+class PermissionSetting(DOMExporter, DOMImporter):
    
     __implements__ = (IPermissionSetting, )
 
     nodeName = "permission"
-    attributes = (WorkflowAttribute('permission', 'name', '',
-                                    'The permission affected.'),
+    attributes = (WorkflowAttribute('permission', 'id', '',
+                                    'id is deprecated, use name!',
+                                    encoding="ascii", datatype=str,
+                                    importHandler='_attr_import_permid',
+                                    exportHandler=None),
+                  WorkflowAttribute('permission', 'name', '',
+                                    'The permission affected.',
+                                    encoding="ascii", datatype=str),
                   WorkflowAttribute('roles', 'roles', '',
-                                    'Sequence of affected roles.'),
+                                    'Sequence of affected roles.',
+                                    encoding="ascii", datatype=tuple),
                   WorkflowAttribute('acquire', 'acquire', '',
-                                    '(bool) acquire permission or not.'),
+                                    '(bool) acquire permission or not.',
+                                    required=True, datatype=bool),
                   )
 
-    def __init__(self, context, permission, roles, acquire):
-        self.permission = permission
-        self.roles = roles
-        self.acquire = acquire
-        self._validate(context)
-
     def _validate(self, context):
         """Validate the permission configuration.
 
         - Permissions are required to exist
-        - Acquire must be a boolean.
         """
-        if not isinstance(self.acquire, bool):
-            raise ValueError, "Acquire must be bool"
-       
-        # assert the permission does exist
         app = context.getPhysicalRoot()
         permission_valid = False
         permission = self.permission
(at)(at) -62,11 +59,18 (at)(at)
             if name == permission:
                 permission_valid = True
                 break
-
         if not permission_valid:
-            raise ValueError, "The permission %r is invalid." % permission
+            raise ConfigurationError, \
+                  "The permission %r does not exist." % permission
+
+    def _attr_import_permid(self, attr, node):
+        warn('<permission id="..." /> is deprecated, use name="..."
instead. '
+             'id will get removed in version 1.1.',
+             DeprecationWarning, stacklevel=4)
+        self._attr_import_simple(attr, node)
+    
 
-InitializeWorkflowAttributes(PermissionSetting)
+InitializeWorkflowAttributes(PermissionSetting, PermissionSetting.nodeName)
 
 
 class PermissionActivity(BaseAutomaticActivity):
(at)(at) -82,43 +86,11 (at)(at)
     attributes = BaseAutomaticActivity.attributes + (
         WorkflowAttribute('permissions', '', (),
                           'Tuple of IPermissionSettings',
-                          importHandler="attrImport_permission",
+                          datatype=tuple,
+                          importHandler="_attr_import_permission",
                           exportHandler="_attr_export_permission"),
         )
 
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        BaseAutomaticActivity.configureFromDOMNode(self, node)
-        defs = []
-        for perm in node.childNodes:
-            if perm.nodeType in (perm.TEXT_NODE, perm.COMMENT_NODE):
-                # ignore text and comment nodes
-                continue
-            if perm.nodeType != perm.ELEMENT_NODE:
-                raise ConfigurationError, "Invalid node type %r (%r)" % (
-                    perm.nodeType, perm.nodeName)
-            if perm.nodeName != "permission":
-                raise ConfigurationError, "Invalid node %r" % (
-                    node.nodeName, )
-            
-            get = perm.getAttribute
-            has = perm.hasAttribute
-            if has('id'):
-                warn('<permission id="..." /> is deprecated, use
name="..." instead. '
-                     'id will get removed in version 1.1.',
-                     DeprecationWarning, stacklevel=4)
-                perm = get("id").encode("ascii")
-            else:
-                perm = get("name").encode("ascii")
-            roles = flexSplit(get("roles").encode("ascii"))
-            acquire = makeBoolFromUnicode(get("acquire"))
-            try:
-                p = PermissionSetting(self, perm, roles, acquire)
-            except ValueError, e:
-                raise ConfigurationError, e
-            defs.append(p)
-        self.permissions = tuple(defs)
-        
     security.declareProtected(config.MANAGE_WORKFLOW, 'setPermissions')
     def setPermissions(self, permission_setting):
         permissions = []
(at)(at) -135,6 +107,14 (at)(at)
         for permObj in self.permissions:
             permObj.writeDOM(node)
 
+    security.declarePrivate('_attr_import_permission')
+    def _attr_import_permission(self, attr, node):
+        permissions = self.createAndConfigureChildNodes(
+            node, workflow_attributes_registry)
+        self.permissions = attr.datatype(permissions)
+        for perm in self.permissions:
+            perm._validate(self)
+
 
 class PermissionWorkItem(BaseAutomaticWorkItem):
     

Modified: AlphaFlow/trunk/activities/recursion.py
==============================================================================
--- AlphaFlow/trunk/activities/recursion.py	(original)
+++ AlphaFlow/trunk/activities/recursion.py	Mon Jun 27 15:24:52 2005
(at)(at) -5,6 +5,7 (at)(at)
 
 # Zope imports
 from AccessControl import ClassSecurityInfo
+import zLOG
 
 # Plone/AT imports
 from Products.CMFCore.utils import getToolByName
(at)(at) -15,11 +16,11 (at)(at)
 from Products.AlphaFlow.workitem import registerWorkItem,
BaseAutomaticWorkItem
 from Products.AlphaFlow.activity import \
     registerActivity, BaseAutomaticActivity
-from Products.AlphaFlow import config, utils
+from Products.AlphaFlow import config
 from Products.AlphaFlow.interfaces import IDaemonActivity
 from Products.AlphaFlow.workflowattr import WorkflowAttribute
 
-import zLOG
+
 
 
 class RecursionActivity(BaseAutomaticActivity):
(at)(at) -32,13 +33,15 (at)(at)
 
     attributes = BaseAutomaticActivity.attributes + (
         WorkflowAttribute('recursion_activity', 'recursion_activity', (),
-                          'Activities which will get called recursively.'),
+                          'Activities which will get called recursively.',
+                          encoding='ascii', datatype=tuple),
         WorkflowAttribute('break_activities', 'break_activities', (),
-                          'Activities which stop recursion.'),
+                          'Activities which stop recursion.',
+                          encoding='ascii', datatype=tuple),
         WorkflowAttribute('optional_recursion', 'optional_recursion', True,
                           'User can select via UI if recursion should be '
                           'called.',
-                          importHandler="_attr_import_bool"),
+                          datatype=bool),
         )
     
     configurationSchema = Schema((
(at)(at) -62,21 +65,6 (at)(at)
         """Return a list of possible following activities. (List of ids)"""
         return self.recursion_activity + self.continue_activity
 
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        RecursionActivity.inheritedAttribute('configureFromDOMNode')(self,
node)
-        if node.hasAttribute("recursion_activity"):
-            self.recursion_activity = tuple(
-               
utils.flexSplit(node.getAttribute("recursion_activity").encode("ascii"))
-            )
-        if node.hasAttribute("break_activities"):
-            self.break_activities = tuple(
-               
utils.flexSplit(node.getAttribute("break_activities").encode("ascii"))
-            )
-        if node.hasAttribute('optional_recursion'):
-            self.optional_recursion = \
-                bool(node.getAttribute('optional_recursion'))
-
     def graphGetPossibleChildren(self):
         """Return a list of possible following activities. (List of ids)"""
         acts = []

Modified: AlphaFlow/trunk/activities/review.py
==============================================================================
--- AlphaFlow/trunk/activities/review.py	(original)
+++ AlphaFlow/trunk/activities/review.py	Mon Jun 27 15:24:52 2005
(at)(at) -39,9 +39,11 (at)(at)
         WorkflowAttribute('review_notice', 'review_notice', '',
                           'Describing the review role.'),
         WorkflowAttribute('reject_activity', 'reject_activity', (),
-                          'Activity if one votes "no".'),
+                          'Activity if one votes "no".',
+                          encoding='ascii', datatype=tuple),
         WorkflowAttribute('accept_activity', 'accept_activity', (),
-                          'Activity if all vote "yes".'),
+                          'Activity if all vote "yes".',
+                          encoding='ascii', datatype=tuple),
         )
 
     configurationSchema = BaseAssignableActivity.configurationSchema.copy()
(at)(at) -77,18 +79,6 (at)(at)
         warn('Using ReviewActivity is deprecated, use DecisionActivity
instead.',
              DeprecationWarning, stacklevel=2)
         ReviewActivity.inheritedAttribute('configureFromDOMNode')(self, node)
-        has = node.hasAttribute
-        get = node.getAttribute
-        if has("review_notice"):
-            self.review_notice = get("review_notice")
-        if has("reject_activity"):
-            self.reject_activity = tuple(
-                utils.flexSplit(get("reject_activity").encode("ascii"))
-            )
-        if has("accept_activity"):
-            self.accept_activity = tuple(
-                utils.flexSplit(get("accept_activity").encode("ascii"))
-            )
 
     def graphGetPossibleChildren(self):
         """Return a list of possible following activities. (List of ids)"""

Modified: AlphaFlow/trunk/activities/routing.py
==============================================================================
--- AlphaFlow/trunk/activities/routing.py	(original)
+++ AlphaFlow/trunk/activities/routing.py	Mon Jun 27 15:24:52 2005
(at)(at) -9,7 +9,8 (at)(at)
 
 # Sibling imports
 from Products.AlphaFlow.workitem import registerWorkItem, BaseWorkItem
-from Products.AlphaFlow.activity import registerActivity, BaseActivity
+from Products.AlphaFlow.activity import \
+     registerActivity, BaseActivity, activity_registry
 from Products.AlphaFlow import config
 from Products.AlphaFlow.utils import killWorkItemRecursively
 from Products.AlphaFlow.interfaces import IRoutingActivity, IRoutingWorkItem
(at)(at) -41,7 +42,7 (at)(at)
     attributes = BaseActivity.attributes + (
         WorkflowAttribute('gates', '', (),
                           'Gate activities inside the route.',
-                          importHandler="attrImport_route",
+                          importHandler="_attr_import_route",
                           exportHandler="_attr_export_route"),
         WorkflowAttribute('routes', '', (),
                           'All activities inside route which are no gates.',
(at)(at) -55,25 +56,7 (at)(at)
          {'id': 'routes', 'type': 'multiple selection', 'mode': 'w',
           'select_variable': 'listActivityIds'},
          )
-    
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        BaseActivity.configureFromDOMNode(self, node)
-
-        process = self.getParentNode()
-        for child in node.childNodes:
-            if child.nodeType in (child.TEXT_NODE,
-                    child.COMMENT_NODE):
-                # Ignore whitespace
-                continue
-            act_id = child.getAttribute('id').encode('ascii')
-            act_type = child.nodeName
-            activity = process.addActivity(act_id, act_type)
-            activity.configureFromDOMNode(child)
-            if act_type == "gate":
-                self.gates = self.gates + (act_id,)
-            else:
-                self.routes = self.routes + (act_id,)
+
 
     security.declareProtected(config.MANAGE_WORKFLOW, "getPossibleChildren")
     def getPossibleChildren(self):
(at)(at) -99,6 +82,22 (at)(at)
         for activity_id in self.routes + self.gates:
             activity = process[activity_id]
             activity.writeDOM(node)
+
+    security.declarePrivate('_attr_import_route')
+    def _attr_import_route(self, attr, node):
+        process = self.acquireProcess()
+        childs = self.createAndConfigureChildNodes(node, activity_registry)
+        gates = []
+        routes = []
+        for child in childs:
+            act_id = child.getId()
+            process._set_activity(act_id, child)
+            if child.activity_type == "gate":
+                gates.append(act_id)
+            else:
+                routes.append(act_id)
+        self.gates = tuple(gates)
+        self.routes = tuple(routes)
            
 
 class RoutingWorkItem(BaseWorkItem):

Modified: AlphaFlow/trunk/activities/task.py
==============================================================================
--- AlphaFlow/trunk/activities/task.py	(original)
+++ AlphaFlow/trunk/activities/task.py	Mon Jun 27 15:24:52 2005
(at)(at) -30,7 +30,8 (at)(at)
 
     attributes = BaseAssignableActivity.attributes + (
         WorkflowAttribute('completion_activity', 'completion_activity', (),
-                          'Activity to start after completion.'),
+                          'Activity to start after completion.',
+                          encoding="ascii", datatype=tuple),
         )
     
     configurationSchema = atapi.Schema((
(at)(at) -55,18 +56,6 (at)(at)
         """Return a list of possible following activities. (List of ids)"""
         return self.completion_activity
 
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        TaskActivity.inheritedAttribute('configureFromDOMNode')(self, node)
-        if node.hasAttribute("completion_activity"):
-            self.completion_activity = tuple(
-               
utils.flexSplit(node.getAttribute("completion_activity").encode("ascii"))
-            )
-        if node.hasAttribute("assignees"):
-            raise ConfigurationError, \
-                  "The assignees attribute is deprecated, use assignees tag
instead!"
-#            self.assignees = node.getAttribute("assignees")
-
     def graphGetPossibleChildren(self):
         """Return a list of possible following activities. (List of ids)"""
         acts = []

Modified: AlphaFlow/trunk/activity.py
==============================================================================
--- AlphaFlow/trunk/activity.py	(original)
+++ AlphaFlow/trunk/activity.py	Mon Jun 27 15:24:52 2005
(at)(at) -26,9 +26,12 (at)(at)
 from Products.AlphaFlow.exception import ConfigurationError
 from Products.AlphaFlow.workflowattr import \
      WorkflowAttribute, InitializeWorkflowAttributes, findAttrInAttributes
-from Products.AlphaFlow.importexport import DOMExporter, convert_to_xml
+from Products.AlphaFlow.importexport import \
+     DOMExporter, DOMImporter, convert_to_xml
+from Products.AlphaFlow.registry import Registry
 
-class BaseActivity(PropertyManager, SimpleItem, DOMExporter):
+
+class BaseActivity(PropertyManager, SimpleItem, DOMExporter, DOMImporter):
     """A base class to implement activities"""
     
     __implements__ = SimpleItem.__implements__ + (IActivity,)
(at)(at) -44,16 +47,19 (at)(at)
                           importHandler=None,
                           exportHandler="_attr_export_id"),
         WorkflowAttribute('title', 'title', '',
-                          'Title of the activity.'),
+                          'Title of the activity.',
+                          encoding="utf-8", datatype=str),
         WorkflowAttribute('sortPriority', 'sort', 0,
                           'Lower priority activities will be shown first.',
-                          importHandler="_attr_import_int"),
+                          datatype=int),
         WorkflowAttribute('nonEditableFields', 'nonEditableFields', (),
                           'Fields in schema which are not to be edited '
-                          'aka configured by user of workflow.'),
+                          'aka configured by user of workflow.',
+                          datatype=tuple),
         WorkflowAttribute('startActivity', 'startActivity', (),
                           'Workitems to be spawned just before the '
-                          'workitem for this activity is started.'),
+                          'workitem for this activity is started.',
+                          datatype=tuple),
         WorkflowAttribute('editor:availableActivities',
                           'editor:availableActivities', None,
                           'a string which holds all activity ids for '
(at)(at) -62,31 +68,7 (at)(at)
                           exportHandler="_attr_export_activities_list"),
         )
 
-    def __init__(self, id):
-        self.id = id
-    
-    security.declareProtected(config.MANAGE_WORKFLOW, "configureFromDOMNode")
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        has = node.hasAttribute
-        get = node.getAttribute
-        if has("title"):
-            self.title = get('title') # XXX needed? .encode("utf-8") (breaks
WF export)
-        if has("sort"):
-            pri = get('sort')
-            try:
-                pri = int(pri)
-            except ValueError:
-                pass
-            else:
-                self.sortPriority = pri
-        if has("nonEditableFields"):
-            non_editable = utils.flexSplit(get("nonEditableFields"))
-            self.nonEditableFields = non_editable
-        if has('startActivity'):
-            start = utils.flexSplit(get('startActivity'))
-            self.startActivity = start
-    
+
     security.declareProtected(config.MANAGE_WORKFLOW, "acquireActivity")
     def acquireActivity(self):
         """returns the activity instance from the acquisition chain"""
(at)(at) -119,7 +101,7 (at)(at)
         "Return a list of possible successor activities as dictionaries."
         return [] # to be overwritten by subclasses
 
-    security.declarePrivate('_attr_export_id')
+    security.declarePrivate('_attr_export_activities_list')
     def _attr_export_activities_list(self, attr, node):
         "Export for editor specific attributes."
         node.setAttribute('xmlns:editor',
(at)(at) -146,7 +128,8 (at)(at)
     attributes = BaseActivity.attributes + (
         WorkflowAttribute('continue_activity', 'continue_activity', (),
                           'A list of activities that follow this'
-                          'automatic activity. (single exit)'),
+                          'automatic activity. (single exit)',
+                          encoding='ascii', datatype=tuple),
         )
 
 
(at)(at) -160,16 +143,8 (at)(at)
         """Return a list of possible following activities. (List of ids)"""
         return self.continue_activity
 
-    security.declareProtected(config.MANAGE_WORKFLOW, "configureFromDOMNode")
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        BaseActivity.configureFromDOMNode(self, node)
-        if node.hasAttribute("continue_activity"):
-            self.continue_activity = tuple(
-               
utils.flexSplit(node.getAttribute("continue_activity").encode("ascii"))
-                )
-
-    security.declareProtected(config.MANAGE_WORKFLOW,
"graphGetPossibleChildren")
+    security.declareProtected(config.MANAGE_WORKFLOW,
+                              "graphGetPossibleChildren")
     def graphGetPossibleChildren(self):
         """Return a list of possible following activities. (List of ids)"""
         acts = []
(at)(at) -183,7 +158,8 (at)(at)
 
 
 class BaseAssignableActivity(BaseActivity):
-
+    "Workflow activity instances of which may be assigned to a member."
+    
     __implements__ = BaseActivity.__implements__ + (IAssignableActivity, )
     security = ClassSecurityInfo()
     
(at)(at) -198,15 +174,18 (at)(at)
                           'e.g. "Edit document" points to the edit-tab'),
         WorkflowAttribute('contentRoles', 'content_roles', None,
                           'Roles which assigned users get on the '
-                          'content object.'),
+                          'content object.',
+                          encoding='ascii', datatype=tuple),
         WorkflowAttribute('assigneesKind', 'kind', 'possible',
                           'Defines the user assignment method, either '
                           '"possible" or "actual".',
+                          required=True, vocabulary=['actual', 'possible'],
                           importHandler="_attr_import_assignees",
                           exportHandler="_attr_export_assignees"),
         WorkflowAttribute('roles', 'roles', (),
                           'Roles to compute which members are assignees',
-                          importHandler=None, # done by attr_import_assignees
(see above)
+                          encoding='ascii', datatype=tuple,
+                          importHandler=None, # done by _attr_import_assignees
                           exportHandler=None),
         WorkflowAttribute('assigneesExpression', 'expression', None,
                           'Tales Expression returning a list of member ids, '
(at)(at) -227,31 +206,6 (at)(at)
             ),
         ))
 
-    security.declareProtected(config.MANAGE_WORKFLOW, "configureFromDOMNode")
-    def configureFromDOMNode(self, node):
-        BaseAssignableActivity.inheritedAttribute('configureFromDOMNode')(
-            self, node)
-        if node.hasAttribute('view_url_expr'):
-            self.viewUrlExpression = node.getAttribute('view_url_expr')
-        
-        if node.hasAttribute('roles'):
-            raise ConfigurationError, 'The roles attribute is deprecated.'
-        
-        assignees = node.getElementsByTagName('assignees')
-        if len(assignees) == 0:
-            # default behaviour
-            self.roles = ()
-        elif len(assignees) == 1:
-            self._parse_assignee(assignees[0])
-        else:
-            raise ConfigurationError, ('<assignees> is only allowed once
per '
-                                       'activity.')
-
-        if node.hasAttribute("content_roles"):
-            self.contentRoles = \
-                    tuple(utils.flexSplit(node.getAttribute('content_roles').
-                                          encode('ascii')))
-            
     security.declareProtected(config.WORK_WITH_PROCESS,
"getPossibleAssignees")
     def getPossibleAssignees(self):
         """Returns a list of possible users."""
(at)(at) -291,40 +245,8 (at)(at)
                 schema.delField('assignees')
         return schema
 
-    ########
+    #########
     # private
-    
-    security.declarePrivate('_parse_assignee')
-    def _parse_assignee(self, assignee):
-        """helper for configureFromDOMNode
-       """
-        has = assignee.hasAttribute
-        get = assignee.getAttribute
-
-        kind = None
-        if has('kind'):
-            kind = get('kind')
-        else:
-            raise ConfigurationError, '<assignees> requires a kind
attribute'
-        if kind not in ('possible', 'actual'):
-            raise ConfigurationError, ('<assignees kind="..."> must be
either '
-                                       '"possible" or "actual"')
-        self.assigneesKind = kind
-        
-        if has('roles') and has('expression'):
-            raise ConfigurationError, ('<assignees> can only have one of
'
-                                       'roles or expression')
-        if not (has('roles') or has('expression')):
-            raise ConfigurationError, ('<assignees> must have one of '
-                                       'roles or expression')
-        if has('roles'):
-            self.roles = tuple(utils.flexSplit(get("roles").encode("ascii")))
-        if has('expression'):
-            if kind == 'possible':
-                raise NotImplementedError, \
-                                    "possible/expression is not implemented"
-            self.assigneesExpression = get('expression')
-        
     security.declarePrivate('_get_assignees_default')
     def _get_assignees_default(self):
         return [getSecurityManager().getUser().getUserName()]
(at)(at) -365,12 +287,53 (at)(at)
                 assignees.setAttribute(curr_attr.domAttr,
                                        convert_to_xml(value))
 
+    security.declarePrivate('_attr_import_assignees')
+    def _attr_import_assignees(self, attr, node):
+        if node.hasAttribute('roles'):
+            raise ConfigurationError, 'The roles attribute is deprecated.'
+        assignees = node.getElementsByTagName('assignees')
+        if len(assignees) == 0:
+            # default behaviour
+            self.roles = ()
+        elif len(assignees) == 1:
+            self._parse_assignee(assignees[0])
+        else:
+            raise ConfigurationError, \
+                  '<assignees> is only allowed once per activity.'
+
+    security.declarePrivate('_parse_assignee')
+    def _parse_assignee(self, assignee):
+        """helper for _attr_import_assignees
+        """
+        has = assignee.hasAttribute
+        get = assignee.getAttribute
+        _import = self._attr_import_simple
+        attr = findAttrInAttributes
+
+        _import(attr(self, 'assigneesKind'), assignee)
+        kind = self.assigneesKind
+        
+        if has('roles') and has('expression'):
+            raise ConfigurationError, \
+                  '<assignees> can only have one of roles or
expression.'
+        if not (has('roles') or has('expression')):
+            raise ConfigurationError, \
+                  '<assignees> must have one of roles or expression.'
+        if has('roles'):
+            _import(attr(self, 'roles'), assignee)
+        if has('expression'):
+            if kind == 'possible':
+                raise NotImplementedError, \
+                                    "possible/expression is not implemented"
+            _import(attr(self, 'assigneesExpression'), assignee)
+
 
 InitializeClass(BaseAssignableActivity)
 
 
 class BaseTalesActivity(BaseAutomaticActivity):
-
+    "Activity based on execution of a TALES-expression."
+    
     __implements__ = BaseAutomaticActivity.__implements__ + \
                      (ITalesActivity, )
     security = ClassSecurityInfo()
(at)(at) -378,44 +341,23 (at)(at)
 
     attributes = BaseAutomaticActivity.attributes + (
         WorkflowAttribute('expression', 'expression', '',
-                          'TALES expression which is to be executed.'),
+                          'TALES expression which is to be executed.',
+                          required=True),
         )
     
-    error_string = "Tal expression required which" \
-                   "should return a DateTime object, in %r."
-
-
-    
-
     _properties = BaseAutomaticActivity._properties + \
         ({'id': 'expression', 'type': 'string', 'mode': 'w'},
          )
 
-    security.declareProtected(config.MANAGE_WORKFLOW, "configureFromDOMNode")
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        BaseAutomaticActivity.configureFromDOMNode(self, node)
-
-        if not node.hasAttribute("expression"):
-            raise ConfigurationError, self.error_string % self.activity_type
-        self.expression = node.getAttribute("expression")
-
 InitializeClass(BaseTalesActivity)
 
 
-###################
-# activity registry
-
-activity_registry = {}
+#############################
+# Registry for all activities
+# Registry keys should be class.nodeName
+activity_registry = Registry()
 
 def registerActivity(activity):
     InitializeClass(activity)
-    InitializeWorkflowAttributes(activity)
-    activity_registry[activity.activity_type] = activity
-
-def getActivity(activity_type):
-    return activity_registry[activity_type]
-
-def listActivities():
-    return activity_registry.keys()
-
+    InitializeWorkflowAttributes(activity, activity.nodeName,
+                                 registry=activity_registry)

Modified: AlphaFlow/trunk/editor/editor.py
==============================================================================
--- AlphaFlow/trunk/editor/editor.py	(original)
+++ AlphaFlow/trunk/editor/editor.py	Mon Jun 27 15:24:52 2005
(at)(at) -76,14 +76,16 (at)(at)
     security.declareProtected(config.EDIT_WORKFLOW, "getActivityIcons")
     def getActivityIcons(self, filter=[]):
         """returns a list of tuples with (activity, icon)"""
+        global activity_registry
+        
         result = []
-        activities = activity_registry.values()
-        for activity in activities:
+        activity_ids = activity_registry.keys()
+        for activity_id in activity_ids:
+            activity = activity_registry.get(activity_id)
             if activity.activity_type in filter:
                 continue
             name, icon = activity.activity_type, activity.icon
             result.append((name, icon))
-            
         return result
 
 InitializeClass(AlphaFlowEditor)

Modified: AlphaFlow/trunk/importexport.py
==============================================================================
--- AlphaFlow/trunk/importexport.py	(original)
+++ AlphaFlow/trunk/importexport.py	Mon Jun 27 15:24:52 2005
(at)(at) -12,9 +12,9 (at)(at)
 from AccessControl import ClassSecurityInfo
 
 # Sibling imports
-from Products.AlphaFlow.interfaces import IDOMExportable
-from Products.AlphaFlow import config
-#from Products.AlphaFlow.exception import ConfigurationError
+from Products.AlphaFlow.interfaces import IDOMExportable, IDOMConfigurable
+from Products.AlphaFlow import config, utils
+from Products.AlphaFlow.exception import ConfigurationError
 
 class DOMExporter:
     """Mixin class with DOM export capabilities."""
(at)(at) -24,22 +24,22 (at)(at)
     
     security.declarePrivate("writeDOM")
     def writeDOM(self, node):
-        "Write the activity into dom node."
+        "Write the object into dom node."
         if hasattr(node, 'ownerDocument') and node.ownerDocument is not None:
             doc = node.ownerDocument # node inside
         else:
             doc = node # Document itself
-        activity = node.appendChild(doc.createElement(self.nodeName))
+        own_node = node.appendChild(doc.createElement(self.nodeName))
         for attr in self.attributes:
             if attr.exportHandler is None:
                 continue
             exportHandler = getattr(self, attr.exportHandler)
-            exportHandler(attr, activity)
+            exportHandler(attr, own_node)
         
 
     security.declareProtected(config.EDIT_WORKFLOW, "getXML")
     def getXML(self, REQUEST=None):
-        """returns the AlphaFlow XML for this activity"""
+        """returns the AlphaFlow XML for this object"""
         doc = minidom.Document()
         self.writeDOM(doc)
         xml = doc.toxml()
(at)(at) -54,7 +54,10 (at)(at)
     def _attr_export_simple(self, attr, node):
         "Export for attributes which need no special handling."
         value = getattr(self, attr.classAttr)
-        node.setAttribute(attr.domAttr, convert_to_xml(value))
+        value = convert_to_xml(value)
+        if attr.encoding is not None:
+            value = value.decode(attr.encoding)
+        node.setAttribute(attr.domAttr, value)
         
     security.declarePrivate('_attr_export_id')
     def _attr_export_id(self, attr, node):
(at)(at) -64,6 +67,110 (at)(at)
 InitializeClass(DOMExporter)
 
 
+class DOMImporter:
+    """Mixin class with capabilities to import attributes from DOM."""
+
+    __implements__ = (IDOMConfigurable, )
+    security = ClassSecurityInfo()
+
+
+    def __init__(self, id, *args, **kw):
+        "Constructor"
+        self.id = id
+
+
+    security.declareProtected(config.MANAGE_WORKFLOW, 'configureFromDOMNode')
+    def configureFromDOMNode(self, node):
+        "Configures the object from the given DOM node."
+        for attr in self.attributes:
+            if attr.importHandler is None:
+                continue
+            importHandler = getattr(self, attr.importHandler)
+            importHandler(attr, node)
+
+    security.declareProtected(config.MANAGE_WORKFLOW,
+                              'createAndConfigureChildNodes')
+    def createAndConfigureChildNodes(self, node, registry):
+        "Configure all child nodes of node."
+        created = []
+        for obj_node in node.childNodes:
+            if obj_node.nodeType in (obj_node.TEXT_NODE,
+                                     obj_node.COMMENT_NODE):
+                # Ignore textnodes, whitespace ...
+                continue
+            obj_type = obj_node.nodeName
+            if obj_node.nodeType != obj_node.ELEMENT_NODE:
+                raise ConfigurationError, "Invalid node type %r (%r)" % (
+                    obj_node.nodeType, obj_type)
+            obj_id = obj_node.getAttribute('id').encode('ascii')
+            try:
+                klass = registry.getFromDOMNode(obj_node)
+            except KeyError:
+                raise ConfigurationError, \
+                      "XMLImporter does not know how to handle %r tag." % (
+                    obj_type,)
+            obj = klass(obj_id)
+             # some validation methods need context, so give it now temporary
+            if hasattr(obj, '__of__'):
+                obj_wrapped = obj.__of__(self)
+            else:
+                obj_wrapped = obj
+            obj_wrapped.configureFromDOMNode(obj_node)
+            created.append(obj)
+        return created
+
+
+    ########################
+    # public import handlers
+
+    security.declarePrivate('_attr_import_simple')
+    def _attr_import_simple(self, attr, node):
+        "Import for attributes which need no special handling."
+        dom_attr = attr.domAttr
+        node_name = node.nodeName
+        datatype = attr.datatype
+        value = ''
+        if node.hasAttribute(dom_attr):
+            value = node.getAttribute(dom_attr)
+        if attr.required and value == '': # req but not set
+            raise ConfigurationError, \
+                  "%s requires attribute %s!" % (node_name, dom_attr)
+        if attr.encoding is not None:
+            value = value.encode(attr.encoding)
+        if datatype in [list, tuple]:
+            value = datatype(utils.flexSplit(value))
+            if not len(value):
+                value = attr.default
+        elif datatype == bool:
+            if value == '': # not set and not required
+                value = attr.default
+            else:
+                try:
+                    value = utils.makeBoolFromUnicode(value)
+                except ValueError:
+                    import sys
+                    raise ConfigurationError, str(sys.exc_info()[1])
+        else:
+            # do not try to convert strings or empty values
+            if not (isinstance(datatype, basestring) or value == ''):
+                try:
+                    value = datatype(value)
+                except ValueError:
+                    raise ConfigurationError, \
+                          "%s.%s must be of %s" % (node_name, dom_attr,
+                                                   datatype)
+            if value == '': # no attribute or empty value
+                value = attr.default
+        if attr.vocabulary is not None and value not in attr.vocabulary:
+            raise ConfigurationError, \
+                  "%s.%s must be one of %s" % (node_name, dom_attr,
+                                               attr.vocabulary)
+        setattr(self, attr.classAttr, value)
+
+
+InitializeClass(DOMImporter)
+
+
 ###################
 # helper methods
 

Modified: AlphaFlow/trunk/interfaces.py
==============================================================================
--- AlphaFlow/trunk/interfaces.py	(original)
+++ AlphaFlow/trunk/interfaces.py	Mon Jun 27 15:24:52 2005
(at)(at) -1,6 +1,6 (at)(at)
 # Copyright (c) 2004-2005 gocept gmbh & co. kg
 # See also LICENSE.txt
-# interfaces.py,v 1.61.2.3 2005/05/02 09:02:02 zagy Exp
+# $Id$
 
 from Interface import Interface, Attribute
 
(at)(at) -9,20 +9,34 (at)(at)
 class IDOMConfigurable(Interface):
     """Implemented by objects which are configurable by DOM nodes."""
 
+    def __init__(id, *args, **kw):
+        """Constructor must have this signature.
+
+        id ... id for the object
+        """
+
     def configureFromDOMNode(node):
-        """Configures the activity from the given DOM node.
+        """Configures the object from the given DOM node.
 
            Returns nothing.
+           May raise ConfigurationError.
+        """
+
+    def createAndConfigureChildNodes(self, node):
+        """Create and configure all child nodes of node.
+
+        Returns list of created activities.
         """
 
+
 class IDOMExportable(Interface):
     """Implemented by objects which can export itself into a DOM."""
 
     def writeDOM(node):
-        """Write the activity into dom node.
+        """Write the object into dom node.
 
         node ... dom node or document
-        Returns the created activity node
+        Returns the created dom node
         """
     
     def getXML(REQUEST=None):
(at)(at) -259,6 +273,7 (at)(at)
         """Add a new activity to this process definition by type.
 
            Returns the new activity.
+           Raises KeyError if activity_type is unknown.
         """
     def acquireProcess():
         """returns the process instance from the acquisition chain"""
(at)(at) -690,9 +705,7 (at)(at)
         portal - the portal root object
 
     """
-    error_string = Attribute("String which is shown when the "
-                             "expression-attribute is missing. (String must"
-                             "include a %r for the activity_type.)")
+
 
 class ITalesWorkItem(IAutomaticWorkItem):
     """WorkItem which uses TALES-Expression."""
(at)(at) -707,29 +720,67 (at)(at)
 
 
 class IWorkflowAttribute(Interface):
-    """Attribute for an activity ... data used by import and export"""
+    """Attribute on objects in workflow (activity, process, ...)
 
-    classAttr = Attribute("Name of the attribute in the activity class.")
+    data used for import and export
+    """
+
+    classAttr = Attribute("Name of the attribute in the python class.")
     domAttr = Attribute("Name of the attribute in the dom.")
     default = Attribute("Default value.")
     description = Attribute("Description for the attribute.")
+    required = Attribute("Is this Attribute required?")
+    encoding = Attribute("Encode value with this encoding before converting to
"
+                         "datatype. May be None if no encoding needed.")
+    datatype = Attribute("Datatype of value as type.")
+    vocabulary = Attribute("List or tuple of allowed values or None.")
     importHandler = Attribute("Name of the method which handles the import "
                               "of this attribute or None for no import. "
                               "The method must accept exactly two parameters:"
-                              " - the activity attribute"
+                              " - the WorkflowAttribute"
                               " - the dom node to be read from")
     exportHandler = Attribute("Name of the method which handles the export "
                               "of this attribute or None for no export. "
                               "The method must accept exactly two parameters:"
-                              " - the activity attribute"
+                              " - the WorkflowAttribute"
                               " - the dom node to be written to")
 
     def __init__(classAttr, domAttr, default, description,
+                 required=False, encoding=None, datatype=unicode,
+                 vocabulary=None,
                  importHandler="_attr_import_simple",
                  exportHandler="_attr_export_simple"):
         "Constructor."
                               
-    
+class IRegistry(Interface):
+    """Registry for class objects."""
+
+    def register(key, klass):
+        """Register a class object on the registry.
+        
+        If key already exists, its value gets replaced.
+
+        key ... string: search key in registry
+        klass ... class: object behind key
+        Raises ValueError if klass is no class object.
+        """
+
+    def get(key):
+        """Get class object by key.
+
+        Raises KeyError if key not found.
+        """
+
+    def getFromDOMNode(node):
+        """Get a class object from data given in DOM-Node.
+
+        Which parts of DOM node are taken for getting the key depends on
+        implementation.
+
+        Raises KeyError if key not found.
+        """
+    def keys():
+        """Return the keys in the registry as a list."""
 
 
 # Need the activity interface here after a refactoring for backwards

Modified: AlphaFlow/trunk/process.py
==============================================================================
--- AlphaFlow/trunk/process.py	(original)
+++ AlphaFlow/trunk/process.py	Mon Jun 27 15:24:52 2005
(at)(at) -20,11 +20,11 (at)(at)
 from Products.AlphaFlow.interfaces import IProcess
 from Products.AlphaFlow import utils, config
 from Products.AlphaFlow.exception import ConfigurationError
-from Products.AlphaFlow.activity import listActivities, getActivity
+from Products.AlphaFlow.activity import activity_registry
 from Products.AlphaFlow.adapters.renderableadapter import getRenderableAdapter
 from Products.AlphaFlow.workflowattr import \
      WorkflowAttribute, InitializeWorkflowAttributes
-from Products.AlphaFlow.importexport import DOMExporter
+from Products.AlphaFlow.importexport import DOMExporter, DOMImporter
 
 
 manage_addProcessForm=PageTemplateFile('www/addProcess', globals())
(at)(at) -32,7 +32,7 (at)(at)
     self.manage_addProcess(id, REQUEST)
 
 
-class Process(Folder, DOMExporter):
+class Process(Folder, DOMExporter, DOMImporter):
 
     __implements__ = Folder.__implements__ + (IProcess,)
     meta_type = "AlphaFlow Process"
(at)(at) -86,11 +86,11 (at)(at)
         """Add a new activity to this process definition.
 
            Returns the new activity.
+           Raises KeyError if activity_type is unknown.
         """
-        act = getActivity(activity_type)(id)
-        self._setObject(id, act)
-        return getattr(self, id)
-        
+        act = activity_registry.get(activity_type)(id)
+        return self._set_activity(id, act)
+
     security.declareProtected(config.MANAGE_WORKFLOW, "listActivityIds")
     def listActivityIds(self):
         """Returns a list of activity ids from this process."""
(at)(at) -98,7 +98,7 (at)(at)
 
     security.declareProtected(config.MANAGE_WORKFLOW,
"listPossibleActivities")
     def listPossibleActivities(self):
-        return listActivities()
+        return activity_registry.keys()
 
     security.declareProtected(CMFCorePermissions.View, "getGraphVizGif")
     def getGraphVizGif(self, REQUEST):
(at)(at) -128,19 +128,10 (at)(at)
             roles = utils.flexSplit(get("onlyAllowRoles").encode('ascii'))
             self.roles = roles
 
-        # Extract all nodes
-        for act_node in node.childNodes:
-            if act_node.nodeType in (act_node.TEXT_NODE,
-                    act_node.COMMENT_NODE):
-                # Ignore textnodes, whitespace ...
-                continue
-            if act_node.nodeType != act_node.ELEMENT_NODE:
-                raise ConfigurationError, "Invalid node type %r (%r)" % (
-                    act_node.nodeType, act_node.nodeName)
-            act_id = act_node.getAttribute('id').encode('ascii')
-            act_type = act_node.nodeName
-            activity = self.addActivity(act_id, act_type)
-            activity.configureFromDOMNode(act_node)
+        # Setup ChildNodes
+        childs = self.createAndConfigureChildNodes(node, activity_registry)
+        for child in childs:
+            self._set_activity(child.id, child)
             
     security.declareProtected(config.EDIT_WORKFLOW, "getGraph")
     def renderGraph(self, **kwargs):
(at)(at) -215,9 +206,17 (at)(at)
     #########
     # private
     
+    security.declarePrivate('_set_allowed_roles_restriction')
     def _set_allowed_roles_restriction(self, roles):
         roles = tuple(roles)  # do not acquire
         utils.modifyRolesForPermission(self, config.INIT_PROCESS, roles)
 
+    security.declarePrivate('_set_activity')
+    def _set_activity(self, id, activity):
+        "Place the activity inside process."
+        self._setObject(id, activity)
+        return getattr(self, id)
+
+
 InitializeClass(Process)
-InitializeWorkflowAttributes(Process)
+InitializeWorkflowAttributes(Process, Process.nodeName)

Modified: AlphaFlow/trunk/processmanager.py
==============================================================================
--- AlphaFlow/trunk/processmanager.py	(original)
+++ AlphaFlow/trunk/processmanager.py	Mon Jun 27 15:24:52 2005
(at)(at) -433,7 +433,9 (at)(at)
            Returns the imported process definition.
         """
         if not hasattr(xmlfile, "read"):
-            raise ValueError, "Only file uploads are allowed for importing XML
data."
+            raise ValueError, \
+                  "Only file uploads or open files are allowed for " \
+                  "importing XML data."
         wf = parse(xmlfile).documentElement
         assert wf.tagName == "workflow", "This is not a workflow definition"
         # try to get the id from the process definition if available

Added: AlphaFlow/trunk/registry.py
==============================================================================
--- (empty file)
+++ AlphaFlow/trunk/registry.py	Mon Jun 27 15:24:52 2005
(at)(at) -0,0 +1,42 (at)(at)
+# Copyright (c) 2005 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id$
+"""Registry for activities etc."""
+
+# Python imports
+from types import ClassType
+
+# Zope imports
+from ExtensionClass import ExtensionClass
+
+# sibling imports
+from Products.AlphaFlow.interfaces import IRegistry
+
+class Registry:
+    """Registry for class objects."""
+
+    __implements__ = (IRegistry, )
+
+    _registry = None
+
+    def __init__(self):
+        self._registry = {}
+
+    def register(self, key, klass):
+        "Register a class object on the registry."
+        t_klass = type(klass)
+        if not (t_klass == ClassType or t_klass == ExtensionClass):
+            raise ValueError, "klass must be a classobj not %s." % t_klass
+        self._registry[key] = klass
+
+    def get(self, key):
+        "Get class object by key."
+        return self._registry[key]
+
+    def getFromDOMNode(self, node):
+        "Get a class object from data given in DOM-Node."
+        return self.get(node.nodeName)
+
+    def keys(self):
+        """Return the keys in the registry as a list."""
+        return self._registry.keys()

Modified: AlphaFlow/trunk/tests/test_definition.py
==============================================================================
--- AlphaFlow/trunk/tests/test_definition.py	(original)
+++ AlphaFlow/trunk/tests/test_definition.py	Mon Jun 27 15:24:52 2005
(at)(at) -26,15 +26,15 (at)(at)
 from Products.AlphaFlow.tests.AlphaFlowTestCase import AlphaFlowTestCase
 
 from Products.AlphaFlow.interfaces import \
-    IProcess, IAlphaFlowed, IInstance, IActivity, \
-    IWorkItem, IAutomaticWorkItem, IAction, IReviewWorkItem, IReviewActivity,
\
-    IWorkflowAttribute, ITalesActivity, IAssignableActivity,
IAutomaticActivity, \
-    IExit, IPermissionSetting
+    IProcess, IAlphaFlowed, IInstance, IActivity, IWorkItem, ITalesActivity, \
+    IAutomaticWorkItem, IAction, IReviewWorkItem, IReviewActivity, IExit, \
+    IWorkflowAttribute, IAssignableActivity, IAutomaticActivity, \
+    IPermissionSetting
 from Products.AlphaFlow.workflowedobject import AlphaFlowed
 from Products.AlphaFlow.instance import Instance
 from Products.AlphaFlow.process import Process
 from Products.AlphaFlow.activity import \
-     listActivities, getActivity, BaseTalesActivity, BaseAssignableActivity, \
+     activity_registry, BaseTalesActivity, BaseAssignableActivity, \
      BaseActivity, BaseAutomaticActivity
 from Products.AlphaFlow import config
 from Products.AlphaFlow.workitem import \
(at)(at) -45,9 +45,10 (at)(at)
 from Products.AlphaFlow.utils import flexSplit, unique
 from Products.AlphaFlow.exception import ConfigurationError
 from Products.AlphaFlow.workflowattr import \
-     WorkflowAttribute, InitializeWorkflowAttributes, getWorkflowAttributes, \
-     findAttrInAttributes
+     WorkflowAttribute, InitializeWorkflowAttributes, findAttrInAttributes, \
+     workflow_attributes_registry
 from Products.AlphaFlow.importexport import convert_to_xml
+from Products.AlphaFlow.activities.notify import notify_registry
 
 
 _chars = 'abcdefghijklmnopqrstuvwxyz'
(at)(at) -90,8 +91,8 (at)(at)
                           (IAutomaticActivity, BaseAutomaticActivity),
                           (IPermissionSetting, PermissionSetting),
                           (IReviewWorkItem, ReviewWorkItem)] + \
-                          [(IActivity, getActivity(act_id))
-                           for act_id in listActivities() ] + \
+                          [(IActivity, activity_registry.get(act_id))
+                           for act_id in activity_registry.keys() ] + \
                           [(IWorkItem, getWorkItemClass(wi_id))
                            for wi_id in listWorkItems()]
    
(at)(at) -132,18 +133,26 (at)(at)
         
 
     def _filter_relevant_attrs(self, node):
-        """Get a sorted list of the relevant (not empty, not default)
attributes."""
-        try:
-            act_attrs = getWorkflowAttributes(node.nodeName)
-        except KeyError:
+        "Get a sorted list of the relevant (not empty, not default)
attributes."
+        registries = [activity_registry, workflow_attributes_registry,
+                      notify_registry]
+        act_attrs = None
+        for registry in registries:
+            try:
+                act_attrs = registry.getFromDOMNode(node).attributes
+                break
+            except KeyError:
+                pass
+        if act_attrs is None:
             if node.nodeName == 'assignees':
-                task = getActivity('task')
+                task = activity_registry.get('task')
                 act_attrs = (findAttrInAttributes(task, 'assigneesKind'),
                              findAttrInAttributes(task, 'roles'),
                              findAttrInAttributes(task,
'assigneesExpression'),
                              )
             else:
-                raise
+                raise AssertionError, '%s: can not get Workflowattributes' % (
+                    node.nodeName)
         res = []
         for attr, value in node.attributes.items():
             if value == '':
(at)(at) -283,6 +292,10 (at)(at)
             "workflow tool")
         process.startActivity = ("write_document",)
 
+        # check if process.addActivity raises KeyError on unknown activity
type
+        self.assertRaises(KeyError, process.addActivity, "a",
+                          "__not%existing%type$__")
+
         # "task" is a special kind of activity to ask people to do
         # something
         write_document = process.addActivity("write_document", "task")
(at)(at) -703,6 +716,12 (at)(at)
         self.failUnless(instance.aq_base is doc.getInstance().aq_base)
         instance.restart('more testing')
         self.failUnless(instance.aq_base is doc.getInstance().aq_base)
+
+    def test_invalid_permission(self):
+        self.loginAsPortalOwner()
+        self.assertRaises(ConfigurationError, self._import_wf,
+                          'workflows/invalid_permission.alf')
+        
         
 def test_suite():
     suite = unittest.TestSuite()

Modified: AlphaFlow/trunk/tests/test_email.py
==============================================================================
--- AlphaFlow/trunk/tests/test_email.py	(original)
+++ AlphaFlow/trunk/tests/test_email.py	Mon Jun 27 15:24:52 2005
(at)(at) -65,9 +65,9 (at)(at)
         wi = instance.getWorkItems(state="complete")[0]
         self.assert_(IEMailWorkItem.isImplementedBy(wi))
         
-        ro = RecipientOwner()
-        rna = RecipientNextAssignees()
-        rar = RecipientActualRole()
+        ro = RecipientOwner('ro')
+        rna = RecipientNextAssignees('rna')
+        rar = RecipientActualRole('rar')
         rar.roles = ('Editor',)
 
         _test_recipients(ro, ['author'], wi)

Added: AlphaFlow/trunk/tests/test_registry.py
==============================================================================
--- (empty file)
+++ AlphaFlow/trunk/tests/test_registry.py	Mon Jun 27 15:24:52 2005
(at)(at) -0,0 +1,90 (at)(at)
+# Copyright (c) 2005 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id$
+
+import common
+
+
+import unittest
+from xml.dom import minidom
+
+from Testing import ZopeTestCase
+
+# from Products.Archetypes.tests.utils import *
+# from Products.Archetypes.tests.common import *
+
+# from Products.CMFCore.utils import getToolByName
+
+from Products.AlphaFlow.tests.AlphaFlowTestCase import AlphaFlowTestCase
+
+from Products.AlphaFlow.interfaces import IRegistry
+from Products.AlphaFlow.registry import Registry
+from Products.AlphaFlow.activities.notify import notify_registry,
RecipientOwner
+
+class Demo1:
+    pass
+
+class Demo2:
+    pass
+
+
+
+class RegistryTest(AlphaFlowTestCase):
+
+    interfaces_to_test = [(IRegistry, Registry),
+                          ]
+
+    def test_registry(self):
+        r = Registry()
+        self.assertRaises(ValueError, r.register, 'asdf', None)
+        self.assertRaises(ValueError, r.register, 'asdf', 'asdf')
+        self.assertRaises(ValueError, r.register, 'asdf', object())
+        self.assertRaises(KeyError, r.get, 'asdf')
+        self.assertEqual([], r.keys())
+        r.register('asdf', Demo1)
+        self.assertEqual(Demo1, r.get('asdf'))
+        self.assertEqual(['asdf'], r.keys())
+        r.register('qwe', Demo2)
+        self.assertEqual(Demo1, r.get('asdf'))
+        self.assertEqual(Demo2, r.get('qwe'))
+        r.register('asdf', Demo2)
+        self.assertEqual(Demo2, r.get('asdf'))
+        self.assertEqual(Demo2, r.get('qwe'))
+        keys = r.keys()
+        keys.sort()
+        self.failUnless(['asdf', 'qwe'], keys)
+        r.register('qwe', Demo1)
+        # test getFromDOMNode
+        dom1 = minidom.parseString('<asdf/>')
+        dom2 = minidom.parseString('<qwe asdf="asdf"/>')
+        dom3 = minidom.parseString('<zui/>')
+        self.assertEqual(Demo2, r.getFromDOMNode(dom1.documentElement))
+        self.assertEqual(Demo1, r.getFromDOMNode(dom2.documentElement))
+        self.assertRaises(KeyError, r.getFromDOMNode, dom3.documentElement)
+
+    def test_notify_registry(self):
+        global notify_registry
+
+        nr = notify_registry
+        self.assertRaises(KeyError, nr.get, 'asdf')
+        self.assertEqual(RecipientOwner, nr.get('owner'))
+        dom1 = minidom.parseString('<owner />')
+        dom2 = minidom.parseString('<owner type="owner" />')
+        dom3 = minidom.parseString('<recipient />')
+        dom4 = minidom.parseString('<recipient type="owner"/>')
+        self.assertRaises(KeyError, nr.getFromDOMNode, dom1.documentElement)
+        self.assertRaises(KeyError, nr.getFromDOMNode, dom2.documentElement)
+        self.assertRaises(KeyError, nr.getFromDOMNode, dom3.documentElement)
+        self.assertEqual(RecipientOwner,
+                         nr.getFromDOMNode(dom4.documentElement))
+
+
+
+def test_suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(RegistryTest))
+    return suite 
+
+if __name__ == '__main__':
+    framework()
+

Modified: AlphaFlow/trunk/tests/test_security.py
==============================================================================
--- AlphaFlow/trunk/tests/test_security.py	(original)
+++ AlphaFlow/trunk/tests/test_security.py	Mon Jun 27 15:24:52 2005
(at)(at) -25,7 +25,6 (at)(at)
 from Products.AlphaFlow.instance import Instance
 from Products.AlphaFlow.process import Process
 from Products.AlphaFlow.processmanager import ProcessManager
-from Products.AlphaFlow.activity import listActivities, getActivity
 from Products.AlphaFlow import config, utils
 from Products.AlphaFlow.exception import ConfigurationError
 from Products.AlphaFlow.eventchannel import EventChannelIndex

Added: AlphaFlow/trunk/tests/workflows/invalid_permission.alf
==============================================================================
--- (empty file)
+++ AlphaFlow/trunk/tests/workflows/invalid_permission.alf	Mon Jun 27 15:24:52
2005
(at)(at) -0,0 +1,24 (at)(at)
+<?xml version="1.0" encoding="iso-8859-1"?>
+
+<workflow   
+    startActivity="make_private"
+    onlyAllowRoles="Manager Reviewer">
+
+    <permission-change id="make_private"
+                       title="Autor-Rechte setzen"
+                       continue_activity="dc_private">
+        <permission name="Access contents information"
+                    acquire="false"
+                    roles="Manager Owner ProcessUser"/>
+        <!-- invalid permission-->
+        <permission name="Modipfui portool contains"
+                    acquire="false"
+                    roles="Manager Owner ProcessUser"/>
+        <permission name="View"
+                    acquire="false"
+                    roles="Manager Owner ProcessUser"/>
+    </permission-change>
+
+    <dcworkflow id="dc_private" status="private"/>
+
+</workflow>

Modified: AlphaFlow/trunk/utils.py
==============================================================================
--- AlphaFlow/trunk/utils.py	(original)
+++ AlphaFlow/trunk/utils.py	Mon Jun 27 15:24:52 2005
(at)(at) -359,7 +359,7 (at)(at)
 def flexSplit(string):
     string = string.replace(',', ' ')
     result = string.split(' ')
-    result = [ x for x in result if x ] # filter empty
+    result = [ x for x in result if x ] # filter out empty
     return result
    
 

Modified: AlphaFlow/trunk/workflowattr.py
==============================================================================
--- AlphaFlow/trunk/workflowattr.py	(original)
+++ AlphaFlow/trunk/workflowattr.py	Mon Jun 27 15:24:52 2005
(at)(at) -4,8 +4,8 (at)(at)
 """WorkflowAttribute definitions and helpers"""
 
 # Sibling imports
-from Products.AlphaFlow.interfaces import IWorkflowAttribute
-
+from Products.AlphaFlow.interfaces import IWorkflowAttribute, IActivity
+from Products.AlphaFlow.registry import Registry
 
 class WorkflowAttribute:
     """Attribute on objects in workflow (activity, process, ...)
(at)(at) -19,10 +19,16 (at)(at)
     domAttr = None
     default = ""
     description = ""
+    required=False
+    encoding=None
+    datatype=unicode
+    vocabulary=None
     importHandler = "_attr_import_simple"
     exportHandler = "_attr_export_simple"
 
     def __init__(self, classAttr, domAttr, default, description,
+                 required=False, encoding=None, datatype=unicode,
+                 vocabulary=None,
                  importHandler="_attr_import_simple",
                  exportHandler="_attr_export_simple"):
         if not isinstance(classAttr, str):
(at)(at) -33,6 +39,23 (at)(at)
         self.domAttr = domAttr
         self.default = default
         self.description = description
+        if not isinstance(datatype, type):
+            raise ValueError, "datatype must be a python type."
+        self.datatype = datatype
+        if not (isinstance(encoding, str) or encoding is None):
+            raise ValueError, "encoding must be a string encoding or None."
+        self.encoding = encoding
+        if encoding is not None and datatype == unicode:
+            raise ValueError, \
+                  "If encoding is not None, datatype must not be unicode."
+        if not isinstance(required, bool):
+            raise ValueError, "required must be a boolean."
+        self.required = required
+        if not (isinstance(vocabulary, list) or
+                isinstance(vocabulary, tuple) or
+                vocabulary is None):
+            raise ValueError, "vocabulary must be a list or None."
+        self.vocabulary = vocabulary
         if not (isinstance(importHandler, str) or importHandler is None):
             raise ValueError, "importHandler must be a string or None."
         self.importHandler = importHandler
(at)(at) -52,19 +75,24 (at)(at)
             return attr
 
 
-##########
-# registry
-
-_workflow_attributes_registry = {}
+#######################################################################
+# Registry for classes having WorkflowAttributes which are not in other
+# registries.
+# Registry keys should be class.nodeName
+workflow_attributes_registry = Registry()
+
+def InitializeWorkflowAttributes(klass, registry_key,
+                                 registry=workflow_attributes_registry):
+    """Write the WorkflowAttribute on the class object klass.
+
+    registry_key: Key under which the entry is stored in registry
+    registry: registry object (IRegistry) to register within
+              None means: do not register class
 
-def InitializeWorkflowAttributes(klass):
-    "Write the WorkflowAttribute on the class object klass."
+    """
     for attribute in klass.attributes:
         setattr(klass, attribute.classAttr, attribute.default)
-    _workflow_attributes_registry[klass.nodeName] = klass
-
-def getWorkflowAttributes(nodeName):
-    "Get the WorkflowAttributes for a class' nodeName."
-    return _workflow_attributes_registry[nodeName].attributes
+    if registry is not None:
+        registry.register(registry_key, klass)

SVN: r3103 - in AlphaFlow/trunk: . adapters editor tests
Michael Howitz <mh(at)gocept.com>
2005-06-28 09:39:29 [ FULL ]
Author: mac
Date: Tue Jun 28 09:34:19 2005
New Revision: 3103

Modified:
   AlphaFlow/trunk/adapters/alphaflowable.py
   AlphaFlow/trunk/editor/editor.py
   AlphaFlow/trunk/interfaces.py
   AlphaFlow/trunk/process.py
   AlphaFlow/trunk/processmanager.py
   AlphaFlow/trunk/tests/test_definition.py
Log:
- added export of process id
- moved duplicate code of importWorkflowFromXML to adapters/alphaflowable
- moved validateALF to adapters/alphaflowable
- Process now uses configureFromDOMNode from DOMImporter
- exportAsXML exports string UTF-8 encoded


Modified: AlphaFlow/trunk/adapters/alphaflowable.py
==============================================================================
--- AlphaFlow/trunk/adapters/alphaflowable.py	(original)
+++ AlphaFlow/trunk/adapters/alphaflowable.py	Tue Jun 28 09:34:19 2005
(at)(at) -1,6 +1,25 (at)(at)
+# Copyright (c) 2005 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id$
+
+# Python imports
+from xml.dom import minidom
+try:
+  import libxml2
+  have_libxml2 = True
+except ImportError:
+  have_libxml2 = False
+
+
+# sibling imports
 from Products.AlphaFlow.interfaces import IProcessManager, IAlphaFlowEditor
 from Products.AlphaFlow.adapters import adapter
 from Products.AlphaFlow.process import Process
+from Products.AlphaFlow import config
+from Products.AlphaFlow.activity import activity_registry
+
+validate_wf_defs = have_libxml2 and config.validate_wf_defs
+
 
 class ProcessManagerAdapter(adapter.Adapter):
 
(at)(at) -10,6 +29,57 (at)(at)
         self.context.processes._setObject(process_id, process)
         return getattr(self.context.processes, process_id)
 
+    def importWorkflowFromXML(self, id, xmlfile):
+        if not hasattr(xmlfile, "read"):
+            raise ValueError, \
+                  "Only file uploads or open files are allowed for " \
+                  "importing XML data."
+        wf = minidom.parse(xmlfile).documentElement
+        assert wf.tagName == "workflow", "This is not a workflow definition"
+        # try to get the id from the process definition if available
+        if not id:
+          id = wf.getAttribute('id').encode('ascii')
+        p = self.addProcess(id)
+        p.configureFromDOMNode(wf)
+        childs = p.createAndConfigureChildNodes(wf, activity_registry)
+        for child in childs:
+            p._set_activity(child.id, child)
+        if validate_wf_defs:
+          self.validateALF(p, xmlfile)
+        return p
+
+
+    def validateALF(self, process, xmlfile):
+        """Validate the process definition against a RelaxNG schema.
+
+           xmlfile: file, filename or fileupload instance
+        """
+        errors = []
+        def ALFValidationError(localcontext, unused):
+          e = libxml2.lastError()
+          errors.append((e.message(), e.level()))
+        
+        libxml2.registerErrorHandler(ALFValidationError, 'Schema Syntax')
+        rngp = libxml2.relaxNGNewMemParserCtxt(self.schema, len(self.schema))
+        rngs = rngp.relaxNGParse()
+        ctxt = rngs.relaxNGNewValidCtxt()
+
+        if isinstance(xmlfile, file) or hasattr(xmlfile, 'read'):
+          # seek to 0, because the file was already parsed
+          xmlfile.seek(0)
+        elif isinstance(xmlfile, str):
+          xmlfile = file(xmlfile)
+        else:
+          raise TypeError, "xmlfile must be str or file."
+
+        buff = xmlfile.read()
+        doc = libxml2.parseMemory(buff, len(buff))
+        doc.relaxNGValidateDoc(ctxt)
+        process.validation_errors = errors
+
+
+    
+
 def getAlphaFlowableAdapter(context):
     if IProcessManager.isImplementedBy(context) or\
        IAlphaFlowEditor.isImplementedBy(context):

Modified: AlphaFlow/trunk/editor/editor.py
==============================================================================
--- AlphaFlow/trunk/editor/editor.py	(original)
+++ AlphaFlow/trunk/editor/editor.py	Tue Jun 28 09:34:19 2005
(at)(at) -1,8 +1,8 (at)(at)
+# Copyright (c) 2005 gocept gmbh & co. kg
+# See also LICENSE.txt
+# $Id$
 """The workflow editor"""
 
-# Python imports
-from xml.dom import minidom
-
 # Zope imports
 from Globals import InitializeClass
 from AccessControl import ClassSecurityInfo
(at)(at) -55,23 +55,9 (at)(at)
     
     security.declareProtected(config.MANAGE_WORKFLOW, 'importWorkflowFromXML')
     def importWorkflowFromXML(self, id, xmlfile):
-        """Import a process definition from an xml file.
-
-           xmlfile: file, filename, fileupload instance
-
-           Returns the imported process definition.
-        """
-        # XXX duplicated code, this code is moved from process_manager
-        # to this location, but still in process_manager for backwards
-        # compatibility
-        wf = minidom.parse(xmlfile).documentElement
-        assert wf.tagName == "workflow", "This is not a workflow definition"
-        # try to get the id from the process definition if available
-        if not id:
-          id = wf.getAttribute('id').encode('ascii')
-        p = self.manage_addProcess(id)
-        p.configureFromDOMNode(wf)
-        return p
+        "Import a process definition from an xml file."
+        adapter = getAlphaFlowableAdapter(self)
+        return adapter.importWorkflowFromXML(id, xmlfile)
     
     security.declareProtected(config.EDIT_WORKFLOW, "getActivityIcons")
     def getActivityIcons(self, filter=[]):

Modified: AlphaFlow/trunk/interfaces.py
==============================================================================
--- AlphaFlow/trunk/interfaces.py	(original)
+++ AlphaFlow/trunk/interfaces.py	Tue Jun 28 09:34:19 2005
(at)(at) -205,12 +205,10 (at)(at)
     def importWorkflowFromXML(process_id, xmlfile):
         """Import a process definition from a xml file.
 
-           xmlfile: file, file name or fileupload instance
+           xmlfile: file or fileupload instance
 
            Returns the imported process definition.
         """
-    def validateALF(xmlfile):
-        """validates the process definition against a RelaxNG schema"""
 
     def pingCronItems():
         """Trigger all due alarmworkitems.
(at)(at) -305,7 +303,7 (at)(at)
         """Returns XML as a string containing editor information"""
 
     def exportAsXML():
-        """Exports process as XML-String."""
+        """Exports process as UTF-8 encoded XML-String."""
 
 
 class IActivity(IWorkflowAttributeAware, IDOMConfigurable, IDOMExportable):

Modified: AlphaFlow/trunk/process.py
==============================================================================
--- AlphaFlow/trunk/process.py	(original)
+++ AlphaFlow/trunk/process.py	Tue Jun 28 09:34:19 2005
(at)(at) -40,15 +40,22 (at)(at)
 
     nodeName = "workflow"
     attributes = (
+        WorkflowAttribute('id', 'id', None,
+                          'Id of the workflow definition.',
+                          encoding='ascii', datatype=str,
+                          importHandler=None,
+                          exportHandler='_attr_export_id'),
         WorkflowAttribute('title', 'title', '',
-                          'Title of this process definition.'),
+                          'Title of this process definition.',
+                          encoding='utf-8', datatype=str),
         WorkflowAttribute('startActivity', 'startActivity', (),
-                          'List of activity ids to instantiate at start.'),
+                          'List of activity ids to instantiate at start.',
+                          encoding='ascii', datatype=tuple),
         WorkflowAttribute('description', 'description', '',
                           'Description of this process definition.'),
         WorkflowAttribute('roles', 'onlyAllowRoles', [],
-                          'Only members with this roles my start this
workflow.'
-                          ),
+                          'Only members with this roles my start this
workflow.',
+                          encoding='ascii', datatype=list),
         )
 
 
(at)(at) -111,27 +118,6 (at)(at)
     def acquireProcess(self):
         """returns the process instance from the acquisition chain"""
         return self
-
-    security.declareProtected(config.MANAGE_WORKFLOW, 'configureFromDOMNode')
-    def configureFromDOMNode(self, node):
-        """Configures the activity from a given DOM-Node"""
-        # Setup my own data
-        has = node.hasAttribute
-        get = node.getAttribute
-        if has("title"):
-            self.title = get("title").encode("utf-8")
-        if has("startActivity"):
-            self.startActivity =
utils.flexSplit(get("startActivity").encode("ascii"))
-        if has("description"):
-            self.description = get("description")
-        if has("onlyAllowRoles"):
-            roles = utils.flexSplit(get("onlyAllowRoles").encode('ascii'))
-            self.roles = roles
-
-        # Setup ChildNodes
-        childs = self.createAndConfigureChildNodes(node, activity_registry)
-        for child in childs:
-            self._set_activity(child.id, child)
             
     security.declareProtected(config.EDIT_WORKFLOW, "getGraph")
     def renderGraph(self, **kwargs):
(at)(at) -170,7 +156,7 (at)(at)
 
     security.declareProtected(config.MANAGE_WORKFLOW, 'exportAsXML')
     def exportAsXML(self):
-        """Exports process as XML-String."""
+        """Exports process as UTF-8 encoded XML-String."""
         doc = self.getProcessDOM()
         workflow = doc.documentElement
         for activitiy in self.objectValues():
(at)(at) -184,7 +170,7 (at)(at)
         for node in workflow.childNodes[:]:
             if node.getAttribute('id') in inside_routes:
                 workflow.removeChild(node)
-        return doc.toxml()
+        return doc.toxml('utf-8')
             
     security.declareProtected(config.MANAGE_WORKFLOW,
                               'changeProcessProperties')

Modified: AlphaFlow/trunk/processmanager.py
==============================================================================
--- AlphaFlow/trunk/processmanager.py	(original)
+++ AlphaFlow/trunk/processmanager.py	Tue Jun 28 09:34:19 2005
(at)(at) -4,7 +4,6 (at)(at)
 """Process manager"""
 
 # Python imports
-from xml.dom.minidom import parse
 import sys
 
 try:
(at)(at) -38,7 +37,6 (at)(at)
 from Products.AlphaFlow import config, utils
 from Products.AlphaFlow.adapters.alphaflowable import getAlphaFlowableAdapter
 
-validate_wf_defs = have_libxml2 and config.validate_wf_defs
 
 _marker = object()
 
(at)(at) -426,55 +424,9 (at)(at)
         
     security.declareProtected(config.MANAGE_WORKFLOW, 'importWorkflowFromXML')
     def importWorkflowFromXML(self, id, xmlfile):
-        """Import a process definition from an xml file.
-
-           xmlfile: file, filename, fileupload instance
-
-           Returns the imported process definition.
-        """
-        if not hasattr(xmlfile, "read"):
-            raise ValueError, \
-                  "Only file uploads or open files are allowed for " \
-                  "importing XML data."
-        wf = parse(xmlfile).documentElement
-        assert wf.tagName == "workflow", "This is not a workflow definition"
-        # try to get the id from the process definition if available
-        if not id:
-          id = wf.getAttribute('id').encode('ascii')
-        p = self.addProcess(id)
-        p.configureFromDOMNode(wf)
-        if validate_wf_defs:
-          self.validateALF(p, xmlfile)
-        return p
-
-    security.declareProtected(config.MANAGE_WORKFLOW, 'validateALF')
-    def validateALF(self, process, xmlfile):
-        """Validate the process definition against a RelaxNG schema.
-
-           xmlfile: file, filename, fileupload instance
-        """
-        errors = []
-        def ALFValidationError(localcontext, unused):
-          e = libxml2.lastError()
-          errors.append((e.message(), e.level()))
-        
-        libxml2.registerErrorHandler(ALFValidationError, 'Schema Syntax')
-        rngp = libxml2.relaxNGNewMemParserCtxt(self.schema, len(self.schema))
-        rngs = rngp.relaxNGParse()
-        ctxt = rngs.relaxNGNewValidCtxt()
-
-        if isinstance(xmlfile, file) or hasattr(xmlfile, 'read'):
-          # seek to 0, because the file was already parsed
-          xmlfile.seek(0)
-        elif isinstance(xmlfile, str):
-          xmlfile = file(xmlfile)
-        else:
-          raise TypeError, "xmlfile must be str or file."
-
-        buff = xmlfile.read()
-        doc = libxml2.parseMemory(buff, len(buff))
-        doc.relaxNGValidateDoc(ctxt)
-        process.validation_errors = errors
+        "Import a process definition from an xml file."
+        adapter = getAlphaFlowableAdapter(self)
+        return adapter.importWorkflowFromXML(id, xmlfile)
 
     security.declarePublic('translate')
     def translateMsg(self, message, translation_domain='alphaflow', **kwargs):

Modified: AlphaFlow/trunk/tests/test_definition.py
==============================================================================
--- AlphaFlow/trunk/tests/test_definition.py	(original)
+++ AlphaFlow/trunk/tests/test_definition.py	Tue Jun 28 09:34:19 2005
(at)(at) -137,6 +137,7 (at)(at)
         registries = [activity_registry, workflow_attributes_registry,
                       notify_registry]
         act_attrs = None
+        nodeName = node.nodeName
         for registry in registries:
             try:
                 act_attrs = registry.getFromDOMNode(node).attributes
(at)(at) -144,7 +145,7 (at)(at)
             except KeyError:
                 pass
         if act_attrs is None:
-            if node.nodeName == 'assignees':
+            if nodeName == 'assignees':
                 task = activity_registry.get('task')
                 act_attrs = (findAttrInAttributes(task, 'assigneesKind'),
                              findAttrInAttributes(task, 'roles'),
(at)(at) -152,13 +153,15 (at)(at)
                              )
             else:
                 raise AssertionError, '%s: can not get Workflowattributes' % (
-                    node.nodeName)
+                    nodeName)
         res = []
         for attr, value in node.attributes.items():
             if value == '':
                 continue
             if attr.startswith("editor:") or attr.startswith("xmlns"):
                 continue
+            if nodeName == 'workflow' and attr == 'id':
+                continue # id in workflow tag may be left out or set by hand
             breaked = False
             for act_attr in act_attrs:
                 if act_attr.domAttr == attr:
(at)(at) -180,7 +183,8 (at)(at)
                 continue
             if pot_node.parentNode.nodeName != node.parentNode.nodeName:
                 continue
-            if pot_node.parentNode.getAttribute('id') != \
+            if pot_node.parentNode.nodeName != 'workflow' and \
+                   pot_node.parentNode.getAttribute('id') != \
                    node.parentNode.getAttribute('id'):
                 continue
             pot_node_items = self._filter_relevant_attrs(pot_node)
(at)(at) -190,19 +194,24 (at)(at)
             return pot_node
     
 
-    def _compare_DOM_nodes(self, exp_node, got_node, wf_name,
documentElement=False):
+    def _compare_DOM_nodes(self, exp_node, got_node, wf_name,
+                           documentElement=False):
 #        print exp_node.getAttribute('id'),
         self.failIf(got_node is None,
-                    "%s: %s(%s) missing in got DOM" % (wf_name,
-                                                       exp_node.nodeName,
-                                                      
exp_node.attributes.items()))
-        self.assertEqual(exp_node.getAttribute('id'),
-                         got_node.getAttribute('id'))
+                    "%s: %s(%s) missing in got DOM" % (
+            wf_name, exp_node.nodeName, exp_node.attributes.items()))
+        self.assertEqual(exp_node.nodeName, got_node.nodeName)
+        if exp_node.nodeName != 'workflow':
+            # workflow does not have compareable id
+            self.assertEqual(exp_node.getAttribute('id'),
+                             got_node.getAttribute('id'))
         if not documentElement:
             self.assertEqual(exp_node.parentNode.nodeName,
                              got_node.parentNode.nodeName)
-            self.assertEqual(exp_node.parentNode.getAttribute('id'),
-                             got_node.parentNode.getAttribute('id'))
+            if exp_node.parentNode.nodeName != "workflow":
+                # workflow does not have compareable id
+                self.assertEqual(exp_node.parentNode.getAttribute('id'),
+                                 got_node.parentNode.getAttribute('id'))
         
         exp_node_items = self._filter_relevant_attrs(exp_node)
         got_node_items = self._filter_relevant_attrs(got_node)
(at)(at) -236,9 +245,9 (at)(at)
                 continue
             wf_file.seek(0)
             test = alf.getProcess('test')
-#             if wf_name == "actual_assignees.alf":
+#             if wf_name == "configuration.alf":
 #                 import pdb; pdb.set_trace() #############################
-            got_dom = minidom.parseString(test.exportAsXML().encode('utf-8'))
+            got_dom = minidom.parseString(test.exportAsXML())
             exp_dom = minidom.parseString(wf_file.read())
             self._check_DOM_equality(exp_dom, got_dom, wf_name)
             alf.deleteProcess('test')

MailBoxer