1 /*
2  * Copyright (c) 2002, 2014, 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.plaf.synth;
27 
28 import java.awt.Color;
29 import java.awt.Component;
30 import java.awt.Dimension;
31 import java.awt.Graphics;
32 import java.awt.Point;
33 import java.awt.Rectangle;
34 import java.beans.PropertyChangeEvent;
35 import java.beans.PropertyChangeListener;
36 import java.text.DateFormat;
37 import java.text.Format;
38 import java.text.NumberFormat;
39 import java.util.Date;
40 import javax.swing.Icon;
41 import javax.swing.ImageIcon;
42 import javax.swing.JCheckBox;
43 import javax.swing.JComponent;
44 import javax.swing.JLabel;
45 import javax.swing.JTable;
46 import javax.swing.LookAndFeel;
47 import javax.swing.border.Border;
48 import javax.swing.plaf.*;
49 import javax.swing.plaf.basic.BasicTableUI;
50 import javax.swing.table.DefaultTableCellRenderer;
51 import javax.swing.table.JTableHeader;
52 import javax.swing.table.TableCellRenderer;
53 import javax.swing.table.TableColumn;
54 import javax.swing.table.TableColumnModel;
55 
56 /**
57  * Provides the Synth L&F UI delegate for
58  * {@link javax.swing.JTable}.
59  *
60  * @author Philip Milne
61  * @since 1.7
62  */
63 public class SynthTableUI extends BasicTableUI
64                           implements SynthUI, PropertyChangeListener {
65 //
66 // Instance Variables
67 //
68 
69     private SynthStyle style;
70 
71     private boolean useTableColors;
72     private boolean useUIBorder;
73     private Color alternateColor; //the background color to use for cells for alternate cells
74 
75     // TableCellRenderer installed on the JTable at the time we're installed,
76     // cached so that we can reinstall them at uninstallUI time.
77     private TableCellRenderer dateRenderer;
78     private TableCellRenderer numberRenderer;
79     private TableCellRenderer doubleRender;
80     private TableCellRenderer floatRenderer;
81     private TableCellRenderer iconRenderer;
82     private TableCellRenderer imageIconRenderer;
83     private TableCellRenderer booleanRenderer;
84     private TableCellRenderer objectRenderer;
85 
86 //
87 //  The installation/uninstall procedures and support
88 //
89 
90     /**
91      * Creates a new UI object for the given component.
92      *
93      * @param c component to create UI object for
94      * @return the UI object
95      */
createUI(JComponent c)96     public static ComponentUI createUI(JComponent c) {
97         return new SynthTableUI();
98     }
99 
100     /**
101      * Initializes JTable properties, such as font, foreground, and background.
102      * The font, foreground, and background properties are only set if their
103      * current value is either null or a UIResource, other properties are set
104      * if the current value is null.
105      *
106      * @see #installUI
107      */
108     @Override
installDefaults()109     protected void installDefaults() {
110         dateRenderer = installRendererIfPossible(Date.class, null);
111         numberRenderer = installRendererIfPossible(Number.class, null);
112         doubleRender = installRendererIfPossible(Double.class, null);
113         floatRenderer = installRendererIfPossible(Float.class, null);
114         iconRenderer = installRendererIfPossible(Icon.class, null);
115         imageIconRenderer = installRendererIfPossible(ImageIcon.class, null);
116         booleanRenderer = installRendererIfPossible(Boolean.class,
117                                  new SynthBooleanTableCellRenderer());
118         objectRenderer = installRendererIfPossible(Object.class,
119                                         new SynthTableCellRenderer());
120         updateStyle(table);
121     }
122 
installRendererIfPossible(Class<?> objectClass, TableCellRenderer renderer)123     private TableCellRenderer installRendererIfPossible(Class<?> objectClass,
124                                      TableCellRenderer renderer) {
125         TableCellRenderer currentRenderer = table.getDefaultRenderer(
126                                  objectClass);
127         if (currentRenderer instanceof UIResource) {
128             table.setDefaultRenderer(objectClass, renderer);
129         }
130         return currentRenderer;
131     }
132 
updateStyle(JTable c)133     private void updateStyle(JTable c) {
134         SynthContext context = getContext(c, ENABLED);
135         SynthStyle oldStyle = style;
136         style = SynthLookAndFeel.updateStyle(context, this);
137         if (style != oldStyle) {
138             context.setComponentState(ENABLED | SELECTED);
139 
140             Color sbg = table.getSelectionBackground();
141             if (sbg == null || sbg instanceof UIResource) {
142                 table.setSelectionBackground(style.getColor(
143                                         context, ColorType.TEXT_BACKGROUND));
144             }
145 
146             Color sfg = table.getSelectionForeground();
147             if (sfg == null || sfg instanceof UIResource) {
148                 table.setSelectionForeground(style.getColor(
149                                   context, ColorType.TEXT_FOREGROUND));
150             }
151 
152             context.setComponentState(ENABLED);
153 
154             Color gridColor = table.getGridColor();
155             if (gridColor == null || gridColor instanceof UIResource) {
156                 gridColor = (Color)style.get(context, "Table.gridColor");
157                 if (gridColor == null) {
158                     gridColor = style.getColor(context, ColorType.FOREGROUND);
159                 }
160                 table.setGridColor(gridColor == null ? new ColorUIResource(Color.GRAY) : gridColor);
161             }
162 
163             useTableColors = style.getBoolean(context,
164                                   "Table.rendererUseTableColors", true);
165             useUIBorder = style.getBoolean(context,
166                                   "Table.rendererUseUIBorder", true);
167 
168             Object rowHeight = style.get(context, "Table.rowHeight");
169             if (rowHeight != null) {
170                 LookAndFeel.installProperty(table, "rowHeight", rowHeight);
171             }
172             boolean showGrid = style.getBoolean(context, "Table.showGrid", true);
173             if (!showGrid) {
174                 table.setShowGrid(false);
175             }
176             Dimension d = table.getIntercellSpacing();
177 //            if (d == null || d instanceof UIResource) {
178             if (d != null) {
179                 d = (Dimension)style.get(context, "Table.intercellSpacing");
180             }
181             alternateColor = (Color)style.get(context, "Table.alternateRowColor");
182             if (d != null) {
183                 table.setIntercellSpacing(d);
184             }
185 
186 
187             if (oldStyle != null) {
188                 uninstallKeyboardActions();
189                 installKeyboardActions();
190             }
191         }
192     }
193 
194     /**
195      * Attaches listeners to the JTable.
196      */
197     @Override
installListeners()198     protected void installListeners() {
199         super.installListeners();
200         table.addPropertyChangeListener(this);
201     }
202 
203     /**
204      * {@inheritDoc}
205      */
206     @Override
uninstallDefaults()207     protected void uninstallDefaults() {
208         table.setDefaultRenderer(Date.class, dateRenderer);
209         table.setDefaultRenderer(Number.class, numberRenderer);
210         table.setDefaultRenderer(Double.class, doubleRender);
211         table.setDefaultRenderer(Float.class, floatRenderer);
212         table.setDefaultRenderer(Icon.class, iconRenderer);
213         table.setDefaultRenderer(ImageIcon.class, imageIconRenderer);
214         table.setDefaultRenderer(Boolean.class, booleanRenderer);
215         table.setDefaultRenderer(Object.class, objectRenderer);
216 
217         if (table.getTransferHandler() instanceof UIResource) {
218             table.setTransferHandler(null);
219         }
220         SynthContext context = getContext(table, ENABLED);
221         style.uninstallDefaults(context);
222         style = null;
223     }
224 
225     /**
226      * {@inheritDoc}
227      */
228     @Override
uninstallListeners()229     protected void uninstallListeners() {
230         table.removePropertyChangeListener(this);
231         super.uninstallListeners();
232     }
233 
234     //
235     // SynthUI
236     //
237 
238     /**
239      * {@inheritDoc}
240      */
241     @Override
getContext(JComponent c)242     public SynthContext getContext(JComponent c) {
243         return getContext(c, SynthLookAndFeel.getComponentState(c));
244     }
245 
getContext(JComponent c, int state)246     private SynthContext getContext(JComponent c, int state) {
247         return SynthContext.getContext(c, style, state);
248     }
249 
250 //
251 //  Paint methods and support
252 //
253 
254     /**
255      * Notifies this UI delegate to repaint the specified component.
256      * This method paints the component background, then calls
257      * the {@link #paint(SynthContext,Graphics)} method.
258      *
259      * <p>In general, this method does not need to be overridden by subclasses.
260      * All Look and Feel rendering code should reside in the {@code paint} method.
261      *
262      * @param g the {@code Graphics} object used for painting
263      * @param c the component being painted
264      * @see #paint(SynthContext,Graphics)
265      */
266     @Override
update(Graphics g, JComponent c)267     public void update(Graphics g, JComponent c) {
268         SynthContext context = getContext(c);
269 
270         SynthLookAndFeel.update(context, g);
271         context.getPainter().paintTableBackground(context,
272                           g, 0, 0, c.getWidth(), c.getHeight());
273         paint(context, g);
274     }
275 
276     /**
277      * {@inheritDoc}
278      */
279     @Override
paintBorder(SynthContext context, Graphics g, int x, int y, int w, int h)280     public void paintBorder(SynthContext context, Graphics g, int x,
281                             int y, int w, int h) {
282         context.getPainter().paintTableBorder(context, g, x, y, w, h);
283     }
284 
285     /**
286      * Paints the specified component according to the Look and Feel.
287      * <p>This method is not used by Synth Look and Feel.
288      * Painting is handled by the {@link #paint(SynthContext,Graphics)} method.
289      *
290      * @param g the {@code Graphics} object used for painting
291      * @param c the component being painted
292      * @see #paint(SynthContext,Graphics)
293      */
294     @Override
paint(Graphics g, JComponent c)295     public void paint(Graphics g, JComponent c) {
296         SynthContext context = getContext(c);
297 
298         paint(context, g);
299     }
300 
301     /**
302      * Paints the specified component.
303      *
304      * @param context context for the component being painted
305      * @param g the {@code Graphics} object used for painting
306      * @see #update(Graphics,JComponent)
307      */
paint(SynthContext context, Graphics g)308     protected void paint(SynthContext context, Graphics g) {
309         Rectangle clip = g.getClipBounds();
310 
311         Rectangle bounds = table.getBounds();
312         // account for the fact that the graphics has already been translated
313         // into the table's bounds
314         bounds.x = bounds.y = 0;
315 
316         if (table.getRowCount() <= 0 || table.getColumnCount() <= 0 ||
317                 // this check prevents us from painting the entire table
318                 // when the clip doesn't intersect our bounds at all
319                 !bounds.intersects(clip)) {
320 
321             paintDropLines(context, g);
322             return;
323         }
324 
325         boolean ltr = table.getComponentOrientation().isLeftToRight();
326 
327         Point upperLeft = clip.getLocation();
328 
329         Point lowerRight = new Point(clip.x + clip.width - 1,
330                                      clip.y + clip.height - 1);
331 
332         int rMin = table.rowAtPoint(upperLeft);
333         int rMax = table.rowAtPoint(lowerRight);
334         // This should never happen (as long as our bounds intersect the clip,
335         // which is why we bail above if that is the case).
336         if (rMin == -1) {
337             rMin = 0;
338         }
339         // If the table does not have enough rows to fill the view we'll get -1.
340         // (We could also get -1 if our bounds don't intersect the clip,
341         // which is why we bail above if that is the case).
342         // Replace this with the index of the last row.
343         if (rMax == -1) {
344             rMax = table.getRowCount()-1;
345         }
346 
347         int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight);
348         int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft);
349         // This should never happen.
350         if (cMin == -1) {
351             cMin = 0;
352         }
353         // If the table does not have enough columns to fill the view we'll get -1.
354         // Replace this with the index of the last column.
355         if (cMax == -1) {
356             cMax = table.getColumnCount()-1;
357         }
358 
359         // Paint the cells.
360         paintCells(context, g, rMin, rMax, cMin, cMax);
361 
362         // Paint the grid.
363         // it is important to paint the grid after the cells, otherwise the grid will be overpainted
364         // because in Synth cell renderers are likely to be opaque
365         paintGrid(context, g, rMin, rMax, cMin, cMax);
366 
367         paintDropLines(context, g);
368     }
369 
paintDropLines(SynthContext context, Graphics g)370     private void paintDropLines(SynthContext context, Graphics g) {
371         JTable.DropLocation loc = table.getDropLocation();
372         if (loc == null) {
373             return;
374         }
375 
376         Color color = (Color)style.get(context, "Table.dropLineColor");
377         Color shortColor = (Color)style.get(context, "Table.dropLineShortColor");
378         if (color == null && shortColor == null) {
379             return;
380         }
381 
382         Rectangle rect;
383 
384         rect = getHDropLineRect(loc);
385         if (rect != null) {
386             int x = rect.x;
387             int w = rect.width;
388             if (color != null) {
389                 extendRect(rect, true);
390                 g.setColor(color);
391                 g.fillRect(rect.x, rect.y, rect.width, rect.height);
392             }
393             if (!loc.isInsertColumn() && shortColor != null) {
394                 g.setColor(shortColor);
395                 g.fillRect(x, rect.y, w, rect.height);
396             }
397         }
398 
399         rect = getVDropLineRect(loc);
400         if (rect != null) {
401             int y = rect.y;
402             int h = rect.height;
403             if (color != null) {
404                 extendRect(rect, false);
405                 g.setColor(color);
406                 g.fillRect(rect.x, rect.y, rect.width, rect.height);
407             }
408             if (!loc.isInsertRow() && shortColor != null) {
409                 g.setColor(shortColor);
410                 g.fillRect(rect.x, y, rect.width, h);
411             }
412         }
413     }
414 
getHDropLineRect(JTable.DropLocation loc)415     private Rectangle getHDropLineRect(JTable.DropLocation loc) {
416         if (!loc.isInsertRow()) {
417             return null;
418         }
419 
420         int row = loc.getRow();
421         int col = loc.getColumn();
422         if (col >= table.getColumnCount()) {
423             col--;
424         }
425 
426         Rectangle rect = table.getCellRect(row, col, true);
427 
428         if (row >= table.getRowCount()) {
429             row--;
430             Rectangle prevRect = table.getCellRect(row, col, true);
431             rect.y = prevRect.y + prevRect.height;
432         }
433 
434         if (rect.y == 0) {
435             rect.y = -1;
436         } else {
437             rect.y -= 2;
438         }
439 
440         rect.height = 3;
441 
442         return rect;
443     }
444 
getVDropLineRect(JTable.DropLocation loc)445     private Rectangle getVDropLineRect(JTable.DropLocation loc) {
446         if (!loc.isInsertColumn()) {
447             return null;
448         }
449 
450         boolean ltr = table.getComponentOrientation().isLeftToRight();
451         int col = loc.getColumn();
452         Rectangle rect = table.getCellRect(loc.getRow(), col, true);
453 
454         if (col >= table.getColumnCount()) {
455             col--;
456             rect = table.getCellRect(loc.getRow(), col, true);
457             if (ltr) {
458                 rect.x = rect.x + rect.width;
459             }
460         } else if (!ltr) {
461             rect.x = rect.x + rect.width;
462         }
463 
464         if (rect.x == 0) {
465             rect.x = -1;
466         } else {
467             rect.x -= 2;
468         }
469 
470         rect.width = 3;
471 
472         return rect;
473     }
474 
extendRect(Rectangle rect, boolean horizontal)475     private Rectangle extendRect(Rectangle rect, boolean horizontal) {
476         if (rect == null) {
477             return rect;
478         }
479 
480         if (horizontal) {
481             rect.x = 0;
482             rect.width = table.getWidth();
483         } else {
484             rect.y = 0;
485 
486             if (table.getRowCount() != 0) {
487                 Rectangle lastRect = table.getCellRect(table.getRowCount() - 1, 0, true);
488                 rect.height = lastRect.y + lastRect.height;
489             } else {
490                 rect.height = table.getHeight();
491             }
492         }
493 
494         return rect;
495     }
496 
497     /*
498      * Paints the grid lines within <I>aRect</I>, using the grid
499      * color set with <I>setGridColor</I>. Paints vertical lines
500      * if <code>getShowVerticalLines()</code> returns true and paints
501      * horizontal lines if <code>getShowHorizontalLines()</code>
502      * returns true.
503      */
paintGrid(SynthContext context, Graphics g, int rMin, int rMax, int cMin, int cMax)504     private void paintGrid(SynthContext context, Graphics g, int rMin,
505                            int rMax, int cMin, int cMax) {
506         g.setColor(table.getGridColor());
507 
508         Rectangle minCell = table.getCellRect(rMin, cMin, true);
509         Rectangle maxCell = table.getCellRect(rMax, cMax, true);
510         Rectangle damagedArea = minCell.union( maxCell );
511         SynthGraphicsUtils synthG = context.getStyle().getGraphicsUtils(
512                      context);
513 
514         if (table.getShowHorizontalLines()) {
515             int tableWidth = damagedArea.x + damagedArea.width;
516             int y = damagedArea.y;
517             for (int row = rMin; row <= rMax; row++) {
518                 y += table.getRowHeight(row);
519                 synthG.drawLine(context, "Table.grid",
520                                 g, damagedArea.x, y - 1, tableWidth - 1,y - 1);
521             }
522         }
523         if (table.getShowVerticalLines()) {
524             TableColumnModel cm = table.getColumnModel();
525             int tableHeight = damagedArea.y + damagedArea.height;
526             int x;
527             if (table.getComponentOrientation().isLeftToRight()) {
528                 x = damagedArea.x;
529                 for (int column = cMin; column <= cMax; column++) {
530                     int w = cm.getColumn(column).getWidth();
531                     x += w;
532                     synthG.drawLine(context, "Table.grid", g, x - 1, 0,
533                                     x - 1, tableHeight - 1);
534                 }
535             } else {
536                 x = damagedArea.x;
537                 for (int column = cMax; column >= cMin; column--) {
538                     int w = cm.getColumn(column).getWidth();
539                     x += w;
540                     synthG.drawLine(context, "Table.grid", g, x - 1, 0, x - 1,
541                                     tableHeight - 1);
542                 }
543             }
544         }
545     }
546 
viewIndexForColumn(TableColumn aColumn)547     private int viewIndexForColumn(TableColumn aColumn) {
548         TableColumnModel cm = table.getColumnModel();
549         for (int column = 0; column < cm.getColumnCount(); column++) {
550             if (cm.getColumn(column) == aColumn) {
551                 return column;
552             }
553         }
554         return -1;
555     }
556 
paintCells(SynthContext context, Graphics g, int rMin, int rMax, int cMin, int cMax)557     private void paintCells(SynthContext context, Graphics g, int rMin,
558                             int rMax, int cMin, int cMax) {
559         JTableHeader header = table.getTableHeader();
560         TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();
561 
562         TableColumnModel cm = table.getColumnModel();
563         int columnMargin = cm.getColumnMargin();
564 
565         Rectangle cellRect;
566         TableColumn aColumn;
567         int columnWidth;
568         if (table.getComponentOrientation().isLeftToRight()) {
569             for(int row = rMin; row <= rMax; row++) {
570                 cellRect = table.getCellRect(row, cMin, false);
571                 for(int column = cMin; column <= cMax; column++) {
572                     aColumn = cm.getColumn(column);
573                     columnWidth = aColumn.getWidth();
574                     cellRect.width = columnWidth - columnMargin;
575                     if (aColumn != draggedColumn) {
576                         paintCell(context, g, cellRect, row, column);
577                     }
578                     cellRect.x += columnWidth;
579                 }
580             }
581         } else {
582             for(int row = rMin; row <= rMax; row++) {
583                 cellRect = table.getCellRect(row, cMin, false);
584                 aColumn = cm.getColumn(cMin);
585                 if (aColumn != draggedColumn) {
586                     columnWidth = aColumn.getWidth();
587                     cellRect.width = columnWidth - columnMargin;
588                     paintCell(context, g, cellRect, row, cMin);
589                 }
590                 for(int column = cMin+1; column <= cMax; column++) {
591                     aColumn = cm.getColumn(column);
592                     columnWidth = aColumn.getWidth();
593                     cellRect.width = columnWidth - columnMargin;
594                     cellRect.x -= columnWidth;
595                     if (aColumn != draggedColumn) {
596                         paintCell(context, g, cellRect, row, column);
597                     }
598                 }
599             }
600         }
601 
602         // Paint the dragged column if we are dragging.
603         if (draggedColumn != null) {
604             paintDraggedArea(context, g, rMin, rMax, draggedColumn, header.getDraggedDistance());
605         }
606 
607         // Remove any renderers that may be left in the rendererPane.
608         rendererPane.removeAll();
609     }
610 
paintDraggedArea(SynthContext context, Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance)611     private void paintDraggedArea(SynthContext context, Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance) {
612         int draggedColumnIndex = viewIndexForColumn(draggedColumn);
613 
614         Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);
615         Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);
616 
617         Rectangle vacatedColumnRect = minCell.union(maxCell);
618 
619         // Paint a gray well in place of the moving column.
620         g.setColor(table.getParent().getBackground());
621         g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
622                    vacatedColumnRect.width, vacatedColumnRect.height);
623 
624         // Move to the where the cell has been dragged.
625         vacatedColumnRect.x += distance;
626 
627         // Fill the background.
628         g.setColor(context.getStyle().getColor(context, ColorType.BACKGROUND));
629         g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
630                    vacatedColumnRect.width, vacatedColumnRect.height);
631 
632         SynthGraphicsUtils synthG = context.getStyle().getGraphicsUtils(
633                                             context);
634 
635 
636         // Paint the vertical grid lines if necessary.
637         if (table.getShowVerticalLines()) {
638             g.setColor(table.getGridColor());
639             int x1 = vacatedColumnRect.x;
640             int y1 = vacatedColumnRect.y;
641             int x2 = x1 + vacatedColumnRect.width - 1;
642             int y2 = y1 + vacatedColumnRect.height - 1;
643             // Left
644             synthG.drawLine(context, "Table.grid", g, x1-1, y1, x1-1, y2);
645             // Right
646             synthG.drawLine(context, "Table.grid", g, x2, y1, x2, y2);
647         }
648 
649         for(int row = rMin; row <= rMax; row++) {
650             // Render the cell value
651             Rectangle r = table.getCellRect(row, draggedColumnIndex, false);
652             r.x += distance;
653             paintCell(context, g, r, row, draggedColumnIndex);
654 
655             // Paint the (lower) horizontal grid line if necessary.
656             if (table.getShowHorizontalLines()) {
657                 g.setColor(table.getGridColor());
658                 Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);
659                 rcr.x += distance;
660                 int x1 = rcr.x;
661                 int y1 = rcr.y;
662                 int x2 = x1 + rcr.width - 1;
663                 int y2 = y1 + rcr.height - 1;
664                 synthG.drawLine(context, "Table.grid", g, x1, y2, x2, y2);
665             }
666         }
667     }
668 
paintCell(SynthContext context, Graphics g, Rectangle cellRect, int row, int column)669     private void paintCell(SynthContext context, Graphics g,
670             Rectangle cellRect, int row, int column) {
671         if (table.isEditing() && table.getEditingRow()==row &&
672                                  table.getEditingColumn()==column) {
673             Component component = table.getEditorComponent();
674             component.setBounds(cellRect);
675             component.validate();
676         }
677         else {
678             TableCellRenderer renderer = table.getCellRenderer(row, column);
679             Component component = table.prepareRenderer(renderer, row, column);
680             Color b = component.getBackground();
681             if ((b == null || b instanceof UIResource
682                     || component instanceof SynthBooleanTableCellRenderer)
683                     && !table.isCellSelected(row, column)) {
684                 if (alternateColor != null && row % 2 != 0) {
685                     component.setBackground(alternateColor);
686                 }
687             }
688             rendererPane.paintComponent(g, component, table, cellRect.x,
689                     cellRect.y, cellRect.width, cellRect.height, true);
690         }
691     }
692 
693     /**
694      * {@inheritDoc}
695      */
696     @Override
propertyChange(PropertyChangeEvent event)697     public void propertyChange(PropertyChangeEvent event) {
698         if (SynthLookAndFeel.shouldUpdateStyle(event)) {
699             updateStyle((JTable)event.getSource());
700         }
701     }
702 
703     @SuppressWarnings("serial") // Superclass is not serializable across versions
704     private class SynthBooleanTableCellRenderer extends JCheckBox implements
705                       TableCellRenderer {
706         private boolean isRowSelected;
707 
SynthBooleanTableCellRenderer()708         public SynthBooleanTableCellRenderer() {
709             setHorizontalAlignment(JLabel.CENTER);
710             setName("Table.cellRenderer");
711         }
712 
getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)713         public Component getTableCellRendererComponent(
714                             JTable table, Object value, boolean isSelected,
715                             boolean hasFocus, int row, int column) {
716             isRowSelected = isSelected;
717 
718             if (isSelected) {
719                 setForeground(unwrap(table.getSelectionForeground()));
720                 setBackground(unwrap(table.getSelectionBackground()));
721             } else {
722                 setForeground(unwrap(table.getForeground()));
723                 setBackground(unwrap(table.getBackground()));
724             }
725 
726             setSelected((value != null && ((Boolean)value).booleanValue()));
727             return this;
728         }
729 
unwrap(Color c)730         private Color unwrap(Color c) {
731             if (c instanceof UIResource) {
732                 return new Color(c.getRGB());
733             }
734             return c;
735         }
736 
isOpaque()737         public boolean isOpaque() {
738             return isRowSelected ? true : super.isOpaque();
739         }
740     }
741 
742     @SuppressWarnings("serial") // Superclass is not serializable across versions
743     private class SynthTableCellRenderer extends DefaultTableCellRenderer {
744         private Object numberFormat;
745         private Object dateFormat;
746         private boolean opaque;
747 
setOpaque(boolean isOpaque)748         public void setOpaque(boolean isOpaque) {
749             opaque = isOpaque;
750         }
751 
isOpaque()752         public boolean isOpaque() {
753             return opaque;
754         }
755 
getName()756         public String getName() {
757             String name = super.getName();
758             if (name == null) {
759                 return "Table.cellRenderer";
760             }
761             return name;
762         }
763 
setBorder(Border b)764         public void setBorder(Border b) {
765             if (useUIBorder || b instanceof SynthBorder) {
766                 super.setBorder(b);
767             }
768         }
769 
getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)770         public Component getTableCellRendererComponent(
771                   JTable table, Object value, boolean isSelected,
772                   boolean hasFocus, int row, int column) {
773             if (!useTableColors && (isSelected || hasFocus)) {
774                 SynthLookAndFeel.setSelectedUI((SynthLabelUI)SynthLookAndFeel.
775                              getUIOfType(getUI(), SynthLabelUI.class),
776                                    isSelected, hasFocus, table.isEnabled(), false);
777             }
778             else {
779                 SynthLookAndFeel.resetSelectedUI();
780             }
781             super.getTableCellRendererComponent(table, value, isSelected,
782                                                 hasFocus, row, column);
783 
784             setIcon(null);
785             if (table != null) {
786                 configureValue(value, table.getColumnClass(column));
787             }
788             return this;
789         }
790 
configureValue(Object value, Class<?> columnClass)791         private void configureValue(Object value, Class<?> columnClass) {
792             if (columnClass == Object.class || columnClass == null) {
793                 setHorizontalAlignment(JLabel.LEADING);
794             } else if (columnClass == Float.class || columnClass == Double.class) {
795                 if (numberFormat == null) {
796                     numberFormat = NumberFormat.getInstance();
797                 }
798                 setHorizontalAlignment(JLabel.TRAILING);
799                 setText((value == null) ? "" : ((NumberFormat)numberFormat).format(value));
800             }
801             else if (columnClass == Number.class) {
802                 setHorizontalAlignment(JLabel.TRAILING);
803                 // Super will have set value.
804             }
805             else if (columnClass == Icon.class || columnClass == ImageIcon.class) {
806                 setHorizontalAlignment(JLabel.CENTER);
807                 setIcon((value instanceof Icon) ? (Icon)value : null);
808                 setText("");
809             }
810             else if (columnClass == Date.class) {
811                 if (dateFormat == null) {
812                     dateFormat = DateFormat.getDateInstance();
813                 }
814                 setHorizontalAlignment(JLabel.LEADING);
815                 setText((value == null) ? "" : ((Format)dateFormat).format(value));
816             }
817             else {
818                 configureValue(value, columnClass.getSuperclass());
819             }
820         }
821 
paint(Graphics g)822         public void paint(Graphics g) {
823             super.paint(g);
824             SynthLookAndFeel.resetSelectedUI();
825         }
826     }
827 }
828