/* * Copyright 2017 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.client.canvas.command; import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvasHandler; import org.kie.workbench.common.stunner.core.client.command.CanvasCommandResultBuilder; import org.kie.workbench.common.stunner.core.client.command.CanvasViolation; import org.kie.workbench.common.stunner.core.client.command.HasGraphCommand; import org.kie.workbench.common.stunner.core.command.Command; import org.kie.workbench.common.stunner.core.command.CommandResult; import org.kie.workbench.common.stunner.core.command.util.CommandUtils; import org.kie.workbench.common.stunner.core.graph.Edge; 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.rule.RuleViolation; /** * Base type for commands which update both graph status/structure and canvas. */ public abstract class AbstractCanvasGraphCommand extends AbstractCanvasCommand implements HasGraphCommand<AbstractCanvasHandler> { /** * The private instance of the graph command. * It's a private stateful command instance - will be used for undoing the operation on the graph. */ private Command<GraphCommandExecutionContext, RuleViolation> graphCommand; /** * The private instance of the canvas command. * It's a private stateful command instance - will be used for undoing the operation on the graph. */ private Command<AbstractCanvasHandler, CanvasViolation> canvasCommand; /** * Creates a new command instance for the graph context. */ protected abstract Command<GraphCommandExecutionContext, RuleViolation> newGraphCommand(final AbstractCanvasHandler context); /** * Creates a new command instance for the canvas context. */ protected abstract Command<AbstractCanvasHandler, CanvasViolation> newCanvasCommand(final AbstractCanvasHandler context); @Override public Command<GraphCommandExecutionContext, RuleViolation> getGraphCommand(final AbstractCanvasHandler context) { if (null == graphCommand) { graphCommand = newGraphCommand(context); } return graphCommand; } public Command<AbstractCanvasHandler, CanvasViolation> getCanvasCommand(final AbstractCanvasHandler context) { if (null == canvasCommand) { canvasCommand = newCanvasCommand(context); } return canvasCommand; } @Override public CommandResult<CanvasViolation> allow(final AbstractCanvasHandler context) { final CommandResult<CanvasViolation> canvasResult = performOperationOnGraph(context, CommandOperation.ALLOW); if (canDoCanvasOperation(canvasResult)) { return getCanvasCommand(context).allow(context); } return canvasResult; } @Override public CommandResult<CanvasViolation> execute(final AbstractCanvasHandler context) { final CommandResult<CanvasViolation> canvasResult = performOperationOnGraph(context, CommandOperation.EXECUTE); if (canDoCanvasOperation(canvasResult)) { return getCanvasCommand(context).execute(context); } return canvasResult; } @Override public CommandResult<CanvasViolation> undo(final AbstractCanvasHandler context) { final CommandResult<CanvasViolation> canvasResult = performOperationOnGraph(context, CommandOperation.UNDO); if (canDoCanvasOperation(canvasResult)) { return getCanvasCommand(context).undo(context); } return canvasResult; } @SuppressWarnings("unchecked") protected Node<?, Edge> getNode(final AbstractCanvasHandler context, final String uuid) { return context.getGraphIndex().getNode(uuid); } private enum CommandOperation { ALLOW, EXECUTE, UNDO } private CommandResult<CanvasViolation> performOperationOnGraph(final AbstractCanvasHandler context, final CommandOperation op) { // Ensure the canvas command is initialized before updating the element on the graph side. getCanvasCommand(context); // Obtain the graph execution context and execute the graph command updates. final GraphCommandExecutionContext graphContext = context.getGraphExecutionContext(); if (null != graphContext) { final Command<GraphCommandExecutionContext, RuleViolation> graphCommand = getGraphCommand(context); CommandResult<RuleViolation> graphResult = null; switch (op) { case ALLOW: graphResult = graphCommand.allow(graphContext); break; case EXECUTE: graphResult = graphCommand.execute(graphContext); break; case UNDO: graphResult = graphCommand.undo(graphContext); break; } return new CanvasCommandResultBuilder(graphResult).build(); } return null; } private boolean canDoCanvasOperation(CommandResult<CanvasViolation> result) { return null == result || !CommandUtils.isError(result); } @Override public String toString() { return "[" + this.getClass().getName() + "]" + " [canvasCommand=" + (null != canvasCommand ? canvasCommand.toString() : "null") + " [graphCommand=" + (null != graphCommand ? graphCommand.toString() : null) + "]"; } }