/[schmitzm]/branches/1.0-gt2-2.6/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
ViewVC logotype

Contents of /branches/1.0-gt2-2.6/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 455 - (show annotations)
Sun Oct 11 21:41:53 2009 UTC (15 years, 4 months ago) by alfonx
File MIME type: text/plain
File size: 14878 byte(s)
* Feature iterator has to be closed!
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.feature.FeatureCollection;
59 import org.geotools.map.MapLayer;
60 import org.geotools.renderer.GTRenderer;
61 import org.geotools.renderer.label.LabelCacheImpl;
62 import org.geotools.renderer.lite.StreamingRenderer;
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.feature.simple.SimpleFeatureType;
68 import org.opengis.filter.identity.FeatureId;
69
70 import schmitzm.geotools.FilterUtil;
71 import schmitzm.geotools.GTUtil;
72 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 import skrueger.geotools.MapPaneToolBar;
78 import skrueger.geotools.StyledLayerInterface;
79
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 StyledLayerSelectionModelSynchronizer<StyledFeatureLayerSelectionModel>
100 implements JMapPaneListener {
101 public static final String SELECTION_STYLING = "SELECTION";
102 /**
103 * Holds the {@link MapLayer} to keep synchronized with the layer selection
104 * model.
105 */
106 protected final MapLayer mapLayer;
107 protected final StyledLayerInterface<?> styledLayer;
108 protected final JMapPane mapPane;
109 private final MapPaneToolBar toolBar;
110 private final HashMap<Object, Object> defaultGTRenderingHints;
111
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 StyledLayerInterface<?> styledLayer, MapLayer mapLayer,
125 JMapPane mapPane, MapPaneToolBar toolBar,
126 HashMap<Object, Object> defaultGTRenderingHints) {
127
128 super(layerSelModel);
129 this.styledLayer = styledLayer;
130
131 this.mapLayer = mapLayer;
132 this.mapPane = mapPane;
133 this.toolBar = toolBar;
134 if (defaultGTRenderingHints != null)
135 this.defaultGTRenderingHints = defaultGTRenderingHints;
136 else
137 this.defaultGTRenderingHints = new HashMap<Object, Object>();
138 }
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
153 if (!isEnabled())
154 return;
155
156 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 Vector<String> newSelection = layerSelModel.getSelection();
166 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 /**
179 * Changes the Style of the {@link MapLayer} to reflect changes of the
180 * selection.
181 *
182 * @param newSelection
183 * A {@link Vector} of SimpleFeature-IDs that are selected.
184 */
185 private void changeLayerStyle(final Vector<String> newSelection) {
186 try {
187
188 Style originalStyle = mapLayer.getStyle();
189 if (newSelection.isEmpty()) {
190
191 // Check if the Style contains a SELECTION FTS
192
193 FeatureTypeStyle[] clone = originalStyle.featureTypeStyles()
194 .toArray(new FeatureTypeStyle[] {}).clone();
195
196 for (FeatureTypeStyle fts : clone) {
197 if (fts.getName() != null
198 && fts.getName().equals(SELECTION_STYLING)) {
199 originalStyle.featureTypeStyles().remove(fts);
200
201 replaceRenderer();
202 // mapPane.refresh();
203
204 return;
205 }
206 }
207
208 } else {
209 LOGGER.debug("SELECTION .. change style");
210
211 // We take Style from the MapLayer that is displayed at the
212 // moment. We do not use the styledLayer.getStyle, because in
213 // the atlas, this always return the default style, but
214 // additional styles might be selected.
215 // Taking the style from the mapLayer indicated, that we have to
216 // remove any selection rules first.
217
218 FeatureTypeStyle selectionFTStyle = StylingUtil
219 .createSelectionStyle(styledLayer.getGeoObject());
220
221 selectionFTStyle.setName(SELECTION_STYLING);
222
223 /**
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 * It is NEVER allowed to GeoTools extend Filter () { .. } (and
230 * write tests into the evaluate block). Especially for the
231 * ShapeFileRenderer, we may only use a geotools Filter.<br/>
232 *
233 * Note 2:<br/>
234 * The FilterUtil.FILTER_FAC2.id(fids) wants a set of
235 * FeatureId-Objects!
236 */
237
238 Set<FeatureId> fids = new HashSet<FeatureId>();
239 for (String fid : newSelection) {
240 fids.add(FilterUtil.FILTER_FAC2.featureId(fid));
241 }
242
243 selectionFTStyle.rules().get(0).setFilter(
244 FilterUtil.FILTER_FAC2.id(fids));
245
246 // 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 }
258 if (!foundAndReplaced) {
259 originalStyle.featureTypeStyles().add(selectionFTStyle);
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();
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 final FeatureCollection<SimpleFeatureType, SimpleFeature> selectionResult = fse
371 .getSelectionResult();
372 Iterator<SimpleFeature> fi = selectionResult.iterator();
373 try {
374
375 // reset the selection of the DpLayerSelectionModel
376 // layerSelModel.setValueIsAdjusting(true);
377
378 if (selectedTool == MapPaneToolBar.TOOL_SELECTION_ADD) {
379 layerSelModel.setValueIsAdjusting(true);
380
381 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
390 for (int fIdx = 0; fi.hasNext(); fIdx++) {
391 SimpleFeature f = fi.next();
392 layerSelModel.addSelection(f.getID());
393 }
394
395 // LOGGER.debug("Setting selection to " + fi.());
396
397 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 }
406
407 } finally {
408 selectionResult.close(fi);
409 }
410
411 // Show selected features in the map, which is not automatically done by
412 // the origin: FeatureSelectedEvent
413 changeLayerStyle(layerSelModel.getSelection());
414
415 // Danger of event circles in propertyChange(..) banned
416 selectionChangeCausedByMe = false;
417 }
418
419 }

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