123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- /* *************************************************************************
-
- Enably Toolkit
-
- Development of Browser User Intarfaces Made Easy
-
- Copyright (C) 2000-2006 IT Mill Ltd
-
- *************************************************************************
-
- This product is distributed under commercial license that can be found
- from the product package on license/license.txt. Use of this product might
- require purchasing a commercial license from IT Mill Ltd. For guidelines
- on usage, see license/licensing-guidelines.html
-
- *************************************************************************
-
- For more information, contact:
-
- IT Mill Ltd phone: +358 2 4802 7180
- Ruukinkatu 2-4 fax: +358 2 4802 7181
- 20540, Turku email: info@enably.com
- Finland company www: www.enably.com
-
- Primary source for information and releases: www.enably.com
-
- ********************************************************************** */
-
- package com.enably.tk.data.util;
-
- import java.util.Collection;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.Hashtable;
-
- import com.enably.tk.data.Container;
- import com.enably.tk.data.Item;
- import com.enably.tk.data.Property;
-
- /** <p>A wrapper class for adding external ordering to containers not
- * implementing the {@link com.enably.tk.data.Container.Ordered}
- * interface.</p>
- *
- * <p>If the wrapped container is changed directly (that is, not through
- * the wrapper), the ordering must be updated with the
- * {@link #updateOrderWrapper()} method.</p>
- *
- * @author IT Mill Ltd.
- * @version @VERSION@
- * @since 3.0
- */
- public class ContainerOrderedWrapper
- implements
- Container.Ordered,
- Container.ItemSetChangeNotifier,
- Container.PropertySetChangeNotifier {
-
- /** The wrapped container */
- private Container container;
-
- /** Ordering information, ie. the mapping from Item ID to the next
- * item ID
- */
- private Hashtable next;
-
- /** Reverse ordering information for convenience and performance
- * reasons.
- */
- private Hashtable 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;
-
- /** 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;
-
- // Check arguments
- if (container == null)
- throw new NullPointerException("Null can not be wrapped");
-
- // Create initial order if needed
- updateOrderWrapper();
- }
-
- /** Removes the specified Item from the wrapper's internal hierarchy
- * structure. Note that the Item is not removed from the underlying
- * Container.
- *
- * @param id ID of the Item to be removed from the ordering
- */
- private void removeFromOrderWrapper(Object id) {
- if (id != null) {
- Object pid = prev.get(id);
- Object nid = next.get(id);
- if (first.equals(id))
- first = nid;
- if (last.equals(id))
- first = pid;
- if (nid != null)
- prev.put(nid, pid);
- if (pid != null)
- next.put(pid, nid);
- next.remove(id);
- prev.remove(id);
- }
- }
-
- /** Adds the specified Item to the last position in the wrapper's
- * internal ordering. The underlying container is not modified.
- *
- * @param id ID of the Item to be added to the ordering
- */
- private void addToOrderWrapper(Object id) {
-
- // Add the if to tail
- if (last != null) {
- next.put(last, id);
- prev.put(id, last);
- last = id;
- } else {
- first = last = id;
- }
- }
-
- /** Adds 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 ID of the Item to be added to the ordering
- */
- 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. 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.
- */
- public void updateOrderWrapper() {
-
- if (!ordered) {
-
- Collection ids = container.getItemIds();
-
- // Recreate ordering if some parts of it are missing
- if (next == null
- || first == null
- || last == null
- || prev != null) {
- first = null;
- last = null;
- next = new Hashtable();
- prev = new Hashtable();
- }
-
- // Filter out all the missing items
- LinkedList l = new LinkedList(next.keySet());
- for (Iterator i = l.iterator(); i.hasNext();) {
- Object id = i.next();
- if (!container.containsId(id))
- removeFromOrderWrapper(id);
- }
-
- // Add missing items
- for (Iterator i = ids.iterator(); i.hasNext();) {
- Object id = i.next();
- if (!next.containsKey(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.
- */
- public Object firstItemId() {
- if (ordered)
- return ((Container.Ordered) container).firstItemId();
- return first;
- }
-
- /* Test 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.
- */
- public boolean isFirstId(Object itemId) {
- if (ordered)
- return ((Container.Ordered) container).isFirstId(itemId);
- return first != null && first.equals(itemId);
- }
-
- /* Test 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.
- */
- 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.
- */
- public Object lastItemId() {
- if (ordered)
- return ((Container.Ordered) container).lastItemId();
- return last;
- }
-
- /* Get the item that is next from the specified item.
- * Don't add a JavaDoc comment here, we use the default documentation
- * from implemented interface.
- */
- public Object nextItemId(Object itemId) {
- if (ordered)
- return ((Container.Ordered) container).nextItemId(itemId);
- return next.get(itemId);
- }
-
- /* Get the item that is previous from the specified item.
- * Don't add a JavaDoc comment here, we use the default documentation
- * from implemented interface.
- */
- public Object prevItemId(Object itemId) {
- if (ordered)
- return ((Container.Ordered) container).prevItemId(itemId);
- return prev.get(itemId);
- }
-
- /** Adds a new Property to all Items in the Container.
- *
- * @param propertyId ID of the new Property
- * @param type 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
- */
- 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
- */
- public Object addItem() throws UnsupportedOperationException {
-
- Object id = container.addItem();
- if (id != null)
- addToOrderWrapper(id);
- return id;
- }
-
- /** Adds a new Item by its ID to the underlying container and to the
- * ordering.
- *
- * @return the added Item or <code>null</code> if the operation failed
- */
- public Item addItem(Object itemId) throws UnsupportedOperationException {
- Item item = container.addItem(itemId);
- if (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,
- * <code>false</code> if not
- */
- public boolean removeAllItems() throws UnsupportedOperationException {
- boolean success = container.removeAllItems();
- if (success) {
- first = last = null;
- next.clear();
- prev.clear();
- }
- return success;
- }
-
- /** Removes an Item specified by <code>itemId</code> from the underlying
- * container and from the ordering.
- *
- * @return <code>true</code> if the operation succeeded,
- * <code>false</code> if not
- */
- public boolean removeItem(Object itemId)
- throws UnsupportedOperationException {
-
- boolean success = container.removeItem(itemId);
- if (success)
- removeFromOrderWrapper(itemId);
- return success;
- }
-
- /** Removes the specified Property from the underlying container and
- * from the ordering. Note that the Property will be removed from all
- * Items in the Container.
- *
- * @param propertyId ID of the Property to remove
- * @return <code>true</code> if the operation succeeded,
- * <code>false</code> if not
- */
- 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.
- */
- 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.
- */
- 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.
- */
- 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.
- */
- 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.
- */
- 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.
- */
- 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.
- */
- public int size() {
- return container.size();
- }
-
- /* 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.
- */
- public void addListener(Container.ItemSetChangeListener listener) {
- if (container instanceof Container.ItemSetChangeNotifier)
- ((Container.ItemSetChangeNotifier) container).addListener(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.
- */
- public void removeListener(Container.ItemSetChangeListener listener) {
- if (container instanceof Container.ItemSetChangeNotifier)
- ((Container.ItemSetChangeNotifier) container).removeListener(
- 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.
- */
- public void addListener(Container.PropertySetChangeListener listener) {
- if (container instanceof Container.PropertySetChangeNotifier)
- ((Container.PropertySetChangeNotifier) container).addListener(
- 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.
- */
- public void removeListener(Container.PropertySetChangeListener listener) {
- if (container instanceof Container.PropertySetChangeNotifier)
- ((Container.PropertySetChangeNotifier) container).removeListener(
- listener);
- }
- /**
- * @see com.enably.tk.data.Container.Ordered#addItemAfter(Object, Object)
- */
- 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;
-
- // Add the item to container
- Item item = container.addItem(newItemId);
-
- // Put the new item to its correct place
- if (item != null)
- addToOrderWrapper(newItemId, previousItemId);
-
- return item;
- }
-
- /**
- * @see com.enably.tk.data.Container.Ordered#addItemAfter(Object)
- */
- public Object addItemAfter(Object previousItemId)
- throws UnsupportedOperationException {
-
- // If the previous item is not in the container, fail
- if (previousItemId != null && !containsId(previousItemId))
- return null;
-
- // Add the item to container
- Object id = container.addItem();
-
- // Put the new item to its correct place
- if (id != null)
- addToOrderWrapper(id, previousItemId);
-
- return id;
- }
-
- }
|