123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364 |
- /*
- * Copyright 2000-2016 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
- package com.vaadin.v7.ui;
-
- import java.io.Serializable;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.EventObject;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.LinkedHashSet;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
-
- import com.vaadin.ui.AbstractListing;
- import org.jsoup.nodes.Element;
-
- import com.vaadin.event.Transferable;
- import com.vaadin.event.dd.DragAndDropEvent;
- import com.vaadin.event.dd.DropTarget;
- import com.vaadin.event.dd.TargetDetailsImpl;
- import com.vaadin.event.dd.acceptcriteria.ClientSideCriterion;
- import com.vaadin.event.dd.acceptcriteria.ContainsDataFlavor;
- import com.vaadin.event.dd.acceptcriteria.TargetDetailIs;
- import com.vaadin.server.KeyMapper;
- import com.vaadin.server.PaintException;
- import com.vaadin.server.PaintTarget;
- import com.vaadin.server.Resource;
- import com.vaadin.server.VaadinSession;
- import com.vaadin.shared.ui.dd.VerticalDropLocation;
- import com.vaadin.ui.AbstractComponent;
- import com.vaadin.ui.Component;
- import com.vaadin.ui.LegacyComponent;
- import com.vaadin.ui.declarative.DesignAttributeHandler;
- import com.vaadin.ui.declarative.DesignContext;
- import com.vaadin.ui.declarative.DesignException;
- import com.vaadin.ui.declarative.DesignFormatter;
- import com.vaadin.v7.data.Container;
- import com.vaadin.v7.data.Item;
- import com.vaadin.v7.data.Property;
- import com.vaadin.v7.data.Validator.InvalidValueException;
- import com.vaadin.v7.data.util.IndexedContainer;
- import com.vaadin.v7.data.util.converter.Converter;
- import com.vaadin.v7.data.util.converter.Converter.ConversionException;
- import com.vaadin.v7.data.util.converter.ConverterUtil;
- import com.vaadin.v7.event.DataBoundTransferable;
- import com.vaadin.v7.shared.ui.combobox.FilteringMode;
- import com.vaadin.v7.shared.ui.select.AbstractSelectState;
-
- /**
- * <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 Item}s in a {@link 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 Vaadin Ltd.
- * @since 5.0
- * @deprecated As of 8.0, replaced by {@link AbstractListing}
- */
- @SuppressWarnings("serial")
- @Deprecated
- // TODO currently cannot specify type more precisely in case of multi-select
- public abstract class AbstractSelect extends AbstractField<Object> implements
- Container, Container.Viewer, Container.PropertySetChangeListener,
- Container.PropertySetChangeNotifier, Container.ItemSetChangeNotifier,
- Container.ItemSetChangeListener, LegacyComponent {
-
- @Deprecated
- public enum ItemCaptionMode {
- /**
- * Item caption mode: Item's ID converted to a String using
- * {@link VaadinSession#getConverterFactory()} is used as caption.
- */
- ID,
- /**
- * Item caption mode: Item's ID's <code>String</code> representation is
- * used as caption.
- *
- * @since 7.5.6
- */
- ID_TOSTRING,
- /**
- * Item caption mode: Item's <code>String</code> representation is used
- * as caption.
- */
- ITEM,
- /**
- * Item caption mode: Index of the item is used as caption. The index
- * mode can only be used with the containers implementing the
- * {@link Container.Indexed} interface.
- */
- INDEX,
- /**
- * Item caption mode: If an Item has a caption it's used, if not, Item's
- * ID converted to a String using
- * {@link VaadinSession#getConverterFactory()} is used as caption.
- * <b>This is the default</b>.
- */
- EXPLICIT_DEFAULTS_ID,
- /**
- * Item caption mode: Captions must be explicitly specified.
- */
- EXPLICIT,
- /**
- * Item caption mode: Only icons are shown, captions are hidden.
- */
- ICON_ONLY,
- /**
- * Item caption mode: Item captions are read from property specified
- * with <code>setItemCaptionPropertyId</code>.
- */
- PROPERTY;
- }
-
- /**
- * @deprecated As of 7.0, use {@link ItemCaptionMode#ID} instead
- */
- @Deprecated
- public static final ItemCaptionMode ITEM_CAPTION_MODE_ID = ItemCaptionMode.ID;
-
- /**
- * @deprecated As of 7.0, use {@link ItemCaptionMode#ITEM} instead
- */
- @Deprecated
- public static final ItemCaptionMode ITEM_CAPTION_MODE_ITEM = ItemCaptionMode.ITEM;
-
- /**
- * @deprecated As of 7.0, use {@link ItemCaptionMode#INDEX} instead
- */
- @Deprecated
- public static final ItemCaptionMode ITEM_CAPTION_MODE_INDEX = ItemCaptionMode.INDEX;
-
- /**
- * @deprecated As of 7.0, use {@link ItemCaptionMode#EXPLICIT_DEFAULTS_ID}
- * instead
- */
- @Deprecated
- public static final ItemCaptionMode ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID = ItemCaptionMode.EXPLICIT_DEFAULTS_ID;
-
- /**
- * @deprecated As of 7.0, use {@link ItemCaptionMode#EXPLICIT} instead
- */
- @Deprecated
- public static final ItemCaptionMode ITEM_CAPTION_MODE_EXPLICIT = ItemCaptionMode.EXPLICIT;
-
- /**
- * @deprecated As of 7.0, use {@link ItemCaptionMode#ICON_ONLY} instead
- */
- @Deprecated
- public static final ItemCaptionMode ITEM_CAPTION_MODE_ICON_ONLY = ItemCaptionMode.ICON_ONLY;
-
- /**
- * @deprecated As of 7.0, use {@link ItemCaptionMode#PROPERTY} instead
- */
- @Deprecated
- public static final ItemCaptionMode ITEM_CAPTION_MODE_PROPERTY = ItemCaptionMode.PROPERTY;
-
- /**
- * Interface for option filtering, used to filter options based on user
- * entered value. The value is matched to the item caption.
- * <code>FilteringMode.OFF</code> (0) turns the filtering off.
- * <code>FilteringMode.STARTSWITH</code> (1) matches from the start of the
- * caption. <code>FilteringMode.CONTAINS</code> (1) matches anywhere in the
- * caption.
- */
- @Deprecated
- public interface Filtering extends Serializable {
-
- /**
- * @deprecated As of 7.0, use {@link FilteringMode#OFF} instead
- */
- @Deprecated
- public static final FilteringMode FILTERINGMODE_OFF = FilteringMode.OFF;
- /**
- * @deprecated As of 7.0, use {@link FilteringMode#STARTSWITH} instead
- */
- @Deprecated
- public static final FilteringMode FILTERINGMODE_STARTSWITH = FilteringMode.STARTSWITH;
- /**
- * @deprecated As of 7.0, use {@link FilteringMode#CONTAINS} instead
- */
- @Deprecated
- public static final FilteringMode FILTERINGMODE_CONTAINS = FilteringMode.CONTAINS;
-
- /**
- * Sets the option filtering mode.
- *
- * @param filteringMode
- * the filtering mode to use
- */
- public void setFilteringMode(FilteringMode filteringMode);
-
- /**
- * Gets the current filtering mode.
- *
- * @return the filtering mode in use
- */
- public FilteringMode getFilteringMode();
-
- }
-
- /**
- * 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<Object> itemIdMapper = new KeyMapper<Object>();
-
- /**
- * Item icons.
- */
- private final HashMap<Object, Resource> itemIcons = new HashMap<Object, Resource>();
-
- /**
- * Item captions.
- */
- private final HashMap<Object, String> itemCaptions = new HashMap<Object, String>();
-
- /**
- * Item caption mode.
- */
- private ItemCaptionMode itemCaptionMode = ItemCaptionMode.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 Set<Container.PropertySetChangeListener> propertySetEventListeners = null;
-
- /**
- * List of item set change event listeners.
- */
- private Set<Container.ItemSetChangeListener> itemSetEventListeners = null;
-
- /**
- * Item id that represents null selection of this select.
- *
- * <p>
- * Data interface does not support nulls as item ids. Selecting the item
- * identified 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;
-
- // Null (empty) selection is enabled by default
- private boolean nullSelectionAllowed = true;
- private NewItemHandler newItemHandler;
-
- // Caption (Item / Property) change listeners
- CaptionChangeListener captionChangeListener;
-
- /* Constructors */
-
- /**
- * Creates an empty Select. The caption is not used.
- */
- public AbstractSelect() {
- setContainerDataSource(new IndexedContainer());
- }
-
- /**
- * Creates an empty Select with caption.
- */
- public AbstractSelect(String caption) {
- setContainerDataSource(new IndexedContainer());
- setCaption(caption);
- }
-
- /**
- * Creates a new select that is connected to a data-source.
- *
- * @param caption
- * the Caption of the component.
- * @param dataSource
- * the Container datasource to be selected from by this select.
- */
- public AbstractSelect(String caption, Container dataSource) {
- setCaption(caption);
- setContainerDataSource(dataSource);
- }
-
- /**
- * Creates a new select that is filled from a collection of option values.
- *
- * @param caption
- * the Caption of this field.
- * @param options
- * the Collection containing the options.
- */
- public AbstractSelect(String caption, Collection<?> options) {
-
- // Creates the options container and add given options to it
- final Container c = new IndexedContainer();
- if (options != null) {
- for (final Object item : options) {
- c.addItem(item);
- }
- }
-
- setCaption(caption);
- setContainerDataSource(c);
- }
-
- /* Component methods */
-
- /**
- * Paints the content of this component.
- *
- * @param target
- * the Paint Event.
- * @throws PaintException
- * if the paint operation failed.
- */
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
-
- // Paints select attributes
- if (isMultiSelect()) {
- target.addAttribute("selectmode", "multi");
- }
- if (isNewItemsAllowed()) {
- target.addAttribute("allownewitem", true);
- }
- if (isNullSelectionAllowed()) {
- target.addAttribute("nullselect", true);
- if (getNullSelectionItemId() != null) {
- target.addAttribute("nullselectitem", true);
- }
- }
-
- // Constructs selected keys array
- String[] selectedKeys;
- if (isMultiSelect()) {
- selectedKeys = new String[((Set<?>) getValue()).size()];
- } else {
- selectedKeys = new String[(getValue() == null
- && getNullSelectionItemId() == null ? 0 : 1)];
- }
-
- // ==
- // first remove all previous item/property listeners
- getCaptionChangeListener().clear();
- // Paints the options and create array of selected id keys
-
- target.startTag("options");
- int keyIndex = 0;
- // Support for external null selection item id
- final Collection<?> ids = getItemIds();
- if (isNullSelectionAllowed() && getNullSelectionItemId() != null
- && !ids.contains(getNullSelectionItemId())) {
- final Object id = getNullSelectionItemId();
- // Paints option
- target.startTag("so");
- paintItem(target, id);
- if (isSelected(id)) {
- selectedKeys[keyIndex++] = itemIdMapper.key(id);
- }
- target.endTag("so");
- }
-
- final Iterator<?> i = getItemIds().iterator();
- // Paints the available selection options from data source
- while (i.hasNext()) {
- // Gets the option attribute values
- final Object id = i.next();
- if (!isNullSelectionAllowed() && id != null
- && id.equals(getNullSelectionItemId())) {
- // Remove item if it's the null selection item but null
- // selection is not allowed
- continue;
- }
- final String key = itemIdMapper.key(id);
- // add listener for each item, to cause repaint if an item changes
- getCaptionChangeListener().addNotifierForItem(id);
- target.startTag("so");
- paintItem(target, id);
- if (isSelected(id) && keyIndex < selectedKeys.length) {
- selectedKeys[keyIndex++] = key;
- }
- target.endTag("so");
- }
- target.endTag("options");
- // ==
-
- // Paint variables
- target.addVariable(this, "selected", selectedKeys);
- if (isNewItemsAllowed()) {
- target.addVariable(this, "newitem", "");
- }
-
- }
-
- protected void paintItem(PaintTarget target, Object itemId)
- throws PaintException {
- final String key = itemIdMapper.key(itemId);
- final String caption = getItemCaption(itemId);
- final Resource icon = getItemIcon(itemId);
- if (icon != null) {
- target.addAttribute("icon", icon);
- }
- target.addAttribute("caption", caption);
- if (itemId != null && itemId.equals(getNullSelectionItemId())) {
- target.addAttribute("nullselection", true);
- }
- target.addAttribute("key", key);
- if (isSelected(itemId)) {
- target.addAttribute("selected", true);
- }
- }
-
- /**
- * Invoked when the value of a variable has changed.
- *
- * @see AbstractComponent#changeVariables(java.lang.Object, java.util.Map)
- */
- @Override
- public void changeVariables(Object source, Map<String, Object> variables) {
-
- // New option entered (and it is allowed)
- if (isNewItemsAllowed()) {
- final String newitem = (String) variables.get("newitem");
- if (newitem != null && !newitem.isEmpty()) {
- getNewItemHandler().addNewItem(newitem);
- }
- }
-
- // Selection change
- if (variables.containsKey("selected")) {
- final String[] clientSideSelectedKeys = (String[]) variables
- .get("selected");
-
- // Multiselect mode
- if (isMultiSelect()) {
-
- // TODO Optimize by adding repaintNotNeeded when applicable
-
- // Converts the key-array to id-set
- final LinkedList<Object> acceptedSelections = new LinkedList<Object>();
- for (int i = 0; i < clientSideSelectedKeys.length; i++) {
- final Object id = itemIdMapper
- .get(clientSideSelectedKeys[i]);
- if (!isNullSelectionAllowed()
- && (id == null || id == getNullSelectionItemId())) {
- // skip empty selection if nullselection is not allowed
- markAsDirty();
- } else if (id != null && containsId(id)) {
- acceptedSelections.add(id);
- }
- }
-
- if (!isNullSelectionAllowed()
- && acceptedSelections.size() < 1) {
- // empty selection not allowed, keep old value
- markAsDirty();
- return;
- }
-
- // Limits the deselection to the set of visible items
- // (non-visible items can not be deselected)
- Collection<?> visibleNotSelected = getVisibleItemIds();
- if (visibleNotSelected != null) {
- visibleNotSelected = new HashSet<Object>(
- visibleNotSelected);
- // Don't remove those that will be added to preserve order
- visibleNotSelected.removeAll(acceptedSelections);
-
- @SuppressWarnings("unchecked")
- Set<Object> newsel = (Set<Object>) getValue();
- if (newsel == null) {
- newsel = new LinkedHashSet<Object>();
- } else {
- newsel = new LinkedHashSet<Object>(newsel);
- }
- newsel.removeAll(visibleNotSelected);
- newsel.addAll(acceptedSelections);
- setValue(newsel, true);
- }
- } else {
- // Single select mode
- if (!isNullSelectionAllowed()
- && (clientSideSelectedKeys.length == 0
- || clientSideSelectedKeys[0] == null
- || clientSideSelectedKeys[0] == getNullSelectionItemId())) {
- markAsDirty();
- return;
- }
- if (clientSideSelectedKeys.length == 0) {
- // Allows deselection only if the deselected item is
- // visible
- final Object current = getValue();
- final Collection<?> visible = getVisibleItemIds();
- if (visible != null && visible.contains(current)) {
- setValue(null, true);
- }
- } else {
- String clientSelectedKey = clientSideSelectedKeys[0];
- if ("null".equals(clientSelectedKey)
- || itemIdMapper.containsKey(clientSelectedKey)) {
- // Happens to work for nullselection
- // (get ("null") -> null))
- final Object id = itemIdMapper.get(clientSelectedKey);
-
- if (!isNullSelectionAllowed() && id == null) {
- markAsDirty();
- } else if (id != null
- && id.equals(getNullSelectionItemId())) {
- setValue(null, true);
- } else {
- setValue(id, true);
- }
- }
- }
- }
- }
- }
-
- /**
- * TODO refine doc Setter for new item handler that is called when user adds
- * new item in newItemAllowed mode.
- *
- * @param newItemHandler
- */
- public void setNewItemHandler(NewItemHandler newItemHandler) {
- this.newItemHandler = newItemHandler;
- }
-
- /**
- * TODO refine doc
- *
- * @return
- */
- public NewItemHandler getNewItemHandler() {
- if (newItemHandler == null) {
- newItemHandler = new DefaultNewItemHandler();
- }
- return newItemHandler;
- }
-
- @Deprecated
- public interface NewItemHandler extends Serializable {
- void addNewItem(String newItemCaption);
- }
-
- /**
- * TODO refine doc
- *
- * This is a default class that handles adding new items that are typed by
- * user to selects container.
- *
- * By extending this class one may implement some logic on new item addition
- * like database inserts.
- *
- */
- @Deprecated
- public class DefaultNewItemHandler implements NewItemHandler {
- @Override
- public void addNewItem(String newItemCaption) {
- // Checks for readonly
- if (isReadOnly()) {
- throw new Property.ReadOnlyException();
- }
-
- // Adds new option
- if (addItem(newItemCaption) != null) {
-
- // Sets the caption property, if used
- if (getItemCaptionPropertyId() != null) {
- getContainerProperty(newItemCaption,
- getItemCaptionPropertyId())
- .setValue(newItemCaption);
- }
- if (isMultiSelect()) {
- Set values = new HashSet((Collection) getValue());
- values.add(newItemCaption);
- setValue(values);
- } else {
- setValue(newItemCaption);
- }
- }
- }
- }
-
- /**
- * Gets 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() {
- return getItemIds();
- }
-
- /* Property methods */
-
- /**
- * Returns the type of the property. <code>getValue</code> and
- * <code>setValue</code> methods must be compatible with this type: one can
- * safely cast <code>getValue</code> to given type and pass any variable
- * assignable to this type as a parameter to <code>setValue</code>.
- *
- * @return the Type of the property.
- */
- @Override
- public Class<?> getType() {
- if (isMultiSelect()) {
- return Set.class;
- } else {
- return Object.class;
- }
- }
-
- /**
- * Gets the selected item id or in multiselect mode a set of selected ids.
- *
- * @see AbstractField#getValue()
- */
- @Override
- public Object getValue() {
- final Object retValue = super.getValue();
-
- if (isMultiSelect()) {
-
- // If the return value is not a set
- if (retValue == null) {
- return new HashSet<Object>();
- }
- if (retValue instanceof Set) {
- return Collections.unmodifiableSet((Set<?>) retValue);
- } else if (retValue instanceof Collection) {
- return new HashSet<Object>((Collection<?>) retValue);
- } else {
- final Set<Object> s = new HashSet<Object>();
- if (items.containsId(retValue)) {
- s.add(retValue);
- }
- return s;
- }
-
- } else {
- return retValue;
- }
- }
-
- /**
- * Sets 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
- * the New selected item or collection of selected items.
- * @see AbstractField#setValue(java.lang.Object)
- */
- @Override
- public void setValue(Object newValue) throws Property.ReadOnlyException {
- if (newValue == getNullSelectionItemId()) {
- newValue = null;
- }
-
- setValue(newValue, false);
- }
-
- /**
- * Sets 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>
- *
- * @since 7.5.7
- * @param newValue
- * the New selected item or collection of selected items.
- * @param repaintIsNotNeeded
- * True if caller is sure that repaint is not needed.
- * @param ignoreReadOnly
- * True if read-only check should be omitted.
- * @see AbstractField#setValue(java.lang.Object, java.lang.Boolean)
- */
- @Override
- protected void setValue(Object newFieldValue, boolean repaintIsNotNeeded,
- boolean ignoreReadOnly) throws Property.ReadOnlyException,
- ConversionException, InvalidValueException {
- if (isMultiSelect()) {
- if (newFieldValue == null) {
- super.setValue(new LinkedHashSet<Object>(), repaintIsNotNeeded,
- ignoreReadOnly);
- } else if (Collection.class
- .isAssignableFrom(newFieldValue.getClass())) {
- super.setValue(
- new LinkedHashSet<Object>(
- (Collection<?>) newFieldValue),
- repaintIsNotNeeded, ignoreReadOnly);
- }
- } else if (newFieldValue == null || items.containsId(newFieldValue)) {
- super.setValue(newFieldValue, repaintIsNotNeeded, ignoreReadOnly);
- }
- }
-
- /* Container methods */
-
- /**
- * Gets the item from the container with given id. If the container does not
- * contain the requested item, null is returned.
- *
- * @param itemId
- * the item id.
- * @return the item from the container.
- */
- @Override
- public Item getItem(Object itemId) {
- return items.getItem(itemId);
- }
-
- /**
- * Gets the item Id collection from the container.
- *
- * @return the Collection of item ids.
- */
- @Override
- public Collection<?> getItemIds() {
- return items.getItemIds();
- }
-
- /**
- * Gets the property Id collection from the container.
- *
- * @return the Collection of property ids.
- */
- @Override
- public Collection<?> getContainerPropertyIds() {
- return items.getContainerPropertyIds();
- }
-
- /**
- * Gets the property type.
- *
- * @param propertyId
- * the Id identifying the property.
- * @see Container#getType(java.lang.Object)
- */
- @Override
- public Class<?> getType(Object propertyId) {
- return items.getType(propertyId);
- }
-
- /**
- * Gets the number of items in the container.
- *
- * @return the Number of items in the container.
- *
- * @see Container#size()
- */
- @Override
- public int size() {
- int size = items.size();
- assert size >= 0;
- return size;
- }
-
- /**
- * Tests, if the collection contains an item with given id.
- *
- * @param itemId
- * the Id the of item to be tested.
- */
- @Override
- public boolean containsId(Object itemId) {
- if (itemId != null) {
- return items.containsId(itemId);
- } else {
- return false;
- }
- }
-
- /**
- * Gets the Property identified by the given itemId and propertyId from the
- * Container
- *
- * @see Container#getContainerProperty(Object, Object)
- */
- @Override
- public Property getContainerProperty(Object itemId, Object propertyId) {
- return items.getContainerProperty(itemId, propertyId);
- }
-
- /**
- * Adds the 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 if the operation succeeded.
- * @see Container#addContainerProperty(java.lang.Object, java.lang.Class,
- * java.lang.Object)
- */
- @Override
- public boolean addContainerProperty(Object propertyId, Class<?> type,
- Object defaultValue) throws UnsupportedOperationException {
-
- final boolean retval = items.addContainerProperty(propertyId, type,
- defaultValue);
- if (retval && !(items instanceof Container.PropertySetChangeNotifier)) {
- firePropertySetChange();
- }
- return retval;
- }
-
- /**
- * Removes all items from the container.
- *
- * This functionality is optional. If the function is unsupported, it always
- * returns false.
- *
- * @return True if the operation succeeded.
- * @see Container#removeAllItems()
- */
- @Override
- public boolean removeAllItems() throws UnsupportedOperationException {
-
- final boolean retval = items.removeAllItems();
- itemIdMapper.removeAll();
- if (retval) {
- setValue(null);
- if (!(items instanceof Container.ItemSetChangeNotifier)) {
- fireItemSetChange();
- }
- }
- return retval;
- }
-
- /**
- * Creates 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 the Id of the created item or null in case of failure.
- * @see Container#addItem()
- */
- @Override
- public Object addItem() throws UnsupportedOperationException {
-
- final 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
- * the Identification of the item to be created.
- * @return the Created item with the given id, or null in case of failure.
- * @see Container#addItem(java.lang.Object)
- */
- @Override
- public Item addItem(Object itemId) throws UnsupportedOperationException {
-
- final Item retval = items.addItem(itemId);
- if (retval != null
- && !(items instanceof Container.ItemSetChangeNotifier)) {
- fireItemSetChange();
- }
- return retval;
- }
-
- /**
- * Adds given items with given item ids to container.
- *
- * @since 7.2
- * @param itemId
- * item identifiers to be added to underlying container
- * @throws UnsupportedOperationException
- * if the underlying container don't support adding items with
- * identifiers
- */
- public void addItems(Object... itemId)
- throws UnsupportedOperationException {
- for (Object id : itemId) {
- addItem(id);
- }
- }
-
- /**
- * Adds given items with given item ids to container.
- *
- * @since 7.2
- * @param itemIds
- * item identifiers to be added to underlying container
- * @throws UnsupportedOperationException
- * if the underlying container don't support adding items with
- * identifiers
- */
- public void addItems(Collection<?> itemIds)
- throws UnsupportedOperationException {
- addItems(itemIds.toArray());
- }
-
- @Override
- public boolean removeItem(Object itemId)
- throws UnsupportedOperationException {
-
- unselect(itemId);
- final boolean retval = items.removeItem(itemId);
- itemIdMapper.remove(itemId);
- if (retval && !(items instanceof Container.ItemSetChangeNotifier)) {
- fireItemSetChange();
- }
- return retval;
- }
-
- /**
- * Checks that the current selection is valid, i.e. the selected item ids
- * exist in the container. Updates the selection if one or several selected
- * item ids are no longer available in the container.
- */
- @SuppressWarnings("unchecked")
- public void sanitizeSelection() {
- Object value = getValue();
- if (value == null) {
- return;
- }
-
- boolean changed = false;
-
- if (isMultiSelect()) {
- Collection<Object> valueAsCollection = (Collection<Object>) value;
- List<Object> newSelection = new ArrayList<Object>(
- valueAsCollection.size());
- for (Object subValue : valueAsCollection) {
- if (containsId(subValue)) {
- newSelection.add(subValue);
- } else {
- changed = true;
- }
- }
- if (changed) {
- setValue(newSelection);
- }
- } else {
- if (!containsId(value)) {
- setValue(null);
- }
- }
-
- }
-
- /**
- * Removes the 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 if the operation succeeded.
- * @see Container#removeContainerProperty(java.lang.Object)
- */
- @Override
- public boolean removeContainerProperty(Object propertyId)
- throws UnsupportedOperationException {
-
- final boolean retval = items.removeContainerProperty(propertyId);
- if (retval && !(items instanceof Container.PropertySetChangeNotifier)) {
- firePropertySetChange();
- }
- return retval;
- }
-
- /* Container.Viewer methods */
-
- /**
- * Sets the Container that serves as the data source of the viewer.
- *
- * As a side-effect the fields value (selection) is set to null due old
- * selection not necessary exists in new Container.
- *
- * @see Container.Viewer#setContainerDataSource(Container)
- *
- * @param newDataSource
- * the new data source.
- */
- @Override
- public void setContainerDataSource(Container newDataSource) {
- if (newDataSource == null) {
- newDataSource = new IndexedContainer();
- }
-
- getCaptionChangeListener().clear();
-
- if (items != newDataSource) {
-
- // Removes listeners from the old datasource
- if (items != null) {
- if (items instanceof Container.ItemSetChangeNotifier) {
- ((Container.ItemSetChangeNotifier) items)
- .removeItemSetChangeListener(this);
- }
- if (items instanceof Container.PropertySetChangeNotifier) {
- ((Container.PropertySetChangeNotifier) items)
- .removePropertySetChangeListener(this);
- }
- }
-
- // Assigns new data source
- items = newDataSource;
-
- // Clears itemIdMapper also
- itemIdMapper.removeAll();
-
- // Adds listeners
- if (items != null) {
- if (items instanceof Container.ItemSetChangeNotifier) {
- ((Container.ItemSetChangeNotifier) items)
- .addItemSetChangeListener(this);
- }
- if (items instanceof Container.PropertySetChangeNotifier) {
- ((Container.PropertySetChangeNotifier) items)
- .addPropertySetChangeListener(this);
- }
- }
-
- /*
- * We expect changing the data source should also clean value. See
- * #810, #4607, #5281
- */
- setValue(null);
-
- markAsDirty();
-
- }
- }
-
- /**
- * Gets the viewing data-source container.
- *
- * @see Container.Viewer#getContainerDataSource()
- */
- @Override
- public Container getContainerDataSource() {
- return items;
- }
-
- /* Select attributes */
-
- /**
- * Is the select in multiselect mode? In multiselect mode
- *
- * @return the Value of property multiSelect.
- */
- public boolean isMultiSelect() {
- return multiSelect;
- }
-
- /**
- * Sets the multiselect mode. Setting multiselect mode false may lose
- * selection information: if selected items set contains one or more
- * selected items, only one of the selected items is kept as selected.
- *
- * Subclasses of AbstractSelect can choose not to support changing the
- * multiselect mode, and may throw {@link UnsupportedOperationException}.
- *
- * @param multiSelect
- * the New value of property multiSelect.
- */
- public void setMultiSelect(boolean multiSelect) {
- if (multiSelect && getNullSelectionItemId() != null) {
- throw new IllegalStateException(
- "Multiselect and NullSelectionItemId can not be set at the same time.");
- }
- if (multiSelect != this.multiSelect) {
-
- // Selection before mode change
- final Object oldValue = getValue();
-
- this.multiSelect = multiSelect;
-
- // Convert the value type
- if (multiSelect) {
- final Set<Object> s = new HashSet<Object>();
- if (oldValue != null) {
- s.add(oldValue);
- }
- setValue(s);
- } else {
- final 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());
- }
- }
-
- markAsDirty();
- }
- }
-
- /**
- * 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. Note that data-source must allow adding new items.
- *
- * @return True if additions are allowed.
- */
- public boolean isNewItemsAllowed() {
- return allowNewOptions;
- }
-
- /**
- * Enables or disables possibility to add new options by the user.
- *
- * @param allowNewOptions
- * the New value of property allowNewOptions.
- */
- public void setNewItemsAllowed(boolean allowNewOptions) {
-
- // Only handle change requests
- if (this.allowNewOptions != allowNewOptions) {
-
- this.allowNewOptions = allowNewOptions;
-
- markAsDirty();
- }
- }
-
- /**
- * 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
- * the New caption.
- */
- public void setItemCaption(Object itemId, String caption) {
- if (itemId != null) {
- itemCaptions.put(itemId, caption);
- markAsDirty();
- }
- }
-
- /**
- * Gets 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 the 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 ID:
- caption = idToCaption(itemId);
- break;
- case ID_TOSTRING:
- caption = itemId.toString();
- break;
- case INDEX:
- if (items instanceof Container.Indexed) {
- caption = String
- .valueOf(((Container.Indexed) items).indexOfId(itemId));
- } else {
- caption = "ERROR: Container is not indexed";
- }
- break;
-
- case ITEM:
- final Item i = getItem(itemId);
- if (i != null) {
- caption = i.toString();
- }
- break;
-
- case EXPLICIT:
- caption = itemCaptions.get(itemId);
- break;
-
- case EXPLICIT_DEFAULTS_ID:
- caption = itemCaptions.get(itemId);
- if (caption == null) {
- caption = idToCaption(itemId);
- }
- break;
-
- case PROPERTY:
- final Property<?> p = getContainerProperty(itemId,
- getItemCaptionPropertyId());
- if (p != null) {
- Object value = p.getValue();
- if (value != null) {
- caption = value.toString();
- }
- }
- break;
- }
-
- // All items must have some captions
- return caption != null ? caption : "";
- }
-
- private String idToCaption(Object itemId) {
- try {
- Converter<String, Object> c = (Converter<String, Object>) ConverterUtil
- .getConverter(String.class, itemId.getClass(),
- getSession());
- return ConverterUtil.convertFromModel(itemId, String.class, c,
- getLocale());
- } catch (Exception e) {
- return itemId.toString();
- }
- }
-
- /**
- * Sets the icon for an item.
- *
- * @param itemId
- * the id of the item to be assigned an icon.
- * @param icon
- * the icon to use or null.
- */
- public void setItemIcon(Object itemId, Resource icon) {
- if (itemId != null) {
- if (icon == null) {
- itemIcons.remove(itemId);
- } else {
- itemIcons.put(itemId, icon);
- }
- markAsDirty();
- }
- }
-
- /**
- * Gets the item icon.
- *
- * @param itemId
- * the id of the item to be assigned an icon.
- * @return the icon for the item or null, if not specified.
- */
- public Resource getItemIcon(Object itemId) {
- final Resource explicit = itemIcons.get(itemId);
- if (explicit != null) {
- return explicit;
- }
-
- if (getItemIconPropertyId() == null) {
- return null;
- }
-
- final Property<?> ip = getContainerProperty(itemId,
- getItemIconPropertyId());
- if (ip == null) {
- return null;
- }
- final Object icon = ip.getValue();
- if (icon instanceof Resource) {
- return (Resource) icon;
- }
-
- return null;
- }
-
- /**
- * Sets the item caption mode.
- *
- * See {@link ItemCaptionMode} for a description of the modes.
- * <p>
- * {@link ItemCaptionMode#EXPLICIT_DEFAULTS_ID} is the default mode.
- * </p>
- *
- * @param mode
- * the One of the modes listed above.
- */
- public void setItemCaptionMode(ItemCaptionMode mode) {
- if (mode != null) {
- itemCaptionMode = mode;
- markAsDirty();
- }
- }
-
- /**
- * Gets 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 the One of the modes listed above.
- */
- public ItemCaptionMode getItemCaptionMode() {
- return itemCaptionMode;
- }
-
- /**
- * Sets 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>
- * Note that the type of the property used for caption must be String
- * </p>
- * <p>
- * Setting the property id to null disables this feature. The id is null by
- * default
- * </p>
- * .
- *
- * @param propertyId
- * the id of the property.
- *
- */
- public void setItemCaptionPropertyId(Object propertyId) {
- if (propertyId != null) {
- itemCaptionPropertyId = propertyId;
- setItemCaptionMode(ITEM_CAPTION_MODE_PROPERTY);
- markAsDirty();
- } else {
- itemCaptionPropertyId = null;
- if (getItemCaptionMode() == ITEM_CAPTION_MODE_PROPERTY) {
- setItemCaptionMode(ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID);
- }
- markAsDirty();
- }
- }
-
- /**
- * Gets the item caption property.
- *
- * @return the Id of the property used as item caption source.
- */
- public Object getItemCaptionPropertyId() {
- return itemCaptionPropertyId;
- }
-
- /**
- * Sets 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 Resource.
- * </p>
- *
- * <p>
- * Note : 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
- * the id of the property that specifies icons for items or null
- * @throws IllegalArgumentException
- * If the propertyId is not in the container or is not of a
- * valid type
- */
- public void setItemIconPropertyId(Object propertyId)
- throws IllegalArgumentException {
- if (propertyId == null) {
- itemIconPropertyId = null;
- } else if (!getContainerPropertyIds().contains(propertyId)) {
- throw new IllegalArgumentException(
- "Property id not found in the container");
- } else if (Resource.class.isAssignableFrom(getType(propertyId))) {
- itemIconPropertyId = propertyId;
- } else {
- throw new IllegalArgumentException(
- "Property type must be assignable to Resource");
- }
- markAsDirty();
- }
-
- /**
- * Gets 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 : 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 the Id of the property containing the item icons.
- */
- public Object getItemIconPropertyId() {
- return itemIconPropertyId;
- }
-
- /**
- * Tests 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>
- *
- * @param itemId
- * the Id the of the item to be tested.
- * @see #getNullSelectionItemId()
- * @see #setNullSelectionItemId(Object)
- *
- */
- public boolean isSelected(Object itemId) {
- if (itemId == null) {
- return false;
- }
- if (isMultiSelect()) {
- return ((Set<?>) getValue()).contains(itemId);
- } else {
- final Object value = getValue();
- return itemId
- .equals(value == null ? getNullSelectionItemId() : value);
- }
- }
-
- /**
- * Selects an item.
- *
- * <p>
- * In single select mode selecting item identified by
- * {@link #getNullSelectionItemId()} sets the value of the property to null.
- * </p>
- *
- * @param itemId
- * the identifier of Item to be selected.
- * @see #getNullSelectionItemId()
- * @see #setNullSelectionItemId(Object)
- *
- */
- public void select(Object itemId) {
- if (!isMultiSelect()) {
- setValue(itemId);
- } else if (!isSelected(itemId) && itemId != null
- && items.containsId(itemId)) {
- final Set<Object> s = new HashSet<Object>((Set<?>) getValue());
- s.add(itemId);
- setValue(s);
- }
- }
-
- /**
- * Unselects an item.
- *
- * @param itemId
- * the identifier of the Item to be unselected.
- * @see #getNullSelectionItemId()
- * @see #setNullSelectionItemId(Object)
- *
- */
- public void unselect(Object itemId) {
- if (isSelected(itemId)) {
- if (isMultiSelect()) {
- final Set<Object> s = new HashSet<Object>((Set<?>) getValue());
- s.remove(itemId);
- setValue(s);
- } else {
- setValue(null);
- }
- }
- }
-
- /**
- * Notifies this listener that the Containers contents has changed.
- *
- * @see Container.PropertySetChangeListener#containerPropertySetChange(Container.PropertySetChangeEvent)
- */
- @Override
- public void containerPropertySetChange(
- Container.PropertySetChangeEvent event) {
- firePropertySetChange();
- }
-
- /**
- * Adds a new Property set change listener for this Container.
- *
- * @see Container.PropertySetChangeNotifier#addListener(Container.PropertySetChangeListener)
- */
- @Override
- public void addPropertySetChangeListener(
- Container.PropertySetChangeListener listener) {
- if (propertySetEventListeners == null) {
- propertySetEventListeners = new LinkedHashSet<PropertySetChangeListener>();
- }
- propertySetEventListeners.add(listener);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addPropertySetChangeListener(Container.PropertySetChangeListener)}
- **/
- @Override
- @Deprecated
- public void addListener(Container.PropertySetChangeListener listener) {
- addPropertySetChangeListener(listener);
- }
-
- /**
- * Removes a previously registered Property set change listener.
- *
- * @see Container.PropertySetChangeNotifier#removeListener(Container.PropertySetChangeListener)
- */
- @Override
- public void removePropertySetChangeListener(
- Container.PropertySetChangeListener listener) {
- if (propertySetEventListeners != null) {
- propertySetEventListeners.remove(listener);
- if (propertySetEventListeners.isEmpty()) {
- propertySetEventListeners = null;
- }
- }
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removePropertySetChangeListener(Container.PropertySetChangeListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(Container.PropertySetChangeListener listener) {
- removePropertySetChangeListener(listener);
- }
-
- /**
- * Adds an Item set change listener for the object.
- *
- * @see Container.ItemSetChangeNotifier#addListener(Container.ItemSetChangeListener)
- */
- @Override
- public void addItemSetChangeListener(
- Container.ItemSetChangeListener listener) {
- if (itemSetEventListeners == null) {
- itemSetEventListeners = new LinkedHashSet<ItemSetChangeListener>();
- }
- itemSetEventListeners.add(listener);
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addItemSetChangeListener(Container.ItemSetChangeListener)}
- **/
- @Override
- @Deprecated
- public void addListener(Container.ItemSetChangeListener listener) {
- addItemSetChangeListener(listener);
- }
-
- /**
- * Removes the Item set change listener from the object.
- *
- * @see Container.ItemSetChangeNotifier#removeListener(Container.ItemSetChangeListener)
- */
- @Override
- public void removeItemSetChangeListener(
- Container.ItemSetChangeListener listener) {
- if (itemSetEventListeners != null) {
- itemSetEventListeners.remove(listener);
- if (itemSetEventListeners.isEmpty()) {
- itemSetEventListeners = null;
- }
- }
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeItemSetChangeListener(Container.ItemSetChangeListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(Container.ItemSetChangeListener listener) {
- removeItemSetChangeListener(listener);
- }
-
- @Override
- public Collection<?> getListeners(Class<?> eventType) {
- if (Container.ItemSetChangeEvent.class.isAssignableFrom(eventType)) {
- if (itemSetEventListeners == null) {
- return Collections.EMPTY_LIST;
- } else {
- return Collections
- .unmodifiableCollection(itemSetEventListeners);
- }
- } else if (Container.PropertySetChangeEvent.class
- .isAssignableFrom(eventType)) {
- if (propertySetEventListeners == null) {
- return Collections.EMPTY_LIST;
- } else {
- return Collections
- .unmodifiableCollection(propertySetEventListeners);
- }
- }
-
- return super.getListeners(eventType);
- }
-
- /**
- * Lets the listener know a Containers Item set has changed.
- *
- * @see Container.ItemSetChangeListener#containerItemSetChange(Container.ItemSetChangeEvent)
- */
- @Override
- public void containerItemSetChange(Container.ItemSetChangeEvent event) {
- // Clears the item id mapping table
- itemIdMapper.removeAll();
-
- // Notify all listeners
- fireItemSetChange();
- }
-
- /**
- * Fires the property set change event.
- */
- protected void firePropertySetChange() {
- if (propertySetEventListeners != null
- && !propertySetEventListeners.isEmpty()) {
- final Container.PropertySetChangeEvent event = new PropertySetChangeEvent(
- this);
- final Object[] listeners = propertySetEventListeners.toArray();
- for (int i = 0; i < listeners.length; i++) {
- ((Container.PropertySetChangeListener) listeners[i])
- .containerPropertySetChange(event);
- }
- }
- markAsDirty();
- }
-
- /**
- * Fires the item set change event.
- */
- protected void fireItemSetChange() {
- if (itemSetEventListeners != null && !itemSetEventListeners.isEmpty()) {
- final Container.ItemSetChangeEvent event = new ItemSetChangeEvent(
- this);
- final Object[] listeners = itemSetEventListeners.toArray();
- for (int i = 0; i < listeners.length; i++) {
- ((Container.ItemSetChangeListener) listeners[i])
- .containerItemSetChange(event);
- }
- }
- markAsDirty();
- }
-
- /**
- * Implementation of item set change event.
- */
- private static class ItemSetChangeEvent extends EventObject
- implements Serializable, Container.ItemSetChangeEvent {
-
- private ItemSetChangeEvent(Container source) {
- super(source);
- }
-
- /**
- * Gets the Property where the event occurred.
- *
- * @see Container.ItemSetChangeEvent#getContainer()
- */
- @Override
- public Container getContainer() {
- return (Container) getSource();
- }
-
- }
-
- /**
- * Implementation of property set change event.
- */
- private static class PropertySetChangeEvent extends EventObject
- implements Container.PropertySetChangeEvent, Serializable {
-
- private PropertySetChangeEvent(Container source) {
- super(source);
- }
-
- /**
- * Retrieves the Container whose contents have been modified.
- *
- * @see Container.PropertySetChangeEvent#getContainer()
- */
- @Override
- public Container getContainer() {
- return (Container) getSource();
- }
-
- }
-
- /**
- * For multi-selectable fields, also an empty collection of values is
- * considered to be an empty field.
- *
- * @see LegacyAbstractField#isEmpty().
- */
- @Override
- public boolean isEmpty() {
- if (!multiSelect) {
- return super.isEmpty();
- } else {
- Object value = getValue();
- return super.isEmpty() || (value instanceof Collection
- && ((Collection<?>) value).isEmpty());
- }
- }
-
- /**
- * Allow or disallow empty selection by the user. If the select is in
- * single-select mode, you can make an item represent the empty selection by
- * calling <code>setNullSelectionItemId()</code>. This way you can for
- * instance set an icon and caption for the null selection item.
- *
- * @param nullSelectionAllowed
- * whether or not to allow empty selection
- * @see #setNullSelectionItemId(Object)
- * @see #isNullSelectionAllowed()
- */
- public void setNullSelectionAllowed(boolean nullSelectionAllowed) {
- if (nullSelectionAllowed != this.nullSelectionAllowed) {
- this.nullSelectionAllowed = nullSelectionAllowed;
- markAsDirty();
- }
- }
-
- /**
- * Checks if null empty selection is allowed by the user.
- *
- * @return whether or not empty selection is allowed
- * @see #setNullSelectionAllowed(boolean)
- */
- public boolean isNullSelectionAllowed() {
- return nullSelectionAllowed;
- }
-
- /**
- * 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
- * identified by this id is the same as selecting no items at all. This
- * setting only affects the single select mode.
- * </p>
- *
- * @return the Object Null value item id.
- * @see #setNullSelectionItemId(Object)
- * @see #isSelected(Object)
- * @see #select(Object)
- */
- public 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
- * identified by this id is the same as selecting no items at all. This
- * setting only affects the single select mode.
- * </p>
- *
- * @param nullSelectionItemId
- * the nullSelectionItemId to set.
- * @see #getNullSelectionItemId()
- * @see #isSelected(Object)
- * @see #select(Object)
- */
- public void setNullSelectionItemId(Object nullSelectionItemId) {
- if (nullSelectionItemId != null && isMultiSelect()) {
- throw new IllegalStateException(
- "Multiselect and NullSelectionItemId can not be set at the same time.");
- }
- this.nullSelectionItemId = nullSelectionItemId;
- }
-
- /**
- * Notifies the component that it is connected to an application.
- *
- * @see AbstractField#attach()
- */
- @Override
- public void attach() {
- super.attach();
- }
-
- /**
- * Detaches the component from application.
- *
- * @see vaadin.ui.AbstractComponent#detach()
- */
- @Override
- public void detach() {
- getCaptionChangeListener().clear();
- super.detach();
- }
-
- // Caption change listener
- protected CaptionChangeListener getCaptionChangeListener() {
- if (captionChangeListener == null) {
- captionChangeListener = new CaptionChangeListener();
- }
- return captionChangeListener;
- }
-
- /**
- * This is a listener helper for Item and Property changes that should cause
- * a repaint. It should be attached to all items that are displayed, and the
- * default implementation does this in paintContent(). Especially
- * "lazyloading" components should take care to add and remove listeners as
- * appropriate. Call addNotifierForItem() for each painted item (and
- * remember to clear).
- *
- * NOTE: singleton, use getCaptionChangeListener().
- *
- */
- @Deprecated
- protected class CaptionChangeListener implements
- Item.PropertySetChangeListener, Property.ValueChangeListener {
-
- // TODO clean this up - type is either Item.PropertySetChangeNotifier or
- // Property.ValueChangeNotifier
- HashSet<Object> captionChangeNotifiers = new HashSet<Object>();
-
- public void addNotifierForItem(Object itemId) {
- switch (getItemCaptionMode()) {
- case ITEM:
- final Item i = getItem(itemId);
- if (i == null) {
- return;
- }
- if (i instanceof Item.PropertySetChangeNotifier) {
- ((Item.PropertySetChangeNotifier) i)
- .addPropertySetChangeListener(
- getCaptionChangeListener());
- captionChangeNotifiers.add(i);
- }
- Collection<?> pids = i.getItemPropertyIds();
- if (pids != null) {
- for (Iterator<?> it = pids.iterator(); it.hasNext();) {
- Property<?> p = i.getItemProperty(it.next());
- if (p != null
- && p instanceof Property.ValueChangeNotifier) {
- ((Property.ValueChangeNotifier) p)
- .addValueChangeListener(
- getCaptionChangeListener());
- captionChangeNotifiers.add(p);
- }
- }
-
- }
- break;
- case PROPERTY:
- final Property<?> p = getContainerProperty(itemId,
- getItemCaptionPropertyId());
- if (p != null && p instanceof Property.ValueChangeNotifier) {
- ((Property.ValueChangeNotifier) p)
- .addValueChangeListener(getCaptionChangeListener());
- captionChangeNotifiers.add(p);
- }
- break;
-
- }
- if (getItemIconPropertyId() != null) {
- final Property p = getContainerProperty(itemId,
- getItemIconPropertyId());
- if (p != null && p instanceof Property.ValueChangeNotifier) {
- ((Property.ValueChangeNotifier) p)
- .addValueChangeListener(getCaptionChangeListener());
- captionChangeNotifiers.add(p);
- }
- }
- }
-
- public void clear() {
- for (Iterator<Object> it = captionChangeNotifiers.iterator(); it
- .hasNext();) {
- Object notifier = it.next();
- if (notifier instanceof Item.PropertySetChangeNotifier) {
- ((Item.PropertySetChangeNotifier) notifier)
- .removePropertySetChangeListener(
- getCaptionChangeListener());
- } else {
- ((Property.ValueChangeNotifier) notifier)
- .removeValueChangeListener(
- getCaptionChangeListener());
- }
- }
- captionChangeNotifiers.clear();
- }
-
- @Override
- public void valueChange(Property.ValueChangeEvent event) {
- markAsDirty();
- }
-
- @Override
- public void itemPropertySetChange(Item.PropertySetChangeEvent event) {
- markAsDirty();
- }
-
- }
-
- /**
- * Criterion which accepts a drop only if the drop target is (one of) the
- * given Item identifier(s). Criterion can be used only on a drop targets
- * that extends AbstractSelect like {@link Table} and {@link Tree}. The
- * target and identifiers of valid Items are given in constructor.
- *
- * @since 6.3
- */
- @Deprecated
- public static class TargetItemIs extends AbstractItemSetCriterion {
-
- /**
- * @param select
- * the select implementation that is used as a drop target
- * @param itemId
- * the identifier(s) that are valid drop locations
- */
- public TargetItemIs(AbstractSelect select, Object... itemId) {
- super(select, itemId);
- }
-
- @Override
- public boolean accept(DragAndDropEvent dragEvent) {
- AbstractSelectTargetDetails dropTargetData = (AbstractSelectTargetDetails) dragEvent
- .getTargetDetails();
- if (dropTargetData.getTarget() != select) {
- return false;
- }
- return itemIds.contains(dropTargetData.getItemIdOver());
- }
-
- }
-
- /**
- * Abstract helper class to implement item id based criterion.
- *
- * Note, inner class used not to open itemIdMapper for public access.
- *
- * @since 6.3
- *
- */
- private abstract static class AbstractItemSetCriterion
- extends ClientSideCriterion {
- protected final Collection<Object> itemIds = new HashSet<Object>();
- protected AbstractSelect select;
-
- public AbstractItemSetCriterion(AbstractSelect select,
- Object... itemId) {
- if (itemIds == null || select == null) {
- throw new IllegalArgumentException(
- "Accepted item identifiers must be accepted.");
- }
- Collections.addAll(itemIds, itemId);
- this.select = select;
- }
-
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
- super.paintContent(target);
- String[] keys = new String[itemIds.size()];
- int i = 0;
- for (Object itemId : itemIds) {
- String key = select.itemIdMapper.key(itemId);
- keys[i++] = key;
- }
- target.addAttribute("keys", keys);
- target.addAttribute("s", select);
- }
-
- }
-
- /**
- * This criterion accepts a only a {@link Transferable} that contains given
- * Item (practically its identifier) from a specific AbstractSelect.
- *
- * @since 6.3
- */
- @Deprecated
- public static class AcceptItem extends AbstractItemSetCriterion {
-
- /**
- * @param select
- * the select from which the item id's are checked
- * @param itemId
- * the item identifier(s) of the select that are accepted
- */
- public AcceptItem(AbstractSelect select, Object... itemId) {
- super(select, itemId);
- }
-
- @Override
- public boolean accept(DragAndDropEvent dragEvent) {
- DataBoundTransferable transferable = (DataBoundTransferable) dragEvent
- .getTransferable();
- if (transferable.getSourceComponent() != select) {
- return false;
- }
- return itemIds.contains(transferable.getItemId());
- }
-
- /**
- * A simple accept criterion which ensures that {@link Transferable}
- * contains an {@link Item} (or actually its identifier). In other words
- * the criterion check that drag is coming from a {@link Container} like
- * {@link Tree} or {@link Table}.
- */
- public static final ClientSideCriterion ALL = new ContainsDataFlavor(
- "itemId");
-
- }
-
- /**
- * TargetDetails implementation for subclasses of {@link AbstractSelect}
- * that implement {@link DropTarget}.
- *
- * @since 6.3
- */
- @Deprecated
- public class AbstractSelectTargetDetails extends TargetDetailsImpl {
-
- /**
- * The item id over which the drag event happened.
- */
- protected Object idOver;
-
- /**
- * Constructor that automatically converts itemIdOver key to
- * corresponding item Id
- *
- */
- protected AbstractSelectTargetDetails(
- Map<String, Object> rawVariables) {
- super(rawVariables, (DropTarget) AbstractSelect.this);
- // eagar fetch itemid, mapper may be emptied
- String keyover = (String) getData("itemIdOver");
- if (keyover != null) {
- idOver = itemIdMapper.get(keyover);
- }
- }
-
- /**
- * If the drag operation is currently over an {@link Item}, this method
- * returns the identifier of that {@link Item}.
- *
- */
- public Object getItemIdOver() {
- return idOver;
- }
-
- /**
- * Returns a detailed vertical location where the drop happened on Item.
- */
- public VerticalDropLocation getDropLocation() {
- String detail = (String) getData("detail");
- if (detail == null) {
- return null;
- }
- return VerticalDropLocation.valueOf(detail);
- }
-
- }
-
- /**
- * An accept criterion to accept drops only on a specific vertical location
- * of an item.
- * <p>
- * This accept criterion is currently usable in Tree and Table
- * implementations.
- */
- @Deprecated
- public static class VerticalLocationIs extends TargetDetailIs {
- public static VerticalLocationIs TOP = new VerticalLocationIs(
- VerticalDropLocation.TOP);
- public static VerticalLocationIs BOTTOM = new VerticalLocationIs(
- VerticalDropLocation.BOTTOM);
- public static VerticalLocationIs MIDDLE = new VerticalLocationIs(
- VerticalDropLocation.MIDDLE);
-
- private VerticalLocationIs(VerticalDropLocation l) {
- super("detail", l.name());
- }
- }
-
- /**
- * Implement this interface and pass it to Tree.setItemDescriptionGenerator
- * or Table.setItemDescriptionGenerator to generate mouse over descriptions
- * ("tooltips") for the rows and cells in Table or for the items in Tree.
- */
- @Deprecated
- public interface ItemDescriptionGenerator extends Serializable {
-
- /**
- * Called by Table when a cell (and row) is painted or a item is painted
- * in Tree
- *
- * @param source
- * The source of the generator, the Tree or Table the
- * generator is attached to
- * @param itemId
- * The itemId of the painted cell
- * @param propertyId
- * The propertyId of the cell, null when getting row
- * description
- * @return The description or "tooltip" of the item.
- */
- public String generateDescription(Component source, Object itemId,
- Object propertyId);
- }
-
- @Override
- public void readDesign(Element design, DesignContext context) {
- // handle default attributes
- super.readDesign(design, context);
- // handle children specifying selectable items (<option>)
- readItems(design, context);
- }
-
- protected void readItems(Element design, DesignContext context) {
- Set<String> selected = new HashSet<String>();
- for (Element child : design.children()) {
- readItem(child, selected, context);
- }
- if (!selected.isEmpty()) {
- if (isMultiSelect()) {
- setValue(selected, false, true);
- } else if (selected.size() == 1) {
- setValue(selected.iterator().next(), false, true);
- } else {
- throw new DesignException(
- "Multiple values selected for a single select component");
- }
- }
- }
-
- /**
- * Reads an Item from a design and inserts it into the data source.
- * Hierarchical select components should override this method to recursively
- * recursively read any child items as well.
- *
- * @since 7.5.0
- * @param child
- * a child element representing the item
- * @param selected
- * A set accumulating selected items. If the item that is read is
- * marked as selected, its item id should be added to this set.
- * @param context
- * the DesignContext instance used in parsing
- * @return the item id of the new item
- *
- * @throws DesignException
- * if the tag name of the {@code child} element is not
- * {@code option}.
- */
- protected Object readItem(Element child, Set<String> selected,
- DesignContext context) {
- if (!"option".equals(child.tagName())) {
- throw new DesignException("Unrecognized child element in "
- + getClass().getSimpleName() + ": " + child.tagName());
- }
-
- String itemId;
- String caption = DesignFormatter.decodeFromTextNode(child.html());
- if (child.hasAttr("item-id")) {
- itemId = child.attr("item-id");
- addItem(itemId);
- setItemCaption(itemId, caption);
- } else {
- addItem(itemId = caption);
- }
-
- if (child.hasAttr("icon")) {
- setItemIcon(itemId, DesignAttributeHandler.readAttribute("icon",
- child.attributes(), Resource.class));
- }
-
- if (child.hasAttr("selected")) {
- selected.add(itemId);
- }
-
- return itemId;
- }
-
- @Override
- public void writeDesign(Element design, DesignContext context) {
- // Write default attributes
- super.writeDesign(design, context);
-
- // Write options if warranted
- if (context.shouldWriteData(this)) {
- writeItems(design, context);
- }
- }
-
- /**
- * Writes the data source items to a design. Hierarchical select components
- * should override this method to only write the root items.
- *
- * @since 7.5.0
- * @param design
- * the element into which to insert the items
- * @param context
- * the DesignContext instance used in writing
- */
- protected void writeItems(Element design, DesignContext context) {
- for (Object itemId : getItemIds()) {
- writeItem(design, itemId, context);
- }
- }
-
- /**
- * Writes a data source Item to a design. Hierarchical select components
- * should override this method to recursively write any child items as well.
- *
- * @since 7.5.0
- * @param design
- * the element into which to insert the item
- * @param itemId
- * the id of the item to write
- * @param context
- * the DesignContext instance used in writing
- * @return
- */
- protected Element writeItem(Element design, Object itemId,
- DesignContext context) {
- Element element = design.appendElement("option");
-
- String caption = getItemCaption(itemId);
- if (caption != null && !caption.equals(itemId.toString())) {
- element.html(DesignFormatter.encodeForTextNode(caption));
- element.attr("item-id", itemId.toString());
- } else {
- element.html(DesignFormatter.encodeForTextNode(itemId.toString()));
- }
-
- Resource icon = getItemIcon(itemId);
- if (icon != null) {
- DesignAttributeHandler.writeAttribute("icon", element.attributes(),
- icon, null, Resource.class, context);
- }
-
- if (isSelected(itemId)) {
- element.attr("selected", "");
- }
-
- return element;
- }
-
- @Override
- protected AbstractSelectState getState() {
- return (AbstractSelectState) super.getState();
- }
-
- @Override
- protected AbstractSelectState getState(boolean markAsDirty) {
- return (AbstractSelectState) super.getState(markAsDirty);
- }
- }
|