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}