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

ca.odell.glazedlists.swing.GlazedListsSwing Maven / Gradle / Ivy

/* Glazed Lists                                                 (c) 2003-2013 */
/* http://publicobject.com/glazedlists/                      publicobject.com,*/
/*                                                     O'Dell Engineering Ltd.*/
package ca.odell.glazedlists.swing;

import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.ThresholdList;
import ca.odell.glazedlists.TransformedList;
import ca.odell.glazedlists.event.ListEvent;
import ca.odell.glazedlists.gui.TableFormat;
import ca.odell.glazedlists.impl.swing.DefaultTableModelEventAdapterFactory;
import ca.odell.glazedlists.impl.swing.LowerThresholdRangeModel;
import ca.odell.glazedlists.impl.swing.ManyToOneTableModelEventAdapterFactory;
import ca.odell.glazedlists.impl.swing.SwingThreadProxyEventList;
import ca.odell.glazedlists.impl.swing.UpperThresholdRangeModel;
import ca.odell.glazedlists.swing.TableModelEventAdapter.Factory;

import javax.swing.BoundedRangeModel;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;

/**
 * A factory for creating all sorts of objects to be used with Glazed Lists.
 *
 * @author Jesse Wilson
 */
public final class GlazedListsSwing {

    /**
     * A dummy constructor to prevent instantiation of this class
     */
    private GlazedListsSwing() {
        throw new UnsupportedOperationException();
    }

    // EventLists // // // // // // // // // // // // // // // // // // // // //

    /**
     * Wraps the source in an {@link EventList} that fires all of its update
     * events from the Swing event dispatch thread.
     */
    public static  TransformedList swingThreadProxyList(EventList source) {
        return new SwingThreadProxyEventList(source);
    }

    /**
     * Returns true iff list is an {@link EventList} that fires
     * all of its update events from the Swing event dispatch thread.
     */
    public static boolean isSwingThreadProxyList(EventList list) {
        return list instanceof SwingThreadProxyEventList;
    }

    // ThresholdRangeModels // // // // // // // // // // // // // // // // //

    /**
     * Creates a model that manipulates the lower bound of the specified
     * ThresholdList.  The ThresholdList linked to this model type will contain
     * a range of Objects between the results of getValue() and getMaximum()
     * on the BoundedRangeModel.
     */
    public static BoundedRangeModel lowerRangeModel(ThresholdList target) {
        return new LowerThresholdRangeModel(target);
    }

    /**
     * Creates a model that manipulates the upper bound of the specified
     * ThresholdList.  The ThresholdList linked to this model type will contain
     * a range of Objects between the results of getMinimum() and getValue()
     * on the BoundedRangeModel.
     */
    public static BoundedRangeModel upperRangeModel(ThresholdList target) {
        return new UpperThresholdRangeModel(target);
    }

    // TableModel convenience creators

