001: /*
002: * Copyright (c) 2004 JETA Software, Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without modification,
005: * are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JETA Software nor the names of its contributors may
015: * be used to endorse or promote products derived from this software without
016: * specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
021: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
022: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
023: * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
024: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
025: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026: * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: */
029:
030: package com.jeta.forms.gui.form;
031:
032: import java.awt.Component;
033: import java.awt.Container;
034: import java.util.Iterator;
035: import java.util.NoSuchElementException;
036:
037: import com.jeta.forms.gui.beans.JETABean;
038:
039: /**
040: * An iterator for a collection of Java Beans (java.awt.Component objects)
041: * contained by a FormPanel. Only components that occupy a cell in the grid on
042: * the form are returned - not children of those components. For example, if you
043: * have a Java Bean such as a calendar that has several child components, only
044: * the calendar instance will be returned. This iterator will not return the
045: * child components of that bean. However, if a component is a nested form and
046: * this iterator is nested, then this iterator will return the components in the
047: * nested form (as well as the form itself).
048: *
049: * If an iterator encounters a nested form instance, that object will be
050: * returned (regardless of whether the nested flag is set). A component is a
051: * nested form if it is an instance of a FormAccessor:
052: *
053: * <PRE>
054: *
055: * Iterator iter = formaccessor.beanIterator(); while( iter.hasNext() ) {
056: * Component comp = (Component)iter.next(); if ( comp instanceof FormAccessor ) { //
057: * found a nested form. // if this iterator is nested, the next call to <i>next</i>
058: * will // return components in the nested form. } else { // found a standard
059: * Java Bean } }
060: *
061: * </PRE>
062: *
063: * This iterator is fail-fast. If any components are added or removed by
064: * invoking the underlying FormAccessors at any time after the Iterator is
065: * created, the iterator will throw a ConcurrentModificationException. If nested
066: * is true, then the iterator will fail if components are added to <i>any</i>
067: * FormAccessor in the form hierarchy. You may safely call remove on the
068: * iterator if you want to remove the component from the form. Note that you
069: * should not modify the underlying form container by calling the
070: * {@link java.awt.Container} methods directly. This is not recommended and can
071: * also leave the form in an undefined state.
072: *
073: * @author Jeff Tassin
074: */
075: public class FormIterator implements Iterator {
076: /**
077: * The form panel that we are iterating over
078: */
079: private FormAccessor m_accessor;
080:
081: /**
082: * The last time the grid view was modified by an add/remove
083: */
084: private long m_time_stamp;
085:
086: /**
087: * Flag that indicates if components contained by nested forms should be
088: * included If set to false, only components found in the top most form are
089: * included.
090: */
091: private boolean m_nested;
092:
093: /**
094: * The index in the current container
095: */
096: private int m_index = -1;
097:
098: /**
099: * Used if this iterator is nested and we are currently iterating over a
100: * nested form.
101: */
102: private Iterator m_nested_iter = null;
103:
104: /**
105: * The component that last returned by next. This value is cleared every
106: * time we call next or if we call remove.
107: */
108: private Component m_last_comp;
109:
110: /**
111: * This is a modification stamp that the GridView maintains. It keeps track
112: * of when the last modifiation was made to the form. The FormIterator uses
113: * this to implement fail-fast.
114: */
115: private long m_mod_stamp;
116:
117: /**
118: * Constructor
119: *
120: * @param panel
121: * the FormPanel which this iterator is associated with.
122: * @param nested
123: * a flag that indicates if components contained by nested forms
124: * should be included. If set to false, only components found in
125: * the top most form are included.
126: */
127: public FormIterator(FormAccessor accessor, boolean nested) {
128: m_accessor = accessor;
129: m_nested = nested;
130: m_index = -1;
131: m_mod_stamp = ((GridView) accessor).getModificationStamp();
132: }
133:
134: /**
135: * Checks if the container has been modified since this form iterator was
136: * created. This is used to test for fail-fast.
137: */
138: private void checkConcurrentModification() {
139: GridView view = (GridView) m_accessor;
140: if (m_mod_stamp < view.getModificationStamp()) {
141: throw new java.util.ConcurrentModificationException();
142: }
143:
144: long nested_stamp = view.getNestedModificationStamp();
145: if (nested_stamp <= 0)
146: nested_stamp = m_mod_stamp;
147:
148: if (isNested() && (m_mod_stamp < nested_stamp)) {
149: throw new java.util.ConcurrentModificationException();
150: }
151: }
152:
153: /**
154: * Returns the next component in the iteration.
155: *
156: * @return the next component in the iteration.
157: *
158: * @exception NoSuchElementException
159: * iteration has no more elements.
160: */
161: public boolean hasNext() {
162: if (m_nested_iter != null) {
163: if (m_nested_iter.hasNext()) {
164: return true;
165: } else {
166: m_nested_iter = null;
167: }
168: }
169:
170: Container cc = m_accessor.getContainer();
171:
172: int pos = m_index + 1;
173: if (pos >= cc.getComponentCount())
174: return false;
175:
176: while (pos < cc.getComponentCount()) {
177: Component comp = cc.getComponent(pos);
178: if (comp instanceof GridComponent) {
179: GridComponent gc = (GridComponent) comp;
180: if (gc instanceof FormComponent) {
181: m_index = pos - 1;
182: return true;
183: } else if (gc instanceof StandardComponent) {
184: Component jbean = gc.getBeanDelegate();
185: if (jbean != null) {
186: m_index = pos - 1;
187: return true;
188: }
189: }
190: } else if (comp instanceof Component) {
191: m_index = pos - 1;
192: return true;
193: }
194: pos++;
195: }
196: m_index = pos;
197: return false;
198: }
199:
200: private boolean isNested() {
201: return m_nested;
202: }
203:
204: /**
205: * Returns the next component in the iteration.
206: *
207: * @return the next component in the iteration.
208: *
209: * @exception NoSuchElementException
210: * iteration has no more elements.
211: */
212: public Object next() {
213: checkConcurrentModification();
214:
215: if (m_nested_iter != null)
216: return m_nested_iter.next();
217:
218: m_last_comp = null;
219:
220: m_index++;
221: Container cc = m_accessor.getContainer();
222:
223: if (m_index >= cc.getComponentCount())
224: throw new NoSuchElementException();
225:
226: while (m_index < cc.getComponentCount()) {
227: Component comp = cc.getComponent(m_index);
228: if (comp instanceof GridComponent) {
229: GridComponent gc = (GridComponent) comp;
230: if (gc instanceof FormComponent) {
231: FormComponent fc = (FormComponent) gc;
232: if (isNested()) {
233: Iterator niter = new FormIterator(fc
234: .getChildView().getFormAccessor(),
235: isNested());
236: if (niter.hasNext()) {
237: m_nested_iter = niter;
238: }
239: }
240: m_last_comp = fc;
241: return fc.getChildView();
242: } else if (gc instanceof StandardComponent) {
243: /**
244: * This is for handling the case where a delegate is
245: * contained by a JScrollPane (e.g. JTree, JTable etc.) We
246: * should return the scroll pane in this case.
247: */
248: JETABean jetabean = gc.getBean();
249: Component jbean = null;
250: if (jetabean != null)
251: jbean = jetabean.getBeanChildComponent();
252: if (jbean != null) {
253: m_last_comp = jbean;
254: return jbean;
255: }
256: }
257: } else if (comp instanceof Component) {
258: m_last_comp = comp;
259: return comp;
260: }
261: m_index++;
262: }
263:
264: throw new NoSuchElementException();
265: }
266:
267: /**
268: *
269: * Removes from the underlying collection the last component returned by the
270: * iterator. This method can be called only once per call to <tt>next</tt>.
271: *
272: * @exception UnsupportedOperationException
273: * if the <tt>remove</tt> operation is not supported by
274: * this Iterator.
275: *
276: * @exception IllegalStateException
277: * if the <tt>next</tt> method has not yet been called, or
278: * the <tt>remove</tt> method has already been called after
279: * the last call to the <tt>next</tt> method.
280: */
281: public void remove() {
282: checkConcurrentModification();
283:
284: if (m_nested_iter != null) {
285: m_nested_iter.remove();
286: return;
287: }
288:
289: if (m_last_comp == null)
290: throw new IllegalStateException();
291:
292: if (m_accessor.removeBean(m_last_comp) != null) {
293: m_index--;
294: m_last_comp = null;
295: m_mod_stamp = ((GridView) m_accessor)
296: .getModificationStamp();
297: }
298: }
299:
300: }
|