/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.user.client.ui; import java.util.Iterator; import java.util.NoSuchElementException; /** * A simple collection of widgets to be used by * {@link com.google.gwt.user.client.ui.Panel panels} and * {@link com.google.gwt.user.client.ui.Composite composites}. * * <p> * The main purpose of this specialized collection is to implement * {@link java.util.Iterator#remove()} in a way that delegates removal to its * panel. This makes it much easier for the panel to implement an * {@link com.google.gwt.user.client.ui.HasWidgets#iterator() iterator} that * supports removal of widgets. * </p> */ public class WidgetCollection 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 Widget[] 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 WidgetCollection(HasWidgets parent) { this.parent = parent; array = new Widget[INITIAL_SIZE]; } /** * Adds a widget to the end of this collection. * * @param w the widget to be added */ public void add(Widget 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]; } /** * 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(Widget w, int beforeIndex) { if ((beforeIndex < 0) || (beforeIndex > size)) { throw new IndexOutOfBoundsException(); } // Realloc array if necessary (doubling). if (size == array.length) { Widget[] newArray = new Widget[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; } }