/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo 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 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.fge.connectors.rpc; import java.awt.Cursor; import java.awt.event.MouseEvent; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.fge.connectors.rpc.RectPolylinConnector.RectPolylinAdjustability; import org.openflexo.fge.geom.FGEGeometricObject; import org.openflexo.fge.geom.FGEGeometricObject.SimplifiedCardinalDirection; import org.openflexo.fge.geom.FGEPoint; import org.openflexo.fge.geom.FGESegment; import org.openflexo.fge.geom.area.FGEArea; import org.openflexo.fge.geom.area.FGEHalfPlane; import org.openflexo.fge.geom.area.FGEPlane; public class AdjustableIntermediateControlPoint extends RectPolylinAdjustableControlPoint { static final Logger logger = Logger.getLogger(AdjustableIntermediateControlPoint.class.getPackage().getName()); private int index; public AdjustableIntermediateControlPoint(FGEPoint point, int index, RectPolylinConnector connector) { super(point, connector); this.index = index; } @Override public FGEArea getDraggingAuthorizedArea() { return new FGEPlane(); } @Override public Cursor getDraggingCursor() { if (getConnector().getAdjustability() == RectPolylinAdjustability.BASICALLY_ADJUSTABLE) { return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); } return super.getDraggingCursor(); } @Override public boolean dragToPoint(FGEPoint newRelativePoint, FGEPoint pointRelativeToInitialConfiguration, FGEPoint newAbsolutePoint, FGEPoint initialPoint, MouseEvent event) { if (getConnector().getAdjustability() == RectPolylinAdjustability.BASICALLY_ADJUSTABLE) { getConnector().setCrossedControlPoint(newRelativePoint); getConnector()._connectorChanged(true); getGraphicalRepresentation().notifyConnectorChanged(); return true; } FGEPoint pt = getNearestPointOnAuthorizedArea(newRelativePoint); if (pt == null) { logger.warning("Cannot nearest point for point " + newRelativePoint + " and area " + getDraggingAuthorizedArea()); return false; } // Following little hack is used here to prevent some equalities that may // lead to inconsistent orientations pt.x += FGEGeometricObject.EPSILON; pt.y += FGEGeometricObject.EPSILON; FGEPoint oldPoint = getPoint(); setPoint(pt); getPolylin().updatePointAt(index, pt); boolean continueDragging = movedIntermediateCP(index, oldPoint, true); getConnector()._connectorChanged(true); getGraphicalRepresentation().notifyConnectorChanged(); return continueDragging; } /** * This method is internally called to notify that intermediate control point at supplied index has just been moved. * * Previous and next point are updated accordingly * * Return boolean indicating if dragging lead to major layout modification where current dragged control point was suppressed: - When * true: control point still exist - When false: control point has disappeared and dragging should stop * * @param index */ private boolean movedIntermediateCP(int index, FGEPoint oldCPLocation, boolean simplifyLayout) { if (RectPolylinConnector.logger.isLoggable(Level.FINE)) { RectPolylinConnector.logger.fine("Moved intermediate point at index: " + index); } // First, obtain location of Control Point being moved FGEPoint newCPLocation = getPolylin().getPointAt(index); // Then obtain locations of previous and following control points FGEPoint previousCPLocation = getPolylin().getPointAt(index - 1); FGEPoint previousCPOldLocation = previousCPLocation.clone(); FGEPoint nextCPLocation = getPolylin().getPointAt(index + 1); FGEPoint nextCPOldLocation = nextCPLocation.clone(); // And their orientations, that will be usefull too SimplifiedCardinalDirection previousSegmentOrientation = getPolylin().getApproximatedOrientationOfSegment(index - 1); SimplifiedCardinalDirection nextSegmentOrientation = getPolylin().getApproximatedOrientationOfSegment(index); // SimplifiedCardinalDirection startSegmentOrientation = getPolylin().getApproximatedOrientationOfSegment(index-2); // SimplifiedCardinalDirection endSegmentOrientation = getPolylin().getApproximatedOrientationOfSegment(index+1); FGESegment intermediateCPStartSegment = getPolylin().getSegmentAt(index - 2); FGESegment intermediateCPEndSegment = getPolylin().getSegmentAt(index + 1); // FGESegment intermediateCPFirstSegment = polylin.getSegmentAt(index-1); // FGESegment intermediateCPNextSegment = polylin.getSegmentAt(index); // Declare new locations FGEPoint previousCPNewLocation = new FGEPoint(previousCPLocation); FGEPoint nextCPNewLocation = new FGEPoint(nextCPLocation); // Update previous control point location according to orientation of related segment if (previousSegmentOrientation.isHorizontal()) { previousCPNewLocation.y = newCPLocation.y; } else if (previousSegmentOrientation.isVertical()) { previousCPNewLocation.x = newCPLocation.x; } else { RectPolylinConnector.logger.warning("Inconsistent data: segment not horizontal nor vertical"); } // If we don't modify general layout of connector, // control point will move from location previousCPLocation to previousCPNewLocation if (simplifyLayout) { // But meanwhile, we can also decide to change general shape by deleting some points. // This will happen if oldCPLocation and newCPLocation are each other // From both side of half-plane formed by intermediateCPStartSegment FGEHalfPlane intermediateCPStartSegmentHalfPlane = new FGEHalfPlane(intermediateCPStartSegment, oldCPLocation); if (!intermediateCPStartSegmentHalfPlane.containsPoint(newCPLocation)) { if (logger.isLoggable(Level.INFO)) { logger.info("Two points will be removed (pattern 1) at index=" + (index - 1)); } getConnector()._simplifyLayoutOfCurrentPolylinByDeletingTwoPoints(index - 1, newCPLocation); /* getPolylin().removePointAtIndex(index-1); getPolylin().removePointAtIndex(index-1); getConnector()._getControlPoints().remove(index-1); getConnector()._getControlPoints().remove(index-1); if (previousSegmentOrientation.isHorizontal()) { getPolylin().updatePointAt(index-2, new FGEPoint(newCPLocation.x,getPolylin().getPointAt(index-2).y)); getPolylin().updatePointAt(index-1, new FGEPoint(newCPLocation.x,getPolylin().getPointAt(index-1).y)); } else if (previousSegmentOrientation.isVertical()) { getPolylin().updatePointAt(index-2, new FGEPoint(getPolylin().getPointAt(index-2).x,newCPLocation.y)); getPolylin().updatePointAt(index-1, new FGEPoint(getPolylin().getPointAt(index-1).x,newCPLocation.y)); } getConnector().updateWithNewPolylin(getPolylin());*/ return false; } if (index > 2) { // This may also happen if previousCPOldLocation and previousCPNewLocation are each other // From both side of half-plane formed by intermediateCPBeforeStartSegment FGESegment intermediateCPBeforeStartSegment = getPolylin().getSegmentAt(index - 3); FGEHalfPlane intermediateCPBeforeStartSegmentHalfPlane = new FGEHalfPlane(intermediateCPBeforeStartSegment, previousCPOldLocation); if (!intermediateCPBeforeStartSegmentHalfPlane.containsPoint(previousCPNewLocation)) { if (logger.isLoggable(Level.INFO)) { logger.info("Two points will be removed (pattern 2) at index=" + (index - 2)); } getConnector()._simplifyLayoutOfCurrentPolylinByDeletingTwoPoints(index - 2, newCPLocation); /* getPolylin().removePointAtIndex(index-2); getPolylin().removePointAtIndex(index-2); getConnector()._getControlPoints().remove(index-2); getConnector()._getControlPoints().remove(index-2); if (startSegmentOrientation.isVertical()) { getPolylin().updatePointAt(index-2, new FGEPoint(newCPLocation.x,getPolylin().getPointAt(index-2).y)); getPolylin().updatePointAt(index-1, new FGEPoint(newCPLocation.x,getPolylin().getPointAt(index-1).y)); } else if (startSegmentOrientation.isHorizontal()) { getPolylin().updatePointAt(index-2, new FGEPoint(getPolylin().getPointAt(index-2).x,newCPLocation.y)); getPolylin().updatePointAt(index-1, new FGEPoint(getPolylin().getPointAt(index-1).x,newCPLocation.y)); } getConnector().updateWithNewPolylin(getPolylin());*/ return false; } } } getPolylin().updatePointAt(index - 1, previousCPNewLocation); getConnector()._getControlPoints().elementAt(index - 1).setPoint(previousCPNewLocation); // Update next control point location according to orientation of related segment if (nextSegmentOrientation.isHorizontal()) { nextCPNewLocation.y = newCPLocation.y; } else if (nextSegmentOrientation.isVertical()) { nextCPNewLocation.x = newCPLocation.x; } else { RectPolylinConnector.logger.warning("Inconsistent data: segment not horizontal nor vertical"); } // If we don't modify general layout of connector, // control point will move from location nextCPLocation to nextCPNewLocation if (simplifyLayout) { // But meanwhile, we can also decide to change general shape by deleting some points. // This will happen if oldCPLocation and newCPLocation are each other // From both side of half-plane formed by intermediateCPEndSegment FGEHalfPlane intermediateCPEndSegmentHalfPlane = new FGEHalfPlane(intermediateCPEndSegment, oldCPLocation); if (!intermediateCPEndSegmentHalfPlane.containsPoint(newCPLocation)) { if (logger.isLoggable(Level.INFO)) { logger.info("Two points will be removed (pattern 3) at index=" + index); } getConnector()._simplifyLayoutOfCurrentPolylinByDeletingTwoPoints(index, newCPLocation); /* getPolylin().removePointAtIndex(index); getPolylin().removePointAtIndex(index); getConnector()._getControlPoints().remove(index); getConnector()._getControlPoints().remove(index); if (nextSegmentOrientation.isHorizontal()) { getPolylin().updatePointAt(index-1, new FGEPoint(newCPLocation.x,getPolylin().getPointAt(index-1).y)); getPolylin().updatePointAt(index, new FGEPoint(newCPLocation.x,getPolylin().getPointAt(index).y)); } else if (nextSegmentOrientation.isVertical()) { getPolylin().updatePointAt(index-1, new FGEPoint(getPolylin().getPointAt(index-1).x,newCPLocation.y)); getPolylin().updatePointAt(index, new FGEPoint(getPolylin().getPointAt(index).x,newCPLocation.y)); } getConnector().updateWithNewPolylin(getPolylin());*/ return false; } if (getPolylin().getSegmentNb() > index + 2) { // This may also happen if nextCPOldLocation and nextCPNewLocation are each other // From both side of half-plane formed by intermediateCPAfterEndSegment FGESegment intermediateCPAfterEndSegment = getPolylin().getSegmentAt(index + 2); FGEHalfPlane intermediateCPAfterEndSegmentHalfPlane = new FGEHalfPlane(intermediateCPAfterEndSegment, nextCPOldLocation); if (!intermediateCPAfterEndSegmentHalfPlane.containsPoint(nextCPNewLocation)) { if (logger.isLoggable(Level.INFO)) { logger.info("Two points will be removed (pattern 4) at index=" + (index + 1)); } getConnector()._simplifyLayoutOfCurrentPolylinByDeletingTwoPoints(index + 1, newCPLocation); /* getPolylin().removePointAtIndex(index+1); getPolylin().removePointAtIndex(index+1); getConnector()._getControlPoints().remove(index+1); getConnector()._getControlPoints().remove(index+1); if (endSegmentOrientation.isHorizontal()) { getPolylin().updatePointAt(index, new FGEPoint(newCPLocation.x,getPolylin().getPointAt(index).y)); getPolylin().updatePointAt(index+1, new FGEPoint(newCPLocation.x,getPolylin().getPointAt(index+1).y)); } else if (endSegmentOrientation.isVertical()) { getPolylin().updatePointAt(index, new FGEPoint(getPolylin().getPointAt(index).x,newCPLocation.y)); getPolylin().updatePointAt(index+1, new FGEPoint(getPolylin().getPointAt(index+1).x,newCPLocation.y)); } getConnector().updateWithNewPolylin(getPolylin());*/ return false; } } } getPolylin().updatePointAt(index + 1, nextCPNewLocation); getConnector()._getControlPoints().elementAt(index + 1).setPoint(nextCPNewLocation); /*if (!getPolylin().isNormalized()) { getConnector().updateWithNewPolylin(getPolylin(), true); }*/ return true; } }