001: package org.geotools.feature.iso.collection;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.HashMap;
006: import java.util.Iterator;
007: import java.util.List;
008: import java.util.Map;
009:
010: import org.geotools.data.collection.ResourceCollection;
011: import org.geotools.feature.CollectionListener;
012: import org.geotools.feature.iso.FeatureImpl;
013: import org.geotools.geometry.jts.ReferencedEnvelope;
014: import org.opengis.feature.Attribute;
015: import org.opengis.feature.Feature;
016: import org.opengis.feature.FeatureCollection;
017: import org.opengis.feature.simple.BoundingBoxAttribute;
018: import org.opengis.feature.type.AttributeDescriptor;
019: import org.opengis.feature.type.FeatureType;
020: import org.opengis.geometry.BoundingBox;
021: import org.opengis.referencing.crs.CoordinateReferenceSystem;
022:
023: /**
024: * This is *not* a Feature - it is a Delegate used by FeatureCollection
025: * implementations as "mix-in", provides implementation of featureCollection
026: * events, featureType, and attribute access.
027: * <p>
028: * To use cut&paste the following code exactly:<pre>
029: * <code>
030: *
031: * </code>
032: * </p>
033: * <p>
034: * On the bright side this means we can "fix" all the FeatureCollection implementations
035: * in one fell-swoop.
036: * </p>
037: *
038: * @author Jody Garnett, Refractions Reserach, Inc.
039: * @since GeoTools 2.2
040: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/community-schemas/fm/src/main/java/org/geotools/feature/iso/collection/FeatureState.java $
041: */
042: public class FeatureState extends FeatureImpl {
043: Map userData = null;
044:
045: /**
046: * The data.
047: */
048: protected FeatureCollection data;
049: /**
050: * Internal listener storage list
051: */
052: protected List listeners = new ArrayList(2);
053:
054: protected FeatureState(Collection values, AttributeDescriptor desc,
055: String id, FeatureCollection data) {
056: super (values, desc, id);
057: this .data = data;
058: }
059:
060: protected FeatureState(Collection values, FeatureType type,
061: String id, FeatureCollection data) {
062: super (values, type, id);
063: this .data = data;
064: }
065:
066: //
067: // FeatureCollection Event Support
068: //
069:
070: /**
071: * Adds a listener for collection events.
072: *
073: * @param listener The listener to add
074: */
075: public void addListener(CollectionListener listener) {
076: listeners.add(listener);
077: }
078:
079: /**
080: * Removes a listener for collection events.
081: *
082: * @param listener The listener to remove
083: */
084: public void removeListener(CollectionListener listener) {
085: listeners.remove(listener);
086: }
087:
088: /**
089: * To let listeners know that something has changed.
090: */
091: protected void fireChange(Feature[] features, int type) {
092: /*
093: boundsAttribute().set(null); // must recalculate bounds
094:
095: CollectionEvent cEvent = new CollectionEvent(
096: (FeatureCollection) data, features, type
097: );
098:
099: for (int i = 0, ii = listeners.size(); i < ii; i++) {
100: ((CollectionListener) listeners.get(i)).collectionChanged(cEvent);
101: }
102: */
103: }
104:
105: protected void fireChange(Feature feature, int type) {
106: fireChange(new Feature[] { feature }, type);
107: }
108:
109: protected void fireChange(Collection coll, int type) {
110: Feature[] features = new Feature[coll.size()];
111: features = (Feature[]) coll.toArray(features);
112: fireChange(features, type);
113: }
114:
115: /**
116: * Accessor for getting bouding box attribute.
117: */
118: protected BoundingBoxAttribute boundsAttribute() {
119: for (Iterator itr = attributes().iterator(); itr.hasNext();) {
120: Attribute att = (Attribute) itr.next();
121: //JD: check for GML namespace
122: if ("bounds".equals(att.name().getLocalPart())) {
123: return (BoundingBoxAttribute) att;
124: }
125: }
126:
127: return null;
128: }
129:
130: //
131: // Feature Methods
132: //
133: /**
134: * Gets the bounding box for the features in this feature collection.
135: *
136: * @return the envelope of the geometries contained by this feature
137: * collection.
138: */
139: public BoundingBox getBounds() {
140: BoundingBoxAttribute bbox = boundsAttribute();
141: if (bbox.getValue() == null) {
142: BoundingBox bounds = new ReferencedEnvelope(
143: (CoordinateReferenceSystem) null);
144:
145: Iterator i = data.iterator();
146: try {
147: while (i.hasNext()) {
148: BoundingBox geomBounds = ((Feature) i.next())
149: .getBounds();
150: if (!geomBounds.isEmpty()) {
151: bounds.include(geomBounds);
152: }
153: }
154: } finally {
155: data.close(i);
156: }
157: }
158: return (BoundingBox) bbox.getValue();
159: }
160:
161: /** Test if collection is all features! */
162: public static boolean isFeatures(Collection stuff) {
163: if (stuff instanceof FeatureCollection)
164: return true;
165:
166: Iterator i = stuff.iterator();
167: try {
168: while (i.hasNext()) {
169: if (!(i.next() instanceof Feature))
170: return false;
171: }
172: } finally {
173: if (stuff instanceof ResourceCollection) {
174: ((ResourceCollection) stuff).close(i);
175: }
176: }
177: return true;
178: }
179:
180: public synchronized void putUserData(Object key, Object value) {
181: if (userData == null) {
182: userData = new HashMap();
183: }
184: userData.put(key, value);
185: }
186:
187: public synchronized Object getUserData(Object key) {
188: if (userData != null) {
189: return userData.get(key);
190: }
191: return null;
192: }
193:
194: }
|