/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
/*
* DeleteFeatureListener.java
*
* Created on 20. April 2005, 11:22
*/
package de.cismet.cismap.commons.gui.piccolo.eventlistener;
import com.vividsolutions.jts.geom.*;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolo.nodes.PText;
import edu.umd.cs.piccolox.event.PNotificationCenter;
import java.awt.Color;
import java.awt.Font;
import java.awt.geom.RoundRectangle2D;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import de.cismet.cismap.commons.CrsTransformer;
import de.cismet.cismap.commons.features.Feature;
import de.cismet.cismap.commons.gui.MappingComponent;
import de.cismet.cismap.commons.gui.piccolo.PFeature;
import de.cismet.cismap.commons.gui.piccolo.eventlistener.actions.FeatureAddEntityAction;
import de.cismet.cismap.commons.gui.piccolo.eventlistener.actions.FeatureAddHoleAction;
import de.cismet.cismap.commons.gui.piccolo.eventlistener.actions.FeatureCreateAction;
import de.cismet.cismap.commons.tools.PFeatureTools;
/**
* DOCUMENT ME!
*
* @author hell
* @version $Revision$, $Date$
*/
public class DeleteFeatureListener extends PBasicInputEventHandler {
//~ Static fields/initializers ---------------------------------------------
private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DeleteFeatureListener.class);
public static final String FEATURE_DELETE_REQUEST_NOTIFICATION = "FEATURE_DELETE_REQUEST_NOTIFICATION"; // NOI18N
private static final ClassComparator comparator = new ClassComparator();
//~ Instance fields --------------------------------------------------------
private PFeature featureRequestedForDeletion = null;
private final InvalidPolygonTooltip multiPolygonPointerAnnotation = new InvalidPolygonTooltip();
private final MappingComponent mc;
private Class[] allowedFeatureClassesToDelete = null;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new DeleteFeatureListener object.
*
* @param mc DOCUMENT ME!
*/
public DeleteFeatureListener(final MappingComponent mc) {
this.mc = mc;
mc.getCamera().addChild(multiPolygonPointerAnnotation);
}
//~ Methods ----------------------------------------------------------------
@Override
public void mouseMoved(final PInputEvent pInputEvent) {
multiPolygonPointerAnnotation.setOffset(
pInputEvent.getCanvasPosition().getX()
+ 20.0d,
pInputEvent.getCanvasPosition().getY()
+ 20.0d);
final Collection selectedFeatures = mc.getFeatureCollection().getSelectedFeatures();
if (selectedFeatures.size() != 1) {
if (pInputEvent.isAltDown()) {
multiPolygonPointerAnnotation.setMode(InvalidPolygonTooltip.Mode.SELECT_FEATURE);
multiPolygonPointerAnnotation.setVisible(true);
} else {
multiPolygonPointerAnnotation.setVisible(false);
}
} else {
multiPolygonPointerAnnotation.setVisible(false);
}
}
@Override
public void mouseClicked(final edu.umd.cs.piccolo.event.PInputEvent pInputEvent) {
super.mouseClicked(pInputEvent);
if (pInputEvent.getComponent() instanceof MappingComponent) {
final MappingComponent mappingComponent = (MappingComponent)pInputEvent.getComponent();
final PFeature clickedPFeature = (PFeature)PFeatureTools.getFirstValidObjectUnderPointer(
pInputEvent,
new Class[] { PFeature.class });
if ((clickedPFeature != null) && (clickedPFeature.getFeature() != null)
&& (allowedFeatureClassesToDelete != null)
&& (Arrays.binarySearch(
allowedFeatureClassesToDelete,
clickedPFeature.getFeature().getClass(),
comparator) < 0)) {
return;
}
if (pInputEvent.isAltDown()) { // alt-modifier => speziall-handling für
// multipolygone
final Collection selectedFeatures = mappingComponent.getFeatureCollection().getSelectedFeatures();
if (selectedFeatures.size() == 1) { // es ist genau ein feature selektiert
final PFeature selectedPFeature = mappingComponent.getPFeatureHM()
.get((Feature)selectedFeatures.toArray()[0]);
if ((selectedPFeature != null) && selectedPFeature.getFeature().canBeSelected()
&& selectedPFeature.getFeature().isEditable()
&& ((selectedPFeature.getFeature().getGeometry() instanceof MultiPolygon)
|| (selectedPFeature.getFeature().getGeometry() instanceof Polygon))) {
if ((selectedPFeature.getNumOfEntities() == 1) && (selectedPFeature.equals(clickedPFeature))) { // hat nur ein teil-polygon
// "normales" löschen des geklickten features
deletePFeature(selectedPFeature, mappingComponent);
} else { // hat mehrere teil-polygone
// koordinate der maus berechnen
final Coordinate mouseCoord = new Coordinate(
mappingComponent.getWtst().getSourceX(
pInputEvent.getPosition().getX()
- mappingComponent.getClip_offset_x()),
mappingComponent.getWtst().getSourceY(
pInputEvent.getPosition().getY()
- mappingComponent.getClip_offset_y()));
// teil-polygon unter der maus suchen
final GeometryFactory geometryFactory = new GeometryFactory(
new PrecisionModel(PrecisionModel.FLOATING),
CrsTransformer.extractSridFromCrs(
mappingComponent.getMappingModel().getSrs().getCode()));
final Point mousePoint = CrsTransformer.transformToGivenCrs(geometryFactory.createPoint(
mouseCoord),
CrsTransformer.createCrsFromSrid(
selectedPFeature.getFeature().getGeometry().getSRID()));
final int selectedEntityPosition = selectedPFeature.getEntityPositionUnderPoint(mousePoint);
if (selectedEntityPosition >= 0) { // gefunden => teil-polygon entfernen
final Polygon entity = selectedPFeature.getEntityByPosition(selectedEntityPosition);
selectedPFeature.removeEntity(selectedEntityPosition);
mappingComponent.getMemUndo()
.addAction(new FeatureAddEntityAction(
mappingComponent,
selectedPFeature.getFeature(),
entity));
mappingComponent.getMemRedo().clear();
} else { // nicht gefunden => es muss also ein loch sein => suchen
// und entfernen (komplex)
final int entityPosition = selectedPFeature.getMostInnerEntityUnderPoint(mousePoint);
final int holePosition = selectedPFeature.getHolePositionUnderPoint(
mousePoint,
entityPosition);
final LineString hole = selectedPFeature.getHoleByPosition(
entityPosition,
holePosition);
selectedPFeature.removeHoleUnderPoint(mousePoint);
mappingComponent.getMemUndo()
.addAction(new FeatureAddHoleAction(
mappingComponent,
selectedPFeature.getFeature(),
entityPosition,
hole));
mappingComponent.getMemRedo().clear();
}
}
}
} else { // mehrere features selektiert => alt-selektionsmodus
if (clickedPFeature != null) {
mappingComponent.getFeatureCollection().select(clickedPFeature.getFeature());
}
}
} else { // alt-modifier nicht gedrückt
if (clickedPFeature != null) {
// geklicktes feature entfernen
deletePFeature(clickedPFeature, mappingComponent);
}
}
}
}
/**
* DOCUMENT ME!
*
* @param pFeature DOCUMENT ME!
* @param mappingComponent DOCUMENT ME!
*/
private void deletePFeature(final PFeature pFeature, final MappingComponent mappingComponent) {
if (pFeature.getFeature().isEditable() && pFeature.getFeature().canBeSelected()) {
featureRequestedForDeletion = (PFeature)pFeature.clone();
mappingComponent.getFeatureCollection().removeFeature(pFeature.getFeature());
mappingComponent.getMemUndo().addAction(new FeatureCreateAction(mappingComponent, pFeature.getFeature()));
mappingComponent.getMemRedo().clear();
postFeatureDeleteRequest();
}
}
/**
* DOCUMENT ME!
*/
private void postFeatureDeleteRequest() {
final PNotificationCenter pn = PNotificationCenter.defaultCenter();
pn.postNotification(FEATURE_DELETE_REQUEST_NOTIFICATION, this);
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public PFeature getFeatureRequestedForDeletion() {
return featureRequestedForDeletion;
}
/**
* DOCUMENT ME!
*
* @return the allowedFeatrueClassesToDelete
*/
public Class[] getAllowedFeatureClassesToDelete() {
return allowedFeatureClassesToDelete;
}
/**
* Set the feature types, which are allowed to remove. If null is set, all feature types are allowed to remove. The
* given array will be sorted.
*
* @param allowedFeatureClassesToDelete the allowedFeatrueClassesToDelete to set
*/
public void setAllowedFeatureClassesToDelete(final Class[] allowedFeatureClassesToDelete) {
this.allowedFeatureClassesToDelete = allowedFeatureClassesToDelete;
if (allowedFeatureClassesToDelete != null) {
Arrays.sort(this.allowedFeatureClassesToDelete, comparator);
}
}
//~ Inner Classes ----------------------------------------------------------
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
class Tooltip extends PNode {
//~ Instance fields ----------------------------------------------------
private final Color COLOR_BACKGROUND = new Color(255, 255, 222, 200);
//~ Constructors -------------------------------------------------------
/**
* Creates a new Tooltip object.
*
* @param text DOCUMENT ME!
*/
public Tooltip(final String text) {
final PText pText = new PText(text);
final Font defaultFont = pText.getFont();
final Font boldDefaultFont = new Font(defaultFont.getName(),
defaultFont.getStyle()
+ Font.BOLD,
defaultFont.getSize());
pText.setFont(boldDefaultFont);
pText.setOffset(5, 5);
final PPath background = new PPath(new RoundRectangle2D.Double(
0,
0,
pText.getWidth()
+ 15,
pText.getHeight()
+ 15,
10,
10));
background.setPaint(COLOR_BACKGROUND);
background.addChild(pText);
setTransparency(0.85f);
addChild(background);
}
}
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
private static class ClassComparator implements Comparator<Class> {
//~ Methods ------------------------------------------------------------
@Override
public int compare(final Class o1, final Class o2) {
return o1.getName().compareTo(o2.getName());
}
}
}