diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/canvas/controls/LocationControlImpl.java b/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/canvas/controls/LocationControlImpl.java index 4dc52d5eaa5..166d86a4fb0 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/canvas/controls/LocationControlImpl.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/canvas/controls/LocationControlImpl.java @@ -21,7 +21,6 @@ import java.util.Collection; import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -110,6 +109,10 @@ public LocationControlImpl(final CanvasCommandFactory can this.selectionEvent = selectionEvent; } + public Collection getSelectedIDs() { + return selectedIDs; + } + @Override public void bind(final EditorSession session) { // Keyboard event handling. @@ -125,8 +128,7 @@ private void onKeyDownEvent(final KeyboardEvent.Key... keys) { handleArrowKeys(keys); } - private void handleArrowKeys(final KeyboardEvent.Key... keys) { - + public void handleArrowKeys(final KeyboardEvent.Key... keys) { final int selectedIDsCount = selectedIDs.size(); if (selectedIDsCount == 0) { @@ -231,20 +233,16 @@ public void handle(MouseExitEvent event) { final DragHandler dragHandler = new DragHandler() { @Override public void start(DragEvent event) { - if (Objects.nonNull(selectionEvent)) { - //select the moving shape, if not - selectionEvent.fire(new CanvasSelectionEvent(canvasHandler, shape.getUUID())); - } + // Instead of firing the event on Drag start, now will be fired at the end, hence improving performance } @Override public void end(DragEvent event) { - + selectionEvent.fire(new CanvasSelectionEvent(canvasHandler, shape.getUUID())); } @Override public void handle(DragEvent event) { - } }; diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/drag/PrimitiveDragProxyImpl.java b/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/drag/PrimitiveDragProxyImpl.java index e4234d9e224..78c30e9b998 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/drag/PrimitiveDragProxyImpl.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/drag/PrimitiveDragProxyImpl.java @@ -50,7 +50,7 @@ public DragProxy, DragProxyCallback> show(final IPrimitive< item, x, y, - 200, + 1, new org.kie.workbench.common.stunner.lienzo.primitive.PrimitiveDragProxy.Callback() { @Override @@ -63,6 +63,7 @@ public void onStart(final int x, @Override public void onMove(final int x, final int y) { + callback.onMove(x, y); } diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/drag/ShapeViewDragProxyImpl.java b/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/drag/ShapeViewDragProxyImpl.java index 70c2e045111..6c11814a059 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/drag/ShapeViewDragProxyImpl.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/main/java/org/kie/workbench/common/stunner/client/lienzo/components/drag/ShapeViewDragProxyImpl.java @@ -72,21 +72,25 @@ public void onComplete(final int x, y); } }; + if (item instanceof WiresShape) { + final WiresShape wiresShape = (WiresShape) item; this.proxy = new WiresShapeDragProxy(getLayer().getLienzoLayer(), wiresShape, x, y, - 100, + 1, c); } else if (item instanceof WiresConnector) { + final WiresConnector wiresConnector = (WiresConnector) item; + this.proxy = new WiresConnectorDragProxy(getLayer().getLienzoLayer(), wiresConnector, x, y, - 100, + 1, c); } return this; diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/test/java/org/kie/workbench/common/stunner/client/lienzo/canvas/controls/LocationControlImplTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/test/java/org/kie/workbench/common/stunner/client/lienzo/canvas/controls/LocationControlImplTest.java index 51c47b8b348..33ee128f19b 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/test/java/org/kie/workbench/common/stunner/client/lienzo/canvas/controls/LocationControlImplTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-client/kie-wb-common-stunner-lienzo/src/test/java/org/kie/workbench/common/stunner/client/lienzo/canvas/controls/LocationControlImplTest.java @@ -50,6 +50,7 @@ import org.kie.workbench.common.stunner.core.client.command.CanvasCommandFactory; import org.kie.workbench.common.stunner.core.client.command.CanvasCommandFactoryStub; import org.kie.workbench.common.stunner.core.client.command.CanvasCommandManager; +import org.kie.workbench.common.stunner.core.client.event.keyboard.KeyboardEvent; import org.kie.workbench.common.stunner.core.client.shape.Shape; import org.kie.workbench.common.stunner.core.client.shape.ShapeViewExtStub; import org.kie.workbench.common.stunner.core.client.shape.view.HasControlPoints; @@ -141,6 +142,12 @@ public class LocationControlImplTest { @Mock private Node element; + @Mock + private Node, Edge> node; + + @Mock + private View nodeContent; + @Mock private View elementContent; @@ -234,6 +241,8 @@ public void testRegisterAndSetBounds() { ArgumentCaptor dragHandlerArgumentCaptor = forClass(DragHandler.class); verify(shapeEventHandler).addHandler(eq(ViewEventType.DRAG), dragHandlerArgumentCaptor.capture()); dragHandlerArgumentCaptor.getValue().start(mock(DragEvent.class)); + dragHandlerArgumentCaptor.getValue().end(mock(DragEvent.class)); + ArgumentCaptor canvasSelectionEventArgumentCaptor = forClass(CanvasSelectionEvent.class); verify(canvasSelectionEvent).fire(canvasSelectionEventArgumentCaptor.capture()); assertTrue(canvasSelectionEventArgumentCaptor.getValue().getIdentifiers().contains(element.getUUID())); @@ -327,6 +336,19 @@ public void testLocationAcceptor() { assertEquals(new Point2D(40d, 50d), updateElementPositionCommand.getLocation()); } + @Test + public void testHandleKeys() { + tested.init(canvasHandler); + tested.register(element); + + when (canvasHandler.getGraphIndex().getNode(any())).thenReturn(element); + + tested.getSelectedIDs().add(element.getUUID()); + tested.handleArrowKeys(KeyboardEvent.Key.ARROW_DOWN); + + verify(commandManager, atLeastOnce()).execute(any(), any()); + } + @Test public void testEnsureDragConstraints() throws Exception { tested.init(canvasHandler); diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-api/kie-wb-common-stunner-client-api/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/listener/CanvasElementListener.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-api/kie-wb-common-stunner-client-api/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/listener/CanvasElementListener.java index a73e17772a1..6007375c723 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-api/kie-wb-common-stunner-client-api/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/listener/CanvasElementListener.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-api/kie-wb-common-stunner-client-api/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/listener/CanvasElementListener.java @@ -16,6 +16,8 @@ package org.kie.workbench.common.stunner.core.client.canvas.listener; +import java.util.List; + import org.kie.workbench.common.stunner.core.client.canvas.CanvasHandler; import org.kie.workbench.common.stunner.core.graph.Element; @@ -26,4 +28,11 @@ public interface CanvasElementListener extends CanvasListener queue) { + } } diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-api/kie-wb-common-stunner-core-api/src/main/java/org/kie/workbench/common/stunner/core/preferences/StunnerPreferences.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-api/kie-wb-common-stunner-core-api/src/main/java/org/kie/workbench/common/stunner/core/preferences/StunnerPreferences.java index e8031669e39..663b6684e47 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-api/kie-wb-common-stunner-core-api/src/main/java/org/kie/workbench/common/stunner/core/preferences/StunnerPreferences.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-api/kie-wb-common-stunner-core-api/src/main/java/org/kie/workbench/common/stunner/core/preferences/StunnerPreferences.java @@ -31,7 +31,7 @@ public class StunnerPreferences implements BasePreference, @Override public StunnerPreferences defaultValue(final StunnerPreferences defaultValue) { defaultValue.diagramEditorPreferences.setAutoHidePalettePanel(false); - defaultValue.diagramEditorPreferences.setEnableHiDPI(false); + defaultValue.diagramEditorPreferences.setEnableHiDPI(true); return defaultValue; } diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/AbstractCanvasHandler.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/AbstractCanvasHandler.java index 440f4a73cd1..d7d00961e47 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/AbstractCanvasHandler.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/AbstractCanvasHandler.java @@ -29,6 +29,7 @@ import org.kie.workbench.common.stunner.core.client.canvas.listener.HasCanvasListeners; import org.kie.workbench.common.stunner.core.client.canvas.listener.HasDomainObjectListeners; import org.kie.workbench.common.stunner.core.client.canvas.util.CanvasLayoutUtils; +import org.kie.workbench.common.stunner.core.client.command.QueueGraphExecutionContext; import org.kie.workbench.common.stunner.core.client.shape.MutationContext; import org.kie.workbench.common.stunner.core.client.shape.Shape; import org.kie.workbench.common.stunner.core.client.shape.factory.ShapeFactory; @@ -396,12 +397,39 @@ public void notifyCanvasElementRemoved(final Element candidate) { } } + private GraphCommandExecutionContext graphContext = null; + + /** + * Sets the Graphic Context to be used for multiple operations + * @param graphContext Graph context to be set + */ + public void setStaticContext(GraphCommandExecutionContext graphContext) { + this.graphContext = graphContext; + } + /** * Notifies an element updated to the listeners. */ public void notifyCanvasElementUpdated(final Element candidate) { + + if (graphContext != null) { + if (graphContext instanceof QueueGraphExecutionContext) { + ((QueueGraphExecutionContext) graphContext).addElement(candidate); + } else { + for (final CanvasElementListener instance : listeners) { + instance.update(candidate); + } + } + } + } + + /** + * Does Batch update + * @param queue Queue to be sent to be updated + */ + public void doBatchUpdate(final List queue) { for (final CanvasElementListener instance : listeners) { - instance.update(candidate); + instance.updateBatch(queue); } } diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/command/AbstractCanvasGraphCommand.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/command/AbstractCanvasGraphCommand.java index 4a4a8126017..bad7de0b39b 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/command/AbstractCanvasGraphCommand.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/command/AbstractCanvasGraphCommand.java @@ -124,6 +124,8 @@ private CommandResult performOperationOnGraph(final AbstractCan getCanvasCommand(context); // Obtain the graph execution context and execute the graph command updates. final GraphCommandExecutionContext graphContext = context.getGraphExecutionContext(); + context.setStaticContext(graphContext); + if (Objects.isNull(graphContext)) { //skipping command in case there is no graph execution context return CanvasCommandResultBuilder.SUCCESS; diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/controls/select/MapSelectionControl.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/controls/select/MapSelectionControl.java index 110be9f9c02..3ae8bc529d8 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/controls/select/MapSelectionControl.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/controls/select/MapSelectionControl.java @@ -82,6 +82,7 @@ public void handle(final MouseClickEvent event) { final String canvasRootUUID = getRootUUID(); fireCanvasClear(); if (null != canvasRootUUID) { + lastSelected = ""; selectionEventConsumer.accept(new CanvasSelectionEvent(canvasHandler, canvasRootUUID)); } @@ -254,6 +255,7 @@ public void onShapeRemoved(final CanvasShapeRemovedEvent shapeRemovedEvent) { } if (getCanvas().equals(shapeRemovedEvent.getCanvas())) { items.remove(shapeRemovedEvent.getShape().getUUID()); + lastSelected = ""; } } @@ -263,6 +265,7 @@ public void onCanvasElementSelected(final CanvasSelectionEvent event) { if (null == canvasHandler) { return; } + final boolean isSameCtxt = canvasHandler.equals(event.getCanvasHandler()); final boolean isSingleSelection = event.getIdentifiers().size() == 1; final boolean isCanvasRoot = isSingleSelection && @@ -301,9 +304,21 @@ protected String getRootUUID() { return canvasHandler.getDiagram().getMetadata().getCanvasRootUUID(); } + private String lastSelected = ""; + private void fireSelectedItemsEvent() { final Collection selectedItems = getSelectedItems(); if (!selectedItems.isEmpty()) { + if (selectedItems.size() == 1) { + + final String next = selectedItems.iterator().next(); + + if (lastSelected.equals(next)) { + return; + } + + lastSelected = next; + } selectionEventConsumer.accept(new CanvasSelectionEvent(canvasHandler, selectedItems)); } diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/controls/toolbox/AbstractToolboxControl.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/controls/toolbox/AbstractToolboxControl.java index bfdb6027d1e..abde62b4a21 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/controls/toolbox/AbstractToolboxControl.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/canvas/controls/toolbox/AbstractToolboxControl.java @@ -109,10 +109,16 @@ void onCanvasShapeRemovedEvent(final @Observes CanvasShapeRemovedEvent event) { handleCanvasShapeRemovedEvent(event); } + private String lastSelected = ""; + protected void handleCanvasSelectionEvent(final CanvasSelectionEvent event) { if (checkEventContext(event)) { if (1 == event.getIdentifiers().size()) { final String uuid = event.getIdentifiers().iterator().next(); + if (lastSelected.equals(uuid)) { + return; + } + lastSelected = uuid; show(uuid); } else { showMultiple(event.getIdentifiers()); @@ -123,12 +129,14 @@ protected void handleCanvasSelectionEvent(final CanvasSelectionEvent event) { protected void handleCanvasClearSelectionEvent(final CanvasClearSelectionEvent event) { if (checkEventContext(event)) { toolboxControl.destroyToolboxes(); + lastSelected = ""; clear(); } } protected void handleCanvasShapeRemovedEvent(final CanvasShapeRemovedEvent event) { if (checkEventContext(event)) { + lastSelected = ""; clear(); } } diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/command/CanvasCommandManagerImpl.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/command/CanvasCommandManagerImpl.java index 91537bfbe17..d5f46a69465 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/command/CanvasCommandManagerImpl.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/command/CanvasCommandManagerImpl.java @@ -16,6 +16,8 @@ package org.kie.workbench.common.stunner.core.client.command; +import java.util.ArrayList; +import java.util.List; import java.util.function.Supplier; import javax.enterprise.context.Dependent; @@ -33,7 +35,7 @@ import org.kie.workbench.common.stunner.core.command.CommandResult; import org.kie.workbench.common.stunner.core.command.HasCommandListener; import org.kie.workbench.common.stunner.core.command.impl.CommandManagerImpl; -import org.kie.workbench.common.stunner.core.graph.command.ContextualGraphCommandExecutionContext; +import org.kie.workbench.common.stunner.core.graph.Element; /** * The default canvas command manager implementation. @@ -101,20 +103,46 @@ public void setCommandListener(final CommandListener listene private CommandResult runInContext(final AbstractCanvasHandler context, final Supplier> function) { - final ContextualGraphCommandExecutionContext graphExecutionContext = newGraphExecutionContext(context); - context.setGraphExecutionContext(() -> newGraphExecutionContext(context)); + + final List queue = new ArrayList<>(); + final List contextsCreated = new ArrayList<>(); + + context.setGraphExecutionContext(() -> { + final QueueGraphExecutionContext queueGraphExecutionContext2 = newQueueGraphExecutionContext(context); + contextsCreated.add(queueGraphExecutionContext2); + return queueGraphExecutionContext2; + }); + final CommandResult result = function.get(); - graphExecutionContext.clear(); + + boolean multipleSubqueues = false; + for (QueueGraphExecutionContext contexts : contextsCreated) { + if (!queue.isEmpty()) { + multipleSubqueues = true; + break; + } + queue.addAll(contexts.getUpdatedElements()); + } + + if (!queue.isEmpty() && !multipleSubqueues) { // Only send updates to first queue + context.doBatchUpdate(queue); + } + + for (QueueGraphExecutionContext contexts : contextsCreated) { + contexts.resetUpdatedElements(); + contexts.clear(); + } + context.setGraphExecutionContext(() -> null); return result; } - private ContextualGraphCommandExecutionContext newGraphExecutionContext(final AbstractCanvasHandler context) { - return new ContextualGraphCommandExecutionContext(context.getDefinitionManager(), - clientFactoryManager, - context.getRuleManager(), - context.getGraphIndex(), - context.getRuleSet()); + public QueueGraphExecutionContext newQueueGraphExecutionContext(final AbstractCanvasHandler context) { + return new QueueGraphExecutionContext(context.getDefinitionManager(), + clientFactoryManager, + context.getRuleManager(), + context.getGraphIndex(), + context.getRuleSet()); } @SuppressWarnings("unchecked") diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/command/QueueGraphExecutionContext.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/command/QueueGraphExecutionContext.java new file mode 100644 index 00000000000..f1ad19614de --- /dev/null +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/command/QueueGraphExecutionContext.java @@ -0,0 +1,115 @@ +/* + * Copyright 2019 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.command; + +import java.util.ArrayList; +import java.util.List; + +import org.jboss.errai.common.client.api.annotations.NonPortable; +import org.kie.workbench.common.stunner.core.api.DefinitionManager; +import org.kie.workbench.common.stunner.core.api.FactoryManager; +import org.kie.workbench.common.stunner.core.graph.Element; +import org.kie.workbench.common.stunner.core.graph.command.AbstractGraphCommandExecutionContext; +import org.kie.workbench.common.stunner.core.graph.processing.index.Index; +import org.kie.workbench.common.stunner.core.rule.RuleManager; +import org.kie.workbench.common.stunner.core.rule.RuleSet; +import org.kie.workbench.common.stunner.core.rule.RuleViolations; +import org.kie.workbench.common.stunner.core.rule.context.GraphEvaluationContext; +import org.kie.workbench.common.stunner.core.rule.context.impl.AbstractGraphEvaluationContext; +import org.kie.workbench.common.stunner.core.rule.context.impl.RuleEvaluationContextBuilder; +import org.kie.workbench.common.stunner.core.rule.context.impl.StatefulGraphEvaluationContexts; +import org.kie.workbench.common.stunner.core.rule.context.impl.StatefulGraphEvaluationState; + +/** + * This Queued graph execution context type provides composite rule context evaluations. + * Each evaluations accumulates the state in the actual context, so composite operations + * can share evaluation states. + * It delays the updating of the Elements in the end and sends the Batch Update + */ +@NonPortable +public class QueueGraphExecutionContext extends AbstractGraphCommandExecutionContext { + + private final transient RuleManager ruleManager; + private final transient RuleSet ruleSet; + private final transient RuleEvaluationContextBuilder.StatefulGraphContextBuilder contextBuilder; + + public QueueGraphExecutionContext(final DefinitionManager definitionManager, + final FactoryManager factoryManager, + final RuleManager ruleManager, + final Index graphIndex, + final RuleSet ruleSet) { + this(definitionManager, + factoryManager, + ruleManager, + new RuleEvaluationContextBuilder.StatefulGraphContextBuilder(graphIndex.getGraph()), + graphIndex, + ruleSet); + } + + QueueGraphExecutionContext(final DefinitionManager definitionManager, + final FactoryManager factoryManager, + final RuleManager ruleManager, + final RuleEvaluationContextBuilder.StatefulGraphContextBuilder contextBuilder, + final Index graphIndex, + final RuleSet ruleSet) { + super(definitionManager, + factoryManager, + graphIndex); + this.contextBuilder = contextBuilder; + this.ruleManager = ruleManager; + this.ruleSet = ruleSet; + } + + public void clear() { + getState().clear(); + } + + @Override + public RuleViolations evaluate(final GraphEvaluationContext context) { + ((AbstractGraphEvaluationContext) context).setState(this::getState); + return StatefulGraphEvaluationContexts.evaluate(context, + c -> ruleManager.evaluate(ruleSet, c)); + } + + @Override + public RuleSet getRuleSet() { + return ruleSet; + } + + private StatefulGraphEvaluationState getState() { + return contextBuilder.getState(); + } + + @Override + protected RuleEvaluationContextBuilder.GraphContextBuilder getContextBuilder() { + return contextBuilder; + } + + private List updatedElements = new ArrayList<>(); + + public void addElement(final Element candidate) { + updatedElements.add(candidate); + } + + public List getUpdatedElements() { + return updatedElements; + } + + public void resetUpdatedElements() { + updatedElements.clear(); + } +} + diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/components/toolbox/actions/ActionsToolbox.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/components/toolbox/actions/ActionsToolbox.java index 0812eba43be..131d875ed51 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/components/toolbox/actions/ActionsToolbox.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/components/toolbox/actions/ActionsToolbox.java @@ -88,8 +88,17 @@ public Shape getShape() { return canvasHandlerSupplier.get().getCanvas().getShape(uuid); } + private String lastToolBoxRendered = ""; + @Override public ActionsToolbox show() { + + if (lastToolBoxRendered.equals(this.uuid)) { + return this; + } + + lastToolBoxRendered = this.uuid; + getView().show(); return this; } diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CopySelectionSessionCommand.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CopySelectionSessionCommand.java index bc70d0773b4..7bcd3c62367 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CopySelectionSessionCommand.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CopySelectionSessionCommand.java @@ -25,6 +25,7 @@ import javax.enterprise.inject.Default; import javax.inject.Inject; +import org.kie.workbench.common.stunner.core.client.api.SessionManager; 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.ClipboardControl; @@ -57,13 +58,23 @@ public class CopySelectionSessionCommand extends AbstractSelectionAwareSessionCo private ClipboardControl clipboardControl; public CopySelectionSessionCommand() { - this(null); + this(null, null); } @Inject - public CopySelectionSessionCommand(final Event commandExecutedEvent) { + public CopySelectionSessionCommand(final Event commandExecutedEvent, final SessionManager sessionManager) { super(true); this.commandExecutedEvent = commandExecutedEvent; + SessionSingletonCommandsFactory.createOrPut(this, sessionManager); + } + + public static CopySelectionSessionCommand getInstance(SessionManager sessionManager) { + + return SessionSingletonCommandsFactory.getInstanceCopy(null, sessionManager); + } + + public static CopySelectionSessionCommand getInstance(final Event commandExecutedEvent, SessionManager sessionManager) { + return SessionSingletonCommandsFactory.getInstanceCopy(commandExecutedEvent, sessionManager); } @Override @@ -94,7 +105,7 @@ private void handleCtrlC(final Key[] keys) { @Override public void execute(final Callback callback) { - if (null != getSession().getSelectionControl()) { + if (getSession() != null && null != getSession().getSelectionControl()) { try { //for now just copy Nodes not Edges final SelectionControl selectionControl = getSession().getSelectionControl(); diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CutSelectionSessionCommand.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CutSelectionSessionCommand.java index 9acd5f66631..050ffbb80c4 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CutSelectionSessionCommand.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CutSelectionSessionCommand.java @@ -23,6 +23,7 @@ import javax.enterprise.inject.Default; import javax.inject.Inject; +import org.kie.workbench.common.stunner.core.client.api.SessionManager; import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvasHandler; import org.kie.workbench.common.stunner.core.client.canvas.controls.ClipboardControl; import org.kie.workbench.common.stunner.core.client.canvas.event.registration.CanvasElementsClearEvent; @@ -45,7 +46,7 @@ @Default public class CutSelectionSessionCommand extends AbstractSelectionAwareSessionCommand { - private final CopySelectionSessionCommand copySelectionSessionCommand; + private CopySelectionSessionCommand copySelectionSessionCommand; private final DeleteSelectionSessionCommand deleteSelectionSessionCommand; private final Event commandExecutedEvent; private static Logger LOGGER = Logger.getLogger(CopySelectionSessionCommand.class.getName()); @@ -54,32 +55,33 @@ public class CutSelectionSessionCommand extends AbstractSelectionAwareSessionCom protected CutSelectionSessionCommand() { this(null, - null, null, null); } @Inject - public CutSelectionSessionCommand(final CopySelectionSessionCommand copySelectionSessionCommand, - final DeleteSelectionSessionCommand deleteSelectionSessionCommand, - final @Session SessionCommandManager sessionCommandManager, - final Event commandExecutedEvent) { + public CutSelectionSessionCommand(final @Session SessionCommandManager sessionCommandManager, + final Event commandExecutedEvent, + final SessionManager sessionManager) { super(true); - this.copySelectionSessionCommand = copySelectionSessionCommand; - this.deleteSelectionSessionCommand = deleteSelectionSessionCommand; + this.copySelectionSessionCommand = CopySelectionSessionCommand.getInstance(sessionManager); + this.deleteSelectionSessionCommand = DeleteSelectionSessionCommand.getInstance(sessionManager); this.sessionCommandManager = sessionCommandManager; this.commandExecutedEvent = commandExecutedEvent; } @Override public void bind(final EditorSession session) { - super.bind(session); - copySelectionSessionCommand.bind(session); - deleteSelectionSessionCommand.bind(session); session.getKeyboardControl().addKeyShortcutCallback(this::onKeyDownEvent); + + super.bind(session); this.clipboardControl = session.getClipboardControl(); } + public void setCopySelectionSessionCommand(CopySelectionSessionCommand copySelectionSessionCommand) { + this.copySelectionSessionCommand = copySelectionSessionCommand; + } + @Override public boolean accepts(final ClientSession session) { return session instanceof EditorSession; diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/DeleteSelectionSessionCommand.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/DeleteSelectionSessionCommand.java index 0e92315629b..4a35a9c8a76 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/DeleteSelectionSessionCommand.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/DeleteSelectionSessionCommand.java @@ -28,6 +28,7 @@ import javax.inject.Inject; import org.jboss.errai.ioc.client.api.ManagedInstance; +import org.kie.workbench.common.stunner.core.client.api.SessionManager; import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvasHandler; import org.kie.workbench.common.stunner.core.client.canvas.controls.SelectionControl; import org.kie.workbench.common.stunner.core.client.canvas.event.registration.CanvasElementsClearEvent; @@ -69,19 +70,36 @@ protected DeleteSelectionSessionCommand() { this(null, null, null, - null); + null, + null + ); } @Inject public DeleteSelectionSessionCommand(final @Session SessionCommandManager sessionCommandManager, final @Any ManagedInstance> canvasCommandFactoryInstance, final Event clearSelectionEvent, - final DefinitionUtils definitionUtils) { + final DefinitionUtils definitionUtils, + final SessionManager sessionmanager) { super(false); this.sessionCommandManager = sessionCommandManager; this.canvasCommandFactoryInstance = canvasCommandFactoryInstance; this.clearSelectionEvent = clearSelectionEvent; this.definitionUtils = definitionUtils; + SessionSingletonCommandsFactory.createOrPut(this, sessionmanager); + } + + public static DeleteSelectionSessionCommand getInstance(SessionManager sessionManager) { + return SessionSingletonCommandsFactory.getInstanceDelete(null, null, null, null, sessionManager); + } + + public static DeleteSelectionSessionCommand getInstance(final SessionCommandManager sessionCommandManager, + final ManagedInstance> canvasCommandFactoryInstance, + final Event clearSelectionEvent, + final DefinitionUtils definitionUtils, + final SessionManager sessionmanager) { + + return SessionSingletonCommandsFactory.getInstanceDelete(sessionCommandManager, canvasCommandFactoryInstance, clearSelectionEvent, definitionUtils, sessionmanager); } @Override @@ -101,7 +119,7 @@ public boolean accepts(final ClientSession session) { public void execute(final Callback callback) { checkNotNull("callback", callback); - if (null != getSession().getSelectionControl()) { + if (null != getSession() && null != getSession().getSelectionControl()) { final AbstractCanvasHandler canvasHandler = getSession().getCanvasHandler(); final SelectionControl selectionControl = getSession().getSelectionControl(); final Collection selectedItems = selectionControl.getSelectedItems(); @@ -117,6 +135,7 @@ public void execute(final Callback callback) { .map(uuid -> canvasHandler.getGraphIndex().get(uuid)) .filter(Objects::nonNull) .collect(Collectors.toList()))); + // Check the results. if (!CommandUtils.isError(result)) { callback.onSuccess(); diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/PasteSelectionSessionCommand.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/PasteSelectionSessionCommand.java index 3a8326f4b29..28d90553dae 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/PasteSelectionSessionCommand.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/PasteSelectionSessionCommand.java @@ -37,6 +37,7 @@ import javax.inject.Inject; import org.jboss.errai.ioc.client.api.ManagedInstance; +import org.kie.workbench.common.stunner.core.client.api.SessionManager; 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.ClipboardControl; @@ -84,9 +85,9 @@ public class PasteSelectionSessionCommand extends AbstractClientSessionCommand selectionEvent; private final Map clonedElements; private final CopySelectionSessionCommand copySelectionSessionCommand; - private final DefinitionUtils definitionUtils; private ClipboardControl clipboardControl; private transient DoubleSummaryStatistics yPositionStatistics; + private final DefinitionUtils definitionUtils; private CanvasCommandFactory canvasCommandFactory; private boolean testEdgeFoundInCanvas = false; private boolean testEdgeFoundInClipboard = false; @@ -99,14 +100,14 @@ protected PasteSelectionSessionCommand() { public PasteSelectionSessionCommand(final @Session SessionCommandManager sessionCommandManager, @Any ManagedInstance> canvasCommandFactoryInstance, final Event selectionEvent, - final CopySelectionSessionCommand copySelectionSessionCommand, - final DefinitionUtils definitionUtils) { + final DefinitionUtils definitionUtils, + final SessionManager sessionManager) { super(true); this.sessionCommandManager = sessionCommandManager; this.canvasCommandFactoryInstance = canvasCommandFactoryInstance; this.selectionEvent = selectionEvent; this.clonedElements = new HashMap<>(); - this.copySelectionSessionCommand = copySelectionSessionCommand; + this.copySelectionSessionCommand = CopySelectionSessionCommand.getInstance(sessionManager); this.definitionUtils = definitionUtils; } @@ -123,7 +124,6 @@ public void bind(final EditorSession session) { super.bind(session); session.getKeyboardControl().addKeyShortcutCallback(this::onKeyDownEvent); this.clipboardControl = session.getClipboardControl(); - this.copySelectionSessionCommand.bind(session); this.canvasCommandFactory = this.loadCanvasFactory(canvasCommandFactoryInstance, definitionUtils); } @@ -160,6 +160,7 @@ public void execute(final Callback callback) { //first processing nodes nodesCommandBuilder.addCommands(clipboardControl.getElements().stream() .filter(element -> element instanceof Node) + .filter(Objects::nonNull) .map(node -> (Node, Edge>) node) .map(node -> { String newParentUUID = getNewParentUUID(node); @@ -177,7 +178,7 @@ public void execute(final Callback callback) { //in case of a cut command the source elements were deleted from graph, so first undo the command to take node back into canvas clipboardControl.getRollbackCommands().forEach(command -> nodesCommandBuilder.addFirstCommand(new ReverseCommand(command))); //after the clone execution than delete source elements again - clipboardControl.getRollbackCommands().forEach(nodesCommandBuilder::addCommand); + clipboardControl.getRollbackCommands().forEach(node -> nodesCommandBuilder.addCommand(node)); finalResult = executeCommands(nodesCommandBuilder, processedNodesCountdown); } else { @@ -201,9 +202,11 @@ public void execute(final Callback callback) { private CommandResult executeCommands(CompositeCommand.Builder commandBuilder, Counter processedNodesCountdown) { CommandResult nodesResult = sessionCommandManager.execute(getCanvasHandler(), commandBuilder.build()); + if (CommandUtils.isError(nodesResult)) { return nodesResult; } + // Processing connectors: after all nodes has been cloned (this is necessary because we need the cloned nodes UUIDs to than clone the Connectors CommandResult connectorsResult = processConnectors(processedNodesCountdown); @@ -211,7 +214,6 @@ private CommandResult executeCommands(CompositeCommand.Builder< if (!CommandUtils.isError(connectorsResult)) { updateCommandsRegistry(); } - return new CanvasCommandResultBuilder() .setType(nodesResult.getType()) .addViolations((Objects.nonNull(nodesResult.getViolations()) ? @@ -235,7 +237,6 @@ private void updateCommandsRegistry() { private CommandResult processConnectors(Counter processedNodesCountdown) { if (processedNodesCountdown.equalsToValue(0)) { - final CompositeCommand.Builder commandBuilder = createCommandBuilder(); commandBuilder.addCommands(clipboardControl.getElements().stream() .filter(element -> element instanceof Edge) diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/SessionSingletonCommandsFactory.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/SessionSingletonCommandsFactory.java new file mode 100644 index 00000000000..fde526e8cb4 --- /dev/null +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/SessionSingletonCommandsFactory.java @@ -0,0 +1,99 @@ +/* + * Copyright 2019 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.session.command.impl; + +import java.util.HashMap; + +import javax.enterprise.event.Event; +import javax.inject.Singleton; + +import org.jboss.errai.ioc.client.api.ManagedInstance; +import org.kie.workbench.common.stunner.core.client.api.SessionManager; +import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvasHandler; +import org.kie.workbench.common.stunner.core.client.canvas.event.selection.CanvasClearSelectionEvent; +import org.kie.workbench.common.stunner.core.client.command.CanvasCommandFactory; +import org.kie.workbench.common.stunner.core.client.command.SessionCommandManager; +import org.kie.workbench.common.stunner.core.client.session.ClientSession; +import org.kie.workbench.common.stunner.core.client.session.impl.EditorSession; +import org.kie.workbench.common.stunner.core.util.DefinitionUtils; + +/** + * The purpose of this class is to have only one copy of Copy, Delete per Client Session. + * An alternate easier aproach was tried with @Produces on those classes, but the issue is that @Produces Factory from erray does not generate + * Decorators for @Observes extension and the result was that commands created using @Produces did not listen for Events + */ +@Singleton +public class SessionSingletonCommandsFactory { + + private static HashMap copySessionInstances = new HashMap<>(); + + private static HashMap deleteSessionInstances = new HashMap<>(); + + public static void createOrPut(AbstractSelectionAwareSessionCommand command, SessionManager sessionManager) { + + if (sessionManager == null) { + throw new IllegalStateException("Session Manager is Null"); + } + + if (command instanceof CopySelectionSessionCommand) { + if (copySessionInstances.containsKey(sessionManager.getCurrentSession())) { // there is one already one + throw new IllegalStateException("Only one instance of CopySelectionSessionCommand per Client Session can exist"); + } + + copySessionInstances.put(sessionManager.getCurrentSession(), (CopySelectionSessionCommand) command); + } else if (command instanceof DeleteSelectionSessionCommand) { + if (deleteSessionInstances.containsKey(sessionManager.getCurrentSession())) { // there is one already one + throw new IllegalStateException("Only one instance of DeleteSelectionSessionCommand per Client Session can exist"); + } + deleteSessionInstances.put(sessionManager.getCurrentSession(), (DeleteSelectionSessionCommand) command); + } else { + throw new UnsupportedOperationException("Session Command Not Compatible Yet : " + command.getClass()); + } + } + + public static CopySelectionSessionCommand getInstanceCopy( + final Event commandExecutedEvent, + SessionManager sessionManager) { + + final ClientSession currentSession = sessionManager.getCurrentSession(); + + if (!copySessionInstances.containsKey(currentSession)) { + final CopySelectionSessionCommand copySelectionSessionCommand = new CopySelectionSessionCommand((Event) commandExecutedEvent, sessionManager); + + return copySelectionSessionCommand; + } + + final CopySelectionSessionCommand copySelectionSessionCommand = copySessionInstances.get(currentSession); + + return copySelectionSessionCommand; + } + + public static DeleteSelectionSessionCommand getInstanceDelete( + final SessionCommandManager sessionCommandManager, + final ManagedInstance> canvasCommandFactoryInstance, + final Event clearSelectionEvent, + final DefinitionUtils definitionUtils, + final SessionManager sessionManager) { + final ClientSession currentSession = sessionManager.getCurrentSession(); + + if (!deleteSessionInstances.containsKey(currentSession)) { + return new DeleteSelectionSessionCommand(sessionCommandManager, canvasCommandFactoryInstance, clearSelectionEvent, definitionUtils, sessionManager); + } + + return deleteSessionInstances.get(currentSession); + } +} diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/UndoSessionCommand.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/UndoSessionCommand.java index 4a120ae7be0..ff6f4a27605 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/UndoSessionCommand.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/main/java/org/kie/workbench/common/stunner/core/client/session/command/impl/UndoSessionCommand.java @@ -76,6 +76,7 @@ private void handleCtrlZ(final KeyboardEvent.Key[] keys) { @Override @SuppressWarnings("unchecked") public void execute(final Callback callback) { + checkNotNull("callback", callback); final SessionCommandManager scm = getSessionCommandManager(); diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/BaseCanvasHandlerTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/BaseCanvasHandlerTest.java new file mode 100644 index 00000000000..a957f38bd6e --- /dev/null +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/BaseCanvasHandlerTest.java @@ -0,0 +1,202 @@ +/* + * Copyright 2019 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; + +import java.util.Collections; +import java.util.List; + +import javax.enterprise.event.Event; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.kie.workbench.common.stunner.core.client.api.ClientDefinitionManager; +import org.kie.workbench.common.stunner.core.client.api.ShapeManager; +import org.kie.workbench.common.stunner.core.client.canvas.controls.actions.TextPropertyProviderFactory; +import org.kie.workbench.common.stunner.core.client.canvas.event.registration.CanvasElementAddedEvent; +import org.kie.workbench.common.stunner.core.client.canvas.event.registration.CanvasElementRemovedEvent; +import org.kie.workbench.common.stunner.core.client.canvas.event.registration.CanvasElementUpdatedEvent; +import org.kie.workbench.common.stunner.core.client.canvas.event.registration.CanvasElementsClearEvent; +import org.kie.workbench.common.stunner.core.client.canvas.listener.CanvasElementListener; +import org.kie.workbench.common.stunner.core.client.command.CanvasCommandFactory; +import org.kie.workbench.common.stunner.core.client.command.QueueGraphExecutionContext; +import org.kie.workbench.common.stunner.core.client.shape.ElementShape; +import org.kie.workbench.common.stunner.core.client.shape.MutationContext; +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.Node; +import org.kie.workbench.common.stunner.core.graph.command.ContextualGraphCommandExecutionContext; +import org.kie.workbench.common.stunner.core.graph.processing.index.GraphIndexBuilder; +import org.kie.workbench.common.stunner.core.graph.processing.index.MutableIndex; +import org.kie.workbench.common.stunner.core.graph.util.GraphUtils; +import org.kie.workbench.common.stunner.core.rule.RuleManager; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class BaseCanvasHandlerTest { + + private BaseCanvasHandler canvasHandler; + + @Mock + private ClientDefinitionManager clientDefinitionManager; + + @Mock + private CanvasCommandFactory commandFactory; + + @Mock + private RuleManager ruleManager; + + @Mock + private GraphUtils graphUtils; + + @Mock + private GraphIndexBuilder> indexBuilder; + + @Mock + private ShapeManager shapeManager; + + @Mock + private TextPropertyProviderFactory textPropertyProviderFactory; + + @Mock + private Event canvasElementAddedEvent; + + @Mock + private Event canvasElementRemovedEvent; + + @Mock + private Event canvasElementUpdatedEvent; + + @Mock + private Event canvasElementsClearEvent; + + @Mock + private QueueGraphExecutionContext queueGraphExecutionContext; + + @Mock + private ContextualGraphCommandExecutionContext contextualGraphExecutionContext; + + @Mock + private CanvasElementListener updateListener; + + @Before + public void setup() { + canvasHandler = new CanvasHandlerImpl(clientDefinitionManager, + commandFactory, + ruleManager, + graphUtils, + indexBuilder, + shapeManager, + textPropertyProviderFactory, + canvasElementAddedEvent, + canvasElementRemovedEvent, + canvasElementUpdatedEvent, + canvasElementsClearEvent); + } + + @Test + public void checkApplyElementMutationOnPosition() { + final ElementShape shape = mock(ElementShape.class); + final Element candidate = mock(Element.class); + final boolean applyPosition = true; + final boolean applyProperties = false; + final MutationContext mutationContext = mock(MutationContext.class); + canvasHandler.applyElementMutation(shape, + candidate, + applyPosition, + applyProperties, + mutationContext); + + verify(shape, atLeastOnce()).applyPosition(any(), any()); + verify(canvasElementUpdatedEvent, atLeastOnce()).fire(any()); + } + + @Test + public void checkApplyElementMutationNotifyQueued() { + canvasHandler.setStaticContext(queueGraphExecutionContext); + final ElementShape shape = mock(ElementShape.class); + final Element candidate = mock(Element.class); + final boolean applyPosition = true; + final boolean applyProperties = false; + final MutationContext mutationContext = mock(MutationContext.class); + canvasHandler.applyElementMutation(shape, + candidate, + applyPosition, + applyProperties, + mutationContext); + + verify(shape, atLeastOnce()).applyPosition(any(), any()); + verify(canvasElementUpdatedEvent, atLeastOnce()).fire(any()); + verify(queueGraphExecutionContext, times(1)).addElement(candidate); + } + + @Test + public void checkApplyElementMutationNullQueue() { + canvasHandler.setStaticContext(null); + final ElementShape shape = mock(ElementShape.class); + final Element candidate = mock(Element.class); + final boolean applyPosition = true; + final boolean applyProperties = false; + final MutationContext mutationContext = mock(MutationContext.class); + canvasHandler.applyElementMutation(shape, + candidate, + applyPosition, + applyProperties, + mutationContext); + + verify(shape, atLeastOnce()).applyPosition(any(), any()); + verify(canvasElementUpdatedEvent, atLeastOnce()).fire(any()); + verify(queueGraphExecutionContext, never()).addElement(candidate); + } + + @Test + public void checkNotifyElementUpdatedOnNonQueuedContext() { + canvasHandler.addRegistrationListener(updateListener); + canvasHandler.setStaticContext(contextualGraphExecutionContext); + final ElementShape shape = mock(ElementShape.class); + final Element candidate = mock(Element.class); + final boolean applyPosition = true; + final boolean applyProperties = false; + final MutationContext mutationContext = mock(MutationContext.class); + canvasHandler.applyElementMutation(shape, + candidate, + applyPosition, + applyProperties, + mutationContext); + + verify(shape, atLeastOnce()).applyPosition(any(), any()); + verify(canvasElementUpdatedEvent, atLeastOnce()).fire(any()); + verify(queueGraphExecutionContext, never()).addElement(candidate); + } + + @Test + public void checkNotifyElementUpdatedAndListenerUpdated() { + canvasHandler.addRegistrationListener(updateListener); + + final List updatedElements = Collections.singletonList(mock(Element.class)); + + canvasHandler.doBatchUpdate(updatedElements); + verify(updateListener, times(1)).updateBatch(any()); + } +} diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/controls/select/MapSelectionControlTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/controls/select/MapSelectionControlTest.java index 9a45a817afb..3eefda87cb3 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/controls/select/MapSelectionControlTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/controls/select/MapSelectionControlTest.java @@ -237,6 +237,30 @@ public void testSelect() { assertEquals(ELEMENT_UUID, event.getIdentifiers().iterator().next()); } + @Test + public void testSelectOnlyOnce() { + tested.init(canvasHandler); + tested.register(element); + tested.select(element.getUUID()); + tested.select(element.getUUID()); + + assertEquals(1, tested.getSelectedItems().size()); + assertEquals(ELEMENT_UUID, tested.getSelectedItems().iterator().next()); + verify(shape, times(2)).applyState(eq(ShapeState.SELECTED)); + verify(shape, never()).applyState(eq(ShapeState.NONE)); + verify(shape, never()).applyState(eq(ShapeState.INVALID)); + verify(shape, never()).applyState(eq(ShapeState.HIGHLIGHT)); + verify(canvas, times(2)).focus(); + final ArgumentCaptor elementSelectedEventArgumentCaptor = + ArgumentCaptor.forClass(CanvasSelectionEvent.class); + // Verify it has only been fired once + verify(elementSelectedEvent, + times(1)).fire(elementSelectedEventArgumentCaptor.capture()); + final CanvasSelectionEvent event = elementSelectedEventArgumentCaptor.getValue(); + assertEquals(1, event.getIdentifiers().size()); + assertEquals(ELEMENT_UUID, event.getIdentifiers().iterator().next()); + } + @Test public void testSelectReadOnly() { tested.init(canvasHandler); diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/controls/toolbox/ToolboxControlTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/controls/toolbox/ToolboxControlTest.java index 727c0c23d96..75431848b1e 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/controls/toolbox/ToolboxControlTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/canvas/controls/toolbox/ToolboxControlTest.java @@ -125,6 +125,21 @@ public void testElementSelectedEvent() { never()).destroy(); } + @Test + public void testElementSelectedEventCache() { + final String uuid = "uuid1"; + when(element.getUUID()).thenReturn(uuid); + final CanvasSelectionEvent event = new CanvasSelectionEvent(canvasHandler, + element.getUUID()); + tested.onCanvasSelectionEvent(event); + tested.onCanvasSelectionEvent(event); + // Verify it has onl been selected once and called show + verify(delegated, + times(1)).show(eq(uuid)); + verify(delegated, + never()).destroy(); + } + @Test public void testClearSelectionEvent() { final CanvasClearSelectionEvent event = new CanvasClearSelectionEvent(canvasHandler); diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/command/QueueGraphExecutionContextTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/command/QueueGraphExecutionContextTest.java new file mode 100644 index 00000000000..01543b2c201 --- /dev/null +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/command/QueueGraphExecutionContextTest.java @@ -0,0 +1,118 @@ +/* + * Copyright 2019 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.command; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.kie.workbench.common.stunner.core.api.DefinitionManager; +import org.kie.workbench.common.stunner.core.api.FactoryManager; +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.impl.NodeImpl; +import org.kie.workbench.common.stunner.core.graph.processing.index.Index; +import org.kie.workbench.common.stunner.core.rule.RuleManager; +import org.kie.workbench.common.stunner.core.rule.RuleSet; +import org.kie.workbench.common.stunner.core.rule.context.NodeContainmentContext; +import org.kie.workbench.common.stunner.core.rule.context.impl.RuleEvaluationContextBuilder; +import org.kie.workbench.common.stunner.core.rule.context.impl.StatefulGraphEvaluationState; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class QueueGraphExecutionContextTest { + + @Mock + private DefinitionManager definitionManager; + + @Mock + private FactoryManager factoryManager; + + @Mock + private RuleManager ruleManager; + + @Mock + private StatefulGraphEvaluationState state; + + @Mock + private Index graphIndex; + + @Mock + private RuleSet ruleSet; + + private QueueGraphExecutionContext tested; + private RuleEvaluationContextBuilder.StatefulGraphContextBuilder contextBuilder; + + @Before + public void setUp() { + contextBuilder = new RuleEvaluationContextBuilder.StatefulGraphContextBuilder(state); + tested = new QueueGraphExecutionContext(definitionManager, + factoryManager, + ruleManager, + contextBuilder, + graphIndex, + ruleSet); + } + + @Test + @SuppressWarnings("unchecked") + public void testEvaluate() { + StatefulGraphEvaluationState.StatefulContainmentState containmentState = new StatefulGraphEvaluationState.StatefulContainmentState(); + when(state.getContainmentState()).thenReturn(containmentState); + Element parent = new NodeImpl<>("parent"); + Node child = new NodeImpl<>("child"); + final NodeContainmentContext[] containmentContext = new NodeContainmentContext[1]; + tested.evaluate(builder -> containmentContext[0] = builder.containment(parent, child)); + verify(ruleManager, times(1)).evaluate(eq(ruleSet), eq(containmentContext[0])); + assertEquals(parent, containmentState.getParent(child)); + } + + @Test + public void testClear() { + tested.clear(); + verify(state, times(1)).clear(); + } + + @Test + public void testAddElement() { + Element node1 = new NodeImpl<>("parent"); + tested.addElement(node1); + assertEquals("Should be One Element in Updated Elements", 1, tested.getUpdatedElements().size()); + } + + @Test + public void testGetUpdatedElements() { + Element node1 = new NodeImpl<>("parent"); + tested.addElement(node1); + assertEquals("node 1 should be returned from Updated Elements", node1, tested.getUpdatedElements().get(0)); + } + + @Test + public void testResetUpdatedElements() { + Element parent = new NodeImpl<>("parent"); + + tested.addElement(parent); + assertEquals("Should be One Element in Updated Elements", 1, tested.getUpdatedElements().size()); + tested.resetUpdatedElements(); + assertEquals("Updated Elements should be empty", 0, tested.getUpdatedElements().size()); + } +} diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/components/toolbox/actions/ActionsToolboxTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/components/toolbox/actions/ActionsToolboxTest.java index 136d198965c..fadf0670ebf 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/components/toolbox/actions/ActionsToolboxTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/components/toolbox/actions/ActionsToolboxTest.java @@ -129,6 +129,14 @@ public void testShow() { times(1)).show(); } + @Test + public void testShowOnlyOnce() { + tested.show(); + tested.show(); + verify(view, + times(1)).show(); + } + @Test public void testHide() { tested.hide(); diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/BaseSessionCommandKeyboardTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/BaseSessionCommandKeyboardTest.java index c76e58f67d6..2265ceea98d 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/BaseSessionCommandKeyboardTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/BaseSessionCommandKeyboardTest.java @@ -67,9 +67,9 @@ public abstract class BaseSessionCommandKeyboardTest { @Before public void setup() { - this.command = spy(getCommand()); when(session.getKeyboardControl()).thenReturn(keyboardControl); when(session.getSelectionControl()).thenReturn(selectionControl); + this.command = spy(getCommand()); } @Test diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CopySelectionSessionCommandTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CopySelectionSessionCommandTest.java index c190bcae74b..d829d83bd5e 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CopySelectionSessionCommandTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CopySelectionSessionCommandTest.java @@ -18,11 +18,11 @@ import java.util.Arrays; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.kie.workbench.common.stunner.core.TestingGraphInstanceBuilder; import org.kie.workbench.common.stunner.core.TestingGraphMockHandler; +import org.kie.workbench.common.stunner.core.client.api.SessionManager; import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvas; import org.kie.workbench.common.stunner.core.client.canvas.controls.ClipboardControl; import org.kie.workbench.common.stunner.core.client.canvas.controls.SelectionControl; @@ -38,6 +38,7 @@ import org.uberfire.mocks.EventSourceMock; import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -54,6 +55,9 @@ public class CopySelectionSessionCommandTest extends BaseSessionCommandKeyboardS @Mock private EventSourceMock commandExecutedEvent; + @Mock + private SessionManager sessionManager; + private ArgumentCaptor eventArgumentCaptor; private ClipboardControl clipboardControl; @@ -68,13 +72,12 @@ public class CopySelectionSessionCommandTest extends BaseSessionCommandKeyboardS private TestingGraphInstanceBuilder.TestGraph2 graphInstance; - @Before - public void setUp() throws Exception { + @Override + public void setup() { + super.setup(); + when(sessionManager.getCurrentSession()).thenReturn(session); eventArgumentCaptor = ArgumentCaptor.forClass(CopySelectionSessionCommandExecutedEvent.class); clipboardControl = spy(new LocalClipboardControl()); - - super.setup(); - TestingGraphMockHandler graphMockHandler = new TestingGraphMockHandler(); this.graphInstance = TestingGraphInstanceBuilder.newGraph2(graphMockHandler); this.copySelectionSessionCommand = getCommand(); @@ -191,9 +194,28 @@ public void testExecuteMultiSelection() { assertEquals(0, clipboardControl.getEdgeMap().size()); } + @Test + public void testExecuteNullSessionAndNullSelectionControl() { + copySelectionSessionCommand.execute(callback); + // if session null, then it should never copy items + verify(clipboardControl, never()).set(any(), any(), any()); + + copySelectionSessionCommand.bind(session); + when(session.getSelectionControl()).thenReturn(null); + copySelectionSessionCommand.execute(callback); + // if session null, then it should never copy items + verify(clipboardControl, never()).set(any(), any(), any()); + } + + @Test(expected = IllegalStateException.class) + @SuppressWarnings("unchecked") + public void testEmptyConstructor() { + CopySelectionSessionCommand copy = new CopySelectionSessionCommand(null, null); + } + @Override protected CopySelectionSessionCommand getCommand() { - return new CopySelectionSessionCommand(commandExecutedEvent); + return CopySelectionSessionCommand.getInstance(commandExecutedEvent, sessionManager); } @Override diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CutSelectionSessionCommandTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CutSelectionSessionCommandTest.java index 00651cc5dc6..35e94cfffc3 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CutSelectionSessionCommandTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/CutSelectionSessionCommandTest.java @@ -16,24 +16,35 @@ package org.kie.workbench.common.stunner.core.client.session.command.impl; +import java.lang.annotation.Annotation; + +import javax.enterprise.event.Event; + +import org.jboss.errai.ioc.client.api.ManagedInstance; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.kie.workbench.common.stunner.core.client.api.SessionManager; 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.command.DeleteNodeCommand; import org.kie.workbench.common.stunner.core.client.canvas.controls.ClipboardControl; import org.kie.workbench.common.stunner.core.client.canvas.controls.clipboard.LocalClipboardControl; +import org.kie.workbench.common.stunner.core.client.canvas.event.selection.CanvasClearSelectionEvent; +import org.kie.workbench.common.stunner.core.client.command.CanvasCommandFactory; import org.kie.workbench.common.stunner.core.client.event.keyboard.KeyboardEvent.Key; import org.kie.workbench.common.stunner.core.client.session.ClientSession; import org.kie.workbench.common.stunner.core.client.session.command.ClientSessionCommand; import org.kie.workbench.common.stunner.core.graph.Element; import org.kie.workbench.common.stunner.core.registry.command.CommandRegistry; +import org.kie.workbench.common.stunner.core.util.DefinitionUtils; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.uberfire.mocks.EventSourceMock; import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -45,11 +56,20 @@ public class CutSelectionSessionCommandTest extends BaseSessionCommandKeyboardSe private CutSelectionSessionCommand cutSelectionSessionCommand; + @Mock + private SessionManager sessionManager; + @Mock private CopySelectionSessionCommand copySelectionSessionCommand; @Mock - private DeleteSelectionSessionCommand deleteSelectionSessionCommand; + private Event canvasClearSelectionEventEvent; + + @Mock + private DefinitionUtils definitionUtils; + + @Mock + private ManagedInstance> canvasCommandFactoryInstance; @Mock private EventSourceMock commandExecutedEvent; @@ -68,6 +88,11 @@ public class CutSelectionSessionCommandTest extends BaseSessionCommandKeyboardSe private ClipboardControl clipboardControl; + private final String DEFINITION_SET_ID = "mockDefinitionSetId"; + + @Mock + private Annotation qualifier; + @Before @SuppressWarnings("unchecked") public void setUp() throws Exception { @@ -75,22 +100,34 @@ public void setUp() throws Exception { when(sessionCommandManager.getRegistry()).thenReturn(commandRegistry); when(commandRegistry.peek()).thenReturn(deleteNodeCommand); when(session.getClipboardControl()).thenReturn(clipboardControl); - commandExecutedEventCaptor = ArgumentCaptor.forClass(CutSelectionSessionCommandExecutedEvent.class); + when(sessionManager.getCurrentSession()).thenReturn(session); + + when(metadata.getDefinitionSetId()).thenReturn(DEFINITION_SET_ID); + when(definitionUtils.getQualifier(eq(DEFINITION_SET_ID))).thenReturn(qualifier); + when(canvasCommandFactoryInstance.select(eq(qualifier))).thenReturn(canvasCommandFactoryInstance); + when(canvasCommandFactoryInstance.isUnsatisfied()).thenReturn(false); + when(canvasCommandFactoryInstance.get()).thenReturn(canvasCommandFactory); + super.setup(); this.cutSelectionSessionCommand = getCommand(); + + commandExecutedEventCaptor = ArgumentCaptor.forClass(CutSelectionSessionCommandExecutedEvent.class); } @Test @SuppressWarnings("unchecked") public void testExecute() { + cutSelectionSessionCommand.bind(session); + CopySelectionSessionCommand.getInstance(sessionManager).bind(session); + cutSelectionSessionCommand.setCopySelectionSessionCommand(copySelectionSessionCommand); cutSelectionSessionCommand.execute(mainCallback); + ArgumentCaptor callbackArgumentCaptor = ArgumentCaptor.forClass(ClientSessionCommand.Callback.class); verify(copySelectionSessionCommand).execute(callbackArgumentCaptor.capture()); //success callbackArgumentCaptor.getValue().onSuccess(); - verify(deleteSelectionSessionCommand, times(1)).execute(mainCallback); verify(sessionCommandManager.getRegistry(), atLeastOnce()).peek(); verify(clipboardControl, atLeastOnce()).setRollbackCommand(deleteNodeCommand); verify(commandExecutedEvent, times(1)).fire(commandExecutedEventCaptor.capture()); @@ -105,7 +142,7 @@ public void testExecute() { @Override protected CutSelectionSessionCommand getCommand() { - return new CutSelectionSessionCommand(copySelectionSessionCommand, deleteSelectionSessionCommand, sessionCommandManager, commandExecutedEvent); + return new CutSelectionSessionCommand(sessionCommandManager, commandExecutedEvent, sessionManager); } @Override diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/DeleteSelectionSessionCommandTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/DeleteSelectionSessionCommandTest.java index 3de9a8b35bf..f7fc3346a47 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/DeleteSelectionSessionCommandTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/DeleteSelectionSessionCommandTest.java @@ -23,6 +23,7 @@ import org.jboss.errai.ioc.client.api.ManagedInstance; import org.junit.Test; import org.junit.runner.RunWith; +import org.kie.workbench.common.stunner.core.client.api.SessionManager; import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvasHandler; import org.kie.workbench.common.stunner.core.client.canvas.event.selection.CanvasClearSelectionEvent; import org.kie.workbench.common.stunner.core.client.command.CanvasCommandFactory; @@ -34,7 +35,10 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -44,6 +48,9 @@ public class DeleteSelectionSessionCommandTest extends BaseSessionCommandKeyboar @Mock private Event canvasClearSelectionEventEvent; + @Mock + private SessionManager sessionManager; + @Mock private ClientSessionCommand.Callback callback; @@ -60,10 +67,11 @@ public class DeleteSelectionSessionCommandTest extends BaseSessionCommandKeyboar @Override public void setup() { + when(sessionManager.getCurrentSession()).thenReturn(session); super.setup(); when(metadata.getDefinitionSetId()).thenReturn(DEFINITION_SET_ID); - when(definitionUtils.getQualifier(eq(DEFINITION_SET_ID))).thenReturn(qualifier); + when(definitionUtils.getQualifier(anyString())).thenReturn(qualifier); when(canvasCommandFactoryInstance.select(eq(qualifier))).thenReturn(canvasCommandFactoryInstance); when(canvasCommandFactoryInstance.isUnsatisfied()).thenReturn(false); when(canvasCommandFactoryInstance.get()).thenReturn(canvasCommandFactory); @@ -71,16 +79,18 @@ public void setup() { @Override protected AbstractClientSessionCommand getCommand() { - return new DeleteSelectionSessionCommand(sessionCommandManager, - canvasCommandFactoryInstance, - canvasClearSelectionEventEvent, - definitionUtils); + return DeleteSelectionSessionCommand.getInstance(sessionCommandManager, + canvasCommandFactoryInstance, + canvasClearSelectionEventEvent, + definitionUtils, sessionManager); } @Test public void testClearSessionInvoked() { DeleteSelectionSessionCommand deleteCommand = (DeleteSelectionSessionCommand) this.command; + when(definitionUtils.getQualifier(anyString())).thenReturn(qualifier); + deleteCommand.bind(session); deleteCommand.execute(callback); @@ -88,6 +98,26 @@ public void testClearSessionInvoked() { verify(selectionControl).clearSelection(); } + @Test + public void testExecuteNullSessionAndNullSelectionControl() { + DeleteSelectionSessionCommand deleteCommand = (DeleteSelectionSessionCommand) this.command; + deleteCommand.execute(callback); + // if session null, then it should never fire event + + verify(canvasClearSelectionEventEvent, never()).fire(any()); + + deleteCommand.bind(session); + when(session.getSelectionControl()).thenReturn(null); + deleteCommand.execute(callback); + // if session null, then it should never fire event + verify(canvasClearSelectionEventEvent, never()).fire(any()); + } + + @Test(expected = IllegalStateException.class) + public void testEmptyConstructor() { + DeleteSelectionSessionCommand del = new DeleteSelectionSessionCommand(); + } + @Override protected KeyboardEvent.Key[] getExpectedKeys() { return new KeyboardEvent.Key[]{KeyboardEvent.Key.DELETE}; diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/PasteSelectionSessionCommandTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/PasteSelectionSessionCommandTest.java index 8f4a698d6cb..5c15259d594 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/PasteSelectionSessionCommandTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/PasteSelectionSessionCommandTest.java @@ -32,6 +32,7 @@ import org.junit.runner.RunWith; import org.kie.workbench.common.stunner.core.TestingGraphInstanceBuilder; import org.kie.workbench.common.stunner.core.TestingGraphMockHandler; +import org.kie.workbench.common.stunner.core.client.api.SessionManager; 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.command.CloneConnectorCommand; @@ -155,7 +156,7 @@ public class PasteSelectionSessionCommandTest extends BaseSessionCommandKeyboard private CloneConnectorCommand cloneConnectorCommand; @Mock - private CopySelectionSessionCommand copySelectionSessionCommand; + private SessionManager sessionManager; @Mock private org.uberfire.mvp.Command statusCallback; @@ -200,6 +201,7 @@ public void setUp() throws Exception { when(clone2.getUUID()).thenReturn(CLONE2_UUID); when(session.getClipboardControl()).thenReturn(clipboardControl); when(sessionCommandManager.getRegistry()).thenReturn(commandRegistry); + when(sessionManager.getCurrentSession()).thenReturn(session); cloneMap = new HashMap() {{ put(node, clone); @@ -233,6 +235,8 @@ public void execute() { //same parent clipboardControl.set(graphInstance.startNode); when(selectionControl.getSelectedItems()).thenReturn(Arrays.asList(node.getUUID())); + CopySelectionSessionCommand.getInstance(sessionManager).bind(session); + pasteSelectionSessionCommand.execute(callback); verify(canvasCommandFactory, times(1)) .cloneNode(eq(node), eq(graphInstance.parentNode.getUUID()), eq(new Point2D(X, DEFAULT_PADDING + Y + NODE_SIZE)), any()); @@ -314,6 +318,7 @@ public void executeWithMultiSelection() { //Executing the command clipboardControl.set(graphInstance.startNode, graphInstance.edge1, graphInstance.intermNode); when(selectionControl.getSelectedItems()).thenReturn(Arrays.asList(graphInstance.startNode.getUUID(), graphInstance.edge1.getUUID(), graphInstance.intermNode.getUUID())); + CopySelectionSessionCommand.getInstance(sessionManager).bind(session); pasteSelectionSessionCommand.execute(callback); @@ -392,6 +397,7 @@ public void executeWithMultiSelectionWithEdgesClipboard() { //Executing the command clipboardControl.set(graphInstance.startNode, graphInstance.edge1, graphInstance.intermNode); when(selectionControl.getSelectedItems()).thenReturn(Arrays.asList(graphInstance.startNode.getUUID(), graphInstance.edge1.getUUID(), graphInstance.intermNode.getUUID())); + CopySelectionSessionCommand.getInstance(sessionManager).bind(session); pasteSelectionSessionCommand.execute(callback); verify(canvasCommandFactory, times(1)) .cloneNode(eq(graphInstance.startNode), eq(graphInstance.parentNode.getUUID()), eq(new Point2D(X, DEFAULT_PADDING + Y + NODE_SIZE)), any()); @@ -459,8 +465,8 @@ public void testFoundOnCanvasAndClipboard() { @Override protected PasteSelectionSessionCommand getCommand() { return new PasteSelectionSessionCommand(sessionCommandManager, canvasCommandFactoryInstance, - selectionEvent, copySelectionSessionCommand, - definitionUtils); + selectionEvent, + definitionUtils, sessionManager); } @Override diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/SessionSingletonCommandsFactoryTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/SessionSingletonCommandsFactoryTest.java new file mode 100644 index 00000000000..c911f2a2044 --- /dev/null +++ b/kie-wb-common-stunner/kie-wb-common-stunner-core/kie-wb-common-stunner-commons/kie-wb-common-stunner-client-common/src/test/java/org/kie/workbench/common/stunner/core/client/session/command/impl/SessionSingletonCommandsFactoryTest.java @@ -0,0 +1,139 @@ +/* + * 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.session.command.impl; + +import javax.enterprise.event.Event; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.kie.workbench.common.stunner.core.client.api.SessionManager; +import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvasHandler; +import org.kie.workbench.common.stunner.core.client.command.SessionCommandManager; +import org.kie.workbench.common.stunner.core.client.session.impl.EditorSession; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class SessionSingletonCommandsFactoryTest { + + @Mock + protected EditorSession session; + + @Mock + protected EditorSession session2; + + @Mock + protected SessionManager sessionManager; + + @Mock + protected SessionCommandManager sessionCommandManager; + + @Mock + protected Event commandExecutedEvent; + + @Before + public void setUp() throws Exception { + when(sessionManager.getCurrentSession()).thenReturn(session); + } + + @Test(expected = IllegalStateException.class) + public void testOnlyOneInstancePerSessionCopy() { + final CopySelectionSessionCommand copySelectionSessionCommand = new CopySelectionSessionCommand(null, sessionManager); + final CopySelectionSessionCommand copySelectionSessionCommand2 = new CopySelectionSessionCommand(null, sessionManager); + } + + @Test(expected = UnsupportedOperationException.class) + public void testOnlyAllowedCommands() { + final CutSelectionSessionCommand cut = new CutSelectionSessionCommand(sessionCommandManager, commandExecutedEvent, sessionManager); + SessionSingletonCommandsFactory.createOrPut(cut, sessionManager); + } + + @Test + public void testNewInstancesOndifferentSessionsCopy() { + final CopySelectionSessionCommand copySelectionSessionCommand = new CopySelectionSessionCommand(null, sessionManager); + when(sessionManager.getCurrentSession()).thenReturn(session2); + final CopySelectionSessionCommand copySelectionSessionCommand2 = new CopySelectionSessionCommand(null, sessionManager); + assertTrue(copySelectionSessionCommand.hashCode() != copySelectionSessionCommand2.hashCode()); + } + + @Test + public void testGetInstancesCopy() { + final CopySelectionSessionCommand copySelectionSessionCommand = new CopySelectionSessionCommand(null, sessionManager); + final CopySelectionSessionCommand instanceCopy = SessionSingletonCommandsFactory.getInstanceCopy(null, sessionManager); + + assertEquals(copySelectionSessionCommand, instanceCopy); + + when(sessionManager.getCurrentSession()).thenReturn(session2); + final CopySelectionSessionCommand copySelectionSessionCommand2 = new CopySelectionSessionCommand(null, sessionManager); + final CopySelectionSessionCommand instanceCopy2 = SessionSingletonCommandsFactory.getInstanceCopy(null, sessionManager); + + assertEquals(copySelectionSessionCommand2, instanceCopy2); + } + + @Test + public void testGetInstancesOnFetchCopy() { + final CopySelectionSessionCommand instanceCopy = SessionSingletonCommandsFactory.getInstanceCopy(null, sessionManager); + final CopySelectionSessionCommand instanceCopy2 = SessionSingletonCommandsFactory.getInstanceCopy(null, sessionManager); + + assertEquals(instanceCopy, instanceCopy2); + } + + @Test(expected = IllegalStateException.class) + public void testGetInstancesOnFetchCopyError() { + final CopySelectionSessionCommand instanceCopy = SessionSingletonCommandsFactory.getInstanceCopy(null, sessionManager); + final CopySelectionSessionCommand instanceCopy2 = new CopySelectionSessionCommand(null, sessionManager); + } + + @Test(expected = IllegalStateException.class) + public void testOnlyOneInstancePerSessionDelete() { + final DeleteSelectionSessionCommand deleteSelectionSessionCommand = new DeleteSelectionSessionCommand(null, null, null, null, sessionManager); + final DeleteSelectionSessionCommand deleteSelectionSessionCommand2 = new DeleteSelectionSessionCommand(null, null, null, null, sessionManager); + } + + @Test + public void testNewInstancesOndifferentSessionsDelete() { + final DeleteSelectionSessionCommand deleteSelectionSessionCommand = new DeleteSelectionSessionCommand(null, null, null, null, sessionManager); + when(sessionManager.getCurrentSession()).thenReturn(session2); + final DeleteSelectionSessionCommand deleteSelectionSessionCommand2 = new DeleteSelectionSessionCommand(null, null, null, null, sessionManager); + assertTrue(deleteSelectionSessionCommand.hashCode() != deleteSelectionSessionCommand2.hashCode()); + } + + @Test + public void testGetInstancesDelete() { + final DeleteSelectionSessionCommand deleteSelectionSessionCommand = new DeleteSelectionSessionCommand(null, null, null, null, sessionManager); + final DeleteSelectionSessionCommand instanceCopy = SessionSingletonCommandsFactory.getInstanceDelete(null, null, null, null, sessionManager); + + assertEquals(deleteSelectionSessionCommand, instanceCopy); + + when(sessionManager.getCurrentSession()).thenReturn(session2); + final DeleteSelectionSessionCommand deleteSelectionSessionCommand2 = new DeleteSelectionSessionCommand(null, null, null, null, sessionManager); + final DeleteSelectionSessionCommand instanceCopy2 = SessionSingletonCommandsFactory.getInstanceDelete(null, null, null, null, sessionManager); + + assertEquals(deleteSelectionSessionCommand2, instanceCopy2); + } + + @Test(expected = IllegalStateException.class) + public void testGetInstancesOnFetchDelete() { + final DeleteSelectionSessionCommand instanceCopy = SessionSingletonCommandsFactory.getInstanceDelete(null, null, null, null, sessionManager); + final DeleteSelectionSessionCommand instanceCopy2 = new DeleteSelectionSessionCommand(null, null, null, null, sessionManager); + } +} \ No newline at end of file diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/FormPropertiesWidget.java b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/FormPropertiesWidget.java index dc758b102c0..bd55005a24c 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/FormPropertiesWidget.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/FormPropertiesWidget.java @@ -36,8 +36,12 @@ import org.kie.workbench.common.stunner.core.diagram.Diagram; import org.kie.workbench.common.stunner.core.diagram.Metadata; import org.kie.workbench.common.stunner.core.domainobject.DomainObject; +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.Node; import org.kie.workbench.common.stunner.core.graph.content.definition.Definition; +import org.kie.workbench.common.stunner.core.graph.content.view.Point2D; +import org.kie.workbench.common.stunner.core.graph.util.GraphUtils; import org.kie.workbench.common.stunner.core.util.DefinitionUtils; import org.kie.workbench.common.stunner.forms.client.event.FormPropertiesOpened; import org.kie.workbench.common.stunner.forms.client.widgets.container.FormsContainer; @@ -100,6 +104,16 @@ public void clear(String graphUuid, Element element) { public void clearAll(String graphUuid) { formsContainer.clearDiagramDisplayers(graphUuid); } + + @Override + public void resetCache() { + resetLastElementRenderedCache(); + } + + @Override + public boolean areLastPositionsSameForElement(final Element element) { + return areLastPositionsForSameElementSame(element); + } }); view.init(this); } @@ -148,13 +162,33 @@ public void show() { @SuppressWarnings("unchecked") public void show(final Command callback) { + resetLastElementRenderedCache(); formSessionHandler.show(callback); } + private Element lastElement = null; + private Point2D lastPosition = null; + + public void resetLastElementRenderedCache() { + lastElement = null; + lastPosition = null; + } + + public boolean areLastPositionsForSameElementSame(final Element element) { + final Point2D computedPosition = GraphUtils.getComputedPosition((Node) element); + return (lastElement != null && lastElement.getUUID().equals(element.getUUID()) && computedPosition.equals(lastPosition)); + } + private void show(final String graphUuid, final Element> element, final Command callback) { if (element != null) { + + if (lastElement != null && lastElement.getUUID().equals(element.getUUID())) { + lastPosition = GraphUtils.getComputedPosition((Node) element); + return; + } + final String uuid = element.getUUID(); final Diagram diagram = formSessionHandler.getDiagram(); if (Objects.isNull(diagram)) { @@ -170,6 +204,7 @@ private void show(final String graphUuid, return; } final Object definition = content.getDefinition(); + final RenderMode renderMode = formSessionHandler.getSession() instanceof EditorSession ? RenderMode.EDIT_MODE : RenderMode.READ_ONLY_MODE; formsContainer.render(graphUuid, @@ -191,6 +226,8 @@ private void show(final String graphUuid, }, renderMode); final String name = definitionUtils.getName(definition); propertiesOpenedEvent.fire(new FormPropertiesOpened(formSessionHandler.getSession(), uuid, name)); + lastElement = element; + lastPosition = GraphUtils.getComputedPosition((Node) element); } } diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/FormsCanvasSessionHandler.java b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/FormsCanvasSessionHandler.java index c9e63d5a8c6..87aa1a28f50 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/FormsCanvasSessionHandler.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/FormsCanvasSessionHandler.java @@ -16,6 +16,7 @@ package org.kie.workbench.common.stunner.forms.client.widgets; +import java.util.List; import java.util.Objects; import java.util.Optional; @@ -24,6 +25,7 @@ import javax.enterprise.event.Observes; import javax.inject.Inject; +import com.google.gwt.user.client.Timer; import org.kie.workbench.common.forms.dynamic.service.shared.RenderMode; import org.kie.workbench.common.stunner.core.api.DefinitionManager; import org.kie.workbench.common.stunner.core.client.canvas.AbstractCanvasHandler; @@ -56,12 +58,15 @@ @Dependent public class FormsCanvasSessionHandler { + /** + * An ORDERED array of feature providers supported. + */ + private static final FormFeaturesSessionProvider[] FEATURE_SESSION_PROVIDERS = new FormFeaturesSessionProvider[]{new FormFeaturesFullSessionProvider(), new FormFeaturesReadOnlySessionProvider()}; private final DefinitionManager definitionManager; private final CanvasCommandFactory commandFactory; private final FormsCanvasListener canvasListener; private final FormsDomainObjectCanvasListener domainObjectCanvasListener; private final SessionCommandManager sessionCommandManager; - private ClientSession session; private FormFeaturesSessionProvider featuresSessionProvider; private FormRenderer renderer; @@ -164,7 +169,7 @@ private boolean execute(CanvasCommand command, FormsListe void onRefreshFormPropertiesEvent(@Observes RefreshFormPropertiesEvent event) { checkNotNull("event", event); - if (checkSession(event.getSession())) { + if (checkSession(event.getSession())) { // Possible Improvement if (event.hasUuid()) { final String uuid = event.getUuid(); final Element> element = CanvasLayoutUtils.getElement(getCanvasHandler(), uuid); @@ -178,10 +183,22 @@ void onRefreshFormPropertiesEvent(@Observes RefreshFormPropertiesEvent event) { void onCanvasSelectionEvent(@Observes CanvasSelectionEvent event) { checkNotNull("event", event); + if (checkCanvasHandler(event.getCanvasHandler())) { if (event.getIdentifiers().size() == 1) { final String uuid = event.getIdentifiers().iterator().next(); final Element> element = CanvasLayoutUtils.getElement(getCanvasHandler(), uuid); + final Timer timer = new Timer() { + @Override + public void run() { + render(element); + } + }; + + timer.schedule(100); + } else { + // Select root canvas + final Element> element = CanvasLayoutUtils.getElement(getCanvasHandler(), this.getDiagram().getMetadata().getCanvasRootUUID()); render(element); } } @@ -267,6 +284,121 @@ private boolean checkSession(final ClientSession s) { return checkCanvasHandler(s.getCanvasHandler()); } + private FormFeaturesSessionProvider getFeaturesSessionProvider(final ClientSession session) { + for (final FormFeaturesSessionProvider featureSessionProvider : FEATURE_SESSION_PROVIDERS) { + if (featureSessionProvider.supports(session)) { + return featureSessionProvider; + } + } + return null; + } + + private interface FormsListener { + + void startProcessing(); + + void endProcessing(); + } + + /** + * Provides form features to the {@link FormsCanvasSessionHandler} + */ + public interface FormRenderer { + + /** + * Renders the form properties panel for the given {@link Element} + * @param graphUuid the current {@link Graph} UUID + * @param element the {@link Element} to render properties form + * @param callback a {@link Command} to execute after a property value change + */ + void render(String graphUuid, Element element, Command callback); + + /** + * Renders the form properties panel for the given {@link Object} + * @param graphUuid the current {@link Graph} UUID + * @param domainObject the {@link DomainObject} to render properties form + * @param callback a {@link Command} to execute after a property value change + */ + void render(String graphUuid, DomainObject domainObject, Command callback); + + /** + * Clears the properties form for the given {@link Element} + * @param graphUuid the current {@link Graph} UUID + * @param element the {@link Element} to clear its properties form + */ + void clear(String graphUuid, Element element); + + /** + * Clears all properties forms for the current {@link Graph} + * @param graphUuid the current {@link Graph} UUID + */ + void clearAll(String graphUuid); + + /** + * Resets Cache + */ + void resetCache(); + + /** + * Checks if Positions are the same for the last element rendered and if Elements are the same + * @param element Element to be checked + * @return True if Elements are the same and their positions or False if they are not + */ + boolean areLastPositionsSameForElement(final Element element); + } + + /** + * This type provides required features that are specific for concrete client + * session types. + */ + private interface FormFeaturesSessionProvider { + + /** + * Returns true is the session type is supported. + */ + boolean supports(ClientSession type); + + /** + * Returns the session's selection control instance, if not available, it + * returns null. + */ + SelectionControl getSelectionControl(S session); + } + + private static class FormFeaturesReadOnlySessionProvider implements FormFeaturesSessionProvider { + + @Override + public boolean supports(final ClientSession type) { + return type instanceof ViewerSession; + } + + @Override + public SelectionControl getSelectionControl(final ViewerSession session) { + return cast(session).getSelectionControl(); + } + + private ViewerSession cast(final ClientSession session) { + return (ViewerSession) session; + } + } + + private static class FormFeaturesFullSessionProvider implements FormFeaturesSessionProvider { + + @Override + public boolean supports(final ClientSession type) { + return type instanceof EditorSession; + } + + @Override + public SelectionControl getSelectionControl(final EditorSession session) { + return cast(session).getSelectionControl(); + } + + private EditorSession cast(final ClientSession session) { + return (EditorSession) session; + } + } + /** * A listener that refresh the forms once an element has been updated, * but it skips the refreshing when updates come from this forms widget instance. @@ -306,11 +438,24 @@ public void endProcessing() { @Override public void update(final Element item) { + + if (!Objects.isNull(renderer) && renderer.areLastPositionsSameForElement(item)) { + renderer.resetCache(); + } + if (!areFormsProcessing) { render(item); } } + @Override + public void updateBatch(final List queue) { + if (!queue.isEmpty()) { + // No point in updating lots of elements, just last one or if single the only one + update(queue.get(queue.size() - 1)); + } + } + @Override public void deregister(final Element element) { if (null != renderer) { @@ -378,112 +523,4 @@ public void update(final DomainObject domainObject) { } } } - - private interface FormsListener { - - void startProcessing(); - - void endProcessing(); - } - - private FormFeaturesSessionProvider getFeaturesSessionProvider(final ClientSession session) { - for (final FormFeaturesSessionProvider featureSessionProvider : FEATURE_SESSION_PROVIDERS) { - if (featureSessionProvider.supports(session)) { - return featureSessionProvider; - } - } - return null; - } - - /** - * Provides form features to the {@link FormsCanvasSessionHandler} - */ - public interface FormRenderer { - - /** - * Renders the form properties panel for the given {@link Element} - * @param graphUuid the current {@link Graph} UUID - * @param element the {@link Element} to render properties form - * @param callback a {@link Command} to execute after a property value change - */ - void render(String graphUuid, Element element, Command callback); - - /** - * Renders the form properties panel for the given {@link Object} - * @param graphUuid the current {@link Graph} UUID - * @param domainObject the {@link DomainObject} to render properties form - * @param callback a {@link Command} to execute after a property value change - */ - void render(String graphUuid, DomainObject domainObject, Command callback); - - /** - * Clears the properties form for the given {@link Element} - * @param graphUuid the current {@link Graph} UUID - * @param element the {@link Element} to clear its properties form - */ - void clear(String graphUuid, Element element); - - /** - * Clears all properties forms for the current {@link Graph} - * @param graphUuid the current {@link Graph} UUID - */ - void clearAll(String graphUuid); - } - - /** - * An ORDERED array of feature providers supported. - */ - private static final FormFeaturesSessionProvider[] FEATURE_SESSION_PROVIDERS = new FormFeaturesSessionProvider[]{new FormFeaturesFullSessionProvider(), new FormFeaturesReadOnlySessionProvider()}; - - /** - * This type provides required features that are specific for concrete client - * session types. - */ - private interface FormFeaturesSessionProvider { - - /** - * Returns true is the session type is supported. - */ - boolean supports(ClientSession type); - - /** - * Returns the session's selection control instance, if not available, it - * returns null. - */ - SelectionControl getSelectionControl(S session); - } - - private static class FormFeaturesReadOnlySessionProvider implements FormFeaturesSessionProvider { - - @Override - public boolean supports(final ClientSession type) { - return type instanceof ViewerSession; - } - - @Override - public SelectionControl getSelectionControl(final ViewerSession session) { - return cast(session).getSelectionControl(); - } - - private ViewerSession cast(final ClientSession session) { - return (ViewerSession) session; - } - } - - private static class FormFeaturesFullSessionProvider implements FormFeaturesSessionProvider { - - @Override - public boolean supports(final ClientSession type) { - return type instanceof EditorSession; - } - - @Override - public SelectionControl getSelectionControl(final EditorSession session) { - return cast(session).getSelectionControl(); - } - - private EditorSession cast(final ClientSession session) { - return (EditorSession) session; - } - } } diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/container/FormsContainer.java b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/container/FormsContainer.java index f53dfaebc1f..5cb8be8c83c 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/container/FormsContainer.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/container/FormsContainer.java @@ -65,7 +65,6 @@ public void render(final String graphUuid, final Path diagramPath, final FieldChangeHandler changeHandler, final RenderMode renderMode) { - FormDisplayer displayer = getDisplayer(graphUuid, domainObjectUUID); displayer.render(domainObjectUUID, domainObject, diagramPath, changeHandler, renderMode); diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/container/displayer/FormDisplayer.java b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/container/displayer/FormDisplayer.java index 3244f33f227..956e6407663 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/container/displayer/FormDisplayer.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/main/java/org/kie/workbench/common/stunner/forms/client/widgets/container/displayer/FormDisplayer.java @@ -89,7 +89,6 @@ private void doRender(final String domainObjectUUID, final RenderMode renderMode) { final List previousExpandedCollapses = new ArrayList<>(); - if (renderer.isInitialized()) { // Collecting expanded collapses from current form to synchronize the new form collapses renderer.getCurrentForm().getFields() diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/test/java/org/kie/workbench/common/stunner/forms/client/widgets/FormPropertiesWidgetTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/test/java/org/kie/workbench/common/stunner/forms/client/widgets/FormPropertiesWidgetTest.java index 478f976d4a7..1c83d04ff3b 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/test/java/org/kie/workbench/common/stunner/forms/client/widgets/FormPropertiesWidgetTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/test/java/org/kie/workbench/common/stunner/forms/client/widgets/FormPropertiesWidgetTest.java @@ -54,9 +54,11 @@ import org.uberfire.mvp.Command; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -69,6 +71,7 @@ public class FormPropertiesWidgetTest { private static final String GRAPH_UUID = "graph1"; private static final String DIAGRAM_NAME = "diagram1"; private static final String ROOT_UUID = "root1"; + private static final String NODE2_UUID = "node2"; private static final String DOMAIN_OBJECT_UUID = "domainObject1"; private static final String DOMAIN_OBJECT_TRANSLATION_KEY = "domainObjectTranslationKey"; @@ -101,6 +104,8 @@ public class FormPropertiesWidgetTest { @Mock private NodeImpl node; @Mock + private NodeImpl node2; + @Mock private Definition nodeContent; @Mock private Object nodeDefObject; @@ -143,6 +148,8 @@ public void setup() throws Exception { when(node.getUUID()).thenReturn(ROOT_UUID); when(node.getContent()).thenReturn(nodeContent); when(nodeContent.getDefinition()).thenReturn(nodeDefObject); + when(node2.getUUID()).thenReturn(NODE2_UUID); + when(node2.getContent()).thenReturn(nodeContent); BindableProxyFactory.addBindableProxy(Object.class, proxyProvider); when(proxyProvider.getBindableProxy()).thenReturn((BindableProxy) proxy); @@ -268,4 +275,41 @@ public void testShowNullElement() { verify(formsContainer, never()).render(any(), any(), any(), any(), any(), any()); verify(command, never()).execute(); } + + @Test + public void testShowElement() { + tested.init(); + + verify(formsCanvasSessionHandler).setRenderer(formRendererArgumentCaptor.capture()); + final FormsCanvasSessionHandler.FormRenderer formRenderer = formRendererArgumentCaptor.getValue(); + + final Command command = mock(Command.class); + when(formsCanvasSessionHandler.getDiagram()).thenReturn(diagram); + + formRenderer.render(GRAPH_UUID, node, command); + formRenderer.render(GRAPH_UUID, node, command); + + verify(formsCanvasSessionHandler, never()).executeUpdateProperty(any(), any(), any()); + // Verify it is only rendered once, since the same item was already rendered + verify(formsContainer, atMost(1)).render(any(), any(), any(), any(), any(), any()); + } + + @Test + public void testAreElementsPositionSame() { + tested.init(); + + verify(formsCanvasSessionHandler).setRenderer(formRendererArgumentCaptor.capture()); + final FormsCanvasSessionHandler.FormRenderer formRenderer = formRendererArgumentCaptor.getValue(); + + final Command command = mock(Command.class); + when(formsCanvasSessionHandler.getDiagram()).thenReturn(diagram); + + formRenderer.render(GRAPH_UUID, node, command); + + assertEquals("Value is not the same ", tested.areLastPositionsForSameElementSame(node), true); + + formRenderer.render(GRAPH_UUID, node2, command); + assertEquals("Value is not the same ", tested.areLastPositionsForSameElementSame(node), false); + assertEquals("Value is not the same ", tested.areLastPositionsForSameElementSame(node2), true); + } } diff --git a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/test/java/org/kie/workbench/common/stunner/forms/client/widgets/FormsCanvasSessionHandlerTest.java b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/test/java/org/kie/workbench/common/stunner/forms/client/widgets/FormsCanvasSessionHandlerTest.java index 9b0477b4a78..af1c7e16f58 100644 --- a/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/test/java/org/kie/workbench/common/stunner/forms/client/widgets/FormsCanvasSessionHandlerTest.java +++ b/kie-wb-common-stunner/kie-wb-common-stunner-extensions/kie-wb-common-stunner-forms/kie-wb-common-stunner-forms-client/src/test/java/org/kie/workbench/common/stunner/forms/client/widgets/FormsCanvasSessionHandlerTest.java @@ -15,9 +15,13 @@ */ package org.kie.workbench.common.stunner.forms.client.widgets; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Optional; +import com.google.gwt.user.client.Timer; +import com.google.gwtmockito.GwtMockitoTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,7 +45,6 @@ import org.kie.workbench.common.stunner.forms.client.event.RefreshFormPropertiesEvent; import org.mockito.InOrder; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; import org.uberfire.mvp.Command; import static org.mockito.Matchers.any; @@ -51,11 +54,12 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -@RunWith(MockitoJUnitRunner.class) +@RunWith(GwtMockitoTestRunner.class) public class FormsCanvasSessionHandlerTest { private static final String GRAPH_UUID = "graph-uuid"; @@ -211,10 +215,14 @@ public void testOnCanvasSelectionEventSameSession() { handler.bind(session); canvasSelectionEvent = new CanvasSelectionEvent(abstractCanvasHandler, UUID); - handler.onCanvasSelectionEvent(canvasSelectionEvent); - verify(formRenderer).render(anyString(), eq(element), any(Command.class)); + new Timer() { + @Override + public void run() { + verify(formRenderer).render(anyString(), eq(element), any(Command.class)); + } + }.schedule(200); } @Test @@ -228,6 +236,52 @@ public void testOnCanvasSelectionEventSameSessionMultipleNodes() { verify(formRenderer, never()).render(anyString(), any(Element.class), any(Command.class)); } + @Test + public void testOnCanvasBatchUpdateMultiple() { + handler.bind(session); + when(formRenderer.areLastPositionsSameForElement(any())).thenReturn(true); + + final List queue = new ArrayList<>(); + + queue.add(mock(Element.class)); + queue.add(mock(Element.class)); + queue.add(mock(Element.class)); + + handler.getFormsCanvasListener().updateBatch(queue); + + // Will action on the very last item + verify(formRenderer, times(1)).resetCache(); + // Render will be called + } + + @Test + public void testOnCanvasBatchUpdateEmpty() { + handler.bind(session); + when(formRenderer.areLastPositionsSameForElement(any())).thenReturn(true); + + final List queue = new ArrayList<>(); + + handler.getFormsCanvasListener().updateBatch(queue); + + verify(formRenderer, never()).resetCache(); + } + + @Test + public void testOnCanvasBatchUpdateOne() { + handler.bind(session); + when(formRenderer.areLastPositionsSameForElement(any())).thenReturn(true); + + final List queue = new ArrayList<>(); + + queue.add(mock(Element.class)); + + handler.getFormsCanvasListener().updateBatch(queue); + + // Will action on the very last item + verify(formRenderer, times(1)).resetCache(); + // Render will be calleds + } + @Test public void testOnCanvasSelectionEventDifferentSession() { handler.bind(mock(EditorSession.class));