001: /*
002: * Copyright (c) 2005-2008 Substance Kirill Grouchnikov. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of Substance Kirill Grouchnikov nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030: package org.jvnet.substance;
031:
032: import java.awt.*;
033: import java.text.DateFormat;
034: import java.text.NumberFormat;
035:
036: import javax.swing.*;
037: import javax.swing.border.*;
038: import javax.swing.plaf.TableUI;
039: import javax.swing.table.DefaultTableCellRenderer;
040: import javax.swing.table.TableCellRenderer;
041:
042: import org.jvnet.lafwidget.animation.FadeKind;
043: import org.jvnet.lafwidget.animation.FadeState;
044: import org.jvnet.substance.SubstanceTableUI.TableCellId;
045: import org.jvnet.substance.border.ClassicBorderPainter;
046: import org.jvnet.substance.theme.SubstanceTheme;
047: import org.jvnet.substance.utils.*;
048:
049: /**
050: * Default renderer for table cells.
051: *
052: * @author Kirill Grouchnikov
053: */
054: public class SubstanceDefaultTableCellRenderer extends
055: DefaultTableCellRenderer {
056: /**
057: * Place to store the color the JLabel should be returned to after its
058: * foreground and background colors have been set to the selection
059: * background color.
060: */
061: // private Color unselectedBackground;
062: /**
063: * Indicates whether this renderer is opaque.
064: */
065: private boolean defaultOpacity;
066:
067: /**
068: * Renderer for boolean columns.
069: *
070: * @author Kirill Grouchnikov
071: */
072: public static class BooleanRenderer extends JCheckBox implements
073: TableCellRenderer {
074: /**
075: * Border for cells that do not have focus.
076: */
077: private static final Border noFocusBorder = new EmptyBorder(1,
078: 1, 1, 1);
079:
080: /**
081: * Creates a new renderer for boolean columns.
082: */
083: public BooleanRenderer() {
084: super ();
085: this .setHorizontalAlignment(SwingConstants.CENTER);
086: this .setBorderPainted(true);
087: this .putClientProperty(
088: SubstanceLookAndFeel.BORDER_PAINTER_PROPERTY,
089: new ClassicBorderPainter());
090: }
091:
092: /*
093: * (non-Javadoc)
094: *
095: * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable,
096: * java.lang.Object, boolean, boolean, int, int)
097: */
098: public Component getTableCellRendererComponent(JTable table,
099: Object value, boolean isSelected, boolean hasFocus,
100: int row, int column) {
101: if (isSelected) {
102: this .setForeground(table.getSelectionForeground());
103: // super.setBackground(table.getSelectionBackground());
104: } else {
105: this .setForeground(table.getForeground());
106: }
107: SubstanceCoreUtilities.applyStripedBackground(table, row,
108: this );
109:
110: this .setSelected(((value != null) && ((Boolean) value)
111: .booleanValue()));
112: this .setEnabled(table.isEnabled());
113:
114: TableUI tableUI = table.getUI();
115: if (tableUI instanceof SubstanceTableUI) {
116: SubstanceTableUI ui = (SubstanceTableUI) tableUI;
117:
118: // Recompute the focus indication to prevent flicker - JTable
119: // registers a listener on selection changes and repaints the
120: // relevant cell before our listener (in TableUI) gets the
121: // chance to start the fade sequence. The result is that the
122: // first frame uses full opacity, and the next frame starts the
123: // fade sequence. So, we use the UI delegate to compute the
124: // focus indication.
125: hasFocus = ui.isFocusedCell(row, column);
126:
127: TableCellId cellFocusId = new TableCellId(row, column);
128: // set indication to make exact comparison (since
129: // focus can be only on one cell).
130: cellFocusId.setExactComparison(true);
131: FadeState focusState = SubstanceFadeUtilities
132: .getFadeState(table, cellFocusId,
133: FadeKind.FOCUS);
134: if (hasFocus || (focusState != null)) {
135: SubstanceBorder border = new SubstanceBorder();
136: if (focusState != null) {
137: border
138: .setAlpha(focusState.getFadePosition() / 10.0f);
139: }
140: this .setBorder(border);
141: } else {
142: this .setBorder(BooleanRenderer.noFocusBorder);
143: }
144: } else {
145: if (hasFocus) {
146: this
147: .setBorder(UIManager
148: .getBorder("Table.focusCellHighlightBorder"));
149: } else {
150: this .setBorder(BooleanRenderer.noFocusBorder);
151: }
152: }
153:
154: this .setOpaque(!SubstanceCoreUtilities
155: .toBleedWatermark(table));
156:
157: return this ;
158: }
159: }
160:
161: /**
162: * Renderer for icon columns.
163: *
164: * @author Kirill Grouchnikov
165: */
166: public static class IconRenderer extends
167: SubstanceDefaultTableCellRenderer {
168: /**
169: * Creates a new renderer for icon columns.
170: */
171: public IconRenderer() {
172: super ();
173: this .setHorizontalAlignment(SwingConstants.CENTER);
174: }
175:
176: @Override
177: public void setValue(Object value) {
178: this .setIcon((value instanceof Icon) ? (Icon) value : null);
179: this .setText(null);
180: }
181: }
182:
183: /**
184: * Renderer for number columns.
185: *
186: * @author Kirill Grouchnikov
187: */
188: public static class NumberRenderer extends
189: SubstanceDefaultTableCellRenderer {
190: /**
191: * Creates a new renderer for number columns.
192: */
193: public NumberRenderer() {
194: super ();
195: this .setHorizontalAlignment(SwingConstants.RIGHT);
196: }
197: }
198:
199: /**
200: * Renderer for double columns.
201: *
202: * @author Kirill Grouchnikov
203: */
204: public static class DoubleRenderer extends NumberRenderer {
205: /**
206: * Number formatter for this renderer.
207: */
208: NumberFormat formatter;
209:
210: /**
211: * Creates a new renderer for double columns.
212: */
213: public DoubleRenderer() {
214: super ();
215: }
216:
217: @Override
218: public void setValue(Object value) {
219: if (this .formatter == null) {
220: this .formatter = NumberFormat.getInstance();
221: }
222: this .setText((value == null) ? "" : this .formatter
223: .format(value));
224: }
225: }
226:
227: /**
228: * Renderer for date columns.
229: *
230: * @author Kirill Grouchnikov
231: */
232: public static class DateRenderer extends
233: SubstanceDefaultTableCellRenderer {
234: /**
235: * Date formatter for this renderer.
236: */
237: DateFormat formatter;
238:
239: /**
240: * Creates a new renderer for date columns.
241: */
242: public DateRenderer() {
243: super ();
244: }
245:
246: @Override
247: public void setValue(Object value) {
248: if (this .formatter == null) {
249: this .formatter = DateFormat.getDateInstance();
250: }
251: this .setText((value == null) ? "" : this .formatter
252: .format(value));
253: }
254: }
255:
256: /**
257: * Creates a default opaque table cell renderer.
258: */
259: public SubstanceDefaultTableCellRenderer() {
260: this (true);
261: }
262:
263: /**
264: * Creates a default table cell renderer.
265: *
266: * @param defaultOpacity
267: * Renderer opacity indication.
268: * @deprecated This constructore will be removed in version 5.0.
269: */
270: @Deprecated
271: public SubstanceDefaultTableCellRenderer(boolean defaultOpacity) {
272: this .defaultOpacity = defaultOpacity;
273: this .putClientProperty(
274: SubstanceLookAndFeel.BORDER_PAINTER_PROPERTY,
275: new ClassicBorderPainter());
276: }
277:
278: /*
279: * (non-Javadoc)
280: *
281: * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable,
282: * java.lang.Object, boolean, boolean, int, int)
283: */
284: @Override
285: public Component getTableCellRendererComponent(JTable table,
286: Object value, boolean isSelected, boolean hasFocus,
287: int row, int column) {
288: if (!(UIManager.getLookAndFeel() instanceof SubstanceLookAndFeel))
289: return super .getTableCellRendererComponent(table, value,
290: isSelected, hasFocus, row, column);
291:
292: TableUI tableUI = table.getUI();
293: SubstanceTableUI ui = (SubstanceTableUI) tableUI;
294:
295: // Recompute the focus indication to prevent flicker - JTable
296: // registers a listener on selection changes and repaints the
297: // relevant cell before our listener (in TableUI) gets the
298: // chance to start the fade sequence. The result is that the
299: // first frame uses full opacity, and the next frame starts the
300: // fade sequence. So, we use the UI delegate to compute the
301: // focus indication.
302: hasFocus = ui.isFocusedCell(row, column);
303:
304: TableCellId cellId = new TableCellId(row, column);
305: Comparable<?> compId = ui.getId(row, column);
306: ComponentState state = ui.getCellState(cellId);
307: ComponentState prevState = ui.getPrevCellState(cellId);
308: SubstanceTheme theme = SubstanceThemeUtilities.getTheme(table,
309: state);
310: Color color = SubstanceCoreUtilities
311: .getInterpolatedForegroundColor(table, compId, theme,
312: state, prevState, FadeKind.SELECTION,
313: FadeKind.ROLLOVER);
314:
315: // System.out.println("[" + row + "," + column + "] - " +
316: // prevState.name()
317: // + ":" + state.name() + ":" + color);
318:
319: super .setForeground(color);
320:
321: SubstanceCoreUtilities.applyStripedBackground(table, row, this );
322:
323: this .setFont(table.getFont());
324:
325: TableCellId cellFocusId = new TableCellId(row, column);
326: // set indication to make exact comparison (since
327: // focus can be only on one cell).
328: cellFocusId.setExactComparison(true);
329: FadeState focusState = SubstanceFadeUtilities.getFadeState(
330: table, cellFocusId, FadeKind.FOCUS);
331:
332: Insets regInsets = SubstanceSizeUtils
333: .getTableCellRendererInsets(SubstanceSizeUtils
334: .getComponentFontSize(table));
335: if (hasFocus || (focusState != null)) {
336: SubstanceBorder border = new SubstanceBorder(regInsets);
337:
338: // System.out.println("[" + row + ":" + column + "] hasFocus : "
339: // + hasFocus + ", focusState : " + focusState);
340: if (focusState != null) {
341: border.setAlpha(focusState.getFadePosition() / 10.0f);
342: }
343:
344: // special case for tables with no grids
345: if (!table.getShowHorizontalLines()
346: && !table.getShowVerticalLines()) {
347: this .setBorder(new CompoundBorder(new EmptyBorder(0, 0,
348: table.getRowMargin(), table.getColumnModel()
349: .getColumnMargin()), border));
350: } else {
351: this .setBorder(border);
352: }
353: } else {
354: this .setBorder(new EmptyBorder(regInsets.top,
355: regInsets.left, regInsets.bottom, regInsets.right));
356: }
357:
358: this.setValue(value);
359: this.setOpaque(this.defaultOpacity
360: && !SubstanceCoreUtilities.toBleedWatermark(table));
361: this.setEnabled(table.isEnabled());
362: return this;
363: }
364: }
|