package fr.lteconsulting.hexa.client.ui.chart.raphael; import java.util.Iterator; import java.util.NoSuchElementException; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Widget; import fr.lteconsulting.hexa.client.ui.chart.raphael.Raphael.Shape; public class ShapeCollection implements Iterable<Widget> { private class WidgetIterator implements Iterator<Widget> { private int index = -1; public boolean hasNext() { return index < (size - 1); } public Widget next() { if( index >= size ) { throw new NoSuchElementException(); } return array[++index]; } public void remove() { if( (index < 0) || (index >= size) ) { throw new IllegalStateException(); } parent.remove( array[index--] ); } } private static final int INITIAL_SIZE = 4; private Shape[] array; private HasWidgets parent; private int size; /** * Constructs a new widget collection. * * @param parent * the container whose {@link HasWidgets#remove(Widget)} will be * delegated to by the iterator's {@link Iterator#remove()} * method. */ public ShapeCollection( HasWidgets parent ) { this.parent = parent; array = new Shape[INITIAL_SIZE]; } /** * Adds a widget to the end of this collection. * * @param w * the widget to be added */ public void add( Shape w ) { insert( w, size ); } /** * Determines whether a given widget is contained in this collection. * * @param w * the widget to be searched for * @return <code>true</code> if the widget is present */ public boolean contains( Widget w ) { return(indexOf( w ) != -1); } /** * Gets the widget at the given index. * * @param index * the index to be retrieved * @return the widget at the specified index * @throws IndexOutOfBoundsException * if the index is out of range */ public Widget get( int index ) { if( (index < 0) || (index >= size) ) { throw new IndexOutOfBoundsException(); } return array[index]; } public Shape getShape( Widget w ) { int index = indexOf( w ); if( (index < 0) || (index >= size) ) { throw new IndexOutOfBoundsException(); } return array[index]; } /** * Gets the index of the specified index. * * @param w * the widget to be found * @return the index of the specified widget, or <code>-1</code> if it is * not found */ public int indexOf( Widget w ) { for( int i = 0; i < size; ++i ) { if( array[i] == w ) { return i; } } return -1; } /** * Inserts a widget before the specified index. * * @param w * the widget to be inserted * @param beforeIndex * the index before which the widget will be inserted * @throws IndexOutOfBoundsException * if <code>beforeIndex</code> is out of range */ public void insert( Shape w, int beforeIndex ) { if( (beforeIndex < 0) || (beforeIndex > size) ) { throw new IndexOutOfBoundsException(); } // Realloc array if necessary (doubling). if( size == array.length ) { Shape[] newArray = new Shape[array.length * 2]; for( int i = 0; i < array.length; ++i ) { newArray[i] = array[i]; } array = newArray; } ++size; // Move all widgets after 'beforeIndex' back a slot. for( int i = size - 1; i > beforeIndex; --i ) { array[i] = array[i - 1]; } array[beforeIndex] = w; } /** * Gets an iterator on this widget collection. This iterator is guaranteed * to implement remove() in terms of its containing {@link HasWidgets}. * * @return an iterator */ public Iterator<Widget> iterator() { return new WidgetIterator(); } /** * Removes the widget at the specified index. * * @param index * the index of the widget to be removed * @throws IndexOutOfBoundsException * if <code>index</code> is out of range */ public void remove( int index ) { if( (index < 0) || (index >= size) ) { throw new IndexOutOfBoundsException(); } --size; for( int i = index; i < size; ++i ) { array[i] = array[i + 1]; } array[size] = null; } /** * Removes the specified widget. * * @param w * the widget to be removed * @throws NoSuchElementException * if the widget is not present */ public void remove( Widget w ) { int index = indexOf( w ); if( index == -1 ) { throw new NoSuchElementException(); } remove( index ); } /** * Gets the number of widgets in this collection. * * @return the number of widgets */ public int size() { return size; } }