/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kie.workbench.common.stunner.core.graph.command.impl; import java.util.logging.Level; import java.util.logging.Logger; import org.jboss.errai.common.client.api.annotations.MapsTo; import org.jboss.errai.common.client.api.annotations.Portable; import org.kie.workbench.common.stunner.core.client.canvas.Point2D; import org.kie.workbench.common.stunner.core.command.CommandResult; import org.kie.workbench.common.stunner.core.graph.Edge; import org.kie.workbench.common.stunner.core.graph.Element; import org.kie.workbench.common.stunner.core.graph.Graph; import org.kie.workbench.common.stunner.core.graph.Node; import org.kie.workbench.common.stunner.core.graph.command.GraphCommandExecutionContext; import org.kie.workbench.common.stunner.core.graph.command.GraphCommandResultBuilder; import org.kie.workbench.common.stunner.core.graph.content.Bounds; import org.kie.workbench.common.stunner.core.graph.content.definition.DefinitionSet; import org.kie.workbench.common.stunner.core.graph.content.view.BoundImpl; import org.kie.workbench.common.stunner.core.graph.content.view.BoundsImpl; import org.kie.workbench.common.stunner.core.graph.content.view.View; import org.kie.workbench.common.stunner.core.graph.util.GraphUtils; import org.kie.workbench.common.stunner.core.rule.RuleViolation; import org.kie.workbench.common.stunner.core.rule.violations.BoundsExceededViolation; import org.uberfire.commons.validation.PortablePreconditions; /** * A Command to update an element's bounds. */ @Portable public final class UpdateElementPositionCommand extends AbstractGraphCommand { private static Logger LOGGER = Logger.getLogger(UpdateElementPositionCommand.class.getName()); private final String uuid; private final Double x; private final Double y; private Double oldX; private Double oldY; private transient Node<?, Edge> node; public UpdateElementPositionCommand(final @MapsTo("uuid") String uuid, final @MapsTo("x") Double x, final @MapsTo("y") Double y) { this.uuid = PortablePreconditions.checkNotNull("uuid", uuid); this.x = PortablePreconditions.checkNotNull("x", x); this.y = PortablePreconditions.checkNotNull("y", y); this.node = null; } public UpdateElementPositionCommand(final Node<?, Edge> node, final Double x, final Double y) { this(node.getUUID(), x, y); this.node = PortablePreconditions.checkNotNull("node", node); } public Double getX() { return x; } public Double getY() { return y; } public Node<?, Edge> getNode() { return node; } public Double getOldX() { return oldX; } public Double getOldY() { return oldY; } public String getUuid() { return uuid; } @Override @SuppressWarnings("unchecked") protected CommandResult<RuleViolation> check(final GraphCommandExecutionContext context) { return checkBounds(context); } @Override @SuppressWarnings("unchecked") public CommandResult<RuleViolation> execute(final GraphCommandExecutionContext context) { final BoundsImpl newBounds = getTargetBounds(checkNodeNotNull(context)); LOGGER.log(Level.FINE, "Moving element bounds to " + "[" + newBounds.getX() + "," + newBounds.getY() + "] " + "[" + newBounds.getWidth() + "," + newBounds.getHeight() + "]"); return checkBounds(context); } @SuppressWarnings("unchecked") private CommandResult<RuleViolation> checkBounds(final GraphCommandExecutionContext context) { final Element<?> element = checkNodeNotNull(context); final Graph<DefinitionSet, Node> graph = (Graph<DefinitionSet, Node>) getGraph(context); final BoundsImpl newBounds = getTargetBounds(element); final GraphCommandResultBuilder result = new GraphCommandResultBuilder(); if (checkBoundsExceeded(graph, newBounds)) { ((View) element.getContent()).setBounds(newBounds); } else { final Bounds graphBounds = graph.getContent().getBounds(); result.addViolation(new BoundsExceededViolation(graphBounds) .setUUID(element.getUUID())); } return result.build(); } @SuppressWarnings("unchecked") private BoundsImpl getTargetBounds(final Element<?> element) { final Point2D oldPosition = GraphUtils.getPosition((View) element.getContent()); final double[] oldSize = GraphUtils.getNodeSize((View) element.getContent()); this.oldX = oldPosition.getX(); this.oldY = oldPosition.getY(); final double w = oldSize[0]; final double h = oldSize[1]; return new BoundsImpl(new BoundImpl(x, y), new BoundImpl(x + w, y + h)); } @SuppressWarnings("unchecked") private boolean checkBoundsExceeded(final Graph<DefinitionSet, Node> graph, final Bounds bounds) { return GraphUtils.checkBoundsExceeded(graph, bounds); } @Override public CommandResult<RuleViolation> undo(final GraphCommandExecutionContext context) { final UpdateElementPositionCommand undoCommand = new UpdateElementPositionCommand(checkNodeNotNull(context), oldX, oldY); return undoCommand.execute(context); } private Node<?, Edge> checkNodeNotNull(final GraphCommandExecutionContext context) { if (null == node) { node = super.checkNodeNotNull(context, uuid); } return node; } @Override public String toString() { return "UpdateElementPositionCommand [element=" + uuid + ", x=" + x + ", y=" + y + "]"; } }