001/* 002 * $Id: PainterHighlighter.java 3927 2011-02-22 16:34:11Z kleopatra $ 003 * 004 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021package org.jdesktop.swingx.decorator; 022 023import java.awt.Component; 024import java.beans.PropertyChangeEvent; 025import java.beans.PropertyChangeListener; 026 027import org.jdesktop.swingx.painter.AbstractPainter; 028import org.jdesktop.swingx.painter.Painter; 029import org.jdesktop.swingx.renderer.PainterAware; 030 031/** 032 * Highlighter implementation which uses a Painter to decorate the component. 033 * <p> 034 * 035 * As Painter implementations can be mutable and Highlighters have the 036 * responsibility to notify their own listeners about any changes which might 037 * effect the visuals, this class provides api to install/uninstall a listener 038 * to the painter, as appropriate. It takes care of Painters of type 039 * AbstractHighlighter by registering a PropertyChangeListener. Subclasses might 040 * override to correctly handle different types as well. 041 * <p> 042 * 043 * Subclasses might be implemented to change the Painter during the decoration 044 * process, which must not passed-on to the Highlighter's listeners. The default 045 * routing is controlled by a flag isAdjusting. This is set/reset in this 046 * implementation's highlight method to ease subclass' burden (and to keep 047 * backward compatibility with implementations preceding the introduction of the 048 * painter listener). That is, subclasses are free to change painter properties 049 * during the decoration. 050 * <p> 051 * 052 * As an example, a ValueBasedPainterHighlighter might safely change any painter 053 * property to decorate a component depending on content. 054 * 055 * <pre><code> 056 * @Override 057 * protected Component doHighlight(Component renderer, ComponentAdapter adapter) { 058 * float end = getEndOfGradient((Number) adapter.getValue()); 059 * RelativePainter painter = (RelativePainter) getPainter(); 060 * painter.setXFraction(end); 061 * ((PainterAware) renderer).setPainter(painter); 062 * return renderer; 063 * } 064 * 065 * @Override 066 * protected boolean canHighlight(Component renderer, ComponentAdapter adapter) { 067 * return super.canHighlight(renderer, adapter) && 068 * (adapter.getValue() instanceof Number); 069 * } 070 * </code></pre> 071 * 072 * NOTE: this will change once the Painter api is stable. 073 * 074 * @author Jeanette Winzenburg 075 */ 076public class PainterHighlighter extends AbstractHighlighter { 077 078 /** The painter to use for decoration. */ 079 private Painter painter; 080 /** The listener registered with the Painter. */ 081 private PropertyChangeListener painterListener; 082 /** 083 * A flag indicating whether or not changes in the Painter 084 * should be passed-on to the Highlighter's ChangeListeners. 085 */ 086 private boolean isAdjusting; 087 088 /** 089 * Instantiates a PainterHighlighter with null painter and 090 * default predicate. 091 */ 092 public PainterHighlighter() { 093 this(null, null); 094 } 095 /** 096 * Instantiates a PainterHighlighter with null painter which 097 * uses the given predicate. 098 * 099 * @param predicate the HighlightPredicate which controls the highlight 100 * application. 101 */ 102 public PainterHighlighter(HighlightPredicate predicate) { 103 this(predicate, null); 104 } 105 106 /** 107 * Instantiates a PainterHighlighter with the given Painter and 108 * default predicate. 109 * 110 * @param painter the painter to use 111 */ 112 public PainterHighlighter(Painter painter) { 113 this(null, painter); 114 } 115 116 /** 117 * Instantiates a PainterHighlighter with the given painter and 118 * predicate. 119 * @param predicate 120 * @param painter 121 */ 122 public PainterHighlighter(HighlightPredicate predicate, Painter painter) { 123 super(predicate); 124 setPainter(painter); 125 } 126 127 128 129 /** 130 * Returns to Painter used in this Highlighter. 131 * 132 * @return the Painter used in this Highlighter, may be null. 133 */ 134 public Painter getPainter() { 135 return painter; 136 } 137 138 /** 139 * Sets the Painter to use in this Highlighter, may be null. 140 * Un/installs the listener to changes painter's properties. 141 * 142 * @param painter the Painter to uses for decoration. 143 */ 144 public void setPainter(Painter painter) { 145 if (areEqual(painter, getPainter())) return; 146 uninstallPainterListener(); 147 this.painter = painter; 148 installPainterListener(); 149 fireStateChanged(); 150 } 151 152 /** 153 * Installs a listener to the painter if appropriate. 154 * This implementation registers its painterListener if 155 * the Painter is of type AbstractPainter. 156 */ 157 protected void installPainterListener() { 158 if (getPainter() instanceof AbstractPainter) { 159 ((AbstractPainter) getPainter()).addPropertyChangeListener(getPainterListener()); 160 } 161 } 162 163 /** 164 * Uninstalls a listener from the painter if appropriate. 165 * This implementation removes its painterListener if 166 * the Painter is of type AbstractPainter. 167 */ 168 protected void uninstallPainterListener() { 169 if (getPainter() instanceof AbstractPainter) { 170 ((AbstractPainter) getPainter()).removePropertyChangeListener(painterListener); 171 } 172 } 173 174 175 /** 176 * Lazyly creates and returns the property change listener used 177 * to listen to changes of the painter. 178 * 179 * @return the property change listener used to listen to changes 180 * of the painter. 181 */ 182 protected final PropertyChangeListener getPainterListener() { 183 if (painterListener == null) { 184 painterListener = createPainterListener(); 185 } 186 return painterListener; 187 } 188 189 /** 190 * Creates and returns the property change listener used 191 * to listen to changes of the painter. <p> 192 * 193 * This implementation fires a stateChanged on receiving 194 * any propertyChange, if the isAdjusting flag is false. 195 * Otherwise does nothing. 196 * 197 * @return the property change listener used to listen to changes 198 * of the painter. 199 */ 200 protected PropertyChangeListener createPainterListener() { 201 PropertyChangeListener l = new PropertyChangeListener() { 202 203 @Override 204 public void propertyChange(PropertyChangeEvent evt) { 205 if (isAdjusting) return; 206 fireStateChanged(); 207 } 208 209 }; 210 return l; 211 } 212 213 /** 214 * {@inheritDoc} <p> 215 * 216 * Overridden to set/reset the flag indicating whether or not 217 * painter's property changes should be passed on to the 218 * Highlighter's listener. 219 */ 220 @Override 221 public Component highlight(Component component, ComponentAdapter adapter) { 222 isAdjusting = true; 223 Component stamp = super.highlight(component, adapter); 224 isAdjusting = false; 225 return stamp; 226 } 227 228 /** 229 * {@inheritDoc} 230 * <p> 231 * This implementation sets the painter if it is not null. Does nothing 232 * otherwise. 233 */ 234 @Override 235 protected Component doHighlight(Component component, 236 ComponentAdapter adapter) { 237 ((PainterAware) component).setPainter(painter); 238 return component; 239 } 240 241 /** 242 * {@inheritDoc} <p> 243 * 244 * Overridden to return false if the Painter is null or the component is not 245 * of type PainterAware. 246 */ 247 @Override 248 protected boolean canHighlight(Component component, ComponentAdapter adapter) { 249 return getPainter() != null && (component instanceof PainterAware); 250 } 251 252 253}