/******************************************************************************
* Copyright (c) 2016 itemis AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alexander Nyßen (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef.common.collections;
import com.google.common.collect.Multiset;
/**
* A {@link MultisetChangeListener} is the notification target for changes
* related to an {@link ObservableMultiset}.
*
* @param <E>
* The element type of the {@link ObservableMultiset}.
*
* @author anyssen
*
*/
public interface MultisetChangeListener<E> {
/**
* Represents an atomic change done to an {@link ObservableMultiset}, i.e. a
* change resulting from a single method invocation on an
* {@link ObservableMultiset}.
* <p>
* The change may internally consist of several elementary sub-changes,
* which are related to changes of a single element. That is, a call to
* {@link ObservableMultiset#add(Object)} or
* {@link ObservableMultiset#setCount(Object, int)} will lead to an atomic
* change that comprises only a single elementary sub-change, while a call
* to {@link ObservableMultiset#clear()} will potentially lead to several
* elementary sub-changes (one for each element contained in the Multiset).
* <p>
* The comprised elementary sub-changes need to be navigated using
* {@link #next()}, the relevant information can then be retrieved via
* {@link #getElement()}, {@link #getAddCount()}, and
* {@link #getRemoveCount()} (for the current elementary sub-change the
* internal cursor currently points at). Initially, the internal cursor is
* set to point before the first elementary sub-change, so that an initial
* call to {@link #next()} is required to access the first elementary
* sub-change, while {@link #reset()} can be used to reset the cursor to
* this initial state before the first elementary sub-change.
* <p>
* The {@link #getMultiset()} returns the source {@link ObservableMultiset}
* that was changed (in the state after the atomic change was applied). The
* previous contents of the source {@link ObservableMultiset} (in the state
* before the atomic change was applied) can be obtained via
* {@link #getPreviousContents()}. Both are independent of the state of the
* internal cursor and may be accessed at any time.
*
* @param <E>
* The element type of the {@link ObservableMultiset}.
*/
public static abstract class Change<E> {
private final ObservableMultiset<E> source;
/**
* Creates a new (atomic) change associated with the given source
* {@link ObservableMultiset}.
*
* @param source
* The source of the change.
*/
public Change(ObservableMultiset<E> source) {
this.source = source;
}
/**
* Places the internal cursor on the next elementary sub-change, so that
* it be processed using {@link #getElement()}, {@link #getAddCount()},
* and {@link #getRemoveCount()}. This method has to be called initially
* to have the internal cursor point to the first elementary sub-change
* that is comprised.
*
* @return <code>true</code> if the internal cursor could be switched to
* the next elementary sub-change, <code>false</code> if the
* current elementary sub-change was the last change that is
* comprised.
*/
public abstract boolean next();
/**
* Reset the internal cursor to the initial state, so that the first
* elementary sub-change can be accessed by calling {@link #next()}.
*/
public abstract void reset();
/**
* The source {@link ObservableMultiset} this atomic change is
* associated with.
* <p>
* This method does not depend on the state of the internal cursor, may
* thus be accessed independent on which elementary sub-change is
* currently processed.
*
* @return The source {@link ObservableMultiset}.
*/
public ObservableMultiset<E> getMultiset() {
return source;
}
/**
* Returns an unmodifiable {@link Multiset} that contains the previous
* contents of the source {@link ObservableMultiset} before the atomic
* change was applied.
* <p>
* This method does not depend on the state of the internal cursor, may
* thus be accessed independent on which elementary sub-change is
* currently processed.
*
* @return An unmodifiable {@link Multiset} representing the contents of
* the {@link ObservableMultiset} before the change.
*/
public abstract Multiset<E> getPreviousContents();
/**
* Returns how often an element has been added in the current elementary
* sub-change, if one has been added.
* <p>
* This method depends on the state of the internal cursor that can be
* manipulated via {@link #next()} and {@link #reset()}.
*
* @return The number of occurrences that have been added.
*/
public abstract int getAddCount();
/**
* Returns how often an element has been removed in the current
* elementary sub-change, if one has been removed.
* <p>
* This method depends on the state of the internal cursor that can be
* manipulated via {@link #next()} and {@link #reset()}.
*
* @return The number of occurrences that have been removed.
*/
public abstract int getRemoveCount();
/**
* Retrieves the element that was altered in the current elementary
* sub-change.
* <p>
* This method depends on the state of the internal cursor that can be
* manipulated via {@link #next()} and {@link #reset()}.
*
* @return The added element in case an element was added.
*/
public abstract E getElement();
}
/**
* Called after an atomic change has been made to an
* {@link ObservableMultiset}. Each call to a modifying method of
* {@link ObservableMultiset} will lead to exactly one invocation, which may
* internally comprise several elementary sub-changes.
*
* @param change
* A {@link Change} object representing an atomic change that was
* performed on the source {@link ObservableSetMultimap}.
*/
void onChanged(Change<? extends E> change);
}