001: package net.refractions.udig.style.sld;
002:
003: import java.awt.Color;
004: import java.util.ArrayList;
005: import java.util.List;
006:
007: import net.refractions.udig.project.internal.Layer;
008: import net.refractions.udig.project.internal.StyleBlackboard;
009: import net.refractions.udig.style.sld.simple.FillViewer;
010: import net.refractions.udig.style.sld.simple.GraphicViewer;
011: import net.refractions.udig.style.sld.simple.LabelViewer;
012: import net.refractions.udig.style.sld.simple.Mode;
013: import net.refractions.udig.style.sld.simple.ScaleViewer;
014: import net.refractions.udig.style.sld.simple.StrokeViewer;
015: import net.refractions.udig.ui.graphics.SLDs;
016:
017: import org.eclipse.swt.SWT;
018: import org.eclipse.swt.events.KeyAdapter;
019: import org.eclipse.swt.events.KeyEvent;
020: import org.eclipse.swt.events.SelectionEvent;
021: import org.eclipse.swt.events.SelectionListener;
022: import org.eclipse.swt.widgets.Composite;
023: import org.geotools.data.FeatureSource;
024: import org.geotools.feature.FeatureType;
025: import org.geotools.styling.FeatureTypeStyle;
026: import org.geotools.styling.Fill;
027: import org.geotools.styling.Graphic;
028: import org.geotools.styling.LabelPlacement;
029: import org.geotools.styling.LineSymbolizer;
030: import org.geotools.styling.PointSymbolizer;
031: import org.geotools.styling.PolygonSymbolizer;
032: import org.geotools.styling.Rule;
033: import org.geotools.styling.Stroke;
034: import org.geotools.styling.Style;
035: import org.geotools.styling.Symbolizer;
036: import org.geotools.styling.TextSymbolizer;
037:
038: /**
039: * Defines a "simple" StyleConfigurator for working with SLD documents.
040: * <p>
041: * This style configurator is defined as follows:
042: *
043: * <pre><code>
044: * +-+ +-------+ +------+ +------+
045: * Line: |x| | color | |size\/| |100%\/|
046: * +-+ +-------+ +------+ +------+
047: * +-+ +-------+ +------+
048: * Fill: |x| | color | | 90%\/|
049: * +-+ +-------+ +------+
050: * +-+ +----------------+ +------+
051: * Label: |x| | title\/| | Font |
052: * +-+ +----------------+ +------+
053: * +-+ +-------+ +------+
054: * Point: |x| | star\/| |size\/|
055: * +-+ +-------+ +------+
056: * +-+ +-------------+
057: * Min scale d.: |x| | scale\/|
058: * +-+ +-------------+
059: * +-+ +-------------+
060: * Max scale d.: |x| | scale\/|
061: * +-+ +-------------+
062: * </code></pre>
063: *
064: * </p>
065: * Where:
066: * <ul>
067: * <li>Line is used for: <br>
068: * LineString: line color, width, opacity <br>
069: * Polygon: border color, width, opacity <br>
070: * Point: border color, width, opacity
071: * <li>Fill is used for Polygon or Point fill color, opacity
072: * <li>Label is used to choose attribute and set font (the only dialog)
073: * <li>Point is used to set the marker type and size
074: * <li>Min/max scale denominator define at which scale the layer is visible
075: * </ul>
076: * </p>
077: * <p>
078: * Notes:
079: * <ul>
080: * <li>RasterSymbolizer is handled by its own thing, as is WMS etc...
081: * <li>Layout as per the SLDEditorPart examples - so we can take advantage of more or less room.
082: * <li>Presets is a good idea, just not here
083: * <li>Apply/Revert buttons to be green/red
084: * <li>Advanced (edit the SLD) can be in the view menu
085: * <li>If possible replace color button with a drop down list (may not be possible)
086: * </ul>
087: * </P>
088: * <p>
089: * We will do our best to make this thing reusable on an Array of Symbolizers.
090: * </p>
091: *
092: * @author Jody Garnett
093: * @since 1.0.0
094: */
095: public class SimpleStyleConfigurator extends AbstractSimpleConfigurator {
096: StrokeViewer line = new StrokeViewer();
097: FillViewer fill = new FillViewer();
098: GraphicViewer point = new GraphicViewer();
099: LabelViewer label = new LabelViewer();
100: ScaleViewer minScale = new ScaleViewer(ScaleViewer.MIN);
101: ScaleViewer maxScale = new ScaleViewer(ScaleViewer.MAX);
102:
103: Mode mode;
104:
105: SelectionListener synchronize = new SelectionListener() {
106:
107: public void widgetSelected(SelectionEvent e) {
108: synchronize();
109: }
110:
111: public void widgetDefaultSelected(SelectionEvent e) {
112: synchronize();
113: }
114:
115: };
116:
117: /**
118: * Construct <code>SimpleStyleConfigurator</code>.
119: */
120: public SimpleStyleConfigurator() {
121: super ();
122: this .line.addListener(this .synchronize);
123: this .fill.addListener(this .synchronize);
124: this .label.addListener(this .synchronize);
125: this .point.addListener(this .synchronize);
126: this .minScale.addListener(this .synchronize);
127: this .maxScale.addListener(this .synchronize);
128: }
129:
130: @Override
131: public boolean canStyle(Layer aLayer) {
132: if (aLayer.hasResource(FeatureSource.class))
133: return true;
134: return false;
135: }
136:
137: @Override
138: protected void refresh() {
139: Style style = getStyle(); // grab an SLD style or bust
140:
141: // obtain the fts (if an FTS tagged with the SemanticTypeIdentifier "simple" doesn't exist,
142: // null is fine)
143: FeatureTypeStyle[] ftsList = style.getFeatureTypeStyles();
144: FeatureTypeStyle fts = null;
145: for (int i = 0; i < ftsList.length; i++) {
146: if (SLDs.isSemanticTypeMatch(ftsList[i], "simple")) { //$NON-NLS-1$
147: fts = ftsList[i];
148: }
149: // note: the last matching fts is returned (the one drawn last) -- although there should
150: // only be one tagged "simple"
151: }
152:
153: FeatureType schema = getLayer().getSchema();
154: Stroke stroke = null;
155: Fill fill = null;
156: Graphic graphic = null;
157: TextSymbolizer text = null;
158: LabelPlacement placement = null;
159:
160: if (schema == null) {
161: this .mode = Mode.NONE;
162: } else if (SLD.isLine(schema)) {
163: this .mode = Mode.LINE;
164: LineSymbolizer sym = SLDs.lineSymbolizer(fts);
165: stroke = SLDs.stroke(sym);
166: placement = SLDs.getPlacement(SLDs.ALIGN_LEFT,
167: SLDs.ALIGN_MIDDLE, 0);
168: } else if (SLD.isPoint(schema)) {
169: this .mode = Mode.POINT;
170: PointSymbolizer sym = SLDs.pointSymbolizer(fts);
171: stroke = SLDs.stroke(sym);
172: fill = SLDs.fill(sym);
173: graphic = SLDs.graphic(sym);
174: placement = SLDs.getPlacement(SLDs.ALIGN_LEFT,
175: SLDs.ALIGN_MIDDLE, 0);
176: } else if (SLD.isPolygon(schema)) {
177: this .mode = Mode.POLYGON;
178: PolygonSymbolizer sym = SLDs.polySymbolizer(fts);
179: stroke = SLDs.stroke(sym);
180: fill = SLDs.fill(sym);
181: placement = SLDs.getPlacement(SLDs.ALIGN_CENTER,
182: SLDs.ALIGN_MIDDLE, 0);
183: } else {
184: this .mode = Mode.ALL;
185: placement = SLDs.getPlacement(SLDs.ALIGN_LEFT,
186: SLDs.ALIGN_MIDDLE, 0);
187: }
188: if (this .mode != Mode.NONE) {
189: text = SLDs.textSymbolizer(fts);
190: if (text != null && placement != null) {
191: text.setPlacement(placement);
192: }
193: }
194: double minScaleDen = SLDs.minScale(fts);
195: double maxScaleDen = SLDs.maxScale(fts);
196: Color defaultColor = getLayer().getDefaultColor();
197:
198: this .line.setStroke(stroke, this .mode, defaultColor);
199:
200: this .fill.setFill(fill, this .mode, defaultColor);
201: this .point.setGraphic(graphic, this .mode, defaultColor);
202: this .label.set(schema, text, this .mode);
203: this .minScale.setScale(minScaleDen, Math.round(getLayer()
204: .getMap().getViewportModel().getScaleDenominator()));
205: this .maxScale.setScale(maxScaleDen, Math.round(getLayer()
206: .getMap().getViewportModel().getScaleDenominator()));
207: }
208:
209: /** Synchronize the SLD with the array of symbolizers */
210: @Override
211: public void synchronize() {
212: List<Symbolizer> acquire = new ArrayList<Symbolizer>();
213: TextSymbolizer textSym = this .label.get(this .build);
214: switch (this .mode) {
215: case LINE:
216: acquire.add(this .build.createLineSymbolizer(this .line
217: .getStroke(this .build)));
218: if (textSym != null) {
219: acquire.add(textSym);
220: }
221: break;
222: case POLYGON:
223: acquire.add(this .build.createPolygonSymbolizer(this .line
224: .getStroke(this .build), this .fill
225: .getFill(this .build)));
226: if (textSym != null) {
227: acquire.add(textSym);
228: }
229: break;
230: case POINT:
231: acquire
232: .add(this .build.createPointSymbolizer(this .point
233: .getGraphic(this .fill.getFill(this .build),
234: this .line.getStroke(this .build),
235: this .build)));
236: if (textSym != null) {
237: acquire.add(textSym);
238: }
239: break;
240: case ALL:
241: acquire.add(this .build.createLineSymbolizer(this .line
242: .getStroke(this .build)));
243: acquire.add(this .build.createPolygonSymbolizer(this .line
244: .getStroke(this .build), this .fill
245: .getFill(this .build)));
246: acquire
247: .add(this .build.createPointSymbolizer(this .point
248: .getGraphic(this .fill.getFill(this .build),
249: this .line.getStroke(this .build),
250: this .build)));
251: if (textSym != null) {
252: acquire.add(textSym);
253: }
254: break;
255: case NONE:
256: }
257: double minScaleDen = minScale.getScale();
258: double maxScaleDen = maxScale.getScale();
259:
260: Symbolizer[] array = acquire.toArray(new Symbolizer[acquire
261: .size()]);
262: Rule rule = this .build.createRule(array);
263: if (minScale.isEnabled())
264: rule.setMinScaleDenominator(minScaleDen);
265: if (maxScale.isEnabled())
266: rule.setMaxScaleDenominator(maxScaleDen);
267: FeatureTypeStyle featureTypeStyle = this .build
268: .createFeatureTypeStyle(getLayer().getSchema()
269: .getTypeName(), rule);
270: featureTypeStyle.setName("simple"); //$NON-NLS-1$
271: featureTypeStyle.setSemanticTypeIdentifiers(new String[] {
272: "generic:geometry", "simple" }); //$NON-NLS-1$ //$NON-NLS-2$
273:
274: Style style = (Style) getStyleBlackboard().get(SLDContent.ID);
275: style.setDefault(true);
276: FeatureTypeStyle[] fts = style.getFeatureTypeStyles();
277: boolean match = false;
278: for (int i = fts.length - 1; i > -1; i--) {
279: if (SLDs.isSemanticTypeMatch(fts[i], "simple")) { //$NON-NLS-1$
280: fts[i] = featureTypeStyle;
281: match = true;
282: break;
283: }
284: }
285: if (match) {
286: style.setFeatureTypeStyles(fts);
287: } else {
288: // add the new entry to the array
289: FeatureTypeStyle[] fts2 = new FeatureTypeStyle[fts.length + 1];
290: System.arraycopy(fts, 0, fts2, 0, fts.length);
291: fts2[fts.length] = featureTypeStyle;
292: style.setFeatureTypeStyles(fts2);
293: }
294: // put style on blackboard
295: getStyleBlackboard().put(SLDContent.ID, style);
296: ((StyleBlackboard) getStyleBlackboard())
297: .setSelected(new String[] { SLDContent.ID });
298: }
299:
300: @Override
301: public void createControl(Composite parent) {
302: setLayout(parent);
303: KeyAdapter adp = new KeyAdapter() {
304: @Override
305: public void keyReleased(KeyEvent e) {
306: /*
307: * I don't like having different ways of checking for keypad enter and the normal
308: * one. Using the keyCode would be better, but I couldn't readily find the value for
309: * CR.
310: */
311: if (e.keyCode == SWT.KEYPAD_CR || e.character == SWT.CR) {
312: makeActionDoStuff();
313: }
314: }
315: };
316: this.line.createControl(parent, adp);
317: this.fill.createControl(parent, adp);
318: this.point.createControl(parent, adp, this.build);
319: this.label.createControl(parent, adp);
320: this.minScale.createControl(parent, adp);
321: this.maxScale.createControl(parent, adp);
322: }
323:
324: }
|