/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package de.cismet.cismap.commons.gui.piccolo.eventlistener; import edu.umd.cs.piccolo.PNode; import edu.umd.cs.piccolo.event.PInputEvent; import org.apache.log4j.Logger; import java.awt.Color; import java.awt.EventQueue; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import de.cismet.cismap.commons.features.AbstractNewFeature; import de.cismet.cismap.commons.features.SearchFeature; import de.cismet.cismap.commons.gui.MappingComponent; import de.cismet.cismap.commons.gui.piccolo.PFeature; import de.cismet.cismap.commons.tools.PFeatureTools; /** * DOCUMENT ME! * * @author jruiz * @version $Revision$, $Date$ */ public abstract class AbstractCreateSearchGeometryListener extends CreateGeometryListener implements CreateSearchGeometryListener { //~ Static fields/initializers --------------------------------------------- private static final Logger LOG = Logger.getLogger(AbstractCreateSearchGeometryListener.class); // Now some property change event types. // We need to synchronize the mode and the last feature between AbstractCreateSearchGeometryListeners. public static final String PROPERTY_LAST_FEATURE = "PROPERTY_LAST_FEATURE"; public static final String PROPERTY_MODE = "PROPERTY_MODE"; // Additionally we want an AbstractCreateSearchGeometryListener to be the same color, ... as the // MetaSearchCreateSearchGeometryListener, since it's the only one which can be set by its own option dialog. public static final String PROPERTY_NUM_OF_ELLIPSE_EDGES = "PROPERTY_NUM_OF_ELLIPSE_EDGES"; public static final String PROPERTY_HOLD_GEOMETRIES = "PROPERTY_HOLD_GEOMETRIES"; public static final String PROPERTY_SEARCH_COLOR = "PROPERTY_SEARCH_COLOR"; public static final String PROPERTY_SEARCH_TRANSPARENCY = "PROPERTY_SEARCH_TRANSPARENCY"; //~ Instance fields -------------------------------------------------------- private boolean holdGeometries = false; private Color searchColor = Color.GREEN; private float searchTransparency = 0.5f; private SearchFeature lastFeature; private SearchFeature searchFeature; private SearchFeature recentlyCreatedFeature; private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); private final String inputListenerName; //~ Constructors ----------------------------------------------------------- /** * Creates a new CreateSearchGeometryListener object. * * @param mc DOCUMENT ME! * @param inputListenerName DOCUMENT ME! */ public AbstractCreateSearchGeometryListener(final MappingComponent mc, final String inputListenerName) { super(mc, SearchFeature.class); this.inputListenerName = inputListenerName; } //~ Methods ---------------------------------------------------------------- /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public String getInputListenerName() { return inputListenerName; } /** * DOCUMENT ME! * * @param listener DOCUMENT ME! */ public void addPropertyChangeListener(final PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } /** * DOCUMENT ME! * * @param listener DOCUMENT ME! */ public void removePropertyChangeListener(final PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ protected PropertyChangeSupport getPropertyChangeSupport() { return propertyChangeSupport; } @Override protected Color getFillingColor() { return new Color(searchColor.getRed(), searchColor.getGreen(), searchColor.getBlue(), 255 - (int)(255f * searchTransparency)); } @Override protected void finishGeometry(final AbstractNewFeature newFeature) { super.finishGeometry(newFeature); final SearchFeature newSearchFeature = (SearchFeature)newFeature; newSearchFeature.setInputListenerName(inputListenerName); recentlyCreatedFeature = newSearchFeature; } /** * DOCUMENT ME! * * @param feature DOCUMENT ME! */ protected void cleanup(final SearchFeature feature) { final PFeature pFeature = (PFeature)getMappingComponent().getPFeatureHM().get(feature); if (isHoldingGeometries()) { pFeature.moveToFront(); // funktioniert nicht?! feature.setEditable(true); getMappingComponent().getFeatureCollection().holdFeature(feature); } else { getMappingComponent().getTmpFeatureLayer().addChild(pFeature); // Transparenz animieren pFeature.animateToTransparency(0, 2500); // warten bis Animation zu Ende ist um Feature aus Liste zu entfernen new Thread(new Runnable() { @Override public void run() { while (pFeature.getTransparency() > 0) { try { Thread.sleep(100); } catch (InterruptedException ex) { } } getMappingComponent().getFeatureCollection().removeFeature(feature); } }).start(); } } /** * DOCUMENT ME! * * @param newValue DOCUMENT ME! */ protected void setLastFeature(final SearchFeature newValue) { final SearchFeature oldValue = this.lastFeature; this.lastFeature = newValue; // Notify other AbstractCreateSearchGeometryListeners about the change. propertyChangeSupport.firePropertyChange(PROPERTY_LAST_FEATURE, oldValue, newValue); } /** * DOCUMENT ME! */ @Override public void redoLastSearch() { search(lastFeature); } /** * DOCUMENT ME! */ @Override public void showLastFeature() { showFeature(lastFeature); getMappingComponent().getFeatureCollection().holdFeature(lastFeature); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public SearchFeature getSearchFeature() { return searchFeature; } /** * DOCUMENT ME! * * @param searchFeature DOCUMENT ME! */ protected void setSearchFeature(final SearchFeature searchFeature) { this.searchFeature = searchFeature; } /** * DOCUMENT ME! * * @param feature DOCUMENT ME! */ protected void showFeature(final SearchFeature feature) { if (feature != null) { feature.setInputListenerName(inputListenerName); feature.setEditable(feature.getGeometryType() != AbstractNewFeature.geomTypes.MULTIPOLYGON); getMappingComponent().getFeatureCollection().addFeature(feature); if (isHoldingGeometries()) { getMappingComponent().getFeatureCollection().holdFeature(feature); } } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ @Override public boolean isHoldingGeometries() { return holdGeometries; } /** * DOCUMENT ME! * * @param newValue DOCUMENT ME! */ @Override public void setHoldGeometries(final boolean newValue) { final boolean oldValue = this.holdGeometries; this.holdGeometries = newValue; propertyChangeSupport.firePropertyChange(PROPERTY_HOLD_GEOMETRIES, oldValue, newValue); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ @Override public float getSearchTransparency() { return searchTransparency; } /** * DOCUMENT ME! * * @param newValue searchTransparency DOCUMENT ME! */ @Override public void setSearchTransparency(final float newValue) { final float oldValue = this.searchTransparency; this.searchTransparency = newValue; propertyChangeSupport.firePropertyChange(PROPERTY_SEARCH_TRANSPARENCY, oldValue, newValue); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ @Override public Color getSearchColor() { final Color filling = getFillingColor(); return new Color(filling.getRed(), filling.getGreen(), filling.getBlue()); } /** * DOCUMENT ME! * * @param newValue DOCUMENT ME! */ @Override public void setSearchColor(final Color newValue) { final Color oldValue = this.searchColor; this.searchColor = newValue; propertyChangeSupport.firePropertyChange(PROPERTY_SEARCH_COLOR, oldValue, newValue); } @Override public void setNumOfEllipseEdges(final int newValue) { final int oldValue = getNumOfEllipseEdges(); super.setNumOfEllipseEdges(newValue); propertyChangeSupport.firePropertyChange(PROPERTY_NUM_OF_ELLIPSE_EDGES, oldValue, newValue); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ @Override public SearchFeature getLastSearchFeature() { return lastFeature; } /** * DOCUMENT ME! * * @param searchFeature DOCUMENT ME! */ @Override public void search(final SearchFeature searchFeature) { if (searchFeature != null) { setSearchFeature(searchFeature); final boolean searchExecuted = performSearch(searchFeature); if (searchExecuted) { setLastFeature(searchFeature); showFeature(searchFeature); cleanup(searchFeature); } } } @Override public void mousePressed(final PInputEvent pInputEvent) { final boolean progressBefore = isInProgress(); super.mousePressed(pInputEvent); if (recentlyCreatedFeature != null) { // super.mousePressed(pInputEvent) called this.finishGeometry(Feature) since the user created a new search // geometry search(recentlyCreatedFeature); // handleUserFinishedSearchGeometry(recentlyCreatedFeature); recentlyCreatedFeature = null; } else if ((!isInProgress() || (!progressBefore && isInProgress())) && (pInputEvent.getClickCount() == 2)) { handleDoubleClickInMap(pInputEvent); } } @Override public void mouseReleased(final PInputEvent arg0) { super.mouseReleased(arg0); if (recentlyCreatedFeature != null) { // super.mousePressed(pInputEvent) called finishGeometry since the user created a new search geometry search(recentlyCreatedFeature); // handleUserFinishedSearchGeometry(recentlyCreatedFeature); recentlyCreatedFeature = null; } } /** * DOCUMENT ME! * * @param feature DOCUMENT ME! */ protected void handleUserFinishedSearchGeometry(final SearchFeature feature) { getMappingComponent().getFeatureCollection().addFeature(feature); setLastFeature(feature); performSearch(feature); cleanup(feature); } /** * DOCUMENT ME! * * @param pInputEvent DOCUMENT ME! */ protected void handleDoubleClickInMap(final PInputEvent pInputEvent) { final Object o = PFeatureTools.getFirstValidObjectUnderPointer(pInputEvent, new Class[] { PFeature.class }); if (!(o instanceof PFeature)) { return; } final PFeature sel = (PFeature)o; if (!(sel.getFeature() instanceof SearchFeature)) { return; } final SearchFeature searchFeature = (SearchFeature)sel.getFeature(); if (pInputEvent.isLeftMouseButton()) { getMappingComponent().getHandleLayer().removeAllChildren(); search(searchFeature); } } @Override public void setMode(final String newValue) throws IllegalArgumentException { final String oldValue = getMode(); super.setMode(newValue); // Notify other AbstractCreateSearchGeometryListeners about the change. propertyChangeSupport.firePropertyChange(PROPERTY_MODE, oldValue, newValue); // But here we don't need to notify the visualizing component of this AbstractCreateSearchGeometryListener about // the change, since this method is invoked by it. It already knows about the change. if (getMappingComponent().getInteractionMode().equals(MappingComponent.CREATE_SEARCH_POLYGON)) { generateAndShowPointerAnnotation(); } } @Override public void mouseEntered(final PInputEvent event) { super.mouseEntered(event); if (event.isMouseEnteredOrMouseExited()) { generateAndShowPointerAnnotation(); } } @Override public void mouseExited(final PInputEvent event) { super.mouseExited(event); if (event.isMouseEnteredOrMouseExited()) { getMappingComponent().setPointerAnnotationVisibility(false); } } /** * DOCUMENT ME! */ protected void generateAndShowPointerAnnotation() { final PNode pointerAnnotation = getPointerAnnotation(); if (pointerAnnotation == null) { return; } final Runnable showPointerAnnotation = new Runnable() { @Override public void run() { getMappingComponent().setPointerAnnotation(pointerAnnotation); getMappingComponent().setPointerAnnotationVisibility(true); } }; if (EventQueue.isDispatchThread()) { showPointerAnnotation.run(); } else { EventQueue.invokeLater(showPointerAnnotation); } } /** * DOCUMENT ME! * * @param searchFeature DOCUMENT ME! * * @return DOCUMENT ME! */ protected abstract boolean performSearch(final SearchFeature searchFeature); /** * DOCUMENT ME! * * @return DOCUMENT ME! */ protected abstract PNode getPointerAnnotation(); }