001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032:
033: package com.vividsolutions.jump.workbench.ui;
034:
035: import java.util.ArrayList;
036: import java.util.Arrays;
037: import java.util.Collection;
038: import java.util.Collections;
039: import java.util.HashSet;
040: import java.util.Iterator;
041: import java.util.List;
042:
043: import com.vividsolutions.jts.geom.Geometry;
044: import com.vividsolutions.jump.feature.Feature;
045: import com.vividsolutions.jump.workbench.model.CategoryEvent;
046: import com.vividsolutions.jump.workbench.model.FeatureEvent;
047: import com.vividsolutions.jump.workbench.model.FeatureEventType;
048: import com.vividsolutions.jump.workbench.model.Layer;
049: import com.vividsolutions.jump.workbench.model.LayerEvent;
050: import com.vividsolutions.jump.workbench.model.LayerEventType;
051: import com.vividsolutions.jump.workbench.model.LayerListener;
052: import com.vividsolutions.jump.workbench.model.LayerManager;
053: import com.vividsolutions.jump.workbench.model.LayerManagerProxy;
054: import com.vividsolutions.jump.workbench.ui.renderer.SelectionBackgroundRenderer;
055:
056: /**
057: * Provides aggregate information for selected features, parts, and linestrings.
058: * Note that there is a difference between "selected features" and "features with
059: * selected items": the former consists of wholly selected features; the latter,
060: * wholly and partially selected features. To access a specific level of selection,
061: * use #getFeatureSelection, #getPartSelection, or #getLineStringSelection.
062: * "Parts" are components of GeometryCollections.
063: * <p>
064: * To get wholly selected features (i.e. not those that just have selected
065: * parts or linestrings), use <code>getFeatureSelection().getFeaturesWithSelectedItems()</code>
066: * <p>
067: * To get features that are selected or have selected parts or linestrings,
068: * use <code>getFeaturesWithSelectedItems()</code>
069: * <p>
070: * Yes there is a way to listen for selection events: LayerViewPanel#addListener.
071: */
072: public class SelectionManager {
073: private FeatureSelection featureSelection;
074: private PartSelection partSelection;
075: private LineStringSelection lineStringSelection;
076: private LayerManagerProxy layerManagerProxy;
077: private LayerViewPanel panel;
078:
079: /**
080: * A feature may get split into two or more -- for example, if two linestrings of a feature
081: * are selected.
082: */
083: public Collection createFeaturesFromSelectedItems() {
084: ArrayList newFeatures = new ArrayList();
085: for (Iterator i = getLayersWithSelectedItems().iterator(); i
086: .hasNext();) {
087: Layer layer = (Layer) i.next();
088: newFeatures.addAll(createFeaturesFromSelectedItems(layer));
089: }
090: return newFeatures;
091: }
092:
093: public Collection createFeaturesFromSelectedItems(Layer layer) {
094: ArrayList newFeatures = new ArrayList();
095: for (Iterator i = getFeaturesWithSelectedItems(layer)
096: .iterator(); i.hasNext();) {
097: Feature feature = (Feature) i.next();
098: for (Iterator j = getSelectedItems(layer, feature)
099: .iterator(); j.hasNext();) {
100: Geometry item = (Geometry) j.next();
101: Feature newFeature = (Feature) feature.clone();
102: newFeature.setGeometry(item);
103: newFeatures.add(newFeature);
104: }
105: }
106: return newFeatures;
107: }
108:
109: private boolean panelUpdatesEnabled = true;
110:
111: public SelectionManager(LayerViewPanel panel,
112: LayerManagerProxy layerManagerProxy) {
113: this .panel = panel;
114: this .layerManagerProxy = layerManagerProxy;
115: featureSelection = new FeatureSelection(this );
116: lineStringSelection = new LineStringSelection(this );
117: partSelection = new PartSelection(this );
118: featureSelection.setParent(null);
119: featureSelection.setChild(partSelection);
120: partSelection.setParent(featureSelection);
121: partSelection.setChild(lineStringSelection);
122: lineStringSelection.setParent(partSelection);
123: lineStringSelection.setChild(null);
124: selections = Collections.unmodifiableList(Arrays
125: .asList(new Object[] { featureSelection, partSelection,
126: lineStringSelection }));
127: addLayerListenerTo(layerManagerProxy.getLayerManager());
128: }
129:
130: private LayerListener layerListener = new LayerListener() {
131: public void featuresChanged(FeatureEvent e) {
132: if (e.getType() == FeatureEventType.DELETED) {
133: unselectItems(e.getLayer(), e.getFeatures());
134: }
135: if (e.getType() == FeatureEventType.GEOMETRY_MODIFIED) {
136: unselectFromFeaturesWithModifiedItemCounts(
137: e.getLayer(), e.getFeatures(), e
138: .getOldFeatureClones());
139: }
140: }
141:
142: public void layerChanged(LayerEvent e) {
143: if (!(e.getLayerable() instanceof Layer)) {
144: return;
145: }
146: if (e.getType() == LayerEventType.REMOVED
147: || e.getType() == LayerEventType.VISIBILITY_CHANGED) {
148: unselectItems((Layer) e.getLayerable());
149: }
150: }
151:
152: public void categoryChanged(CategoryEvent e) {
153: }
154: };
155:
156: private void addLayerListenerTo(LayerManager layerManager) {
157: layerManager.addLayerListener(layerListener);
158: }
159:
160: public void clear() {
161: boolean originalPanelUpdatesEnabled = arePanelUpdatesEnabled();
162: setPanelUpdatesEnabled(false);
163: try {
164: for (Iterator i = selections.iterator(); i.hasNext();) {
165: AbstractSelection selection = (AbstractSelection) i
166: .next();
167: selection.unselectItems();
168: }
169: } finally {
170: setPanelUpdatesEnabled(originalPanelUpdatesEnabled);
171: }
172: updatePanel();
173: }
174:
175: public FeatureSelection getFeatureSelection() {
176: return featureSelection;
177: }
178:
179: public LineStringSelection getLineStringSelection() {
180: return lineStringSelection;
181: }
182:
183: /**
184: * @return AbstractSelections
185: */
186: public Collection getSelections() {
187: return selections;
188: }
189:
190: private List selections;
191:
192: /**
193: * "items" rather than "geometries" because the user may have selected a part
194: * of a Geometry (an element of a GeometryCollection or a ring of a Polygon).
195: * @return a collection of Geometries
196: */
197: public Collection getSelectedItems() {
198: ArrayList selectedItems = new ArrayList();
199: for (Iterator i = selections.iterator(); i.hasNext();) {
200: AbstractSelection selection = (AbstractSelection) i.next();
201: selectedItems.addAll(selection.getSelectedItems());
202: }
203: return selectedItems;
204: }
205:
206: public Collection getSelectedItems(Layer layer) {
207: ArrayList selectedItems = new ArrayList();
208: for (Iterator i = selections.iterator(); i.hasNext();) {
209: AbstractSelection selection = (AbstractSelection) i.next();
210: selectedItems.addAll(selection.getSelectedItems(layer));
211: }
212: return selectedItems;
213: }
214:
215: public Collection getSelectedItems(Layer layer, Feature feature) {
216: ArrayList selectedItems = new ArrayList();
217: for (Iterator i = selections.iterator(); i.hasNext();) {
218: AbstractSelection selection = (AbstractSelection) i.next();
219: selectedItems.addAll(selection.getSelectedItems(layer,
220: feature));
221: }
222: return selectedItems;
223: }
224:
225: /**
226: * @param geometry the feature's Geometry or equivalent; that is, a clone or
227: * similar enough Geometry from which Geometries can be retrieved using
228: * the selection indices
229: */
230: public Collection getSelectedItems(Layer layer, Feature feature,
231: Geometry geometry) {
232: ArrayList selectedItems = new ArrayList();
233: for (Iterator i = selections.iterator(); i.hasNext();) {
234: AbstractSelection selection = (AbstractSelection) i.next();
235: selectedItems.addAll(selection.getSelectedItems(layer,
236: feature, geometry));
237: }
238: return selectedItems;
239: }
240:
241: public Collection getLayersWithSelectedItems() {
242: HashSet layersWithSelectedItems = new HashSet();
243: for (Iterator i = selections.iterator(); i.hasNext();) {
244: AbstractSelection selection = (AbstractSelection) i.next();
245: layersWithSelectedItems.addAll(selection
246: .getLayersWithSelectedItems());
247: }
248: return layersWithSelectedItems;
249: }
250:
251: public PartSelection getPartSelection() {
252: return partSelection;
253: }
254:
255: public void updatePanel() {
256: if (!panelUpdatesEnabled) {
257: return;
258: }
259: panel.fireSelectionChanged();
260: panel.getRenderingManager().render(
261: SelectionBackgroundRenderer.CONTENT_ID);
262: for (Iterator i = selections.iterator(); i.hasNext();) {
263: AbstractSelection selection = (AbstractSelection) i.next();
264: panel.getRenderingManager().render(
265: selection.getRendererContentID());
266: }
267: }
268:
269: public void setPanelUpdatesEnabled(boolean panelUpdatesEnabled) {
270: this .panelUpdatesEnabled = panelUpdatesEnabled;
271: }
272:
273: public Collection getFeaturesWithSelectedItems(Layer layer) {
274: HashSet featuresWithSelectedItems = new HashSet();
275: for (Iterator i = selections.iterator(); i.hasNext();) {
276: AbstractSelection selection = (AbstractSelection) i.next();
277: featuresWithSelectedItems.addAll(selection
278: .getFeaturesWithSelectedItems(layer));
279: }
280: return featuresWithSelectedItems;
281: }
282:
283: public void unselectItems(Layer layer) {
284: boolean originalPanelUpdatesEnabled = arePanelUpdatesEnabled();
285: setPanelUpdatesEnabled(false);
286: try {
287: for (Iterator i = selections.iterator(); i.hasNext();) {
288: AbstractSelection selection = (AbstractSelection) i
289: .next();
290: selection.unselectItems(layer);
291: }
292: } finally {
293: setPanelUpdatesEnabled(originalPanelUpdatesEnabled);
294: }
295: updatePanel();
296: }
297:
298: public void unselectItems(Layer layer, Collection features) {
299: boolean originalPanelUpdatesEnabled = arePanelUpdatesEnabled();
300: setPanelUpdatesEnabled(false);
301: try {
302: for (Iterator i = selections.iterator(); i.hasNext();) {
303: AbstractSelection selection = (AbstractSelection) i
304: .next();
305: selection.unselectItems(layer, features);
306: }
307: } finally {
308: setPanelUpdatesEnabled(originalPanelUpdatesEnabled);
309: }
310: updatePanel();
311: }
312:
313: public void unselectFromFeaturesWithModifiedItemCounts(Layer layer,
314: Collection features, Collection oldFeatureClones) {
315: boolean originalPanelUpdatesEnabled = arePanelUpdatesEnabled();
316: setPanelUpdatesEnabled(false);
317: try {
318: for (Iterator i = selections.iterator(); i.hasNext();) {
319: AbstractSelection selection = (AbstractSelection) i
320: .next();
321: selection.unselectFromFeaturesWithModifiedItemCounts(
322: layer, features, oldFeatureClones);
323: }
324: } finally {
325: setPanelUpdatesEnabled(originalPanelUpdatesEnabled);
326: }
327: updatePanel();
328: }
329:
330: public Collection getFeaturesWithSelectedItems() {
331: ArrayList featuresWithSelectedItems = new ArrayList();
332: for (Iterator i = getLayersWithSelectedItems().iterator(); i
333: .hasNext();) {
334: Layer layer = (Layer) i.next();
335: featuresWithSelectedItems
336: .addAll(getFeaturesWithSelectedItems(layer));
337: }
338: return featuresWithSelectedItems;
339: }
340:
341: public boolean arePanelUpdatesEnabled() {
342: return panelUpdatesEnabled;
343: }
344:
345: public void dispose() {
346: layerManagerProxy.getLayerManager().removeLayerListener(
347: layerListener);
348: }
349:
350: }
|