org.arakhne.afc.ui.selection.SelectionManager Maven / Gradle / Ivy
/*
* $Id: org/arakhne/afc/ui/selection/SelectionManager.java v12.0 2015-04-09 01:26:18$
*
* Copyright (C) 2002 Stephane GALLAND, Madhi HANNOUN, Marc BAUMGARTNER.
* Copyright (C) 2012-13 Stephane GALLAND.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* This program is free software; you can redistribute it and/or modify
*/
package org.arakhne.afc.ui.selection ;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeSet;
import org.arakhne.afc.util.ListenerCollection;
/** Abstracxt implementation of a selection manager.
*
* @param is the type of the objects inside this manager.
* @author Stéphane GALLAND
* @version 12.0 2015-04-09 01:26:18
* @mavengroupid org.arakhne.afc.ui
* @mavenartifactid base
*/
public abstract class SelectionManager implements Set {
private final ListenerCollection listeners = new ListenerCollection();
private final Class elementType;
/** Create a new SelectionManager.
*
* @param elementType is the type of the elements inside this selection manager.
*/
public SelectionManager(Class elementType) {
this.elementType = elementType;
}
/** Update the system's selection.
*/
protected void updateSystemSelection() {
//
}
/** Reset any internal bufferized value.
*/
protected void resetInternalBuffers() {
//
}
/** Add the given object inside the inner storage data structure.
*
* @param object
* @return true if the object was added; false
* if not added.
*/
protected abstract boolean addInStorage(OBJ object);
/** Remove the given object from the inner storage data structure.
*
* @param object
* @return true if the object was removed; false
* if not removed.
*/
protected abstract boolean removeFromStorage(OBJ object);
/** Clear the storage
*
* @return the removed objects.
*/
protected abstract Collection clearStorage();
/** Replies an iterator on the storage.
*
* @return the iterator.
*/
protected abstract Iterator getIteratorOnStorage();
/** Invoked when the given object was removed from the inner storage.
*
* @param object
*/
protected void onRemovedObject(OBJ object) {
//
}
/** Invoked when the given object was added into the inner storage.
*
* @param object
*/
protected void onAddedObject(OBJ object) {
//
}
/** Add selection listener.
*
* @param listener
*/
public final void addSelectionListener(SelectionListener listener) {
this.listeners.add(SelectionListener.class, listener);
}
/** Remove selection listener.
*
* @param listener
*/
public final void removeSelectionListener(SelectionListener listener) {
this.listeners.remove(SelectionListener.class, listener);
}
/** Notifies the listeners about the selection of a selectable object.
*
* @param selectableObject is the selected object.
* @param isAdjusting indicates if the event to fire is the last inside
* a sequence of events. If true the event to fire must
* be followed by other selection events that are produces by the
* same action on the selection manager. If false, there
* is no following selection event for the same action on the selection
* manager.
*/
protected final void fireSelected(OBJ selectableObject, boolean isAdjusting) {
SelectionEvent event = new SelectionEvent(this, selectableObject, false, isAdjusting);
for(SelectionListener listener : this.listeners.getListeners(SelectionListener.class)) {
listener.selectionChanged(event);
}
}
/** Notifies the listeners about the deselection of a selectable object.
*
* @param selectableObject is the unselected object.
* @param isAdjusting indicates if the event to fire is the last inside
* a sequence of events. If true the event to fire must
* be followed by other selection events that are produces by the
* same action on the selection manager. If false, there
* is no following selection event for the same action on the selection
* manager.
*/
protected final void fireUnselected(OBJ selectableObject, boolean isAdjusting) {
SelectionEvent event = new SelectionEvent(this, selectableObject, true, isAdjusting);
for(SelectionListener listener : this.listeners.getListeners(SelectionListener.class)) {
listener.selectionChanged(event);
}
}
/** Toggle the selection of figures.
*
* @param selectableObject are the figures to toggle.
* @return true if the selection of a selectable object
* has changed; false if no object has changed
* of selection state.
*/
public final boolean toggle(OBJ... selectableObject) {
return toggle(Arrays.asList(selectableObject));
}
/** Toggle the selection of figures.
*
* @param selectableObjects are the figures to toggle.
* @return true if the selection of a selectable object
* has changed; false if no object has changed
* of selection state.
*/
public synchronized final boolean toggle(Collection extends OBJ> selectableObjects) {
boolean changed = false;
OBJ selected = null;
OBJ unselected = null;
for(OBJ f : selectableObjects) {
if (removeFromStorage(f)) {
if (selected!=null) {
fireSelected(selected, true);
selected = null;
}
else if (unselected!=null) {
fireUnselected(unselected, true);
unselected = null;
}
onRemovedObject(f);
changed = true;
resetInternalBuffers();
unselected = f;
}
else if (f.isSelectable() && addInStorage(f)) {
if (selected!=null) {
fireSelected(selected, true);
selected = null;
}
else if (unselected!=null) {
fireUnselected(unselected, true);
unselected = null;
}
onAddedObject(f);
changed = true;
resetInternalBuffers();
selected = f;
}
}
if (selected!=null) {
fireSelected(selected, false);
}
else if (unselected!=null) {
fireUnselected(unselected, false);
}
if (changed) {
updateSystemSelection();
}
return changed;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized final boolean add(OBJ e) {
if (e.isSelectable() && addInStorage(e)) {
onAddedObject(e);
resetInternalBuffers();
fireSelected(e, false);
updateSystemSelection();
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized final boolean remove(Object o) {
if (o!=null && this.elementType.isInstance(o)) {
OBJ obj = this.elementType.cast(o);
if (removeFromStorage(obj)) {
onRemovedObject(obj);
resetInternalBuffers();
fireUnselected(obj, false);
updateSystemSelection();
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized final boolean addAll(Collection extends OBJ> c) {
boolean changed = false;
if (c!=null) {
OBJ selected = null;
for(OBJ obj : c) {
if (obj.isSelectable() && addInStorage(obj)) {
if (selected!=null) {
fireSelected(selected, true);
}
onAddedObject(obj);
resetInternalBuffers();
changed = true;
selected = obj;
}
}
if (selected!=null) {
fireSelected(selected, false);
}
}
if (changed) {
updateSystemSelection();
}
return changed;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized final boolean retainAll(Collection> c) {
boolean changed = false;
if (c==null || c.isEmpty()) {
changed = !isEmpty();
clear();
}
else {
OBJ unselected = null;
Iterator iterator = getIteratorOnStorage();
OBJ selObject;
while (iterator.hasNext()) {
selObject = iterator.next();
if (!c.contains(selObject)) {
if (unselected!=null) {
fireUnselected(unselected, true);
}
iterator.remove();
onRemovedObject(selObject);
changed = true;
resetInternalBuffers();
unselected = selObject;
}
}
if (unselected!=null) {
fireUnselected(unselected, false);
}
}
if (changed) {
updateSystemSelection();
}
return changed;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized final boolean removeAll(Collection> c) {
boolean changed = false;
if (c!=null) {
OBJ unselected = null;
for(Object o : c) {
if (o!=null && this.elementType.isInstance(o)) {
OBJ obj = this.elementType.cast(o);
if (removeFromStorage(obj)) {
if (unselected!=null) {
fireUnselected(unselected, true);
}
onRemovedObject(obj);
resetInternalBuffers();
changed = true;
unselected = obj;
}
}
}
if (unselected!=null) {
fireUnselected(unselected, false);
}
}
if (changed) {
updateSystemSelection();
}
return changed;
}
/**
* Select the specified selectable object and deselect all the previously
* selected objects.
*
* @param e is the selectable object to select.
* @return true if the selection has changed;
* otherwise false.
*/
public final boolean setSelection(OBJ... e) {
return setSelection(Arrays.asList(e));
}
/**
* Select the specified selectable object and deselect all the previously
* selected objects.
*
* @param e is the selectable object to select.
* @return true if the selection has changed;
* otherwise false.
*/
public synchronized final boolean setSelection(Collection extends OBJ> e) {
boolean changed = false;
Set alreadySelected = new TreeSet();
OBJ unselected = null;
OBJ selected = null;
Iterator iterator = getIteratorOnStorage();
OBJ selObject;
while (iterator.hasNext()) {
selObject = iterator.next();
if (!e.contains(selObject)) {
if (unselected!=null) {
fireUnselected(unselected, true);
}
iterator.remove();
onRemovedObject(selObject);
changed = true;
resetInternalBuffers();
unselected = selObject;
}
else {
alreadySelected.add(selObject);
}
}
for(OBJ fig : e) {
if (fig.isSelectable() &&
!alreadySelected.contains(fig)
&& addInStorage(fig)) {
if (selected!=null) {
fireSelected(selected, true);
}
else if (unselected!=null) {
fireUnselected(unselected, true);
unselected = null;
}
onAddedObject(fig);
changed = true;
resetInternalBuffers();
selected = fig;
}
}
if (selected!=null) {
fireSelected(selected, false);
}
else if (unselected!=null) {
fireUnselected(unselected, false);
}
if (changed) {
updateSystemSelection();
}
return changed;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized final Iterator iterator() {
return new SelectionIterator(getIteratorOnStorage());
}
/**
* {@inheritDoc}
*/
@Override
public synchronized final void clear() {
Collection elements = clearStorage();
if (!elements.isEmpty()) {
resetInternalBuffers();
updateSystemSelection();
Iterator iterator = elements.iterator();
OBJ obj;
while (iterator.hasNext()) {
obj = iterator.next();
onRemovedObject(obj);
resetInternalBuffers();
fireUnselected(obj, iterator.hasNext());
}
}
}
/**
* @author Stéphane GALLAND
* @version 12.0 2015-04-09 01:26:18
* @mavengroupid org.arakhne.afc.ui
* @mavenartifactid base
*/
private class SelectionIterator implements Iterator {
private final Iterator iterator;
private OBJ lastObject = null;
public SelectionIterator(Iterator iterator) {
this.iterator = iterator;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
synchronized(SelectionManager.this) {
return this.iterator.hasNext();
}
}
/**
* {@inheritDoc}
*/
@Override
public OBJ next() {
synchronized(SelectionManager.this) {
this.lastObject = this.iterator.next();
}
return this.lastObject;
}
/**
* {@inheritDoc}
*/
@Override
public void remove() {
OBJ obj = this.lastObject;
this.lastObject = null;
if (obj==null) throw new NoSuchElementException();
synchronized(SelectionManager.this) {
this.iterator.remove();
}
onRemovedObject(obj);
resetInternalBuffers();
fireUnselected(obj, false);
updateSystemSelection();
}
} // class SelectionIterator
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy