001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.user.client.ui;
017:
018: import java.util.Iterator;
019: import java.util.NoSuchElementException;
020:
021: /**
022: * A simple collection of widgets to be used by
023: * {@link com.google.gwt.user.client.ui.Panel panels} and
024: * {@link com.google.gwt.user.client.ui.Composite composites}.
025: *
026: * <p>
027: * The main purpose of this specialized collection is to implement
028: * {@link java.util.Iterator#remove()} in a way that delegates removal to its
029: * panel. This makes it much easier for the panel to implement an
030: * {@link com.google.gwt.user.client.ui.HasWidgets#iterator() iterator} that
031: * supports removal of widgets.
032: * </p>
033: */
034: public class WidgetCollection {
035:
036: private class WidgetIterator implements Iterator<Widget> {
037:
038: private int index = -1;
039:
040: public boolean hasNext() {
041: return index < (size - 1);
042: }
043:
044: public Widget next() {
045: if (index >= size) {
046: throw new NoSuchElementException();
047: }
048: return array[++index];
049: }
050:
051: public void remove() {
052: if ((index < 0) || (index >= size)) {
053: throw new IllegalStateException();
054: }
055: parent.remove(array[index--]);
056: }
057: }
058:
059: private static final int INITIAL_SIZE = 4;
060:
061: private Widget[] array;
062: private HasWidgets parent;
063: private int size;
064:
065: /**
066: * Constructs a new widget collection.
067: *
068: * @param parent the container whose {@link HasWidgets#remove(Widget)} will be
069: * delegated to by the iterator's {@link Iterator#remove()} method.
070: */
071: public WidgetCollection(HasWidgets parent) {
072: this .parent = parent;
073: array = new Widget[INITIAL_SIZE];
074: }
075:
076: /**
077: * Adds a widget to the end of this collection.
078: *
079: * @param w the widget to be added
080: */
081: public void add(Widget w) {
082: insert(w, size);
083: }
084:
085: /**
086: * Determines whether a given widget is contained in this collection.
087: *
088: * @param w the widget to be searched for
089: * @return <code>true</code> if the widget is present
090: */
091: public boolean contains(Widget w) {
092: return (indexOf(w) != -1);
093: }
094:
095: /**
096: * Gets the widget at the given index.
097: *
098: * @param index the index to be retrieved
099: * @return the widget at the specified index
100: * @throws IndexOutOfBoundsException if the index is out of range
101: */
102: public Widget get(int index) {
103: if ((index < 0) || (index >= size)) {
104: throw new IndexOutOfBoundsException();
105: }
106:
107: return array[index];
108: }
109:
110: /**
111: * Gets the index of the specified index.
112: *
113: * @param w the widget to be found
114: * @return the index of the specified widget, or <code>-1</code> if it is
115: * not found
116: */
117: public int indexOf(Widget w) {
118: for (int i = 0; i < size; ++i) {
119: if (array[i] == w) {
120: return i;
121: }
122: }
123:
124: return -1;
125: }
126:
127: /**
128: * Inserts a widget before the specified index.
129: *
130: * @param w the widget to be inserted
131: * @param beforeIndex the index before which the widget will be inserted
132: * @throws IndexOutOfBoundsException if <code>beforeIndex</code> is out of
133: * range
134: */
135: public void insert(Widget w, int beforeIndex) {
136: if ((beforeIndex < 0) || (beforeIndex > size)) {
137: throw new IndexOutOfBoundsException();
138: }
139:
140: // Realloc array if necessary (doubling).
141: if (size == array.length) {
142: Widget[] newArray = new Widget[array.length * 2];
143: for (int i = 0; i < array.length; ++i) {
144: newArray[i] = array[i];
145: }
146: array = newArray;
147: }
148:
149: ++size;
150:
151: // Move all widgets after 'beforeIndex' back a slot.
152: for (int i = size - 1; i > beforeIndex; --i) {
153: array[i] = array[i - 1];
154: }
155:
156: array[beforeIndex] = w;
157: }
158:
159: /**
160: * Gets an iterator on this widget collection. This iterator is guaranteed to
161: * implement remove() in terms of its containing {@link HasWidgets}.
162: *
163: * @return an iterator
164: */
165: public Iterator<Widget> iterator() {
166: return new WidgetIterator();
167: }
168:
169: /**
170: * Removes the widget at the specified index.
171: *
172: * @param index the index of the widget to be removed
173: * @throws IndexOutOfBoundsException if <code>index</code> is out of range
174: */
175: public void remove(int index) {
176: if ((index < 0) || (index >= size)) {
177: throw new IndexOutOfBoundsException();
178: }
179:
180: --size;
181: for (int i = index; i < size; ++i) {
182: array[i] = array[i + 1];
183: }
184:
185: array[size] = null;
186: }
187:
188: /**
189: * Removes the specified widget.
190: *
191: * @param w the widget to be removed
192: * @throws NoSuchElementException if the widget is not present
193: */
194: public void remove(Widget w) {
195: int index = indexOf(w);
196: if (index == -1) {
197: throw new NoSuchElementException();
198: }
199:
200: remove(index);
201: }
202:
203: /**
204: * Gets the number of widgets in this collection.
205: *
206: * @return the number of widgets
207: */
208: public int size() {
209: return size;
210: }
211: }
|