/[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 419 - (hide annotations)
Wed Sep 30 15:36:39 2009 UTC (15 years, 5 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: 14976 byte(s)
* A way has been found to set the transparency color of a DpLayerRasterPyramid.
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 97 import schmitzm.geotools.gui.JMapPane;
71     import schmitzm.geotools.map.event.FeatureSelectedEvent;
72     import schmitzm.geotools.map.event.JMapPaneEvent;
73     import schmitzm.geotools.map.event.JMapPaneListener;
74     import schmitzm.geotools.styling.StylingUtil;
75 alfonx 111 import skrueger.geotools.MapPaneToolBar;
76 alfonx 224 import skrueger.geotools.StyledLayerInterface;
77 alfonx 97
78     /**
79     * This class keeps the selection of a (feature) {@link JTable} synchronized
80     * with the {@link StyledLayerSelectionModel} of a layer. This is done by
81     * implementing:
82     * <ul>
83     * <li>a {@link PropertyChangeListener} which listens to the
84     * {@link StyledLayerSelectionModel} and accordingly changes the {@link JTable}
85     * selection</li>
86     * <li>a {@link ListSelectionListener} which listens to the {@link JTable} and
87     * accordingly changes the {@link StyledLayerSelectionModel} selection</li>
88     * </ul>
89     * After creating, the instance of this synchronizer must be added as listener
90     * to both, the {@link StyledLayerSelectionModel} and the table's
91     * {@link ListSelectionModel}.
92     *
93     * @author <a href="mailto:[email protected]">Martin Schmitz</a>
94     * (University of Bonn/Germany)
95     */
96     public class FeatureMapLayerSelectionSynchronizer extends
97 alfonx 106 StyledLayerSelectionModelSynchronizer<StyledFeatureLayerSelectionModel>
98     implements JMapPaneListener {
99 alfonx 111 public static final String SELECTION_STYLING = "SELECTION";
100 alfonx 97 /**
101     * Holds the {@link MapLayer} to keep synchronized with the layer selection
102     * model.
103     */
104     protected final MapLayer mapLayer;
105 alfonx 224 protected final StyledLayerInterface<?> styledLayer;
106 alfonx 97 protected final JMapPane mapPane;
107 alfonx 111 private final MapPaneToolBar toolBar;
108 alfonx 419 private final HashMap<Object, Object> defaultGTRenderingHints;
109 alfonx 97
110     /**
111     * Creates a new synchronizer
112     *
113     * @param layerSelModel
114     * layer selection model to keep synchronized with the
115     * {@link MapLayer}
116     *
117     * @param mapLayer
118     * {@link MapLayer} to keep synchronized with.
119     */
120     public FeatureMapLayerSelectionSynchronizer(
121     StyledFeatureLayerSelectionModel layerSelModel,
122 alfonx 224 StyledLayerInterface<?> styledLayer, MapLayer mapLayer,
123 alfonx 419 JMapPane mapPane, MapPaneToolBar toolBar, HashMap<Object, Object> defaultGTRenderingHints) {
124 alfonx 97
125     super(layerSelModel);
126 alfonx 224 this.styledLayer = styledLayer;
127 alfonx 97
128     this.mapLayer = mapLayer;
129     this.mapPane = mapPane;
130 alfonx 111 this.toolBar = toolBar;
131 alfonx 419 if (defaultGTRenderingHints != null)
132     this.defaultGTRenderingHints = defaultGTRenderingHints;
133     else
134     this.defaultGTRenderingHints = new HashMap<Object, Object>();
135 alfonx 97 }
136    
137     /**
138     * Called by {@link StyledLayerSelectionModel} when a the selection on other
139     * selection components (map, chart, ...) has changed. When calling this
140     *
141     * method changes the {@link MapLayer} selection according to the
142     * {@link StyledLayerSelectionModel} selection.
143     *
144     * @param evt
145     * an event
146     */
147     @Override
148     public void propertyChange(PropertyChangeEvent evt) {
149 alfonx 151
150     if (!isEnabled())
151     return;
152    
153 alfonx 97 if (!(evt instanceof StyledLayerSelectionEvent))
154     return;
155     StyledLayerSelectionEvent selEvt = (StyledLayerSelectionEvent) evt;
156     // Only react on own layer and ignore events invoked by
157     // this component itself
158     if (selEvt.getEmitter() != layerSelModel || selectionChangeCausedByMe)
159     return;
160     // Apply new selection on table (except this event is one of
161     // some more events)
162 alfonx 111 Vector<String> newSelection = layerSelModel.getSelection();
163 alfonx 97 if (newSelection == null)
164     return;
165    
166     // Avoid event circles in valueChanged(..)
167     selectionChangeCausedByMe = true;
168    
169     changeLayerStyle(newSelection);
170    
171     // Danger of event circles in valueChanged(..) banned
172     selectionChangeCausedByMe = false;
173     }
174    
175 alfonx 151 /**
176     * Changes the Style of the {@link MapLayer} to reflect changes of the
177     * selection.
178     *
179     * @param newSelection
180 alfonx 318 * A {@link Vector} of SimpleFeature-IDs that are selected.
181 alfonx 151 */
182 alfonx 111 private void changeLayerStyle(final Vector<String> newSelection) {
183 alfonx 97 try {
184 alfonx 415 // GTRenderer r = mapPane.getRenderer();
185     // if (r instanceof ShapefileRenderer) {
186     // ShapefileRenderer sfr = (ShapefileRenderer)r;
187     // sfr.setCaching(false);
188     // }
189     //
190    
191 alfonx 419
192    
193 alfonx 412 Style originalStyle = mapLayer.getStyle();
194 alfonx 97 if (newSelection.isEmpty()) {
195    
196 alfonx 412 // Check if the Style contains a SELECTION FTS
197    
198     FeatureTypeStyle[] clone = originalStyle.featureTypeStyles().toArray( new FeatureTypeStyle[] {} ).clone();
199    
200     for (FeatureTypeStyle fts : clone) {
201     if (fts.getName() != null
202     && fts.getName().equals(SELECTION_STYLING)) {
203     originalStyle.featureTypeStyles().remove(fts);
204    
205 alfonx 419 replaceRenderer();
206     // mapPane.refresh();
207    
208 alfonx 106
209 alfonx 412 return;
210     }
211     }
212    
213 alfonx 97 } else {
214 alfonx 100 LOGGER.debug("SELECTION .. change style");
215 alfonx 106
216 alfonx 123 // We take Style from the MapLayer that is displayed at the
217 alfonx 224 // moment. We do not use the styledLayer.getStyle, because in
218 alfonx 123 // the atlas, this always return the default style, but
219 alfonx 224 // additional styles might be selected.
220 alfonx 123 // Taking the style from the mapLayer indicated, that we have to
221 alfonx 125 // remove any selection rules first.
222 alfonx 101
223 alfonx 412 FeatureTypeStyle selectionFTStyle = StylingUtil
224 alfonx 224 .createSelectionStyle(styledLayer.getGeoObject());
225 alfonx 106
226 alfonx 412 selectionFTStyle.setName(SELECTION_STYLING);
227 alfonx 123
228 alfonx 158 /**
229     *
230     * Add a Filter to the selectionMapStyle, so that it is only
231     * used on objects that are selected. <br/>
232     *
233     * Note 1:<br/>
234 alfonx 409 * It is NEVER allowed to GeoTools extend Filter () { .. } (and
235     * write tests into the evaluate block). Especially for the
236 alfonx 158 * ShapeFileRenderer, we may only use a geotools Filter.<br/>
237     *
238     * Note 2:<br/>
239 alfonx 409 * The FilterUtil.FILTER_FAC2.id(fids) wants a set of
240     * FeatureId-Objects!
241 alfonx 158 */
242 alfonx 106
243 alfonx 158 Set<FeatureId> fids = new HashSet<FeatureId>();
244     for (String fid : newSelection) {
245     fids.add(FilterUtil.FILTER_FAC2.featureId(fid));
246     }
247 alfonx 106
248 alfonx 412 selectionFTStyle.rules().get(0).setFilter(
249     FilterUtil.FILTER_FAC2.id(fids));
250 alfonx 106
251 alfonx 412 // Maybe there has already been another selection
252     // FeatureTypeStyle... Let's replace it...
253     boolean foundAndReplaced = false;
254     for (FeatureTypeStyle fts : originalStyle.featureTypeStyles()) {
255     if (fts.getName() != null
256     && fts.getName().equals(SELECTION_STYLING)) {
257     foundAndReplaced = true;
258     fts.rules().clear();
259     fts.rules().addAll(selectionFTStyle.rules());
260     break;
261     }
262 alfonx 123 }
263 alfonx 412 if (!foundAndReplaced) {
264     originalStyle.featureTypeStyles().add(selectionFTStyle);
265     }
266 alfonx 419
267    
268 alfonx 151
269 alfonx 412 // Refresh the map
270 alfonx 419 // mapPane.refresh();
271    
272     DuplicatingStyleVisitor dsv = new DuplicatingStyleVisitor();
273     dsv.visit(originalStyle);
274     Style newStyle = (Style)dsv.getCopy();
275    
276     // Style newStyle = StylingUtil.STYLE_BUILDER.createStyle();
277     // newStyle.featureTypeStyles().addAll(originalStyle.featureTypeStyles());
278     mapLayer.setStyle(newStyle);
279    
280     replaceRenderer();
281 alfonx 97 }
282 alfonx 415 //
283     // if (r instanceof ShapefileRenderer) {
284     // ShapefileRenderer sfr = (ShapefileRenderer)r;
285     // sfr.setCaching(true);
286     // }
287 alfonx 97
288 alfonx 415
289 alfonx 97 } catch (Exception e) {
290     LOGGER.error("Error while trying to create a selection style", e);
291     }
292     }
293    
294 alfonx 419 private void replaceRenderer() {
295     //
296     // // Has to be done before we apply the new Renderer
297     // mapLayer.setStyle(style);
298    
299     GTRenderer oldRenderer = mapPane.getRenderer();
300    
301     /**
302     * Explicitly putting a new instance of LabelCacheDefault into the
303     * renderer instance, so JMapPane doesn't reuse the old one. This is
304     * very useful when changing the TextSymbolizer with AtlasStyler<br/>
305     * SK 9.7.09: It's not enought to user LabelCache.clear(). We can not
306     * reuse the old Renderer - better to create a new one!
307     */
308     final GTRenderer newRenderer = new ShapefileRenderer();
309    
310     final HashMap<Object, Object> rendererHints = defaultGTRenderingHints;
311     rendererHints.put(StreamingRenderer.LABEL_CACHE_KEY,
312     new LabelCacheImpl());
313    
314     newRenderer.setRendererHints(rendererHints);
315     mapPane.setRenderer(newRenderer);
316    
317     if (oldRenderer != null) {
318    
319     RenderingHints java2DHints = oldRenderer.getJava2DHints();
320     if (java2DHints != null) {
321     newRenderer.setRendererHints(java2DHints);
322     }
323    
324     oldRenderer.setContext(null);
325     oldRenderer = null;
326     }
327    
328     mapPane.refresh();
329    
330     }
331    
332 alfonx 151 /**
333     * Used to synchronize {@link FeatureSelectedEvent}s with the
334     * {@link StyledFeatureLayerSelectionModel}
335     */
336 alfonx 97 @Override
337     public void performMapPaneEvent(JMapPaneEvent e) {
338 alfonx 106
339 alfonx 151 // Ignore event if it is caused by us or the synchronizer is disabled.
340     if (!isEnabled() || selectionChangeCausedByMe)
341     return;
342    
343     if (!(e instanceof FeatureSelectedEvent)) {
344     // LOGGER.debug("Ignoring event " + e);
345     return;
346     }
347    
348 alfonx 111 /**
349 alfonx 151 * Only listen to FeatureSelectedEvents if an appropriate tool is
350 alfonx 111 * selected.
351     */
352     final int selectedTool = toolBar.getSelectedTool();
353     if (selectedTool != MapPaneToolBar.TOOL_SELECTION_ADD
354     && selectedTool != MapPaneToolBar.TOOL_SELECTION_REMOVE
355     && selectedTool != MapPaneToolBar.TOOL_SELECTION_SET) {
356     return;
357     }
358    
359 mojays 109 // only listen to events directly coming from JMapPane
360     // selection (ignore selections from FilterDialog)
361 alfonx 111 if (e.getSourceObject() != this.mapPane)
362     return;
363    
364 alfonx 97 FeatureSelectedEvent fse = (FeatureSelectedEvent) e;
365    
366 alfonx 151 /**
367 alfonx 158 * Checking, that the FeatureSelectedEvent actually contains features
368     * from this layer
369 alfonx 151 */
370     final String sourceID = fse.getSourceLayer().getTitle();
371     final String syncForID = mapLayer.getTitle();
372     if (sourceID != null && syncForID != null
373 alfonx 158 && !sourceID.equals(syncForID)) {
374     LOGGER.debug("Ignoring a FeatureSelectedEvent from " + sourceID);
375 alfonx 97 return;
376 alfonx 151 }
377 alfonx 97
378 alfonx 151 LOGGER.debug("do event " + fse);
379 alfonx 111
380 alfonx 97 // Avoid event circles in propertyChange(..)
381     selectionChangeCausedByMe = true;
382    
383 alfonx 409 Iterator<SimpleFeature> fi = fse.getSelectionResult().iterator();
384 alfonx 97
385 alfonx 151 // reset the selection of the DpLayerSelectionModel
386     // layerSelModel.setValueIsAdjusting(true);
387 alfonx 97
388 alfonx 151 if (selectedTool == MapPaneToolBar.TOOL_SELECTION_ADD) {
389     layerSelModel.setValueIsAdjusting(true);
390 alfonx 409
391     for (int fIdx = 0; fi.hasNext(); fIdx++) {
392     SimpleFeature f = fi.next();
393 alfonx 151 layerSelModel.addSelection(f.getID());
394     }
395     layerSelModel.setValueIsAdjusting(false);
396     } else if (selectedTool == MapPaneToolBar.TOOL_SELECTION_SET) {
397     layerSelModel.setValueIsAdjusting(true);
398     layerSelModel.clearSelection();
399 alfonx 97
400 alfonx 409 for (int fIdx = 0; fi.hasNext(); fIdx++) {
401     SimpleFeature f = fi.next();
402 alfonx 151 layerSelModel.addSelection(f.getID());
403     }
404 alfonx 111
405 alfonx 409 // LOGGER.debug("Setting selection to " + fi.());
406    
407 alfonx 151 layerSelModel.setValueIsAdjusting(false);
408     } else if (selectedTool == MapPaneToolBar.TOOL_SELECTION_REMOVE) {
409     layerSelModel.setValueIsAdjusting(true);
410 alfonx 409 for (int fIdx = 0; fi.hasNext(); fIdx++) {
411     SimpleFeature f = fi.next();
412 alfonx 151 layerSelModel.removeSelection(f.getID());
413 alfonx 111 }
414 alfonx 151 layerSelModel.setValueIsAdjusting(false);
415     }
416 alfonx 111
417     // Show selected features in the map, which is not automatically done by
418     // the origin: FeatureSelectedEvent
419 alfonx 97 changeLayerStyle(layerSelModel.getSelection());
420 alfonx 106
421 alfonx 97 // Danger of event circles in propertyChange(..) banned
422     selectionChangeCausedByMe = false;
423     }
424 alfonx 151
425 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