    /**
     * Creates a new table model that extracts column data from the given
     * source using the the given tableFormat.
     *
     * 

The returned table model is not thread-safe. Unless otherwise * noted, all methods are only safe to be called from the event dispatch thread. * To do this programmatically, use {@link SwingUtilities#invokeAndWait(Runnable)} and * wrap the source list (or some part of the source list's pipeline) using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}.

* * @param source the EventList that provides the row objects * @param tableFormat the object responsible for extracting column data * from the row objects */ public static AdvancedTableModel eventTableModel(EventList source, TableFormat tableFormat) { return new DefaultEventTableModel(source, tableFormat); } /** * Creates a new table model that extracts column data from the given source * using the the given tableFormat. While holding a read lock, * this method wraps the source list using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}. *

* The returned table model is not thread-safe. Unless otherwise noted, all * methods are only safe to be called from the event dispatch thread. *

* * @param source the EventList that provides the row objects * @param tableFormat the object responsible for extracting column data from the row objects */ public static AdvancedTableModel eventTableModelWithThreadProxyList(EventList source, TableFormat tableFormat) { final EventList proxySource = createSwingThreadProxyList(source); return new DefaultEventTableModel(proxySource, true, tableFormat); } /** * Creates a new table model that extracts column data from the given * source using the the given tableFormat. * *

The eventAdapterFactory is used to create a {@link TableModelEventAdapter}, * which is then used by the created table model to convert list events to table model events.

* *

The returned table model is not thread-safe. Unless otherwise * noted, all methods are only safe to be called from the event dispatch thread. * To do this programmatically, use {@link SwingUtilities#invokeAndWait(Runnable)} and * wrap the source list (or some part of the source list's pipeline) using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}.

* * @param source the EventList that provides the row objects * @param tableFormat the object responsible for extracting column data * from the row objects * @param eventAdapterFactory factory for creating a {@link TableModelEventAdapter} */ public static AdvancedTableModel eventTableModel(EventList source, TableFormat tableFormat, TableModelEventAdapter.Factory eventAdapterFactory) { final DefaultEventTableModel result = new DefaultEventTableModel(source, tableFormat); final TableModelEventAdapter eventAdapter = eventAdapterFactory.create(result); result.setEventAdapter(eventAdapter); return result; } /** * Creates a new table model that extracts column data from the given source * using the the given tableFormat. * *

While holding a read lock, this method wraps the source list using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}.

* *

The eventAdapterFactory is used to create a {@link TableModelEventAdapter}, * which is then used by the created table model to convert list events to table model events.

* *

* The returned table model is not thread-safe. Unless otherwise noted, all * methods are only safe to be called from the event dispatch thread. *

* * @param source the EventList that provides the row objects * @param tableFormat the object responsible for extracting column data from the row objects * @param eventAdapterFactory factory for creating a {@link TableModelEventAdapter} */ public static AdvancedTableModel eventTableModelWithThreadProxyList(EventList source, TableFormat tableFormat, TableModelEventAdapter.Factory eventAdapterFactory) { final EventList proxySource = createSwingThreadProxyList(source); final DefaultEventTableModel result = new DefaultEventTableModel(proxySource, true, tableFormat); final TableModelEventAdapter eventAdapter = eventAdapterFactory.create(result); result.setEventAdapter(eventAdapter); return result; } /** * Creates a new table model that renders the specified list with an automatically * generated {@link TableFormat}. It uses JavaBeans and reflection to create * a {@link TableFormat} as specified. * *

Note that classes that will be obfuscated may not work with * reflection. In this case, implement a {@link TableFormat} manually.

* *

The returned table model is not thread-safe. Unless otherwise * noted, all methods are only safe to be called from the event dispatch thread. * To do this programmatically, use {@link SwingUtilities#invokeAndWait(Runnable)} and * wrap the source list (or some part of the source list's pipeline) using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}.

* * @param source the EventList that provides the row objects * @param propertyNames an array of property names in the JavaBeans format. * For example, if your list contains Objects with the methods getFirstName(), * setFirstName(String), getAge(), setAge(Integer), then this array should * contain the two strings "firstName" and "age". This format is specified * by the JavaBeans {@link java.beans.PropertyDescriptor}. * @param columnLabels the corresponding column names for the listed property * names. For example, if your columns are "firstName" and "age", then * your labels might be "First Name" and "Age". * @param writable an array of booleans specifying which of the columns in * your table are writable. * */ public static AdvancedTableModel eventTableModel(EventList source, String[] propertyNames, String[] columnLabels, boolean[] writable) { return eventTableModel(source, GlazedLists.tableFormat(propertyNames, columnLabels, writable)); } /** * Creates a new table model that renders the specified list with an automatically * generated {@link TableFormat}. It uses JavaBeans and reflection to create * a {@link TableFormat} as specified. While holding a read lock, * this method wraps the source list using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}. * *

Note that classes that will be obfuscated may not work with * reflection. In this case, implement a {@link TableFormat} manually.

* *

The returned table model is not thread-safe. Unless otherwise * noted, all methods are only safe to be called from the event dispatch thread.

* * @param source the EventList that provides the row objects * @param propertyNames an array of property names in the JavaBeans format. * For example, if your list contains Objects with the methods getFirstName(), * setFirstName(String), getAge(), setAge(Integer), then this array should * contain the two strings "firstName" and "age". This format is specified * by the JavaBeans {@link java.beans.PropertyDescriptor}. * @param columnLabels the corresponding column names for the listed property * names. For example, if your columns are "firstName" and "age", then * your labels might be "First Name" and "Age". * @param writable an array of booleans specifying which of the columns in * your table are writable. * */ public static AdvancedTableModel eventTableModelWithThreadProxyList(EventList source, String[] propertyNames, String[] columnLabels, boolean[] writable) { return eventTableModelWithThreadProxyList(source, GlazedLists.tableFormat(propertyNames, columnLabels, writable)); } // event adapter factories /** * Gets a factory for creating a default {@link TableModelEventAdapter}. *

The default strategy to convert list events to table model events is to be as accurate as possible. * In particular, each list event block as converted to and fired as a separate {@link TableModelEvent}. * So, one list event can cause multiple table model events. *

*

In some cases, this conversion strategy can lead to undesirable effects, such as table repainting issues. * One known case is when the table property {@link JTable#getFillsViewportHeight() fillsViewportHeight} is true. * Using the {@link #manyToOneEventAdapterFactory() other standard factory} is then recommended. * * @return the factory for creating a default {@link TableModelEventAdapter} * * @see #manyToOneEventAdapterFactory() * @see Factory * @see ListEvent * @see TableModelEvent */ public static Factory defaultEventAdapterFactory() { return DefaultTableModelEventAdapterFactory.getInstance(); } /** * Gets a factory for creating a non-default {@link TableModelEventAdapter}. *

* Whereas the default TableModelEventAdapter converts each ListEvent block to a * TableModelEvent, this strategy tries to create only one TableModelEvent * for a ListEvent, if it does not represent a reorder. If the ListEvent * contains multiple blocks, a special data changed TableModelEvent * will be fired, indicating that all row data has changed. Note, that such * a data changed TableModelEvent can lead to a loss of the table * selection. *

*

* Therefore you should use this strategy only, when the * {@link #defaultEventAdapterFactory() default strategy} doesn't fit your * needs or causes undesirable effects/behaviour. *

* * @return the factory for creating a non-default {@link TableModelEventAdapter} * * @see #defaultEventAdapterFactory() * @see Factory * @see ListEvent * @see TableModelEvent */ public static Factory manyToOneEventAdapterFactory() { return ManyToOneTableModelEventAdapterFactory.getInstance(); } // ListSelectionModel convenience creators /** * Creates a new selection model that also presents a list of the selection. * * The {@link AdvancedListSelectionModel} listens to this {@link EventList} in order * to adjust selection when the {@link EventList} is modified. For example, * when an element is added to the {@link EventList}, this may offset the * selection of the following elements. * *

The returned selection model is not thread-safe. Unless otherwise * noted, all methods are only safe to be called from the event dispatch thread. * To do this programmatically, use {@link SwingUtilities#invokeAndWait(Runnable)} and * wrap the source list (or some part of the source list's pipeline) using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}.

* * @param source the {@link EventList} whose selection will be managed. This should * be the same {@link EventList} passed to the constructor of your * {@link AdvancedTableModel} or {@link EventListModel}. */ public static AdvancedListSelectionModel eventSelectionModel(EventList source) { return new DefaultEventSelectionModel(source); } /** * Creates a new selection model that also presents a list of the selection. * While holding a read lock, it wraps the source list using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}. The * {@link AdvancedListSelectionModel} listens to this {@link EventList} in order to adjust * selection when the {@link EventList} is modified. For example, when an element is added to * the {@link EventList}, this may offset the selection of the following elements. *

* The returned selection model is not thread-safe. Unless otherwise noted, * all methods are only safe to be called from the event dispatch thread. *

* * @param source the {@link EventList} whose selection will be managed. This should be the * same {@link EventList} passed to the constructor of your * {@link AdvancedTableModel} or {@link EventListModel}. */ public static AdvancedListSelectionModel eventSelectionModelWithThreadProxyList(EventList source) { final EventList proxySource = createSwingThreadProxyList(source); return new DefaultEventSelectionModel(proxySource, true); } // EventListModel convenience creators /** * Creates a new list model that contains all objects located in the given * source and reacts to any changes in the given source. * *

The returned selection model is not thread-safe. Unless otherwise * noted, all methods are only safe to be called from the event dispatch thread. * To do this programmatically, use {@link SwingUtilities#invokeAndWait(Runnable)} and * wrap the source list (or some part of the source list's pipeline) using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}. *

* * @param source the EventList that provides the elements */ public static DefaultEventListModel eventListModel(EventList source) { return new DefaultEventListModel(source); } /** * Creates a new list model that contains all objects located in the given * source and reacts to any changes in the given source. * While holding a read lock, it wraps the source list using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}. * *

The returned selection model is not thread-safe. Unless otherwise * noted, all methods are only safe to be called from the event dispatch thread. *

* * @param source the EventList that provides the elements */ public static DefaultEventListModel eventListModelWithThreadProxyList(EventList source) { final EventList proxySource = createSwingThreadProxyList(source); return new DefaultEventListModel(proxySource, true); } // EventComboBoxModel convenience creators /** * Creates a new combobox model that contains all objects located in the given * source and reacts to any changes in the given source. * *

The returned combobox model is not thread-safe. Unless otherwise * noted, all methods are only safe to be called from the event dispatch thread. * To do this programmatically, use {@link SwingUtilities#invokeAndWait(Runnable)} and * wrap the source list (or some part of the source list's pipeline) using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}. *

* * @param source the EventList that provides the elements */ public static DefaultEventComboBoxModel eventComboBoxModel(EventList source) { return new DefaultEventComboBoxModel(source); } /** * Creates a new combobox model that contains all objects located in the given * source and reacts to any changes in the given source. * While holding a read lock, it wraps the source list using * {@link GlazedListsSwing#swingThreadProxyList(EventList)}. * *

The returned combobox model is not thread-safe. Unless otherwise * noted, all methods are only safe to be called from the event dispatch thread. *

* * @param source the EventList that provides the elements */ public static DefaultEventComboBoxModel eventComboBoxModelWithThreadProxyList(EventList source) { final EventList proxySource = createSwingThreadProxyList(source); return new DefaultEventComboBoxModel(proxySource, true); } /** Helper method to create a SwingThreadProxyList with read locks. */ private static EventList createSwingThreadProxyList(EventList source) { final EventList result; source.getReadWriteLock().readLock().lock(); try { result = GlazedListsSwing.swingThreadProxyList(source); } finally { source.getReadWriteLock().readLock().unlock(); } return result; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy