001/* 002 * $Id: JRendererLabel.java 3884 2010-11-05 10:39:28Z 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.renderer; 022 023import java.awt.Color; 024import java.awt.Component; 025import java.awt.Graphics; 026import java.awt.Graphics2D; 027import java.awt.Rectangle; 028 029import javax.swing.JLabel; 030import javax.swing.UIManager; 031 032import org.jdesktop.swingx.painter.Painter; 033 034/** 035 * A <code>JLabel</code> optimized for usage in renderers and 036 * with a minimal background painter support. <p> 037 * 038 * <i>Note</i>: the painter support will be switched to painter_work as 039 * soon it enters main. 040 * 041 * The reasoning for the performance-overrides is copied from core: <p> 042 * 043 * The standard <code>JLabel</code> component was not 044 * designed to be used this way and we want to avoid 045 * triggering a <code>revalidate</code> each time the 046 * cell is drawn. This would greatly decrease performance because the 047 * <code>revalidate</code> message would be 048 * passed up the hierarchy of the container to determine whether any other 049 * components would be affected. 050 * As the renderer is only parented for the lifetime of a painting operation 051 * we similarly want to avoid the overhead associated with walking the 052 * hierarchy for painting operations. 053 * So this class 054 * overrides the <code>validate</code>, <code>invalidate</code>, 055 * <code>revalidate</code>, <code>repaint</code>, and 056 * <code>firePropertyChange</code> methods to be 057 * no-ops and override the <code>isOpaque</code> method solely to improve 058 * performance. If you write your own renderer component, 059 * please keep this performance consideration in mind. 060 * <p> 061 * 062 * @author Jeanette Winzenburg 063 */ 064public class JRendererLabel extends JLabel implements PainterAware, IconAware { 065 066 protected Painter painter; 067 068 /** 069 * 070 */ 071 public JRendererLabel() { 072 super(); 073 setOpaque(true); 074 } 075 076 /** 077 * Overridden for performance reasons.<p> 078 * PENDING: Think about Painters and opaqueness? 079 * 080 */ 081 @Override 082 public boolean isOpaque() { 083 Color back = getBackground(); 084 Component p = getParent(); 085 if (p != null) { 086 p = p.getParent(); 087 } 088 // p should now be the JTable. 089 boolean colorMatch = (back != null) && (p != null) && 090 back.equals(p.getBackground()) && 091 p.isOpaque(); 092 return !colorMatch && super.isOpaque(); 093 // PENDING JW: Issue #1188-swingx: problems with background in Synth 094 // basically a core issue - nevertheless, evaluate implications of 095 // a simple straight-forward implemenation - return the property 096 // no tricks 097// return super.isOpaque(); 098 } 099 100 /** 101 * {@inheritDoc} 102 */ 103 public void setPainter(Painter painter) { 104 Painter old = getPainter(); 105 this.painter = painter; 106 firePropertyChange("painter", old, getPainter()); 107 } 108 109 /** 110 * {@inheritDoc} 111 */ 112 public Painter getPainter() { 113 return painter; 114 } 115 /** 116 * {@inheritDoc} <p> 117 * 118 * Overridden to inject Painter's painting. <p> 119 * TODO: cleanup logic - see JRendererCheckBox. 120 * 121 */ 122 @Override 123 protected void paintComponent(Graphics g) { 124 // JW: hack around for #1178-swingx (core issue) 125 // grab painting if Nimbus detected 126 if ((painter != null) || isNimbus()) { 127 // we have a custom (background) painter 128 // try to inject if possible 129 // there's no guarantee - some LFs have their own background 130 // handling elsewhere 131 if (isOpaque()) { 132 // replace the paintComponent completely 133 paintComponentWithPainter((Graphics2D) g); 134 } else { 135 // transparent apply the background painter before calling super 136 paintPainter(g); 137 super.paintComponent(g); 138 } 139 } else { 140 // nothing to worry about - delegate to super 141 super.paintComponent(g); 142 } 143 } 144 145 /** 146 * Hack around Nimbus not respecting background colors if UIResource. 147 * So by-pass ... 148 * 149 * @return 150 */ 151 private boolean isNimbus() { 152 return UIManager.getLookAndFeel().getName().contains("Nimbus"); 153 } 154 155 156 /** 157 * 158 * Hack around AbstractPainter.paint bug which disposes the Graphics. 159 * So here we give it a scratch to paint on. <p> 160 * TODO - remove again, the issue is fixed? 161 * 162 * @param g the graphics to paint on 163 */ 164 private void paintPainter(Graphics g) { 165 if (painter == null) return; 166 // fail fast: we assume that g must not be null 167 // which throws an NPE here instead deeper down the bowels 168 // this differs from corresponding core implementation! 169 Graphics2D scratch = (Graphics2D) g.create(); 170 try { 171 painter.paint(scratch, this, getWidth(), getHeight()); 172 } 173 finally { 174 scratch.dispose(); 175 } 176 } 177 178// public void setStrictWidth(boolean strict) { 179// this.strict = strict; 180// } 181// 182// @Override 183// public Dimension getMaximumSize() { 184// if (strict) { 185// return super.getMaximumSize(); 186// } 187// Dimension max = super.getMaximumSize(); 188// max.width = Integer.MAX_VALUE - 1; 189// return max; 190// } 191 192 /** 193 * PRE: painter != null, isOpaque() 194 * @param g 195 */ 196 protected void paintComponentWithPainter(Graphics2D g) { 197 // 1. be sure to fill the background 198 // 2. paint the painter 199 // by-pass ui.update and hook into ui.paint directly 200 if (ui != null) { 201 // fail fast: we assume that g must not be null 202 // which throws an NPE here instead deeper down the bowels 203 // this differs from corresponding core implementation! 204 Graphics2D scratchGraphics = (Graphics2D) g.create(); 205 try { 206 scratchGraphics.setColor(getBackground()); 207 scratchGraphics.fillRect(0, 0, getWidth(), getHeight()); 208 paintPainter(g); 209 ui.paint(scratchGraphics, this); 210 } 211 finally { 212 scratchGraphics.dispose(); 213 } 214 } 215 } 216 217 218 /** 219 * {@inheritDoc} <p> 220 * 221 * Overridden to not automatically de/register itself from/to the ToolTipManager. 222 * As rendering component it is not considered to be active in any way, so the 223 * manager must not listen. 224 */ 225 @Override 226 public void setToolTipText(String text) { 227 putClientProperty(TOOL_TIP_TEXT_KEY, text); 228 } 229 230 /** 231 * Overridden for performance reasons. 232 * See the <a href="#override">Implementation Note</a> 233 * for more information. 234 * 235 * @since 1.5 236 */ 237 @Override 238 public void invalidate() {} 239 240 /** 241 * Overridden for performance reasons. 242 * See the <a href="#override">Implementation Note</a> 243 * for more information. 244 */ 245 @Override 246 public void validate() {} 247 248 /** 249 * Overridden for performance reasons. 250 * See the <a href="#override">Implementation Note</a> 251 * for more information. 252 */ 253 @Override 254 public void revalidate() {} 255 256 /** 257 * Overridden for performance reasons. 258 * See the <a href="#override">Implementation Note</a> 259 * for more information. 260 */ 261 @Override 262 public void repaint(long tm, int x, int y, int width, int height) {} 263 264 /** 265 * Overridden for performance reasons. 266 * See the <a href="#override">Implementation Note</a> 267 * for more information. 268 */ 269 @Override 270 public void repaint(Rectangle r) { } 271 272 /** 273 * Overridden for performance reasons. 274 * See the <a href="#override">Implementation Note</a> 275 * for more information. 276 * 277 * @since 1.5 278 */ 279 @Override 280 public void repaint() { 281 } 282 283 /** 284 * Overridden for performance reasons. 285 * See the <a href="#override">Implementation Note</a> 286 * for more information. 287 */ 288 @Override 289 protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { 290 // Strings get interned... 291 if ("text".equals(propertyName)) { 292 super.firePropertyChange(propertyName, oldValue, newValue); 293 } 294 } 295 296 /** 297 * Overridden for performance reasons. 298 * See the <a href="#override">Implementation Note</a> 299 * for more information. 300 */ 301 @Override 302 public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { } 303 304 305}