blob: f205623f9c621b395f05fa2abf2c29bc08b1dc38 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002, 2020 IBM Corporation and others.
* 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
* Obeo - Adaptations.
*******************************************************************************/
package org.eclipse.sirius.diagram.ui.graphical.edit.policies;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.eclipse.core.runtime.IAdaptable;
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.UnexecutableCommand;
import org.eclipse.gef.requests.GroupRequest;
import org.eclipse.gmf.runtime.common.core.util.ObjectAdapter;
import org.eclipse.gmf.runtime.common.core.util.StringStatics;
import org.eclipse.gmf.runtime.diagram.ui.actions.ActionIds;
import org.eclipse.gmf.runtime.diagram.ui.commands.ArrangeCommand;
import org.eclipse.gmf.runtime.diagram.ui.commands.CommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.commands.DeferredLayoutCommand;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.ContainerEditPolicy;
import org.eclipse.gmf.runtime.diagram.ui.internal.properties.WorkspaceViewerProperties;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramGraphicalViewer;
import org.eclipse.gmf.runtime.diagram.ui.requests.ArrangeRequest;
import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
import org.eclipse.gmf.runtime.diagram.ui.services.layout.LayoutType;
import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractDiagramElementContainerEditPart;
import org.eclipse.sirius.diagram.ui.internal.edit.commands.CenterEdgeLayoutCommand;
import org.eclipse.sirius.diagram.ui.internal.edit.commands.DistributeCommand;
import org.eclipse.sirius.diagram.ui.internal.layout.GenericLayoutProvider;
import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider;
import org.eclipse.sirius.diagram.ui.tools.api.requests.DistributeRequest;
import org.eclipse.sirius.diagram.ui.tools.internal.commands.SnapCommand;
import org.eclipse.sirius.diagram.ui.tools.internal.layout.provider.LayoutService;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
/**
* A specific class to override the arrangeCommand to handles edge centering, snapping, ...<BR>
* This class launches the arrange even for one element.
*
* @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
*
*/
@SuppressWarnings("restriction")
public class SiriusContainerEditPolicy extends ContainerEditPolicy {
private final Predicate<Object> isRegionEditPart = new Predicate<Object>() {
@Override
public boolean apply(Object input) {
return input instanceof AbstractDiagramElementContainerEditPart && ((AbstractDiagramElementContainerEditPart) input).isRegion();
}
};
@Override
public Command getCommand(Request request) {
if (org.eclipse.sirius.diagram.ui.tools.api.requests.RequestConstants.REQ_DISTRIBUTE.equals(request.getType())) {
return getDistributeCommand((DistributeRequest) request);
}
return super.getCommand(request);
}
// CHECKSTYLE:OFF
@SuppressWarnings("unchecked")
@Override
protected Command getArrangeCommand(ArrangeRequest request) {
if ((ActionIds.ACTION_ARRANGE_SELECTION.equals(request.getType())) || (ActionIds.ACTION_TOOLBAR_ARRANGE_SELECTION.equals(request.getType()))) {
if (Iterables.any(request.getPartsToArrange(), isRegionEditPart)) {
return UnexecutableCommand.INSTANCE;
}
}
Command commandToReturn = doDuplicatedGetArrangeCommand(request);
// We add a Command to center edges that need to be at the end of the
// layout.
if (commandToReturn != null) {
EditPart host = getHost();
if (host instanceof GraphicalEditPart) {
CenterEdgeLayoutCommand centerEdgeLayoutCommand = new CenterEdgeLayoutCommand((GraphicalEditPart) host);
commandToReturn = commandToReturn.chain(new ICommandProxy(centerEdgeLayoutCommand));
}
}
return commandToReturn;
}
/**
* Duplicated from
* org.eclipse.gmf.runtime.diagram.ui.editpolicies.ContainerEditPolicy.getArrangeCommand(ArrangeRequest) to override
* the SnapCommand.
*
* @param request
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private Command doDuplicatedGetArrangeCommand(ArrangeRequest request) {
if (RequestConstants.REQ_ARRANGE_DEFERRED.equals(request.getType())) {
String layoutType = request.getLayoutType();
TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain();
return new ICommandProxy(new DeferredLayoutCommand(editingDomain, request.getViewAdaptersToArrange(), (IGraphicalEditPart) getHost(), layoutType));
}
String layoutDesc = request.getLayoutType() != null ? request.getLayoutType() : LayoutType.DEFAULT;
boolean offsetFromBoundingBox = false;
List<IGraphicalEditPart> editparts = new ArrayList<IGraphicalEditPart>();
if ((ActionIds.ACTION_ARRANGE_ALL.equals(request.getType())) || (ActionIds.ACTION_TOOLBAR_ARRANGE_ALL.equals(request.getType()))) {
editparts = ((IGraphicalEditPart) getHost()).getChildren();
request.setPartsToArrange(editparts);
}
if ((ActionIds.ACTION_ARRANGE_SELECTION.equals(request.getType())) || (ActionIds.ACTION_TOOLBAR_ARRANGE_SELECTION.equals(request.getType()))) {
editparts = request.getPartsToArrange();
offsetFromBoundingBox = true;
}
if (RequestConstants.REQ_ARRANGE_RADIAL.equals(request.getType())) {
editparts = request.getPartsToArrange();
offsetFromBoundingBox = true;
layoutDesc = LayoutType.RADIAL;
}
if (editparts.isEmpty())
return null;
List hints = new ArrayList(2);
hints.add(layoutDesc);
hints.add(getHost());
IAdaptable layoutHint = new ObjectAdapter(hints);
TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain();
CompositeTransactionalCommand ctc = new CompositeTransactionalCommand(editingDomain, StringStatics.BLANK);
ctc.add(new ArrangeCommand(editingDomain, StringStatics.BLANK, null, editparts, layoutHint, offsetFromBoundingBox));
// retrieves the preference store from the first edit part
IGraphicalEditPart firstEditPart = editparts.get(0);
if (firstEditPart.getViewer() instanceof DiagramGraphicalViewer) {
IPreferenceStore preferenceStore = ((DiagramGraphicalViewer) firstEditPart.getViewer()).getWorkspaceViewerPreferenceStore();
if (preferenceStore != null && preferenceStore.getBoolean(WorkspaceViewerProperties.SNAPTOGRID)) {
Command snapCmd = getSnapCommand(request);
if (snapCmd != null) {
ctc.add(new CommandProxy(getSnapCommand(request)));
}
}
}
return new ICommandProxy(ctc);
}
/**
* Duplicates method from {@link org.eclipse.gmf.runtime.diagram.ui.editpolicies.ContainerEditPolicy} for the
* duplication of getArrangeCommand.
*
* @param request
* The current request.
* @return A command to snap the edit parts of the request.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private Command getSnapCommand(Request request) {
List editparts = null;
if (request instanceof GroupRequest) {
editparts = ((GroupRequest) request).getEditParts();
} else if (request instanceof ArrangeRequest) {
editparts = ((ArrangeRequest) request).getPartsToArrange();
}
TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost()).getEditingDomain();
if (editparts != null && shouldLaunchSnapTo(editparts)) {
return new ICommandProxy(new SnapCommand(editingDomain, editparts));
}
return null;
}
private boolean shouldLaunchSnapTo(List<? extends IGraphicalEditPart> editparts) {
Optional<? extends IGraphicalEditPart> optionalFirstEditPart = editparts.stream().findFirst();
if (optionalFirstEditPart.isPresent()) {
LayoutProvider layoutProvider = LayoutService.getProvider(optionalFirstEditPart.get());
if (layoutProvider instanceof GenericLayoutProvider) {
return ((GenericLayoutProvider) layoutProvider).shouldLaunchSnapTo(optionalFirstEditPart.get());
}
}
return true;
}
// CHECKSTYLE:ON
/**
* Gets a distribute command.
*
* @param request
* The distribute request
* @return command
*/
protected Command getDistributeCommand(DistributeRequest request) {
List<IGraphicalEditPart> editparts = request.getEditParts();
if (!editparts.isEmpty() && getHost() instanceof IGraphicalEditPart) {
return new ICommandProxy(new DistributeCommand(((IGraphicalEditPart) getHost()).getEditingDomain(), editparts, request.getDistributeType()));
}
return null;
}
}