aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/itmill/toolkit/ui/Select.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/itmill/toolkit/ui/Select.java')
-rw-r--r--src/com/itmill/toolkit/ui/Select.java1202
1 files changed, 1202 insertions, 0 deletions
diff --git a/src/com/itmill/toolkit/ui/Select.java b/src/com/itmill/toolkit/ui/Select.java
new file mode 100644
index 0000000000..be73c31420
--- /dev/null
+++ b/src/com/itmill/toolkit/ui/Select.java
@@ -0,0 +1,1202 @@
+/* *************************************************************************
+
+ IT Mill Toolkit
+
+ Development of Browser User Intarfaces Made Easy
+
+ Copyright (C) 2000-2006 IT Mill Ltd
+
+ *************************************************************************
+
+ This product is distributed under commercial license that can be found
+ from the product package on license/license.txt. Use of this product might
+ require purchasing a commercial license from IT Mill Ltd. For guidelines
+ on usage, see license/licensing-guidelines.html
+
+ *************************************************************************
+
+ For more information, contact:
+
+ IT Mill Ltd phone: +358 2 4802 7180
+ Ruukinkatu 2-4 fax: +358 2 4802 7181
+ 20540, Turku email: info@itmill.com
+ Finland company www: www.itmill.com
+
+ Primary source for information and releases: www.itmill.com
+
+ ********************************************************************** */
+
+package com.itmill.toolkit.ui;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+import com.itmill.toolkit.data.Container;
+import com.itmill.toolkit.data.Item;
+import com.itmill.toolkit.data.Property;
+import com.itmill.toolkit.data.util.IndexedContainer;
+import com.itmill.toolkit.terminal.KeyMapper;
+import com.itmill.toolkit.terminal.PaintException;
+import com.itmill.toolkit.terminal.PaintTarget;
+import com.itmill.toolkit.terminal.Resource;
+
+/** <p>A class representing a selection of items the user has selected in a
+ * UI. The set of choices is presented as a set of
+ * {@link com.itmill.toolkit.data.Item}s in a
+ * {@link com.itmill.toolkit.data.Container}.</p>
+ *
+ * <p>A <code>Select</code> component may be in single- or multiselect mode.
+ * Multiselect mode means that more than one item can be selected
+ * simultaneously.</p>
+ *
+ * @author IT Mill Ltd.
+ * @version @VERSION@
+ * @since 3.0
+ */
+public class Select
+ extends AbstractField
+ implements
+ Container,
+ Container.Viewer,
+ Container.PropertySetChangeListener,
+ Container.PropertySetChangeNotifier,
+ Container.ItemSetChangeNotifier,
+ Container.ItemSetChangeListener {
+
+ /** Item caption mode: Item's ID's <code>String</code> representation
+ * is used as caption.
+ */
+ public static final int ITEM_CAPTION_MODE_ID = 0;
+
+ /** Item caption mode: Item's <code>String</code> representation is
+ * used as caption.
+ */
+ public static final int ITEM_CAPTION_MODE_ITEM = 1;
+
+ /** Item caption mode: Index of the item is used as caption. The
+ * index mode can only be used with the containers implementing the
+ * {@link com.itmill.toolkit.data.Container.Indexed} interface.
+ */
+ public static final int ITEM_CAPTION_MODE_INDEX = 2;
+
+ /** Item caption mode: If an Item has a caption it's used, if not,
+ * Item's ID's <code>String</code> representation is used as caption.
+ * <b>This is the default</b>.
+ */
+ public static final int ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID = 3;
+
+ /** Item caption mode: Captions must be explicitly specified.
+ */
+ public static final int ITEM_CAPTION_MODE_EXPLICIT = 4;
+
+ /** Item caption mode: Only icons are shown, captions are hidden.
+ */
+ public static final int ITEM_CAPTION_MODE_ICON_ONLY = 5;
+
+ /** Item caption mode: Item captions are read from property specified
+ * with <code>setItemCaptionPropertyId</code>.
+ */
+ public static final int ITEM_CAPTION_MODE_PROPERTY = 6;
+
+ /** Is the select in multiselect mode? */
+ private boolean multiSelect = false;
+
+ /** Select options */
+ protected Container items;
+
+ /** Is the user allowed to add new options? */
+ private boolean allowNewOptions;
+
+ /** Keymapper used to map key values */
+ protected KeyMapper itemIdMapper = new KeyMapper();
+
+ /** Item icons */
+ private HashMap itemIcons = new HashMap();
+
+ /** Item captions */
+ private HashMap itemCaptions = new HashMap();
+
+ /** Item caption mode */
+ private int itemCaptionMode = ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID;
+
+ /** Item caption source property id */
+ private Object itemCaptionPropertyId = null;
+
+ /** Item icon source property id */
+ private Object itemIconPropertyId = null;
+
+ /** List of property set change event listeners */
+ private LinkedList propertySetEventListeners = null;
+
+ /** List of item set change event listeners */
+ private LinkedList itemSetEventListeners = null;
+
+ /** Item id that represents null selection of this select.
+ *
+ * <p>Data interface does not support nulls as item ids. Selecting the item idetified
+ * by this id is the same as selecting no items at all. This setting only affects the
+ * single select mode.</p>
+ */
+ private Object nullSelectionItemId = null;
+
+ /* Constructors ********************************************************* */
+
+ /** Creates an empty Select.
+ * The caption is not used.
+ */
+ public Select() {
+ setContainerDataSource(new IndexedContainer());
+ }
+
+ /** Creates an empty Select with caption.
+ */
+ public Select(String caption) {
+ setContainerDataSource(new IndexedContainer());
+ setCaption(caption);
+ }
+
+ /** Creates a new select wthat is connected to a data-source.
+ * @param dataSource Container datasource to be selected from by this select.
+ * @param caption Caption of the component.
+ * @param selected Selected item id or null, if none selected.
+ */
+ public Select(String caption, Container dataSource) {
+ setCaption(caption);
+ setContainerDataSource(dataSource);
+ }
+
+ /** Creates a new select that is filled from a collection of option values.
+ * @param caption Caption of this field.
+ * @param options Collection containing the options.
+ * @param selected Selected option or null, if none selected.
+ */
+ public Select(String caption, Collection options) {
+
+ // Create options container and add given options to it
+ Container c = new IndexedContainer();
+ if (options != null)
+ for (Iterator i = options.iterator(); i.hasNext();)
+ c.addItem(i.next());
+
+ setCaption(caption);
+ setContainerDataSource((Container) c);
+ }
+
+ /* Component methods **************************************************** */
+
+ /** Paint the content of this component.
+ * @param event PaintEvent.
+ * @throws PaintException The paint operation failed.
+ */
+ public void paintContent(PaintTarget target) throws PaintException {
+
+ // Paint field properties
+ super.paintContent(target);
+
+ // Paint select attributes
+ if (isMultiSelect())
+ target.addAttribute("selectmode", "multi");
+ if (isNewItemsAllowed())
+ target.addAttribute("allownewitem", true);
+
+ // Paint options and create array of selected id keys
+ String[] selectedKeys;
+ if (isMultiSelect())
+ selectedKeys = new String[((Set) getValue()).size()];
+ else
+ selectedKeys =
+ new String[(
+ getValue() == null
+ && getNullSelectionItemId() == null ? 0 : 1)];
+ int keyIndex = 0;
+ target.startTag("options");
+
+ // Support for external null selection item id
+ Collection ids = getItemIds();
+ if (getNullSelectionItemId() != null
+ && (!ids.contains(getNullSelectionItemId()))) {
+
+ // Get the option attribute values
+ Object id = getNullSelectionItemId();
+ String key = itemIdMapper.key(id);
+ String caption = getItemCaption(id);
+ Resource icon = getItemIcon(id);
+
+ // Paint option
+ target.startTag("so");
+ if (icon != null)
+ target.addAttribute("icon", icon);
+ target.addAttribute("caption", caption);
+ target.addAttribute("nullselection", true);
+ target.addAttribute("key", key);
+ if (isSelected(id)) {
+ target.addAttribute("selected", true);
+ selectedKeys[keyIndex++] = key;
+ }
+ target.endTag("so");
+ }
+
+ // Paint available selection options from data source
+ for (Iterator i = getItemIds().iterator(); i.hasNext();) {
+
+ // Get the option attribute values
+ Object id = i.next();
+ String key = itemIdMapper.key(id);
+ String caption = getItemCaption(id);
+ Resource icon = getItemIcon(id);
+
+ // Paint option
+ target.startTag("so");
+ if (icon != null)
+ target.addAttribute("icon", icon);
+ target.addAttribute("caption", caption);
+ if (id != null && id.equals(getNullSelectionItemId()))
+ target.addAttribute("nullselection", true);
+ target.addAttribute("key", key);
+ if (isSelected(id) && keyIndex < selectedKeys.length) {
+ target.addAttribute("selected", true);
+ selectedKeys[keyIndex++] = key;
+ }
+ target.endTag("so");
+ }
+ target.endTag("options");
+
+ // Paint variables
+ target.addVariable(this, "selected", selectedKeys);
+ if (isNewItemsAllowed())
+ target.addVariable(this, "newitem", "");
+ }
+
+ /** Invoked when the value of a variable has changed.
+ * @param event Variable change event containing the information about
+ * the changed variable.
+ */
+ public void changeVariables(Object source, Map variables) {
+
+ // Try to set the property value
+
+ // New option entered (and it is allowed)
+ String newitem = (String) variables.get("newitem");
+ if (newitem != null && newitem.length() > 0) {
+
+ // Check for readonly
+ if (isReadOnly())
+ throw new Property.ReadOnlyException();
+
+ // Add new option
+ if (addItem(newitem) != null) {
+
+ // Set the caption property, if used
+ if (getItemCaptionPropertyId() != null)
+ try {
+ getContainerProperty(
+ newitem,
+ getItemCaptionPropertyId()).setValue(
+ newitem);
+ } catch (Property.ConversionException ignored) {
+ // The conversion exception is safely ignored, the caption is
+ // just missing
+ }
+ }
+ }
+
+ // Selection change
+ if (variables.containsKey("selected")) {
+ String[] ka = (String[]) variables.get("selected");
+
+ // Multiselect mode
+ if (isMultiSelect()) {
+
+ // Convert the key-array to id-set
+ LinkedList s = new LinkedList();
+ for (int i = 0; i < ka.length; i++) {
+ Object id = itemIdMapper.get(ka[i]);
+ if (id != null && containsId(id))
+ s.add(id);
+ else if (
+ itemIdMapper.isNewIdKey(ka[i])
+ && newitem != null
+ && newitem.length() > 0)
+ s.add(newitem);
+ }
+
+ // Limit the deselection to the set of visible items
+ // (non-visible items can not be deselected)
+ Collection visible = getVisibleItemIds();
+ if (visible != null) {
+ Set newsel = (Set) getValue();
+ if (newsel == null)
+ newsel = new HashSet();
+ else
+ newsel = new HashSet(newsel);
+ newsel.removeAll(visible);
+ newsel.addAll(s);
+ super.setValue(newsel);
+ }
+ }
+
+ // Single select mode
+ else {
+ if (ka.length == 0) {
+
+ // Allow deselection only if the deselected item is visible
+ Object current = getValue();
+ Collection visible = getVisibleItemIds();
+ if (visible != null && visible.contains(current))
+ setValue(null);
+ } else {
+ Object id = itemIdMapper.get(ka[0]);
+ if (id != null && id.equals(getNullSelectionItemId()))
+ setValue(null);
+ else if (itemIdMapper.isNewIdKey(ka[0]))
+ setValue(newitem);
+ else
+ setValue(id);
+ }
+ }
+ }
+ }
+
+ /** Get component UIDL tag.
+ * @return Component UIDL tag as string.
+ */
+ public String getTag() {
+ return "select";
+ }
+
+ /** Get the visible item ids. In Select, this returns list of all item ids,
+ * but can be overriden in subclasses if they paint only part of the items
+ * to the terminal or null if no items is visible.
+ */
+ public Collection getVisibleItemIds() {
+ if (isVisible())
+ return getItemIds();
+ return null;
+ }
+
+ /* Property methods ***************************************************** */
+
+ /** Return the type of the property.
+ * getValue and setValue functions must be compatible with this type:
+ * one can safely cast getValue() to given type and pass any variable
+ * assignable to this type as a parameter to setValue().
+ * @return type Type of the property.
+ */
+ public Class getType() {
+ if (isMultiSelect())
+ return Set.class;
+ else
+ return Object.class;
+ }
+
+ /** Get the selected item id or in multiselect mode a set of selected ids.
+ */
+ public Object getValue() {
+ Object retValue = super.getValue();
+
+ if (isMultiSelect()) {
+
+ // If the return value is not a set
+ if (retValue == null)
+ return new HashSet();
+ if (retValue instanceof Set) {
+ return Collections.unmodifiableSet((Set) retValue);
+ } else if (retValue instanceof Collection) {
+ return new HashSet((Collection)retValue);
+ } else {
+ Set s = new HashSet();
+ if (items.containsId(retValue))
+ s.add(retValue);
+ return s;
+ }
+
+ } else
+ return retValue;
+ }
+
+ /** Set the visible value of the property.
+ *
+ * <p>The value of the select is the selected item id. If the select is in
+ * multiselect-mode, the value is a set of selected item keys. In multiselect
+ * mode all collections of id:s can be assigned.</p>
+ *
+ * @param newValue New selected item or collection of selected items.
+ */
+ public void setValue(Object newValue)
+ throws Property.ReadOnlyException, Property.ConversionException {
+
+ if (isMultiSelect()) {
+ if (newValue == null)
+ super.setValue(new HashSet());
+ else if (Collection.class.isAssignableFrom(newValue.getClass()))
+ super.setValue(new HashSet((Collection) newValue));
+ } else if (newValue == null || items.containsId(newValue))
+ super.setValue(newValue);
+ }
+
+ /* Container methods **************************************************** */
+
+ /** Get the item from the container with given id.
+ * If the container does not contain the requested item, null is returned.
+ */
+ public Item getItem(Object itemId) {
+ return items.getItem(itemId);
+ }
+
+ /** Get item Id collection from the container.
+ * @return Collection of item ids.
+ */
+ public Collection getItemIds() {
+ return items.getItemIds();
+ }
+
+ /** Get property Id collection from the container.
+ * @return Collection of property ids.
+ */
+ public Collection getContainerPropertyIds() {
+ return items.getContainerPropertyIds();
+ }
+
+ /** Get property type.
+ * @param id Id identifying the of the property.
+ */
+ public Class getType(Object propertyId) {
+ return items.getType(propertyId);
+ }
+
+ /** Get the number of items in the container.
+ * @return Number of items in the container.
+ */
+ public int size() {
+ return items.size();
+ }
+
+ /** Test, if the collection contains an item with given id.
+ * @param itemId Id the of item to be tested.
+ */
+ public boolean containsId(Object itemId) {
+ if (itemId != null)
+ return items.containsId(itemId);
+ else
+ return false;
+ }
+
+ /**
+ * @see com.itmill.toolkit.data.Container#getContainerProperty(Object, Object)
+ */
+ public Property getContainerProperty(Object itemId, Object propertyId) {
+ return items.getContainerProperty(itemId, propertyId);
+ }
+
+ /* Container.Managed methods ******************************************** */
+
+ /** Add new property to all items.
+ * Adds a property with given id, type and default value to all items
+ * in the container.
+ *
+ * This functionality is optional. If the function is unsupported, it always
+ * returns false.
+ *
+ * @return True iff the operation succeeded.
+ */
+ public boolean addContainerProperty(
+ Object propertyId,
+ Class type,
+ Object defaultValue)
+ throws UnsupportedOperationException {
+
+ boolean retval =
+ items.addContainerProperty(propertyId, type, defaultValue);
+ if (retval
+ && !(items instanceof Container.PropertySetChangeNotifier)) {
+ firePropertySetChange();
+ }
+ return retval;
+ }
+
+ /** Remove all items from the container.
+ *
+ * This functionality is optional. If the function is unsupported, it always
+ * returns false.
+ *
+ * @return True iff the operation succeeded.
+ */
+ public boolean removeAllItems() throws UnsupportedOperationException {
+
+ boolean retval = items.removeAllItems();
+ this.itemIdMapper.removeAll();
+ if (retval) {
+ setValue(null);
+ if (!(items instanceof Container.ItemSetChangeNotifier))
+ fireItemSetChange();
+ }
+ return retval;
+ }
+
+ /** Create a new item into container with container managed id.
+ * The id of the created new item is returned. The item can be fetched with
+ * getItem() method.
+ * if the creation fails, null is returned.
+ *
+ * @return Id of the created item or null in case of failure.
+ */
+ public Object addItem() throws UnsupportedOperationException {
+
+ Object retval = items.addItem();
+ if (retval != null
+ && !(items instanceof Container.ItemSetChangeNotifier))
+ fireItemSetChange();
+ return retval;
+ }
+
+ /** Create a new item into container.
+ * The created new item is returned and ready for setting property values.
+ * if the creation fails, null is returned. In case the container already
+ * contains the item, null is returned.
+ *
+ * This functionality is optional. If the function is unsupported, it always
+ * returns null.
+ *
+ * @param itemId Identification of the item to be created.
+ * @return Created item with the given id, or null in case of failure.
+ */
+ public Item addItem(Object itemId) throws UnsupportedOperationException {
+
+ Item retval = items.addItem(itemId);
+ if (retval != null
+ && !(items instanceof Container.ItemSetChangeNotifier))
+ fireItemSetChange();
+ return retval;
+ }
+
+ /** Remove item identified by Id from the container.
+ * This functionality is optional. If the function is not implemented,
+ * the functions allways returns false.
+ *
+ * @return True iff the operation succeeded.
+ */
+ public boolean removeItem(Object itemId)
+ throws UnsupportedOperationException {
+
+ unselect(itemId);
+ boolean retval = items.removeItem(itemId);
+ this.itemIdMapper.remove(itemId);
+ if (retval && !(items instanceof Container.ItemSetChangeNotifier))
+ fireItemSetChange();
+ return retval;
+ }
+
+ /** Remove property from all items.
+ * Removes a property with given id from all the items in the container.
+ *
+ * This functionality is optional. If the function is unsupported, it always
+ * returns false.
+ *
+ * @return True iff the operation succeeded.
+ */
+ public boolean removeContainerProperty(Object propertyId)
+ throws UnsupportedOperationException {
+
+ boolean retval = items.removeContainerProperty(propertyId);
+ if (retval && !(items instanceof Container.PropertySetChangeNotifier))
+ firePropertySetChange();
+ return retval;
+ }
+
+ /* Container.Viewer methods ********************************************* */
+
+ /** Set the container as data-source for viewing. */
+ public void setContainerDataSource(Container newDataSource) {
+ if (newDataSource == null)
+ newDataSource = new IndexedContainer();
+
+ if (items != newDataSource) {
+
+ // Remove listeners from the old datasource
+ if (items != null) {
+ try {
+ ((Container.ItemSetChangeNotifier) items).removeListener(
+ (Container.ItemSetChangeListener) this);
+ } catch (ClassCastException ignored) {
+ // Ignored
+ }
+ try {
+ (
+ (
+ Container
+ .PropertySetChangeNotifier) items)
+ .removeListener(
+ (Container.PropertySetChangeListener) this);
+ } catch (ClassCastException ignored) {
+ // Ignored
+ }
+ }
+
+ // Assign new data source
+ items = newDataSource;
+
+ // Clear itemIdMapper also
+ this.itemIdMapper.removeAll();
+
+ // Add listeners
+ if (items != null) {
+ try {
+ ((Container.ItemSetChangeNotifier) items).addListener(
+ (Container.ItemSetChangeListener) this);
+ } catch (ClassCastException ignored) {
+ // Ignored
+ }
+ try {
+ ((Container.PropertySetChangeNotifier) items).addListener(
+ (Container.PropertySetChangeListener) this);
+ } catch (ClassCastException ignored) {
+ // Ignored
+ }
+ }
+ //TODO: This should be conditional
+ fireValueChange();
+ }
+ }
+
+ /** Get viewing data-source container. */
+ public Container getContainerDataSource() {
+ return items;
+ }
+
+ /* Select attributes **************************************************** */
+
+ /** Is the select in multiselect mode? In multiselect mode
+ * @return Value of property multiSelect.
+ */
+ public boolean isMultiSelect() {
+ return this.multiSelect;
+ }
+
+ /** Set the multiselect mode.
+ * Setting multiselect mode false may loose selection information: if
+ * selected items set contains one or more selected items, only one of the
+ * selected items is kept as selected.
+ *
+ * @param multiSelect New value of property multiSelect.
+ */
+ public void setMultiSelect(boolean multiSelect) {
+
+ if (multiSelect != this.multiSelect) {
+
+ // Selection before mode change
+ Object oldValue = getValue();
+
+ this.multiSelect = multiSelect;
+
+ // Convert the value type
+ if (multiSelect) {
+ Set s = new HashSet();
+ if (oldValue != null)
+ s.add(oldValue);
+ setValue(s);
+ } else {
+ Set s = (Set) oldValue;
+ if (s == null || s.isEmpty())
+ setValue(null);
+ else
+
+ // Set the single select to contain only the first
+ // selected value in the multiselect
+ setValue(s.iterator().next());
+ }
+
+ requestRepaint();
+ }
+ }
+
+ /** Does the select allow adding new options by the user.
+ * If true, the new options can be added to the Container. The text entered
+ * by the user is used as id. No that data-source must allow adding new
+ * items (it must implement Container.Managed).
+ * @return True iff additions are allowed.
+ */
+ public boolean isNewItemsAllowed() {
+
+ return this.allowNewOptions;
+ }
+
+ /** Enable or disable possibility to add new options by the user.
+ * @param allowNewOptions New value of property allowNewOptions.
+ */
+ public void setNewItemsAllowed(boolean allowNewOptions) {
+
+ // Only handle change requests
+ if (this.allowNewOptions != allowNewOptions) {
+
+ this.allowNewOptions = allowNewOptions;
+
+ requestRepaint();
+ }
+ }
+
+ /** Override the caption of an item.
+ * Setting caption explicitly overrides id, item and index captions.
+ *
+ * @param itemId The id of the item to be recaptioned.
+ * @param caption New caption.
+ */
+ public void setItemCaption(Object itemId, String caption) {
+ if (itemId != null) {
+ itemCaptions.put(itemId, caption);
+ requestRepaint();
+ }
+ }
+
+ /** Get the caption of an item.
+ * The caption is generated as specified by the item caption mode. See
+ * <code>setItemCaptionMode()</code> for more details.
+ *
+ * @param itemId The id of the item to be queried.
+ * @return caption for specified item.
+ */
+ public String getItemCaption(Object itemId) {
+
+ // Null items can not be found
+ if (itemId == null)
+ return null;
+
+ String caption = null;
+
+ switch (getItemCaptionMode()) {
+
+ case ITEM_CAPTION_MODE_ID :
+ caption = itemId.toString();
+ break;
+
+ case ITEM_CAPTION_MODE_INDEX :
+ try {
+ caption =
+ String.valueOf(
+ ((Container.Indexed) items).indexOfId(itemId));
+ } catch (ClassCastException ignored) {
+ }
+ break;
+
+ case ITEM_CAPTION_MODE_ITEM :
+ Item i = getItem(itemId);
+ if (i != null)
+ caption = i.toString();
+ break;
+
+ case ITEM_CAPTION_MODE_EXPLICIT :
+ caption = (String) itemCaptions.get(itemId);
+ break;
+
+ case ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID :
+ caption = (String) itemCaptions.get(itemId);
+ if (caption == null)
+ caption = itemId.toString();
+ break;
+
+ case ITEM_CAPTION_MODE_PROPERTY :
+ Property p =
+ getContainerProperty(itemId, getItemCaptionPropertyId());
+ if (p != null)
+ caption = p.toString();
+ break;
+ }
+
+ // All items must have some captions
+ return caption != null ? caption : "";
+ }
+
+ /** Set icon for an item.
+ *
+ * @param itemId The id of the item to be assigned an icon.
+ * @param icon New icon.
+ */
+ public void setItemIcon(Object itemId, Resource icon) {
+ if (itemId != null) {
+ if (icon == null)
+ itemIcons.remove(itemId);
+ else
+ itemIcons.put(itemId, icon);
+ requestRepaint();
+ }
+ }
+
+ /** Get the item icon.
+ *
+ * @param itemId The id of the item to be assigned an icon.
+ * @return Icon for the item or null, if not specified.
+ */
+ public Resource getItemIcon(Object itemId) {
+ Resource explicit = (Resource) itemIcons.get(itemId);
+ if (explicit != null)
+ return explicit;
+
+ if (getItemIconPropertyId() == null)
+ return null;
+
+ Property ip = getContainerProperty(itemId, getItemIconPropertyId());
+ if (ip == null)
+ return null;
+ Object icon = ip.getValue();
+ if (icon instanceof Resource)
+ return (Resource) icon;
+
+ return null;
+ }
+
+ /** Set the item caption mode.
+ *
+ * <p>The mode can be one of the following ones:
+ * <ul>
+ * <li><code>ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID</code> : Items
+ * Id-objects <code>toString()</code> is used as item caption. If
+ * caption is explicitly specified, it overrides the id-caption.
+ * <li><code>ITEM_CAPTION_MODE_ID</code> : Items Id-objects
+ * <code>toString()</code> is used as item caption.</li>
+ * <li><code>ITEM_CAPTION_MODE_ITEM</code> : Item-objects
+ * <code>toString()</code> is used as item caption.</li>
+ * <li><code>ITEM_CAPTION_MODE_INDEX</code> : The index of the item is
+ * used as item caption. The index mode can
+ * only be used with the containers implementing
+ * <code>Container.Indexed</code> interface.</li>
+ * <li><code>ITEM_CAPTION_MODE_EXPLICIT</code> : The item captions
+ * must be explicitly specified.</li>
+ * <li><code>ITEM_CAPTION_MODE_PROPERTY</code> : The item captions
+ * are read from property, that must be specified with
+ * <code>setItemCaptionPropertyId()</code>.</li>
+ * </ul>
+ * The <code>ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID</code> is the default
+ * mode.
+ * </p>
+ *
+ * @param mode One of the modes listed above.
+ */
+ public void setItemCaptionMode(int mode) {
+ if (ITEM_CAPTION_MODE_ID <= mode
+ && mode <= ITEM_CAPTION_MODE_PROPERTY) {
+ itemCaptionMode = mode;
+ requestRepaint();
+ }
+ }
+
+ /** Get the item caption mode.
+ *
+ * <p>The mode can be one of the following ones:
+ * <ul>
+ * <li><code>ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID</code> : Items
+ * Id-objects <code>toString()</code> is used as item caption. If
+ * caption is explicitly specified, it overrides the id-caption.
+ * <li><code>ITEM_CAPTION_MODE_ID</code> : Items Id-objects
+ * <code>toString()</code> is used as item caption.</li>
+ * <li><code>ITEM_CAPTION_MODE_ITEM</code> : Item-objects
+ * <code>toString()</code> is used as item caption.</li>
+ * <li><code>ITEM_CAPTION_MODE_INDEX</code> : The index of the item is
+ * used as item caption. The index mode can
+ * only be used with the containers implementing
+ * <code>Container.Indexed</code> interface.</li>
+ * <li><code>ITEM_CAPTION_MODE_EXPLICIT</code> : The item captions
+ * must be explicitly specified.</li>
+ * <li><code>ITEM_CAPTION_MODE_PROPERTY</code> : The item captions
+ * are read from property, that must be specified with
+ * <code>setItemCaptionPropertyId()</code>.</li>
+ * </ul>
+ * The <code>ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID</code> is the default
+ * mode.
+ * </p>
+ *
+ * @return One of the modes listed above.
+ */
+ public int getItemCaptionMode() {
+ return itemCaptionMode;
+ }
+
+ /** Set the item caption property.
+ *
+ * <p>Setting the id to a existing property implicitly sets
+ * the item caption mode to <code>ITEM_CAPTION_MODE_PROPERTY</code>.
+ * If the object is in <code>ITEM_CAPTION_MODE_PROPERTY</code>
+ * mode, setting caption property id null resets the
+ * item caption mode to <code>ITEM_CAPTION_EXPLICIT_DEFAULTS_ID</code>.</p>
+
+ * <p>Setting the property id to null disables this feature. The
+ * id is null by default</p>.
+ *
+ */
+ public void setItemCaptionPropertyId(Object propertyId) {
+ if (propertyId != null) {
+ itemCaptionPropertyId = propertyId;
+ setItemCaptionMode(ITEM_CAPTION_MODE_PROPERTY);
+ requestRepaint();
+ } else {
+ itemCaptionPropertyId = null;
+ if (getItemCaptionMode() == ITEM_CAPTION_MODE_PROPERTY)
+ setItemCaptionMode(ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID);
+ requestRepaint();
+ }
+ }
+
+ /** Get the item caption property.
+ *
+ * @return Id of the property used as item caption source.
+ */
+ public Object getItemCaptionPropertyId() {
+ return itemCaptionPropertyId;
+ }
+
+ /** Set the item icon property.
+ *
+ * <p>If the property id is set to a valid value, each item is given
+ * an icon got from the given property of the items. The type
+ * of the property must be assignable to Icon.</p>
+ *
+ * <p>Note that the icons set with <code>setItemIcon</code>
+ * function override the icons from the property.</p>
+ *
+ * <p>Setting the property id to null disables this feature. The
+ * id is null by default</p>.
+ *
+ * @param propertyId Id of the property that specifies icons for
+ * items.
+ */
+ public void setItemIconPropertyId(Object propertyId) {
+ if ((propertyId != null)
+ && Resource.class.isAssignableFrom(getType(propertyId))) {
+ itemIconPropertyId = propertyId;
+ requestRepaint();
+ } else
+ itemIconPropertyId = null;
+ }
+
+ /** Get the item icon property.
+ *
+ * <p>If the property id is set to a valid value, each item is given
+ * an icon got from the given property of the items. The type
+ * of the property must be assignable to Icon.</p>
+ *
+ * <p>Note that the icons set with <code>setItemIcon</code>
+ * function override the icons from the property.</p>
+ *
+ * <p>Setting the property id to null disables this feature. The
+ * id is null by default</p>.
+ *
+ * @return Id of the property containing the item icons.
+ */
+ public Object getItemIconPropertyId() {
+ return itemIconPropertyId;
+ }
+
+ /** Test if an item is selected
+ *
+ * <p>In single select mode testing selection status of the item identified
+ * by {@link #getNullSelectionItemId()} returns true if the value of the
+ * property is null.</p>
+ *
+ * @see #getNullSelectionItemId()
+ * @see #setNullSelectionItemId(Object)
+ * @param itemId Id the of the item to be tested
+ */
+ public boolean isSelected(Object itemId) {
+ if (itemId == null)
+ return false;
+ if (isMultiSelect())
+ return ((Set) getValue()).contains(itemId);
+ else {
+ Object value = getValue();
+ return itemId.equals(
+ value == null ? getNullSelectionItemId() : value);
+ }
+ }
+
+ /** Select an item.
+ *
+ * <p>In single select mode selecting item identified
+ * by {@link #getNullSelectionItemId()} sets the value of the
+ * property to null.</p>
+ *
+ * @see #getNullSelectionItemId()
+ * @see #setNullSelectionItemId(Object)
+ * @param itemId Item to be selected.
+ */
+ public void select(Object itemId) {
+ if (!isSelected(itemId) && items.containsId(itemId)) {
+ if (isMultiSelect()) {
+ Set s = new HashSet((Set) getValue());
+ s.add(itemId);
+ setValue(s);
+ } else if (itemId.equals(getNullSelectionItemId()))
+ setValue(null);
+ else
+ setValue(itemId);
+ }
+ }
+
+ /** Unselect an item.
+ *
+ * @see #getNullSelectionItemId()
+ * @see #setNullSelectionItemId(Object)
+ * @param itemId Item to be unselected.
+ */
+ public void unselect(Object itemId) {
+ if (isSelected(itemId)) {
+ if (isMultiSelect()) {
+ Set s = new HashSet((Set) getValue());
+ s.remove(itemId);
+ setValue(s);
+ } else
+ setValue(null);
+ }
+ }
+
+ /**
+ * @see com.itmill.toolkit.data.Container.PropertySetChangeListener#containerPropertySetChange(com.itmill.toolkit.data.Container.PropertySetChangeEvent)
+ */
+ public void containerPropertySetChange(
+ Container.PropertySetChangeEvent event) {
+ firePropertySetChange();
+ }
+
+ /**
+ * @see com.itmill.toolkit.data.Container.PropertySetChangeNotifier#addListener(com.itmill.toolkit.data.Container.PropertySetChangeListener)
+ */
+ public void addListener(Container.PropertySetChangeListener listener) {
+ if (propertySetEventListeners == null)
+ propertySetEventListeners = new LinkedList();
+ propertySetEventListeners.add(listener);
+ }
+
+ /**
+ * @see com.itmill.toolkit.data.Container.PropertySetChangeNotifier#removeListener(com.itmill.toolkit.data.Container.PropertySetChangeListener)
+ */
+ public void removeListener(Container.PropertySetChangeListener listener) {
+ if (propertySetEventListeners != null) {
+ propertySetEventListeners.remove(listener);
+ if (propertySetEventListeners.isEmpty())
+ propertySetEventListeners = null;
+ }
+ }
+
+ /**
+ * @see com.itmill.toolkit.data.Container.ItemSetChangeNotifier#addListener(com.itmill.toolkit.data.Container.ItemSetChangeListener)
+ */
+ public void addListener(Container.ItemSetChangeListener listener) {
+ if (itemSetEventListeners == null)
+ itemSetEventListeners = new LinkedList();
+ itemSetEventListeners.add(listener);
+ }
+
+ /**
+ * @see com.itmill.toolkit.data.Container.ItemSetChangeNotifier#removeListener(com.itmill.toolkit.data.Container.ItemSetChangeListener)
+ */
+ public void removeListener(Container.ItemSetChangeListener listener) {
+ if (itemSetEventListeners != null) {
+ itemSetEventListeners.remove(listener);
+ if (itemSetEventListeners.isEmpty())
+ itemSetEventListeners = null;
+ }
+ }
+
+ /**
+ * @see com.itmill.toolkit.data.Container.ItemSetChangeListener#containerItemSetChange(com.itmill.toolkit.data.Container.ItemSetChangeEvent)
+ */
+ public void containerItemSetChange(Container.ItemSetChangeEvent event) {
+ // Clear item id mapping table
+ this.itemIdMapper.removeAll();
+
+ // Notify all listeners
+ fireItemSetChange();
+ }
+
+ /** Fire property set change event */
+ protected void firePropertySetChange() {
+ if (propertySetEventListeners != null
+ && !propertySetEventListeners.isEmpty()) {
+ Container.PropertySetChangeEvent event =
+ new PropertySetChangeEvent();
+ Object[] listeners = propertySetEventListeners.toArray();
+ for (int i = 0; i < listeners.length; i++)
+ (
+ (
+ Container
+ .PropertySetChangeListener) listeners[i])
+ .containerPropertySetChange(
+ event);
+ }
+ requestRepaint();
+ }
+
+ /** Fire item set change event */
+ protected void fireItemSetChange() {
+ if (itemSetEventListeners != null
+ && !itemSetEventListeners.isEmpty()) {
+ Container.ItemSetChangeEvent event = new ItemSetChangeEvent();
+ Object[] listeners = itemSetEventListeners.toArray();
+ for (int i = 0; i < listeners.length; i++)
+ (
+ (
+ Container
+ .ItemSetChangeListener) listeners[i])
+ .containerItemSetChange(
+ event);
+ }
+ requestRepaint();
+ }
+
+ /** Implementation of item set change event */
+ private class ItemSetChangeEvent implements Container.ItemSetChangeEvent {
+
+ /**
+ * @see com.itmill.toolkit.data.Container.ItemSetChangeEvent#getContainer()
+ */
+ public Container getContainer() {
+ return Select.this;
+ }
+
+ }
+
+ /** Implementation of property set change event */
+ private class PropertySetChangeEvent
+ implements Container.PropertySetChangeEvent {
+
+ /**
+ * @see com.itmill.toolkit.data.Container.PropertySetChangeEvent#getContainer()
+ */
+ public Container getContainer() {
+ return Select.this;
+ }
+
+ }
+ /** Returns the item id that represents null value of this select in single select mode.
+ *
+ * <p>Data interface does not support nulls as item ids. Selecting the item idetified
+ * by this id is the same as selecting no items at all. This setting only affects the
+ * single select mode.</p>
+
+ * @return Object Null value item id.
+ * @see #setNullSelectionItemId(Object)
+ * @see #isSelected(Object)
+ * @see #select(Object)
+ */
+ public final Object getNullSelectionItemId() {
+ return nullSelectionItemId;
+ }
+
+ /** Sets the item id that represents null value of this select.
+ *
+ * <p>Data interface does not support nulls as item ids. Selecting the item idetified
+ * by this id is the same as selecting no items at all. This setting only affects the
+ * single select mode.</p>
+ *
+ * @param nullPropertyValueContainerItemId The nullPropertyValueContainerItemId to set
+ * @see #getNullSelectionItemId()
+ * @see #isSelected(Object)
+ * @see #select(Object)
+ */
+ public void setNullSelectionItemId(Object nullSelectionItemId) {
+ this.nullSelectionItemId = nullSelectionItemId;
+ }
+}