1 /*
   2  * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing.table;
  27 
  28 import javax.swing.*;
  29 import javax.swing.border.*;
  30 
  31 import java.awt.Component;
  32 import java.awt.Color;
  33 import java.awt.Rectangle;
  34 
  35 import java.io.Serializable;
  36 import sun.swing.DefaultLookup;
  37 
  38 
  39 /**
  40  * The standard class for rendering (displaying) individual cells
  41  * in a <code>JTable</code>.
  42  * <p>
  43  *
  44  * <strong><a id="override">Implementation Note:</a></strong>
  45  * This class inherits from <code>JLabel</code>, a standard component class.
  46  * However <code>JTable</code> employs a unique mechanism for rendering
  47  * its cells and therefore requires some slightly modified behavior
  48  * from its cell renderer.
  49  * The table class defines a single cell renderer and uses it as a
  50  * as a rubber-stamp for rendering all cells in the table;
  51  * it renders the first cell,
  52  * changes the contents of that cell renderer,
  53  * shifts the origin to the new location, re-draws it, and so on.
  54  * The standard <code>JLabel</code> component was not
  55  * designed to be used this way and we want to avoid
  56  * triggering a <code>revalidate</code> each time the
  57  * cell is drawn. This would greatly decrease performance because the
  58  * <code>revalidate</code> message would be
  59  * passed up the hierarchy of the container to determine whether any other
  60  * components would be affected.
  61  * As the renderer is only parented for the lifetime of a painting operation
  62  * we similarly want to avoid the overhead associated with walking the
  63  * hierarchy for painting operations.
  64  * So this class
  65  * overrides the <code>validate</code>, <code>invalidate</code>,
  66  * <code>revalidate</code>, <code>repaint</code>, and
  67  * <code>firePropertyChange</code> methods to be
  68  * no-ops and override the <code>isOpaque</code> method solely to improve
  69  * performance.  If you write your own renderer,
  70  * please keep this performance consideration in mind.
  71  * <p>
  72  *
  73  * <strong>Warning:</strong>
  74  * Serialized objects of this class will not be compatible with
  75  * future Swing releases. The current serialization support is
  76  * appropriate for short term storage or RMI between applications running
  77  * the same version of Swing.  As of 1.4, support for long term storage
  78  * of all JavaBeans&trade;
  79  * has been added to the <code>java.beans</code> package.
  80  * Please see {@link java.beans.XMLEncoder}.
  81  *
  82  * @author Philip Milne
  83  * @see JTable
  84  */
  85 @SuppressWarnings("serial") // Same-version serialization only
  86 public class DefaultTableCellRenderer extends JLabel
  87     implements TableCellRenderer, Serializable
  88 {
  89 
  90    /**
  91     * An empty <code>Border</code>. This field might not be used. To change the
  92     * <code>Border</code> used by this renderer override the
  93     * <code>getTableCellRendererComponent</code> method and set the border
  94     * of the returned component directly.
  95     */
  96     private static final Border SAFE_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
  97     private static final Border DEFAULT_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
  98     /**
  99      * A border without focus.
 100      */
 101     protected static Border noFocusBorder = DEFAULT_NO_FOCUS_BORDER;
 102 
 103     // We need a place to store the color the JLabel should be returned
 104     // to after its foreground and background colors have been set
 105     // to the selection background color.
 106     // These ivars will be made protected when their names are finalized.
 107     private Color unselectedForeground;
 108     private Color unselectedBackground;
 109 
 110     /**
 111      * Creates a default table cell renderer.
 112      */
 113     public DefaultTableCellRenderer() {
 114         super();
 115         setOpaque(true);
 116         setBorder(getNoFocusBorder());
 117         setName("Table.cellRenderer");
 118     }
 119 
 120     private Border getNoFocusBorder() {
 121         Border border = DefaultLookup.getBorder(this, ui, "Table.cellNoFocusBorder");
 122         if (System.getSecurityManager() != null) {
 123             if (border != null) return border;
 124             return SAFE_NO_FOCUS_BORDER;
 125         } else if (border != null) {
 126             if (noFocusBorder == null || noFocusBorder == DEFAULT_NO_FOCUS_BORDER) {
 127                 return border;
 128             }
 129         }
 130         return noFocusBorder;
 131     }
 132 
 133     /**
 134      * Overrides <code>JComponent.setForeground</code> to assign
 135      * the unselected-foreground color to the specified color.
 136      *
 137      * @param c set the foreground color to this value
 138      */
 139     public void setForeground(Color c) {
 140         super.setForeground(c);
 141         unselectedForeground = c;
 142     }
 143 
 144     /**
 145      * Overrides <code>JComponent.setBackground</code> to assign
 146      * the unselected-background color to the specified color.
 147      *
 148      * @param c set the background color to this value
 149      */
 150     public void setBackground(Color c) {
 151         super.setBackground(c);
 152         unselectedBackground = c;
 153     }
 154 
 155     /**
 156      * Notification from the <code>UIManager</code> that the look and feel
 157      * [L&amp;F] has changed.
 158      * Replaces the current UI object with the latest version from the
 159      * <code>UIManager</code>.
 160      *
 161      * @see JComponent#updateUI
 162      */
 163     public void updateUI() {
 164         super.updateUI();
 165         setForeground(null);
 166         setBackground(null);
 167     }
 168 
 169     // implements javax.swing.table.TableCellRenderer
 170     /**
 171      *
 172      * Returns the default table cell renderer.
 173      * <p>
 174      * During a printing operation, this method will be called with
 175      * <code>isSelected</code> and <code>hasFocus</code> values of
 176      * <code>false</code> to prevent selection and focus from appearing
 177      * in the printed output. To do other customization based on whether
 178      * or not the table is being printed, check the return value from
 179      * {@link javax.swing.JComponent#isPaintingForPrint()}.
 180      *
 181      * @param table  the <code>JTable</code>
 182      * @param value  the value to assign to the cell at
 183      *                  <code>[row, column]</code>
 184      * @param isSelected true if cell is selected
 185      * @param hasFocus true if cell has focus
 186      * @param row  the row of the cell to render
 187      * @param column the column of the cell to render
 188      * @return the default table cell renderer
 189      * @see javax.swing.JComponent#isPaintingForPrint()
 190      */
 191     public Component getTableCellRendererComponent(JTable table, Object value,
 192                           boolean isSelected, boolean hasFocus, int row, int column) {
 193         if (table == null) {
 194             return this;
 195         }
 196 
 197         Color fg = null;
 198         Color bg = null;
 199 
 200         JTable.DropLocation dropLocation = table.getDropLocation();
 201         if (dropLocation != null
 202                 && !dropLocation.isInsertRow()
 203                 && !dropLocation.isInsertColumn()
 204                 && dropLocation.getRow() == row
 205                 && dropLocation.getColumn() == column) {
 206 
 207             fg = DefaultLookup.getColor(this, ui, "Table.dropCellForeground");
 208             bg = DefaultLookup.getColor(this, ui, "Table.dropCellBackground");
 209 
 210             isSelected = true;
 211         }
 212 
 213         if (isSelected) {
 214             super.setForeground(fg == null ? table.getSelectionForeground()
 215                                            : fg);
 216             super.setBackground(bg == null ? table.getSelectionBackground()
 217                                            : bg);
 218         } else {
 219             Color background = unselectedBackground != null
 220                                     ? unselectedBackground
 221                                     : table.getBackground();
 222             if (background == null || background instanceof javax.swing.plaf.UIResource) {
 223                 Color alternateColor = DefaultLookup.getColor(this, ui, "Table.alternateRowColor");
 224                 if (alternateColor != null && row % 2 != 0) {
 225                     background = alternateColor;
 226                 }
 227             }
 228             super.setForeground(unselectedForeground != null
 229                                     ? unselectedForeground
 230                                     : table.getForeground());
 231             super.setBackground(background);
 232         }
 233 
 234         setFont(table.getFont());
 235 
 236         if (hasFocus) {
 237             Border border = null;
 238             if (isSelected) {
 239                 border = DefaultLookup.getBorder(this, ui, "Table.focusSelectedCellHighlightBorder");
 240             }
 241             if (border == null) {
 242                 border = DefaultLookup.getBorder(this, ui, "Table.focusCellHighlightBorder");
 243             }
 244             setBorder(border);
 245 
 246             if (!isSelected && table.isCellEditable(row, column)) {
 247                 Color col;
 248                 col = DefaultLookup.getColor(this, ui, "Table.focusCellForeground");
 249                 if (col != null) {
 250                     super.setForeground(col);
 251                 }
 252                 col = DefaultLookup.getColor(this, ui, "Table.focusCellBackground");
 253                 if (col != null) {
 254                     super.setBackground(col);
 255                 }
 256             }
 257         } else {
 258             setBorder(getNoFocusBorder());
 259         }
 260 
 261         setValue(value);
 262 
 263         return this;
 264     }
 265 
 266     /*
 267      * The following methods are overridden as a performance measure to
 268      * to prune code-paths are often called in the case of renders
 269      * but which we know are unnecessary.  Great care should be taken
 270      * when writing your own renderer to weigh the benefits and
 271      * drawbacks of overriding methods like these.
 272      */
 273 
 274     /**
 275      * Overridden for performance reasons.
 276      * See the <a href="#override">Implementation Note</a>
 277      * for more information.
 278      */
 279     public boolean isOpaque() {
 280         Color back = getBackground();
 281         Component p = getParent();
 282         if (p != null) {
 283             p = p.getParent();
 284         }
 285 
 286         // p should now be the JTable.
 287         boolean colorMatch = (back != null) && (p != null) &&
 288             back.equals(p.getBackground()) &&
 289                         p.isOpaque();
 290         return !colorMatch && super.isOpaque();
 291     }
 292 
 293     /**
 294      * Overridden for performance reasons.
 295      * See the <a href="#override">Implementation Note</a>
 296      * for more information.
 297      *
 298      * @since 1.5
 299      */
 300     public void invalidate() {}
 301 
 302     /**
 303      * Overridden for performance reasons.
 304      * See the <a href="#override">Implementation Note</a>
 305      * for more information.
 306      */
 307     public void validate() {}
 308 
 309     /**
 310      * Overridden for performance reasons.
 311      * See the <a href="#override">Implementation Note</a>
 312      * for more information.
 313      */
 314     public void revalidate() {}
 315 
 316     /**
 317      * Overridden for performance reasons.
 318      * See the <a href="#override">Implementation Note</a>
 319      * for more information.
 320      */
 321     public void repaint(long tm, int x, int y, int width, int height) {}
 322 
 323     /**
 324      * Overridden for performance reasons.
 325      * See the <a href="#override">Implementation Note</a>
 326      * for more information.
 327      */
 328     public void repaint(Rectangle r) { }
 329 
 330     /**
 331      * Overridden for performance reasons.
 332      * See the <a href="#override">Implementation Note</a>
 333      * for more information.
 334      *
 335      * @since 1.5
 336      */
 337     public void repaint() {
 338     }
 339 
 340     /**
 341      * Overridden for performance reasons.
 342      * See the <a href="#override">Implementation Note</a>
 343      * for more information.
 344      */
 345     protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
 346         // Strings get interned...
 347         if (propertyName=="text"
 348                 || propertyName == "labelFor"
 349                 || propertyName == "displayedMnemonic"
 350                 || ((propertyName == "font" || propertyName == "foreground")
 351                     && oldValue != newValue
 352                     && getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey) != null)) {
 353 
 354             super.firePropertyChange(propertyName, oldValue, newValue);
 355         }
 356     }
 357 
 358     /**
 359      * Overridden for performance reasons.
 360      * See the <a href="#override">Implementation Note</a>
 361      * for more information.
 362      */
 363     public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { }
 364 
 365 
 366     /**
 367      * Sets the <code>String</code> object for the cell being rendered to
 368      * <code>value</code>.
 369      *
 370      * @param value  the string value for this cell; if value is
 371      *          <code>null</code> it sets the text value to an empty string
 372      * @see JLabel#setText
 373      *
 374      */
 375     protected void setValue(Object value) {
 376         setText((value == null) ? "" : value.toString());
 377     }
 378 
 379 
 380     /**
 381      * A subclass of <code>DefaultTableCellRenderer</code> that
 382      * implements <code>UIResource</code>.
 383      * <code>DefaultTableCellRenderer</code> doesn't implement
 384      * <code>UIResource</code>
 385      * directly so that applications can safely override the
 386      * <code>cellRenderer</code> property with
 387      * <code>DefaultTableCellRenderer</code> subclasses.
 388      * <p>
 389      * <strong>Warning:</strong>
 390      * Serialized objects of this class will not be compatible with
 391      * future Swing releases. The current serialization support is
 392      * appropriate for short term storage or RMI between applications running
 393      * the same version of Swing.  As of 1.4, support for long term storage
 394      * of all JavaBeans&trade;
 395      * has been added to the <code>java.beans</code> package.
 396      * Please see {@link java.beans.XMLEncoder}.
 397      */
 398     @SuppressWarnings("serial") // Same-version serialization only
 399     public static class UIResource extends DefaultTableCellRenderer
 400         implements javax.swing.plaf.UIResource
 401     {
 402     }
 403 
 404 }