From 38004fdda70b083bee7ab0ea0c4de067be617ac3 Mon Sep 17 00:00:00 2001 From: Tobias Ortmayr Date: Tue, 23 Mar 2021 14:02:13 +0100 Subject: [PATCH] #197, #196: Improve dirty state handling (#101) The `SetDirtyStateAction` now also declares the reason which caused the dirty state change. Ensure that the `SetDirtyStateAction` is only sent once during a model update Part of https://github.com/eclipse-glsp/glsp/issues/197 Fixes https://github.com/eclipse-glsp/glsp/issues/196 --- .../actions/SaveModelActionHandler.java | 4 +- .../server/actions/SetDirtyStateAction.java | 21 ++++++++- .../server/diagram/DiagramConfiguration.java | 4 ++ .../core/model/ModelSubmissionHandler.java | 44 ++++++++++++++----- .../core/model/RequestModelActionHandler.java | 2 +- .../undoredo/UndoRedoActionHandler.java | 7 +-- .../operations/OperationActionHandler.java | 5 ++- 7 files changed, 65 insertions(+), 22 deletions(-) diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/SaveModelActionHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/SaveModelActionHandler.java index 73957585..53e1008d 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/SaveModelActionHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/SaveModelActionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019 EclipseSource and others. + * Copyright (c) 2019-2021 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -51,7 +51,7 @@ public List executeAction(final SaveModelAction action, final GModelStat } finally { modelSourceWatcher.continueWatching(modelState); } - return listOf(new SetDirtyStateAction(modelState.isDirty())); + return listOf(new SetDirtyStateAction(modelState.isDirty(), SetDirtyStateAction.Reason.SAVE)); } protected void saveModelState(final GModelState modelState) { diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/SetDirtyStateAction.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/SetDirtyStateAction.java index 9d45f661..09dad13c 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/SetDirtyStateAction.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/actions/SetDirtyStateAction.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2020 EclipseSource and others. + * Copyright (c) 2020-2021 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -16,10 +16,10 @@ package org.eclipse.glsp.server.actions; public class SetDirtyStateAction extends Action { - public static final String ID = "setDirtyState"; private boolean isDirty; + private String reason; public SetDirtyStateAction() { super(ID); @@ -30,8 +30,25 @@ public SetDirtyStateAction(final boolean isDirty) { this.isDirty = isDirty; } + public SetDirtyStateAction(final boolean isDirty, final String reason) { + this(isDirty); + this.reason = reason; + } + public boolean isDirty() { return isDirty; } public void setDirty(final boolean isDirty) { this.isDirty = isDirty; } + public String getReason() { return reason; } + + public void setReason(final String reason) { this.reason = reason; } + + public static class Reason { + public static final String OPERATION = "operation"; + public static final String UNDO = "undo"; + public static final String REDO = "redo"; + public static final String SAVE = "save"; + public static final String EXTERNAL = "external"; + } + } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/diagram/DiagramConfiguration.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/diagram/DiagramConfiguration.java index 2fadf7f5..e00a53cf 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/diagram/DiagramConfiguration.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/diagram/DiagramConfiguration.java @@ -48,4 +48,8 @@ default ShapeTypeHint createDefaultNodeTypeHint(final String elementId) { default boolean needsClientLayout() { return true; } + + default boolean animatedUpdate() { + return true; + } } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/core/model/ModelSubmissionHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/core/model/ModelSubmissionHandler.java index 9ac61d33..88e4642a 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/core/model/ModelSubmissionHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/core/model/ModelSubmissionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019 EclipseSource and others. + * Copyright (c) 2019-2021 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -15,6 +15,7 @@ ********************************************************************************/ package org.eclipse.glsp.server.features.core.model; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -55,28 +56,32 @@ public class ModelSubmissionHandler { *

