/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * Copyright (C) 2003 Vivid Solutions * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.vividsolutions.jump.workbench.ui; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jump.feature.Feature; import com.vividsolutions.jump.workbench.model.CategoryEvent; import com.vividsolutions.jump.workbench.model.FeatureEvent; import com.vividsolutions.jump.workbench.model.FeatureEventType; import com.vividsolutions.jump.workbench.model.Layer; import com.vividsolutions.jump.workbench.model.LayerEvent; import com.vividsolutions.jump.workbench.model.LayerEventType; import com.vividsolutions.jump.workbench.model.LayerListener; import com.vividsolutions.jump.workbench.model.LayerManager; import com.vividsolutions.jump.workbench.model.LayerManagerProxy; import com.vividsolutions.jump.workbench.ui.renderer.SelectionBackgroundRenderer; /** * Provides aggregate information for selected features, parts, and linestrings. * Note that there is a difference between "selected features" and "features with * selected items": the former consists of wholly selected features; the latter, * wholly and partially selected features. To access a specific level of selection, * use #getFeatureSelection, #getPartSelection, or #getLineStringSelection. * "Parts" are components of GeometryCollections. * <p> * To get wholly selected features (i.e. not those that just have selected * parts or linestrings), use <code>getFeatureSelection().getFeaturesWithSelectedItems()</code> * <p> * To get features that are selected or have selected parts or linestrings, * use <code>getFeaturesWithSelectedItems()</code> * <p> * Yes there is a way to listen for selection events: LayerViewPanel#addListener. */ public class SelectionManager { private FeatureSelection featureSelection; private PartSelection partSelection; private LineStringSelection lineStringSelection; private LayerManagerProxy layerManagerProxy; private LayerViewPanel panel; protected int featuresWithSelectedItemsCount = 0; protected int selectedItems = 0; /** * A feature may get split into two or more -- for example, if two linestrings of a feature * are selected. */ public Collection createFeaturesFromSelectedItems() { ArrayList newFeatures = new ArrayList(); for (Iterator i = getLayersWithSelectedItems().iterator(); i.hasNext();) { Layer layer = (Layer) i.next(); newFeatures.addAll(createFeaturesFromSelectedItems(layer)); } return newFeatures; } public Collection createFeaturesFromSelectedItems(Layer layer) { ArrayList newFeatures = new ArrayList(); for (Iterator i = getFeaturesWithSelectedItems(layer).iterator(); i.hasNext();) { Feature feature = (Feature) i.next(); for (Iterator j = getSelectedItems(layer, feature).iterator(); j.hasNext();) { Geometry item = (Geometry) j.next(); Feature newFeature = (Feature) feature.clone(); newFeature.setGeometry(item); newFeatures.add(newFeature); } } return newFeatures; } private boolean panelUpdatesEnabled = true; public SelectionManager(LayerViewPanel panel, LayerManagerProxy layerManagerProxy) { this.panel = panel; this.layerManagerProxy = layerManagerProxy; featureSelection = new FeatureSelection(this); lineStringSelection = new LineStringSelection(this); partSelection = new PartSelection(this); featureSelection.setParent(null); featureSelection.setChild(partSelection); partSelection.setParent(featureSelection); partSelection.setChild(lineStringSelection); lineStringSelection.setParent(partSelection); lineStringSelection.setChild(null); selections = Collections.unmodifiableList( Arrays.asList( new Object[] { featureSelection, partSelection, lineStringSelection })); addLayerListenerTo(layerManagerProxy.getLayerManager()); } private LayerListener layerListener = new LayerListener() { public void featuresChanged(FeatureEvent e) { if (e.getType() == FeatureEventType.DELETED) { unselectItems(e.getLayer(), e.getFeatures()); } if (e.getType() == FeatureEventType.GEOMETRY_MODIFIED) { unselectFromFeaturesWithModifiedItemCounts( e.getLayer(), e.getFeatures(), e.getOldFeatureClones()); } } public void layerChanged(LayerEvent e) { if (!(e.getLayerable() instanceof Layer)) { return; } if (e.getType() == LayerEventType.REMOVED || e.getType() == LayerEventType.VISIBILITY_CHANGED) { unselectItems((Layer) e.getLayerable()); } } public void categoryChanged(CategoryEvent e) {} }; private void addLayerListenerTo(LayerManager layerManager) { layerManager.addLayerListener(layerListener); } public void clear() { boolean originalPanelUpdatesEnabled = arePanelUpdatesEnabled(); setPanelUpdatesEnabled(false); try { for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); selection.unselectItems(); } } finally { setPanelUpdatesEnabled(originalPanelUpdatesEnabled); } updatePanel(); } public FeatureSelection getFeatureSelection() { return featureSelection; } public LineStringSelection getLineStringSelection() { return lineStringSelection; } /** * @return AbstractSelections */ public Collection getSelections() { return selections; } private List selections; /** * "items" rather than "geometries" because the user may have selected a part * of a Geometry (an element of a GeometryCollection or a ring of a Polygon). * @return a collection of Geometries */ public Collection getSelectedItems() { ArrayList selectedItems = new ArrayList(); for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); selectedItems.addAll(selection.getSelectedItems()); } return selectedItems; } public int getSelectedItemsCount() { return selectedItems; } public Collection getSelectedItems(Layer layer) { ArrayList selectedItems = new ArrayList(); for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); selectedItems.addAll(selection.getSelectedItems(layer)); } return selectedItems; } public Collection getSelectedItems(Layer layer, Feature feature) { ArrayList selectedItems = new ArrayList(); for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); selectedItems.addAll(selection.getSelectedItems(layer, feature)); } return selectedItems; } /** * @param geometry the feature's Geometry or equivalent; that is, a clone or * similar enough Geometry from which Geometries can be retrieved using * the selection indices */ public Collection getSelectedItems(Layer layer, Feature feature, Geometry geometry) { ArrayList selectedItems = new ArrayList(); for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); selectedItems.addAll(selection.getSelectedItems(layer, feature, geometry)); } return selectedItems; } public Collection getLayersWithSelectedItems() { HashSet layersWithSelectedItems = new HashSet(); for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); layersWithSelectedItems.addAll(selection.getLayersWithSelectedItems()); } return layersWithSelectedItems; } public PartSelection getPartSelection() { return partSelection; } public void updatePanel() { if (!panelUpdatesEnabled) { return; } selectedItems = this.getSelectedItems().size(); //need to cache these to optimize size checks featuresWithSelectedItemsCount = this.getFeaturesWithSelectedItems().size(); panel.fireSelectionChanged(); panel.getRenderingManager().render(SelectionBackgroundRenderer.CONTENT_ID); for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); panel.getRenderingManager().render(selection.getRendererContentID()); } } public void setPanelUpdatesEnabled(boolean panelUpdatesEnabled) { this.panelUpdatesEnabled = panelUpdatesEnabled; } public Collection getFeaturesWithSelectedItems(Layer layer) { HashSet featuresWithSelectedItems = new HashSet(); for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); featuresWithSelectedItems.addAll(selection.getFeaturesWithSelectedItems(layer)); } return featuresWithSelectedItems; } public void unselectItems(Layer layer) { boolean originalPanelUpdatesEnabled = arePanelUpdatesEnabled(); setPanelUpdatesEnabled(false); try { for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); selection.unselectItems(layer); } } finally { setPanelUpdatesEnabled(originalPanelUpdatesEnabled); } updatePanel(); } public void unselectItems(Layer layer, Collection features) { boolean originalPanelUpdatesEnabled = arePanelUpdatesEnabled(); setPanelUpdatesEnabled(false); try { for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); selection.unselectItems(layer, features); } } finally { setPanelUpdatesEnabled(originalPanelUpdatesEnabled); } updatePanel(); } public void unselectFromFeaturesWithModifiedItemCounts( Layer layer, Collection features, Collection oldFeatureClones) { boolean originalPanelUpdatesEnabled = arePanelUpdatesEnabled(); setPanelUpdatesEnabled(false); try { for (Iterator i = selections.iterator(); i.hasNext();) { AbstractSelection selection = (AbstractSelection) i.next(); selection.unselectFromFeaturesWithModifiedItemCounts( layer, features, oldFeatureClones); } } finally { setPanelUpdatesEnabled(originalPanelUpdatesEnabled); } updatePanel(); } public Collection getFeaturesWithSelectedItems() { ArrayList featuresWithSelectedItems = new ArrayList(); for (Iterator i = getLayersWithSelectedItems().iterator(); i.hasNext();) { Layer layer = (Layer) i.next(); featuresWithSelectedItems.addAll(getFeaturesWithSelectedItems(layer)); } return featuresWithSelectedItems; } public int getFeaturesWithSelectedItemsCount() { return featuresWithSelectedItemsCount; } public boolean arePanelUpdatesEnabled() { return panelUpdatesEnabled; } public void dispose() { layerManagerProxy.getLayerManager().removeLayerListener(layerListener); } }