Commit 160df616 authored by Christian Theune's avatar Christian Theune

Moving code to satellite.

parent df23e50e
# Extension information for zpkg:
<extension _zope_app_container_contained>
source _zope_app_container_contained.c
</extension>
#
# This file is necessary to make this directory a package.
/*############################################################################
#
# Copyright (c) 2003 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.
#
############################################################################*/
#define _ZOPE_APP_CONTAINER_CONTAINED_C "$Id$\n"
/* Contained Proxy Base class
Contained proxies provide __parent__ and __name__ attributes for
objects without them.
There is something strange and, possibly cool, going on here, wrt
persistence. To reuse the base proxy implementation we don't treat
the proxied object as part of the persistent state of the proxy.
This means that the proxy still operates as a proxy even if it is a
ghost.
The proxy will only be unghostified if you need to access one of the
attributes provided by the proxy.
*/
#include "Python.h"
#include "persistent/cPersistence.h"
static PyObject *str_p_deactivate;
typedef struct {
cPersistent_HEAD
PyObject *po_weaklist;
PyObject *proxy_object;
PyObject *__parent__;
PyObject *__name__;
} ProxyObject;
typedef struct {
PyTypeObject *proxytype;
int (*check)(PyObject *obj);
PyObject *(*create)(PyObject *obj);
PyObject *(*getobject)(PyObject *proxy);
} ProxyInterface;
#define OBJECT(O) ((PyObject*)(O))
#define Proxy_GET_OBJECT(ob) (((ProxyObject *)(ob))->proxy_object)
#define CLEAR(O) \
if (O) {PyObject *clr__tmp = O; O = NULL; Py_DECREF(clr__tmp); }
/* Supress inclusion of the original proxy.h */
#define _proxy_H_ 1
/* Incude the proxy C source */
#include "_zope_proxy_proxy.c"
#define SPECIAL(NAME) ( \
*(NAME) == '_' && \
(((NAME)[1] == 'p' && (NAME)[2] == '_') \
|| \
((NAME)[1] == '_' && ( \
strcmp((NAME), "__parent__") == 0 \
|| \
strcmp((NAME), "__name__") == 0 \
|| \
strcmp((NAME), "__getstate__") == 0 \
|| \
strcmp((NAME), "__setstate__") == 0 \
|| \
strcmp((NAME), "__getnewargs__") == 0 \
|| \
strcmp((NAME), "__reduce__") == 0 \
|| \
strcmp((NAME), "__reduce_ex__") == 0 \
)) \
))
static PyObject *
CP_getattro(PyObject *self, PyObject *name)
{
char *cname;
cname = PyString_AsString(name);
if (cname == NULL)
return NULL;
if (SPECIAL(cname))
/* delegate to persistent */
return cPersistenceCAPI->pertype->tp_getattro(self, name);
/* Use the wrapper version to delegate */
return wrap_getattro(self, name);
}
static int
CP_setattro(PyObject *self, PyObject *name, PyObject *v)
{
char *cname;
cname = PyString_AsString(name);
if (cname == NULL)
return -1;
if (SPECIAL(cname))
/* delegate to persistent */
return cPersistenceCAPI->pertype->tp_setattro(self, name, v);
/* Use the wrapper version to delegate */
return wrap_setattro(self, name, v);
}
static PyObject *
CP_getstate(ProxyObject *self)
{
return Py_BuildValue("OO",
self->__parent__ ? self->__parent__ : Py_None,
self->__name__ ? self->__name__ : Py_None
);
}
static PyObject *
CP_getnewargs(ProxyObject *self)
{
return Py_BuildValue("(O)", self->proxy_object);
}
static PyObject *
CP_setstate(ProxyObject *self, PyObject *state)
{
PyObject *parent, *name;
if(! PyArg_ParseTuple(state, "OO", &parent, &name))
return NULL;
CLEAR(self->__parent__);
CLEAR(self->__name__);
Py_INCREF(parent);
Py_INCREF(name);
self->__parent__ = parent;
self->__name__ = name;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
CP_reduce(ProxyObject *self)
{
PyObject *result;
if (! PER_USE(self))
return NULL;
result = Py_BuildValue("O(O)(OO)",
self->ob_type,
self->proxy_object,
self->__parent__ ? self->__parent__ : Py_None,
self->__name__ ? self->__name__ : Py_None
);
PER_ALLOW_DEACTIVATION(self);
return result;
}
static PyObject *
CP_reduce_ex(ProxyObject *self, PyObject *proto)
{
return CP_reduce(self);
}
static PyObject *
CP__p_deactivate(ProxyObject *self)
{
PyObject *result;
result = PyObject_CallMethodObjArgs(OBJECT(cPersistenceCAPI->pertype),
str_p_deactivate,
self, NULL);
if (result == NULL)
return NULL;
if (self->jar && self->oid && self->state == cPersistent_UPTODATE_STATE)
{
Py_XDECREF(self->__parent__);
self->__parent__ = NULL;
Py_XDECREF(self->__name__);
self->__name__ = NULL;
}
return result;
}
static PyMethodDef
CP_methods[] = {
{"__getstate__", (PyCFunction)CP_getstate, METH_NOARGS,
"Get the object state"},
{"__setstate__", (PyCFunction)CP_setstate, METH_O,
"Set the object state"},
{"__getnewargs__", (PyCFunction)CP_getnewargs, METH_NOARGS,
"Get the arguments that must be passed to __new__"},
{"__reduce__", (PyCFunction)CP_reduce, METH_NOARGS,
"Reduce the object to constituent parts."},
{"__reduce_ex__", (PyCFunction)CP_reduce_ex, METH_O,
"Reduce the object to constituent parts."},
{"_p_deactivate", (PyCFunction)CP__p_deactivate, METH_NOARGS,
"Deactivate the object."},
{NULL, NULL},
};
/* Code to access structure members by accessing attributes */
#include "structmember.h"
static PyMemberDef CP_members[] = {
{"__parent__", T_OBJECT, offsetof(ProxyObject, __parent__)},
{"__name__", T_OBJECT, offsetof(ProxyObject, __name__)},
{NULL} /* Sentinel */
};
static int
CP_traverse(ProxyObject *self, visitproc visit, void *arg)
{
if (cPersistenceCAPI->pertype->tp_traverse((PyObject *)self, visit, arg) < 0)
return -1;
if (self->proxy_object != NULL && visit(self->proxy_object, arg) < 0)
return -1;
if (self->__parent__ != NULL && visit(self->__parent__, arg) < 0)
return -1;
if (self->__name__ != NULL && visit(self->__name__, arg) < 0)
return -1;
return 0;
}
static int
CP_clear(ProxyObject *self)
{
/* Drop references that may have created reference
cycles. Immutable objects do not have to define this method
since they can never directly create reference cycles. Note
that the object must still be valid after calling this
method (don't just call Py_DECREF() on a reference). The
collector will call this method if it detects that this
object is involved in a reference cycle.
*/
if (cPersistenceCAPI->pertype->tp_clear != NULL)
cPersistenceCAPI->pertype->tp_clear((PyObject*)self);
CLEAR(self->proxy_object);
CLEAR(self->__parent__);
CLEAR(self->__name__);
return 0;
}
static void
CP_dealloc(ProxyObject *self)
{
if (self->po_weaklist != NULL)
PyObject_ClearWeakRefs((PyObject *)self);
CLEAR(self->proxy_object);
CLEAR(self->__parent__);
CLEAR(self->__name__);
cPersistenceCAPI->pertype->tp_dealloc((PyObject*)self);
}
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
init_zope_app_container_contained(void)
{
PyObject *m;
str_p_deactivate = PyString_FromString("_p_deactivate");
if (str_p_deactivate == NULL)
return;
/* Try to fake out compiler nag function */
if (0) init_zope_proxy_proxy();
m = Py_InitModule3("_zope_app_container_contained",
module_functions, module___doc__);
if (m == NULL)
return;
if (empty_tuple == NULL)
empty_tuple = PyTuple_New(0);
/* Initialize the PyPersist_C_API and the type objects. */
cPersistenceCAPI = PyCObject_Import("persistent.cPersistence", "CAPI");
if (cPersistenceCAPI == NULL)
return;
ProxyType.tp_name = "zope.app.container.contained.ContainedProxyBase";
ProxyType.ob_type = &PyType_Type;
ProxyType.tp_base = cPersistenceCAPI->pertype;
ProxyType.tp_getattro = CP_getattro;
ProxyType.tp_setattro = CP_setattro;
ProxyType.tp_members = CP_members;
ProxyType.tp_methods = CP_methods;
ProxyType.tp_traverse = (traverseproc) CP_traverse;
ProxyType.tp_clear = (inquiry) CP_clear;
ProxyType.tp_dealloc = (destructor) CP_dealloc;
ProxyType.tp_weaklistoffset = offsetof(ProxyObject, po_weaklist);
if (PyType_Ready(&ProxyType) < 0)
return;
Py_INCREF(&ProxyType);
PyModule_AddObject(m, "ContainedProxyBase", (PyObject *)&ProxyType);
}
This diff is collapsed.
#
# This file is necessary to make this directory a package.
<html metal:use-macro="context/@@standard_macros/addingdialog"
i18n:domain="zope">
<body>
<div metal:fill-slot="body">
<form method="post" action="action.html">
<table class="TypeListing" cellpadding="3">
<tal:block define="title view/title | nothing">
<caption tal:condition="title" tal:content="title"
i18n:translate="">Inserted title</caption>
<caption tal:condition="not:title"
i18n:translate="">Add Content</caption>
</tal:block>
<tbody tal:define="infos view/addingInfo">
<tr tal:repeat="info infos">
<td class="Selector">
<input type="radio" name="type_name"
tal:attributes="value info/action;
id info/action;
checked python:len(infos)==1" />
</td>
<td class="TypeName">
<label style="font-weight: bold;"
tal:attributes="for info/action">
<span tal:replace="info/title" i18n:translate="">Folder</span>
</label>
<div class="TypeDescription" tal:content="info/description"
i18n:translate="">
Folders are generic containers for content, including other
folders.
</div>
</td>
</tr>
<tr>
<td><br /></td>
<td><input type="text" name="id"
tal:condition="view/nameAllowed"
tal:attributes="value request/id | nothing" />
<input type="submit" name="add" value=" Add "
i18n:attributes="value add-button" />
</td>
</tr>
</tbody>
</table>
</form>
</div>
</body>
</html>
##############################################################################
#
# Copyright (c) 2002 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.
#
##############################################################################
"""Adding View
The Adding View is used to add new objects to a container. It is sort of a
factory screen.
$Id$
"""
__docformat__ = 'restructuredtext'
import zope.security.checker
from zope.component.interfaces import IFactory
from zope.event import notify
from zope.interface import implements
from zope.publisher.interfaces import IPublishTraverse
from zope.publisher.browser import BrowserView
from zope.security.proxy import removeSecurityProxy
from zope.exceptions.interfaces import UserError
from zope.location import LocationProxy
from zope.lifecycleevent import ObjectCreatedEvent
from zope.app.container.interfaces import IAdding, INameChooser
from zope.app.container.interfaces import IContainerNamesContainer
from zope.app.container.constraints import checkFactory, checkObject
from zope.app import zapi
from zope.app.container.i18n import ZopeMessageFactory as _
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
from zope.app.publisher.browser.menu import getMenu
class Adding(BrowserView):
implements(IAdding, IPublishTraverse)
def add(self, content):
"""See zope.app.container.interfaces.IAdding
"""
container = self.context
name = self.contentName
chooser = INameChooser(container)
# check precondition
checkObject(container, name, content)
if IContainerNamesContainer.providedBy(container):
# The container picks its own names.
# We need to ask it to pick one.
name = chooser.chooseName(self.contentName or '', content)
else:
request = self.request
name = request.get('add_input_name', name)
if name is None:
name = chooser.chooseName(self.contentName or '', content)
elif name == '':
name = chooser.chooseName('', content)
chooser.checkName(name, content)
container[name] = content
self.contentName = name # Set the added object Name
return container[name]
contentName = None # usually set by Adding traverser
def nextURL(self):
"""See zope.app.container.interfaces.IAdding"""
return zapi.absoluteURL(self.context, self.request) + '/@@contents.html'
# set in BrowserView.__init__
request = None
context = None
def publishTraverse(self, request, name):
"""See zope.app.container.interfaces.IAdding"""
if '=' in name:
view_name, content_name = name.split("=", 1)
self.contentName = content_name
if view_name.startswith('@@'):
view_name = view_name[2:]
return zapi.getMultiAdapter((self, request), name=view_name)
if name.startswith('@@'):
view_name = name[2:]
else:
view_name = name
view = zapi.queryMultiAdapter((self, request), name=view_name)
if view is not None:
return view
factory = zapi.queryUtility(IFactory, name)
if factory is None:
return super(Adding, self).publishTraverse(request, name)
return factory
def action(self, type_name='', id=''):
if not type_name:
raise UserError(_(u"You must select the type of object to add."))
if type_name.startswith('@@'):
type_name = type_name[2:]
if '/' in type_name:
view_name = type_name.split('/', 1)[0]
else:
view_name = type_name
if zapi.queryMultiAdapter((self, self.request),
name=view_name) is not None:
url = "%s/%s=%s" % (
zapi.absoluteURL(self, self.request), type_name, id)
self.request.response.redirect(url)
return
if not self.contentName:
self.contentName = id
# TODO: If the factory wrapped by LocationProxy is already a Proxy,
# then ProxyFactory does not do the right thing and the
# original's checker info gets lost. No factory that was
# registered via ZCML and was used via addMenuItem worked
# here. (SR)
factory = zapi.getUtility(IFactory, type_name)
if not type(factory) is zope.security.checker.Proxy:
factory = LocationProxy(factory, self, type_name)
factory = zope.security.checker.ProxyFactory(factory)
content = factory()
# Can't store security proxies.
# Note that it is important to do this here, rather than
# in add, otherwise, someone might be able to trick add
# into unproxying an existing object,
content = removeSecurityProxy(content)
notify(ObjectCreatedEvent(content))
self.add(content)
self.request.response.redirect(self.nextURL())
def nameAllowed(self):
"""Return whether names can be input by the user."""
return not IContainerNamesContainer.providedBy(self.context)
menu_id = None
index = ViewPageTemplateFile("add.pt")
def addingInfo(self):
"""Return menu data.
This is sorted by title.
"""
container = self.context
result = []
for menu_id in (self.menu_id, 'zope.app.container.add'):
if not menu_id:
continue
for item in getMenu(menu_id, self, self.request):
extra = item.get('extra')
if extra:
factory = extra.get('factory')
if factory:
factory = zapi.getUtility(IFactory, factory)
if not checkFactory(container, None, factory):
continue
elif item['extra']['factory'] != item['action']:
item['has_custom_add_view']=True
result.append(item)
result.sort(lambda a, b: cmp(a['title'], b['title']))
return result
def isSingleMenuItem(self):
"Return whether there is single menu item or not."
return len(self.addingInfo()) == 1
def hasCustomAddView(self):
"This should be called only if there is `singleMenuItem` else return 0"
if self.isSingleMenuItem():
menu_item = self.addingInfo()[0]
if 'has_custom_add_view' in menu_item:
return True
return False
<tal:block define="addingInfo context/@@+/addingInfo|nothing"
condition="addingInfo" i18n:domain="zope">
<tal:block repeat="info addingInfo"
define="namesRequired context/@@+/nameAllowed">
<div tal:define="oddrow repeat/info/odd;
namesRequired context/@@+/nameAllowed;
has_custom_add_view python:'has_custom_add_view' in info"
tal:attributes="class python:oddrow and 'content even' or 'content odd'"
class="even">
<a href="#"
tal:define="baseurl python:request.getURL(1)"
tal:condition="python: not info['action'].startswith('../')
and namesRequired and not has_custom_add_view"
tal:attributes="
href string:${baseurl}/@@contents.html?type_name=${info/action};
class info/selected"
tal:content="info/title" i18n:translate="">Folder
</a>
<a href="#"
tal:define="baseurl python:request.getURL(1)"
tal:condition="python: not info['action'].startswith('../')
and (has_custom_add_view or not namesRequired)"
tal:attributes="
href string:${baseurl}/@@+/action.html?type_name=${info/action};
class info/selected"
tal:content="info/title" i18n:translate="">Folder
</a>
<a href="#"
tal:define="baseurl python:request.getURL(1)"
tal:condition="python: info['action'].startswith('../')"
tal:attributes="
href python: info['action'][3:];
class info/selected"
tal:content="info/title" i18n:translate="">Folder
</a>
</div>
</tal:block>
</tal:block>
<zope:configure
xmlns:zope="http://namespaces.zope.org/zope"
xmlns="http://namespaces.zope.org/browser">
<page
for="zope.app.container.interfaces.IReadContainer"
name="find.html"
permission="zope.ManageContent"
class="zope.app.container.browser.find.Find"
template="find.pt"
menu="zmi_actions" title="Find" />
<page
for="zope.app.container.interfaces.IWriteContainer"
permission="zope.ManageContent"
name="commonTasks"
class="zope.app.container.browser.contents.Contents"
template="commontasks.pt" />
</zope:configure>
<html metal:use-macro="context/@@standard_macros/view"
i18n:domain="zope">
<body>
<div metal:fill-slot="body">
<div metal:define-macro="contents">
<form name="containerContentsForm" method="post" action="."
tal:attributes="action request/URL"
tal:define="container_contents view/listContentInfo">
<input type="hidden" name="type_name" value=""
tal:attributes="value request/type_name"
tal:condition="request/type_name|nothing"
/>
<input type="hidden" name="retitle_id" value=""
tal:attributes="value request/retitle_id"
tal:condition="request/retitle_id|nothing"
/>
<div class="page_error"
tal:condition="view/error"
tal:content="view/error"
i18n:translate="">
Error message
</div>
<table id="sortable" class="listing" summary="Content listing"
i18n:attributes="summary">
<thead>
<tr>
<th><input type="checkbox" onchange="updateCheckboxes(this, 'slaveBox');" /></th>
<th i18n:translate="">Name</th>
<th i18n:translate="">Title</th>
<th i18n:translate="">Size</th>
<th i18n:translate="">Created</th>
<th i18n:translate="">Modified</th>
</tr>
</thead>
<tbody>
<metal:block tal:condition="view/hasAdding">
<tr tal:define="names_required context/@@+/nameAllowed"
tal:condition="python:names_required and request.has_key('type_name')">
<td></td>
<td><input name="new_value" id="focusid" value="" /></td>
<td></td>
<td></td>
<td></td>
</tr>
</metal:block>
<metal:block tal:define="supportsRename view/supportsRename"
tal:repeat="item container_contents">
<tr tal:define="oddrow repeat/item/odd; url item/url;
id_quoted item/id/url:quote"
tal:attributes="class python:oddrow and 'even' or 'odd'" >
<td>
<input type="checkbox" class="noborder slaveBox" name="ids:list" id="#"
value="#"
tal:attributes="value item/id;
id item/cb_id;
checked request/ids_checked|nothing;"/>
</td>
<td><a href="#"
tal:attributes="href
string:${url}/@@SelectedManagementView.html"
tal:content="structure item/icon|default">
</a
><span tal:condition="item/rename"
><input name="new_value:list"
tal:attributes="value item/id"
/><input type="hidden" name="rename_ids:list" value=""
tal:attributes="value item/rename"
/></span
><span tal:condition="not:item/rename">
<a href="#"
tal:attributes="href
string:${url}/@@SelectedManagementView.html"
tal:content="item/id"
>foo</a
><a href="#"
tal:attributes="href
string:${request/URL}?rename_ids:list=${id_quoted}"
tal:condition="supportsRename"
>&nbsp;&nbsp;</a
></span
></td>
<td>
<input name="new_value" id="focusid"
tal:attributes="value item/title|nothing"
tal:condition="item/retitle"
/>
<a href="#"
tal:attributes="href
string:${request/URL}?retitle_id=${id_quoted}"
tal:condition="item/retitleable"
tal:content="item/title|default"
i18n:translate=""
>&nbsp;&nbsp;&nbsp;&nbsp;</a>
<span
tal:condition="item/plaintitle"
tal:content="item/title|default"
i18n:translate=""
>&nbsp;&nbsp;&nbsp;&nbsp;</span>
</td>
<td><span tal:content="item/size/sizeForDisplay|nothing"
i18n:translate="">
&nbsp;</span></td>
<td><span tal:define="created item/created|default"
tal:content="created"
i18n:translate="">&nbsp;</span></td>
<td><span tal:define="modified item/modified|default"
tal:content="modified"
i18n:translate="">&nbsp;</span></td>
</tr>
</metal:block>
</tbody>
</table>
<tal:block tal:condition="view/normalButtons">
<input type="submit" name="container_rename_button" value="Rename"
i18n:attributes="value container-rename-button"
tal:condition="view/supportsRename"
/>
<input type="submit" name="container_cut_button" value="Cut"
i18n:attributes="value container-cut-button"
tal:condition="view/supportsCut"
/>
<input type="submit" name="container_copy_button" value="Copy"
i18n:attributes="value container-copy-button"
tal:condition="view/supportsCopy"
/>
<input type="submit" name="container_paste_button" value="Paste"
tal:condition="view/hasClipboardContents"
i18n:attributes="value container-paste-button"
/>
<input type="submit" name="container_delete_button" value="Delete"
i18n:attributes="value container-delete-button"
tal:condition="view/supportsDelete"
i18n:domain="zope"
/>
<div tal:condition="view/hasAdding" tal:omit-tag="">
<div tal:omit-tag=""
tal:define="adding nocall:context/@@+;
addingInfo adding/addingInfo;
has_custom_add_view adding/hasCustomAddView;
names_required adding/nameAllowed"
tal:condition="adding/isSingleMenuItem">
<input type="submit" name="container_add_button" value="Add"
i18n:attributes="value add-button"
i18n:domain="zope"
/>
<input type="text" name="single_new_value" id="focusid"
tal:condition="python:names_required and not has_custom_add_view"
i18n:domain="zope"
/>
<input type="hidden" name="single_type_name"
value=""
tal:attributes="value python:addingInfo[0]['action']"
/>
</div>
</div>
</tal:block>
<div tal:condition="view/specialButtons">
<input type="submit" value="Apply"
i18n:attributes="value container-apply-button"
/>
<input type="submit" name="container_cancel_button" value="Cancel"
i18n:attributes="value container-cancel-button"
/>
</div>
</form>
<script type="text/javascript"><!--
if (document.containerContentsForm.new_value)
document.containerContentsForm.new_value.focus();
//-->
</script>
</div>
</div>
</body>
</html>
This diff is collapsed.
<html metal:use-macro="context/@@standard_macros/dialog"
i18n:domain="zope">
<body>
<div metal:fill-slot="body" >
<form action="@@find.html" method="get">
<input type="text" name="ids" value="" /><br />
<input type="submit" name="find_submit" value=" Find "
i18n:attributes="value find-button"/>
</form>
<table tal:condition="request/ids|nothing">
<tr tal:repeat="item python:view.findByIds(request['ids'])">
<td>
<a href="" tal:attributes="href item/url" tal:content="item/id">id</a>
</td>
</tr>
</table>
</div>
</body>
</html>
##############################################################################
#
# Copyright (c) 2001, 2002 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.
#
##############################################################################
"""Find View Class
$Id$
"""
__docformat__ = 'restructuredtext'
from zope.traversing.api import getName
from zope.traversing.browser.absoluteurl import absoluteURL
from zope.publisher.browser import BrowserView
from zope.app.container.find import SimpleIdFindFilter
from zope.app.container.interfaces import IFind
# Very simple implementation right now
class Find(BrowserView):
def findByIds(self, ids):
"""Do a find for the `ids` listed in `ids`, which is a string."""
finder = IFind(self.context)
ids = ids.split()
# if we don't have any ids listed, don't search at all
if not ids:
return []
request = self.request
result = []
for object in finder.find([SimpleIdFindFilter(ids)]):
url = absoluteURL(object, request)
result.append({ 'id': getName(object), 'url': url})
return result
#
# This file is necessary to make this directory a package.
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<class class=".test_contents.ReadOnlyContainer">
<require
permission="zope.ManageContent"
interface="zope.app.container.interfaces.IReadContainer"
/>
</class>
<browser:containerViews
for="zope.app.container.interfaces.IReadContainer"
contents="zope.ManageContent" />
</configure>
The containerViews directive lets us associate some standard forms
for containers with an interface. There's an "index.html" view that
provides a listing of the contained objects without provinding any way
to manage them (though it allows us to visit them by clicking on
links).
We can get this view from the root folder easily::
>>> response = http(r"""
... GET / HTTP/1.1
... """)
And we can check that there isn't a form (where the management
operations would have buttons)::
>>> body = response.getBody().lower()
>>> "<form" in body
False
This diff is collapsed.
<html metal:use-macro="context/@@standard_macros/page"
i18n:domain="zope">
<head>
<style metal:fill-slot="headers" type="text/css">
<!--
.ContentIcon {
width: 20px;
}
.ContentTitle {
text-align: left;
}
-->
</style>
</head>
<body>
<div metal:fill-slot="body">
<table
id="sortable" class="listing" summary="Content listing"
cellpadding="2" cellspacing="0"
i18n:attributes="summary">
<thead>
<tr>
<th>&nbsp;</th>
<th i18n:translate="">Name</th>
<th i18n:translate="">Title</th>
<th i18n:translate="">Created</th>
<th i18n:translate="">Modified</th>
</tr>
</thead>
<tbody>
<tr tal:repeat="info view/listContentInfo">
<td>
<a
href="#"
tal:attributes="href info/url"
tal:content="structure info/icon|default" />
</td>
<td class="ContentTitle">
<a href="subfolder_id"
tal:attributes="href info/url"
tal:content="info/id"
i18n:translate=""
>ID here</a>
</td>
<td><span tal:content="info/title|default"
i18n:translate="">&nbsp;</span></td>
<td><span tal:content="info/created|default"
i18n:translate="">&nbsp;</span></td>
<td><span tal:content="info/modified|default"
i18n:translate="">&nbsp;</span></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:meta="http://namespaces.zope.org/meta">
<meta:directives namespace="http://namespaces.zope.org/browser">
<!-- browser cotainer views -->
<meta:directive
name="containerViews"
schema=".metaconfigure.IContainerViews"
handler=".metaconfigure.containerViews"
/>
</meta:directives>
</configure>
\ No newline at end of file
##############################################################################
#
# Copyright (c) 2001, 2002 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.
#
##############################################################################
"""Container-specific browser ZCML namespace directive handlers
$Id$
"""
__docformat__ = 'restructuredtext'
from zope.interface import Interface
from zope.configuration.fields import GlobalObject
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
from zope.schema import Id
from zope.security.zcml import Permission
from zope.app.publisher.browser.viewmeta import page, view
from zope.app.container.browser.contents import Contents
from zope.app.container.browser.adding import Adding
from zope.app.component.back35 import LayerField
from zope.app.container.i18n import ZopeMessageFactory as _
class IContainerViews(Interface):
"""Define several container views for an `IContainer` implementation."""
for_ = GlobalObject(
title=u"The declaration this containerViews are for.",
description=u"""
The containerViews will be available for all objects that
provide this declaration.
""",
required=True)
contents = Permission(
title=u"The permission needed for content page.",
required=False)
index = Permission(
title=u"The permission needed for index page.",
required=False)
add = Permission(
title=u"The permission needed for add page.",
required=False)
layer = LayerField(
title=_("The layer the view is in."),
description=_("""A skin is composed of layers. It is common to put
skin specific views in a layer named after the skin. If the 'layer'
attribute is not supplied, it defaults to 'default'."""),
required=False
)
def containerViews(_context, for_, contents=None, add=None, index=None,
layer=IDefaultBrowserLayer):
"""Set up container views for a given content type."""
if for_ is None:
raise ValueError("A for interface must be specified.")
if contents is not None:
from zope.app.menus import zmi_views
page(_context, name='contents.html', permission=contents,
for_=for_, layer=layer, class_=Contents, attribute='contents',
menu=zmi_views, title=_('Contents'))
if index is not None:
page(_context, name='index.html', permission=index, for_=for_,
layer=layer, class_=Contents, attribute='index')
if add is not None:
from zope.app.menus import zmi_actions
viewObj = view(_context, name='+', layer=layer, menu=zmi_actions,
title=_('Add'), for_=for_, permission=add,
class_=Adding)
viewObj.page(_context, name='index.html', attribute='index')
viewObj.page(_context, name='action.html', attribute='action')
viewObj()
#
# This file is necessary to make this directory a package.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
##############################################################################
#
# Copyright (c) 2001, 2002 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.
#
##############################################################################
"""This module provides a sample container implementation.
This is primarily for testing purposes.
It might be useful as a mix-in for some classes, but many classes will
need a very different implementation.
$Id$
"""
__docformat__ = 'restructuredtext'
from persistent import Persistent
from BTrees.OOBTree import OOBTree
from zope.app.container.sample import SampleContainer
class BTreeContainer(SampleContainer, Persistent):
# implements(what my base classes implement)
# TODO: It appears that BTreeContainer uses SampleContainer only to
# get the implementation of __setitem__(). All the other methods
# provided by that base class are just slower replacements for
# operations on the BTree itself. It would probably be clearer to
# just delegate those methods directly to the btree.
def _newContainerData(self):
"""Construct an item-data container
Subclasses should override this if they want different data.
The value returned is a mapping object that also has get,
has_key, keys, items, and values methods.
"""
return OOBTree()
def __contains__(self, key):
'''See interface IReadContainer
Reimplement this method, since has_key() returns the key if available,
while we expect True or False.
>>> c = BTreeContainer()
>>> "a" in c
False
>>> c["a"] = 1
>>> "a" in c
True
>>> "A" in c
False
'''
return key in self._SampleContainer__data
has_key = __contains__
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
i18n_domain="zope"
>
<adapter
provides=".interfaces.IFind"
for=".interfaces.IReadContainer"
permission="zope.ManageContent"
factory="zope.app.container.find.FindAdapter"
/>
<adapter
for=".interfaces.IReadContainer"
provides="zope.filerepresentation.interfaces.IReadDirectory"
factory=".directory.noop"
/>
<adapter
for=".interfaces.IWriteContainer"
provides="zope.filerepresentation.interfaces.IWriteDirectory"
factory=".directory.noop"
/>
<adapter
factory="zope.app.container.traversal.ContainerTraversable"
provides="zope.traversing.interfaces.ITraversable"
for="zope.app.container.interfaces.IReadContainer"
/>
<adapter
factory="zope.app.container.size.ContainerSized"
provides="zope.size.interfaces.ISized"
for="zope.app.container.interfaces.IReadContainer"
/>
<adapter
provides=".interfaces.INameChooser"
for="zope.app.container.interfaces.IWriteContainer"
factory=".contained.NameChooser"
/>
<subscriber
handler=".dependency.CheckDependency"
for="zope.app.container.interfaces.IObjectRemovedEvent"
trusted="y"
/>
<subscriber
for="zope.location.interfaces.ILocation
zope.app.container.interfaces.IObjectMovedEvent"
handler=".contained.dispatchToSublocations"
>
Handler dispatches moved events to sublocations of the original object.
</subscriber>
<adapter
provides="zope.location.interfaces.ISublocations"
for="zope.app.container.interfaces.IReadContainer"
factory=".contained.ContainerSublocations"
/>
<class class=".constraints.ItemTypePrecondition">
<allow interface=".constraints.IItemTypePrecondition" />
</class>
<view
for="zope.app.container.interfaces.IItemContainer"
type="zope.publisher.interfaces.browser.IBrowserRequest"
provides="zope.publisher.interfaces.browser.IBrowserPublisher"
factory="zope.app.container.traversal.ItemTraverser"
permission="zope.Public"
allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
/>
<view
for="zope.app.container.interfaces.ISimpleReadContainer"
type="zope.publisher.interfaces.browser.IBrowserRequest"
provides="zope.publisher.interfaces.browser.IBrowserPublisher"
factory="zope.app.container.traversal.ItemTraverser"
permission="zope.Public"
allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
/>
</configure>
This diff is collapsed.
Containment constraints
=======================
Containment constraints allow us to express restrictions on the types
of items that can be placed in containers or on the types of
containers an item can be placed in. We express these constraints in
interfaces. Let's define some container and item interfaces:
>>> from zope.app.container.interfaces import IContainer, IContained
>>> from zope.app.container.constraints import containers, contains
>>> class IBuddyFolder(IContainer):
... contains('.IBuddy')
In this example, we used the contains function to declare that objects
that provide IBuddyFolder can only contain items that provide IBuddy.
Note that we used a string containing a dotted name for the IBuddy
interface. This is because IBuddy hasn't been defined yet. When we
define IBuddy, we can use IBuddyFolder directly:
>>> class IBuddy(IContained):
... containers(IBuddyFolder)
Now, with these interfaces in place, we can define Buddy and
BuddyFolder classes and verify that we can put buddies in buddy
folders:
>>> from zope import interface
>>> class Buddy:
... interface.implements(IBuddy)
>>> class BuddyFolder:
... interface.implements(IBuddyFolder)
>>> from zope.app.container.constraints import checkObject, checkFactory
>>> from zope.component.factory import Factory
>>> checkObject(BuddyFolder(), 'x', Buddy())
>>> checkFactory(BuddyFolder(), 'x', Factory(Buddy))
True
If we try to use other containers or folders, we'll get errors:
>>> class Container:
... interface.implements(IContainer)
>>> class Contained:
... interface.implements(IContained)
>>> checkObject(Container(), 'x', Buddy())
... # doctest: +ELLIPSIS
Traceback (most recent call last):
InvalidContainerType: ...
>>> checkFactory(Container(), 'x', Factory(Buddy))
False
>>> checkObject(BuddyFolder(), 'x', Contained())
... # doctest: +ELLIPSIS
Traceback (most recent call last):
InvalidItemType: ...
>>> checkFactory(BuddyFolder(), 'x', Factory(Contained))
False
In the example, we defined the container first and then the items. We
could have defined these in the opposite order:
>>> class IContact(IContained):
... containers('.IContacts')
>>> class IContacts(IContainer):
... contains(IContact)
>>> class Contact:
... interface.implements(IContact)
>>> class Contacts:
... interface.implements(IContacts)
>>> checkObject(Contacts(), 'x', Contact())
>>> checkFactory(Contacts(), 'x', Factory(Contact))
True
>>> checkObject(Contacts(), 'x', Buddy())
... # doctest: +ELLIPSIS
Traceback (most recent call last):
InvalidItemType: ...
>>> checkFactory(Contacts(), 'x', Factory(Buddy))
False
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#
# This file is necessary to make this directory a package.
This diff is collapsed.
This diff is collapsed.
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""Customization of zope.i18n for the Zope application server
$Id$
"""
__docformat__ = 'restructuredtext'
# import this as _ to create i18n messages in the zope domain
from zope.i18nmessageid import MessageFactory
ZopeMessageFactory = MessageFactory('zope')
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
import os
from zope.app.testing.functional import ZCMLLayer
AppContainerLayer = ZCMLLayer(
os.path.join(os.path.split(__file__)[0], 'ftesting.zcml'),
__name__, 'AppContainerLayer', allow_teardown=True)
#
# This file is necessary to make this directory a package.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment