How can I use zope 3 / ztk layers without having a zope 2 skin layer in Plone 4? - plone

We're trying to develop our Plone 4.1 product using only ZTK (Zope 3) views and hence haven't defined a portal skin. I'm trying to override a view from a different package and in the past have used the layer attribute to do this.
plone.theme allows you to mark the request with a "layer" interface conditional on the currently selected skin. I'd like to mark requests with a "layer" interface if my product is installed, without creating a skin layer. How do I do that?
I have my interface defined already in zcml
<interface
interface=".interfaces.IThemeSpecific"
type="zope.publisher.interfaces.browser.IBrowserSkinType"
name="My Theme"
/>
and declared
from zope.interface import Interface
class IThemeSpecific(Interface):
"""Marker interface for skins part of 'My Theme'
"""

You have to use a browserlayer.
So, if you don't need it for something else, you can remove the zcml interface declaration and keep only the python interface (maybe you can rename it something more specific like IMyPackageLayer). Then add a file browserlayer.xml in your generic setup profile with this:
<?xml version="1.0"?>
<!-- Register the package-specific browser layer, so that it will be activated
when this product is installed. -->
<layers>
<layer name="my.package.browserlayer"
interface="my.package.browser.interfaces.IThemeSpecific" />
</layers>
After that you can use the layer attribute as always:
<browser:page
name="my-view"
for="*"
layer="my.package.browser.interfaces.IThemeSpecific"
/>
Just remember to restart zope and reinstall you product to apply the new genericsetup configuration.
That's all.

Related

Selecting different templates for a Plone tile

on Plone, tiles are nothing but Zope browser views; we were wondering if it is possible to declare/use different templates for a tile on an simple way.
according to plone.tiles documentation you can override a template for a different context.
<plone:tile
name="sample.persistenttile"
template="override.pt"
permission="zope.Public"
for="*"
layer=".interfaces.IMyLayer"
/>
should we need to implement a way to mark the tiles with some interface for this? is there a different/easier solution?

Override viewlet to be less pervasive

I'm using a 3rd party product that provides a viewlet with an overly pervasive context of plone.uuid.interfaces.IUUIDAware, so it's effectively appearing on everything. I'd like to override this to restrict it to specific content types on my site.
I've tried adding the following declarative to both configures.zcml and overrides.zcml in the site package:
<browser:viewlet
name="other.product.viewlet"
for="my.site.interfaces.ICustomContentType"
manager="plone.app.layout.viewlets.interfaces.IAboveContentBody"
class="other.product.ViewletClass"
template="browser/copy_of_product_viewlet.pt"
layer="my.site.interfaces.ISiteLayerMarker"
permission="zope2.View"
/>
However, it doesn't seem to replace the one provided by the product (I'm not sure how to refer to the template in the product from the site package override, so made a local copy).
Use a convenient configure.zcml instead of overrides.zcml and add the layer-attribute to bind the viewlet to your product's interface.
See also:
http://developer.plone.org/views/more_view_examples.html

how to make Plone Dexterity container look like Archetypes folder

I've created a Dexterity product that includes container and non-container Dexterity content types. Having discovered collective.documentviewer (yay! thanks! huzzah!), I'd like to use its dvpdf-group-view, but that is registered in ZCML as being for Folders, and my Dexterity containers don't qualify. I've looked through the web interfaces available on my container type, added SiteRoot, and that enabled the view to be applied, but is also completely wrong.
I'm confident there's a right way to do this, and I'm pretty sure it's central to the whole adapter/interface mechanism, but I just can't find it in any of the books.
Anyone care to try an explanation? First, the line or two that would enable a Dexterity container to pretend it's also a Folder; second, how to change the default view of a single instance of a Dexterity type so that it presents a foreign component's view?
Thanks.
1. Register the view for dexterity containers too
The view is registered for the Archetypes folder interface (Products.CMFCore.interfaces._content.IFolderish), but your dexterity container does not provide this interface (but plone.dexterity.interfaces.IDexterityContainer).
The reason may be that the product and/or the view is not compatible with dexterity.
Anway, you can try it out yourself by registering the view also for the the IDexterityContainer interface by putting a little ZCML in the configure.zcml in your package (see also the Creating a package section of the Dexterity Developer Manual):
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<configure package="collective.documentviewer">
<browser:page
name="dvpdf-group-view"
for="plone.dexterity.interfaces.IDexterityContainer"
class=".views.GroupView"
template="templates/group-view.pt"
permission="zope2.View"
layer=".interfaces.ILayer" />
</configure>
</configure>
The <browser:page> is copied from the collective.documentviewer configure.zcml but I've changed the interface for= to the dexterity container interface, so that the view also works for dexterity containers.
The inner <configure package="collective.documentviewer"> tells the ZCML parser that the configuration should be applied as if the configure.zcml would be directly in collective.documentviewer - this allows you for example to use the original template (otherwise you would have to copy it or do some nasty things).
I did not test it myself: it may still be that the view needs an archetypes container and does not work with a dexterity container. It may also be that you have to register more components from the documentviewer for dexterity containers (maybe the menus? take a look at what is registered in the original configure.zcml.
If everything works well you should consider doing the changes in collective.documentviewer on github directly and make a pull-request to the author (be aware that dexterity is not plone-core yet). But first ask if and how you should do it :-)
2. Changing the default view
With plone it is possible to define multiple views for a specific type. The view can then be selected in the display menu per instance of this type. If you open up http://localhost:8080/Plone/portal_types/manage_main and click on your type, there is a field Available view methods, where you can add the view-name (dvpdf-group-view) on a seperate line.
After you create a new object of your type or visit an existing one, you have a "Display"-menu which should list the view. Select it and this object now has this view as default.
(If you want to make the view not selectable on other objects of this type you could just remove it from the type configuration so that it is not selectable anymore - the existing configuration of your object will stay).

