All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oliveryasuna.beanbag.AbstractObservableList Maven / Gradle / Ivy

package com.oliveryasuna.beanbag;

import com.oliveryasuna.beanbag.event.EventListener;
import com.oliveryasuna.beanbag.event.*;
import com.oliveryasuna.commons.language.pattern.Registration;
import com.oliveryasuna.commons.language.pattern.decorator.ListIteratorDecorator;
import org.apache.commons.lang3.NotImplementedException;

import java.util.*;
import java.util.function.Predicate;

public abstract class AbstractObservableList, SUB extends AbstractObservableList>
    extends AbstractObservableCollection
    implements List {

  // Constructors
  //--------------------------------------------------

  public AbstractObservableList(final LST list) {
    super(list);
  }

  // Methods
  //--------------------------------------------------

  // Collection API
  //

  @Override
  public boolean add(final T t) {
    final LST list = getList();

    final int index = list.size();
    final boolean modified = list.add(t);

    if(modified) {
      fireEvent(new ElementAddedEvent<>(getThis(), t));
      fireEvent(new IndexedElementAddedEvent<>(getThis(), index, t));
      fireEvent(new ElementsAddedEvent<>(getThis(), new ArrayList<>(Collections.singleton(t))));
      fireEvent(new IndexedElementsAddedEvent<>(getThis(), new LinkedHashMap<>(Collections.singletonMap(index, t))));
    }

    return modified;
  }

  @Override
  public boolean addAll(final Collection c) {
    final LST list = getList();

    int index = list.size();
    final boolean modified = list.addAll(c);

    if(modified) {
      final Map indexElementMap = new LinkedHashMap<>();

      for(final T addedElement : c) {
        indexElementMap.put(index, addedElement);

        fireEvent(new ElementAddedEvent<>(getThis(), addedElement));
        fireEvent(new IndexedElementAddedEvent<>(getThis(), index, addedElement));

        index++;
      }

      fireEvent(new ElementsAddedEvent<>(getThis(), new ArrayList<>(c)));
      fireEvent(new IndexedElementsAddedEvent<>(getThis(), indexElementMap));
    }

    return modified;
  }

  @Override
  public boolean remove(final Object o) {
    final LST list = getList();

    final int index = list.indexOf(o);
    final boolean modified = list.remove(o);

    if(modified) {
      final T removedElement = (T)o;

      fireEvent(new ElementRemovedEvent<>(getThis(), removedElement));
      fireEvent(new IndexedElementRemovedEvent<>(getThis(), index, removedElement));
      fireEvent(new ElementsRemovedEvent<>(getThis(), new ArrayList<>(Collections.singleton(removedElement))));
      fireEvent(new IndexedElementsRemovedEvent<>(getThis(), new LinkedHashMap<>(Collections.singletonMap(index, removedElement))));
    }

    return modified;
  }

  @Override
  public boolean removeAll(final Collection c) {
    final LST list = getList();

    final List copy = new ArrayList<>(list);

    final boolean modified = list.removeAll(c);

    if(modified) {
      final Map indexElementMap = new LinkedHashMap<>();

      for(final Object rawRemovedElement : c) {
        final int removedElementIndex = copy.indexOf(rawRemovedElement);

        if(removedElementIndex == -1) {
          continue;
        }

        copy.remove(removedElementIndex);

        final T removedElement = (T)rawRemovedElement;

        indexElementMap.put(removedElementIndex, removedElement);

        fireEvent(new ElementRemovedEvent<>(getThis(), removedElement));
        fireEvent(new IndexedElementRemovedEvent<>(getThis(), removedElementIndex, removedElement));
      }

      fireEvent(new ElementsRemovedEvent<>(getThis(), new ArrayList<>(indexElementMap.values())));
      fireEvent(new IndexedElementsRemovedEvent<>(getThis(), indexElementMap));
    }

    return modified;
  }

  @Override
  public boolean removeIf(final Predicate filter) {
    final LST list = getList();

    final List copy = new ArrayList<>(list);

    final boolean modified = list.removeIf(filter);

    if(modified) {
      final Map indexElementMap = new LinkedHashMap<>();

      for(final ListIterator iterator = copy.listIterator(); iterator.hasNext(); ) {
        final int index = iterator.nextIndex();
        final T element = iterator.next();

        if(filter.test(element)) {
          iterator.remove();

          indexElementMap.put(index, element);

          fireEvent(new ElementRemovedEvent<>(getThis(), element));
          fireEvent(new IndexedElementRemovedEvent<>(getThis(), index, element));
        }
      }

      fireEvent(new ElementsRemovedEvent<>(getThis(), new ArrayList<>(indexElementMap.values())));
      fireEvent(new IndexedElementsRemovedEvent<>(getThis(), indexElementMap));
    }

    return modified;
  }

  @Override
  public boolean retainAll(final Collection c) {
    final LST list = getList();

    final List copy = Collections.unmodifiableList(new ArrayList<>(list));

    final boolean modified = list.retainAll(c);

    if(modified) {
      final Map indexElementMap = new LinkedHashMap<>();

      for(int i = 0; i < copy.size(); i++) {
        final T element = copy.get(i);

        if(!c.contains(element)) {
          indexElementMap.put(i, element);

          fireEvent(new ElementRemovedEvent<>(getThis(), element));
          fireEvent(new IndexedElementRemovedEvent<>(getThis(), i, element));
        }
      }

      fireEvent(new ElementsRemovedEvent<>(getThis(), new ArrayList<>(indexElementMap.values())));
      fireEvent(new IndexedElementsRemovedEvent<>(getThis(), indexElementMap));
    }

    return modified;
  }

  @Override
  public void clear() {
    final LST list = getList();

    final List copy = Collections.unmodifiableList(new ArrayList<>(list));

    list.clear();

    final Map indexElementMap = new LinkedHashMap<>();

    for(int i = 0; i < copy.size(); i++) {
      final T element = copy.get(i);

      indexElementMap.put(i, element);

      fireEvent(new ElementRemovedEvent<>(getThis(), element));
      fireEvent(new IndexedElementRemovedEvent<>(getThis(), i, element));
    }

    fireEvent(new ElementsRemovedEvent<>(getThis(), new ArrayList<>(indexElementMap.values())));
    fireEvent(new IndexedElementsRemovedEvent<>(getThis(), indexElementMap));
  }

  @Override
  public Iterator iterator() {
    return new ObservableIterator();
  }

  // List API
  //

  @Override
  public T get(final int index) {
    return getList().get(index);
  }

  @Override
  public T set(final int index, final T element) {
    final T previousElement = getList().set(index, element);

    fireEvent(new IndexedElementChangedEvent<>(getThis(), index, element, previousElement));

    return previousElement;
  }

  @Override
  public void add(final int index, final T element) {
    getList().add(index, element);

    fireEvent(new ElementAddedEvent<>(getThis(), element));
    fireEvent(new IndexedElementAddedEvent<>(getThis(), index, element));
    fireEvent(new ElementsAddedEvent<>(getThis(), new LinkedHashSet<>(Collections.singleton(element))));
    fireEvent(new IndexedElementsAddedEvent<>(getThis(), new LinkedHashMap<>(Collections.singletonMap(index, element))));
  }

  @Override
  public boolean addAll(int index, final Collection c) {
    final boolean modified = getList().addAll(index, c);

    if(modified) {
      final Map indexElementMap = new LinkedHashMap<>();

      for(final T addedElement : c) {
        indexElementMap.put(index, addedElement);

        fireEvent(new ElementAddedEvent<>(getThis(), addedElement));
        fireEvent(new IndexedElementAddedEvent<>(getThis(), index, addedElement));

        index++;
      }

      fireEvent(new ElementsAddedEvent<>(getThis(), new LinkedHashSet<>(c)));
      fireEvent(new IndexedElementsAddedEvent<>(getThis(), indexElementMap));
    }

    return modified;
  }

  @Override
  public T remove(final int index) {
    final T removedElement = getList().remove(index);

    fireEvent(new ElementRemovedEvent<>(getThis(), removedElement));
    fireEvent(new IndexedElementRemovedEvent<>(getThis(), index, removedElement));
    fireEvent(new ElementsRemovedEvent<>(getThis(), new LinkedHashSet<>(Collections.singleton(removedElement))));
    fireEvent(new IndexedElementsRemovedEvent<>(getThis(), new LinkedHashMap<>(Collections.singletonMap(index, removedElement))));

    return removedElement;
  }

  @Override
  public int indexOf(final Object o) {
    return getList().indexOf(o);
  }

  @Override
  public int lastIndexOf(final Object o) {
    return getList().lastIndexOf(o);
  }

  @Override
  public ListIterator listIterator() {
    return new ObservableListIterator();
  }

  @Override
  public ListIterator listIterator(final int index) {
    return new ObservableListIterator(index);
  }

  @Override
  public List subList(final int fromIndex, final int toIndex) {
    // TODO: Implement.
    throw new NotImplementedException();
  }

  // Listeners
  //

  public Registration addIndexedElementAddedListener(final EventListener, LST, SUB> listener) {
    return addListener(IndexedElementAddedEvent.class, listener);
  }

  public Registration addIndexedElementRemovedListener(final EventListener, LST, SUB> listener) {
    return addListener(IndexedElementRemovedEvent.class, listener);
  }

  public Registration addIndexedElementChangedListener(final EventListener, LST, SUB> listener) {
    return addListener(IndexedElementChangedEvent.class, listener);
  }

  public Registration addIndexedElementsAddedListener(final EventListener, LST, SUB> listener) {
    return addListener(IndexedElementsAddedEvent.class, listener);
  }

  public Registration addIndexedElementsRemovedListener(final EventListener, LST, SUB> listener) {
    return addListener(IndexedElementsRemovedEvent.class, listener);
  }

  // Value
  //

  protected LST getList() {
    return getCollection();
  }

  protected void setList(final LST list) {
    setCollection(list);
  }

  // Nested
  //--------------------------------------------------

  protected class ObservableIterator extends AbstractObservableCollection.ObservableIterator {

    // Constructors
    //--------------------------------------------------

    protected ObservableIterator(final Iterator iterator) {
      super(iterator);
    }

    private ObservableIterator() {
      this(AbstractObservableList.this.getList().iterator());
    }

    // Fields
    //--------------------------------------------------

    private int lastIndex = -1;

    // Methods
    //--------------------------------------------------

    // Iterator API
    //

    @Override
    public T next() {
      final T next = super.next();

      setLastIndex(getLastIndex() + 1);
      setLastElement(next);

      return next;
    }

    @Override
    public void remove() {
      super.remove();

      final int lastIndex = getLastIndex();
      final T lastElement = getLastElement();

      AbstractObservableList.this.fireEvent(new IndexedElementRemovedEvent<>(
          AbstractObservableList.this.getThis(),
          lastIndex,
          lastElement
      ));
      AbstractObservableList.this.fireEvent(new IndexedElementsRemovedEvent<>(
          AbstractObservableList.this.getThis(),
          new LinkedHashMap<>(Collections.singletonMap(lastIndex, lastElement))
      ));
    }

    // Getters/setters
    //--------------------------------------------------

    protected int getLastIndex() {
      return lastIndex;
    }

    protected void setLastIndex(final int lastIndex) {
      this.lastIndex = lastIndex;
    }

  }

  protected class ObservableListIterator extends ListIteratorDecorator {

    // Constructors
    //--------------------------------------------------

    protected ObservableListIterator(final ListIterator iterator) {
      super(iterator);
    }

    private ObservableListIterator() {
      this(AbstractObservableList.this.getList().listIterator());
    }

    private ObservableListIterator(final int index) {
      this(AbstractObservableList.this.getList().listIterator(index));
    }

    // Fields
    //--------------------------------------------------

    private int lastIndex = -1;

    private T lastElement;

    // Methods
    //--------------------------------------------------

    // Iterator API
    //

    @Override
    public T next() {
      final T next = super.next();

      setLastIndex(getLastIndex() + 1);
      setLastElement(next);

      return next;
    }

    @Override
    public void remove() {
      super.remove();

      final int lastIndex = getLastIndex();
      final T lastElement = getLastElement();

      AbstractObservableList.this.fireEvent(new IndexedElementRemovedEvent<>(
          AbstractObservableList.this.getThis(),
          lastIndex,
          lastElement
      ));
      AbstractObservableList.this.fireEvent(new IndexedElementsRemovedEvent<>(
          AbstractObservableList.this.getThis(),
          new LinkedHashMap<>(Collections.singletonMap(lastIndex, lastElement))
      ));
    }

    // ListIterator API
    //

    @Override
    public T previous() {
      final T previous = super.previous();

      setLastIndex(getLastIndex() - 1);
      setLastElement(previous);

      return previous;
    }

    @Override
    public void set(final T t) {
      super.set(t);

      final int lastIndex = getLastIndex();
      final T lastElement = getLastElement();

      AbstractObservableList.this.fireEvent(new IndexedElementChangedEvent<>(
          AbstractObservableList.this.getThis(),
          lastIndex,
          t,
          lastElement
      ));
    }

    @Override
    public void add(final T t) {
      super.add(t);

      final int lastIndex = getLastIndex();

      AbstractObservableList.this.fireEvent(new ElementAddedEvent<>(
          AbstractObservableList.this.getThis(),
          t
      ));
      AbstractObservableList.this.fireEvent(new IndexedElementAddedEvent<>(
          AbstractObservableList.this.getThis(),
          lastIndex,
          t
      ));
      AbstractObservableList.this.fireEvent(new ElementsAddedEvent<>(
          AbstractObservableList.this.getThis(),
          new LinkedHashSet<>(Collections.singleton(t))
      ));
      AbstractObservableList.this.fireEvent(new IndexedElementsAddedEvent<>(
          AbstractObservableList.this.getThis(),
          new LinkedHashMap<>(Collections.singletonMap(lastIndex, t))
      ));
    }

    // Getters/setters
    //--------------------------------------------------

    protected int getLastIndex() {
      return lastIndex;
    }

    protected void setLastIndex(final int lastIndex) {
      this.lastIndex = lastIndex;
    }

    protected T getLastElement() {
      return lastElement;
    }

    protected void setLastElement(final T lastElement) {
      this.lastElement = lastElement;
    }

  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy