/* * $Id: PainterHighlighter.java 3346 2009-05-25 01:52:13Z kschaefe $ * * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.hdesktop.swingx.decorator; import java.awt.Component; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import org.hdesktop.swingx.painter.AbstractPainter; import org.hdesktop.swingx.painter.Painter; import org.hdesktop.swingx.renderer.PainterAware; /** * Highlighter implementation which uses a Painter to decorate the component. * <p> * * As Painter implementations can be mutable and Highlighters have the * responsibility to notify their own listeners about any changes which might * effect the visuals, this class provides api to install/uninstall a listener * to the painter, as appropriate. It takes care of Painters of type * AbstractHighlighter by registering a PropertyChangeListener. Subclasses might * override to correctly handle different types as well. * <p> * * Subclasses might be implemented to change the Painter during the decoration * process, which must not passed-on to the Highlighter's listeners. The default * routing is controlled by a flag isAdjusting. This is set/reset in this * implementation's highlight method to ease subclass' burden (and to keep * backward compatibility with implementations preceding the introduction of the * painter listener). That is, subclasses are free to change painter properties * during the decoration. * <p> * * As an example, a ValueBasedPainterHighlighter might safely change any painter * property to decorate a component depending on content. * * <pre><code> * @Override * protected Component doHighlight(Component renderer, ComponentAdapter adapter) { * float end = getEndOfGradient((Number) adapter.getValue()); * RelativePainter painter = (RelativePainter) getPainter(); * painter.setXFraction(end); * ((PainterAware) renderer).setPainter(painter); * return renderer; * } * * @Override * protected boolean canHighlight(Component renderer, ComponentAdapter adapter) { * return super.canHighlight(renderer, adapter) && * (adapter.getValue() instanceof Number); * } * </code></pre> * * NOTE: this will change once the Painter api is stable. * * @author Jeanette Winzenburg */ public class PainterHighlighter extends AbstractHighlighter { /** The painter to use for decoration. */ private Painter painter; /** The listener registered with the Painter. */ private PropertyChangeListener painterListener; /** * A flag indicating whether or not changes in the Painter * should be passed-on to the Highlighter's ChangeListeners. */ private boolean isAdjusting; /** * Instantiates a PainterHighlighter with null painter and * default predicate. */ public PainterHighlighter() { this(null, null); } /** * Instantiates a PainterHighlighter with null painter which * uses the given predicate. * * @param predicate the HighlightPredicate which controls the highlight * application. */ public PainterHighlighter(HighlightPredicate predicate) { this(predicate, null); } /** * Instantiates a PainterHighlighter with the given Painter and * default predicate. * * @param painter the painter to use */ public PainterHighlighter(Painter painter) { this(null, painter); } /** * Instantiates a PainterHighlighter with the given painter and * predicate. * @param predicate * @param painter */ public PainterHighlighter(HighlightPredicate predicate, Painter painter) { super(predicate); setPainter(painter); } /** * Returns to Painter used in this Highlighter. * * @return the Painter used in this Highlighter, may be null. */ public Painter getPainter() { return painter; } /** * Sets the Painter to use in this Highlighter, may be null. * Un/installs the listener to changes painter's properties. * * @param painter the Painter to uses for decoration. */ public void setPainter(Painter painter) { if (areEqual(painter, getPainter())) return; uninstallPainterListener(); this.painter = painter; installPainterListener(); fireStateChanged(); } /** * Installs a listener to the painter if appropriate. * This implementation registers its painterListener if * the Painter is of type AbstractPainter. */ protected void installPainterListener() { if (getPainter() instanceof AbstractPainter) { ((AbstractPainter) getPainter()).addPropertyChangeListener(getPainterListener()); } } /** * Uninstalls a listener from the painter if appropriate. * This implementation removes its painterListener if * the Painter is of type AbstractPainter. */ protected void uninstallPainterListener() { if (getPainter() instanceof AbstractPainter) { ((AbstractPainter) getPainter()).removePropertyChangeListener(painterListener); } } /** * Lazyly creates and returns the property change listener used * to listen to changes of the painter. * * @return the property change listener used to listen to changes * of the painter. */ protected final PropertyChangeListener getPainterListener() { if (painterListener == null) { painterListener = createPainterListener(); } return painterListener; } /** * Creates and returns the property change listener used * to listen to changes of the painter. <p> * * This implementation fires a stateChanged on receiving * any propertyChange, if the isAdjusting flag is false. * Otherwise does nothing. * * @return the property change listener used to listen to changes * of the painter. */ protected PropertyChangeListener createPainterListener() { PropertyChangeListener l = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if (isAdjusting) return; fireStateChanged(); } }; return l; } /** * {@inheritDoc} <p> * * Overridden to set/reset the flag indicating whether or not * painter's property changes should be passed on to the * Highlighter's listener. */ @Override public Component highlight(Component component, ComponentAdapter adapter) { isAdjusting = true; Component stamp = super.highlight(component, adapter); isAdjusting = false; return stamp; } /** * {@inheritDoc} * <p> * This implementation sets the painter if it is not null. Does nothing * otherwise. */ @Override protected Component doHighlight(Component component, ComponentAdapter adapter) { ((PainterAware) component).setPainter(painter); return component; } /** * {@inheritDoc} <p> * * Overridden to return false if the Painter is null or the component is not * of type PainterAware. */ @Override protected boolean canHighlight(Component component, ComponentAdapter adapter) { return getPainter() != null && (component instanceof PainterAware); } }