/[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 476 - (show annotations)
Fri Oct 16 14:40:47 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: 14933 byte(s)
* Improved GUI for UniqueValuesGUI
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 LOGGER.debug("The selection filter:"+fids);
244
245 selectionFTStyle.rules().get(0).setFilter(
246 FilterUtil.FILTER_FAC2.id(fids));
247
248 // Maybe there has already been another selection
249 // FeatureTypeStyle... Let's replace it...
250 boolean foundAndReplaced = false;
251 for (FeatureTypeStyle fts : originalStyle.featureTypeStyles()) {
252 if (fts.getName() != null
253 && fts.getName().equals(SELECTION_STYLING)) {
254 foundAndReplaced = true;
255 fts.rules().clear();
256 fts.rules().addAll(selectionFTStyle.rules());
257 break;
258 }
259 }
260 if (!foundAndReplaced) {
261 originalStyle.featureTypeStyles().add(selectionFTStyle);
262 }
263
264 // Refresh the map
265 // mapPane.refresh();
266
267 DuplicatingStyleVisitor dsv = new DuplicatingStyleVisitor();
268 dsv.visit(originalStyle);
269 Style newStyle = (Style) dsv.getCopy();
270
271 // Style newStyle = StylingUtil.STYLE_BUILDER.createStyle();
272 // newStyle.featureTypeStyles().addAll(originalStyle.featureTypeStyles());
273 mapLayer.setStyle(newStyle);
274
275 replaceRenderer();
276 }
277
278 } catch (Exception e) {
279 LOGGER.error("Error while trying to create a selection style", e);
280 }
281 }
282
283 private void replaceRenderer() {
284 //
285 // // Has to be done before we apply the new Renderer
286 // mapLayer.setStyle(style);
287
288 GTRenderer oldRenderer = mapPane.getRenderer();
289
290 /**
291 * Explicitly putting a new instance of LabelCacheDefault into the
292 * renderer instance, so JMapPane doesn't reuse the old one. This is
293 * very useful when changing the TextSymbolizer with AtlasStyler<br/>
294 * SK 9.7.09: It's not enought to user LabelCache.clear(). We can not
295 * reuse the old Renderer - better to create a new one!
296 */
297 final GTRenderer newRenderer = GTUtil.createGTRenderer();
298
299 final HashMap<Object, Object> rendererHints = defaultGTRenderingHints;
300 rendererHints.put(StreamingRenderer.LABEL_CACHE_KEY,
301 new LabelCacheImpl());
302
303 newRenderer.setRendererHints(rendererHints);
304 mapPane.setRenderer(newRenderer);
305
306 if (oldRenderer != null) {
307
308 RenderingHints java2DHints = oldRenderer.getJava2DHints();
309 if (java2DHints != null) {
310 newRenderer.setJava2DHints(java2DHints);
311 }
312
313 oldRenderer.setContext(null);
314 oldRenderer = null;
315 }
316
317 mapPane.refresh();
318
319 }
320
321 /**
322 * Used to synchronize {@link FeatureSelectedEvent}s with the
323 * {@link StyledFeatureLayerSelectionModel}
324 */
325 @Override
326 public void performMapPaneEvent(JMapPaneEvent e) {
327
328 // Ignore event if it is caused by us or the synchronizer is disabled.
329 if (!isEnabled() || selectionChangeCausedByMe)
330 return;
331
332 if (!(e instanceof FeatureSelectedEvent)) {
333 // LOGGER.debug("Ignoring event " + e);
334 return;
335 }
336
337 /**
338 * Only listen to FeatureSelectedEvents if an appropriate tool is
339 * selected.
340 */
341 final int selectedTool = toolBar.getSelectedTool();
342 if (selectedTool != MapPaneToolBar.TOOL_SELECTION_ADD
343 && selectedTool != MapPaneToolBar.TOOL_SELECTION_REMOVE
344 && selectedTool != MapPaneToolBar.TOOL_SELECTION_SET) {
345 return;
346 }
347
348 // only listen to events directly coming from JMapPane
349 // selection (ignore selections from FilterDialog)
350 if (e.getSourceObject() != this.mapPane)
351 return;
352
353 FeatureSelectedEvent fse = (FeatureSelectedEvent) e;
354
355 /**
356 * Checking, that the FeatureSelectedEvent actually contains features
357 * from this layer
358 */
359 final String sourceID = fse.getSourceLayer().getTitle();
360 final String syncForID = mapLayer.getTitle();
361 if (sourceID != null && syncForID != null
362 && !sourceID.equals(syncForID)) {
363 LOGGER.debug("Ignoring a FeatureSelectedEvent from " + sourceID);
364 return;
365 }
366
367 // LOGGER.debug("do event " + fse);
368
369 // Avoid event circles in propertyChange(..)
370 selectionChangeCausedByMe = true;
371
372 final FeatureCollection<SimpleFeatureType, SimpleFeature> selectionResult = fse
373 .getSelectionResult();
374 Iterator<SimpleFeature> fi = selectionResult.iterator();
375 try {
376
377 // reset the selection of the DpLayerSelectionModel
378 // layerSelModel.setValueIsAdjusting(true);
379
380 if (selectedTool == MapPaneToolBar.TOOL_SELECTION_ADD) {
381 layerSelModel.setValueIsAdjusting(true);
382
383 for (int fIdx = 0; fi.hasNext(); fIdx++) {
384 SimpleFeature f = fi.next();
385 layerSelModel.addSelection(f.getID());
386 }
387 layerSelModel.setValueIsAdjusting(false);
388 } else if (selectedTool == MapPaneToolBar.TOOL_SELECTION_SET) {
389 layerSelModel.setValueIsAdjusting(true);
390 layerSelModel.clearSelection();
391
392 for (int fIdx = 0; fi.hasNext(); fIdx++) {
393 SimpleFeature f = fi.next();
394 layerSelModel.addSelection(f.getID());
395 }
396
397 // LOGGER.debug("Setting selection to " + fi.());
398
399 layerSelModel.setValueIsAdjusting(false);
400 } else if (selectedTool == MapPaneToolBar.TOOL_SELECTION_REMOVE) {
401 layerSelModel.setValueIsAdjusting(true);
402 for (int fIdx = 0; fi.hasNext(); fIdx++) {
403 SimpleFeature f = fi.next();
404 layerSelModel.removeSelection(f.getID());
405 }
406 layerSelModel.setValueIsAdjusting(false);
407 }
408
409 } finally {
410 selectionResult.close(fi);
411 }
412
413 // Show selected features in the map, which is not automatically done by
414 // the origin: FeatureSelectedEvent
415 changeLayerStyle(layerSelModel.getSelection());
416
417 // Danger of event circles in propertyChange(..) banned
418 selectionChangeCausedByMe = false;
419 }
420
421 }

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