/[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 427 - (show annotations)
Fri Oct 2 19:38:44 2009 UTC (15 years, 5 months ago) by alfonx
File MIME type: text/plain
File size: 14974 byte(s)
* GP-Feature: Some more stuff with FilterDialogs and AtlasStyler
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.map.MapLayer;
59 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 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.filter.identity.FeatureId;
68
69 import schmitzm.geotools.FilterUtil;
70 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 import skrueger.geotools.MapPaneToolBar;
76 import skrueger.geotools.StyledLayerInterface;
77
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 StyledLayerSelectionModelSynchronizer<StyledFeatureLayerSelectionModel>
98 implements JMapPaneListener {
99 public static final String SELECTION_STYLING = "SELECTION";
100 /**
101 * Holds the {@link MapLayer} to keep synchronized with the layer selection
102 * model.
103 */
104 protected final MapLayer mapLayer;
105 protected final StyledLayerInterface<?> styledLayer;
106 protected final JMapPane mapPane;
107 private final MapPaneToolBar toolBar;
108 private final HashMap<Object, Object> defaultGTRenderingHints;
109
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 StyledLayerInterface<?> styledLayer, MapLayer mapLayer,
123 JMapPane mapPane, MapPaneToolBar toolBar, HashMap<Object, Object> defaultGTRenderingHints) {
124
125 super(layerSelModel);
126 this.styledLayer = styledLayer;
127
128 this.mapLayer = mapLayer;
129 this.mapPane = mapPane;
130 this.toolBar = toolBar;
131 if (defaultGTRenderingHints != null)
132 this.defaultGTRenderingHints = defaultGTRenderingHints;
133 else
134 this.defaultGTRenderingHints = new HashMap<Object, Object>();
135 }
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
150 if (!isEnabled())
151 return;
152
153 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 Vector<String> newSelection = layerSelModel.getSelection();
163 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 /**
176 * Changes the Style of the {@link MapLayer} to reflect changes of the
177 * selection.
178 *
179 * @param newSelection
180 * A {@link Vector} of SimpleFeature-IDs that are selected.
181 */
182 private void changeLayerStyle(final Vector<String> newSelection) {
183 try {
184 // GTRenderer r = mapPane.getRenderer();
185 // if (r instanceof ShapefileRenderer) {
186 // ShapefileRenderer sfr = (ShapefileRenderer)r;
187 // sfr.setCaching(false);
188 // }
189 //
190
191
192
193 Style originalStyle = mapLayer.getStyle();
194 if (newSelection.isEmpty()) {
195
196 // 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 replaceRenderer();
206 // mapPane.refresh();
207
208
209 return;
210 }
211 }
212
213 } else {
214 LOGGER.debug("SELECTION .. change style");
215
216 // We take Style from the MapLayer that is displayed at the
217 // moment. We do not use the styledLayer.getStyle, because in
218 // the atlas, this always return the default style, but
219 // additional styles might be selected.
220 // Taking the style from the mapLayer indicated, that we have to
221 // remove any selection rules first.
222
223 FeatureTypeStyle selectionFTStyle = StylingUtil
224 .createSelectionStyle(styledLayer.getGeoObject());
225
226 selectionFTStyle.setName(SELECTION_STYLING);
227
228 /**
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 * It is NEVER allowed to GeoTools extend Filter () { .. } (and
235 * write tests into the evaluate block). Especially for the
236 * ShapeFileRenderer, we may only use a geotools Filter.<br/>
237 *
238 * Note 2:<br/>
239 * The FilterUtil.FILTER_FAC2.id(fids) wants a set of
240 * FeatureId-Objects!
241 */
242
243 Set<FeatureId> fids = new HashSet<FeatureId>();
244 for (String fid : newSelection) {
245 fids.add(FilterUtil.FILTER_FAC2.featureId(fid));
246 }
247
248 selectionFTStyle.rules().get(0).setFilter(
249 FilterUtil.FILTER_FAC2.id(fids));
250
251 // 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 }
263 if (!foundAndReplaced) {
264 originalStyle.featureTypeStyles().add(selectionFTStyle);
265 }
266
267
268
269 // Refresh the map
270 // 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 }
282 //
283 // if (r instanceof ShapefileRenderer) {
284 // ShapefileRenderer sfr = (ShapefileRenderer)r;
285 // sfr.setCaching(true);
286 // }
287
288
289 } catch (Exception e) {
290 LOGGER.error("Error while trying to create a selection style", e);
291 }
292 }
293
294 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.setJava2DHints(java2DHints);
322 }
323
324 oldRenderer.setContext(null);
325 oldRenderer = null;
326 }
327
328 mapPane.refresh();
329
330 }
331
332 /**
333 * Used to synchronize {@link FeatureSelectedEvent}s with the
334 * {@link StyledFeatureLayerSelectionModel}
335 */
336 @Override
337 public void performMapPaneEvent(JMapPaneEvent e) {
338
339 // 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 /**
349 * Only listen to FeatureSelectedEvents if an appropriate tool is
350 * 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 // only listen to events directly coming from JMapPane
360 // selection (ignore selections from FilterDialog)
361 if (e.getSourceObject() != this.mapPane)
362 return;
363
364 FeatureSelectedEvent fse = (FeatureSelectedEvent) e;
365
366 /**
367 * Checking, that the FeatureSelectedEvent actually contains features
368 * from this layer
369 */
370 final String sourceID = fse.getSourceLayer().getTitle();
371 final String syncForID = mapLayer.getTitle();
372 if (sourceID != null && syncForID != null
373 && !sourceID.equals(syncForID)) {
374 LOGGER.debug("Ignoring a FeatureSelectedEvent from " + sourceID);
375 return;
376 }
377
378 LOGGER.debug("do event " + fse);
379
380 // Avoid event circles in propertyChange(..)
381 selectionChangeCausedByMe = true;
382
383 Iterator<SimpleFeature> fi = fse.getSelectionResult().iterator();
384
385 // reset the selection of the DpLayerSelectionModel
386 // layerSelModel.setValueIsAdjusting(true);
387
388 if (selectedTool == MapPaneToolBar.TOOL_SELECTION_ADD) {
389 layerSelModel.setValueIsAdjusting(true);
390
391 for (int fIdx = 0; fi.hasNext(); fIdx++) {
392 SimpleFeature f = fi.next();
393 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
400 for (int fIdx = 0; fi.hasNext(); fIdx++) {
401 SimpleFeature f = fi.next();
402 layerSelModel.addSelection(f.getID());
403 }
404
405 // LOGGER.debug("Setting selection to " + fi.());
406
407 layerSelModel.setValueIsAdjusting(false);
408 } else if (selectedTool == MapPaneToolBar.TOOL_SELECTION_REMOVE) {
409 layerSelModel.setValueIsAdjusting(true);
410 for (int fIdx = 0; fi.hasNext(); fIdx++) {
411 SimpleFeature f = fi.next();
412 layerSelModel.removeSelection(f.getID());
413 }
414 layerSelModel.setValueIsAdjusting(false);
415 }
416
417 // Show selected features in the map, which is not automatically done by
418 // the origin: FeatureSelectedEvent
419 changeLayerStyle(layerSelModel.getSelection());
420
421 // Danger of event circles in propertyChange(..) banned
422 selectionChangeCausedByMe = false;
423 }
424
425 }

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