blob: 887325235999ff551d9f49c05780cb980aee9672 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2002, 2010 IBM Corporation 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:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.diagram.ui.tools;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.Request;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.SharedCursors;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IDiagramPreferenceSupport;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IPrimaryEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.internal.l10n.DiagramUIPluginImages;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramCommandStack;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequestFactory;
import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
/**
* Generic Connection Creation Tool - creates a semantic model element and a
* view for it.
*
* Supports creation of a connection when there is not information is not all
* available even after ther user has selected the target. When the user clicks
* on the target element, then they will be presented with a diaglog to permit
* them to enter the additional information.
*
* @author melaasar
*/
public class ConnectionCreationTool
extends org.eclipse.gef.tools.ConnectionCreationTool {
private IElementType elementType = null;
/** Should deactivation be avoided? */
private boolean avoidDeactivation = false;
/** Does the user have the ctrl key pressed? */
private boolean isCtrlKeyDown;
static private Cursor CURSOR_CONNECTION = new Cursor(Display.getDefault(),
DiagramUIPluginImages.DESC_CONNECTION_CURSOR_SOURCE.getImageData(),
DiagramUIPluginImages.DESC_CONNECTION_CURSOR_MASK.getImageData(), 0, 0);
static private Cursor CURSOR_CONNECTION_NOT = new Cursor(Display
.getDefault(), DiagramUIPluginImages.DESC_NO_CONNECTION_CURSOR_SOURCE
.getImageData(), DiagramUIPluginImages.DESC_NO_CONNECTION_CURSOR_MASK
.getImageData(), 0, 0);
static private Cursor CURSOR_TARGET_MENU = new Cursor(Display.getDefault(), SWT.CURSOR_HAND);
/**
* Creates a new ConnectionCreationTool, the elementTypeInfo and
* viewFactoryhint will be set later.
*/
public ConnectionCreationTool() {
setUnloadWhenFinished(true);
setDefaultCursor(CURSOR_CONNECTION);
setDisabledCursor(CURSOR_CONNECTION_NOT);
}
/**
* Method CreationTool. Creates a new CreationTool with the given
* elementType
*
* @param elementType
*/
public ConnectionCreationTool(IElementType elementType) {
this();
setSemanticRequestType(elementType);
}
/**
* @return Returns the elementType.
* @since 1.5
*/
public IElementType getElementType() {
return elementType;
}
/**
* Sets the elementType.
*
* @param elementType
* The elementType to set
*/
protected void setSemanticRequestType(IElementType elementType) {
this.elementType = elementType;
}
/**
* Gets the preferences hint that is to be used to find the appropriate
* preference store from which to retrieve diagram preference values. The
* preference hint is mapped to a preference store in the preference
* registry <@link DiagramPreferencesRegistry>.
*
* @return the preferences hint
*/
protected PreferencesHint getPreferencesHint() {
EditPartViewer viewer = getCurrentViewer();
if (viewer != null) {
RootEditPart rootEP = viewer.getRootEditPart();
if (rootEP instanceof IDiagramPreferenceSupport) {
return ((IDiagramPreferenceSupport) rootEP)
.getPreferencesHint();
}
}
return PreferencesHint.USE_DEFAULTS;
}
/**
* @see org.eclipse.gef.tools.TargetingTool#createTargetRequest()
*/
protected Request createTargetRequest() {
return CreateViewRequestFactory.getCreateConnectionRequest(
getElementType(), getPreferencesHint());
}
/**
* Since both the view and semantic requests contain results we need to free
* them when the tool is deactivated
*
* @see org.eclipse.gef.Tool#deactivate()
*/
public void deactivate() {
if (!avoidDeactivation()) {
super.deactivate();
setTargetRequest(null);
}
}
/**
* @see org.eclipse.gef.tools.AbstractConnectionCreationTool#eraseSourceFeedback()
*/
protected void eraseSourceFeedback() {
if (!avoidDeactivation()) {
super.eraseSourceFeedback();
}
}
/**
* @see org.eclipse.gef.tools.AbstractTool#handleButtonUp(int)
*/
protected boolean handleButtonUp(int button) {
setCtrlKeyDown(getCurrentInput().isControlKeyDown());
if (isInState(STATE_CONNECTION_STARTED))
handleCreateConnection();
setState(STATE_TERMINAL);
if (isInState(STATE_TERMINAL | STATE_INVALID)) {
handleFinished();
}
return true;
}
/**
* @see org.eclipse.gef.tools.AbstractTool#handleFinished() Called when the
* current tool operation is complete.
*/
protected void handleFinished() {
if (!isCtrlKeyDown()) {
super.handleFinished();
} else {
reactivate();
}
}
/**
* Method selectAddedObject. Select the newly added connection
*/
protected void selectAddedObject(EditPartViewer viewer, Collection objects) {
final List editparts = new ArrayList();
final EditPart[] primaryEP = new EditPart[1];
for (Iterator i = objects.iterator(); i.hasNext();) {
Object object = i.next();
if (object instanceof IAdaptable) {
Object editPart = viewer.getEditPartRegistry().get(
((IAdaptable) object).getAdapter(View.class));
if (editPart instanceof IPrimaryEditPart) {
editparts.add(editPart);
}
// Priority is to put a shape into direct edit mode.
if (editPart instanceof ShapeEditPart) {
primaryEP[0] = (ShapeEditPart) editPart;
}
}
}
if (!editparts.isEmpty()) {
viewer.setSelection(new StructuredSelection(editparts));
// automatically put the first shape into edit-mode
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
if (primaryEP[0] == null) {
primaryEP[0] = (EditPart) editparts.get(0);
}
//
// add active test since test scripts are failing on this
// basically, the editpart has been deleted when this
// code is being executed. (see RATLC00527114)
if (primaryEP[0].isActive()) {
primaryEP[0].performRequest(new Request(
RequestConstants.REQ_DIRECT_EDIT));
}
}
});
}
}
/**
* Handles double click to create the shape in defualt position
*
* @see org.eclipse.gef.tools.AbstractTool#handleDoubleClick(int)
*/
protected boolean handleDoubleClick(int button) {
createConnection();
return true;
}
/**
* Creates a connection between the two select shapes. edit parts.
*/
protected void createConnection() {
List selectedEditParts = getCurrentViewer().getSelectedEditParts();
// only attempt to create connection if there are two shapes selected
if (!selectedEditParts.isEmpty()) {
IGraphicalEditPart sourceEditPart = (IGraphicalEditPart) selectedEditParts
.get(0);
IGraphicalEditPart targetEditPart = selectedEditParts.size() == 2 ? (IGraphicalEditPart) selectedEditParts
.get(1)
: sourceEditPart;
CreateConnectionRequest connectionRequest = (CreateConnectionRequest) createTargetRequest();
connectionRequest.setTargetEditPart(sourceEditPart);
connectionRequest.setType(RequestConstants.REQ_CONNECTION_START);
connectionRequest.setLocation(new Point(0, 0));
// only if the connection is supported will we get a non null
// command from the sourceEditPart
if (sourceEditPart.getCommand(connectionRequest) != null) {
connectionRequest.setSourceEditPart(sourceEditPart);
connectionRequest.setTargetEditPart(targetEditPart);
connectionRequest.setType(RequestConstants.REQ_CONNECTION_END);
connectionRequest.setLocation(new Point(0, 0));
Command command = targetEditPart.getCommand(connectionRequest);
if (command != null) {
setCurrentCommand(command);
executeCurrentCommand();
selectAddedObject(getCurrentViewer(), DiagramCommandStack
.getReturnValues(command));
}
}
deactivate();
}
}
/**
* Overide to handle use case when the user has selected a tool and then
* click on the enter key which translated to SWT.Selection it will result
* in the new shape being created
*
* @see org.eclipse.gef.tools.AbstractTool#handleKeyUp(org.eclipse.swt.events.KeyEvent)
*/
protected boolean handleKeyUp(KeyEvent e) {
if (e.keyCode == SWT.Selection) {
setEditDomain(getCurrentViewer().getEditDomain());
createConnection();
return true;
}
return false;
}
/**
* Overridden so that the tool doesn't get deactivated and the feedback
* erased if popup dialogs appear to complete the command.
*
* @see org.eclipse.gef.tools.AbstractConnectionCreationTool#handleCreateConnection()
*/
protected boolean handleCreateConnection() {
// When a connection is to be created, a dialog box may appear which
// will cause this tool to be deactivated and the feedback to be
// erased. This behavior is overridden by setting the avoid
// deactivation flag.
setAvoidDeactivation(true);
EditPartViewer viewer = getCurrentViewer();
Command endCommand = getCommand();
setCurrentCommand(endCommand);
executeCurrentCommand();
selectAddedObject(viewer, DiagramCommandStack
.getReturnValues(endCommand));
setAvoidDeactivation(false);
eraseSourceFeedback();
deactivate();
return true;
}
/**
* Should deactivation be avoided?
*
* @return true if deactivation is to be avoided
*/
protected boolean avoidDeactivation() {
return avoidDeactivation;
}
/**
* Sets if deactivation be temporarily avoided.
*
* @param avoidDeactivation
* true if deactivation is to be avoided
*/
protected void setAvoidDeactivation(boolean avoidDeactivation) {
this.avoidDeactivation = avoidDeactivation;
}
/**
* @return Returns the isCtrlKeyDown.
*/
protected boolean isCtrlKeyDown() {
return isCtrlKeyDown;
}
/**
* @param isCtrlKeyDown
* The isCtrlKeyDown to set.
*/
protected void setCtrlKeyDown(boolean isCtrlKeyDown) {
this.isCtrlKeyDown = isCtrlKeyDown;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.tools.CreationTool#handleMove()
*/
protected boolean handleMove() {
boolean bool = super.handleMove();
if (isInState(STATE_CONNECTION_STARTED)) {
// Expose the diagram as the user scrolls in the area handled by the
// autoexpose helper.
updateAutoexposeHelper();
}
return bool;
}
/* (non-Javadoc)
* @see org.eclipse.gef.tools.AbstractConnectionCreationTool#calculateCursor()
*/
protected Cursor calculateCursor() {
if (isInState(STATE_CONNECTION_STARTED)) {
// Give some feedback so the user knows the area where autoscrolling
// will occur.
if (getAutoexposeHelper() != null) {
return SharedCursors.HAND;
} else {
// Give some feedback so the user knows that they can't drag
// outside the viewport.
if (getCurrentViewer() != null) {
Control control = getCurrentViewer().getControl();
if (control instanceof FigureCanvas) {
Viewport viewport = ((FigureCanvas) control)
.getViewport();
Rectangle rect = Rectangle.SINGLETON;
viewport.getClientArea(rect);
viewport.translateToParent(rect);
viewport.translateToAbsolute(rect);
if (!rect.contains(getLocation())) {
return getDisabledCursor();
}
}
}
}
}
Command command = getCurrentCommand();
if (command != null && command.canExecute())
{
EditPart ep = getTargetEditPart();
if (ep instanceof DiagramEditPart || ep instanceof CompartmentEditPart)
return CURSOR_TARGET_MENU;
}
return super.calculateCursor();
}
}