How to override Plone's display menu for special case content?

To get a one-off view on a Plone folder I do something like this (not all code shown):
In configure.zcml:
<!-- Marker interface. Set this on the folder through the ZMI
interfaces tab.
-->
<interface interface=".interfaces.IMySpecialFolder" />
In browser/configure.zcml:
<!-- Special case view. Set as the folder's view through the ZMI
properties tab (layout property).
-->
<browser:page
for="..interfaces.IMySpecialFolder"
name="special"
template="special.pt"
permission="zope2.View"
/>
This works great, but I would like to control the folder's display menu to list only my special case view. I can add it, and it shows up only on my marked folder, but I have to change the site-wide ATFolder FTI.
In browser/configure.zcml:
<include package="plone.app.contentmenu" />
<browser:menuItem
for="..interfaces.IMySpecialFolder"
menu="plone_displayviews"
title="Special view"
action="##special"
description="Special case folder view"
/>
In profiles/default/types/Folder.xml:
<?xml version="1.0"?>
<object name="Folder">
<property name="view_methods" purge="False">
<element value="special"/>
</property>
</object>
Of course I cannot remove the existing available view methods without affecting every folder on the site.
Is there a way to do this one-off display menu tweaking without changing a content type's FTI?
Actually, it seems like this problem has been tackled before. p4a.z2utils patches CMFDynamicViewFTI to get the list of available views from an IDynamicallyViewable adapter lookup. (dateable.chronos uses this mechanism for its folder calendar views). So my question becomes:
Is there a way to do this one-off display menu tweaking without changing a content type's FTI and without patching Plone?
The plone display menu builder uses ISelectableBrowserDefault to get available options in the Display menu (see
http://dev.plone.org/plone/browser/plone.app.contentmenu/trunk/plone/app/contentmenu/menu.py#L220)
So I think (but I haven't tried this) that if you define an adapter for a more specific interface (in your case IMySpecialFolder) that provides the Products.CMFDynamicViewFTI.interface.ISelectableBrowserDefault it should work.
The adapter should have the methods required by plone.app.contentmenu.menu.DisplayMenu above.
Answering my own question, I've realised that the most straightforward way to achieve one-off folder views is to follow the pattern Plone itself applies in the Members folder: a PythonScript index_html that calls the custom view, e.g.
member_search=context.restrictedTraverse('member_search_form')
return member_search()
Products.CMFPlone illustrates how to setup such a PythonScript with a GenericSetup import handler.
In retrospect I realise I didn't need the marker interface in my question scenario. It's not necessary here in the answer either.
Note that this solution doesn't result in "the folder's display menu listing only my special case view" as I asked, but does away with the display menu altogether. I'm fine with that.
One way you could have solved it is using traversalhook to register menu items, or in this case, unregister menu items, or register menu items with conditions that make them not appear. With the traversal hook you can use a marker interface to make it just happen in a certain folder, subsection or page.
You can see where we implemented similar code here
https://github.com/collective/collective.listingviews/blob/master/src/collective/listingviews/browser/views/controlpanel.py#L105
In this case we just wanted to register new display menu items dynamically based on control panel configuration.

How can I add a classic portlet at the root of the portal when my product is installed?

What is the simplest way to do this? I added it in the portlets.xml file in profiles/default. It is now available in the "Add portlet" dropdown when I go to ##manage-portlets. But I need it automatically created.
Is it possible to explicitly specify the set of portlets I want on the right and left columns inside my profiles/default?
You can register your classic portlet trough the portlets.Classic portlet, configured with a template and macro name, using an assignment element in your portlets.xml file:
<assignment
manager="plone.rightcolumn"
category="context"
key="/"
type="portlets.Classic"
name="my-classic-portlet"
visible="1">
<property name="template">templatename</property>
<property name="macro">macroname-found-in-template</property>
</assignment>
See the Portlets section of the GenericSetup manual on Plone.org or the original PLIP for details on Portlet assignments and GenericSetup.
The properties match the portlet dataprovider interface, see the Classic Portlet source code for the interface definition for the Classic Portlet.
The portlets.xml file does a few different things and there's a difference between registering a kind of portlet that can be added and actually adding a portlet, both of which can be done in portlets.xml. You need to use an "assignment" element to add a portlet:
<assignment
manager="plone.rightcolumn"
category="context"
key="/plone"
type="plone.portlet.static.Static"
name="foo-portlet">
<property name="header">Foo Portlet Title</property>
<property name="text">Foo portlet contents...</property>
</assignment>
For a not experienced product developer (even the others too) the easiest way to achieve this kind of automation is:
do manual configuration o
assignment like a any other common
plone user/administrator, going in
the portal's root and adding the
portlets you want.
go in zmi -> portal_setup -> export
tab
select portlet step and export it
use portlets.xml in the tar.gz just
got.
this xml contains all what you need: registrations and assignments... actually, even a little more stuff so may be a good thing to make a clean of what unneeded in it.

Resources