/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package de.cismet.cismap.commons.features; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import de.cismet.cismap.commons.gui.MapListener; import de.cismet.cismap.commons.gui.MappingComponent; import de.cismet.tools.CurrentStackTrace; import de.cismet.veto.VetoException; import de.cismet.veto.VetoListener; /** * DOCUMENT ME! * * @author thorsten.hell@cismet.de * @version $Revision$, $Date$ */ public class DefaultFeatureCollection implements FeatureCollection, MapListener { //~ Instance fields -------------------------------------------------------- protected List<Feature> features = new ArrayList<Feature>(); protected final Set<FeatureCollectionListener> listeners = new HashSet<FeatureCollectionListener>(); protected LinkedHashSet<Feature> holdFeatures = new LinkedHashSet<Feature>(); protected LinkedHashSet<Feature> selectedFeatures = new LinkedHashSet<Feature>(); protected boolean holdAll = false; private final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(this.getClass()); private boolean singleSelection = false; private ArrayList<VetoListener> vetoListeners = new ArrayList<VetoListener>(); //~ Constructors ----------------------------------------------------------- /** * Creates a new instance of DefaultFeatureCollection. */ public DefaultFeatureCollection() { } //~ Methods ---------------------------------------------------------------- /** * Wird eigentlich nicht mehr benoetigt. * * @param feature DOCUMENT ME! * @param index DOCUMENT ME! */ public void setFeatureAt(final Feature feature, final int index) { if (!features.contains(feature)) { features.add(index, feature); } } @Override public Feature getFeature(final int index) { try { return features.get(index); } catch (Exception e) { log.fatal("error in getFeature:" + index, e); // NOI18N return null; } } /** * DOCUMENT ME! * * @param vetoListener DOCUMENT ME! */ public void addVetoableSelectionListener(final VetoListener vetoListener) { if (vetoListener != null) { vetoListeners.add(vetoListener); } } /** * DOCUMENT ME! * * @param vetoListener DOCUMENT ME! */ public void removeVetoableSelectionListener(final VetoListener vetoListener) { if (vetoListener != null) { vetoListeners.remove(vetoListener); } } @Override public void setEnabled(final boolean enabled) { } @Override public void addFeatureCollectionListener(final FeatureCollectionListener l) { listeners.add(l); } @Override public void removeFeatureCollectionListener(final FeatureCollectionListener l) { listeners.remove(l); } @Override public void setTranslucency(final float t) { } @Override public boolean canBeDisabled() { return false; } @Override public List<Feature> getAllFeatures() { return features; } @Override public int getFeatureCount() { return features.size(); } @Override public void setLayerPosition(final int layerPosition) { } @Override public int getLayerPosition() { return 0; } @Override public String getName() { return "DefaultFeatureCollection"; // NOI18N } @Override public float getTranslucency() { return 1.0f; } @Override public boolean isEnabled() { return true; } @Override public boolean areFeaturesEditable() { final List<Feature> vf = new ArrayList<Feature>(features); for (final Feature f : vf) { if (f.isEditable()) { return true; } } return false; } @Override public void unholdFeature(final Feature f) { holdFeatures.remove(f); final Set<Feature> v = new HashSet<Feature>(2); v.add(f); fireFeaturesChanged(v); } @Override public void holdFeature(final Feature f) { try { holdFeatures.add(f); final Set<Feature> v = new HashSet<Feature>(2); v.add(f); fireFeaturesChanged(v); } catch (Throwable t) { log.error("Error during hold", t); // NOI18N } } @Override public boolean isHoldFeature(final Feature f) { return holdFeatures.contains(f); } @Override public void setHoldAll(final boolean holdAll) { this.holdAll = holdAll; if (holdAll) { holdFeatures.addAll(features); } else { holdFeatures.clear(); } fireFeaturesChanged(features); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ private boolean assertNoVeto() { for (final VetoListener curVetoListener : vetoListeners) { try { curVetoListener.veto(); } catch (VetoException ex) { return false; } } return true; } @Override public void select(final Feature f) { if (!assertNoVeto()) { return; } enforceSelect(f); } /** * DOCUMENT ME! * * @param f DOCUMENT ME! */ private void enforceSelect(final Feature f) { if (log.isDebugEnabled()) { log.debug("select(Feature f):" + f); // NOI18N } enforceUnselectAll(); selectedFeatures.add(f); fireSelectionChanged(f); } @Override public void select(final Collection<Feature> cf) { if (!assertNoVeto()) { return; } enforceSelect(cf); } /** * DOCUMENT ME! * * @param cf DOCUMENT ME! */ private void enforceSelect(final Collection<Feature> cf) { if (log.isDebugEnabled()) { log.debug("select(Collection<Feature> cf):" + cf); // NOI18N } enforceUnselectAll(true); selectedFeatures.addAll(cf); fireSelectionChanged(cf); } @Override public void addToSelection(final Feature f) { if (!assertNoVeto()) { return; } enforceAddToSelection(f); } /** * DOCUMENT ME! * * @param f DOCUMENT ME! */ private void enforceAddToSelection(final Feature f) { final Set<Feature> v = new HashSet<Feature>(2); v.add(f); enforceAddToSelection(v); } @Override public void addToSelection(final Collection<Feature> cf) { if (assertNoVeto()) { enforceAddToSelection(cf); } } /** * DOCUMENT ME! * * @param cf DOCUMENT ME! */ private void enforceAddToSelection(final Collection<Feature> cf) { selectedFeatures.addAll(cf); fireSelectionChanged(cf); } @Override public void unselect(final Feature f) { if (assertNoVeto()) { if (log.isDebugEnabled()) { log.debug("unselect(Feature f):" + f); // NOI18N } enforceUnselect(f); } } /** * DOCUMENT ME! * * @param f DOCUMENT ME! */ private void enforceUnselect(final Feature f) { if (log.isDebugEnabled()) { log.debug("unselect(Feature f):" + f); // NOI18N } selectedFeatures.remove(f); fireSelectionChanged(f); } @Override public void unselectAll() { if (assertNoVeto()) { enforceUnselectAll(); } } /** * DOCUMENT ME! */ private void enforceUnselectAll() { enforceUnselectAll(false); } @Override public void unselectAll(final boolean quiet) { if (assertNoVeto()) { enforceUnselectAll(quiet); } } /** * DOCUMENT ME! * * @param quiet DOCUMENT ME! */ private void enforceUnselectAll(final boolean quiet) { if (selectedFeatures.size() > 0) { if (log.isDebugEnabled()) { log.debug("unselectAll()"); // NOI18N } final LinkedHashSet<Feature> lhs = new LinkedHashSet<Feature>(selectedFeatures); selectedFeatures.clear(); if (!quiet) { fireSelectionChanged(lhs); } } } @Override public void unselect(final Collection<Feature> cf) { if (assertNoVeto()) { enforceUnselect(cf); } } /** * DOCUMENT ME! * * @param cf DOCUMENT ME! */ private void enforceUnselect(final Collection<Feature> cf) { if (log.isDebugEnabled()) { log.debug("unselect(Collection<Feature> cf):" + cf); // NOI18N } selectedFeatures.removeAll(cf); fireSelectionChanged(); } @Override public Collection getSelectedFeatures() { return new LinkedHashSet<Feature>(selectedFeatures); } @Override public boolean isSelected(final Feature f) { return selectedFeatures.contains(f); } @Override public void removeFeature(final Feature f) { if (log.isDebugEnabled()) { log.debug("before removal:" + features); // NOI18N } boolean removed = false; if (log.isDebugEnabled()) { log.debug("featureToRemove: " + f); // NOI18N log.debug("Feature sizes: " + features.size()); // NOI18N } if (log.isDebugEnabled()) { log.debug("Features: " + features); // NOI18N } removed = features.remove(f); if (log.isDebugEnabled()) { log.debug("feature removed: " + removed); // NOI18N } removed = holdFeatures.remove(f); if (log.isDebugEnabled()) { log.debug("holdFeature removed: " + removed); // NOI18N } removed = selectedFeatures.remove(f); if (log.isDebugEnabled()) { log.debug("selected removed: " + removed); // NOI18N } final Set<Feature> v = new HashSet<Feature>(2); v.add(f); checkForAndCorrectDoubleNaming(); fireFeaturesRemoved(v); if (log.isDebugEnabled()) { log.debug("after removal:" + features); // NOI18N } } @Override public void removeFeatures(final Collection<Feature> cf) { features.removeAll(cf); holdFeatures.removeAll(cf); checkForAndCorrectDoubleNaming(); fireFeaturesRemoved(cf); } @Override public void addFeature(final Feature f) { if (log.isDebugEnabled()) { log.debug("addFeature(Feature f):" + f); // NOI18N } if ((f != null) && (f.getGeometry() != null) && !features.contains(f)) { features.add(f); final Set<Feature> v = new HashSet<Feature>(2); v.add(f); checkForAndCorrectDoubleNaming(); fireFeaturesAdded(v); } else { log.warn( "Feature was not added. It is either null or getGeometry() is null or it is already in the Collection."); // NOI18N } } @Override public void addFeatures(final Collection<? extends Feature> cf) { if (log.isDebugEnabled()) { log.debug("addFeatures(Collection<Feature> cf):" + cf); // NOI18N } final List<Feature> v = new ArrayList<Feature>(); for (final Feature f : cf) { if (!features.contains(f)) { features.add(f); if (holdAll) { holdFeatures.add(f); } v.add(f); } } checkForAndCorrectDoubleNaming(); if (v.size() > 0) { fireFeaturesAdded(v); } } @Override public void substituteFeatures(final Collection<Feature> cf) { try { if (log.isDebugEnabled()) { log.debug("substitute: delete all"); // NOI18N } removeAllFeatures(); if (log.isDebugEnabled()) { log.debug("substitute: add:" + cf); // NOI18N } addFeatures(cf); final Feature f = (Feature)cf.toArray()[cf.size() - 1]; } catch (Exception e) { log.error("Error in substituteFeatures new features:" + cf, e); // NOI18N } // select(f); } /** * DOCUMENT ME! */ public void checkForAndCorrectDoubleNaming() { final HashMap<String, ArrayList<PreventNamingDuplicates>> candidates = new HashMap<String, ArrayList<PreventNamingDuplicates>>(); for (final Feature f : features) { if (f instanceof PreventNamingDuplicates) { ArrayList<PreventNamingDuplicates> list; list = candidates.get(f.getClass().toString()); if (list != null) { list.add((PreventNamingDuplicates)f); } else { list = new ArrayList<PreventNamingDuplicates>(); list.add((PreventNamingDuplicates)f); candidates.put(f.getClass().toString(), list); } } } for (final String key : candidates.keySet()) { final ArrayList<PreventNamingDuplicates> list = candidates.get(key); int counter = 1; if (list.size() >= 1) { for (final PreventNamingDuplicates f : list) { f.setNumber(counter); counter++; } } } } /** * DOCUMENT ME! */ public void clear() { holdFeatures.clear(); removeAllFeatures(); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public Collection<Feature> getHoldFeatures() { return holdFeatures; } @Override public void removeAllFeatures() { final Set<Feature> cf = new HashSet<Feature>(features); features.clear(); fireAllFeaturesRemoved(cf); addFeatures(holdFeatures); } @Override public void reconsiderFeature(final Feature f) { final Set<Feature> reconsiderF = new HashSet<Feature>(2); reconsiderF.add(f); if (log.isDebugEnabled()) { log.debug("reconsiderFeature(Feature f):" + f, new CurrentStackTrace()); // NOI18N } final Iterator<FeatureCollectionListener> it = getListenerIterator(); while (it.hasNext()) { it.next().featureReconsiderationRequested(new FeatureCollectionEvent(this, reconsiderF)); } checkForAndCorrectDoubleNaming(); } /** * DOCUMENT ME! * * @param cf DOCUMENT ME! */ public void fireFeaturesAdded(final Collection<Feature> cf) { final Iterator<FeatureCollectionListener> it = getListenerIterator(); while (it.hasNext()) { final FeatureCollectionListener curListener = it.next(); if (curListener instanceof MappingComponent) { if (log.isDebugEnabled()) { log.debug("adding featuresTo Map"); // NOI18N } ((MappingComponent)curListener).addFeaturesToMap(cf.toArray(new Feature[0])); } } } /** * DOCUMENT ME! * * @param cf DOCUMENT ME! */ public void fireFeaturesRemoved(final Collection<Feature> cf) { if (log.isDebugEnabled()) { log.debug("fireFeaturesRemoved"); // NOI18N } final Iterator<FeatureCollectionListener> it = getListenerIterator(); while (it.hasNext()) { it.next().featuresRemoved(new FeatureCollectionEvent(this, cf)); } } /** * DOCUMENT ME! * * @param cf DOCUMENT ME! */ public void fireAllFeaturesRemoved(final Collection<Feature> cf) { if (log.isDebugEnabled()) { log.debug("fireAllFeaturesRemoved"); // NOI18N } final Iterator<FeatureCollectionListener> it = getListenerIterator(); while (it.hasNext()) { it.next().allFeaturesRemoved(new FeatureCollectionEvent(this, cf)); } } /** * DOCUMENT ME! * * @param cf DOCUMENT ME! */ public void fireFeaturesChanged(final Collection<Feature> cf) { if (log.isDebugEnabled()) { log.debug("fireFeaturesChanged"); // NOI18N } final Iterator<FeatureCollectionListener> it = getListenerIterator(); while (it.hasNext()) { it.next().featuresChanged(new FeatureCollectionEvent(this, cf)); } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ private Iterator<FeatureCollectionListener> getListenerIterator() { final Iterator<FeatureCollectionListener> it; synchronized (listeners) { it = new HashSet<FeatureCollectionListener>(listeners).iterator(); } return it; } /** * DOCUMENT ME! */ public void fireSelectionChanged() { fireSelectionChanged((Collection<Feature>)null); } /** * DOCUMENT ME! * * @param cf DOCUMENT ME! */ public void fireSelectionChanged(final Collection<Feature> cf) { if (log.isDebugEnabled()) { log.debug("fireSelectionChanged"); // NOI18N } final Iterator<FeatureCollectionListener> it = getListenerIterator(); while (it.hasNext()) { it.next().featureSelectionChanged(new FeatureCollectionEvent(this, cf)); } } /** * DOCUMENT ME! * * @param f DOCUMENT ME! */ public void fireSelectionChanged(final Feature f) { final Set<Feature> v = new HashSet<Feature>(2); v.add(f); fireSelectionChanged(v); } @Override public void setName(final String name) { } /** * DOCUMENT ME! * * @param c DOCUMENT ME! */ public void removeFeaturesByInstance(final Class c) { final List<Feature> af = new ArrayList<Feature>(features); for (final Feature f : af) { if (c.isInstance(f)) { removeFeature(f); } } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean isSingleSelection() { return singleSelection; } /** * DOCUMENT ME! * * @param singleSelection DOCUMENT ME! */ public void setSingleSelection(final boolean singleSelection) { this.singleSelection = singleSelection; } @Override public void featuresAddedToMap(final Collection<Feature> cf) { if (log.isDebugEnabled()) { log.debug("fireFeaturesAddedToMap"); // NOI18N } final Iterator<FeatureCollectionListener> it = getListenerIterator(); while (it.hasNext()) { it.next().featuresAdded(new FeatureCollectionEvent(this, cf)); } } @Override public boolean contains(final Feature feature) { return features.contains(feature); } }