001/* 002 * $Id: TableColumnExt.java 3927 2011-02-22 16:34:11Z kleopatra $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022package org.jdesktop.swingx.table; 023import java.awt.Component; 024import java.beans.PropertyChangeEvent; 025import java.beans.PropertyChangeListener; 026import java.util.Comparator; 027import java.util.Hashtable; 028 029import javax.swing.DefaultCellEditor; 030import javax.swing.JComponent; 031import javax.swing.SwingUtilities; 032import javax.swing.event.ChangeEvent; 033import javax.swing.event.ChangeListener; 034import javax.swing.table.TableCellEditor; 035import javax.swing.table.TableCellRenderer; 036import javax.swing.table.TableColumn; 037 038import org.jdesktop.swingx.decorator.CompoundHighlighter; 039import org.jdesktop.swingx.decorator.Highlighter; 040import org.jdesktop.swingx.plaf.UIDependent; 041import org.jdesktop.swingx.renderer.AbstractRenderer; 042 043/** 044 * <code>TableColumn</code> extension for enhanced view column configuration. 045 * The general drift is to strengthen the TableColumn abstraction as <b>the</b> 046 * place to configure and dynamically update view column properties, covering a 047 * broad range of customization requirements. Using collaborators are expected 048 * to listen to property changes and update themselves accordingly. 049 * <p> 050 * 051 * A functionality enhancement is the notion of column visibility: 052 * <code>TableColumnModelExt</code> manages sets of visible/hidden 053 * <code>TableColumnExt</code>s controlled by the columns' 054 * <code>visible</code> property. Typically, users can toggle column 055 * visibility at runtime, f.i. through a dedicated control in the upper trailing 056 * corner of a <code>JScrollPane</code>. 057 * <p> 058 * 059 * A prominent group of properties allows fine-grained, per-column control of 060 * corresponding Table/-Header features. 061 * 062 * <ul> 063 * <li><b>Sorting</b>: <code>sortable</code> controls whether this column 064 * should be sortable by user's sort gestures; <code>Comparator</code> can 065 * hold a column specific type. 066 * 067 * <li><b>Editing</b>: <code>editable</code> controls whether cells of this 068 * column should be accessible to in-table editing. 069 * 070 * <li><b>Tooltip</b>: <code>toolTipText</code> holds the column tooltip 071 * which is shown when hovering over the column's header. 072 * 073 * <li><b>Highlighter</b>: <code>highlighters</code> holds the column 074 * highlighters; these are applied to the renderer after the table highlighters. 075 * Any modification of the list of contained <code>Highlighter</code>s 076 * (setting them, adding one or removing one) will result in a 077 * {@code PropertyChangeEvent} being fired for "highlighters". State changes on 078 * contained <code>Highlighter</code>s will result in a PropertyChangeEvent 079 * for "highlighterStateChanged". 080 * </ul> 081 * 082 * 083 * Analogous to <code>JComponent</code>, this class supports per-instance 084 * "client" properties. They are meant as a small-scale extension mechanism. 085 * They are similar to regular bean properties in that registered 086 * <code>PropertyChangeListener</code>s are notified about changes. TODO: 087 * example? 088 * <p> 089 * 090 * A <code>TableColumnExt</code> implements UIDependent, that is it takes over 091 * responsibility to update LAF dependent properties of contained elements when 092 * messaged with updateUI. This implementation updates its <code>Highlighter</code>s, 093 * Cell-/HeaderRenderer and CellEditor. <p> 094 * 095 * TODO: explain prototype (sizing, collaborator-used-by ColumnFactory (?)) 096 * <p> 097 * 098 * @author Ramesh Gupta 099 * @author Amy Fowler 100 * @author Jeanette Winzenburg 101 * @author Karl Schaefer 102 * 103 * @see TableColumnModelExt 104 * @see ColumnFactory 105 * @see org.jdesktop.swingx.plaf.UIDependent 106 * @see javax.swing.JComponent#putClientProperty 107 */ 108public class TableColumnExt extends TableColumn implements UIDependent { 109 110 /** visible property. Initialized to <code>true</code>.*/ 111 protected boolean visible = true; 112 /** hideable property. Initialized to <code>true</code>.*/ 113 protected boolean hideable = true; 114 115 /** prototype property. */ 116 protected Object prototypeValue; 117 118 119 /** per-column comparator */ 120 protected Comparator<?> comparator; 121 /** per-column sortable property. Initialized to <code>true</code>. */ 122 protected boolean sortable = true; 123 /** per-column editable property. Initialized to <code>true</code>.*/ 124 protected boolean editable = true; 125 /** per-column tool tip text. */ 126 private String toolTipText; 127 128 /** storage for client properties. */ 129 protected Hashtable<Object, Object> clientProperties; 130 131 /** 132 * The compound highlighter for the column. 133 */ 134 protected CompoundHighlighter compoundHighlighter; 135 136 private ChangeListener highlighterChangeListener; 137 138 private boolean ignoreHighlighterStateChange; 139 140 141 /** 142 * Creates new table view column with a model index = 0. 143 */ 144 public TableColumnExt() { 145 this(0); 146 } 147 148 /** 149 * Creates new table view column with the specified model index. 150 * @param modelIndex index of table model column to which this view column 151 * is bound. 152 */ 153 public TableColumnExt(int modelIndex) { 154 this(modelIndex, 75); // default width taken from javax.swing.table.TableColumn 155 } 156 157 /** 158 * Creates new table view column with the specified model index and column width. 159 * @param modelIndex index of table model column to which this view column 160 * is bound. 161 * @param width pixel width of view column 162 */ 163 public TableColumnExt(int modelIndex, int width) { 164 this(modelIndex, width, null, null); 165 } 166 167 /** 168 * Creates new table view column with the specified model index, column 169 * width, cell renderer and cell editor. 170 * @param modelIndex index of table model column to which this view column 171 * is bound. 172 * @param width pixel width of view column 173 * @param cellRenderer the cell renderer which will render all cells in this 174 * view column 175 * @param cellEditor the cell editor which will edit cells in this view column 176 */ 177 public TableColumnExt(int modelIndex, int width, 178 TableCellRenderer cellRenderer, TableCellEditor cellEditor) { 179 super(modelIndex, width, cellRenderer, cellEditor); 180 } 181 182 /** 183 * Instantiates a new table view column with all properties copied from the 184 * given original. 185 * 186 * @param columnExt the column to copy properties from 187 * @see #copyFrom(TableColumnExt) 188 */ 189 public TableColumnExt(TableColumnExt columnExt) { 190 this(columnExt.getModelIndex(), columnExt.getWidth(), columnExt 191 .getCellRenderer(), columnExt.getCellEditor()); 192 copyFrom(columnExt); 193 } 194 195 196 /** 197 * Sets the <code>Highlighter</code>s to the table, replacing any old settings. 198 * None of the given Highlighters must be null.<p> 199 * 200 * This is a bound property. <p> 201 * 202 * Note: as of version #1.257 the null constraint is enforced strictly. To remove 203 * all highlighters use this method without param. 204 * 205 * @param highlighters zero or more not null highlighters to use for renderer decoration. 206 * @throws NullPointerException if array is null or array contains null values. 207 * 208 * @see #getHighlighters() 209 * @see #addHighlighter(Highlighter) 210 * @see #removeHighlighter(Highlighter) 211 * 212 */ 213 public void setHighlighters(Highlighter... highlighters) { 214 ignoreHighlighterStateChange = true; 215 Highlighter[] old = getHighlighters(); 216 getCompoundHighlighter().setHighlighters(highlighters); 217 firePropertyChange("highlighters", old, getHighlighters()); 218 ignoreHighlighterStateChange = false; 219 } 220 221 /** 222 * Returns the <code>Highlighter</code>s used by this table. 223 * Maybe empty, but guarantees to be never null. 224 * 225 * @return the Highlighters used by this table, guaranteed to never null. 226 * @see #setHighlighters(Highlighter[]) 227 */ 228 public Highlighter[] getHighlighters() { 229 return getCompoundHighlighter().getHighlighters(); 230 } 231 /** 232 * Appends a <code>Highlighter</code> to the end of the list of used 233 * <code>Highlighter</code>s. The argument must not be null. 234 * <p> 235 * 236 * @param highlighter the <code>Highlighter</code> to add, must not be null. 237 * @throws NullPointerException if <code>Highlighter</code> is null. 238 * 239 * @see #removeHighlighter(Highlighter) 240 * @see #setHighlighters(Highlighter[]) 241 */ 242 public void addHighlighter(Highlighter highlighter) { 243 ignoreHighlighterStateChange = true; 244 Highlighter[] old = getHighlighters(); 245 getCompoundHighlighter().addHighlighter(highlighter); 246 firePropertyChange("highlighters", old, getHighlighters()); 247 ignoreHighlighterStateChange = false; 248 } 249 250 /** 251 * Removes the given Highlighter. <p> 252 * 253 * Does nothing if the Highlighter is not contained. 254 * 255 * @param highlighter the Highlighter to remove. 256 * @see #addHighlighter(Highlighter) 257 * @see #setHighlighters(Highlighter...) 258 */ 259 public void removeHighlighter(Highlighter highlighter) { 260 ignoreHighlighterStateChange = true; 261 Highlighter[] old = getHighlighters(); 262 getCompoundHighlighter().removeHighlighter(highlighter); 263 firePropertyChange("highlighters", old, getHighlighters()); 264 ignoreHighlighterStateChange = false; 265 } 266 267 /** 268 * Returns the CompoundHighlighter assigned to the table, null if none. 269 * PENDING: open up for subclasses again?. 270 * 271 * @return the CompoundHighlighter assigned to the table. 272 */ 273 protected CompoundHighlighter getCompoundHighlighter() { 274 if (compoundHighlighter == null) { 275 compoundHighlighter = new CompoundHighlighter(); 276 compoundHighlighter.addChangeListener(getHighlighterChangeListener()); 277 } 278 return compoundHighlighter; 279 } 280 281 /** 282 * Returns the <code>ChangeListener</code> to use with highlighters. Lazily 283 * creates the listener. 284 * 285 * @return the ChangeListener for observing changes of highlighters, 286 * guaranteed to be <code>not-null</code> 287 */ 288 protected ChangeListener getHighlighterChangeListener() { 289 if (highlighterChangeListener == null) { 290 highlighterChangeListener = createHighlighterChangeListener(); 291 } 292 return highlighterChangeListener; 293 } 294 295 /** 296 * Creates and returns the ChangeListener observing Highlighters. 297 * <p> 298 * Here: repaints the table on receiving a stateChanged. 299 * 300 * @return the ChangeListener defining the reaction to changes of 301 * highlighters. 302 */ 303 protected ChangeListener createHighlighterChangeListener() { 304 return new ChangeListener() { 305 @Override 306 public void stateChanged(ChangeEvent e) { 307 if (ignoreHighlighterStateChange) return; 308 firePropertyChange("highlighterStateChanged", false, true); 309 } 310 }; 311 } 312 313 /** 314 * Returns true if the user <i>can</i> resize the TableColumn's width, 315 * false otherwise. This is a usability override: it takes into account 316 * the case where it's principally <i>allowed</i> to resize the column 317 * but not possible because the column has fixed size. 318 * 319 * @return a boolean indicating whether the user can resize this column. 320 */ 321 @Override 322 public boolean getResizable() { 323 // TODO JW: resizable is a bound property, so to be strict 324 // we'll need to override setMin/MaxWidth to fire resizable 325 // property change. 326 return super.getResizable() && (getMinWidth() < getMaxWidth()); 327 } 328 329 /** 330 * Sets the editable property. This property allows to mark all cells in a 331 * column as read-only, independent of the per-cell editability as returned 332 * by the <code>TableModel.isCellEditable</code>. If the cell is 333 * read-only in the model layer, this property will have no effect. 334 * 335 * @param editable boolean indicating whether or not the user may edit cell 336 * values in this view column 337 * @see #isEditable 338 * @see org.jdesktop.swingx.JXTable#isCellEditable(int, int) 339 * @see javax.swing.table.TableModel#isCellEditable 340 */ 341 public void setEditable(boolean editable) { 342 boolean oldEditable = this.editable; 343 this.editable = editable; 344 firePropertyChange("editable", 345 Boolean.valueOf(oldEditable), 346 Boolean.valueOf(editable)); 347 } 348 349 /** 350 * Returns the per-column editable property. 351 * The default is <code>true</code>. 352 * 353 * @return boolean indicating whether or not the user may edit cell 354 * values in this view column 355 * @see #setEditable 356 */ 357 public boolean isEditable() { 358 return editable; 359 } 360 361 /** 362 * Sets the prototypeValue property. The value should be of a type 363 * which corresponds to the column's class as defined by the table model. 364 * If non-null, the JXTable instance will use this property to calculate 365 * and set the initial preferredWidth of the column. Note that this 366 * initial preferredWidth will be overridden if the user resizes columns 367 * directly. 368 * 369 * @param value Object containing the value of the prototype to be used 370 * to calculate the initial preferred width of the column 371 * @see #getPrototypeValue 372 * @see org.jdesktop.swingx.JXTable#getPreferredScrollableViewportSize 373 */ 374 public void setPrototypeValue(Object value) { 375 Object oldPrototypeValue = this.prototypeValue; 376 this.prototypeValue = value; 377 firePropertyChange("prototypeValue", 378 oldPrototypeValue, 379 value); 380 381 } 382 383 /** 384 * Returns the prototypeValue property. 385 * The default is <code>null</code>. 386 * 387 * @return Object containing the value of the prototype to be used 388 * to calculate the initial preferred width of the column 389 * @see #setPrototypeValue 390 */ 391 public Object getPrototypeValue() { 392 return prototypeValue; 393 } 394 395 396 /** 397 * Sets the comparator to use for this column. 398 * <code>JXTable</code> sorting api respects this property by passing it on 399 * to the <code>SortController</code>. 400 * 401 * @param comparator a custom comparator to use in interactive 402 * sorting. 403 * @see #getComparator 404 * @see org.jdesktop.swingx.sort.SortController 405 * @see org.jdesktop.swingx.decorator.SortKey 406 */ 407 public void setComparator(Comparator<?> comparator) { 408 Comparator<?> old = getComparator(); 409 this.comparator = comparator; 410 firePropertyChange("comparator", old, getComparator()); 411 } 412 413 /** 414 * Returns the comparator to use for the column. 415 * The default is <code>null</code>. 416 * 417 * @return <code>Comparator</code> to use for this column 418 * @see #setComparator 419 */ 420 public Comparator<?> getComparator() { 421 return comparator; 422 } 423 424 /** 425 * Sets the sortable property. <code>JXTable</code> sorting api respects this 426 * property by disabling interactive sorting on this column if false. 427 * 428 * @param sortable boolean indicating whether or not this column can 429 * be sorted in the table 430 * @see #isSortable 431 */ 432 public void setSortable(boolean sortable) { 433 boolean old = isSortable(); 434 this.sortable = sortable; 435 firePropertyChange("sortable", old, isSortable()); 436 } 437 438 /** 439 * Returns the sortable property. 440 * The default value is <code>true</code>. 441 * 442 * @return boolean indicating whether this view column is sortable 443 * @see #setSortable 444 */ 445 public boolean isSortable() { 446 return sortable; 447 } 448 449 /** 450 * Registers the text to display in the column's tool tip. 451 * Typically, this is used by <code>JXTableHeader</code> to 452 * display when the mouse cursor lingers over the column's 453 * header cell. 454 * 455 * @param toolTipText text to show. 456 * @see #setToolTipText(String) 457 */ 458 public void setToolTipText(String toolTipText) { 459 String old = getToolTipText(); 460 this.toolTipText = toolTipText; 461 firePropertyChange("toolTipText", old, getToolTipText()); 462 } 463 464 /** 465 * Returns the text of to display in the column's tool tip. 466 * The default is <code>null</code>. 467 * 468 * @return the text of the column ToolTip. 469 * @see #setToolTipText(String) 470 */ 471 public String getToolTipText() { 472 return toolTipText; 473 } 474 475 476 /** 477 * Sets the title of this view column. This is a convenience 478 * wrapper for <code>setHeaderValue</code>. 479 * @param title String containing the title of this view column 480 */ 481 public void setTitle(String title) { 482 setHeaderValue(title); // simple wrapper 483 } 484 485 /** 486 * Convenience method which returns the headerValue property after 487 * converting it to a string. 488 * @return String containing the title of this view column or null if 489 * no headerValue is set. 490 */ 491 public String getTitle() { 492 Object header = getHeaderValue(); 493 return header != null ? header.toString() : null; // simple wrapper 494 } 495 496 /** 497 * Sets the visible property. This property controls whether or not 498 * this view column is currently visible in the table. 499 * 500 * @param visible boolean indicating whether or not this view column is 501 * visible in the table 502 * @see #setVisible 503 */ 504 public void setVisible(boolean visible) { 505 boolean oldVisible = isVisible(); 506 this.visible = visible; 507 firePropertyChange("visible", oldVisible, isVisible()); 508 } 509 510 /** 511 * Returns a boolean indicating whether or not this column is visible. 512 * The bare property value is constrained by this column's hideable setting, 513 * that is a not hideable column is always visible, irrespective of the 514 * property setting. 515 * <p> 516 * The default is <code>true</code>. 517 * 518 * @return boolean indicating whether or not this view column is 519 * visible in the table 520 * @see #setVisible 521 */ 522 public boolean isVisible() { 523 if (!isHideable()) return true; 524 return visible; 525 } 526 527 /** 528 * Sets the hideable property. This property controls whether the column can 529 * be hidden. This is a bound property. If the column's visibilty is affected, 530 * listeners are notified about that change as well.. 531 * <p> 532 * 533 * The default value is true. 534 * 535 * @param hideable 536 */ 537 public void setHideable(boolean hideable) { 538 boolean old = isHideable(); 539 boolean oldVisible = isVisible(); 540 this.hideable = hideable; 541 firePropertyChange("visible", oldVisible, isVisible()); 542 firePropertyChange("hideable", old, isHideable()); 543 } 544 545 /** 546 * Returns the hideable property. 547 * 548 * @return the hideable property. 549 * 550 * @see #setHideable(boolean) 551 */ 552 public boolean isHideable() { 553 return hideable; 554 } 555 556 /** 557 * Sets the client property "key" to <code>value</code>. 558 * If <code>value</code> is <code>null</code> this method will remove the property. 559 * Changes to 560 * client properties are reported with <code>PropertyChange</code> events. 561 * The name of the property (for the sake of PropertyChange events) is 562 * <code>key.toString()</code>. 563 * <p> 564 * The <code>get/putClientProperty</code> methods provide access to a 565 * per-instance hashtable, which is intended for small scale extensions of 566 * TableColumn. 567 * <p> 568 * 569 * @param key Object which is used as key to retrieve value 570 * @param value Object containing value of client property 571 * @throws IllegalArgumentException if key is <code>null</code> 572 * @see #getClientProperty 573 * @see javax.swing.JComponent#putClientProperty 574 */ 575 public void putClientProperty(Object key, Object value) { 576 if (key == null) 577 throw new IllegalArgumentException("null key"); 578 579 if ((value == null) && (getClientProperty(key) == null)) { 580 return; 581 } 582 583 Object old = getClientProperty(key); 584 if (value == null) { 585 getClientProperties().remove(key); 586 } 587 else { 588 getClientProperties().put(key, value); 589 } 590 591 firePropertyChange(key.toString(), old, value); 592 /* Make all fireXXX methods in TableColumn protected instead of private */ 593 } 594 595 /** 596 * Returns the value of the property with the specified key. Only properties 597 * added with <code>putClientProperty</code> will return a non-<code>null</code> 598 * value. 599 * 600 * @param key Object which is used as key to retrieve value 601 * @return Object containing value of client property or <code>null</code> 602 * 603 * @see #putClientProperty 604 */ 605 public Object getClientProperty(Object key) { 606 return ((key == null) || (clientProperties == null)) ? 607 null : clientProperties.get(key); 608 } 609 610 private Hashtable<Object, Object> getClientProperties() { 611 if (clientProperties == null) { 612 clientProperties = new Hashtable<Object, Object>(); 613 } 614 return clientProperties; 615 } 616 617 618 /** 619 * Copies properties from original. Handles all properties except 620 * modelIndex, width, cellRenderer, cellEditor. Called from copy 621 * constructor. 622 * 623 * @param original the tableColumn to copy from 624 * 625 * @see #TableColumnExt(TableColumnExt) 626 */ 627 protected void copyFrom(TableColumnExt original) { 628 setEditable(original.isEditable()); 629 setHeaderValue(original.getHeaderValue()); // no need to copy setTitle(); 630 setToolTipText(original.getToolTipText()); 631 setIdentifier(original.getIdentifier()); 632 setMaxWidth(original.getMaxWidth()); 633 setMinWidth(original.getMinWidth()); 634 setPreferredWidth(original.getPreferredWidth()); 635 setPrototypeValue(original.getPrototypeValue()); 636 // JW: isResizable is overridden to return a calculated property! 637 setResizable(original.isResizable); 638 setVisible(original.isVisible()); 639 setSortable(original.isSortable()); 640 setComparator(original.getComparator()); 641 copyClientPropertiesFrom(original); 642 643 if (original.compoundHighlighter != null) { 644 setHighlighters(original.getHighlighters()); 645 } 646 647 } 648 649 /** 650 * Copies all clientProperties of this <code>TableColumnExt</code> 651 * to the target column. 652 * 653 * @param original the target column. 654 */ 655 protected void copyClientPropertiesFrom(TableColumnExt original) { 656 if (original.clientProperties == null) return; 657 for(Object key: original.clientProperties.keySet()) { 658 putClientProperty(key, original.getClientProperty(key)); 659 } 660 } 661 662 663 /** 664 * Notifies registered <code>PropertyChangeListener</code>s 665 * about property changes. This method must be invoked internally 666 * whe any of the enhanced properties changed. 667 * <p> 668 * Implementation note: needed to replicate super 669 * functionality because super's field <code>propertyChangeSupport</code> 670 * and method <code>fireXX</code> are both private. 671 * 672 * @param propertyName name of changed property 673 * @param oldValue old value of changed property 674 * @param newValue new value of changed property 675 */ 676 protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { 677 if ((oldValue != null && !oldValue.equals(newValue)) || 678 oldValue == null && newValue != null) { 679 PropertyChangeListener pcl[] = getPropertyChangeListeners(); 680 if (pcl != null && pcl.length != 0) { 681 PropertyChangeEvent pce = new PropertyChangeEvent(this, 682 propertyName, 683 oldValue, newValue); 684 685 for (int i = 0; i < pcl.length; i++) { 686 pcl[i].propertyChange(pce); 687 } 688 } 689 } 690 } 691 692//---------------- implement UIDependent 693 694 /** 695 * Update ui of owned ui-dependent parts. This implementation 696 * updates the contained highlighters. 697 * 698 */ 699 @Override 700 public void updateUI() { 701 updateHighlighterUI(); 702 updateRendererUI(getCellRenderer()); 703 updateRendererUI(getHeaderRenderer()); 704 updateEditorUI(getCellEditor()); 705 } 706 707 /** 708 * @param editor 709 * 710 */ 711 private void updateEditorUI(TableCellEditor editor) { 712 if (editor == null) return; 713 // internal knowledge of core table - already updated 714 if ((editor instanceof JComponent) 715 || (editor instanceof DefaultCellEditor)) 716 return; 717 try { 718 Component comp = editor 719 .getTableCellEditorComponent(null, null, false, -1, -1); 720 if (comp != null) { 721 SwingUtilities.updateComponentTreeUI(comp); 722 } 723 } catch (Exception e) { 724 // can't do anything - renderer can't cope with off-range cells 725 } 726 } 727 728 /** 729 * @param tableCellRenderer 730 * 731 */ 732 private void updateRendererUI(TableCellRenderer renderer) { 733 if (renderer == null) return; 734 // internal knowledge of core table - already updated 735 if (renderer instanceof JComponent) { 736 return; 737 } 738 Component comp = null; 739 if (renderer instanceof AbstractRenderer) { 740 comp = ((AbstractRenderer) renderer).getComponentProvider().getRendererComponent(null); 741 } else { 742 try { 743 comp = renderer 744 .getTableCellRendererComponent(null, null, false, false, 745 -1, -1); 746 747 } catch (Exception e) { 748 // can't do anything - renderer can't cope with off-range cells 749 } 750 } 751 if (comp != null) { 752 SwingUtilities.updateComponentTreeUI(comp); 753 } 754 } 755 756 /** 757 * 758 */ 759 private void updateHighlighterUI() { 760 if (compoundHighlighter == null) return; 761 compoundHighlighter.updateUI(); 762 } 763}