Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JBPM 8836 : Improve Performance of Copy/Cut and Paste Operations #2983

Merged
merged 9 commits into from Nov 26, 2019
Expand Up @@ -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;
Expand Down Expand Up @@ -110,6 +109,10 @@ public LocationControlImpl(final CanvasCommandFactory<AbstractCanvasHandler> can
this.selectionEvent = selectionEvent;
}

public Collection<String> getSelectedIDs() {
return selectedIDs;
}

@Override
public void bind(final EditorSession session) {
// Keyboard event handling.
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {

}
};

Expand Down
Expand Up @@ -50,7 +50,7 @@ public DragProxy<Layer, IPrimitive<?>, DragProxyCallback> show(final IPrimitive<
item,
x,
y,
200,
1,
new org.kie.workbench.common.stunner.lienzo.primitive.PrimitiveDragProxy.Callback() {

@Override
Expand All @@ -63,6 +63,7 @@ public void onStart(final int x,
@Override
public void onMove(final int x,
final int y) {

callback.onMove(x,
y);
}
Expand Down
Expand Up @@ -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;
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -141,6 +142,12 @@ public class LocationControlImplTest {
@Mock
private Node element;

@Mock
private Node<View<?>, Edge> node;

@Mock
private View nodeContent;

@Mock
private View elementContent;

Expand Down Expand Up @@ -234,6 +241,8 @@ public void testRegisterAndSetBounds() {
ArgumentCaptor<DragHandler> 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<CanvasSelectionEvent> canvasSelectionEventArgumentCaptor = forClass(CanvasSelectionEvent.class);
verify(canvasSelectionEvent).fire(canvasSelectionEventArgumentCaptor.capture());
assertTrue(canvasSelectionEventArgumentCaptor.getValue().getIdentifiers().contains(element.getUUID()));
Expand Down Expand Up @@ -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);
Expand Down
Expand Up @@ -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;

Expand All @@ -26,4 +28,11 @@ public interface CanvasElementListener extends CanvasListener<CanvasHandler, Ele
*/
default void update(Element item) {
}

/**
* Batch Updates Elements
* @param queue Queue of Items to be updated
*/
default void updateBatch(final List<Element> queue) {
}
}
Expand Up @@ -31,7 +31,7 @@ public class StunnerPreferences implements BasePreference<StunnerPreferences>,
@Override
public StunnerPreferences defaultValue(final StunnerPreferences defaultValue) {
defaultValue.diagramEditorPreferences.setAutoHidePalettePanel(false);
defaultValue.diagramEditorPreferences.setEnableHiDPI(false);
defaultValue.diagramEditorPreferences.setEnableHiDPI(true);
return defaultValue;
}

Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Element> queue) {
for (final CanvasElementListener instance : listeners) {
instance.update(candidate);
instance.updateBatch(queue);
}
}

Expand Down
Expand Up @@ -124,6 +124,8 @@ private CommandResult<CanvasViolation> 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;
Expand Down
Expand Up @@ -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));
}
Expand Down Expand Up @@ -254,6 +255,7 @@ public void onShapeRemoved(final CanvasShapeRemovedEvent shapeRemovedEvent) {
}
if (getCanvas().equals(shapeRemovedEvent.getCanvas())) {
items.remove(shapeRemovedEvent.getShape().getUUID());
lastSelected = "";
}
}

Expand All @@ -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 &&
Expand Down Expand Up @@ -301,9 +304,21 @@ protected String getRootUUID() {
return canvasHandler.getDiagram().getMetadata().getCanvasRootUUID();
}

private String lastSelected = "";

private void fireSelectedItemsEvent() {
final Collection<String> 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));
}
Expand Down
Expand Up @@ -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());
Expand All @@ -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();
}
}
Expand Down
Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -101,20 +103,46 @@ public void setCommandListener(final CommandListener<H, CanvasViolation> listene

private CommandResult<CanvasViolation> runInContext(final AbstractCanvasHandler context,
final Supplier<CommandResult<CanvasViolation>> function) {
final ContextualGraphCommandExecutionContext graphExecutionContext = newGraphExecutionContext(context);
context.setGraphExecutionContext(() -> newGraphExecutionContext(context));

final List<Element> queue = new ArrayList<>();
final List<QueueGraphExecutionContext> contextsCreated = new ArrayList<>();

context.setGraphExecutionContext(() -> {
final QueueGraphExecutionContext queueGraphExecutionContext2 = newQueueGraphExecutionContext(context);
contextsCreated.add(queueGraphExecutionContext2);
return queueGraphExecutionContext2;
});

final CommandResult<CanvasViolation> 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")
Expand Down