/[schmitzm]/branches/2.3.x/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
ViewVC logotype

Annotation of /branches/2.3.x/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 438 - (hide 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 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     import org.geotools.map.MapLayer;
59 alfonx 419 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 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 158 import org.opengis.filter.identity.FeatureId;
68 alfonx 97
69 alfonx 158 import schmitzm.geotools.FilterUtil;
70 alfonx 438 import schmitzm.geotools.GTUtil;
71 alfonx 97 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 alfonx 111 import skrueger.geotools.MapPaneToolBar;
77 alfonx 224 import skrueger.geotools.StyledLayerInterface;
78 alfonx 97
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 alfonx 106 StyledLayerSelectionModelSynchronizer<StyledFeatureLayerSelectionModel>
99     implements JMapPaneListener {
100 alfonx 111 public static final String SELECTION_STYLING = "SELECTION";
101 alfonx 97 /**
102     * Holds the {@link MapLayer} to keep synchronized with the layer selection
103     * model.
104     */
105     protected final MapLayer mapLayer;
106 alfonx 224 protected final StyledLayerInterface<?> styledLayer;
107 alfonx 97 protected final JMapPane mapPane;
108 alfonx 111 private final MapPaneToolBar toolBar;
109 alfonx 419 private final HashMap<Object, Object> defaultGTRenderingHints;
110 alfonx 97
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 alfonx 224 StyledLayerInterface<?> styledLayer, MapLayer mapLayer,
124 alfonx 419 JMapPane mapPane, MapPaneToolBar toolBar, HashMap<Object, Object> defaultGTRenderingHints) {
125 alfonx 97
126     super(layerSelModel);
127 alfonx 224 this.styledLayer = styledLayer;
128 alfonx 97
129     this.mapLayer = mapLayer;
130     this.mapPane = mapPane;
131 alfonx 111 this.toolBar = toolBar;
132 alfonx 419 if (defaultGTRenderingHints != null)
133     this.defaultGTRenderingHints = defaultGTRenderingHints;
134     else
135     this.defaultGTRenderingHints = new HashMap<Object, Object>();
136 alfonx 97 }
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 alfonx 151
151     if (!isEnabled())
152     return;
153    
154 alfonx 97 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 alfonx 111 Vector<String> newSelection = layerSelModel.getSelection();
164 alfonx 97 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 alfonx 151 /**
177     * Changes the Style of the {@link MapLayer} to reflect changes of the
178     * selection.
179     *
180     * @param newSelection
181 alfonx 318 * A {@link Vector} of SimpleFeature-IDs that are selected.
182 alfonx 151 */
183 alfonx 111 private void changeLayerStyle(final Vector<String> newSelection) {
184 alfonx 97 try {
185 alfonx 415
186 alfonx 412 Style originalStyle = mapLayer.getStyle();
187 alfonx 97 if (newSelection.isEmpty()) {
188    
189 alfonx 412 // 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 alfonx 419 replaceRenderer();
199     // mapPane.refresh();
200    
201 alfonx 106
202 alfonx 412 return;
203     }
204     }
205    
206 alfonx 97 } else {
207 alfonx 100 LOGGER.debug("SELECTION .. change style");
208 alfonx 106
209 alfonx 123 // We take Style from the MapLayer that is displayed at the
210 alfonx 224 // moment. We do not use the styledLayer.getStyle, because in
211 alfonx 123 // the atlas, this always return the default style, but
212 alfonx 224 // additional styles might be selected.
213 alfonx 123 // Taking the style from the mapLayer indicated, that we have to
214 alfonx 125 // remove any selection rules first.
215 alfonx 101
216 alfonx 412 FeatureTypeStyle selectionFTStyle = StylingUtil
217 alfonx 224 .createSelectionStyle(styledLayer.getGeoObject());
218 alfonx 106
219 alfonx 412 selectionFTStyle.setName(SELECTION_STYLING);
220 alfonx 123
221 alfonx 158 /**
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 alfonx 409 * It is NEVER allowed to GeoTools extend Filter () { .. } (and
228     * write tests into the evaluate block). Especially for the
229 alfonx 158 * ShapeFileRenderer, we may only use a geotools Filter.<br/>
230     *
231     * Note 2:<br/>
232 alfonx 409 * The FilterUtil.FILTER_FAC2.id(fids) wants a set of
233     * FeatureId-Objects!
234 alfonx 158 */
235 alfonx 106
236 alfonx 158 Set<FeatureId> fids = new HashSet<FeatureId>();
237     for (String fid : newSelection) {
238     fids.add(FilterUtil.FILTER_FAC2.featureId(fid));
239     }
240 alfonx 106
241 alfonx 412 selectionFTStyle.rules().get(0).setFilter(
242     FilterUtil.FILTER_FAC2.id(fids));
243 alfonx 106
244 alfonx 412 // 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 alfonx 123 }
256 alfonx 412 if (!foundAndReplaced) {
257     originalStyle.featureTypeStyles().add(selectionFTStyle);
258     }
259 alfonx 419
260    
261 alfonx 151
262 alfonx 412 // Refresh the map
263 alfonx 419 // 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 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     //
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 alfonx 438 final GTRenderer newRenderer = GTUtil.createGTRenderer(oldRenderer.getContext());
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    
306     RenderingHints java2DHints = oldRenderer.getJava2DHints();
307     if (java2DHints != null) {
308 alfonx 427 newRenderer.setJava2DHints(java2DHints);
309 alfonx 419 }
310    
311     oldRenderer.setContext(null);
312     oldRenderer = null;
313     }
314    
315     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 409 Iterator<SimpleFeature> fi = fse.getSelectionResult().iterator();
371 alfonx 97
372 alfonx 151 // reset the selection of the DpLayerSelectionModel
373     // layerSelModel.setValueIsAdjusting(true);
374 alfonx 97
375 alfonx 151 if (selectedTool == MapPaneToolBar.TOOL_SELECTION_ADD) {
376     layerSelModel.setValueIsAdjusting(true);
377 alfonx 409
378     for (int fIdx = 0; fi.hasNext(); fIdx++) {
379     SimpleFeature f = fi.next();
380 alfonx 151 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 alfonx 97
387 alfonx 409 for (int fIdx = 0; fi.hasNext(); fIdx++) {
388     SimpleFeature f = fi.next();
389 alfonx 151 layerSelModel.addSelection(f.getID());
390     }
391 alfonx 111
392 alfonx 409 // LOGGER.debug("Setting selection to " + fi.());
393    
394 alfonx 151 layerSelModel.setValueIsAdjusting(false);
395     } else if (selectedTool == MapPaneToolBar.TOOL_SELECTION_REMOVE) {
396     layerSelModel.setValueIsAdjusting(true);
397 alfonx 409 for (int fIdx = 0; fi.hasNext(); fIdx++) {
398     SimpleFeature f = fi.next();
399 alfonx 151 layerSelModel.removeSelection(f.getID());
400 alfonx 111 }
401 alfonx 151 layerSelModel.setValueIsAdjusting(false);
402     }
403 alfonx 111
404     // Show selected features in the map, which is not automatically done by
405     // the origin: FeatureSelectedEvent
406 alfonx 97 changeLayerStyle(layerSelModel.getSelection());
407 alfonx 106
408 alfonx 97 // Danger of event circles in propertyChange(..) banned
409     selectionChangeCausedByMe = false;
410     }
411 alfonx 151
412 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