Package net.svenbuschbeck.gwt.ao.client

Source Code of net.svenbuschbeck.gwt.ao.client.ActiveList$ReadOnlyRemoveValueHook

/*
* Copyright 2011 Sven Buschbeck.
*
* This file is part of the ActiveObjects library.
*
*  ActiveObjects is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  ActiveObjects is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
*/
package net.svenbuschbeck.gwt.ao.client;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import net.svenbuschbeck.gwt.ao.client.events.HasValueAddedHandlers;
import net.svenbuschbeck.gwt.ao.client.events.HasValueChangedHandlers;
import net.svenbuschbeck.gwt.ao.client.events.HasValueRemovedHandlers;
import net.svenbuschbeck.gwt.ao.client.events.ValueAddedEvent;
import net.svenbuschbeck.gwt.ao.client.events.ValueAddedHandler;
import net.svenbuschbeck.gwt.ao.client.events.ValueChangedEvent;
import net.svenbuschbeck.gwt.ao.client.events.ValueChangedHandler;
import net.svenbuschbeck.gwt.ao.client.events.ValueRemovedEvent;
import net.svenbuschbeck.gwt.ao.client.events.ValueRemovedHandler;

import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;

/**
* Maintains a list of widgets, fires valueChangeEvents if an view is added
*
* @author Sven Buschbeck
*
* @param <T>
*
*            OPTIMIZE Change HandlerManager (deprecated) to whatever it is
*            supposed to be now.
*/
@SuppressWarnings("deprecation") public class ActiveList<T> implements HasValueAddedHandlers<T>,
  HasValueRemovedHandlers<T>, HasValueChangedHandlers<List<T>>, Iterable<T>, List<T> {

  public abstract class ReadOnlyAddValueHook implements ReadOnlyHook<T> {

    @Override public void commitValue(T value) {
      _add(value);
    }
  }

  public abstract class ReadOnlyRemoveValueHook implements ReadOnlyHook<T> {

    @Override public void commitValue(T value) {
      _remove(value);
    }
  }

  private LinkedList<T> collection = new LinkedList<T>();
  private T[] dummyForConvertion = null;
  private HandlerManager manager = new HandlerManager(null);
  private final boolean valuesHaveToBeUnique;
  private final boolean valuesCanBeNull;
  private Long maxSize = null;
  private final ReadOnlyAddValueHook readOnlyAddValueHook;
  private final ReadOnlyRemoveValueHook readOnlyRemoveValueHook;

  /**
   * Creates ActiveCollection setting uniqueValues=false.
   */
  public ActiveList() {
    this(false);
  }

  /**
   * Creates an ActiveCollection requiring all it's elements to be a.equals(b)
   * == false.
   *
   * @param uniqueValues
   */
  public ActiveList(boolean uniqueValues) {
    this(uniqueValues, true);
  }

  /**
   * Creates ActiveCollection setting uniqueValues=false.
   *
   * @param adoptCollection
   */
  public ActiveList(Collection<T> adoptCollection, ReadOnlyAddValueHook readOnlyAddValueHook,
    ReadOnlyRemoveValueHook readOnlyRemoveValueHook) {
    this(false, adoptCollection, readOnlyAddValueHook, readOnlyRemoveValueHook);
  }

  /**
   * Creates ActiveCollection setting valuesCanBeNull=true.
   *
   * @param valuesHaveToBeUnique
   * @param adoptCollection
   */
  public ActiveList(boolean valuesHaveToBeUnique, Collection<T> adoptCollection) {
    this(valuesHaveToBeUnique, adoptCollection, null, null);
  }

  /**
   * Creates ActiveCollection setting valuesCanBeNull=true.
   *
   * @param valuesHaveToBeUnique
   * @param adoptCollection
   */
  public ActiveList(boolean valuesHaveToBeUnique, Collection<T> adoptCollection,
    ReadOnlyAddValueHook readOnlyAddValueHook, ReadOnlyRemoveValueHook readOnlyRemoveValueHook) {
    this(valuesHaveToBeUnique, true, adoptCollection, readOnlyAddValueHook, readOnlyRemoveValueHook);
  }

  /**
   * Creates ActiveCollection setting initial collection to null (will cause
   * creating an empty collection).
   *
   * @param valuesHaveToBeUnique
   * @param valuesCanBeNull
   */
  public ActiveList(boolean valuesHaveToBeUnique, boolean valuesCanBeNull) {
    this(valuesHaveToBeUnique, valuesCanBeNull, null, null);
  }

  /**
   * Creates ActiveCollection setting initial collection to null (will cause
   * creating an empty collection).
   *
   * @param valuesHaveToBeUnique
   * @param valuesCanBeNull
   */
  public ActiveList(boolean valuesHaveToBeUnique, boolean valuesCanBeNull, ReadOnlyAddValueHook readOnlyAddValueHook,
    ReadOnlyRemoveValueHook readOnlyRemoveValueHook) {
    this(valuesHaveToBeUnique, valuesCanBeNull, null, readOnlyAddValueHook, readOnlyRemoveValueHook);
  }

  /**
   * Creates ActiveCollection setting trickerValueAddedEventForAll=false.
   *
   * @param valuesHaveToBeUnique
   * @param valuesCanBeNull
   * @param adoptCollection
   */
  public ActiveList(boolean valuesHaveToBeUnique, boolean valuesCanBeNull, Collection<T> adoptCollection) {
    this(valuesHaveToBeUnique, valuesCanBeNull, adoptCollection, null, null);
  }

  /**
   * Creates ActiveCollection setting trickerValueAddedEventForAll=false.
   *
   * @param valuesHaveToBeUnique
   * @param valuesCanBeNull
   * @param adoptCollection
   */
  public ActiveList(boolean valuesHaveToBeUnique, boolean valuesCanBeNull, Collection<T> adoptCollection,
    ReadOnlyAddValueHook readOnlyAddValueHook, ReadOnlyRemoveValueHook readOnlyRemoveValueHook) {
    this(valuesHaveToBeUnique, valuesCanBeNull, adoptCollection, false, readOnlyAddValueHook,
      readOnlyRemoveValueHook);
  }

  /**
   * Creates ActiveCollection with all parameters there are
   *
   * @param valuesHaveToBeUnique
   * @param valuesCanBeNull
   * @param adoptCollection
   * @param trickerValueAddedEventForAll
   */
  public ActiveList(boolean valuesHaveToBeUnique, boolean valuesCanBeNull, Collection<T> adoptCollection,
    boolean trickerValueAddedEventForAll, ReadOnlyAddValueHook readOnlyAddValueHook,
    ReadOnlyRemoveValueHook readOnlyRemoveValueHook) {
    this.valuesHaveToBeUnique = valuesHaveToBeUnique;
    this.valuesCanBeNull = valuesCanBeNull;
    this.readOnlyAddValueHook = readOnlyAddValueHook;
    this.readOnlyRemoveValueHook = readOnlyRemoveValueHook;
    adopt(adoptCollection, trickerValueAddedEventForAll);
  }

  public void adopt(Collection<T> adoptCollection, boolean trickerValueAddedEventForAll) {
    collection = (adoptCollection != null) ? new LinkedList<T>(adoptCollection) : new LinkedList<T>();
    if (trickerValueAddedEventForAll) {
      trickerValueAddedEventForAll();
    }
  }

  private void trickerValueAddedEventForAll() {
    // TODO Add option to use Scheduler.get().scheduleIncremental() to fire each event using a scheduler not to block UI
    for (T value : collection) {
      ValueAddedEvent.fire(this, value);
    }
    fireValueChangeEvent(new LinkedList<T>(), getStaticCopy());
  }

  @Override public void fireEvent(GwtEvent<?> event) {
    manager.fireEvent(event);
  }

  /**
   * Adds and returns e. Returning e allows to concatenate further operations
   * on e, e.g. added e to two collections in one line:
   * collection2.add(collection.add(e));
   *
   * @param e
   * @return
   */
  public T addAndReturn(T e) {
    add(e);
    return e;
  }

  @Override public boolean add(T e) {
    if (readOnlyAddValueHook != null) {
      readOnlyAddValueHook.onNewValue(e);
      return true;
    }
    return _add(e);
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.List#add(int, java.lang.Object)
   */
  @Override public void add(int arg0, T arg1) {

  }

  private boolean _add(T e) {
    List<T> before = getStaticCopy();
    boolean gotAdded = ValueAddedEvent.addAndFireIfRequired(this, collection, e, valuesHaveToBeUnique,
      valuesCanBeNull, maxSize);
    if (gotAdded) {
      fireValueChangeEvent(before, getStaticCopy());
    }
    return gotAdded;
  }

  /**
   * Removes given object from collection. If contained, ValueRemovedEvent
   * gets fired.
   *
   * @param e
   * @return e
   */
  public T removeAndReturn(T e) {
    _remove(e);
    return e;
  }

  @SuppressWarnings("unchecked") @Override public boolean remove(Object e) {
    if (readOnlyRemoveValueHook != null) {
      readOnlyAddValueHook.onNewValue((T) e);
      return true;
    }
    return _remove((T) e);
  }

  private boolean _remove(T e) {
    List<T> before = getStaticCopy();
    if (ValueRemovedEvent.removeAndFireIfNotNull(this, collection, e)) {
      fireValueChangeEvent(before, getStaticCopy());
      return true;
    }
    return false;
  }

  private void fireValueChangeEvent(List<T> before, List<T> after) {
    ValueChangedEvent.fire(this, before, after);
  }

  @Override public HandlerRegistration addValueAddedHandler(ValueAddedHandler<T> handler) {
    return addValueAddedHandler(handler, false);
  }

  public HandlerRegistration addValueAddedHandler(ValueAddedHandler<T> handler, boolean trickerValueAddedEventForAll) {
    HandlerRegistration handlerRegistration = manager.addHandler(ValueAddedEvent.getType(), handler);
    if (trickerValueAddedEventForAll) {
      trickerValueAddedEventForAll();
    }
    return handlerRegistration;
  }

  @Override public HandlerRegistration addValueRemovedHandler(ValueRemovedHandler<T> handler) {
    return manager.addHandler(ValueRemovedEvent.getType(), handler);
  }

  public HandlerRegistration addValueChangedHandler(ValueChangedHandler<List<T>> valueChangedHandler) {
    return addValueChangedHandler(valueChangedHandler, false);
  };

  /*
   * (non-Javadoc)
   *
   * @seenet.svenbuschbeck.gwt.ao.client.events.HasValueChangedHandlers#
   * addValueChangedHandler
   * (net.svenbuschbeck.gwt.ao.client.events.ValueChangedHandler, boolean)
   */
  @Override public HandlerRegistration addValueChangedHandler(ValueChangedHandler<List<T>> valueChangedHandler,
    boolean triggerInitially) {
    HandlerRegistration handlerRegistration = manager.addHandler(ValueChangedEvent.getType(), valueChangedHandler);
    List<T> staticCopy = getStaticCopy();
    ValueChangedEvent.fire(this, staticCopy, staticCopy);
    return handlerRegistration;
  }

  // Implement Iterator<T> //////////////////////////////////////////////////

  @Override public Iterator<T> iterator() {
    // Can cause CooncurrentUpdateExceptions, so it's always better to iterate over a copy
    //    return collection.iterator();
    return getStaticCopy().iterator();
  }

  // Implement Collection<T> ////////////////////////////////////////////////

  @Override public int size() {
    return collection.size();
  }

  @Override public void clear() {
    // iterating on the copy to avoid java.util.ConcurrentModificationException as the removeValue events might cause the collection to be changed in parallel
    //    T[] copy = (T[]) collection.toArray();
    //    for (T element : copy) {
    //      remove(element);
    //    }

    // idea of copying collection implemented in forEach method
    forEach(new ForEach<T>() {

      @Override public void execute(T element) {
        remove(element);
      }
    });
  }

  @Override public boolean addAll(Collection<? extends T> c) {
    int size = collection.size();
    for (T element : c) {
      add(element);
    }
    return size != collection.size();
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.List#addAll(int, java.util.Collection)
   */
  @Override public boolean addAll(int arg0, Collection<? extends T> arg1) {
    List<T> before = getStaticCopy();
    collection.addAll(arg0, arg1);
    boolean changed = before.size() != collection.size();
    for (T obj : arg1) {
      ValueAddedEvent.fire(this, obj);
    }
    if (changed) {
      fireValueChangeEvent(collection, collection);
    }
    return changed;
  }

  @Override public boolean contains(Object o) {
    return collection.contains(o);
  }

  @Override public boolean containsAll(Collection<?> c) {
    return collection.containsAll(c);
  }

  @Override public boolean isEmpty() {
    return collection.isEmpty();
  }

  @Override public boolean removeAll(Collection<?> c) {
    int size = collection.size();
    for (Object element : c) {
      remove(element);
    }
    return size != collection.size();
  }

  @Override public boolean retainAll(final Collection<?> c) {
    int size = collection.size();
    //    for (T element : collection) {
    //      if (!c.contains(element)) {
    //        remove(element);
    //      }
    //    }
    forEach(new ForEach<T>() {

      @Override public void execute(T element) {
        if (!c.contains(element)) {
          remove(element);
        }
      }
    });
    return size != collection.size();
  }

  @Override public Object[] toArray() {
    return collection.toArray();
  }

  @Override public <T2> T2[] toArray(T2[] a) {
    return collection.toArray(a);
  }

  /**
   * Use this method to iterate over all elements in this collection avoiding
   * "concurrent change" exceptions.
   *
   * @param forEach
   *            callback method
   */
  public void forEach(ForEach<T> forEach) {
    // copy collection to not run into "concurrent change" exceptions.
    //    for (T object : new ArrayList<T>(collection)) {
    Collection<T> staticCopy = getStaticCopy();
    if (staticCopy != null) {
      for (T object : staticCopy) {
        forEach.execute(object);
      }
    }
  }

  /**
   * Returns a static copy of the containing collection of objects. Use this
   * collection to iterate over it over time to avoid "concurrent change"
   * exceptions.
   *
   * @return Independent copy of internal collection.
   */
  public List<T> getStaticCopy() {
    assert collection != null : "Inner collection must not be null.";
    return new ArrayList<T>(collection);
  }

  /**
   * @param maximumNumberOfCanvasMedia
   */
  public void setMaxSize(Long maximumNumberOfElements) {
    this.maxSize = Math.max(0, maximumNumberOfElements);
    while (size() > maximumNumberOfElements) {
      pop();
    }
  }

  /**
   * Removes and returns last element in collection
   */
  public T pop() {
    return removeAndReturn(collection.getLast());
  }

  public Long getMaxSize() {
    return maxSize;
  }

  public void clearMaxSize() {
    maxSize = null;
  }

  /**
   * @return
   */
  public boolean hasFreeSlots() {
    return size() < getMaxSize();
  }

  /**
   * Returns the element at the given index. Makes use of direct access if
   * containing collection is a list or converts collection to array
   * otherwise.
   *
   * @param index
   * @return
   * @throws IndexOutOfBoundsException
   */
  public T get(int index) {
    if (collection instanceof List) {
      return ((List<T>) collection).get(index);
    }
    return collection.toArray(dummyForConvertion)[index];
  }

  /**
   * Returns the index of the given object in this collection or -1 if it is
   * not contained. Makes use of direct access if containing collection is a
   * list or iterates otherwise
   *
   * @param object
   * @return index of the given object or -1 if the object is not contained in
   *         this collection
   */
  @Override public int indexOf(Object object) {
    //    if (object != null) {
    //      if (collection instanceof List) {
    return ((List<T>) collection).indexOf(object);
    //      }
    //      T[] array = collection.toArray(dummyForConvertion);
    //      for (int x = 0; x < array.length; x++) {
    //        if (object.equals(array[x])) {
    //          return x;
    //        }
    //      }
    //    }
    //    return -1;
  }

  /**
   * Returns the first element that is object.equals(element)
   *
   * @param object
   * @return element that equals the given object.
   */
  public T getFirstObjectEqualTo(T object) {
    int index = indexOf(object);
    if (index >= 0) {
      return get(index);
    }
    return null;
  }

  /*
   * (non-Javadoc)
   *
   * @see java.lang.Object#toString()
   */
  @Override public String toString() {
    return "ActiveCollection(size=" + size() + "; maxSize=" + getMaxSize() + ")";
  }

  public boolean isReadOnly() {
    return readOnlyAddValueHook != null;
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.List#lastIndexOf(java.lang.Object)
   */
  @Override public int lastIndexOf(Object arg0) {
    return collection.lastIndexOf(arg0);
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.List#listIterator()
   */
  @Override public ListIterator<T> listIterator() {
    return collection.listIterator();
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.List#listIterator(int)
   */
  @Override public ListIterator<T> listIterator(int arg0) {
    return collection.listIterator(arg0);
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.List#remove(int)
   */
  @Override public T remove(int index) {
    T removed = collection.remove(index);
    if (removed != null) {
      ValueRemovedEvent.fire(this, removed);
    }
    return removed;
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.List#set(int, java.lang.Object)
   */
  @Override public T set(int index, T newObject) {
    T oldObject = collection.get(index);
    if (compare(oldObject, newObject)) {
      return oldObject;
    }
    remove(oldObject);
    add(index, newObject);

    return newObject;
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.List#subList(int, int)
   */
  @Override public List<T> subList(int arg0, int arg1) {
    return collection.subList(arg0, arg1);
  }

  private boolean compare(T object1, T object2) {
    return object1 == object2 || (object1 != null && object1.equals(object2));
  }
}
TOP

Related Classes of net.svenbuschbeck.gwt.ao.client.ActiveList$ReadOnlyRemoveValueHook

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.