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 = GlobalInterface( 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, for_=for_, permission=add, class_=Adding) menuItemDirective( _context, zmi_actions, for_, '+', _('Add'), permission=add, layer=layer, filter= 'python:modules["zope.app.container.browser.metaconfigure"].menuFilter(context, request)' ) viewObj.page(_context, name='index.html', attribute='index') viewObj.page(_context, name='action.html', attribute='action') viewObj()
def removeObjects(self): """Remove objects specified in a list of object ids""" request = self.request ids = request.get('ids') if not ids: self.error = _("You didn't specify any ids to remove.") return container = self.context for id in ids: del container[id]
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, for_=for_, permission=add, class_=Adding) menuItemDirective( _context, zmi_actions, for_, "+", _("Add"), permission=add, layer=layer, filter='python:modules["zope.app.container.browser.metaconfigure"].menuFilter(context, request)', ) viewObj.page(_context, name="index.html", attribute="index") viewObj.page(_context, name="action.html", attribute="action") viewObj()
def listContentInfo(self): request = self.request if "container_cancel_button" in request: if "type_name" in request: del request.form['type_name'] if "rename_ids" in request and "new_value" in request: del request.form['rename_ids'] if "retitle_id" in request and "new_value" in request: del request.form['retitle_id'] return self._normalListContentsInfo() elif "container_rename_button" in request and not request.get("ids"): self.error = _("You didn't specify any ids to rename.") elif "container_add_button" in request: if "single_type_name" in request \ and "single_new_value" in request: request.form['type_name'] = request['single_type_name'] request.form['new_value'] = request['single_new_value'] self.addObject() elif 'single_type_name' in request \ and 'single_new_value' not in request: request.form['type_name'] = request['single_type_name'] request.form['new_value'] = "" self.addObject() elif "type_name" in request and "new_value" in request: self.addObject() elif "rename_ids" in request and "new_value" in request: self.renameObjects() elif "retitle_id" in request and "new_value" in request: self.changeTitle() elif "container_cut_button" in request: self.cutObjects() elif "container_copy_button" in request: self.copyObjects() elif "container_paste_button" in request: self.pasteObjects() elif "container_delete_button" in request: self.removeObjects() else: return self._normalListContentsInfo() if self.error: return self._normalListContentsInfo() status = request.response.getStatus() if status not in (302, 303): # Only redirect if nothing else has request.response.redirect(request.URL) return ()
def copyObjects(self): """Copy objects specified in a list of object ids""" request = self.request ids = request.get('ids') if not ids: self.error = _("You didn't specify any ids to copy.") return container_path = 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 id in ids: ob = self.context[id] copier = IObjectCopier(ob) if not copier.copyable(): m = {"name": id} title = getDCTitle(ob) if title: m["title"] = title self.error = _( "Object '${name}' (${title}) cannot be copied", mapping=m) else: self.error = _("Object '${name}' cannot be copied", mapping=m) return items.append(joinPath(container_path, id)) # store the requested operation in the principal annotations: clipboard = getPrincipalClipboard(self.request) clipboard.clearContents() clipboard.addItems('copy', items)
def cutObjects(self): """move objects specified in a list of object ids""" request = self.request ids = request.get('ids') if not ids: self.error = _("You didn't specify any ids to cut.") return container_path = 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 id in ids: ob = self.context[id] mover = IObjectMover(ob) if not mover.moveable(): m = {"name": id} title = getDCTitle(ob) if title: m["title"] = title self.error = _( "Object '${name}' (${title}) cannot be moved", mapping=m) else: self.error = _("Object '${name}' cannot be moved", mapping=m) return items.append(joinPath(container_path, id)) # store the requested operation in the principal annotations: clipboard = getPrincipalClipboard(self.request) clipboard.clearContents() clipboard.addItems('cut', items)
def pasteObjects(self): """Paste ojects in the user clipboard to the container """ target = self.context clipboard = getPrincipalClipboard(self.request) items = clipboard.getContents() moved = False not_pasteable_ids = [] for item in items: duplicated_id = False try: obj = 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(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 ? raise UserError( _("The given name(s) %s is / are already being used" % (str(not_pasteable_ids))))
def pasteObjects(self): """Paste ojects in the user clipboard to the container """ target = self.context clipboard = getPrincipalClipboard(self.request) items = clipboard.getContents() moved = False not_pasteable_ids = [] for item in items: duplicated_id = False try: obj = 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(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 ? raise UserError( _("The given name(s) %s is / are already being used" %( str(not_pasteable_ids))))
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 queryMultiAdapter((self, self.request), name=view_name) is not None: url = "%s/%s=%s" % ( 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 = 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())