001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI for
003: * visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or modify it under
008: * the terms of the GNU General Public License as published by the Free Software
009: * Foundation; either version 2 of the License, or (at your option) any later
010: * version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
014: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
015: * details.
016: *
017: * You should have received a copy of the GNU General Public License along with
018: * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
019: * Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions Suite #1A 2328 Government Street Victoria BC V8T 5G5 Canada
024: *
025: * (250)385-6040 www.vividsolutions.com
026: */
027: package com.vividsolutions.jump.workbench.ui.renderer.style;
028:
029: import java.awt.BasicStroke;
030: import java.awt.Color;
031: import java.awt.Graphics2D;
032: import java.awt.Stroke;
033: import java.util.*;
034: import java.util.ArrayList;
035: import java.util.HashMap;
036: import java.util.Iterator;
037: import java.util.List;
038: import java.util.Map;
039: import javax.swing.Icon;
040: import com.vividsolutions.jts.util.Assert;
041: import com.vividsolutions.jump.feature.Feature;
042: import com.vividsolutions.jump.feature.FeatureSchema;
043: import com.vividsolutions.jump.util.LangUtil;
044: import com.vividsolutions.jump.workbench.model.Layer;
045: import com.vividsolutions.jump.workbench.ui.GUIUtil;
046: import com.vividsolutions.jump.workbench.ui.Viewport;
047:
048: public class ColorThemingStyle implements Style {
049: public ColorThemingStyle() {
050: //Parameterless constructor for Java2XML. [Jon Aquino]
051: }
052:
053: /**
054: * Call this method after calling #setAttributeValueToBasicStyleMap rather
055: * than before.
056: */
057: public void setAlpha(int alpha) {
058: defaultStyle.setAlpha(alpha);
059: for (Iterator i = attributeValueToBasicStyleMap.values()
060: .iterator(); i.hasNext();) {
061: BasicStyle style = (BasicStyle) i.next();
062: style.setAlpha(alpha);
063: }
064: }
065:
066: /**
067: * Call this method after calling #setAttributeValueToBasicStyleMap rather
068: * than before.
069: */
070: public void setLineWidth(int lineWidth) {
071: defaultStyle.setLineWidth(lineWidth);
072: for (Iterator i = attributeValueToBasicStyleMap.values()
073: .iterator(); i.hasNext();) {
074: BasicStyle style = (BasicStyle) i.next();
075: style.setLineWidth(lineWidth);
076: }
077: }
078:
079: /**
080: * @param defaultStyle
081: * <code>null</code> to prevent drawing features with a null
082: * attribute value
083: */
084: public ColorThemingStyle(String attributeName,
085: Map attributeValueToBasicStyleMap, BasicStyle defaultStyle) {
086: this (
087: attributeName,
088: attributeValueToBasicStyleMap,
089: attributeValueToLabelMap(attributeValueToBasicStyleMap),
090: defaultStyle);
091: // [sstein: 2.Dec.06] i guess this constructor comes from Erwan to
092: // allow different types of classing
093: }
094:
095: public ColorThemingStyle(String attributeName,
096: Map attributeValueToBasicStyleMap,
097: Map attributeValueToLabelMap, BasicStyle defaultStyle) {
098: setAttributeName(attributeName);
099: setAttributeValueToBasicStyleMap(attributeValueToBasicStyleMap);
100: setAttributeValueToLabelMap(attributeValueToLabelMap);
101: setDefaultStyle(defaultStyle);
102: }
103:
104: private static Map attributeValueToLabelMap(
105: Map attributeValueToBasicStyleMap) {
106: // Be sure to use the same Map class -- it may be a RangeTreeMap [Jon Aquino 2005-07-30]
107: Map attributeValueToLabelMap = (Map) LangUtil
108: .newInstance(attributeValueToBasicStyleMap.getClass());
109: for (Iterator i = attributeValueToBasicStyleMap.keySet()
110: .iterator(); i.hasNext();) {
111: Object value = i.next();
112: attributeValueToLabelMap.put(value, value.toString());
113: }
114: return attributeValueToLabelMap;
115: }
116:
117: private BasicStyle defaultStyle;
118:
119: public void paint(Feature f, Graphics2D g, Viewport viewport)
120: throws Exception {
121: getStyle(f).paint(f, g, viewport);
122: }
123:
124: private BasicStyle getStyle(Feature feature) {
125: //Attribute name will be null if a layer has only a spatial attribute.
126: // [Jon Aquino]
127: //If we can't find an attribute with this name, just use the
128: //defaultStyle. The attribute may have been deleted. [Jon Aquino]
129: // If the attribute data type for color theming has been changed -
130: // throws multiple exceptions and the layer dissappears due to the
131: // fact that it can't find the style in the valuetobasicstyle map.
132: // Solved here by catching the exception and returning the default style
133: // (just like when the attribute name has been changed). [Ed Deen]
134: BasicStyle style = null;
135: try {
136: style = attributeName != null
137: && feature.getSchema().hasAttribute(attributeName)
138: && feature.getAttribute(attributeName) != null ? (BasicStyle) attributeValueToBasicStyleMap
139: .get(trimIfString(feature
140: .getAttribute(attributeName)))
141: : defaultStyle;
142: } catch (ClassCastException e) {
143: // Do Nothing
144: }
145: ; /*try*/
146:
147: return style == null ? defaultStyle : style;
148: }
149:
150: public static Object trimIfString(Object object) {
151: return object != null && object instanceof String ? ((String) object)
152: .trim()
153: : object;
154: }
155:
156: private Layer layer;
157: private Map attributeValueToBasicStyleMap = new HashMap(); //[sstein 2.Dec.06] added = new Hashmap
158: private Map attributeValueToLabelMap;
159: private String attributeName;
160:
161: //[sstein 2.Dec.06] note: some things here are different. I am not sure if the changes
162: // come from changes by VividSolution or preparations for different classing by Erwan
163: public Object clone() {
164: try {
165: ColorThemingStyle clone = (ColorThemingStyle) super .clone();
166: //Deep-copy the map, to facilitate undo. [Jon Aquino]
167: clone.attributeValueToBasicStyleMap = (Map) attributeValueToBasicStyleMap
168: .getClass().newInstance();
169: for (Iterator i = attributeValueToBasicStyleMap.keySet()
170: .iterator(); i.hasNext();) {
171: Object attribute = (Object) i.next();
172: clone.attributeValueToBasicStyleMap.put(attribute,
173: ((BasicStyle) attributeValueToBasicStyleMap
174: .get(attribute)).clone());
175: }
176: clone.attributeValueToLabelMap = (Map) attributeValueToLabelMap
177: .getClass().newInstance();
178: clone.attributeValueToLabelMap
179: .putAll(attributeValueToLabelMap);
180: return clone;
181: } catch (InstantiationException e) {
182: Assert.shouldNeverReachHere();
183: return null;
184: } catch (IllegalAccessException e) {
185: Assert.shouldNeverReachHere();
186: return null;
187: } catch (CloneNotSupportedException e) {
188: Assert.shouldNeverReachHere();
189: return null;
190: }
191: }
192:
193: /**
194: * @return null if the layer has no non-spatial attributes
195: */
196: public String getAttributeName() {
197: return attributeName;
198: }
199:
200: /**
201: * You can set the keys to Ranges if the Map is a Range.RangeTreeMap. But
202: * don't mix Ranges and non-Ranges -- the UI expects homogeneity in this
203: * regard (i.e. to test whether or not there are ranges, only the first
204: * attribute value is tested).
205: */
206: public void setAttributeValueToBasicStyleMap(
207: Map attributeValueToBasicStyleMap) {
208: this .attributeValueToBasicStyleMap = attributeValueToBasicStyleMap;
209: }
210:
211: /**
212: * You can set the keys to Ranges if the Map is a Range.RangeTreeMap. But
213: * don't mix Ranges and non-Ranges -- the UI expects homogeneity in this
214: * regard (i.e. to test whether or not there are ranges, only the first
215: * attribute value is tested).
216: */
217: public void setAttributeValueToLabelMap(Map attributeValueToLabelMap) {
218: this .attributeValueToLabelMap = attributeValueToLabelMap;
219: }
220:
221: public void setAttributeName(String attributeName) {
222: this .attributeName = attributeName;
223: }
224:
225: public Map getAttributeValueToBasicStyleMap() {
226: return attributeValueToBasicStyleMap;
227: }
228:
229: public Map getAttributeValueToLabelMap() {
230: return attributeValueToLabelMap;
231: }
232:
233: private boolean enabled = false;
234:
235: public void initialize(Layer layer) {
236: this .layer = layer;
237: }
238:
239: public void setEnabled(boolean enabled) {
240: this .enabled = enabled;
241: }
242:
243: public boolean isEnabled() {
244: return enabled;
245: }
246:
247: public static ColorThemingStyle get(Layer layer) {
248: if ((ColorThemingStyle) layer.getStyle(ColorThemingStyle.class) == null) {
249: ColorThemingStyle colorThemingStyle = new ColorThemingStyle(
250: pickNonSpatialAttributeName(layer
251: .getFeatureCollectionWrapper()
252: .getFeatureSchema()), new HashMap(),
253: new BasicStyle(Color.lightGray));
254: layer.addStyle(colorThemingStyle);
255: }
256: return (ColorThemingStyle) layer
257: .getStyle(ColorThemingStyle.class);
258: }
259:
260: private static String pickNonSpatialAttributeName(
261: FeatureSchema schema) {
262: for (int i = 0; i < schema.getAttributeCount(); i++) {
263: if (schema.getGeometryIndex() != i) {
264: return schema.getAttributeName(i);
265: }
266: }
267: return null;
268: }
269:
270: public BasicStyle getDefaultStyle() {
271: return defaultStyle;
272: }
273:
274: public void setDefaultStyle(BasicStyle defaultStyle) {
275: this.defaultStyle = defaultStyle;
276: }
277: }
|