/[schmitzm]/trunk/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
ViewVC logotype

Annotation of /trunk/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 455 - (hide annotations)
Sun Oct 11 21:41:53 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: 14878 byte(s)
* Feature iterator has to be closed!
1 alfonx 244 /*******************************************************************************
2     * Copyright (c) 2009 Martin O. J. Schmitz.
3     *
4     * This file is part of the SCHMITZM library - a collection of utility
5 alfonx 256 * classes based on Java 1.6, focusing (not only) on Java Swing
6 alfonx 244 * 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 alfonx 97 /**
31     Copyright 2008 Stefan Alfons Krüger
32 alfonx 409
33 alfonx 97 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 alfonx 419 import java.awt.RenderingHints;
46 alfonx 97 import java.beans.PropertyChangeEvent;
47     import java.beans.PropertyChangeListener;
48 alfonx 419 import java.util.HashMap;
49 alfonx 158 import java.util.HashSet;
50 alfonx 409 import java.util.Iterator;
51 alfonx 158 import java.util.Set;
52 alfonx 97 import java.util.Vector;
53    
54     import javax.swing.JTable;
55     import javax.swing.ListSelectionModel;
56     import javax.swing.event.ListSelectionListener;
57    
58 alfonx 455 import org.geotools.feature.FeatureCollection;
59 alfonx 97 import org.geotools.map.MapLayer;
60 alfonx 419 import org.geotools.renderer.GTRenderer;
61     import org.geotools.renderer.label.LabelCacheImpl;
62     import org.geotools.renderer.lite.StreamingRenderer;
63 alfonx 123 import org.geotools.styling.FeatureTypeStyle;
64 alfonx 97 import org.geotools.styling.Style;
65 alfonx 419 import org.geotools.styling.visitor.DuplicatingStyleVisitor;
66 mojays 325 import org.opengis.feature.simple.SimpleFeature;
67 alfonx 455 import org.opengis.feature.simple.SimpleFeatureType;
68 alfonx 158 import org.opengis.filter.identity.FeatureId;
69 alfonx 97
70 alfonx 158 import schmitzm.geotools.FilterUtil;
71 alfonx 438 import schmitzm.geotools.GTUtil;
72 alfonx 97 import schmitzm.geotools.gui.JMapPane;
73     import schmitzm.geotools.map.event.FeatureSelectedEvent;
74     import schmitzm.geotools.map.event.JMapPaneEvent;
75     import schmitzm.geotools.map.event.JMapPaneListener;
76     import schmitzm.geotools.styling.StylingUtil;
77 alfonx 111 import skrueger.geotools.MapPaneToolBar;
78 alfonx 224 import skrueger.geotools.StyledLayerInterface;
79 alfonx 97
80     /**
81     * This class keeps the selection of a (feature) {@link JTable} synchronized
82     * with the {@link StyledLayerSelectionModel} of a layer. This is done by
83     * implementing:
84     * <ul>
85     * <li>a {@link PropertyChangeListener} which listens to the
86     * {@link StyledLayerSelectionModel} and accordingly changes the {@link JTable}
87     * selection</li>
88     * <li>a {@link ListSelectionListener} which listens to the {@link JTable} and
89     * accordingly changes the {@link StyledLayerSelectionModel} selection</li>
90     * </ul>
91     * After creating, the instance of this synchronizer must be added as listener
92     * to both, the {@link StyledLayerSelectionModel} and the table's
93     * {@link ListSelectionModel}.
94     *
95     * @author <a href="mailto:[email protected]">Martin Schmitz</a>
96     * (University of Bonn/Germany)
97     */
98     public class FeatureMapLayerSelectionSynchronizer extends
99 alfonx 106 StyledLayerSelectionModelSynchronizer<StyledFeatureLayerSelectionModel>
100     implements JMapPaneListener {
101 alfonx 111 public static final String SELECTION_STYLING = "SELECTION";
102 alfonx 97 /**
103     * Holds the {@link MapLayer} to keep synchronized with the layer selection
104     * model.
105     */
106     protected final MapLayer mapLayer;
107 alfonx 224 protected final StyledLayerInterface<?> styledLayer;
108 alfonx 97 protected final JMapPane mapPane;
109 alfonx 111 private final MapPaneToolBar toolBar;
110 alfonx 419 private final HashMap<Object, Object> defaultGTRenderingHints;
111 alfonx 97
112     /**
113     * Creates a new synchronizer
114     *
115     * @param layerSelModel
116     * layer selection model to keep synchronized with the
117     * {@link MapLayer}
118     *
119     * @param mapLayer
120     * {@link MapLayer} to keep synchronized with.
121     */
122     public FeatureMapLayerSelectionSynchronizer(
123     StyledFeatureLayerSelectionModel layerSelModel,
124 alfonx 224 StyledLayerInterface<?> styledLayer, MapLayer mapLayer,
125 alfonx 455 JMapPane mapPane, MapPaneToolBar toolBar,
126     HashMap<Object, Object> defaultGTRenderingHints) {
127 alfonx 97
128     super(layerSelModel);
129 alfonx 224 this.styledLayer = styledLayer;
130 alfonx 97
131     this.mapLayer = mapLayer;
132     this.mapPane = mapPane;
133 alfonx 111 this.toolBar = toolBar;
134 alfonx 419 if (defaultGTRenderingHints != null)
135     this.defaultGTRenderingHints = defaultGTRenderingHints;
136 alfonx 455 else
137 alfonx 419 this.defaultGTRenderingHints = new HashMap<Object, Object>();
138 alfonx 97 }
139    
140     /**
141     * Called by {@link StyledLayerSelectionModel} when a the selection on other
142     * selection components (map, chart, ...) has changed. When calling this
143     *
144     * method changes the {@link MapLayer} selection according to the
145     * {@link StyledLayerSelectionModel} selection.
146     *
147     * @param evt
148     * an event
149     */
150     @Override
151     public void propertyChange(PropertyChangeEvent evt) {
152 alfonx 151
153     if (!isEnabled())
154     return;
155    
156 alfonx 97 if (!(evt instanceof StyledLayerSelectionEvent))
157     return;
158     StyledLayerSelectionEvent selEvt = (StyledLayerSelectionEvent) evt;
159     // Only react on own layer and ignore events invoked by
160     // this component itself
161     if (selEvt.getEmitter() != layerSelModel || selectionChangeCausedByMe)
162     return;
163     // Apply new selection on table (except this event is one of
164     // some more events)
165 alfonx 111 Vector<String> newSelection = layerSelModel.getSelection();
166 alfonx 97 if (newSelection == null)
167     return;
168    
169     // Avoid event circles in valueChanged(..)
170     selectionChangeCausedByMe = true;
171    
172     changeLayerStyle(newSelection);
173    
174     // Danger of event circles in valueChanged(..) banned
175     selectionChangeCausedByMe = false;
176     }
177    
178 alfonx 151 /**
179     * Changes the Style of the {@link MapLayer} to reflect changes of the
180     * selection.
181     *
182     * @param newSelection
183 alfonx 318 * A {@link Vector} of SimpleFeature-IDs that are selected.
184 alfonx 151 */
185 alfonx 111 private void changeLayerStyle(final Vector<String> newSelection) {
186 alfonx 97 try {
187 alfonx 455
188 alfonx 412 Style originalStyle = mapLayer.getStyle();
189 alfonx 97 if (newSelection.isEmpty()) {
190    
191 alfonx 412 // Check if the Style contains a SELECTION FTS
192 alfonx 455
193     FeatureTypeStyle[] clone = originalStyle.featureTypeStyles()
194     .toArray(new FeatureTypeStyle[] {}).clone();
195    
196 alfonx 412 for (FeatureTypeStyle fts : clone) {
197     if (fts.getName() != null
198     && fts.getName().equals(SELECTION_STYLING)) {
199     originalStyle.featureTypeStyles().remove(fts);
200 alfonx 455
201 alfonx 419 replaceRenderer();
202 alfonx 455 // mapPane.refresh();
203 alfonx 106
204 alfonx 412 return;
205     }
206     }
207    
208 alfonx 97 } else {
209 alfonx 100 LOGGER.debug("SELECTION .. change style");
210 alfonx 106
211 alfonx 123 // We take Style from the MapLayer that is displayed at the
212 alfonx 224 // moment. We do not use the styledLayer.getStyle, because in
213 alfonx 123 // the atlas, this always return the default style, but
214 alfonx 224 // additional styles might be selected.
215 alfonx 123 // Taking the style from the mapLayer indicated, that we have to
216 alfonx 125 // remove any selection rules first.
217 alfonx 101
218 alfonx 412 FeatureTypeStyle selectionFTStyle = StylingUtil
219 alfonx 224 .createSelectionStyle(styledLayer.getGeoObject());
220 alfonx 106
221 alfonx 412 selectionFTStyle.setName(SELECTION_STYLING);
222 alfonx 123
223 alfonx 158 /**
224     *
225     * Add a Filter to the selectionMapStyle, so that it is only
226     * used on objects that are selected. <br/>
227     *
228     * Note 1:<br/>
229 alfonx 409 * It is NEVER allowed to GeoTools extend Filter () { .. } (and
230     * write tests into the evaluate block). Especially for the
231 alfonx 158 * ShapeFileRenderer, we may only use a geotools Filter.<br/>
232     *
233     * Note 2:<br/>
234 alfonx 409 * The FilterUtil.FILTER_FAC2.id(fids) wants a set of
235     * FeatureId-Objects!
236 alfonx 158 */
237 alfonx 106
238 alfonx 158 Set<FeatureId> fids = new HashSet<FeatureId>();
239     for (String fid : newSelection) {
240     fids.add(FilterUtil.FILTER_FAC2.featureId(fid));
241     }
242 alfonx 106
243 alfonx 412 selectionFTStyle.rules().get(0).setFilter(
244     FilterUtil.FILTER_FAC2.id(fids));
245 alfonx 106
246 alfonx 412 // Maybe there has already been another selection
247     // FeatureTypeStyle... Let's replace it...
248     boolean foundAndReplaced = false;
249     for (FeatureTypeStyle fts : originalStyle.featureTypeStyles()) {
250     if (fts.getName() != null
251     && fts.getName().equals(SELECTION_STYLING)) {
252     foundAndReplaced = true;
253     fts.rules().clear();
254     fts.rules().addAll(selectionFTStyle.rules());
255     break;
256     }
257 alfonx 123 }
258 alfonx 412 if (!foundAndReplaced) {
259     originalStyle.featureTypeStyles().add(selectionFTStyle);
260     }
261 alfonx 151
262 alfonx 412 // Refresh the map
263 alfonx 455 // mapPane.refresh();
264    
265 alfonx 419 DuplicatingStyleVisitor dsv = new DuplicatingStyleVisitor();
266     dsv.visit(originalStyle);
267 alfonx 455 Style newStyle = (Style) dsv.getCopy();
268    
269     // Style newStyle = StylingUtil.STYLE_BUILDER.createStyle();
270     // newStyle.featureTypeStyles().addAll(originalStyle.featureTypeStyles());
271 alfonx 419 mapLayer.setStyle(newStyle);
272 alfonx 455
273 alfonx 419 replaceRenderer();
274 alfonx 97 }
275    
276     } catch (Exception e) {
277     LOGGER.error("Error while trying to create a selection style", e);
278     }
279     }
280    
281 alfonx 419 private void replaceRenderer() {
282 alfonx 455 //
283     // // Has to be done before we apply the new Renderer
284     // mapLayer.setStyle(style);
285 alfonx 419
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 alfonx 440 final GTRenderer newRenderer = GTUtil.createGTRenderer();
296 alfonx 419
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 alfonx 455
306 alfonx 419 RenderingHints java2DHints = oldRenderer.getJava2DHints();
307     if (java2DHints != null) {
308 alfonx 427 newRenderer.setJava2DHints(java2DHints);
309 alfonx 419 }
310 alfonx 455
311 alfonx 419 oldRenderer.setContext(null);
312     oldRenderer = null;
313     }
314 alfonx 455
315 alfonx 419 mapPane.refresh();
316    
317     }
318    
319 alfonx 151 /**
320     * Used to synchronize {@link FeatureSelectedEvent}s with the
321     * {@link StyledFeatureLayerSelectionModel}
322     */
323 alfonx 97 @Override
324     public void performMapPaneEvent(JMapPaneEvent e) {
325 alfonx 106
326 alfonx 151 // 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 alfonx 111 /**
336 alfonx 151 * Only listen to FeatureSelectedEvents if an appropriate tool is
337 alfonx 111 * 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 mojays 109 // only listen to events directly coming from JMapPane
347     // selection (ignore selections from FilterDialog)
348 alfonx 111 if (e.getSourceObject() != this.mapPane)
349     return;
350    
351 alfonx 97 FeatureSelectedEvent fse = (FeatureSelectedEvent) e;
352    
353 alfonx 151 /**
354 alfonx 158 * Checking, that the FeatureSelectedEvent actually contains features
355     * from this layer
356 alfonx 151 */
357     final String sourceID = fse.getSourceLayer().getTitle();
358     final String syncForID = mapLayer.getTitle();
359     if (sourceID != null && syncForID != null
360 alfonx 158 && !sourceID.equals(syncForID)) {
361     LOGGER.debug("Ignoring a FeatureSelectedEvent from " + sourceID);
362 alfonx 97 return;
363 alfonx 151 }
364 alfonx 97
365 alfonx 151 LOGGER.debug("do event " + fse);
366 alfonx 111
367 alfonx 97 // Avoid event circles in propertyChange(..)
368     selectionChangeCausedByMe = true;
369    
370 alfonx 455 final FeatureCollection<SimpleFeatureType, SimpleFeature> selectionResult = fse
371     .getSelectionResult();
372     Iterator<SimpleFeature> fi = selectionResult.iterator();
373     try {
374 alfonx 97
375 alfonx 455 // reset the selection of the DpLayerSelectionModel
376     // layerSelModel.setValueIsAdjusting(true);
377 alfonx 97
378 alfonx 455 if (selectedTool == MapPaneToolBar.TOOL_SELECTION_ADD) {
379     layerSelModel.setValueIsAdjusting(true);
380 alfonx 409
381 alfonx 455 for (int fIdx = 0; fi.hasNext(); fIdx++) {
382     SimpleFeature f = fi.next();
383     layerSelModel.addSelection(f.getID());
384     }
385     layerSelModel.setValueIsAdjusting(false);
386     } else if (selectedTool == MapPaneToolBar.TOOL_SELECTION_SET) {
387     layerSelModel.setValueIsAdjusting(true);
388     layerSelModel.clearSelection();
389 alfonx 97
390 alfonx 455 for (int fIdx = 0; fi.hasNext(); fIdx++) {
391     SimpleFeature f = fi.next();
392     layerSelModel.addSelection(f.getID());
393     }
394 alfonx 111
395 alfonx 455 // LOGGER.debug("Setting selection to " + fi.());
396 alfonx 409
397 alfonx 455 layerSelModel.setValueIsAdjusting(false);
398     } else if (selectedTool == MapPaneToolBar.TOOL_SELECTION_REMOVE) {
399     layerSelModel.setValueIsAdjusting(true);
400     for (int fIdx = 0; fi.hasNext(); fIdx++) {
401     SimpleFeature f = fi.next();
402     layerSelModel.removeSelection(f.getID());
403     }
404     layerSelModel.setValueIsAdjusting(false);
405 alfonx 111 }
406 alfonx 455
407     } finally {
408     selectionResult.close(fi);
409 alfonx 151 }
410 alfonx 111
411     // Show selected features in the map, which is not automatically done by
412     // the origin: FeatureSelectedEvent
413 alfonx 97 changeLayerStyle(layerSelModel.getSelection());
414 alfonx 106
415 alfonx 97 // Danger of event circles in propertyChange(..) banned
416     selectionChangeCausedByMe = false;
417     }
418 alfonx 151
419 alfonx 97 }

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