/[schmitzm]/branches/2.0-RC2/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
ViewVC logotype

Contents of /branches/2.0-RC2/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 438 - (show annotations)
Mon Oct 5 13:04:01 2009 UTC (15 years, 4 months ago) by alfonx
Original Path: branches/1.0-gt2-2.6/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
File MIME type: text/plain
File size: 14711 byte(s)
* Using GTUtil.createGTRenderer wherever GP/AS/AV/SchmitzM needs a GTRenderer
1 /*******************************************************************************
2 * Copyright (c) 2009 Martin O. J. Schmitz.
3 *
4 * This file is part of the SCHMITZM library - a collection of utility
5 * classes based on Java 1.6, focusing (not only) on Java Swing
6 * and the Geotools library.
7 *
8 * The SCHMITZM project is hosted at:
9 * http://wald.intevation.org/projects/schmitzm/
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 3
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License (license.txt)
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 * or try this link: http://www.gnu.org/licenses/lgpl.html
25 *
26 * Contributors:
27 * Martin O. J. Schmitz - initial API and implementation
28 * Stefan A. Krüger - additional utility classes
29 ******************************************************************************/
30 /**
31 Copyright 2008 Stefan Alfons Krüger
32
33 atlas-framework - This file is part of the Atlas Framework
34
35 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
36 This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
37 You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
38
39 Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
40 Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
41 Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
42 **/
43 package skrueger.geotools.selection;
44
45 import java.awt.RenderingHints;
46 import java.beans.PropertyChangeEvent;
47 import java.beans.PropertyChangeListener;
48 import java.util.HashMap;
49 import java.util.HashSet;
50 import java.util.Iterator;
51 import java.util.Set;
52 import java.util.Vector;
53
54 import javax.swing.JTable;
55 import javax.swing.ListSelectionModel;
56 import javax.swing.event.ListSelectionListener;
57
58 import org.geotools.map.MapLayer;
59 import org.geotools.renderer.GTRenderer;
60 import org.geotools.renderer.label.LabelCacheImpl;
61 import org.geotools.renderer.lite.StreamingRenderer;
62 import org.geotools.renderer.shape.ShapefileRenderer;
63 import org.geotools.styling.FeatureTypeStyle;
64 import org.geotools.styling.Style;
65 import org.geotools.styling.visitor.DuplicatingStyleVisitor;
66 import org.opengis.feature.simple.SimpleFeature;
67 import org.opengis.filter.identity.FeatureId;
68
69 import schmitzm.geotools.FilterUtil;
70 import schmitzm.geotools.GTUtil;
71 import schmitzm.geotools.gui.JMapPane;
72 import schmitzm.geotools.map.event.FeatureSelectedEvent;
73 import schmitzm.geotools.map.event.JMapPaneEvent;
74 import schmitzm.geotools.map.event.JMapPaneListener;
75 import schmitzm.geotools.styling.StylingUtil;
76 import skrueger.geotools.MapPaneToolBar;
77 import skrueger.geotools.StyledLayerInterface;
78
79 /**
80 * This class keeps the selection of a (feature) {@link JTable} synchronized
81 * with the {@link StyledLayerSelectionModel} of a layer. This is done by
82 * implementing:
83 * <ul>
84 * <li>a {@link PropertyChangeListener} which listens to the
85 * {@link StyledLayerSelectionModel} and accordingly changes the {@link JTable}
86 * selection</li>
87 * <li>a {@link ListSelectionListener} which listens to the {@link JTable} and
88 * accordingly changes the {@link StyledLayerSelectionModel} selection</li>
89 * </ul>
90 * After creating, the instance of this synchronizer must be added as listener
91 * to both, the {@link StyledLayerSelectionModel} and the table's
92 * {@link ListSelectionModel}.
93 *
94 * @author <a href="mailto:[email protected]">Martin Schmitz</a>
95 * (University of Bonn/Germany)
96 */
97 public class FeatureMapLayerSelectionSynchronizer extends
98 StyledLayerSelectionModelSynchronizer<StyledFeatureLayerSelectionModel>
99 implements JMapPaneListener {
100 public static final String SELECTION_STYLING = "SELECTION";
101 /**
102 * Holds the {@link MapLayer} to keep synchronized with the layer selection
103 * model.
104 */
105 protected final MapLayer mapLayer;
106 protected final StyledLayerInterface<?> styledLayer;
107 protected final JMapPane mapPane;
108 private final MapPaneToolBar toolBar;
109 private final HashMap<Object, Object> defaultGTRenderingHints;
110
111 /**
112 * Creates a new synchronizer
113 *
114 * @param layerSelModel
115 * layer selection model to keep synchronized with the
116 * {@link MapLayer}
117 *
118 * @param mapLayer
119 * {@link MapLayer} to keep synchronized with.
120 */
121 public FeatureMapLayerSelectionSynchronizer(
122 StyledFeatureLayerSelectionModel layerSelModel,
123 StyledLayerInterface<?> styledLayer, MapLayer mapLayer,
124 JMapPane mapPane, MapPaneToolBar toolBar, HashMap<Object, Object> defaultGTRenderingHints) {
125
126 super(layerSelModel);
127 this.styledLayer = styledLayer;
128
129 this.mapLayer = mapLayer;
130 this.mapPane = mapPane;
131 this.toolBar = toolBar;
132 if (defaultGTRenderingHints != null)
133 this.defaultGTRenderingHints = defaultGTRenderingHints;
134 else
135 this.defaultGTRenderingHints = new HashMap<Object, Object>();
136 }
137
138 /**
139 * Called by {@link StyledLayerSelectionModel} when a the selection on other
140 * selection components (map, chart, ...) has changed. When calling this
141 *
142 * method changes the {@link MapLayer} selection according to the
143 * {@link StyledLayerSelectionModel} selection.
144 *
145 * @param evt
146 * an event
147 */
148 @Override
149 public void propertyChange(PropertyChangeEvent evt) {
150
151 if (!isEnabled())
152 return;
153
154 if (!(evt instanceof StyledLayerSelectionEvent))
155 return;
156 StyledLayerSelectionEvent selEvt = (StyledLayerSelectionEvent) evt;
157 // Only react on own layer and ignore events invoked by
158 // this component itself
159 if (selEvt.getEmitter() != layerSelModel || selectionChangeCausedByMe)
160 return;
161 // Apply new selection on table (except this event is one of
162 // some more events)
163 Vector<String> newSelection = layerSelModel.getSelection();
164 if (newSelection == null)
165 return;
166
167 // Avoid event circles in valueChanged(..)
168 selectionChangeCausedByMe = true;
169
170 changeLayerStyle(newSelection);
171
172 // Danger of event circles in valueChanged(..) banned
173 selectionChangeCausedByMe = false;
174 }
175
176 /**
177 * Changes the Style of the {@link MapLayer} to reflect changes of the
178 * selection.
179 *
180 * @param newSelection
181 * A {@link Vector} of SimpleFeature-IDs that are selected.
182 */
183 private void changeLayerStyle(final Vector<String> newSelection) {
184 try {
185
186 Style originalStyle = mapLayer.getStyle();
187 if (newSelection.isEmpty()) {
188
189 // Check if the Style contains a SELECTION FTS
190
191 FeatureTypeStyle[] clone = originalStyle.featureTypeStyles().toArray( new FeatureTypeStyle[] {} ).clone();
192
193 for (FeatureTypeStyle fts : clone) {
194 if (fts.getName() != null
195 && fts.getName().equals(SELECTION_STYLING)) {
196 originalStyle.featureTypeStyles().remove(fts);
197
198 replaceRenderer();
199 // mapPane.refresh();
200
201
202 return;
203 }
204 }
205
206 } else {
207 LOGGER.debug("SELECTION .. change style");
208
209 // We take Style from the MapLayer that is displayed at the
210 // moment. We do not use the styledLayer.getStyle, because in
211 // the atlas, this always return the default style, but
212 // additional styles might be selected.
213 // Taking the style from the mapLayer indicated, that we have to
214 // remove any selection rules first.
215
216 FeatureTypeStyle selectionFTStyle = StylingUtil
217 .createSelectionStyle(styledLayer.getGeoObject());
218
219 selectionFTStyle.setName(SELECTION_STYLING);
220
221 /**
222 *
223 * Add a Filter to the selectionMapStyle, so that it is only
224 * used on objects that are selected. <br/>
225 *
226 * Note 1:<br/>
227 * It is NEVER allowed to GeoTools extend Filter () { .. } (and
228 * write tests into the evaluate block). Especially for the
229 * ShapeFileRenderer, we may only use a geotools Filter.<br/>
230 *
231 * Note 2:<br/>
232 * The FilterUtil.FILTER_FAC2.id(fids) wants a set of
233 * FeatureId-Objects!
234 */
235
236 Set<FeatureId> fids = new HashSet<FeatureId>();
237 for (String fid : newSelection) {
238 fids.add(FilterUtil.FILTER_FAC2.featureId(fid));
239 }
240
241 selectionFTStyle.rules().get(0).setFilter(
242 FilterUtil.FILTER_FAC2.id(fids));
243
244 // Maybe there has already been another selection
245 // FeatureTypeStyle... Let's replace it...
246 boolean foundAndReplaced = false;
247 for (FeatureTypeStyle fts : originalStyle.featureTypeStyles()) {
248 if (fts.getName() != null
249 && fts.getName().equals(SELECTION_STYLING)) {
250 foundAndReplaced = true;
251 fts.rules().clear();
252 fts.rules().addAll(selectionFTStyle.rules());
253 break;
254 }
255 }
256 if (!foundAndReplaced) {
257 originalStyle.featureTypeStyles().add(selectionFTStyle);
258 }
259
260
261
262 // Refresh the map
263 // mapPane.refresh();
264
265 DuplicatingStyleVisitor dsv = new DuplicatingStyleVisitor();
266 dsv.visit(originalStyle);
267 Style newStyle = (Style)dsv.getCopy();
268
269 // Style newStyle = StylingUtil.STYLE_BUILDER.createStyle();
270 // newStyle.featureTypeStyles().addAll(originalStyle.featureTypeStyles());
271 mapLayer.setStyle(newStyle);
272
273 replaceRenderer();
274 }
275
276 } catch (Exception e) {
277 LOGGER.error("Error while trying to create a selection style", e);
278 }
279 }
280
281 private void replaceRenderer() {
282 //
283 // // Has to be done before we apply the new Renderer
284 // mapLayer.setStyle(style);
285
286 GTRenderer oldRenderer = mapPane.getRenderer();
287
288 /**
289 * Explicitly putting a new instance of LabelCacheDefault into the
290 * renderer instance, so JMapPane doesn't reuse the old one. This is
291 * very useful when changing the TextSymbolizer with AtlasStyler<br/>
292 * SK 9.7.09: It's not enought to user LabelCache.clear(). We can not
293 * reuse the old Renderer - better to create a new one!
294 */
295 final GTRenderer newRenderer = GTUtil.createGTRenderer(oldRenderer.getContext());
296
297 final HashMap<Object, Object> rendererHints = defaultGTRenderingHints;
298 rendererHints.put(StreamingRenderer.LABEL_CACHE_KEY,
299 new LabelCacheImpl());
300
301 newRenderer.setRendererHints(rendererHints);
302 mapPane.setRenderer(newRenderer);
303
304 if (oldRenderer != null) {
305
306 RenderingHints java2DHints = oldRenderer.getJava2DHints();
307 if (java2DHints != null) {
308 newRenderer.setJava2DHints(java2DHints);
309 }
310
311 oldRenderer.setContext(null);
312 oldRenderer = null;
313 }
314
315 mapPane.refresh();
316
317 }
318
319 /**
320 * Used to synchronize {@link FeatureSelectedEvent}s with the
321 * {@link StyledFeatureLayerSelectionModel}
322 */
323 @Override
324 public void performMapPaneEvent(JMapPaneEvent e) {
325
326 // Ignore event if it is caused by us or the synchronizer is disabled.
327 if (!isEnabled() || selectionChangeCausedByMe)
328 return;
329
330 if (!(e instanceof FeatureSelectedEvent)) {
331 // LOGGER.debug("Ignoring event " + e);
332 return;
333 }
334
335 /**
336 * Only listen to FeatureSelectedEvents if an appropriate tool is
337 * selected.
338 */
339 final int selectedTool = toolBar.getSelectedTool();
340 if (selectedTool != MapPaneToolBar.TOOL_SELECTION_ADD
341 && selectedTool != MapPaneToolBar.TOOL_SELECTION_REMOVE
342 && selectedTool != MapPaneToolBar.TOOL_SELECTION_SET) {
343 return;
344 }
345
346 // only listen to events directly coming from JMapPane
347 // selection (ignore selections from FilterDialog)
348 if (e.getSourceObject() != this.mapPane)
349 return;
350
351 FeatureSelectedEvent fse = (FeatureSelectedEvent) e;
352
353 /**
354 * Checking, that the FeatureSelectedEvent actually contains features
355 * from this layer
356 */
357 final String sourceID = fse.getSourceLayer().getTitle();
358 final String syncForID = mapLayer.getTitle();
359 if (sourceID != null && syncForID != null
360 && !sourceID.equals(syncForID)) {
361 LOGGER.debug("Ignoring a FeatureSelectedEvent from " + sourceID);
362 return;
363 }
364
365 LOGGER.debug("do event " + fse);
366
367 // Avoid event circles in propertyChange(..)
368 selectionChangeCausedByMe = true;
369
370 Iterator<SimpleFeature> fi = fse.getSelectionResult().iterator();
371
372 // reset the selection of the DpLayerSelectionModel
373 // layerSelModel.setValueIsAdjusting(true);
374
375 if (selectedTool == MapPaneToolBar.TOOL_SELECTION_ADD) {
376 layerSelModel.setValueIsAdjusting(true);
377
378 for (int fIdx = 0; fi.hasNext(); fIdx++) {
379 SimpleFeature f = fi.next();
380 layerSelModel.addSelection(f.getID());
381 }
382 layerSelModel.setValueIsAdjusting(false);
383 } else if (selectedTool == MapPaneToolBar.TOOL_SELECTION_SET) {
384 layerSelModel.setValueIsAdjusting(true);
385 layerSelModel.clearSelection();
386
387 for (int fIdx = 0; fi.hasNext(); fIdx++) {
388 SimpleFeature f = fi.next();
389 layerSelModel.addSelection(f.getID());
390 }
391
392 // LOGGER.debug("Setting selection to " + fi.());
393
394 layerSelModel.setValueIsAdjusting(false);
395 } else if (selectedTool == MapPaneToolBar.TOOL_SELECTION_REMOVE) {
396 layerSelModel.setValueIsAdjusting(true);
397 for (int fIdx = 0; fi.hasNext(); fIdx++) {
398 SimpleFeature f = fi.next();
399 layerSelModel.removeSelection(f.getID());
400 }
401 layerSelModel.setValueIsAdjusting(false);
402 }
403
404 // Show selected features in the map, which is not automatically done by
405 // the origin: FeatureSelectedEvent
406 changeLayerStyle(layerSelModel.getSelection());
407
408 // Danger of event circles in propertyChange(..) banned
409 selectionChangeCausedByMe = false;
410 }
411
412 }

Properties

Name Value
svn:eol-style native
svn:keywords Id
svn:mime-type text/plain

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26