Change icon size in Plone

For a client we had to customize default Plone icon size. The Zope Component Architecture allowed us to do it very easily.

This is not a howto: it is a "note to self" that might be useful to others. Find good documentation about Plone on Plone.org.

There is a related (minimal) egg here.

Plone is great, but customers always want custom-looking sites.

Icons in the navigation portlet can be customized ttw or in a product, because they come from the plone_images skin layer.

But they will always be 16 pixels x 16 pixels images.

If you look at file browser/ploneview.py of the CMFPlone package line 407 reads:

icon = getMultiAdapter((context, self.request, item), IContentIcon)
context here is the object we are viewing, while item

is the one we want the icon for.

So this code asks the ZCA

to find  the right adapter that will provide the interface IContentIcon for our context, request and object.

There are a five adapters registered in the configure.zcml

file in the icons directory of the plone.app.layout package.

They are (leading dots stand for "here", i.e. plone.app.layout.icons):

  • .icons.CatalogBrainContentIcon
  • .icons.CMFContentIcon
  • .icons.FTIContentIcon
  • .icons.PloneSiteContentIcon
  • .icons.DefaultContentIcon

We will override DefaultContentIcon and CatalogBrainContentIcon, for two reasons:

  1. It seems to work for our task.
  2. We don't know where and how other adapters come to effect (just guess that FTIContentIcon has something to do with add menus).

We build custom versions of them in browser/icon.py:

from zope.interface import implements
from Acquisition import aq_inner
from Products.CMFCore.utils  import getToolByName
from plone.app.layout.icons.interfaces import IContentIcon
from plone.app.layout.icons.icons import BaseIcon
from plone.app.layout.icons.icons import CatalogBrainContentIcon
from plone.app.layout.icons.icons import DefaultContentIcon

class wrappedIconMixin:
    width  = 64
    height = 64

class BigContentIcon(wrappedIconMixin,DefaultContentIcon):
    """
    """
    implements(IContentIcon)
    def __init__(self, context, request, obj):
        self.context = context
        self.portal_url = getToolByName(aq_inner(context), 'portal_url')()
        self.obj = obj


class CatalogBrainBigContentIcon(wrappedIconMixin,CatalogBrainContentIcon):
    """ Adapts a brain to IContentIcon
        Overrides plone.app.layout.icons.icons.CatalogBrainContentIcon
        to set with and height = 64
    """

To make things smarter, we could for example use a @property method and return the real width and height of the image object raising from the skin traversal.

TODO: how do we get that object in this context? Or it would be better to implement icon overriding per-object (as you can just paste icons in Mac os x finder file info window) and store the icon somewhere (annotation? local utility?).
Alternative icon sets for Plone would be very nice. I'll Have a look at oxygen or similar projects.

To register an adapter that will be active only when our product is installed we need plone.browserlayer (as explained on Plone.org documentation).

This will allow us to define a custom interface that will be applied to all  requests to Plone sites where this product is installed.

we define an empty (marker) interface in browser/interfaces.py

And we register it in the genericsetup profile with the file profiles/default/browserlayer.xml:

<layers>
  <layer name="gropen.plonebigicons" 
  interface="gropen.plonebigicons.browser.interfaces.bigIconLayer" />
</layers>

So in the line from ploneview.py:

icon = getMultiAdapter((context, self.request, item), IContentIcon)

self.request is marked (if this product is installed) with the

gropen.plonebigicons.browser.interfaces.bigIconLayer marker interface.

We need to register an adapter more specific than the one shipped with the default Plone.

Using our marker interface instead of zope.publisher.interfaces.browser.IBrowserRequest is the right thing to make sure we don't mess up with sites where this product is available but not installed.

So our browser/configure.zcml will look like:

  <configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:browser="http://namespaces.zope.org/browser"
    xmlns:plone="http://namespaces.plone.org/plone"
    i18n_domain="gropen.plonebigicons">
  <adapter for="*
                .interfaces.bigIconLayer
                *"
           factory=".icon.BigContentIcon"
           provides="plone.app.layout.icons.interfaces.IContentIcon" />
  <adapter for="*
                .interfaces.bigIconLayer
                Products.ZCatalog.CatalogBrains.AbstractCatalogBrain"
           factory=".icon.CatalogBrainBigContentIcon"
           provides="plone.app.layout.icons.interfaces.IContentIcon" />
</configure>

 Don't forget Extensions/Install.py and the setuptools dependency as suggested on "customization for developers" on Plone.org

Here we registered an <adapter /> zcml directive.

If we were to customize a <browser:page /> directive we would have used the layer attribute with our marker interface (see Plone.org customization for developers):

    <browser:page
        for="*"
        class="some_class"
        name="a_name"
        template="a_template.pt"
        layer=".interfaces.bigIconLayer"
        permission="some_permission" />

 

 
dicembre 2017 »
dicembre
lumamegivesado
123
45678910
11121314151617
18192021222324
25262728293031