001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.project.ui.internal;
016:
017: import java.net.URI;
018: import java.util.ArrayList;
019: import java.util.List;
020:
021: import org.eclipse.core.runtime.IConfigurationElement;
022: import org.geotools.feature.AttributeType;
023: import org.geotools.feature.Feature;
024: import org.geotools.feature.FeatureType;
025:
026: /**
027: * This class is used to determine whether a FeatureEditor can be used to edit a feature of a given
028: * FeatureType.
029: * <p>
030: * This class uses the FeatureType element of the FeatureEditor Extension point to determine whether
031: * the editor can be used. See the FeatureEditor extension point declaration for more information.
032: * </p>
033: *
034: * @author jones
035: * @since 1.0.0
036: */
037: public class FeatureTypeMatch {
038:
039: /**
040: * Matches a features attributeType to the featureType declared in the extension.
041: *
042: * @author jones
043: * @since 1.0.0
044: */
045: protected static class AttributeMatcher {
046: String name;
047: Class type;
048:
049: /**
050: * New instance.
051: */
052: public AttributeMatcher(IConfigurationElement attr) {
053: name = attr.getAttribute("name"); //$NON-NLS-1$
054: try {
055: type = Class.forName(attr.getAttribute("type")); //$NON-NLS-1$
056: } catch (Exception e) {
057: ProjectUIPlugin
058: .log(
059: "Extension declaration incorrect:" + attr.getDeclaringExtension().getUniqueIdentifier(), e); //$NON-NLS-1$
060: }
061: }
062:
063: /**
064: * returns true if the attr.getType == type and (name==null or name.equals(attr.getName))
065: *
066: * @param attr
067: * @return
068: */
069: public AttributeType match(FeatureType featureType,
070: List<AttributeType> used) {
071: if (name != null) {
072: AttributeType attr = featureType.getAttributeType(name);
073: if (type == null || attr == null)
074: return null;
075: if (type != attr.getType())
076: return null;
077: return attr;
078: }
079: for (int i = 0; i < featureType.getAttributeCount(); i++) {
080: if (!used.contains(featureType.getAttributeType(i))) {
081: if (type == featureType.getAttributeType(i)
082: .getType())
083: return featureType.getAttributeType(i);
084: }
085: }
086: return null;
087: }
088: }
089:
090: /** A matcher that matches all FeatureTypes */
091: public static final FeatureTypeMatch ALL = new FeatureTypeMatch() {
092: public int matches(Object firstElement) {
093: if (firstElement == null)
094: return -1;
095: return Integer.MAX_VALUE - 1;
096: }
097: };
098: private URI namespace;
099: private String typeName;
100: private AttributeMatcher[] attributes;
101:
102: FeatureTypeMatch() {
103: // do nothing
104: }
105:
106: /**
107: * Create a FeatureTypeMatcher Object
108: *
109: * @param element
110: */
111: public FeatureTypeMatch(IConfigurationElement element) {
112: if (element.getChildren("typeName").length == 1) { //$NON-NLS-1$
113: IConfigurationElement typeName = element
114: .getChildren("typeName")[0]; //$NON-NLS-1$
115: this .typeName = typeName.getAttribute("name"); //$NON-NLS-1$
116: try {
117: this .namespace = new URI(typeName
118: .getAttribute("namespace")); //$NON-NLS-1$
119: } catch (Exception e) {
120: ProjectUIPlugin
121: .log(Messages.FeatureTypeMatch_BadURI, e);
122: }
123: } else {
124: IConfigurationElement[] attributes = element
125: .getChildren("attribute"); //$NON-NLS-1$
126: this .attributes = new AttributeMatcher[attributes.length];
127:
128: for (int i = 0; i < attributes.length; i++) {
129: IConfigurationElement attr = attributes[i];
130: this .attributes[i] = new AttributeMatcher(attr);
131: }
132: }
133:
134: }
135:
136: /**
137: * Returns >-1 if the editor has specified a FeatureType declaration that matches the Feature
138: * passed in as a parameter. Each inaccuracy increases the count by 1. a 0 is a perfect match,
139: * using the featureType name and namespace. 1 would be all the attributeTypes have a name and
140: * type and there are no extra attributes in the feature's feature type.
141: * <p>
142: * The matching is done as follows:
143: * <ul>
144: * <li>If the object is not a feature false is returned.</li>
145: * <li>If namespace is not null then the matching is done by matching the namespace and name of
146: * the featureType</li>
147: * <li>Otherwise the attributes used to match. Two passes are made through the attributes
148: * declared in then extension:
149: * <ul>
150: * <li>First all attributes that are declared and have names associated are processed. There
151: * must be an exact match between the declared attribute and one of the attributeTypes in the
152: * feature</li>
153: * <li>Second all the attributes without declared names are processed. only the type is used to
154: * find a match and each attributeType may be matched only once</li>
155: * </ul>
156: * </ul>
157: *
158: * @param element
159: * @return true if the editor has specified a FeatureType declaration that matches the Feature
160: * passed in as a parameter.
161: */
162: public int matches(Object element) {
163: int accuracy = 0;
164: if (element instanceof Feature) {
165: Feature feature = (Feature) element;
166: if (namespace != null) {
167: if (namespace.equals(feature.getFeatureType()
168: .getNamespace())
169: && typeName.equals(feature.getFeatureType()
170: .getTypeName()))
171: return 0;
172: return -1;
173: }
174: if (attributes.length == 0)
175: return -1;
176: accuracy++;
177: List<AttributeType> matched = new ArrayList<AttributeType>();
178: for (AttributeMatcher current : attributes) {
179: if (current.name == null)
180: continue;
181: AttributeType currentMatch = current.match(feature
182: .getFeatureType(), matched);
183: if (currentMatch == null)
184: return -1;
185: matched.add(currentMatch);
186: }
187: for (AttributeMatcher current : attributes) {
188: if (current.name != null)
189: continue;
190:
191: accuracy++;
192:
193: AttributeType currentMatch = current.match(feature
194: .getFeatureType(), matched);
195: if (currentMatch == null)
196: return -1;
197: matched.add(currentMatch);
198: }
199: accuracy += feature.getFeatureType().getAttributeCount()
200: - matched.size();
201: return accuracy;
202: }
203: return -1;
204: }
205: }
|