blob: c3d0b27687519d78c90898263a3e71fd284c5a72 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
* 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:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.diagram.ui.graphical.edit.policies;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.commands.UnexecutableCommand;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager;
import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException;
import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterSiriusVariables;
import org.eclipse.sirius.common.tools.api.util.StringUtil;
import org.eclipse.sirius.common.tools.api.util.TreeItemWrapper;
import org.eclipse.sirius.diagram.DDiagram;
import org.eclipse.sirius.diagram.DDiagramElementContainer;
import org.eclipse.sirius.diagram.DNode;
import org.eclipse.sirius.diagram.business.api.query.ContainerCreationDescriptionQuery;
import org.eclipse.sirius.diagram.business.api.query.NodeCreationDescriptionQuery;
import org.eclipse.sirius.diagram.description.tool.ContainerCreationDescription;
import org.eclipse.sirius.diagram.description.tool.NodeCreationDescription;
import org.eclipse.sirius.diagram.description.tool.RequestDescription;
import org.eclipse.sirius.diagram.tools.api.command.IDiagramCommandFactory;
import org.eclipse.sirius.diagram.ui.business.api.view.SiriusLayoutDataManager;
import org.eclipse.sirius.diagram.ui.business.internal.view.RootLayoutData;
import org.eclipse.sirius.diagram.ui.internal.edit.parts.DDiagramEditPart;
import org.eclipse.sirius.diagram.ui.tools.api.command.GMFCommandWrapper;
import org.eclipse.sirius.diagram.ui.tools.api.requests.RequestConstants;
import org.eclipse.sirius.diagram.ui.tools.internal.commands.emf.AbstractSelectionWizardCommand;
import org.eclipse.sirius.diagram.ui.tools.internal.commands.emf.PaneBasedSelectionWizardCommand;
import org.eclipse.sirius.diagram.ui.tools.internal.commands.emf.SelectionWizardCommand;
import org.eclipse.sirius.viewpoint.DSemanticDecorator;
import org.eclipse.sirius.viewpoint.SiriusPlugin;
import org.eclipse.sirius.viewpoint.description.tool.PaneBasedSelectionWizardDescription;
import org.eclipse.sirius.viewpoint.description.tool.SelectionWizardDescription;
import org.eclipse.sirius.viewpoint.description.tool.ToolDescription;
import org.eclipse.sirius.viewpoint.description.tool.ToolPackage;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
/**
* Useful operations for {@link NodeCreationEditPolicy} and
* {@link ContainerCreationEditPolicy}.
*
* @author ymortier
*/
public class CreationUtil {
/** The location of the clicked point. */
private final Point realLocation;
/** The computed size of the element to create. */
private final Dimension realSize;
/** The EMF Command Factory. */
private final IDiagramCommandFactory emfCommandFactory;
/** The request. */
private final CreateRequest request;
/** The edit part. */
private final EditPart editPart;
/**
* Creates a new <code>CreationUtil</code> with the specified request and
* location.
*
* @param request
* the request.
* @param commandFactory
* the emf command factory.
* @param realLocation
* the location of the clicked point.
* @param editPart
* the edit part
* @since 0.9.0
*/
public CreationUtil(final CreateRequest request, final IDiagramCommandFactory commandFactory, final Point realLocation, final EditPart editPart) {
this.realLocation = realLocation;
this.realSize = null;
this.request = request;
this.emfCommandFactory = commandFactory;
this.editPart = editPart;
}
/**
* Creates a new <code>CreationUtil</code> with the specified request and
* location.
*
* @param request
* the request.
* @param commandFactory
* the emf command factory.
* @param realLocation
* the location of the clicked point.
* @param realSize
* the computed size of the element to create, null if the
* default size must be used
* @param editPart
* the edit part
* @since 0.9.0
*/
public CreationUtil(final CreateRequest request, final IDiagramCommandFactory commandFactory, final Point realLocation, final Dimension realSize, final EditPart editPart) {
this.realLocation = realLocation;
this.realSize = realSize;
this.request = request;
this.emfCommandFactory = commandFactory;
this.editPart = editPart;
}
/**
* Returns a command that is able to create a node in the specified
* container with the specified tool.
*
* @param container
* the container.
* @param tool
* the node creation description tool.
* @return a command that is able to create a node in the specified
* container with the specified tool.
*/
public Command getNodeCreationCommand(final DDiagramElementContainer container, final NodeCreationDescription tool) {
if (new NodeCreationDescriptionQuery(tool).canCreateIn(container)) {
final org.eclipse.emf.common.command.Command command = emfCommandFactory.buildCreateNodeCommandFromTool(container, tool);
final CompoundCommand compoundCommand = new CompoundCommand(tool.getName());
compoundCommand.add(createLayoutDataCommand(Predicates.<EditPart> alwaysTrue()));
compoundCommand.add(new ICommandProxy(new GMFCommandWrapper(getEditingDomain(), command)));
return compoundCommand;
}
return null;
}
/**
* Returns a command that is able to create a node in the specified node
* with the specified tool.
*
* @param node
* the node.
* @param tool
* the node creation description tool.
* @return a command that is able to create a node in the specified node
* with the specified tool.
*/
public Command getNodeCreationCommand(final DNode node, final NodeCreationDescription tool) {
if (new NodeCreationDescriptionQuery(tool).canCreateIn(node)) {
final CompoundCommand compoundCommand = new CompoundCommand(tool.getName());
compoundCommand.add(createLayoutDataCommand(Predicates.<EditPart> alwaysTrue()));
final org.eclipse.emf.common.command.Command command = emfCommandFactory.buildCreateNodeCommandFromTool(node, tool);
compoundCommand.add(new ICommandProxy(new GMFCommandWrapper(getEditingDomain(), command)));
return compoundCommand;
}
return null;
}
/**
* Returns a command that is able to create a node in the specified
* viewpoint with the specified tool.
*
* @param diagram
* the diagram.
* @param tool
* the node creation description tool.
* @return a command that is able to create a node in the specified
* viewpoint with the specified tool.
*/
public Command getNodeCreationCommand(final DDiagram diagram, final NodeCreationDescription tool) {
if (new NodeCreationDescriptionQuery(tool).canCreateIn(diagram)) {
final org.eclipse.emf.common.command.Command command = emfCommandFactory.buildCreateNodeCommandFromTool(diagram, tool);
final CompoundCommand compoundCommand = new CompoundCommand(tool.getName());
compoundCommand.add(createLayoutDataCommand(Predicates.<EditPart> alwaysTrue()));
compoundCommand.add(new ICommandProxy(new GMFCommandWrapper(getEditingDomain(), command)));
return compoundCommand;
}
return null;
}
/**
* Returns a command that is able to create a container in the specified
* container with the specified tool.
*
* @param viewNodeContainer
* the container
* @param ccdTool
* the container creation description tool.
* @return a command that is able to create a container in the specified
* container with the specified tool.
*/
public Command getContainerCreationDescription(final DDiagramElementContainer viewNodeContainer, final ContainerCreationDescription ccdTool) {
if (new ContainerCreationDescriptionQuery(ccdTool).canCreateIn(viewNodeContainer)) {
final org.eclipse.emf.common.command.Command command = emfCommandFactory.buildCreateContainerCommandFromTool(viewNodeContainer, ccdTool);
final CompoundCommand compoundCommand = new CompoundCommand(ccdTool.getName());
compoundCommand.add(createLayoutDataCommand(Predicates.<EditPart> alwaysTrue()));
compoundCommand.add(new ICommandProxy(new GMFCommandWrapper(getEditingDomain(), command)));
return compoundCommand;
}
return null;
}
/**
* Returns a command that is able to create a container in the specified
* viewpoint with the specified tool.
*
* @param diagram
* the diagram.
* @param ccdTool
* the container creation description tool.
* @return a command that is able to create a container in the specified
* viewpoint with the specified tool.
*/
public Command getContainerCreationDescription(final DDiagram diagram, final ContainerCreationDescription ccdTool) {
// if (container instanceof DiagramDescription) {
if (new ContainerCreationDescriptionQuery(ccdTool).canCreateIn(diagram)) {
final org.eclipse.emf.common.command.Command command = emfCommandFactory.buildCreateContainerCommandFromTool(diagram, ccdTool);
final CompoundCommand compoundCommand = new CompoundCommand(ccdTool.getName());
compoundCommand.add(createLayoutDataCommand(Predicates.<EditPart> alwaysTrue()));
compoundCommand.add(new ICommandProxy(new GMFCommandWrapper(getEditingDomain(), command)));
return compoundCommand;
}
return null;
}
/**
* Returns a command that is able to launch a wizard tool.
*
* @param selectionTool
* the wizard description.
* @param containerView
* the container view.
* @return a command that is able to launch a wizard tool.
*/
public Command getSelectionWizardCommand(final SelectionWizardDescription selectionTool, final EObject containerView) {
Command cmd = UnexecutableCommand.INSTANCE;
if (containerView != null) {
final CompoundCommand compoundCommand = new CompoundCommand(selectionTool.getName());
final TreeItemWrapper input = new TreeItemWrapper(null, null);
if (AbstractSelectionWizardCommand.canCreateCommand(selectionTool, containerView, input)) {
compoundCommand.add(createLayoutDataCommand(Predicates.<EditPart> alwaysTrue()));
compoundCommand.add(new ICommandProxy(
new GMFCommandWrapper(getEditingDomain(), new SelectionWizardCommand(emfCommandFactory, selectionTool, input, (DSemanticDecorator) containerView))));
cmd = compoundCommand;
cmd.setLabel(selectionTool.getName());
}
}
return cmd;
}
/**
* Returns a command that is able to launch a wizard tool.
*
* @param selectionTool
* the wizard description.
* @param containerView
* the container view.
* @return a command that is able to launch a wizard tool.
*/
public Command getPaneBasedSelectionWizardCommand(final PaneBasedSelectionWizardDescription selectionTool, final EObject containerView) {
Command cmd = UnexecutableCommand.INSTANCE;
if (containerView != null) {
final CompoundCommand compoundCommand = new CompoundCommand(selectionTool.getName());
final TreeItemWrapper input = new TreeItemWrapper(null, null);
if (AbstractSelectionWizardCommand.canCreateCommand(selectionTool, containerView, input)) {
compoundCommand.add(createLayoutDataCommand(Predicates.<EditPart> alwaysTrue()));
compoundCommand.add(new ICommandProxy(new GMFCommandWrapper(getEditingDomain(), new PaneBasedSelectionWizardCommand(emfCommandFactory, selectionTool, input,
(DSemanticDecorator) containerView))));
cmd = compoundCommand;
cmd.setLabel(selectionTool.getName());
}
}
return cmd;
}
private TransactionalEditingDomain getEditingDomain() {
if (editPart instanceof IGraphicalEditPart) {
return ((IGraphicalEditPart) editPart).getEditingDomain();
}
return null;
}
/**
* Returns a command that is able to launch an user request.
*
* @param requestDescription
* the request description tool.
* @param host
* the host.
* @return a command that is able to launch an user request.
*/
public Command getRequestToolCommand(final RequestDescription requestDescription, final EditPart host) {
final Request req = new Request();
req.setType(requestDescription.getType());
//
// Check the precondition.
if (requestDescription.getPrecondition() != null && !StringUtil.isEmpty(requestDescription.getPrecondition()) && host instanceof IGraphicalEditPart) {
EObject semantic = ((IGraphicalEditPart) host).resolveSemanticElement();
if (semantic instanceof DSemanticDecorator) {
semantic = ((DSemanticDecorator) semantic).getTarget();
}
boolean valid = false;
final IInterpreter acceleoInterpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(semantic);
acceleoInterpreter.setVariable(IInterpreterSiriusVariables.CONTAINER, semantic);
try {
valid = acceleoInterpreter.evaluateBoolean(semantic, requestDescription.getPrecondition());
} catch (final EvaluationException e) {
RuntimeLoggerManager.INSTANCE.error(requestDescription, ToolPackage.eINSTANCE.getAbstractToolDescription_Precondition(), e);
}
acceleoInterpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER);
if (!valid) {
return null; // the precondition is not checked.
}
}
// wrap the command because the command will start the
// wizard in its creation
// see FunctionalChainElementsCreationEditPolicy
final Command cmd = new RequestToolCommand(req, requestDescription, host);
return cmd;
}
/**
* Returns <code>true</code> if a node can be created on the container with
* the specified tool. Returns a command that is able to execute a generic
* {@link ToolDescription}.
*
* @param containerView
* the view element on which the tool has been invoked.
* @param toolDesc
* the tool to invoke.
* @return a command which executes the specified {@link ToolDescription} in
* the context of the view element.
*/
public Command getGenericToolCommand(final EObject containerView, final ToolDescription toolDesc) {
final CompoundCommand compoundCommand = new CompoundCommand(toolDesc.getName());
final org.eclipse.emf.common.command.Command command = emfCommandFactory.buildGenericToolCommandFromTool(containerView, toolDesc);
compoundCommand.add(createLayoutDataCommand(Predicates.<EditPart> alwaysTrue()));
compoundCommand.add(new ICommandProxy(new GMFCommandWrapper(getEditingDomain(), command)));
return compoundCommand;
}
private Command createLayoutDataCommand(final Predicate<EditPart> pred) {
return new Command() {
@Override
public void execute() {
if (pred != null && pred.apply(editPart)) {
// The size of the request take into account the zoom (got
// the size in 100%)
Dimension size = null;
if (realSize != null) {
size = realSize.getCopy();
} else {
size = adaptRequestSizeToZoomFactor();
}
SiriusLayoutDataManager.INSTANCE.addData(new RootLayoutData(editPart, realLocation.getCopy(), size));
}
}
};
}
/**
* Transform the size depending the zoom factor.
*
* @return A new dimension
*/
private Dimension adaptRequestSizeToZoomFactor() {
if (request.getSize() == null) {
return null;
}
final Dimension dimension = request.getSize().getCopy();
// The size of the request take into account the zoom (got
// the size in 100%)
double scale = 1.0;
if (editPart.getRoot() instanceof DiagramRootEditPart) {
final ZoomManager zoomManager = ((DiagramRootEditPart) editPart.getRoot()).getZoomManager();
scale = zoomManager.getZoom();
}
dimension.performScale(1 / scale);
return dimension;
}
/**
* A command that handle a RequestTool.
*
* @author Obeo</a>
*/
private static class RequestToolCommand extends Command {
private Command wrappedCmd;
private final EditPart host;
private final RequestDescription requestDescription;
private final Request req;
/**
* Constructor.
*
* @param req
* the request
* @param desc
* teh request description
* @param host
* the graphical edit part
*/
RequestToolCommand(final Request req, final RequestDescription desc, final EditPart host) {
super(desc.getName());
this.req = req;
this.requestDescription = desc;
this.host = host;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.gef.commands.Command#execute()
*/
@Override
public void execute() {
wrappedCmd = host.getCommand(req);
final CompoundCommand cc = new CompoundCommand();
cc.add(wrappedCmd);
if (requestDescription.isForceRefresh()) {
final Command refresh = this.getRefreshSiriusCommand();
if (refresh != null) {
cc.add(refresh);
}
}
wrappedCmd = cc;
if (wrappedCmd != null && wrappedCmd.canExecute()) {
wrappedCmd.execute();
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.gef.commands.Command#canUndo()
*/
@Override
public boolean canUndo() {
if (wrappedCmd != null) {
return wrappedCmd.canUndo();
}
return false;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.gef.commands.Command#undo()
*/
@Override
public void undo() {
if (wrappedCmd != null) {
wrappedCmd.undo();
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.gef.commands.Command#redo()
*/
@Override
public void redo() {
if (wrappedCmd != null) {
wrappedCmd.redo();
}
}
/**
* Return the command that refreshes the viewpoint.
*
* @return the command that refreshes the viewpoint.
*/
private Command getRefreshSiriusCommand() {
EditPart current = host;
while (!(current instanceof DDiagramEditPart) && current != null) {
current = current.getParent();
}
if (current != null) {
final Request requ = new Request(RequestConstants.REQ_REFRESH_VIEWPOINT);
return current.getCommand(requ);
} else {
return null;
}
}
}
}