/* * 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.client.canvas.controls.toolbox.command.builder; import java.util.logging.Level; import java.util.logging.Logger; import com.google.gwt.logging.client.LogConfiguration; import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvas; import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvasHandler; import org.kie.workbench.common.stunner.core.client.canvas.controls.builder.BuildRequest; import org.kie.workbench.common.stunner.core.client.canvas.controls.builder.BuilderControl; import org.kie.workbench.common.stunner.core.client.canvas.controls.toolbox.command.AbstractToolboxCommand; import org.kie.workbench.common.stunner.core.client.canvas.controls.toolbox.command.Context; import org.kie.workbench.common.stunner.core.client.canvas.util.CanvasHighlight; import org.kie.workbench.common.stunner.core.client.components.drag.DragProxy; import org.kie.workbench.common.stunner.core.client.components.drag.DragProxyCallback; import org.kie.workbench.common.stunner.core.client.service.ClientFactoryService; import org.kie.workbench.common.stunner.core.client.service.ClientRuntimeError; import org.kie.workbench.common.stunner.core.client.service.ServiceCallback; import org.kie.workbench.common.stunner.core.graph.Element; import org.kie.workbench.common.stunner.core.graph.Node; import org.kie.workbench.common.stunner.core.graph.processing.index.bounds.GraphBoundsIndexer; import org.kie.workbench.common.stunner.core.util.UUID; import org.uberfire.mvp.Command; public abstract class AbstractBuilderCommand<I> extends AbstractToolboxCommand<I> { private static Logger LOGGER = Logger.getLogger(AbstractBuilderCommand.class.getName()); private final ClientFactoryService clientFactoryServices; private final GraphBoundsIndexer graphBoundsIndexer; private CanvasHighlight canvasHighlight; public AbstractBuilderCommand(final ClientFactoryService clientFactoryServices, final GraphBoundsIndexer graphBoundsIndexer) { this.clientFactoryServices = clientFactoryServices; this.graphBoundsIndexer = graphBoundsIndexer; } protected abstract String getDefinitionIdentifier(final Context<AbstractCanvasHandler> context); protected abstract DragProxy getDragProxyFactory(); protected abstract DragProxyCallback getDragProxyCallback(final Context<AbstractCanvasHandler> context, final Element element, final Element newElement); protected abstract BuilderControl getBuilderControl(); protected abstract Object createtBuilderControlItem(final Context<AbstractCanvasHandler> context, final Element source, final Element newElement); protected abstract boolean onDragProxyMove(final int x, final int y, final Element source, final Element newElement, final Node targetNode); protected abstract BuildRequest createBuildRequest(final int x, final int y, final Element source, final Element newElement, final Node targetNode); protected void onDefinitionInstanceBuilt(final Context<AbstractCanvasHandler> context, final Element source, final Element newElement, final Command callback) { callback.execute(); } @Override public void mouseDown(final Context<AbstractCanvasHandler> context, final Element element) { super.mouseDown(context, element); showDragProxy(context, element); } @Override public void click(final Context<AbstractCanvasHandler> context, final Element element) { super.click(context, element); } @SuppressWarnings("unchecked") private void showDragProxy(final Context<AbstractCanvasHandler> context, final Element element) { final AbstractCanvasHandler canvasHandler = context.getCanvasHandler(); final double x = context.getAbsoluteX(); final double y = context.getAbsoluteY(); graphBoundsIndexer.setRootUUID(canvasHandler.getDiagram().getMetadata().getCanvasRootUUID()); clientFactoryServices.newElement(UUID.uuid(), getDefinitionIdentifier(context), new ServiceCallback<Element>() { @Override public void onSuccess(final Element item) { onDefinitionInstanceBuilt(context, element, item, () -> { getBuilderControl().enable(canvasHandler); getBuilderControl().setCommandManagerProvider(context::getCommandManager); canvasHighlight = new CanvasHighlight(canvasHandler); graphBoundsIndexer.build(canvasHandler.getDiagram().getGraph()); DragProxyCallback proxyCallback = getDragProxyCallback(context, element, item); getDragProxyFactory().proxyFor(canvasHandler) .show( createtBuilderControlItem(context, element, item), (int) x, (int) y, proxyCallback ); }); } @Override public void onError(final ClientRuntimeError error) { AbstractBuilderCommand.this.onError(context, error); } }); } @SuppressWarnings("unchecked") protected void onStart(final Context<AbstractCanvasHandler> context, final Element element, final Element item, final int x1, final int y1) { } @SuppressWarnings("unchecked") protected void onMove(final Context<AbstractCanvasHandler> context, final Element element, final Element item, final int x1, final int y1) { // TODO: Two expensive calls to bounds indexer, this one and the one inside connectorDragProxyFactory. final Node targetNode = graphBoundsIndexer.getAt(x1, y1); final boolean accepts = onDragProxyMove(x1, y1, element, item, targetNode); canvasHighlight.unhighLight(); if (null != targetNode && accepts) { canvasHighlight.highLight(targetNode); } else if (null != targetNode) { canvasHighlight.invalid(targetNode); } } @SuppressWarnings("unchecked") protected void onComplete(final Context<AbstractCanvasHandler> context, final Element element, final Element item, final int x1, final int y1) { fireLoadingStarted(context); final Node targetNode = graphBoundsIndexer.getAt(x1, y1); log(Level.FINE, "Completing element creation - Creating node for parent [" + (null != targetNode ? targetNode.getUUID() : "null")); if (null != targetNode) { // Ensure back to NONE shape state before any further operations. ensureUnHighLight(); // Create the build request. final BuildRequest buildRequest = createBuildRequest(x1, y1, element, item, targetNode); // Use the builder control to perform the operation. getBuilderControl().build(buildRequest, new BuilderControl.BuildCallback() { @Override public void onSuccess(final String uuid) { log(Level.INFO, "Item build with UUID [" + uuid + "]"); onItemBuilt(context, uuid); getBuilderControl().setCommandManagerProvider(null); fireLoadingCompleted(context); } @Override public void onError(final ClientRuntimeError error) { AbstractBuilderCommand.this.onError(context, error); } }); } else { log(Level.FINE, "No candidate node found at [" + x1 + ", " + y1 + "]. Nothing to do."); } context.getCanvasHandler().getAbstractCanvas().getView().setCursor(AbstractCanvas.Cursors.AUTO); } protected void onError(final Context<AbstractCanvasHandler> context, final ClientRuntimeError error) { fireLoadingCompleted(context); LOGGER.log(Level.SEVERE, error.toString()); } protected void onItemBuilt(final Context<AbstractCanvasHandler> context, final String uuid) { // Nothing to do by default. } @Override @SuppressWarnings("unchecked") public void destroy() { this.getDragProxyFactory().destroy(); getBuilderControl().setCommandManagerProvider(null); this.getBuilderControl().disable(); this.graphBoundsIndexer.destroy(); if (null != canvasHighlight) { this.canvasHighlight.destroy(); this.canvasHighlight = null; } } protected ClientFactoryService getClientFactoryServices() { return clientFactoryServices; } protected GraphBoundsIndexer getGraphBoundsIndexer() { return graphBoundsIndexer; } private void ensureUnHighLight() { if (null != canvasHighlight) { canvasHighlight.unhighLight(); } } private void log(final Level level, final String message) { if (LogConfiguration.loggingIsEnabled()) { LOGGER.log(level, message); } } }