-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
690 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
############################################################################## | ||
# | ||
# 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$ | ||
""" | ||
from warnings import warn | ||
import zope.security.checker | ||
from zope.interface import implements | ||
from zope.publisher.interfaces import IPublishTraverse | ||
from zope.proxy import removeAllProxies | ||
from zope.component.interfaces import IFactory | ||
|
||
from zope.app.exception.interfaces import UserError | ||
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.event.objectevent import ObjectCreatedEvent | ||
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile | ||
from zope.event import notify | ||
from zope.app.publisher.browser import BrowserView | ||
|
||
from zope.app.i18n import ZopeMessageIDFactory as _ | ||
from zope.i18n import translate | ||
from zope.app.location import LocationProxy | ||
|
||
class BasicAdding(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 pick's it's 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, container) | ||
|
||
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 (str(zapi.getView(self.context, "absolute_url", self.request)) | ||
+ '/@@contents.html') | ||
|
||
# set in BrowserView.__init__ | ||
request = None | ||
context = None | ||
|
||
def renderAddButton(self): | ||
warn("The renderAddButton method is deprecated, use nameAllowed", | ||
DeprecationWarning, 2) | ||
|
||
|
||
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.getView(self, view_name, request) | ||
|
||
if name.startswith('@@'): | ||
view_name = name[2:] | ||
else: | ||
view_name = name | ||
|
||
view = zapi.queryView(self, view_name, request) | ||
if view is not None: | ||
return view | ||
|
||
factory = zapi.queryUtility(IFactory, name) | ||
if factory is None: | ||
return super(BasicAdding, 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.queryView(self, view_name, self.request) is not None: | ||
url = "%s/%s=%s" % ( | ||
zapi.getView(self, "absolute_url", 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 = removeAllProxies(content) | ||
|
||
notify(ObjectCreatedEvent(content)) | ||
|
||
self.add(content) | ||
self.request.response.redirect(self.nextURL()) | ||
|
||
def namesAccepted(self): | ||
return not IContainerNamesContainer.providedBy(self.context) | ||
|
||
def nameAllowed(self): | ||
"""Return whether names can be input by the user.""" | ||
return not IContainerNamesContainer.providedBy(self.context) | ||
|
||
|
||
class Adding(BasicAdding): | ||
|
||
menu_id = None | ||
index = ViewPageTemplateFile("add.pt") | ||
|
||
def addingInfo(self): | ||
"""Return menu data. | ||
This is sorted by title. | ||
""" | ||
container = self.context | ||
menu_service = zapi.getService("BrowserMenu") | ||
result = [] | ||
for menu_id in (self.menu_id, 'zope.app.container.add'): | ||
if not menu_id: | ||
continue | ||
for item in menu_service.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 | ||
|
||
class ContentAdding(Adding): | ||
|
||
menu_id = "add_content" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
############################################################################## | ||
# | ||
# 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$ | ||
""" | ||
from zope.app.container.find import SimpleIdFindFilter | ||
from zope.app.container.interfaces import IFind | ||
from zope.app.traversing.api import getName | ||
from zope.component import getView | ||
from zope.app.publisher.browser import BrowserView | ||
|
||
# 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 = str(getView(object, 'absolute_url', request)) | ||
result.append({ 'id': getName(object), 'url': url}) | ||
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
############################################################################## | ||
# | ||
# 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$ | ||
""" | ||
|
||
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__ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
############################################################################## | ||
# 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. | ||
############################################################################## | ||
"""File-system representation adapters for containers | ||
This module includes two adapters (adapter factories, really) for | ||
providing a file-system representation for containers: | ||
noop | ||
Factory that "adapts" IContainer to IWriteDirectory. | ||
This is a lie, since it just returns the original object. | ||
Cloner | ||
An IDirectoryFactory adapter that just clones the original object. | ||
$Id$ | ||
""" | ||
import zope.app.filerepresentation.interfaces | ||
from zope.proxy import removeAllProxies | ||
from zope.interface import implements | ||
|
||
def noop(container): | ||
"""Adapt an IContainer to an IWriteDirectory by just returning it | ||
This "works" because IContainer and IWriteDirectory have the same | ||
methods, however, the output doesn't actually implement IWriteDirectory. | ||
""" | ||
return container | ||
|
||
|
||
class Cloner(object): | ||
"""IContainer to IDirectoryFactory adapter that clones | ||
This adapter provides a factory that creates a new empty container | ||
of the same class as it's context. | ||
""" | ||
|
||
implements(zope.app.filerepresentation.interfaces.IDirectoryFactory) | ||
|
||
def __init__(self, context): | ||
self.context = context | ||
|
||
def __call__(self, name): | ||
# We remove all of the proxies so we can actually | ||
# call the class. This should be OK as we are only | ||
# calling this for objects that get this adapter. | ||
return removeAllProxies(self.context).__class__() |
Oops, something went wrong.