/*******************************************************************************
* Copyright (c) 2015, 2016 itemis AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Matthias Wienand (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef.mvc.examples.logo.handlers;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.gef.common.adapt.AdapterKey;
import org.eclipse.gef.geometry.planar.Dimension;
import org.eclipse.gef.geometry.planar.Point;
import org.eclipse.gef.mvc.examples.logo.MvcLogoExample;
import org.eclipse.gef.mvc.examples.logo.model.GeometricCurve;
import org.eclipse.gef.mvc.examples.logo.parts.GeometricCurvePart;
import org.eclipse.gef.mvc.examples.logo.parts.GeometricShapePart;
import org.eclipse.gef.mvc.fx.gestures.ClickDragGesture;
import org.eclipse.gef.mvc.fx.handlers.AbstractHandler;
import org.eclipse.gef.mvc.fx.handlers.IOnDragHandler;
import org.eclipse.gef.mvc.fx.models.SelectionModel;
import org.eclipse.gef.mvc.fx.operations.DeselectOperation;
import org.eclipse.gef.mvc.fx.parts.CircleSegmentHandlePart;
import org.eclipse.gef.mvc.fx.parts.IContentPart;
import org.eclipse.gef.mvc.fx.parts.IVisualPart;
import org.eclipse.gef.mvc.fx.policies.CreationPolicy;
import org.eclipse.gef.mvc.fx.viewer.InfiniteCanvasViewer;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multiset;
import javafx.event.EventTarget;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
public class CreateCurveOnDragHandler extends AbstractHandler implements IOnDragHandler {
private CircleSegmentHandlePart bendTargetPart;
private Map<AdapterKey<? extends IOnDragHandler>, IOnDragHandler> dragPolicies;
private GeometricCurvePart curvePart;
@Override
public void abortDrag() {
if (bendTargetPart == null) {
return;
}
// forward event to bend target part
if (dragPolicies != null) {
for (IOnDragHandler dragPolicy : dragPolicies.values()) {
dragPolicy.abortDrag();
}
}
restoreRefreshVisuals(curvePart);
curvePart = null;
bendTargetPart = null;
dragPolicies = null;
}
@Override
public void drag(MouseEvent event, Dimension delta) {
if (bendTargetPart == null) {
return;
}
// forward drag events to bend target part
if (dragPolicies != null) {
for (IOnDragHandler dragPolicy : dragPolicies.values()) {
dragPolicy.drag(event, delta);
}
}
}
@Override
public void endDrag(MouseEvent e, Dimension delta) {
if (bendTargetPart == null) {
return;
}
// forward event to bend target part
if (dragPolicies != null) {
for (IOnDragHandler dragPolicy : dragPolicies.values()) {
dragPolicy.endDrag(e, delta);
}
}
restoreRefreshVisuals(curvePart);
curvePart = null;
bendTargetPart = null;
dragPolicies = null;
}
protected CircleSegmentHandlePart findBendTargetPart(GeometricCurvePart curvePart, EventTarget eventTarget) {
// find last segment handle part
Multiset<IVisualPart<? extends Node>> anchoreds = curvePart.getAnchoredsUnmodifiable();
for (IVisualPart<? extends Node> anchored : anchoreds) {
if (anchored instanceof CircleSegmentHandlePart) {
CircleSegmentHandlePart circleSegmentHandlePart = (CircleSegmentHandlePart) anchored;
if (circleSegmentHandlePart.getSegmentParameter() == 1.0) {
return circleSegmentHandlePart;
}
}
}
throw new IllegalStateException("Cannot find bend target part.");
}
protected Point getLocation(MouseEvent e) {
// XXX: Viewer may be null if the host is removed in the same pass in
// which the event is forwarded.
if (getHost().getViewer() == null) {
return new Point(e.getSceneX(), e.getSceneY());
}
// FIXME: Prevent invocation of interaction policies when their host
// does not have a link to the viewer.
Point2D location = ((InfiniteCanvasViewer) getHost().getRoot().getViewer()).getCanvas().getContentGroup()
.sceneToLocal(e.getSceneX(), e.getSceneY());
return new Point(location.getX(), location.getY());
}
protected GeometricShapePart getShapePart() {
return (GeometricShapePart) getHost().getAnchoragesUnmodifiable().keySet().iterator().next();
}
@Override
public void hideIndicationCursor() {
}
@Override
public boolean showIndicationCursor(KeyEvent event) {
return false;
}
@Override
public boolean showIndicationCursor(MouseEvent event) {
return false;
}
@Override
public void startDrag(MouseEvent event) {
// create new curve
GeometricCurve curve = new GeometricCurve(new Point[] { new Point(), new Point() },
MvcLogoExample.GEF_COLOR_GREEN, MvcLogoExample.GEF_STROKE_WIDTH, MvcLogoExample.GEF_DASH_PATTERN, null);
curve.addSourceAnchorage(getShapePart().getContent());
// create using CreationPolicy from root part
CreationPolicy creationPolicy = getHost().getRoot().getAdapter(CreationPolicy.class);
init(creationPolicy);
curvePart = (GeometricCurvePart) creationPolicy.create(curve, getHost().getRoot(),
HashMultimap.<IContentPart<? extends Node>, String> create());
commit(creationPolicy);
// disable refresh visuals for the curvePart
storeAndDisableRefreshVisuals(curvePart);
// move curve to pointer location
curvePart.getVisual().setEndPoint(getLocation(event));
// build operation to deselect all but the new curve part
List<IContentPart<? extends Node>> toBeDeselected = new ArrayList<>(
getHost().getRoot().getViewer().getAdapter(SelectionModel.class).getSelectionUnmodifiable());
toBeDeselected.remove(curvePart);
DeselectOperation deselectOperation = new DeselectOperation(getHost().getRoot().getViewer(), toBeDeselected);
// execute on stack
try {
getHost().getRoot().getViewer().getDomain().execute(deselectOperation, new NullProgressMonitor());
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
// find bend target part
bendTargetPart = findBendTargetPart(curvePart, event.getTarget());
if (bendTargetPart != null) {
dragPolicies = bendTargetPart.getAdapters(ClickDragGesture.ON_DRAG_POLICY_KEY);
}
if (dragPolicies != null) {
MouseEvent dragEvent = new MouseEvent(event.getSource(), event.getTarget(), MouseEvent.MOUSE_DRAGGED,
event.getX(), event.getY(), event.getScreenX(), event.getScreenY(), event.getButton(),
event.getClickCount(), event.isShiftDown(), event.isControlDown(), event.isAltDown(),
event.isMetaDown(), event.isPrimaryButtonDown(), event.isMiddleButtonDown(),
event.isSecondaryButtonDown(), event.isSynthesized(), event.isPopupTrigger(),
event.isStillSincePress(), event.getPickResult());
for (IOnDragHandler dragPolicy : dragPolicies.values()) {
dragPolicy.startDrag(event);
// XXX: send initial drag event so that the end position is set
dragPolicy.drag(dragEvent, new Dimension());
}
}
}
}