All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdesktop.swingx.table.TableColumnExt Maven / Gradle / Ivy

The newest version!
/*
 * $Id: TableColumnExt.java 3691 2010-05-03 18:03:44Z kschaefe $
 *
 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package org.jdesktop.swingx.table;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Comparator;
import java.util.Hashtable;

import javax.swing.DefaultCellEditor;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

import org.jdesktop.swingx.decorator.CompoundHighlighter;
import org.jdesktop.swingx.decorator.Highlighter;
import org.jdesktop.swingx.plaf.UIDependent;
import org.jdesktop.swingx.renderer.AbstractRenderer;

/**
 * TableColumn extension for enhanced view column configuration.
 * The general drift is to strengthen the TableColumn abstraction as the
 * place to configure and dynamically update view column properties, covering a
 * broad range of customization requirements. Using collaborators are expected
 * to listen to property changes and update themselves accordingly.
 * 

* * A functionality enhancement is the notion of column visibility: * TableColumnModelExt manages sets of visible/hidden * TableColumnExts controlled by the columns' * visible property. Typically, users can toggle column * visibility at runtime, f.i. through a dedicated control in the upper trailing * corner of a JScrollPane. *

* * A prominent group of properties allows fine-grained, per-column control of * corresponding Table/-Header features. * *

    *
  • Sorting: sortable controls whether this column * should be sortable by user's sort gestures; Comparator can * hold a column specific type. * *
  • Editing: editable controls whether cells of this * column should be accessible to in-table editing. * *
  • Tooltip: toolTipText holds the column tooltip * which is shown when hovering over the column's header. * *
  • Highlighter: highlighters holds the column * highlighters; these are applied to the renderer after the table highlighters. * Any modification of the list of contained Highlighters * (setting them, adding one or removing one) will result in a * {@code PropertyChangeEvent} being fired for "highlighters". State changes on * contained Highlighters will result in a PropertyChangeEvent * for "highlighterStateChanged". *
* * * Analogous to JComponent, this class supports per-instance * "client" properties. They are meant as a small-scale extension mechanism. * They are similar to regular bean properties in that registered * PropertyChangeListeners are notified about changes. TODO: * example? *

* * A TableColumnExt implements UIDependent, that is it takes over * responsibility to update LAF dependent properties of contained elements when * messaged with updateUI. This implementation updates its Highlighters, * Cell-/HeaderRenderer and CellEditor.

* * TODO: explain prototype (sizing, collaborator-used-by ColumnFactory (?)) *

* * @author Ramesh Gupta * @author Amy Fowler * @author Jeanette Winzenburg * @author Karl Schaefer * * @see TableColumnModelExt * @see ColumnFactory * @see org.jdesktop.swingx.plaf.UIDependent * @see javax.swing.JComponent#putClientProperty */ public class TableColumnExt extends TableColumn implements UIDependent { /** visible property. Initialized to true.*/ protected boolean visible = true; /** prototype property. */ protected Object prototypeValue; /** per-column comparator */ protected Comparator comparator; /** per-column sortable property. Initialized to true. */ protected boolean sortable = true; /** per-column editable property. Initialized to true.*/ protected boolean editable = true; /** per-column tool tip text. */ private String toolTipText; /** storage for client properties. */ protected Hashtable clientProperties; /** * The compound highlighter for the column. */ protected CompoundHighlighter compoundHighlighter; private ChangeListener highlighterChangeListener; private boolean ignoreHighlighterStateChange; /** * Creates new table view column with a model index = 0. */ public TableColumnExt() { this(0); } /** * Creates new table view column with the specified model index. * @param modelIndex index of table model column to which this view column * is bound. */ public TableColumnExt(int modelIndex) { this(modelIndex, 75); // default width taken from javax.swing.table.TableColumn } /** * Creates new table view column with the specified model index and column width. * @param modelIndex index of table model column to which this view column * is bound. * @param width pixel width of view column */ public TableColumnExt(int modelIndex, int width) { this(modelIndex, width, null, null); } /** * Creates new table view column with the specified model index, column * width, cell renderer and cell editor. * @param modelIndex index of table model column to which this view column * is bound. * @param width pixel width of view column * @param cellRenderer the cell renderer which will render all cells in this * view column * @param cellEditor the cell editor which will edit cells in this view column */ public TableColumnExt(int modelIndex, int width, TableCellRenderer cellRenderer, TableCellEditor cellEditor) { super(modelIndex, width, cellRenderer, cellEditor); } /** * Instantiates a new table view column with all properties copied from the * given original. * * @param columnExt the column to copy properties from * @see #copyFrom(TableColumnExt) */ public TableColumnExt(TableColumnExt columnExt) { this(columnExt.getModelIndex(), columnExt.getWidth(), columnExt .getCellRenderer(), columnExt.getCellEditor()); copyFrom(columnExt); } /** * Sets the Highlighters to the table, replacing any old settings. * None of the given Highlighters must be null.

* * This is a bound property.

* * Note: as of version #1.257 the null constraint is enforced strictly. To remove * all highlighters use this method without param. * * @param highlighters zero or more not null highlighters to use for renderer decoration. * @throws NullPointerException if array is null or array contains null values. * * @see #getHighlighters() * @see #addHighlighter(Highlighter) * @see #removeHighlighter(Highlighter) * */ public void setHighlighters(Highlighter... highlighters) { ignoreHighlighterStateChange = true; Highlighter[] old = getHighlighters(); getCompoundHighlighter().setHighlighters(highlighters); firePropertyChange("highlighters", old, getHighlighters()); ignoreHighlighterStateChange = false; } /** * Returns the Highlighters used by this table. * Maybe empty, but guarantees to be never null. * * @return the Highlighters used by this table, guaranteed to never null. * @see #setHighlighters(Highlighter[]) */ public Highlighter[] getHighlighters() { return getCompoundHighlighter().getHighlighters(); } /** * Appends a Highlighter to the end of the list of used * Highlighters. The argument must not be null. *

* * @param highlighter the Highlighter to add, must not be null. * @throws NullPointerException if Highlighter is null. * * @see #removeHighlighter(Highlighter) * @see #setHighlighters(Highlighter[]) */ public void addHighlighter(Highlighter highlighter) { ignoreHighlighterStateChange = true; Highlighter[] old = getHighlighters(); getCompoundHighlighter().addHighlighter(highlighter); firePropertyChange("highlighters", old, getHighlighters()); ignoreHighlighterStateChange = false; } /** * Removes the given Highlighter.

* * Does nothing if the Highlighter is not contained. * * @param highlighter the Highlighter to remove. * @see #addHighlighter(Highlighter) * @see #setHighlighters(Highlighter...) */ public void removeHighlighter(Highlighter highlighter) { ignoreHighlighterStateChange = true; Highlighter[] old = getHighlighters(); getCompoundHighlighter().removeHighlighter(highlighter); firePropertyChange("highlighters", old, getHighlighters()); ignoreHighlighterStateChange = false; } /** * Returns the CompoundHighlighter assigned to the table, null if none. * PENDING: open up for subclasses again?. * * @return the CompoundHighlighter assigned to the table. */ protected CompoundHighlighter getCompoundHighlighter() { if (compoundHighlighter == null) { compoundHighlighter = new CompoundHighlighter(); compoundHighlighter.addChangeListener(getHighlighterChangeListener()); } return compoundHighlighter; } /** * Returns the ChangeListener to use with highlighters. Lazily * creates the listener. * * @return the ChangeListener for observing changes of highlighters, * guaranteed to be not-null */ protected ChangeListener getHighlighterChangeListener() { if (highlighterChangeListener == null) { highlighterChangeListener = createHighlighterChangeListener(); } return highlighterChangeListener; } /** * Creates and returns the ChangeListener observing Highlighters. *

* Here: repaints the table on receiving a stateChanged. * * @return the ChangeListener defining the reaction to changes of * highlighters. */ protected ChangeListener createHighlighterChangeListener() { return new ChangeListener() { public void stateChanged(ChangeEvent e) { if (ignoreHighlighterStateChange) return; firePropertyChange("highlighterStateChanged", false, true); } }; } /** * Returns true if the user can resize the TableColumn's width, * false otherwise. This is a usability override: it takes into account * the case where it's principally allowed to resize the column * but not possible because the column has fixed size. * * @return a boolean indicating whether the user can resize this column. */ @Override public boolean getResizable() { // TODO JW: resizable is a bound property, so to be strict // we'll need to override setMin/MaxWidth to fire resizable // property change. return super.getResizable() && (getMinWidth() < getMaxWidth()); } /** * Sets the editable property. This property allows to mark all cells in a * column as read-only, independent of the per-cell editability as returned * by the TableModel.isCellEditable. If the cell is * read-only in the model layer, this property will have no effect. * * @param editable boolean indicating whether or not the user may edit cell * values in this view column * @see #isEditable * @see org.jdesktop.swingx.JXTable#isCellEditable(int, int) * @see javax.swing.table.TableModel#isCellEditable */ public void setEditable(boolean editable) { boolean oldEditable = this.editable; this.editable = editable; firePropertyChange("editable", Boolean.valueOf(oldEditable), Boolean.valueOf(editable)); } /** * Returns the per-column editable property. * The default is true. * * @return boolean indicating whether or not the user may edit cell * values in this view column * @see #setEditable */ public boolean isEditable() { return editable; } /** * Sets the prototypeValue property. The value should be of a type * which corresponds to the column's class as defined by the table model. * If non-null, the JXTable instance will use this property to calculate * and set the initial preferredWidth of the column. Note that this * initial preferredWidth will be overridden if the user resizes columns * directly. * * @param value Object containing the value of the prototype to be used * to calculate the initial preferred width of the column * @see #getPrototypeValue * @see org.jdesktop.swingx.JXTable#getPreferredScrollableViewportSize */ public void setPrototypeValue(Object value) { Object oldPrototypeValue = this.prototypeValue; this.prototypeValue = value; firePropertyChange("prototypeValue", oldPrototypeValue, value); } /** * Returns the prototypeValue property. * The default is null. * * @return Object containing the value of the prototype to be used * to calculate the initial preferred width of the column * @see #setPrototypeValue */ public Object getPrototypeValue() { return prototypeValue; } /** * Sets the comparator to use for this column. * JXTable sorting api respects this property by passing it on * to the SortController. * * @param comparator a custom comparator to use in interactive * sorting. * @see #getComparator * @see org.jdesktop.swingx.sort.SortController * @see org.jdesktop.swingx.decorator.SortKey */ public void setComparator(Comparator comparator) { Comparator old = getComparator(); this.comparator = comparator; firePropertyChange("comparator", old, getComparator()); } /** * Returns the comparator to use for the column. * The default is null. * * @return Comparator to use for this column * @see #setComparator */ public Comparator getComparator() { return comparator; } /** * Sets the sortable property. JXTable sorting api respects this * property by disabling interactive sorting on this column if false. * * @param sortable boolean indicating whether or not this column can * be sorted in the table * @see #isSortable */ public void setSortable(boolean sortable) { boolean old = isSortable(); this.sortable = sortable; firePropertyChange("sortable", old, isSortable()); } /** * Returns the sortable property. * The default value is true. * * @return boolean indicating whether this view column is sortable * @see #setSortable */ public boolean isSortable() { return sortable; } /** * Registers the text to display in the column's tool tip. * Typically, this is used by JXTableHeader to * display when the mouse cursor lingers over the column's * header cell. * * @param toolTipText text to show. * @see #setToolTipText(String) */ public void setToolTipText(String toolTipText) { String old = getToolTipText(); this.toolTipText = toolTipText; firePropertyChange("toolTipText", old, getToolTipText()); } /** * Returns the text of to display in the column's tool tip. * The default is null. * * @return the text of the column ToolTip. * @see #setToolTipText(String) */ public String getToolTipText() { return toolTipText; } /** * Sets the title of this view column. This is a convenience * wrapper for setHeaderValue. * @param title String containing the title of this view column */ public void setTitle(String title) { setHeaderValue(title); // simple wrapper } /** * Convenience method which returns the headerValue property after * converting it to a string. * @return String containing the title of this view column or null if * no headerValue is set. */ public String getTitle() { Object header = getHeaderValue(); return header != null ? header.toString() : null; // simple wrapper } /** * Sets the visible property. This property controls whether or not * this view column is currently visible in the table. * * @param visible boolean indicating whether or not this view column is * visible in the table * @see #setVisible */ public void setVisible(boolean visible) { boolean oldVisible = this.visible; this.visible = visible; firePropertyChange("visible", Boolean.valueOf(oldVisible), Boolean.valueOf(visible)); } /** * Returns the visible property. * The default is true. * * @return boolean indicating whether or not this view column is * visible in the table * @see #setVisible */ public boolean isVisible() { return visible; } /** * Sets the client property "key" to value. * If value is null this method will remove the property. * Changes to * client properties are reported with PropertyChange events. * The name of the property (for the sake of PropertyChange events) is * key.toString(). *

* The get/putClientProperty methods provide access to a * per-instance hashtable, which is intended for small scale extensions of * TableColumn. *

* * @param key Object which is used as key to retrieve value * @param value Object containing value of client property * @throws IllegalArgumentException if key is null * @see #getClientProperty * @see javax.swing.JComponent#putClientProperty */ public void putClientProperty(Object key, Object value) { if (key == null) throw new IllegalArgumentException("null key"); if ((value == null) && (getClientProperty(key) == null)) { return; } Object old = getClientProperty(key); if (value == null) { getClientProperties().remove(key); } else { getClientProperties().put(key, value); } firePropertyChange(key.toString(), old, value); /* Make all fireXXX methods in TableColumn protected instead of private */ } /** * Returns the value of the property with the specified key. Only properties * added with putClientProperty will return a non-null * value. * * @param key Object which is used as key to retrieve value * @return Object containing value of client property or null * * @see #putClientProperty */ public Object getClientProperty(Object key) { return ((key == null) || (clientProperties == null)) ? null : clientProperties.get(key); } private Hashtable getClientProperties() { if (clientProperties == null) { clientProperties = new Hashtable(); } return clientProperties; } /** * Copies properties from original. Handles all properties except * modelIndex, width, cellRenderer, cellEditor. Called from copy * constructor. * * @param original the tableColumn to copy from * * @see #TableColumnExt(TableColumnExt) */ protected void copyFrom(TableColumnExt original) { setEditable(original.isEditable()); setHeaderValue(original.getHeaderValue()); // no need to copy setTitle(); setToolTipText(original.getToolTipText()); setIdentifier(original.getIdentifier()); setMaxWidth(original.getMaxWidth()); setMinWidth(original.getMinWidth()); setPreferredWidth(original.getPreferredWidth()); setPrototypeValue(original.getPrototypeValue()); // JW: isResizable is overridden to return a calculated property! setResizable(original.isResizable); setVisible(original.isVisible()); setSortable(original.isSortable()); setComparator(original.getComparator()); copyClientPropertiesFrom(original); if (original.compoundHighlighter != null) { setHighlighters(original.getHighlighters()); } } /** * Copies all clientProperties of this TableColumnExt * to the target column. * * @param original the target column. */ protected void copyClientPropertiesFrom(TableColumnExt original) { if (original.clientProperties == null) return; for(Object key: original.clientProperties.keySet()) { putClientProperty(key, original.getClientProperty(key)); } } /** * Notifies registered PropertyChangeListeners * about property changes. This method must be invoked internally * whe any of the enhanced properties changed. *

* Implementation note: needed to replicate super * functionality because super's field propertyChangeSupport * and method fireXX are both private. * * @param propertyName name of changed property * @param oldValue old value of changed property * @param newValue new value of changed property */ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { if ((oldValue != null && !oldValue.equals(newValue)) || oldValue == null && newValue != null) { PropertyChangeListener pcl[] = getPropertyChangeListeners(); if (pcl != null && pcl.length != 0) { PropertyChangeEvent pce = new PropertyChangeEvent(this, propertyName, oldValue, newValue); for (int i = 0; i < pcl.length; i++) { pcl[i].propertyChange(pce); } } } } //---------------- implement UIDependent /** * Update ui of owned ui-dependent parts. This implementation * updates the contained highlighters. * */ public void updateUI() { updateHighlighterUI(); updateRendererUI(getCellRenderer()); updateRendererUI(getHeaderRenderer()); updateEditorUI(getCellEditor()); } /** * @param editor * */ private void updateEditorUI(TableCellEditor editor) { if (editor == null) return; // internal knowledge of core table - already updated if ((editor instanceof JComponent) || (editor instanceof DefaultCellEditor)) return; try { Component comp = editor .getTableCellEditorComponent(null, null, false, -1, -1); if (comp != null) { SwingUtilities.updateComponentTreeUI(comp); } } catch (Exception e) { // can't do anything - renderer can't cope with off-range cells } } /** * @param tableCellRenderer * */ private void updateRendererUI(TableCellRenderer renderer) { if (renderer == null) return; // internal knowledge of core table - already updated if (renderer instanceof JComponent) { return; } Component comp = null; if (renderer instanceof AbstractRenderer) { comp = ((AbstractRenderer) renderer).getComponentProvider().getRendererComponent(null); } else { try { comp = renderer .getTableCellRendererComponent(null, null, false, false, -1, -1); } catch (Exception e) { // can't do anything - renderer can't cope with off-range cells } } if (comp != null) { SwingUtilities.updateComponentTreeUI(comp); } } /** * */ private void updateHighlighterUI() { if (compoundHighlighter == null) return; compoundHighlighter.updateUI(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy