123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711 |
- /*
- * Copyright 2000-2014 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.data.util;
-
- import java.util.Collection;
- import java.util.Hashtable;
- import java.util.Iterator;
- import java.util.LinkedList;
-
- import com.vaadin.data.Container;
- import com.vaadin.data.Item;
- import com.vaadin.data.Property;
-
- /**
- * <p>
- * A wrapper class for adding external ordering to containers not implementing
- * the {@link com.vaadin.data.Container.Ordered} interface.
- * </p>
- *
- * <p>
- * If the wrapped container is changed directly (that is, not through the
- * wrapper), and does not implement Container.ItemSetChangeNotifier and/or
- * Container.PropertySetChangeNotifier the hierarchy information must be updated
- * with the {@link #updateOrderWrapper()} method.
- * </p>
- *
- * @author Vaadin Ltd.
- * @since 3.0
- */
- @SuppressWarnings("serial")
- public class ContainerOrderedWrapper implements Container.Ordered,
- Container.ItemSetChangeNotifier, Container.PropertySetChangeNotifier {
-
- /**
- * The wrapped container
- */
- private final Container container;
-
- /**
- * Ordering information, ie. the mapping from Item ID to the next item ID.
- * The last item id should not be present
- */
- private Hashtable<Object, Object> next;
-
- /**
- * Reverse ordering information for convenience and performance reasons. The
- * first item id should not be present
- */
- private Hashtable<Object, Object> prev;
-
- /**
- * ID of the first Item in the container.
- */
- private Object first;
-
- /**
- * ID of the last Item in the container.
- */
- private Object last;
-
- /**
- * Is the wrapped container ordered by itself, ie. does it implement the
- * Container.Ordered interface by itself? If it does, this class will use
- * the methods of the underlying container directly.
- */
- private boolean ordered = false;
-
- /**
- * The last known size of the wrapped container. Used to check whether items
- * have been added or removed to the wrapped container, when the wrapped
- * container does not send ItemSetChangeEvents.
- */
- private int lastKnownSize = -1;
-
- /**
- * Constructs a new ordered wrapper for an existing Container. Works even if
- * the to-be-wrapped container already implements the Container.Ordered
- * interface.
- *
- * @param toBeWrapped
- * the container whose contents need to be ordered.
- */
- public ContainerOrderedWrapper(Container toBeWrapped) {
-
- container = toBeWrapped;
- ordered = container instanceof Container.Ordered;
-
- // Checks arguments
- if (container == null) {
- throw new NullPointerException("Null can not be wrapped");
- }
-
- // Creates initial order if needed
- updateOrderWrapper();
- }
-
- /**
- * Removes the specified Item from the wrapper's internal hierarchy
- * structure.
- * <p>
- * Note : The Item is not removed from the underlying Container.
- * </p>
- *
- * @param id
- * the ID of the Item to be removed from the ordering.
- */
- private void removeFromOrderWrapper(Object id) {
- if (id != null) {
- final Object pid = prev.get(id);
- final Object nid = next.get(id);
- if (first.equals(id)) {
- first = nid;
- }
- if (last.equals(id)) {
- last = pid;
- }
- if (nid != null) {
- if (pid == null) {
- prev.remove(nid);
- } else {
- prev.put(nid, pid);
- }
- }
- if (pid != null) {
- if (nid == null) {
- next.remove(pid);
- } else {
- next.put(pid, nid);
- }
- }
- next.remove(id);
- prev.remove(id);
- }
- }
-
- /**
- * Registers the specified Item to the last position in the wrapper's
- * internal ordering. The underlying container is not modified.
- *
- * @param id
- * the ID of the Item to be added to the ordering.
- */
- private void addToOrderWrapper(Object id) {
-
- // Adds the if to tail
- if (last != null) {
- next.put(last, id);
- prev.put(id, last);
- last = id;
- } else {
- first = last = id;
- }
- }
-
- /**
- * Registers the specified Item after the specified itemId in the wrapper's
- * internal ordering. The underlying container is not modified. Given item
- * id must be in the container, or must be null.
- *
- * @param id
- * the ID of the Item to be added to the ordering.
- * @param previousItemId
- * the Id of the previous item.
- */
- private void addToOrderWrapper(Object id, Object previousItemId) {
-
- if (last == previousItemId || last == null) {
- addToOrderWrapper(id);
- } else {
- if (previousItemId == null) {
- next.put(id, first);
- prev.put(first, id);
- first = id;
- } else {
- prev.put(id, previousItemId);
- next.put(id, next.get(previousItemId));
- prev.put(next.get(previousItemId), id);
- next.put(previousItemId, id);
- }
- }
- }
-
- /**
- * Updates the wrapper's internal ordering information to include all Items
- * in the underlying container.
- * <p>
- * Note : If the contents of the wrapped container change without the
- * wrapper's knowledge, this method needs to be called to update the
- * ordering information of the Items.
- * </p>
- */
- public void updateOrderWrapper() {
-
- if (!ordered) {
-
- final Collection<?> ids = container.getItemIds();
-
- // Recreates ordering if some parts of it are missing
- if (next == null || first == null || last == null || prev == null) {
- first = null;
- last = null;
- next = new Hashtable<Object, Object>();
- prev = new Hashtable<Object, Object>();
- }
-
- // Filter out all the missing items
- final LinkedList<?> l = new LinkedList<Object>(next.keySet());
- for (final Iterator<?> i = l.iterator(); i.hasNext();) {
- final Object id = i.next();
- if (!container.containsId(id)) {
- removeFromOrderWrapper(id);
- }
- }
-
- // Adds missing items
- for (final Iterator<?> i = ids.iterator(); i.hasNext();) {
- final Object id = i.next();
- if (!next.containsKey(id) && last != id) {
- addToOrderWrapper(id);
- }
- }
- }
- }
-
- /*
- * Gets the first item stored in the ordered container Don't add a JavaDoc
- * comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public Object firstItemId() {
- if (ordered) {
- return ((Container.Ordered) container).firstItemId();
- }
- return first;
- }
-
- /*
- * Tests if the given item is the first item in the container Don't add a
- * JavaDoc comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public boolean isFirstId(Object itemId) {
- if (ordered) {
- return ((Container.Ordered) container).isFirstId(itemId);
- }
- return first != null && first.equals(itemId);
- }
-
- /*
- * Tests if the given item is the last item in the container Don't add a
- * JavaDoc comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public boolean isLastId(Object itemId) {
- if (ordered) {
- return ((Container.Ordered) container).isLastId(itemId);
- }
- return last != null && last.equals(itemId);
- }
-
- /*
- * Gets the last item stored in the ordered container Don't add a JavaDoc
- * comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public Object lastItemId() {
- if (ordered) {
- return ((Container.Ordered) container).lastItemId();
- }
- return last;
- }
-
- /*
- * Gets the item that is next from the specified item. Don't add a JavaDoc
- * comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public Object nextItemId(Object itemId) {
- if (ordered) {
- return ((Container.Ordered) container).nextItemId(itemId);
- }
- if (itemId == null) {
- return null;
- }
- return next.get(itemId);
- }
-
- /*
- * Gets the item that is previous from the specified item. Don't add a
- * JavaDoc comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public Object prevItemId(Object itemId) {
- if (ordered) {
- return ((Container.Ordered) container).prevItemId(itemId);
- }
- if (itemId == null) {
- return null;
- }
- return prev.get(itemId);
- }
-
- /**
- * Registers a new Property to all Items in the Container.
- *
- * @param propertyId
- * the ID of the new Property.
- * @param type
- * the Data type of the new Property.
- * @param defaultValue
- * the value all created Properties are initialized to.
- * @return <code>true</code> if the operation succeeded, <code>false</code>
- * if not
- */
- @Override
- public boolean addContainerProperty(Object propertyId, Class<?> type,
- Object defaultValue) throws UnsupportedOperationException {
-
- return container.addContainerProperty(propertyId, type, defaultValue);
- }
-
- /**
- * Creates a new Item into the Container, assigns it an automatic ID, and
- * adds it to the ordering.
- *
- * @return the autogenerated ID of the new Item or <code>null</code> if the
- * operation failed
- * @throws UnsupportedOperationException
- * if the addItem is not supported.
- */
- @Override
- public Object addItem() throws UnsupportedOperationException {
-
- final Object id = container.addItem();
- if (!ordered && id != null) {
- addToOrderWrapper(id);
- }
- return id;
- }
-
- /**
- * Registers a new Item by its ID to the underlying container and to the
- * ordering.
- *
- * @param itemId
- * the ID of the Item to be created.
- * @return the added Item or <code>null</code> if the operation failed
- * @throws UnsupportedOperationException
- * if the addItem is not supported.
- */
- @Override
- public Item addItem(Object itemId) throws UnsupportedOperationException {
- final Item item = container.addItem(itemId);
- if (!ordered && item != null) {
- addToOrderWrapper(itemId);
- }
- return item;
- }
-
- /**
- * Removes all items from the underlying container and from the ordering.
- *
- * @return <code>true</code> if the operation succeeded, otherwise
- * <code>false</code>
- * @throws UnsupportedOperationException
- * if the removeAllItems is not supported.
- */
- @Override
- public boolean removeAllItems() throws UnsupportedOperationException {
- final boolean success = container.removeAllItems();
- if (!ordered && success) {
- first = last = null;
- next.clear();
- prev.clear();
- }
- return success;
- }
-
- /**
- * Removes an Item specified by the itemId from the underlying container and
- * from the ordering.
- *
- * @param itemId
- * the ID of the Item to be removed.
- * @return <code>true</code> if the operation succeeded, <code>false</code>
- * if not
- * @throws UnsupportedOperationException
- * if the removeItem is not supported.
- */
- @Override
- public boolean removeItem(Object itemId)
- throws UnsupportedOperationException {
-
- final boolean success = container.removeItem(itemId);
- if (!ordered && success) {
- removeFromOrderWrapper(itemId);
- }
- return success;
- }
-
- /**
- * Removes the specified Property from the underlying container and from the
- * ordering.
- * <p>
- * Note : The Property will be removed from all the Items in the Container.
- * </p>
- *
- * @param propertyId
- * the ID of the Property to remove.
- * @return <code>true</code> if the operation succeeded, <code>false</code>
- * if not
- * @throws UnsupportedOperationException
- * if the removeContainerProperty is not supported.
- */
- @Override
- public boolean removeContainerProperty(Object propertyId)
- throws UnsupportedOperationException {
- return container.removeContainerProperty(propertyId);
- }
-
- /*
- * Does the container contain the specified Item? Don't add a JavaDoc
- * comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public boolean containsId(Object itemId) {
- return container.containsId(itemId);
- }
-
- /*
- * Gets the specified Item from the container. Don't add a JavaDoc comment
- * here, we use the default documentation from implemented interface.
- */
- @Override
- public Item getItem(Object itemId) {
- return container.getItem(itemId);
- }
-
- /*
- * Gets the ID's of all Items stored in the Container Don't add a JavaDoc
- * comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public Collection<?> getItemIds() {
- return container.getItemIds();
- }
-
- /*
- * Gets the Property identified by the given itemId and propertyId from the
- * Container Don't add a JavaDoc comment here, we use the default
- * documentation from implemented interface.
- */
- @Override
- public Property getContainerProperty(Object itemId, Object propertyId) {
- return container.getContainerProperty(itemId, propertyId);
- }
-
- /*
- * Gets the ID's of all Properties stored in the Container Don't add a
- * JavaDoc comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public Collection<?> getContainerPropertyIds() {
- return container.getContainerPropertyIds();
- }
-
- /*
- * Gets the data type of all Properties identified by the given Property ID.
- * Don't add a JavaDoc comment here, we use the default documentation from
- * implemented interface.
- */
- @Override
- public Class<?> getType(Object propertyId) {
- return container.getType(propertyId);
- }
-
- /*
- * Gets the number of Items in the Container. Don't add a JavaDoc comment
- * here, we use the default documentation from implemented interface.
- */
- @Override
- public int size() {
- int newSize = container.size();
- assert newSize >= 0;
- if (lastKnownSize != -1 && newSize != lastKnownSize
- && !(container instanceof Container.ItemSetChangeNotifier)) {
- // Update the internal cache when the size of the container changes
- // and the container is incapable of sending ItemSetChangeEvents
- updateOrderWrapper();
- }
- lastKnownSize = newSize;
- return newSize;
- }
-
- /*
- * Registers a new Item set change listener for this Container. Don't add a
- * JavaDoc comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public void addItemSetChangeListener(
- Container.ItemSetChangeListener listener) {
- if (container instanceof Container.ItemSetChangeNotifier) {
- ((Container.ItemSetChangeNotifier) container)
- .addItemSetChangeListener(new PiggybackListener(listener));
- }
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addItemSetChangeListener(com.vaadin.data.Container.ItemSetChangeListener)}
- **/
- @Override
- @Deprecated
- public void addListener(Container.ItemSetChangeListener listener) {
- addItemSetChangeListener(listener);
- }
-
- /*
- * Removes a Item set change listener from the object. Don't add a JavaDoc
- * comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public void removeItemSetChangeListener(
- Container.ItemSetChangeListener listener) {
- if (container instanceof Container.ItemSetChangeNotifier) {
- ((Container.ItemSetChangeNotifier) container)
- .removeItemSetChangeListener(new PiggybackListener(listener));
- }
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removeItemSetChangeListener(com.vaadin.data.Container.ItemSetChangeListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(Container.ItemSetChangeListener listener) {
- removeItemSetChangeListener(listener);
- }
-
- /*
- * Registers a new Property set change listener for this Container. Don't
- * add a JavaDoc comment here, we use the default documentation from
- * implemented interface.
- */
- @Override
- public void addPropertySetChangeListener(
- Container.PropertySetChangeListener listener) {
- if (container instanceof Container.PropertySetChangeNotifier) {
- ((Container.PropertySetChangeNotifier) container)
- .addPropertySetChangeListener(new PiggybackListener(
- listener));
- }
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #addPropertySetChangeListener(com.vaadin.data.Container.PropertySetChangeListener)}
- **/
- @Override
- @Deprecated
- public void addListener(Container.PropertySetChangeListener listener) {
- addPropertySetChangeListener(listener);
- }
-
- /*
- * Removes a Property set change listener from the object. Don't add a
- * JavaDoc comment here, we use the default documentation from implemented
- * interface.
- */
- @Override
- public void removePropertySetChangeListener(
- Container.PropertySetChangeListener listener) {
- if (container instanceof Container.PropertySetChangeNotifier) {
- ((Container.PropertySetChangeNotifier) container)
- .removePropertySetChangeListener(new PiggybackListener(
- listener));
- }
- }
-
- /**
- * @deprecated As of 7.0, replaced by
- * {@link #removePropertySetChangeListener(com.vaadin.data.Container.PropertySetChangeListener)}
- **/
- @Override
- @Deprecated
- public void removeListener(Container.PropertySetChangeListener listener) {
- removePropertySetChangeListener(listener);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object,
- * java.lang.Object)
- */
- @Override
- public Item addItemAfter(Object previousItemId, Object newItemId)
- throws UnsupportedOperationException {
-
- // If the previous item is not in the container, fail
- if (previousItemId != null && !containsId(previousItemId)) {
- return null;
- }
-
- // Adds the item to container
- final Item item = container.addItem(newItemId);
-
- // Puts the new item to its correct place
- if (!ordered && item != null) {
- addToOrderWrapper(newItemId, previousItemId);
- }
-
- return item;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object)
- */
- @Override
- public Object addItemAfter(Object previousItemId)
- throws UnsupportedOperationException {
-
- // If the previous item is not in the container, fail
- if (previousItemId != null && !containsId(previousItemId)) {
- return null;
- }
-
- // Adds the item to container
- final Object id = container.addItem();
-
- // Puts the new item to its correct place
- if (!ordered && id != null) {
- addToOrderWrapper(id, previousItemId);
- }
-
- return id;
- }
-
- /**
- * This listener 'piggybacks' on the real listener in order to update the
- * wrapper when needed. It proxies equals() and hashCode() to the real
- * listener so that the correct listener gets removed.
- *
- */
- private class PiggybackListener implements
- Container.PropertySetChangeListener,
- Container.ItemSetChangeListener {
-
- Object listener;
-
- public PiggybackListener(Object realListener) {
- listener = realListener;
- }
-
- @Override
- public void containerItemSetChange(ItemSetChangeEvent event) {
- updateOrderWrapper();
- ((Container.ItemSetChangeListener) listener)
- .containerItemSetChange(event);
-
- }
-
- @Override
- public void containerPropertySetChange(PropertySetChangeEvent event) {
- updateOrderWrapper();
- ((Container.PropertySetChangeListener) listener)
- .containerPropertySetChange(event);
-
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj == listener || (obj != null && obj.equals(listener));
- }
-
- @Override
- public int hashCode() {
- return listener.hashCode();
- }
-
- }
-
- }
|