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
26package javax.swing.table;
27
28import javax.swing.*;
29import javax.swing.border.*;
30
31import java.awt.Component;
32import java.awt.Color;
33import java.awt.Rectangle;
34
35import java.io.Serializable;
36import 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
86public 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}
405