[Checkins] SVN: zope3org/trunk/src/zorg/multiform/ added container
TODO: fix newDisplayMode
Bernd Dorn
bernd.dorn at fhv.at
Tue Apr 11 17:16:51 EDT 2006
Log message for revision 66865:
added container TODO: fix newDisplayMode
Changed:
A zope3org/trunk/src/zorg/multiform/container/
A zope3org/trunk/src/zorg/multiform/container/__init__.py
A zope3org/trunk/src/zorg/multiform/container/configure.zcml
A zope3org/trunk/src/zorg/multiform/container/container.txt
A zope3org/trunk/src/zorg/multiform/container/grid.pt
A zope3org/trunk/src/zorg/multiform/container/griditem.pt
A zope3org/trunk/src/zorg/multiform/container/interfaces.py
A zope3org/trunk/src/zorg/multiform/container/location.py
A zope3org/trunk/src/zorg/multiform/container/tests.py
A zope3org/trunk/src/zorg/multiform/container/views.py
U zope3org/trunk/src/zorg/multiform/multiform.py
-=-
Added: zope3org/trunk/src/zorg/multiform/container/__init__.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/container/__init__.py 2006-04-11 20:37:34 UTC (rev 66864)
+++ zope3org/trunk/src/zorg/multiform/container/__init__.py 2006-04-11 21:16:50 UTC (rev 66865)
@@ -0,0 +1,3 @@
+# container
+
+
Added: zope3org/trunk/src/zorg/multiform/container/configure.zcml
===================================================================
--- zope3org/trunk/src/zorg/multiform/container/configure.zcml 2006-04-11 20:37:34 UTC (rev 66864)
+++ zope3org/trunk/src/zorg/multiform/container/configure.zcml 2006-04-11 21:16:50 UTC (rev 66865)
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<configure xmlns:zope="http://namespaces.zope.org/zope"
+ xmlns="http://namespaces.zope.org/browser"
+ xmlns:i18n="http://namespaces.zope.org/i18n"
+ i18n_domain="zope">
+
+ <page for="zope.app.container.interfaces.IContainer"
+ name="grid.html"
+ permission="zope.View"
+ class=".views.ContainerGridForm"/>
+
+ <zope:adapter for="zope.app.location.interfaces.ILocation"
+ factory=".location.MovableLocation"
+ provides=".interfaces.IMovableLocation"/>
+
+</configure>
+
Added: zope3org/trunk/src/zorg/multiform/container/container.txt
===================================================================
--- zope3org/trunk/src/zorg/multiform/container/container.txt 2006-04-11 20:37:34 UTC (rev 66864)
+++ zope3org/trunk/src/zorg/multiform/container/container.txt 2006-04-11 21:16:50 UTC (rev 66865)
@@ -0,0 +1,45 @@
+=====================
+ Container Grid Form
+=====================
+
+A container contents view implementation using multiform. This view
+provides cut, copy, paste, edit and save actions. Additionally the
+__name__ attribute of the items can be transparently changed.
+
+In order to test the behaviour of the ``ContainerGridForm`` we
+subclass it and override the template method.
+
+ >>> from zope.app.container.sample import SampleContainer
+ >>> from zope.app.annotation.interfaces import IAttributeAnnotatable
+ >>> from zope.app.dublincore.interfaces import IZopeDublinCore
+ >>> from zope.app.dublincore.interfaces import IDCDescriptiveProperties
+ >>> from multiform.container.views import ContainerGridForm
+ >>> from zope import interface
+ >>> from zope.publisher.browser import TestRequest
+ >>> class ContainerTest(ContainerGridForm):
+ ... actions = ContainerGridForm.actions.copy()
+ ... def template(self):
+ ... res = u''
+ ... forms = list(self.getForms())
+ ... forms.sort(lambda x,y: cmp(x.prefix,y.prefix))
+ ... for form in forms:
+ ... res += '<div>%s</div>\n' % form.render()
+ ... return res
+
+ >>> c = SampleContainer()
+ >>> for i in range(2):
+ ... o = SampleContainer()
+ ... interface.directlyProvides(o,IAttributeAnnotatable)
+ ... c[u'name of %s' % i]=o
+
+ >>> request = TestRequest()
+ >>> view = ContainerTest(c,request)
+ >>> print view()
+ <div...<td>name of 0</td>...<td>name of 1</td>...
+
+
+
+
+
+
+
Added: zope3org/trunk/src/zorg/multiform/container/grid.pt
===================================================================
--- zope3org/trunk/src/zorg/multiform/container/grid.pt 2006-04-11 20:37:34 UTC (rev 66864)
+++ zope3org/trunk/src/zorg/multiform/container/grid.pt 2006-04-11 21:16:50 UTC (rev 66865)
@@ -0,0 +1,192 @@
+<html metal:extend-macro="context/@@standard_macros/view"
+ metal:define-macro="main">
+<head>
+</head>
+
+<body>
+<div metal:fill-slot="body">
+
+<div metal:define-macro="form">
+
+<form action="." metal:define-macro="master"
+ tal:attributes="action request/URL" method="post"
+ class="edit-form" enctype="multipart/form-data"
+ id="zc.page.browser_form">
+
+<script type="text/javascript"><!--
+
+function toggleFormFieldHelp(ob,state) {
+ // ob is the label element
+ var field = ob.form[ob.htmlFor];
+ if (field) {
+ var viz = state && 'hidden' || 'visible';
+ if (field.length == null) {
+ field.style.visibility = viz;
+ }
+ else {
+ for (var i = 0; i < field.length; ++i) {
+ var e = field.item(i);
+ e.style.visibility = viz;
+ }
+ }
+ var help = document.getElementById("field-help-for-" + ob.htmlFor);
+ if (help) {
+ help.style.visibility = state && 'visible' || 'hidden';
+ }
+ }
+}
+
+//-->
+</script>
+
+<div id="viewspace" metal:define-slot="viewspace">
+
+ <h1 i18n:translate=""
+ tal:condition="view/label"
+ tal:content="view/label"
+ metal:define-slot="heading"
+ >Do something</h1>
+
+ <metal:block define-macro="header">
+
+ <div class="form-status"
+ tal:define="status view/status"
+ tal:condition="status">
+
+ <div class="summary"
+ i18n:translate=""
+ tal:content="view/status">
+ Form status summary
+ </div>
+
+ <ul class="errors" tal:condition="view/errors">
+ <li tal:repeat="error view/error_views">
+ <span tal:replace="structure error">Error Type</span>
+ </li>
+ </ul>
+ </div>
+
+ </metal:block>
+
+ <div metal:define-slot="extra_info" tal:replace="nothing">
+ </div>
+
+ <div metal:define-slot="main_form">
+ <table class="form-fields" metal:define-macro="formtable">
+ <tr class="row" metal:define-slot="extra_top" tal:replace="nothing">
+ <td class="label">Extra top</td>
+ <td class="field"><input type="text" /></td>
+ </tr>
+ <tbody metal:define-slot="formbody" tal:omit-tag="">
+ <tal:block omit-tag="" repeat="widget view/widgets">
+ <tr metal:define-macro="formrow">
+ <td class="label" tal:define="hint widget/hint"
+ metal:define-macro="labelcell">
+ <label tal:condition="python:hint"
+ tal:attributes="for widget/name"
+ onmousedown="toggleFormFieldHelp(this,1)"
+ onmouseup="toggleFormFieldHelp(this,0)"
+ onmouseout="toggleFormFieldHelp(this,0)"
+ style="cursor: help">
+ <span class="required" tal:condition="widget/required"
+ >*</span><span i18n:translate=""
+ tal:content="widget/label">label</span>
+ </label>
+ <label tal:condition="python:not hint"
+ tal:attributes="for widget/name">
+ <span class="required" tal:condition="widget/required"
+ >*</span><span i18n:translate=""
+ tal:content="widget/label">label</span>
+ </label>
+ </td>
+ <td class="field" tal:define="hint widget/hint"
+ metal:define-macro="widgetcell">
+ <div class="form-fields-help"
+ i18n:translate=""
+ tal:content="hint"
+ tal:condition="hint"
+ tal:attributes="id string:field-help-for-${widget/name}"
+ onclick="this.style.visibility='hidden';"
+ style="visibility: hidden; position: absolute;"
+ >Title of this content object.</div>
+ <div class="widget" tal:content="structure widget">
+ <input type="text" /></div>
+ <div class="error"
+ tal:condition="widget/error"
+ >
+ <!-- TODO Put this back, the Zope3 way.
+ <img src="alert.gif" alt="Error"
+ tal:replace="structure context/alert.gif" />
+ -->
+ <span tal:replace="structure widget/error">error</span>
+ </div>
+ </td>
+ </tr>
+ </tal:block>
+ </tbody>
+ <tr class="row" metal:define-slot="extra_bottom" tal:replace="nothing">
+ <td class="label">Extra bottom</td>
+ <td class="label"><input type="text" /></td>
+ </tr>
+ </table>
+ </div>
+ <!-- start: subforms -->
+ <table id="sortable" class="listing"
+ summary="Content listing">
+ <thead>
+ <tr>
+ <th tal:repeat="field view/itemFormFactory/form_fields"
+ tal:content="field/field/title" i18n:translate="">
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr tal:repeat="subForm view/getForms"
+ tal:attributes="class python:repeat['subForm'].even and 'even' or 'odd'"
+ tal:content="structure subForm"/>
+ </tbody>
+ </table>
+
+ <!-- end: subforms -->
+
+ <!-- start: parentActions -->
+
+ <div id="parentActionsView"
+ metal:define-macro="form_parent_actions">
+ <span class="actionButtons"
+ tal:condition="view/availableSubActions"
+ metal:define-slot="bottom_buttons">
+ <input tal:repeat="action view/availableSubActions"
+ tal:replace="structure action/render"
+ />
+ </span>
+</div>
+
+ <!-- end: parentActions -->
+
+
+
+ <metal:block define-slot="above_buttons" />
+</div>
+<div id="actionsView"
+ metal:define-macro="form_actions">
+ <span class="actionButtons"
+ tal:condition="view/availableActions"
+ metal:define-slot="bottom_buttons">
+ <input tal:repeat="action view/actions"
+ tal:replace="structure action/render"
+ />
+ </span>
+</div>
+
+</form>
+<script type="text/javascript" metal:define-slot="trackChanges">
+ zc_trackChanges(document.getElementById('zc.page.browser_form'));
+</script>
+
+<script type="text/javascript"
+ tal:define="extra_script view/extra_script | nothing"
+ tal:condition="extra_script"
+ tal:content="structure extra_script" />
+
+</div></div></body></html>
Added: zope3org/trunk/src/zorg/multiform/container/griditem.pt
===================================================================
--- zope3org/trunk/src/zorg/multiform/container/griditem.pt 2006-04-11 20:37:34 UTC (rev 66864)
+++ zope3org/trunk/src/zorg/multiform/container/griditem.pt 2006-04-11 21:16:50 UTC (rev 66865)
@@ -0,0 +1,2 @@
+<td tal:repeat="widget view/widgets"
+ tal:content="structure widget"/>
Added: zope3org/trunk/src/zorg/multiform/container/interfaces.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/container/interfaces.py 2006-04-11 20:37:34 UTC (rev 66864)
+++ zope3org/trunk/src/zorg/multiform/container/interfaces.py 2006-04-11 21:16:50 UTC (rev 66865)
@@ -0,0 +1,15 @@
+from zope.app.location.interfaces import ILocation
+from zope import schema
+from zope.interface import Interface, Attribute
+
+class IMovableLocation(ILocation):
+
+ """a located object that can change its __name__ attribute by
+ itself"""
+
+ __name__ = schema.TextLine(
+ title=u"The name within the parent",
+ description=u"Traverse the parent with this name to get the object.",
+ required=False,
+ default=None)
+
Added: zope3org/trunk/src/zorg/multiform/container/location.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/container/location.py 2006-04-11 20:37:34 UTC (rev 66864)
+++ zope3org/trunk/src/zorg/multiform/container/location.py 2006-04-11 21:16:50 UTC (rev 66865)
@@ -0,0 +1,35 @@
+from interfaces import IMovableLocation
+from zope.interface import implements
+from zope.app.copypastemove.interfaces import IContainerItemRenamer
+from multiform.interfaces import IFormLocation
+from zope.security.proxy import removeSecurityProxy
+
+class MovableLocation(object):
+
+ implements(IMovableLocation)
+
+ def __init__(self,context):
+ self.context = context
+ self.__parent__ = self.context.__parent__
+
+ def _setName(self,v):
+ old = self.context.__name__
+ if v != old:
+ renamer = IContainerItemRenamer(self.__parent__)
+ renamer.renameItem(old, v)
+ if IFormLocation.providedBy(self.context):
+ # if we are in a multiform, we have to add the request
+ # data to our prefix
+ form = removeSecurityProxy(self.context.__form__)
+ oldPrefix = form.prefix
+ newPrefix = form.prefix[:-len(old)] + v
+ for oldKey in list(form.request.form.keys()):
+ if oldKey.startswith(oldPrefix):
+ newKey = newPrefix + oldKey[len(oldPrefix):]
+ form.request.form[newKey]=form.request.form[oldKey]
+
+ def _getName(self):
+ return self.context.__name__
+
+ __name__ = property(_getName,_setName)
+
Added: zope3org/trunk/src/zorg/multiform/container/tests.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/container/tests.py 2006-04-11 20:37:34 UTC (rev 66864)
+++ zope3org/trunk/src/zorg/multiform/container/tests.py 2006-04-11 21:16:50 UTC (rev 66865)
@@ -0,0 +1,113 @@
+import doctest
+import unittest
+from zope.testing.doctestunit import DocFileSuite, DocTestSuite
+from zope.app.testing import setup
+from zope import component
+import zope.schema.interfaces
+import zope.app.form.browser
+import zope.publisher.interfaces.browser
+import zope.app.form.interfaces
+from zope.formlib import form
+from zope.app.dublincore.annotatableadapter import ZDCAnnotatableAdapter
+from zope.app.dublincore.interfaces import IWriteZopeDublinCore
+from zope.app.annotation.interfaces import IAnnotatable
+import location
+from interfaces import IMovableLocation
+from multiform import gridform,multiform,selection
+from multiform.interfaces import IFormLocation,ISelection
+
+from zope.app.location.interfaces import ILocation
+
+def setUp(test):
+ setup.placefulSetUp()
+
+ component.provideAdapter(
+ zope.app.form.browser.TextWidget,
+ [zope.schema.interfaces.ITextLine,
+ zope.publisher.interfaces.browser.IBrowserRequest,
+ ],
+ zope.app.form.interfaces.IInputWidget,
+ )
+ component.provideAdapter(
+ zope.app.form.browser.UnicodeDisplayWidget,
+ [zope.schema.interfaces.ITextLine,
+ zope.publisher.interfaces.browser.IBrowserRequest,
+ ],
+ zope.app.form.interfaces.IDisplayWidget,
+ )
+ component.provideAdapter(
+ zope.app.form.browser.boolwidgets.BooleanDisplayWidget,
+ [zope.schema.interfaces.IBool,
+ zope.publisher.interfaces.browser.IBrowserRequest,
+ ],
+ zope.app.form.interfaces.IDisplayWidget,
+ )
+ component.provideAdapter(
+ zope.app.form.browser.CheckBoxWidget,
+ [zope.schema.interfaces.IBool,
+ zope.publisher.interfaces.browser.IBrowserRequest,
+ ],
+ zope.app.form.interfaces.IInputWidget,
+ )
+ component.provideAdapter(
+ zope.app.form.browser.UnicodeDisplayWidget,
+ [zope.schema.interfaces.IInt,
+ zope.publisher.interfaces.browser.IBrowserRequest,
+ ],
+ zope.app.form.interfaces.IDisplayWidget,
+ )
+ component.provideAdapter(
+ zope.app.form.browser.IntWidget,
+ [zope.schema.interfaces.IInt,
+ zope.publisher.interfaces.browser.IBrowserRequest,
+ ],
+ zope.app.form.interfaces.IInputWidget,
+ )
+ component.provideAdapter(
+ selection.FormLocationProxy,
+ [zope.app.location.interfaces.ILocation,
+ zope.formlib.interfaces.IForm
+ ],
+ IFormLocation
+ )
+ component.provideAdapter(
+ selection.FormLocationSelection,
+ [IFormLocation],
+ ISelection
+ )
+ component.provideAdapter(
+ location.MovableLocation,
+ [ILocation],
+ IMovableLocation
+ )
+ component.provideAdapter(
+ ZDCAnnotatableAdapter,
+ [IAnnotatable],
+ IWriteZopeDublinCore
+ )
+
+
+ component.provideAdapter(gridform.default_grid_template,
+ name="default")
+ component.provideAdapter(gridform.default_griditem_template,
+ name="default")
+ component.provideAdapter(form.render_submit_button, name='render')
+ component.provideAdapter(multiform.render_submit_button, name='render')
+
+def tearDown(test):
+ setup.placefulTearDown()
+
+
+def test_suite():
+
+ return unittest.TestSuite(
+ (
+ DocFileSuite('container.txt',
+ setUp=setUp, tearDown=tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+ ),
+ ))
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: zope3org/trunk/src/zorg/multiform/container/views.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/container/views.py 2006-04-11 20:37:34 UTC (rev 66864)
+++ zope3org/trunk/src/zorg/multiform/container/views.py 2006-04-11 21:16:50 UTC (rev 66865)
@@ -0,0 +1,297 @@
+from zope.formlib.i18n import _
+from multiform import multiform
+from zope.formlib import form
+from multiform.interfaces import ISelection
+from zope.app.dublincore.interfaces import IWriteZopeDublinCore
+from zope.app.size.interfaces import ISized
+from zope.app.pagetemplate import ViewPageTemplateFile
+from zope.app.location.interfaces import ILocation
+from interfaces import IMovableLocation
+from zope.event import notify
+from zope.app.event.objectevent import ObjectModifiedEvent
+from zope.interface.common import idatetime
+import datetime
+import pytz
+from zope.app import zapi
+from zope.app.copypastemove.interfaces import IPrincipalClipboard
+from zope.app.copypastemove.interfaces import IObjectCopier
+from zope.app.copypastemove.interfaces import IObjectMover
+from zope.app.principalannotation.interfaces import IPrincipalAnnotationUtility
+from zope.app.container.interfaces import DuplicateIDError
+from zope.security.interfaces import Unauthorized
+from zope.app.traversing.interfaces import TraversalError
+
+
+def isSelected(form,action):
+ return ISelection(form.context).selected
+
+def isSelectedInput(form,action):
+ print "isSelectedInput",form,form.inputMode,action.__name__,isSelected(form,action)
+ if not form.inputMode:
+ return False
+ return isSelected(form,action)
+
+
+def isSelectedOrDisplay(form,action):
+ print "isSelectedOrDisplay",form.inputMode,isSelected(form,action)
+ return not form.inputMode
+
+
+def pasteable(containerForm):
+ """Decide if there is anything to paste."""
+ target = containerForm.context
+ clipboard = getPrincipalClipboard(containerForm.request)
+ items = clipboard.getContents()
+ for item in items:
+ try:
+ obj = zapi.traverse(target, item['target'])
+ except TraversalError:
+ pass
+ else:
+ if item['action'] == 'cut':
+ mover = IObjectMover(obj)
+ moveableTo = safe_getattr(mover, 'moveableTo', None)
+ if moveableTo is None or not moveableTo(target):
+ return False
+ elif item['action'] == 'copy':
+ copier = IObjectCopier(obj)
+ copyableTo = safe_getattr(copier, 'copyableTo', None)
+ if copyableTo is None or not copyableTo(target):
+ return False
+ else:
+ raise
+
+ return True
+
+def safe_getattr(obj, attr, default):
+ """Attempts to read the attr, returning default if Unauthorized."""
+ try:
+ return getattr(obj, attr, default)
+ except Unauthorized:
+ return default
+
+def hasClipboardContents(form, action):
+ """ interogates the `PrinicipalAnnotation` to see if
+ clipboard contents exist """
+
+ if multiform.anySubFormInputMode(form,action):
+ return False
+
+ if not pasteable(form):
+ return False
+
+ # touch at least one item to in clipboard confirm contents
+ clipboard = getPrincipalClipboard(form.request)
+ items = clipboard.getContents()
+ for item in items:
+ try:
+ zapi.traverse(form.context, item['target'])
+ except TraversalError:
+ pass
+ else:
+ return True
+
+ return False
+
+
+
+class ContainerItemForm(multiform.ItemFormBase):
+
+ inputMode=False
+ forceInput=['selected']
+ template = ViewPageTemplateFile('griditem.pt')
+ form_fields = form.Fields(ISelection['selected'],
+ IMovableLocation['__name__'],
+ IWriteZopeDublinCore['title'],
+ omit_readonly=False,render_context=True)
+
+ @multiform.parentAction('Edit',
+ condition=multiform.allSubFormsDisplayMode)
+ def handle_edit_action(self, action, data):
+ #print "handle_edit_action",action,data,isSelected(self,action)
+ if isSelected(self,action):
+ self.newInputMode = True
+
+ @multiform.parentAction("Save", inputMode=True,
+ condition=multiform.anySubFormInputMode)
+ def handle_save_action(self, action, data):
+ if form.applyChanges(self.context, self.form_fields,
+ data, self.adapters):
+ notify(ObjectModifiedEvent(self.context))
+ formatter = self.request.locale.dates.getFormatter(
+ 'dateTime', 'medium')
+ try:
+ time_zone = idatetime.ITZInfo(self.request)
+ except TypeError:
+ time_zone = pytz.UTC
+ m = {'date_time':formatter.format(datetime.datetime.now(time_zone))}
+ self.status = (_("Updated on ${date_time}", mapping=m),)
+ else:
+ self.status = (_('No changes'),)
+ self.newInputMode = False
+
+
+
+class ContainerGridForm(multiform.MultiFormBase):
+
+ itemFormFactory=ContainerItemForm
+
+ template = ViewPageTemplateFile('grid.pt')
+
+ @form.action('Cancel',condition=multiform.anySubFormInputMode)
+ def handle_cancel_action(self, action, data):
+ for form in self.subForms.values():
+ form.newInputMode = False
+
+ @form.action("Paste", condition=hasClipboardContents)
+ def handle_paste_action(self, action, data):
+ """Paste ojects in the user clipboard to the container"""
+ self.form_reset = True
+ target = self.context
+ clipboard = getPrincipalClipboard(self.request)
+ items = clipboard.getContents()
+ moved = False
+ not_pasteable_ids = []
+ for item in items:
+ duplicated_id = False
+ try:
+ obj = zapi.traverse(target, item['target'])
+ except TraversalError:
+ pass
+ else:
+ if item['action'] == 'cut':
+ mover = IObjectMover(obj)
+ try:
+ mover.moveTo(target)
+ moved = True
+ except DuplicateIDError:
+ duplicated_id = True
+ elif item['action'] == 'copy':
+ copier = IObjectCopier(obj)
+ try:
+ copier.copyTo(target)
+ except DuplicateIDError:
+ duplicated_id = True
+ else:
+ raise
+
+ if duplicated_id:
+ not_pasteable_ids.append(zapi.getName(obj))
+
+ if moved:
+ # Clear the clipboard if we do a move, but not if we only do a copy
+ clipboard.clearContents()
+
+ if not_pasteable_ids != []:
+ # Show the ids of objects that can't be pasted because
+ # their ids are already taken.
+ # TODO Can't we add a 'copy_of' or something as a prefix
+ # instead of raising an exception ?
+ self.errors = (
+ _("The given name(s) %s is / are already being used" %(
+ str(not_pasteable_ids))),)
+
+ @form.action("Cut", condition=multiform.allSubFormsDisplayMode)
+ def handle_cut_action(self, action, data):
+ """move objects specified in a list of object ids"""
+
+ container_path = zapi.getPath(self.context)
+
+ # For each item, check that it can be moved; if so, save the
+ # path of the object for later moving when a destination has
+ # been selected; if not movable, provide an error message
+ # explaining that the object can't be moved.
+ items = []
+ for form in self.getForms():
+ ob = form.context
+ name = ob.__name__
+ selection = ISelection(ob)
+ if not selection.selected:
+ continue
+ selection.selected=False
+ mover = IObjectMover(ob)
+ if not mover.moveable():
+ m = {"name": name}
+ title = getDCTitle(ob)
+ if title:
+ m["title"] = title
+ self.errors = (_(
+ "Object '${name}' (${title}) cannot be moved",
+ mapping=m),)
+ else:
+ self.errors = (_("Object '${name}' cannot be moved",
+ mapping=m),)
+ return
+ items.append(zapi.joinPath(container_path, name))
+ if len(items) == 0:
+ self.errors = (_("You didn't specify any ids to cut."),)
+ else:
+ # store the requested operation in the principal annotations:
+ clipboard = getPrincipalClipboard(self.request)
+ clipboard.clearContents()
+ clipboard.addItems('cut', items)
+
+ @form.action("Copy", condition=multiform.allSubFormsDisplayMode)
+ def handle_copy_action(self, action, data):
+ """Copy objects specified in a list of object ids"""
+
+ container_path = zapi.getPath(self.context)
+
+ # For each item, check that it can be copied; if so, save the
+ # path of the object for later copying when a destination has
+ # been selected; if not copyable, provide an error message
+ # explaining that the object can't be copied.
+
+ items = []
+ for form in self.getForms():
+ ob = form.context
+ name = ob.__name__
+ selection = ISelection(ob)
+ if not selection.selected:
+ continue
+ selection.selected=False
+ copier = IObjectCopier(ob)
+ if not copier.copyable():
+ m = {"name": name}
+ title = getDCTitle(ob)
+ if title:
+ m["title"] = title
+ self.errors = (_(
+ "Object '${name}' (${title}) cannot be copied",
+ mapping=m),)
+ else:
+ self.errors = (_("Object '${name}' cannot be copied",
+ mapping=m),)
+ return
+ items.append(zapi.joinPath(container_path, name))
+ if len(items) == 0:
+ self.errors = (_("You didn't specify any ids to copy."),)
+ else:
+ # store the requested operation in the principal annotations:
+ clipboard = getPrincipalClipboard(self.request)
+ clipboard.clearContents()
+ clipboard.addItems('copy', items)
+
+ @form.action("Delete", condition=multiform.allSubFormsDisplayMode)
+ def handle_delete_action(self, action, data):
+ """Delete objects specified in a list of object ids"""
+ container = self.context
+ toDelete = []
+ for form in self.getForms():
+ if not ISelection(form.context).selected:
+ continue
+ toDelete.append(form.context.__name__)
+ if toDelete:
+ for name in toDelete:
+ del(container[name])
+ self.form_reset = True
+ else:
+ self.errors = (_("You didn't specify any ids to delete."),)
+
+def getPrincipalClipboard(request):
+ """Return the clipboard based on the request."""
+ user = request.principal
+ annotationutil = zapi.getUtility(IPrincipalAnnotationUtility)
+ annotations = annotationutil.getAnnotations(user)
+ return IPrincipalClipboard(annotations)
+
Modified: zope3org/trunk/src/zorg/multiform/multiform.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/multiform.py 2006-04-11 20:37:34 UTC (rev 66864)
+++ zope3org/trunk/src/zorg/multiform/multiform.py 2006-04-11 21:16:50 UTC (rev 66865)
@@ -107,7 +107,7 @@
newInputMode = None
form_fields=[]
actions = []
-
+
def __init__(self,context,request,parentForm):
# we have to copy the default fields, so that we can mutate
# them in our instance
@@ -140,7 +140,6 @@
implements(IMultiForm)
itemFormFactory = ItemFormBase
subForms={}
- subFormsList = []
form_fields = []
actions = []
subActionNames = []
@@ -186,17 +185,21 @@
def setUpForms(self, *args, **kw):
self.subForms = {}
- self.subFormsList = []
for name, item in self.context.items():
inputMode = self.subFormInputMode.get(name,self.itemFormFactory.inputMode)
self.setUpForm(name, item, inputMode)
- self.subFormsList.append(name)
self.refreshSubActionNames()
def getForms(self):
- for name in self.subFormsList:
+ # we have to use the keys here to support all actions that
+ # modifies the keys of our mapping, e.g. rename, delete
+ for name in self.context.keys():
+ if not self.subForms.has_key(name):
+ self.setUpForm(name,self.context[name],
+ self.itemFormFactory.inputMode)
yield self.subForms[name]
+
def refreshSubActionNames(self):
availableActions = set()
for subForm in self.getForms():
More information about the Checkins
mailing list