* * @param modelState The model state to submit. + * @param reason The optional reason that caused the model update. * @return A list of actions to be processed in order to submit the model. */ - public List submitModel(final GModelState modelState) { + public List submitModel(final GModelState modelState, final String reason) { modelFactory.createGModel(modelState); modelState.getRoot().setRevision(modelState.getRoot().getRevision() + 1); DiagramConfiguration diagramConfiguration = diagramConfigurationRegistry.get(modelState); - if (diagramConfiguration.getLayoutKind() == ServerLayoutKind.AUTOMATIC) { - layoutEngine.layout(modelState); - } - if (diagramConfiguration.needsClientLayout()) { + boolean needsClientLayout = diagramConfiguration.needsClientLayout(); + if (needsClientLayout) { synchronized (modelLock) { return Arrays.asList(new RequestBoundsAction(modelState.getRoot()), - new SetDirtyStateAction(modelState.isDirty())); + new SetDirtyStateAction(modelState.isDirty(), reason)); } } - return submitModelDirectly(modelState); + return submitModelDirectly(modelState, reason); + } + + public List submitModel(final GModelState modelState) { + return submitModel(modelState, null); } /** * Returns a list of actions to directly update the client-side model without any server- or client-side layouting. *

- * Typically {@link ActionHandler action handlers} don't invoke this method but use {@link #submitModel(GModelState)} + * Typically {@link ActionHandler action handlers} don't invoke this method but use + * {@link #submitModel(GModelState,String)} * instead, as this is only used to eventually submit the model on the client directly after all layouting is already * performed before. The only foreseen caller of this method is {@link ComputedBoundsActionHandler}. *

@@ -87,15 +92,30 @@ public List submitModel(final GModelState modelState) { *

* * @param modelState The model state to submit. + * @param reason The optional reason that caused the model update. * @return A list of actions to be processed in order to submit the model. */ - public List submitModelDirectly(final GModelState modelState) { + public List submitModelDirectly(final GModelState modelState, final String reason) { GModelRoot gModel = modelState.getRoot(); - Action action = gModel.getRevision() == 0 ? new SetModelAction(gModel) : new UpdateModelAction(gModel); + DiagramConfiguration diagramConfiguration = diagramConfigurationRegistry.get(modelState); + if (diagramConfiguration.getLayoutKind() == ServerLayoutKind.AUTOMATIC) { + layoutEngine.layout(modelState); + } + Action modelAction = gModel.getRevision() == 0 ? new SetModelAction(gModel) + : new UpdateModelAction(gModel, diagramConfiguration.animatedUpdate()); synchronized (modelLock) { - return Arrays.asList(action, new SetDirtyStateAction(modelState.isDirty())); + List result = new ArrayList<>(); + result.add(modelAction); + if (!diagramConfiguration.needsClientLayout()) { + result.add(new SetDirtyStateAction(modelState.isDirty(), reason)); + } + return result; } } + public List submitModelDirectly(final GModelState modelState) { + return submitModelDirectly(modelState, null); + } + public synchronized Object getModelLock() { return modelLock; } } diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/core/model/RequestModelActionHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/core/model/RequestModelActionHandler.java index 8a773a33..745fba6d 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/core/model/RequestModelActionHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/core/model/RequestModelActionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019 EclipseSource and others. + * Copyright (c) 2019-2021 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/undoredo/UndoRedoActionHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/undoredo/UndoRedoActionHandler.java index b247979d..adf739ad 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/undoredo/UndoRedoActionHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/features/undoredo/UndoRedoActionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019 EclipseSource and others. + * Copyright (c) 2019-2021 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -20,6 +20,7 @@ import org.apache.log4j.Logger; import org.eclipse.glsp.server.actions.Action; import org.eclipse.glsp.server.actions.ActionHandler; +import org.eclipse.glsp.server.actions.SetDirtyStateAction; import org.eclipse.glsp.server.features.core.model.ModelSubmissionHandler; import org.eclipse.glsp.server.model.GModelState; @@ -36,10 +37,10 @@ public class UndoRedoActionHandler implements ActionHandler { public List execute(final Action action, final GModelState modelState) { if (action instanceof UndoAction && modelState.canUndo()) { modelState.undo(); - return modelSubmissionHandler.submitModel(modelState); + return modelSubmissionHandler.submitModel(modelState, SetDirtyStateAction.Reason.UNDO); } else if (action instanceof RedoAction && modelState.canRedo()) { modelState.redo(); - return modelSubmissionHandler.submitModel(modelState); + return modelSubmissionHandler.submitModel(modelState, SetDirtyStateAction.Reason.REDO); } LOG.warn("Cannot undo or redo"); return none(); diff --git a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationActionHandler.java b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationActionHandler.java index 6c2669de..657a5e9f 100644 --- a/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationActionHandler.java +++ b/plugins/org.eclipse.glsp.server/src/org/eclipse/glsp/server/operations/OperationActionHandler.java @@ -1,5 +1,5 @@ /******************************************************************************** - * Copyright (c) 2019 EclipseSource and others. + * Copyright (c) 2019-2021 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -20,6 +20,7 @@ import org.eclipse.glsp.server.actions.Action; import org.eclipse.glsp.server.actions.BasicActionHandler; +import org.eclipse.glsp.server.actions.SetDirtyStateAction; import org.eclipse.glsp.server.features.core.model.ModelSubmissionHandler; import org.eclipse.glsp.server.internal.gmodel.commandstack.GModelRecordingCommand; import org.eclipse.glsp.server.model.GModelState; @@ -57,7 +58,7 @@ protected List executeHandler(final Operation operation, final Operation GModelRecordingCommand command = new GModelRecordingCommand(modelState.getRoot(), handler.getLabel(), () -> handler.execute(operation, modelState)); modelState.execute(command); - return modelSubmissionHandler.submitModel(modelState); + return modelSubmissionHandler.submitModel(modelState, SetDirtyStateAction.Reason.OPERATION); } public static Optional getOperationHandler(final Operation operation,