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