/******************************************************************************* | |
* Copyright (c) 2005, 2012 IBM Corporation and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License 2.0 | |
* which accompanies this distribution, and is available at | |
* https://www.eclipse.org/legal/epl-2.0/ | |
* | |
* SPDX-License-Identifier: EPL-2.0 | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.bpel.ui.util; | |
import java.util.Collection; | |
import java.util.List; | |
import org.eclipse.bpel.ui.editparts.FlowEditPart; | |
import org.eclipse.draw2d.Cursors; | |
import org.eclipse.draw2d.PositionConstants; | |
import org.eclipse.draw2d.geometry.Point; | |
import org.eclipse.gef.AccessibleAnchorProvider; | |
import org.eclipse.gef.EditPart; | |
import org.eclipse.gef.EditPartViewer; | |
import org.eclipse.gef.commands.Command; | |
import org.eclipse.gef.requests.CreateConnectionRequest; | |
import org.eclipse.gef.requests.CreationFactory; | |
import org.eclipse.gef.tools.AbstractConnectionCreationTool; | |
import org.eclipse.swt.SWT; | |
import org.eclipse.swt.events.KeyEvent; | |
import org.eclipse.swt.graphics.Rectangle; | |
import org.eclipse.swt.widgets.Control; | |
import org.eclipse.swt.widgets.Scrollable; | |
/** | |
* This class allows an EditPart to have initial source anchor for | |
* the ConnectionCreationTool. | |
*/ | |
public class BPELConnectionCreationTool extends AbstractConnectionCreationTool { | |
private EditPartViewer viewer; | |
private EditPart source; | |
private EditPart proposedTarget; | |
private boolean lastProposedTargetConnectable; | |
public BPELConnectionCreationTool(CreationFactory factory) { | |
super(factory); | |
setDefaultCursor(Cursors.ARROW); // don't use the plug | |
// setDisabledCursor(); TODO: need cursor with arrow and no drop | |
setFactory(factory); | |
setUnloadWhenFinished(true); | |
} | |
@Override | |
protected boolean handleKeyDown(KeyEvent event) { | |
boolean ret = ourHandleKeyDown(event); | |
if (getDomain().getActiveTool() != this) { | |
//set.setLockOut(false); | |
} | |
return ret; | |
} | |
@Override | |
protected void handleFinished() { | |
super.handleFinished(); | |
//set.setLockOut(false); | |
} | |
public void setInitialAnchor(EditPart part, EditPartViewer curViewer) { | |
setViewer(curViewer); | |
setTargetEditPart(part); | |
updateTargetRequest(); | |
setConnectionSource(part); | |
Command command = getCommand(); | |
((CreateConnectionRequest)getTargetRequest()).setSourceEditPart(part); | |
source = part; | |
proposedTarget = null; | |
lastProposedTargetConnectable = false; | |
if (command != null) { | |
setState(STATE_CONNECTION_STARTED); | |
setCurrentCommand(command); | |
viewer = getCurrentViewer(); | |
} | |
if (isInState(STATE_CONNECTION_STARTED)) { | |
updateTargetRequest(); | |
updateTargetUnderMouse(); | |
showSourceFeedback(); | |
showTargetFeedback(); | |
setCurrentCommand(getCommand()); | |
} | |
return; | |
} | |
@Override | |
protected boolean handleButtonDown(int button) { | |
if (button == 1 && stateTransition(STATE_CONNECTION_STARTED, STATE_TERMINAL)) { | |
boolean ret = handleCreateConnection(); | |
if (getCommand() != null) | |
handleFinished(); | |
return ret; | |
} | |
if (isInState(STATE_INITIAL) && button == 1) { | |
updateTargetRequest(); | |
updateTargetUnderMouse(); | |
setConnectionSource(getTargetEditPart()); | |
Command command = getCommand(); | |
((CreateConnectionRequest)getTargetRequest()).setSourceEditPart( | |
getTargetEditPart()); | |
if (command != null) { | |
setState(STATE_CONNECTION_STARTED); | |
setCurrentCommand(command); | |
viewer = getCurrentViewer(); | |
} | |
} | |
if (isInState(STATE_INITIAL) && button != 1) { | |
setState(STATE_INVALID); | |
handleInvalidInput(); | |
} | |
if (isInState(STATE_CONNECTION_STARTED)) { | |
//Fake a drag to cause feedback to be displayed immediately on mouse down. | |
handleDrag(); | |
} | |
return true; | |
} | |
@Override | |
public void deactivate() { | |
viewer = null; | |
super.deactivate(); | |
} | |
@Override | |
protected boolean handleMove() { | |
if (isInState(STATE_CONNECTION_STARTED) && viewer != getCurrentViewer()) | |
return false; | |
if (isInState(STATE_CONNECTION_STARTED | STATE_INITIAL | STATE_ACCESSIBLE_DRAG_IN_PROGRESS)) { | |
updateTargetRequest(); | |
updateTargetUnderMouse(); | |
showSourceFeedback(); | |
showTargetFeedback(); | |
setCurrentCommand(getCommand()); | |
} | |
return true; | |
} | |
@Override | |
protected boolean updateTargetUnderMouse() { | |
if (!isTargetLocked()) { | |
Collection exclude = getExclusionSet(); | |
EditPart editPart = getCurrentViewer().findObjectAtExcluding( | |
getLocation(), | |
exclude, | |
getTargetingConditional()); | |
if (editPart != null) { | |
editPart = editPart.getTargetEditPart(getTargetRequest()); | |
} | |
boolean changed = getTargetEditPart() != editPart; | |
setTargetEditPart(editPart); | |
return changed; | |
} | |
return false; | |
} | |
@Override | |
protected EditPartViewer.Conditional getTargetingConditional() { | |
return new EditPartViewer.Conditional() { | |
public boolean evaluate(EditPart editpart) { | |
EditPart target = editpart.getTargetEditPart(getTargetRequest()); | |
if (target == null) | |
return false; | |
if (target == proposedTarget) | |
return lastProposedTargetConnectable; | |
if (target.getParent() instanceof FlowEditPart) { | |
lastProposedTargetConnectable = ((FlowEditPart)(target.getParent())).detectImpendingCycle(source, target); | |
} | |
else { | |
lastProposedTargetConnectable = true; | |
} | |
proposedTarget = target; | |
return lastProposedTargetConnectable; | |
} | |
}; | |
} | |
boolean acceptConnectionFinish(KeyEvent event) { | |
return isInState(STATE_ACCESSIBLE_DRAG_IN_PROGRESS | STATE_CONNECTION_STARTED) && event.character == 13; | |
} | |
boolean acceptConnectionStart(KeyEvent event) { | |
return isInState(STATE_INITIAL) && event.character == 13; | |
} | |
/** | |
* Cleans up feedback and resets the tool when focus is lost. | |
* @return <code>true</code> if this focus lost event was processed | |
*/ | |
@Override | |
protected boolean handleFocusLost() { | |
if (isInState(STATE_CONNECTION_STARTED | STATE_ACCESSIBLE_DRAG_IN_PROGRESS)) { | |
eraseSourceFeedback(); | |
eraseTargetFeedback(); | |
setState(STATE_INVALID); | |
handleFinished(); | |
} | |
return super.handleFocusLost(); | |
} | |
private boolean ourAcceptArrowKey(KeyEvent e) { | |
int key = e.keyCode; | |
if (!(isInState(STATE_INITIAL | |
| STATE_CONNECTION_STARTED | |
| STATE_ACCESSIBLE_DRAG | |
| STATE_ACCESSIBLE_DRAG_IN_PROGRESS))) | |
return false; | |
return (key == SWT.ARROW_UP) | |
|| (key == SWT.ARROW_RIGHT) | |
|| (key == SWT.ARROW_DOWN) | |
|| (key == SWT.ARROW_LEFT); | |
} | |
private boolean ourHandleKeyDown(KeyEvent event) { | |
if (ourAcceptArrowKey(event)) { | |
int direction = 0; | |
switch (event.keyCode) { | |
case SWT.ARROW_DOWN : | |
direction = PositionConstants.SOUTH; | |
break; | |
case SWT.ARROW_UP: | |
direction = PositionConstants.NORTH; | |
break; | |
case SWT.ARROW_RIGHT: | |
direction = PositionConstants.EAST; | |
break; | |
case SWT.ARROW_LEFT: | |
direction = PositionConstants.WEST; | |
break; | |
} | |
boolean consumed = false; | |
if (direction != 0 && event.stateMask == 0) | |
consumed = navigateNextAnchor(direction); | |
if (!consumed) { | |
event.stateMask |= SWT.CONTROL; | |
event.stateMask &= ~SWT.SHIFT; | |
if (getCurrentViewer().getKeyHandler().keyPressed(event)) { | |
navigateNextAnchor(0); | |
updateTargetRequest(); | |
updateTargetUnderMouse(); | |
Command command = getCommand(); | |
if (command != null) | |
setCurrentCommand(command); | |
return true; | |
} | |
} | |
} | |
if (acceptConnectionStart(event)) { | |
updateTargetUnderMouse(); | |
setConnectionSource(getTargetEditPart()); | |
((CreateConnectionRequest)getTargetRequest()) | |
.setSourceEditPart(getTargetEditPart()); | |
setState(STATE_ACCESSIBLE_DRAG_IN_PROGRESS); | |
ourPlaceMouseInViewer(getLocation().getTranslated(6, 6)); | |
return true; | |
} | |
if (acceptConnectionFinish(event)) { | |
Command command = getCommand(); | |
if (command != null && command.canExecute()) { | |
setState(STATE_INITIAL); | |
ourPlaceMouseInViewer(getLocation().getTranslated(6, 6)); | |
eraseSourceFeedback(); | |
eraseTargetFeedback(); | |
setCurrentCommand(command); | |
executeCurrentCommand(); | |
handleFinished(); | |
} | |
return true; | |
} | |
return super.handleKeyDown(event); | |
} | |
boolean navigateNextAnchor(int direction) { | |
EditPart focus = getCurrentViewer().getFocusEditPart(); | |
AccessibleAnchorProvider provider; | |
provider = (AccessibleAnchorProvider)focus.getAdapter(AccessibleAnchorProvider.class); | |
if (provider == null) | |
return false; | |
List list; | |
if (isInState(STATE_ACCESSIBLE_DRAG_IN_PROGRESS)) | |
list = provider.getTargetAnchorLocations(); | |
else | |
list = provider.getSourceAnchorLocations(); | |
Point start = getLocation(); | |
int distance = Integer.MAX_VALUE; | |
Point next = null; | |
for (int i = 0; i < list.size(); i++) { | |
Point p = (Point)list.get(i); | |
if (p.equals(start) | |
|| (direction != 0 | |
&& (start.getPosition(p) != direction))) | |
continue; | |
int d = p.getDistanceOrthogonal(start); | |
if (d < distance) { | |
distance = d; | |
next = p; | |
} | |
} | |
if (next != null) { | |
ourPlaceMouseInViewer(next); | |
return true; | |
} | |
return false; | |
} | |
void ourPlaceMouseInViewer(Point p) { | |
if (getCurrentViewer() == null) | |
return; | |
Control c = getCurrentViewer().getControl(); | |
Rectangle rect; | |
if (c instanceof Scrollable) | |
rect = ((Scrollable)c).getClientArea(); | |
else | |
rect = c.getBounds(); | |
if (p.x > rect.x + rect.width - 1) | |
p.x = rect.x + rect.width - 1; | |
else if (p.x < rect.x) | |
p.x = rect.x; | |
if (p.y > rect.y + rect.height - 1) | |
p.y = rect.y + rect.height - 1; | |
else if (p.y < rect.y) | |
p.y = rect.y; | |
org.eclipse.swt.graphics.Point swt = new org.eclipse.swt.graphics.Point(p.x, p.y); | |
swt = c.toDisplay(swt); | |
c.getDisplay().setCursorLocation(swt); | |
} | |
} |