From 19f5fdf20da624f13dcc2351aa2fea6716b0732c Mon Sep 17 00:00:00 2001 From: Roger Ineichen Date: Sun, 22 Feb 2009 04:10:56 +0000 Subject: [PATCH] added initial implementation --- AUTHOR.txt | 1 + CHANGES.txt | 8 + LICENSE.txt | 54 ++++++ README.txt | 2 + bootstrap.py | 52 ++++++ buildout.cfg | 27 +++ setup.py | 70 ++++++++ src/z3c/__init__.py | 7 + src/z3c/tabular/README.txt | 288 ++++++++++++++++++++++++++++++++ src/z3c/tabular/__init__.py | 1 + src/z3c/tabular/browser.zcml | 25 +++ src/z3c/tabular/configure.zcml | 7 + src/z3c/tabular/formtable.pt | 18 ++ src/z3c/tabular/interfaces.py | 35 ++++ src/z3c/tabular/subformtable.pt | 29 ++++ src/z3c/tabular/table.pt | 15 ++ src/z3c/tabular/table.py | 258 ++++++++++++++++++++++++++++ src/z3c/tabular/testing.py | 40 +++++ src/z3c/tabular/tests.py | 63 +++++++ 19 files changed, 1000 insertions(+) create mode 100644 AUTHOR.txt create mode 100644 CHANGES.txt create mode 100644 LICENSE.txt create mode 100644 README.txt create mode 100644 bootstrap.py create mode 100644 buildout.cfg create mode 100644 setup.py create mode 100644 src/z3c/__init__.py create mode 100644 src/z3c/tabular/README.txt create mode 100644 src/z3c/tabular/__init__.py create mode 100644 src/z3c/tabular/browser.zcml create mode 100644 src/z3c/tabular/configure.zcml create mode 100644 src/z3c/tabular/formtable.pt create mode 100644 src/z3c/tabular/interfaces.py create mode 100644 src/z3c/tabular/subformtable.pt create mode 100644 src/z3c/tabular/table.pt create mode 100644 src/z3c/tabular/table.py create mode 100644 src/z3c/tabular/testing.py create mode 100644 src/z3c/tabular/tests.py diff --git a/AUTHOR.txt b/AUTHOR.txt new file mode 100644 index 0000000..b50ab17 --- /dev/null +++ b/AUTHOR.txt @@ -0,0 +1 @@ +Roger Ineichen (roger projekt01 ch) diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000..18533d3 --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,8 @@ +======= +CHANGES +======= + +0.5.0 (2009-02-22) +------------------ + +- Initial Release diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..b526704 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,54 @@ +Zope Public License (ZPL) Version 2.1 +------------------------------------- + +A copyright notice accompanies this license document that +identifies the copyright holders. + +This license has been certified as open source. It has also +been designated as GPL compatible by the Free Software +Foundation (FSF). + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the +following conditions are met: + +1. Redistributions in source code must retain the + accompanying copyright notice, this list of conditions, + and the following disclaimer. + +2. Redistributions in binary form must reproduce the accompanying + copyright notice, this list of conditions, and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +3. Names of the copyright holders must not be used to + endorse or promote products derived from this software + without prior written permission from the copyright + holders. + +4. The right to distribute this software or to use it for + any purpose does not give you the right to use + Servicemarks (sm) or Trademarks (tm) of the copyright + holders. Use of them is covered by separate agreement + with the copyright holders. + +5. If any files are modified, you must cause the modified + files to carry prominent notices stating that you changed + the files and the date of any change. + +Disclaimer + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' + AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + NO EVENT SHALL THE COPYRIGHT HOLDERS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..4ecde4d --- /dev/null +++ b/README.txt @@ -0,0 +1,2 @@ +This package provides a table implementation including form support for Zope3 +based on z3c.form and z3c.table. diff --git a/bootstrap.py b/bootstrap.py new file mode 100644 index 0000000..f10ec7a --- /dev/null +++ b/bootstrap.py @@ -0,0 +1,52 @@ +############################################################################## +# +# Copyright (c) 2008 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +"""Bootstrap a buildout-based project + +Simply run this script in a directory containing a buildout.cfg. +The script accepts buildout command-line options, so you can +use the -c option to specify an alternate configuration file. + +$Id:$ +""" + +import os, shutil, sys, tempfile, urllib2 + +tmpeggs = tempfile.mkdtemp() + +ez = {} +exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' + ).read() in ez +ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) + +import pkg_resources + +cmd = 'from setuptools.command.easy_install import main; main()' +if sys.platform == 'win32': + cmd = '"%s"' % cmd # work around spawn lamosity on windows + +ws = pkg_resources.working_set +assert os.spawnle( + os.P_WAIT, sys.executable, sys.executable, + '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout', + dict(os.environ, + PYTHONPATH= + ws.find(pkg_resources.Requirement.parse('setuptools')).location + ), + ) == 0 + +ws.add_entry(tmpeggs) +ws.require('zc.buildout') +import zc.buildout.buildout +zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap']) +shutil.rmtree(tmpeggs) diff --git a/buildout.cfg b/buildout.cfg new file mode 100644 index 0000000..df48153 --- /dev/null +++ b/buildout.cfg @@ -0,0 +1,27 @@ +[buildout] +develop = . +parts = test checker coverage-test coverage-report + + +[test] +recipe = zc.recipe.testrunner +eggs = z3c.tabular [test] +defaults = ['--tests-pattern', '^f?tests$', '-v'] + + +[checker] +recipe = lovely.recipe:importchecker +path = src/z3c/tabular + + +[coverage-test] +recipe = zc.recipe.testrunner +eggs = z3c.tabular [test] +defaults = ['--coverage', '../../coverage'] + + +[coverage-report] +recipe = zc.recipe.egg +eggs = z3c.coverage +scripts = coverage=coverage-report +arguments = ('coverage', 'coverage/report') diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..2be93d3 --- /dev/null +++ b/setup.py @@ -0,0 +1,70 @@ +############################################################################## +# +# Copyright (c) 2008 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" +$Id:$ +""" + +import os +from setuptools import setup, find_packages + +def read(*rnames): + return open(os.path.join(os.path.dirname(__file__), *rnames)).read() + +setup ( + name='z3c.tabular', + version='0.5.0', + author = "Roger Ineichen and the Zope Community", + author_email = "zope3-dev@zope.org", + description = "Table with form support based on z3c.form and z3c.table for Zope3", + long_description=( + read('README.txt') + + '\n\n' + + read('CHANGES.txt') + ), + license = "ZPL 2.1", + keywords = "zope3 z3c tabular data form table contents", + classifiers = [ + 'Development Status :: 4 - Beta', + 'Environment :: Web Environment', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Zope Public License', + 'Programming Language :: Python', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Topic :: Internet :: WWW/HTTP', + 'Framework :: Zope3'], + url = 'http://cheeseshop.python.org/pypi/z3c.tabular', + packages = find_packages('src'), + include_package_data = True, + package_dir = {'':'src'}, + namespace_packages = ['z3c'], + extras_require = dict( + test = [ + 'z3c.table', + 'z3c.testing', + 'zope.publisher', + 'zope.testing', + ], + ), + install_requires = [ + 'setuptools', + 'z3c.form', + 'z3c.formui', + 'z3c.table', + 'z3c.template', + 'zope.i18nmessageid', + 'zope.interface', + ], + zip_safe = False, +) diff --git a/src/z3c/__init__.py b/src/z3c/__init__.py new file mode 100644 index 0000000..10a9055 --- /dev/null +++ b/src/z3c/__init__.py @@ -0,0 +1,7 @@ +try: + # Declare this a namespace package if pkg_resources is available. + import pkg_resources + pkg_resources.declare_namespace('z3c') +except ImportError: + pass + diff --git a/src/z3c/tabular/README.txt b/src/z3c/tabular/README.txt new file mode 100644 index 0000000..d3cd5d3 --- /dev/null +++ b/src/z3c/tabular/README.txt @@ -0,0 +1,288 @@ +========== +Form Table +========== + +The goal of this package is to offer a modular table rendering library which +includes built in support for update forms. This will allow us to adapt items +rendered as table row items to forms. This could prevent to use traversable +exposed forms for such items. But this is just one of the benefits. See more +below. + + +Form support +------------ + +We need to setup the form defaults first: + + >>> from z3c.form.testing import setupFormDefaults + >>> setupFormDefaults() + +And load the formui confguration, which will make sure that all macros get +registered correctly. + + >>> from zope.configuration import xmlconfig + >>> import zope.component + >>> import zope.viewlet + >>> import zope.app.component + >>> import zope.app.publisher.browser + >>> import z3c.macro + >>> import z3c.template + >>> import z3c.formui + >>> xmlconfig.XMLConfig('meta.zcml', zope.component)() + >>> xmlconfig.XMLConfig('meta.zcml', zope.viewlet)() + >>> xmlconfig.XMLConfig('meta.zcml', zope.app.component)() + >>> xmlconfig.XMLConfig('meta.zcml', zope.app.publisher.browser)() + >>> xmlconfig.XMLConfig('meta.zcml', z3c.macro)() + >>> xmlconfig.XMLConfig('meta.zcml', z3c.template)() + >>> xmlconfig.XMLConfig('configure.zcml', z3c.formui)() + +And load the z3c.tabular configure.zcml: + + >>> import z3c.tabular + >>> xmlconfig.XMLConfig('configure.zcml', z3c.tabular)() + + +Sample data setup +----------------- + +Let's create a sample container which we can use as our iterable context: + + >>> from zope.app.container import btree + >>> class Container(btree.BTreeContainer): + ... """Sample container.""" + ... __name__ = u'container' + >>> container = Container() + +and set a parent for the container: + + >>> root['container'] = container + +and create a sample content object which we use as container item: + + >>> import zope.interface + >>> import zope.schema + >>> class IContent(zope.interface.Interface): + ... """Content interface.""" + ... + ... title = zope.schema.TextLine(title=u'Title') + ... number = zope.schema.Int(title=u'Number') + + >>> class Content(object): + ... """Sample content.""" + ... zope.interface.implements(IContent) + ... def __init__(self, title, number): + ... self.__name__ = title.lower() + ... self.title = title + ... self.number = number + +Now setup some items: + + >>> container[u'first'] = Content('First', 1) + >>> container[u'second'] = Content('Second', 2) + >>> container[u'third'] = Content('Third', 3) + + +FormTable setup +--------------- + +The ``FormTable`` offers a sub form setup for rendering items within a form. +Let's first define a form for our used items: + + + >>> from z3c.form import form + >>> from z3c.form import field + >>> class ContentEditForm(form.EditForm): + ... fields = field.Fields(IContent) + +Now we can define our ``FormTable`` including the SelectedItemColumn: + + >>> from z3c.table import column + >>> import z3c.tabular.table + >>> class ContentFormTable(z3c.tabular.table.SubFormTable): + ... + ... subFormClass = ContentEditForm + ... + ... def setUpColumns(self): + ... return [ + ... column.addColumn(self, column.SelectedItemColumn, + ... u'selectedItem', weight=1), + ... ] + +And support the div form layer for our request: + + >>> from z3c.formui.interfaces import IDivFormLayer + >>> from zope.interface import alsoProvides + >>> from z3c.form.testing import TestRequest + >>> request = TestRequest() + >>> alsoProvides(request, IDivFormLayer) + +Now we can render our table. As you can see the ``SelectedItemColumn`` renders +a link which knows hot to select the item: + + >>> contentSubFormTable = ContentFormTable(container, request) + >>> contentSubFormTable.__name__ = 'view.html' + >>> contentSubFormTable.update() + >>> print contentSubFormTable.render() +
+
+
+ * + – required +
+
+ + + + + +
+
+ + + + + + + + + + + + + + + + + +
Name
first
second
third
+
+
+
+
+
+
+
+ + + +
+
+
+ +Now we are ready to select an item by click on the link. We simlate this by +set the relevant data in the request: + + >>> selectRequest = TestRequest(form={ + ... 'subFormTable-selectedItem-0-selectedItems': 'second'}) + >>> alsoProvides(selectRequest, IDivFormLayer) + >>> selectedItemTable = ContentFormTable(container, selectRequest) + >>> selectedItemTable.__name__ = 'view.html' + >>> selectedItemTable.update() + >>> print selectedItemTable.render() +
+
+
+ * + – required +
+
+ + + + + +
+
+ + + + + + + + + + + + + + + + + +
Name
first
second
third
+
+
+
+ +
+
+ * + – required +
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ + + +
+
+ diff --git a/src/z3c/tabular/__init__.py b/src/z3c/tabular/__init__.py new file mode 100644 index 0000000..e7ae9de --- /dev/null +++ b/src/z3c/tabular/__init__.py @@ -0,0 +1 @@ +# make a package diff --git a/src/z3c/tabular/browser.zcml b/src/z3c/tabular/browser.zcml new file mode 100644 index 0000000..a1c4450 --- /dev/null +++ b/src/z3c/tabular/browser.zcml @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/src/z3c/tabular/configure.zcml b/src/z3c/tabular/configure.zcml new file mode 100644 index 0000000..0766b38 --- /dev/null +++ b/src/z3c/tabular/configure.zcml @@ -0,0 +1,7 @@ + + + + + diff --git a/src/z3c/tabular/formtable.pt b/src/z3c/tabular/formtable.pt new file mode 100644 index 0000000..87ab1e2 --- /dev/null +++ b/src/z3c/tabular/formtable.pt @@ -0,0 +1,18 @@ +
+
+
+ + table + +
+
+ + table + +
+
+
+
+
+
diff --git a/src/z3c/tabular/interfaces.py b/src/z3c/tabular/interfaces.py new file mode 100644 index 0000000..c05afdc --- /dev/null +++ b/src/z3c/tabular/interfaces.py @@ -0,0 +1,35 @@ +############################################################################## +# +# Copyright (c) 2008 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" +$Id:$ +""" +__docformat__ = "reStructuredText" + +import z3c.table.interfaces + + +class ITemplateTable(z3c.table.interfaces.ITable): + """Template aware table.""" + + +class IFormTable(ITemplateTable): + """Table including a form setup.""" + + +class IDeleteFormTable(IFormTable): + """Delete button aware table including a form setup.""" + + +class ISubFormTable(IDeleteFormTable): + """Table including a sub form for one selected item.""" diff --git a/src/z3c/tabular/subformtable.pt b/src/z3c/tabular/subformtable.pt new file mode 100644 index 0000000..6a2f023 --- /dev/null +++ b/src/z3c/tabular/subformtable.pt @@ -0,0 +1,29 @@ +
+
+ + + + + +
+
+ + table + +
+
+ + table + +
+
+
+ + form + +
+
+
+
diff --git a/src/z3c/tabular/table.pt b/src/z3c/tabular/table.pt new file mode 100644 index 0000000..ac399d9 --- /dev/null +++ b/src/z3c/tabular/table.pt @@ -0,0 +1,15 @@ +
+
+
+ + table + +
+
+ + table + +
+
+
diff --git a/src/z3c/tabular/table.py b/src/z3c/tabular/table.py new file mode 100644 index 0000000..490f6cc --- /dev/null +++ b/src/z3c/tabular/table.py @@ -0,0 +1,258 @@ +############################################################################## +# +# Copyright (c) 2008 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" +$Id:$ +""" +__docformat__ = "reStructuredText" + +import transaction +import zope.interface +import zope.i18nmessageid + +from z3c.form import button +from z3c.form import field +from z3c.formui import form +from z3c.table import table +from z3c.template.template import getPageTemplate + +from z3c.tabular import interfaces + +_ = zope.i18nmessageid.MessageFactory('z3c') + + +# conditions +def hasContent(form): + return form.hasContent + + +def canCancel(form): + return form.supportsCancel + + +def canDelete(form): + return form.supportsDelete + + +# simple template rendering aware table base class +class TemplateTable(table.Table): + """Template aware teble.""" + + zope.interface.implements(interfaces.ITemplateTable) + + template = getPageTemplate() + + def render(self): + """Render the template.""" + return self.template() + + +# simple form aware table base class +class TableBase(TemplateTable): + """Generic table class with form action support used as form mixin base. + + This table base class allows you to mixin custom forms as base. + """ + + prefix = 'formTable' + + # internal defaults + actions = None + hasContent = False + nextURL = None + selectedItems = [] + ignoreContext = False + + # table defaults + cssClasses = {'table': 'contents'} + cssClassEven = u'even' + cssClassOdd = u'odd' + cssClassSelected = u'selected' + + batchSize = 25 + startBatchingAt = 25 + + # customize this part + allowCancel = True + + def update(self): + # 1. setup widgets + self.updateWidgets() + # 2. setup search values, generate rows, setup headers and columns + super(TableBase, self).update() + # 3. setup conditions + self.setupConditions() + # 4. setup form part + self.updateActions() + if self.actions is not None: + self.actions.execute() + + def setupConditions(self): + self.hasContent = bool(self.rows) + if self.allowCancel: + self.supportsCancel = self.hasContent + + def updateAfterActionExecution(self): + """Update table data if subform changes soemthing.""" + # first update table data which probably changed + super(TableBase, self).update() + # second setup conditions + self.setupConditions() + # third update action which we have probably different conditions for + self.updateActions() + + @button.buttonAndHandler(_('Cancel'), name='cancel', condition=canCancel) + def handleCancel(self, action): + self.nextURL = self.request.getURL() + + def render(self): + """Render the template.""" + if self.nextURL is not None: + self.request.response.redirect(self.nextURL) + return "" + return self.template() + + +class FormTable(TableBase, form.Form): + """Generic table class with form action support based on IForm.""" + + zope.interface.implements(interfaces.IFormTable) + + template = getPageTemplate() + + +class DeleteFormTable(FormTable): + """Table class with form action support based on IForm.""" + + zope.interface.implements(interfaces.IDeleteFormTable) + + prefix = 'deleteFormTable' + + # internal defaults + supportsCancel = False + supportsDelete = False + + deleteErrorMessage = _('Could not delete the selected items') + deleteNoItemsMessage = _('No items selected for delete') + deleteSuccessMessage = _('Data successfully deleted') + + # customize this part + allowCancel = True + allowDelete = True + + def executeDelete(self, item): + raise NotImplementedError('Subclass must implement executeDelete') + + def setupConditions(self): + self.hasContent = bool(self.rows) + if self.allowCancel: + self.supportsCancel = self.hasContent + if self.allowDelete: + self.supportsDelete = self.hasContent + + def doDelete(self, action): + if not len(self.selectedItems): + self.status = self.deleteNoItemsMessage + return + try: + for item in self.selectedItems: + self.executeDelete(item) + # update the table rows before we start with rendering + self.updateAfterActionExecution() + if self.status is None: + # probably execute delete or updateAfterAction already set a + # status + self.status = self.deleteSuccessMessage + except KeyError: + self.status = self.deleteErrorMessage + transaction.doom() + + @button.buttonAndHandler(_('Delete'), name='delete', condition=canDelete) + def handleDelete(self, action): + self.doDelete(action) + + +# form table including a sub form +class SubFormTable(DeleteFormTable): + """Form table including a sub form based on IForm.""" + + zope.interface.implements(interfaces.ISubFormTable) + + buttons = DeleteFormTable.buttons.copy() + handlers = DeleteFormTable.handlers.copy() + + prefix = 'subFormTable' + + # internal defaults + subForm = None + + # error messages + subFormNoItemMessage = _('No item selected for edit') + subFormToManyItemsMessage = _('Only one item could be selected for edit') + subFormNotFoundMessage = _('No edit form found for selected item') + + # customize this part + # use subFormClass or use subFormName. If you set both it will end in + # using subFormClass. See updateSubForm for details. + subFormClass = None + subFormName = u'' + + def update(self): + # 1. setup widgets + super(SubFormTable, self).update() + # 2. setup form after we set probably a selectedItem + self.updateSubForm() + + @property + def selectedItem(self): + if len(self.selectedItems) == 0: + return None + if len(self.selectedItems) > 1: + self.status = self.subFormToManyItemsMessage + return None + return self.selectedItems[0] + + def setUpSubForm(self, selectedItem): + if self.subFormClass is not None: + return self.subFormClass(selectedItem, self.request) + elif self.subFormName is not None: + return zope.component.queryMultiAdapter((selectedItem, + self.request), name=self.subFormName) + + def updateSubForm(self): + selectedItem = self.selectedItem + if selectedItem is None: + return + # set table as parent + self.subForm = self.setUpSubForm(selectedItem) + if self.subForm is None: + self.status = self.subFormNotFoundMessage + return + self.subForm.__parent__ = self + # udpate edit form + self.subForm.update() + + def doSubForm(self, action): + if self.subForm is None: + return + # set ignore request and update again + self.subForm.ignoreRequest = True + self.subForm.update() + + @button.buttonAndHandler(u'Edit') + def handleSubForm(self, action): + self.doSubForm(action) + + @button.buttonAndHandler(_('Cancel'), name='cancel', condition=canCancel) + def handleCancel(self, action): + self.nextURL = self.request.getURL() diff --git a/src/z3c/tabular/testing.py b/src/z3c/tabular/testing.py new file mode 100644 index 0000000..a3824b2 --- /dev/null +++ b/src/z3c/tabular/testing.py @@ -0,0 +1,40 @@ +############################################################################## +# +# Copyright (c) 2008 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" +$Id:$ +""" +__docformat__ = "reStructuredText" + +from zope.app.pagetemplate import metaconfigure +from zope.app.testing import setup + +import z3c.macro.tales +import z3c.table.testing + + +############################################################################### +# +# testing setup +# +############################################################################### + +def setUp(test): + test.globs = {'root': setup.placefulSetUp(True)} + + metaconfigure.registerType('macro', z3c.macro.tales.MacroExpression) + z3c.table.testing.setUpAdapters() + + +def tearDown(test): + setup.placefulTearDown() diff --git a/src/z3c/tabular/tests.py b/src/z3c/tabular/tests.py new file mode 100644 index 0000000..62d3162 --- /dev/null +++ b/src/z3c/tabular/tests.py @@ -0,0 +1,63 @@ +############################################################################## +# +# Copyright (c) 2008 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" +$Id:$ +""" +__docformat__ = "reStructuredText" + +import unittest +from zope.testing import doctest +from zope.publisher.browser import TestRequest + +import z3c.testing +import z3c.table.testing +from z3c.tabular import interfaces +from z3c.tabular import table +from z3c.tabular import testing + + +class FakeContainer(object): + def values(self): + pass + + +# table +class TestFormTable(z3c.testing.InterfaceBaseTest): + + def setUp(test): + z3c.table.testing.setUpAdapters() + + def getTestInterface(self): + return interfaces.IFormTable + + def getTestClass(self): + return table.FormTable + + def getTestPos(self): + return (FakeContainer(), TestRequest()) + + + +def test_suite(): + return unittest.TestSuite(( + doctest.DocFileSuite('README.txt', + setUp=testing.setUp, tearDown=testing.tearDown, + optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS, + ), + unittest.makeSuite(TestFormTable), + )) + + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite')