This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
plone.dexterity/plone/dexterity/browser/add.py

156 lines
5.7 KiB
Python

from zope.component import getUtility, createObject
from zope.publisher.browser import BrowserPage
from zope.event import notify
from z3c.form import form, button
from plone.z3cform import layout
from plone.dexterity.interfaces import IDexterityFTI
from plone.dexterity.i18n import MessageFactory as _
from plone.dexterity.browser.base import DexterityExtensibleForm
from plone.dexterity.utils import addContentToContainer
from plone.dexterity.events import AddBegunEvent
from plone.dexterity.events import AddCancelledEvent
from plone.dexterity.utils import getAdditionalSchemata
from Acquisition import aq_inner, aq_base
from Acquisition.interfaces import IAcquirer
from Products.statusmessages.interfaces import IStatusMessage
class DefaultAddForm(DexterityExtensibleForm, form.AddForm):
"""Standard add form, which is wrapped by DefaultAddView (see below).
This form is capable of rendering the fields of any Dexterity schema,
including behaviours. To do that, needs to know the portal_type, which
can be set as a class variable (in a subclass), or on a created instance.
By default, the DefaultAddView (see below) will set the portal_type based
on the FTI.
"""
portal_type = None
immediate_view = None
def __init__(self, context, request, ti=None):
super(DefaultAddForm, self).__init__(context, request)
if ti is not None:
self.ti = ti
self.portal_type = ti.getId()
self.request['disable_border'] = True
@property
def additionalSchemata(self):
return getAdditionalSchemata(portal_type=self.portal_type)
# API
def create(self, data):
fti = getUtility(IDexterityFTI, name=self.portal_type)
container = aq_inner(self.context)
content = createObject(fti.factory)
# Note: The factory may have done this already, but we want to be sure
# that the created type has the right portal type. It is possible
# to re-define a type through the web that uses the factory from an
# existing type, but wants a unique portal_type!
if hasattr(content, '_setPortalTypeName'):
content._setPortalTypeName(fti.getId())
# Acquisition wrap temporarily to satisfy things like vocabularies
# depending on tools
if IAcquirer.providedBy(content):
content = content.__of__(container)
form.applyChanges(self, content, data)
for group in self.groups:
form.applyChanges(group, content, data)
return aq_base(content)
def add(self, object):
fti = getUtility(IDexterityFTI, name=self.portal_type)
container = aq_inner(self.context)
new_object = addContentToContainer(container, object)
if fti.immediate_view:
self.immediate_view = "%s/%s/%s" % (container.absolute_url(), new_object.id, fti.immediate_view,)
else:
self.immediate_view = "%s/%s" % (container.absolute_url(), new_object.id)
def nextURL(self):
if self.immediate_view is not None:
return self.immediate_view
else:
return self.context.absolute_url()
# Buttons
@button.buttonAndHandler(_('Save'), name='save')
def handleAdd(self, action):
data, errors = self.extractData()
if errors:
self.status = self.formErrorsMessage
return
obj = self.createAndAdd(data)
if obj is not None:
# mark only as finished if we get the new object
self._finishedAdd = True
IStatusMessage(self.request).addStatusMessage(_(u"Item created"), "info")
@button.buttonAndHandler(_(u'Cancel'), name='cancel')
def handleCancel(self, action):
IStatusMessage(self.request).addStatusMessage(_(u"Add New Item operation cancelled"), "info")
self.request.response.redirect(self.nextURL())
notify(AddCancelledEvent(self.context))
def update(self):
super(DefaultAddForm, self).update()
# fire the edit begun only if no action was executed
if len(self.actions.executedActions) == 0:
notify(AddBegunEvent(self.context))
def updateActions(self):
super(DefaultAddForm, self).updateActions()
if 'save' in self.actions:
self.actions["save"].addClass("context")
if 'cancel' in self.actions:
self.actions["cancel"].addClass("standalone")
@property
def label(self):
portal_type = self.portal_type
fti = getUtility(IDexterityFTI, name=portal_type)
type_name = fti.Title()
if self.context.portal_type == 'pfwbgedfolder':
return _(u"${folder}: Ajouter ${name}", mapping={'name': type_name,
'folder': self.context.title})
if portal_type == 'pfwbgedlink':
return _(u"Classer dans le dossier")
return _(u"Add ${name}", mapping={'name': type_name})
class DefaultAddView(layout.FormWrapper, BrowserPage):
"""This is the default add view as looked up by the ++add++ traversal
namespace adapter in CMF. It is an unnamed adapter on
(context, request, fti).
Note that this is registered in ZCML as a simple <adapter />, but we
also use the <class /> directive to set up security.
"""
form = DefaultAddForm
def __init__(self, context, request, ti):
super(DefaultAddView, self).__init__(context, request)
self.ti = ti
# Set portal_type name on newly created form instance
if self.form_instance is not None and not getattr(self.form_instance, 'portal_type', None):
self.form_instance.portal_type = ti.getId()