From 1c5b9dec86be0cffaab448c5aeb32226d4f055b7 Mon Sep 17 00:00:00 2001 From: leodennis Date: Thu, 21 Nov 2019 22:51:34 +0100 Subject: [PATCH 1/8] Resloves #37 Signed-off-by: leodennis --- client/sprotty-ecore/css/diagram.css | 29 +++ client/sprotty-ecore/src/di.config.ts | 5 +- .../src/features/edit-label-autocomplete.ts | 177 ++++++++++++++++++ .../diagram/ecore-diagram-configuration.ts | 10 +- .../ecore-glsp-theia-diagram-server.ts | 30 +++ .../glsp/ecore/EcoreGLSPModule.java | 10 + .../ecore/actions/AttributeTypesAction.java | 28 +++ .../ecore/actions/EcoreActionProvider.java | 44 +++++ .../actions/ReturnAttributeTypesAction.java | 43 +++++ .../EcoreGetAttributeTypesActionHandler.java | 57 ++++++ .../EcoreLabelEditOperationHandler.java | 45 ++++- 11 files changed, 469 insertions(+), 9 deletions(-) create mode 100644 client/sprotty-ecore/src/features/edit-label-autocomplete.ts create mode 100644 client/theia-ecore/src/browser/diagram/ecore-glsp-theia-diagram-server.ts create mode 100644 server/src/main/java/com/eclipsesource/glsp/ecore/actions/AttributeTypesAction.java create mode 100644 server/src/main/java/com/eclipsesource/glsp/ecore/actions/EcoreActionProvider.java create mode 100644 server/src/main/java/com/eclipsesource/glsp/ecore/actions/ReturnAttributeTypesAction.java create mode 100644 server/src/main/java/com/eclipsesource/glsp/ecore/handler/EcoreGetAttributeTypesActionHandler.java diff --git a/client/sprotty-ecore/css/diagram.css b/client/sprotty-ecore/css/diagram.css index 330bcde..f267fe3 100644 --- a/client/sprotty-ecore/css/diagram.css +++ b/client/sprotty-ecore/css/diagram.css @@ -181,3 +181,32 @@ svg { .italic { font-style: italic; } + +.autocomplete { + position: relative; + display: inline-block; + } +.autocomplete-items { + position: absolute; + border: 1px solid #d4d4d4; + color: black; + border-bottom: none; + border-top: none; + z-index: 99; + top: 100%; + left: 0; + right: 0; + } + .autocomplete-items div { + padding: 10px; + cursor: pointer; + background-color: #fff; + border-bottom: 1px solid #d4d4d4; + } + .autocomplete-items div:hover { + background-color: #e9e9e9; + } + .autocomplete-active { + background-color: DodgerBlue !important; + color: #ffffff; + } \ No newline at end of file diff --git a/client/sprotty-ecore/src/di.config.ts b/client/sprotty-ecore/src/di.config.ts index ca8589e..70aa05a 100644 --- a/client/sprotty-ecore/src/di.config.ts +++ b/client/sprotty-ecore/src/di.config.ts @@ -68,7 +68,8 @@ import { } from "@glsp/sprotty-client/lib"; import executeCommandModule from "@glsp/sprotty-client/lib/features/execute/di.config"; import { Container, ContainerModule } from "inversify"; - +import {EditLabelUIAutocomplete} from "./features/edit-label-autocomplete" +import { EditLabelUI } from "sprotty/lib"; import { LabelSelectionFeedback } from "./feedback"; import { Icon, LabeledNode, SEditableLabel, SLabelNode } from "./model"; import { ArrowEdgeView, ClassNodeView, CompositionEdgeView, IconView, InheritanceEdgeView, LabelNodeView } from "./views"; @@ -77,6 +78,8 @@ export default (containerId: string) => { const classDiagramModule = new ContainerModule((bind, unbind, isBound, rebind) => { rebind(TYPES.ILogger).to(ConsoleLogger).inSingletonScope(); rebind(TYPES.LogLevel).toConstantValue(LogLevel.info); + rebind(EditLabelUI).to(EditLabelUIAutocomplete); + const context = { bind, unbind, isBound, rebind }; bind(TYPES.IVNodePostprocessor).to(LabelSelectionFeedback); configureModelElement(context, 'graph', GLSPGraph, SGraphView); diff --git a/client/sprotty-ecore/src/features/edit-label-autocomplete.ts b/client/sprotty-ecore/src/features/edit-label-autocomplete.ts new file mode 100644 index 0000000..05e65fb --- /dev/null +++ b/client/sprotty-ecore/src/features/edit-label-autocomplete.ts @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ******************************************************************************/ +import { RequestAction, ResponseAction, generateRequestId} from "sprotty/lib"; +import { inject, injectable } from "inversify"; +import { matchesKeystroke } from "sprotty/lib/utils/keyboard"; +import { EditLabelUI } from "sprotty/lib"; +import { GLSPActionDispatcher } from "@glsp/sprotty-client/lib"; +import {TYPES} from "@glsp/sprotty-client/lib"; + +export class AttributeTypesAction implements RequestAction { + static readonly KIND = 'getAttributeTypes'; + kind = AttributeTypesAction.KIND; + constructor(public readonly requestId: string = generateRequestId()) { } +} + +export class ReturnAttributeTypesAction implements ResponseAction { + static readonly KIND = 'returnAttributeTypes'; + kind = ReturnAttributeTypesAction.KIND; + types: string[]; + constructor(public readonly actions: string[], public readonly responseId: string = '') { + this.types = this.types; + } +} + +injectable() +export class EditLabelUIAutocomplete extends EditLabelUI { + + protected showAutocomplete : boolean = false; + protected outerDiv : HTMLElement; + protected listContainer : HTMLElement; + protected currentFocus : number; + protected types : string[] = []; + + + constructor(@inject(TYPES.IActionDispatcher) protected actionDispatcher: GLSPActionDispatcher) { + super(); + } + + protected initializeContents(containerElement: HTMLElement) { + this.outerDiv = containerElement; + super.initializeContents(containerElement); + + // request possible element types + this.actionDispatcher.requestUntil(new AttributeTypesAction()).then(response => { + if (response) { + let action : ReturnAttributeTypesAction = response; + this.types = action.types; + } + }); + } + + protected handleKeyDown(event: KeyboardEvent) { + super.handleKeyDown(event); + + if (matchesKeystroke(event, 'Space', 'ctrl')) { + this.showAutocomplete = true; + if (this.isAutoCompleteEnabled()) { + this.createAutocomplete(); + } + } + + this.updateAutocomplete(event); + } + + protected validateLabelIfContentChange(event: KeyboardEvent, value: string) { + if (this.isAutoCompleteEnabled() && this.previousLabelContent !== value) { + // recreate autocomplete list if value changed + this.createAutocomplete(); + } + super.validateLabelIfContentChange(event, value); + } + + protected updateAutocomplete(event: KeyboardEvent) { + if (matchesKeystroke(event, 'ArrowDown')) { + this.currentFocus++; + this.addActive(); + } else if (matchesKeystroke(event, 'ArrowUp')) { + this.currentFocus--; + this.addActive(); + } else if (matchesKeystroke(event, 'Enter')) { + event.preventDefault(); + if (this.currentFocus > -1) { + if (this.listContainer) { + var children = this.listContainer.children; + (children[this.currentFocus]).click(); + } + } + } + } + + protected createAutocomplete() { + let input : String = this.inputElement.value; + let val : String = ""; + if (input.includes(":")) { + val = input.split(":")[1].trim(); + } + + this.closeAllLists(); + this.currentFocus = -1; + + this.listContainer = document.createElement("div"); + this.listContainer.setAttribute("id", this.inputElement.id + "autocomplete-list"); + this.listContainer.setAttribute("class", "autocomplete-items"); + this.outerDiv.appendChild(this.listContainer); + + // create autocomlete items starting with input + for (let i = 0; i < this.types.length; i++) { + if (this.types[i].substr(0, val.length).toLowerCase() == val.toLowerCase()) { + let element = document.createElement("div"); + element.innerHTML = "" + this.types[i].substr(0, val.length) + ""; + element.innerHTML += this.types[i].substr(val.length); + element.innerHTML += ""; + element.addEventListener("click", e => { + // change the type of the label + let name : String = this.inputElement.value; + if (name.includes(":")) { + name = name.split(":")[0]; + } + this.inputElement.value = name + ": " + element.getElementsByTagName("input")[0].value; + this.closeAllLists(); + }); + this.listContainer.appendChild(element); + } + } + } + + protected addActive() { + if (!this.listContainer) return; + this.removeActive(); + var children = this.listContainer.children; + if (children.length > 0) { + if (this.currentFocus >= children.length) this.currentFocus = 0; + if (this.currentFocus < 0) this.currentFocus = (children.length - 1); + children[this.currentFocus].classList.add("autocomplete-active"); + } + } + + protected removeActive() { + var children = this.listContainer.children; + for (var i = 0; i < children.length; i++) { + children[i].classList.remove("autocomplete-active"); + } + } + + protected closeAllLists() { + var x = this.outerDiv.getElementsByClassName("autocomplete-items"); + for (var i = 0; i < x.length; i++) { + this.outerDiv.removeChild(x[i]); + } + } + + protected isAutoCompleteEnabled() { + if (this.label) { + return this.label.type === "node:attribute" && this.showAutocomplete; + } + return false; + } + + public hide() { + super.hide(); + this.showAutocomplete = false; + this.closeAllLists(); + } +} \ No newline at end of file diff --git a/client/theia-ecore/src/browser/diagram/ecore-diagram-configuration.ts b/client/theia-ecore/src/browser/diagram/ecore-diagram-configuration.ts index 29e8e3b..5c47154 100644 --- a/client/theia-ecore/src/browser/diagram/ecore-diagram-configuration.ts +++ b/client/theia-ecore/src/browser/diagram/ecore-diagram-configuration.ts @@ -14,12 +14,11 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ import { registerDefaultTools, TYPES } from "@glsp/sprotty-client/lib"; -import { GLSPTheiaDiagramServer } from "@glsp/theia-integration/lib/browser"; +import { EcoreGLSPTheiaDiagramServer } from "./ecore-glsp-theia-diagram-server"; import { SelectionService } from "@theia/core"; import { Container, inject, injectable } from "inversify"; import { createEcoreDiagramContainer } from "sprotty-ecore/lib"; import { DiagramConfiguration, TheiaDiagramServer, TheiaSprottySelectionForwarder } from "sprotty-theia/lib"; - import { EcoreLanguage } from "../../common/ecore-language"; @injectable() @@ -29,12 +28,13 @@ export class EcoreDiagramConfiguration implements DiagramConfiguration { createContainer(widgetId: string): Container { const container = createEcoreDiagramContainer(widgetId); - container.bind(TYPES.ModelSource).to(GLSPTheiaDiagramServer).inSingletonScope(); - container.bind(TheiaDiagramServer).toService(GLSPTheiaDiagramServer); + container.bind(TYPES.ModelSource).to(EcoreGLSPTheiaDiagramServer).inSingletonScope(); + container.bind(TheiaDiagramServer).toService(EcoreGLSPTheiaDiagramServer); // container.rebind(KeyTool).to(TheiaKeyTool).inSingletonScope() container.bind(TYPES.IActionHandlerInitializer).to(TheiaSprottySelectionForwarder); container.bind(SelectionService).toConstantValue(this.selectionService); + registerDefaultTools(container); return container; } -} +} \ No newline at end of file diff --git a/client/theia-ecore/src/browser/diagram/ecore-glsp-theia-diagram-server.ts b/client/theia-ecore/src/browser/diagram/ecore-glsp-theia-diagram-server.ts new file mode 100644 index 0000000..6623a9f --- /dev/null +++ b/client/theia-ecore/src/browser/diagram/ecore-glsp-theia-diagram-server.ts @@ -0,0 +1,30 @@ +/******************************************************************************** + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +import { ActionHandlerRegistry } from "@glsp/sprotty-client/lib"; +import { GLSPTheiaDiagramServer } from "@glsp/theia-integration/lib/browser"; +import { injectable } from "inversify"; +import { AttributeTypesAction, ReturnAttributeTypesAction } from "sprotty-ecore/lib/features/edit-label-autocomplete"; + +@injectable() +export class EcoreGLSPTheiaDiagramServer extends GLSPTheiaDiagramServer { + initialize(registry: ActionHandlerRegistry): void { + super.initialize(registry); + + registry.register(AttributeTypesAction.KIND, this); + registry.register(ReturnAttributeTypesAction.KIND, this); + } + +} diff --git a/server/src/main/java/com/eclipsesource/glsp/ecore/EcoreGLSPModule.java b/server/src/main/java/com/eclipsesource/glsp/ecore/EcoreGLSPModule.java index a4fc6e9..343fc77 100644 --- a/server/src/main/java/com/eclipsesource/glsp/ecore/EcoreGLSPModule.java +++ b/server/src/main/java/com/eclipsesource/glsp/ecore/EcoreGLSPModule.java @@ -25,7 +25,10 @@ import com.eclipsesource.glsp.api.handler.OperationHandler; import com.eclipsesource.glsp.api.layout.ILayoutEngine; import com.eclipsesource.glsp.api.model.ModelStateProvider; +import com.eclipsesource.glsp.api.provider.ActionProvider; +import com.eclipsesource.glsp.ecore.actions.EcoreActionProvider; import com.eclipsesource.glsp.ecore.handler.EcoreComputedBoundsActionHandler; +import com.eclipsesource.glsp.ecore.handler.EcoreGetAttributeTypesActionHandler; import com.eclipsesource.glsp.ecore.handler.EcoreOperationActionHandler; import com.eclipsesource.glsp.ecore.handler.EcoreSaveModelActionHandler; import com.eclipsesource.glsp.ecore.handler.EcoreUndoRedoActionHandler; @@ -50,6 +53,13 @@ public EcoreGLSPModule() { rebind(ComputedBoundsActionHandler.class, EcoreComputedBoundsActionHandler.class); rebind(OperationActionHandler.class, EcoreOperationActionHandler.class); rebind(UndoRedoActionHandler.class, EcoreUndoRedoActionHandler.class); + + bindActionHandlers().add(EcoreGetAttributeTypesActionHandler.class); + } + + @Override + protected Class bindActionProvider() { + return EcoreActionProvider.class; // includes AttributeTypesAction & DefaultActionProvider } @Override diff --git a/server/src/main/java/com/eclipsesource/glsp/ecore/actions/AttributeTypesAction.java b/server/src/main/java/com/eclipsesource/glsp/ecore/actions/AttributeTypesAction.java new file mode 100644 index 0000000..a7d080a --- /dev/null +++ b/server/src/main/java/com/eclipsesource/glsp/ecore/actions/AttributeTypesAction.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ******************************************************************************/ +package com.eclipsesource.glsp.ecore.actions; + +import com.eclipsesource.glsp.api.action.RequestAction; + +public class AttributeTypesAction extends RequestAction { + + public static String KIND = "getAttributeTypes"; + + public AttributeTypesAction() { + super(KIND); + } + +} \ No newline at end of file diff --git a/server/src/main/java/com/eclipsesource/glsp/ecore/actions/EcoreActionProvider.java b/server/src/main/java/com/eclipsesource/glsp/ecore/actions/EcoreActionProvider.java new file mode 100644 index 0000000..a2ffc11 --- /dev/null +++ b/server/src/main/java/com/eclipsesource/glsp/ecore/actions/EcoreActionProvider.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ******************************************************************************/ +package com.eclipsesource.glsp.ecore.actions; + +import java.util.HashSet; +import java.util.Set; + +import com.eclipsesource.glsp.server.provider.DefaultActionProvider; +import com.eclipsesource.glsp.api.action.Action; + + +public class EcoreActionProvider extends DefaultActionProvider { + + Set ecoreActions = new HashSet<>(); + + public EcoreActionProvider() { + super(); + addEcoreActions(); + } + + private void addEcoreActions() { + ecoreActions.add(new AttributeTypesAction()); + } + + @Override + public Set getActions() { + Set actions = new HashSet<>(super.getActions()); + actions.addAll(ecoreActions); + return actions; + } +} diff --git a/server/src/main/java/com/eclipsesource/glsp/ecore/actions/ReturnAttributeTypesAction.java b/server/src/main/java/com/eclipsesource/glsp/ecore/actions/ReturnAttributeTypesAction.java new file mode 100644 index 0000000..09211c3 --- /dev/null +++ b/server/src/main/java/com/eclipsesource/glsp/ecore/actions/ReturnAttributeTypesAction.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ******************************************************************************/ +package com.eclipsesource.glsp.ecore.actions; + +import java.util.List; + +import com.eclipsesource.glsp.api.action.ResponseAction; + +public class ReturnAttributeTypesAction extends ResponseAction { + + public static String KIND = "returnAttributeTypes"; + private List types; + + public ReturnAttributeTypesAction() { + super(KIND); + } + + public ReturnAttributeTypesAction(List types) { + super(KIND); + this.types = types; + } + + public List getTypes() { + return types; + } + + public void setTypes(List types) { + this.types = types; + } +} \ No newline at end of file diff --git a/server/src/main/java/com/eclipsesource/glsp/ecore/handler/EcoreGetAttributeTypesActionHandler.java b/server/src/main/java/com/eclipsesource/glsp/ecore/handler/EcoreGetAttributeTypesActionHandler.java new file mode 100644 index 0000000..c512f17 --- /dev/null +++ b/server/src/main/java/com/eclipsesource/glsp/ecore/handler/EcoreGetAttributeTypesActionHandler.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2019 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 + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ******************************************************************************/ +package com.eclipsesource.glsp.ecore.handler; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import com.eclipsesource.glsp.api.action.Action; +import com.eclipsesource.glsp.api.model.GraphicalModelState; +import com.eclipsesource.glsp.ecore.ResourceManager; +import com.eclipsesource.glsp.ecore.actions.AttributeTypesAction; +import com.eclipsesource.glsp.ecore.actions.ReturnAttributeTypesAction; +import com.eclipsesource.glsp.ecore.model.EcoreModelState; +import com.eclipsesource.glsp.ecore.operationhandler.EcoreLabelEditOperationHandler; +import com.eclipsesource.glsp.server.actionhandler.AbstractActionHandler; + +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EObject; + +public class EcoreGetAttributeTypesActionHandler extends AbstractActionHandler { + + @Override + public boolean handles(Action action) { + return action instanceof AttributeTypesAction; + } + + @Override + protected Optional execute(Action action, GraphicalModelState modelState) { + List types = getEAttributeTypeList(EcoreModelState.getResourceManager(modelState)); + Collections.sort(types); + + return Optional.of(new ReturnAttributeTypesAction(types)); + } + + private List getEAttributeTypeList(ResourceManager resManager) { + List list = new ArrayList<>(); + for (EObject obj : EcoreLabelEditOperationHandler.getAllEAttributeTypes(resManager)) { + list.add(((ENamedElement) obj).getName()); + } + return list; + } +} \ No newline at end of file diff --git a/server/src/main/java/com/eclipsesource/glsp/ecore/operationhandler/EcoreLabelEditOperationHandler.java b/server/src/main/java/com/eclipsesource/glsp/ecore/operationhandler/EcoreLabelEditOperationHandler.java index df991df..b348cfa 100644 --- a/server/src/main/java/com/eclipsesource/glsp/ecore/operationhandler/EcoreLabelEditOperationHandler.java +++ b/server/src/main/java/com/eclipsesource/glsp/ecore/operationhandler/EcoreLabelEditOperationHandler.java @@ -17,9 +17,17 @@ import static com.eclipsesource.glsp.api.jsonrpc.GLSPServerException.getOrThrow; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.eclipse.emf.common.notify.Notifier; +import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EcorePackage; import com.eclipsesource.glsp.api.action.Action; import com.eclipsesource.glsp.api.action.kind.AbstractOperationAction; @@ -28,6 +36,7 @@ import com.eclipsesource.glsp.api.model.GraphicalModelState; import com.eclipsesource.glsp.ecore.EcoreFacade; import com.eclipsesource.glsp.ecore.EcoreModelIndex; +import com.eclipsesource.glsp.ecore.ResourceManager; import com.eclipsesource.glsp.ecore.enotation.Shape; import com.eclipsesource.glsp.ecore.model.EcoreModelState; import com.eclipsesource.glsp.graph.GNode; @@ -58,10 +67,18 @@ public void execute(AbstractOperationAction action, GraphicalModelState graphica if (inputText.contains(":")) { String[] split = inputText.split(":"); attributeName = split[0].trim(); + + Optional type = parseStringToEType(split[1].trim(), + EcoreModelState.getResourceManager(graphicalModelState)); + if (type.isPresent()) { + ((EAttribute) eObject).setEType(type.get()); + } } else { - attributeName = inputText; + attributeName = inputText.trim(); + } + if (!attributeName.isEmpty()) { + ((EAttribute) eObject).setName(attributeName); } - ((EAttribute) eObject).setName(attributeName); } } else { // Main Label of a Node GNode node = getOrThrow(index.findElementByClass(editLabelAction.getLabelId(), GNode.class), @@ -74,13 +91,35 @@ public void execute(AbstractOperationAction action, GraphicalModelState graphica "No shape element for label with id " + editLabelAction.getLabelId() + " found"); if (eObject instanceof EClassifier) { - ((EClassifier) eObject).setName(editLabelAction.getText()); + ((EClassifier) eObject).setName(editLabelAction.getText().trim()); // nameChange== uri change so we have to recreate the proxy here shape.setSemanticElement(facade.createProxy(eObject)); } } } + private Optional parseStringToEType(String name, ResourceManager resManager) { + for (EClassifier type : getAllEAttributeTypes(resManager)) { + if (type.getName().toLowerCase().equals(name.toLowerCase())) { + return Optional.ofNullable(type); + } + } + return Optional.empty(); + } + + public static List getAllEAttributeTypes(ResourceManager resManager) { + List listOfTypes = new ArrayList<>(EcorePackage.eINSTANCE.getEClassifiers()); + listOfTypes.removeIf(e -> !(e instanceof EDataType)); + TreeIterator resourceSetContent = resManager.getEditingDomain().getResourceSet().getAllContents(); + while (resourceSetContent.hasNext()) { + Notifier res = resourceSetContent.next(); + if (res instanceof EDataType) { + listOfTypes.add((EClassifier) res); + } + } + return listOfTypes; + } + @Override public String getLabel(AbstractOperationAction action) { return "Apply label"; From 974a99eaac040754b74fcfb41ddbba0629dfdac8 Mon Sep 17 00:00:00 2001 From: leodennis Date: Thu, 21 Nov 2019 23:17:15 +0100 Subject: [PATCH 2/8] Resloves #37 cleanup Signed-off-by: leodennis --- client/sprotty-ecore/src/di.config.ts | 2 +- .../src/features/edit-label-autocomplete.ts | 36 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/client/sprotty-ecore/src/di.config.ts b/client/sprotty-ecore/src/di.config.ts index 70aa05a..d814324 100644 --- a/client/sprotty-ecore/src/di.config.ts +++ b/client/sprotty-ecore/src/di.config.ts @@ -68,7 +68,7 @@ import { } from "@glsp/sprotty-client/lib"; import executeCommandModule from "@glsp/sprotty-client/lib/features/execute/di.config"; import { Container, ContainerModule } from "inversify"; -import {EditLabelUIAutocomplete} from "./features/edit-label-autocomplete" +import {EditLabelUIAutocomplete} from "./features/edit-label-autocomplete"; import { EditLabelUI } from "sprotty/lib"; import { LabelSelectionFeedback } from "./feedback"; import { Icon, LabeledNode, SEditableLabel, SLabelNode } from "./model"; diff --git a/client/sprotty-ecore/src/features/edit-label-autocomplete.ts b/client/sprotty-ecore/src/features/edit-label-autocomplete.ts index 05e65fb..356ff30 100644 --- a/client/sprotty-ecore/src/features/edit-label-autocomplete.ts +++ b/client/sprotty-ecore/src/features/edit-label-autocomplete.ts @@ -31,18 +31,18 @@ export class ReturnAttributeTypesAction implements ResponseAction { kind = ReturnAttributeTypesAction.KIND; types: string[]; constructor(public readonly actions: string[], public readonly responseId: string = '') { - this.types = this.types; + this.types = actions; } } injectable() export class EditLabelUIAutocomplete extends EditLabelUI { - protected showAutocomplete : boolean = false; - protected outerDiv : HTMLElement; - protected listContainer : HTMLElement; - protected currentFocus : number; - protected types : string[] = []; + protected showAutocomplete: boolean = false; + protected outerDiv: HTMLElement; + protected listContainer: HTMLElement; + protected currentFocus: number; + protected types: string[] = []; constructor(@inject(TYPES.IActionDispatcher) protected actionDispatcher: GLSPActionDispatcher) { @@ -56,7 +56,7 @@ export class EditLabelUIAutocomplete extends EditLabelUI { // request possible element types this.actionDispatcher.requestUntil(new AttributeTypesAction()).then(response => { if (response) { - let action : ReturnAttributeTypesAction = response; + const action: ReturnAttributeTypesAction = response; this.types = action.types; } }); @@ -94,7 +94,7 @@ export class EditLabelUIAutocomplete extends EditLabelUI { event.preventDefault(); if (this.currentFocus > -1) { if (this.listContainer) { - var children = this.listContainer.children; + const children = this.listContainer.children; (children[this.currentFocus]).click(); } } @@ -102,8 +102,8 @@ export class EditLabelUIAutocomplete extends EditLabelUI { } protected createAutocomplete() { - let input : String = this.inputElement.value; - let val : String = ""; + const input: String = this.inputElement.value; + let val: String = ""; if (input.includes(":")) { val = input.split(":")[1].trim(); } @@ -118,14 +118,14 @@ export class EditLabelUIAutocomplete extends EditLabelUI { // create autocomlete items starting with input for (let i = 0; i < this.types.length; i++) { - if (this.types[i].substr(0, val.length).toLowerCase() == val.toLowerCase()) { - let element = document.createElement("div"); + if (this.types[i].substr(0, val.length).toLowerCase() === val.toLowerCase()) { + const element = document.createElement("div"); element.innerHTML = "" + this.types[i].substr(0, val.length) + ""; element.innerHTML += this.types[i].substr(val.length); element.innerHTML += ""; element.addEventListener("click", e => { // change the type of the label - let name : String = this.inputElement.value; + let name: String = this.inputElement.value; if (name.includes(":")) { name = name.split(":")[0]; } @@ -140,7 +140,7 @@ export class EditLabelUIAutocomplete extends EditLabelUI { protected addActive() { if (!this.listContainer) return; this.removeActive(); - var children = this.listContainer.children; + const children = this.listContainer.children; if (children.length > 0) { if (this.currentFocus >= children.length) this.currentFocus = 0; if (this.currentFocus < 0) this.currentFocus = (children.length - 1); @@ -149,15 +149,15 @@ export class EditLabelUIAutocomplete extends EditLabelUI { } protected removeActive() { - var children = this.listContainer.children; - for (var i = 0; i < children.length; i++) { + const children = this.listContainer.children; + for (let i = 0; i < children.length; i++) { children[i].classList.remove("autocomplete-active"); } } protected closeAllLists() { - var x = this.outerDiv.getElementsByClassName("autocomplete-items"); - for (var i = 0; i < x.length; i++) { + const x = this.outerDiv.getElementsByClassName("autocomplete-items"); + for (let i = 0; i < x.length; i++) { this.outerDiv.removeChild(x[i]); } } From f1a0ec470922edb1b3f64df1c32d64f9b07b3426 Mon Sep 17 00:00:00 2001 From: leodennis Date: Fri, 22 Nov 2019 13:42:01 +0100 Subject: [PATCH 3/8] Added scrolling and fixed error Signed-off-by: leodennis --- client/sprotty-ecore/css/diagram.css | 4 +++- .../src/features/edit-label-autocomplete.ts | 19 ++++++++++++++----- .../diagram/ecore-diagram-configuration.ts | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/client/sprotty-ecore/css/diagram.css b/client/sprotty-ecore/css/diagram.css index f267fe3..839a54f 100644 --- a/client/sprotty-ecore/css/diagram.css +++ b/client/sprotty-ecore/css/diagram.css @@ -196,6 +196,7 @@ svg { top: 100%; left: 0; right: 0; + overflow-y: scroll; } .autocomplete-items div { padding: 10px; @@ -209,4 +210,5 @@ svg { .autocomplete-active { background-color: DodgerBlue !important; color: #ffffff; - } \ No newline at end of file + } + \ No newline at end of file diff --git a/client/sprotty-ecore/src/features/edit-label-autocomplete.ts b/client/sprotty-ecore/src/features/edit-label-autocomplete.ts index 356ff30..a02805b 100644 --- a/client/sprotty-ecore/src/features/edit-label-autocomplete.ts +++ b/client/sprotty-ecore/src/features/edit-label-autocomplete.ts @@ -13,12 +13,12 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ******************************************************************************/ -import { RequestAction, ResponseAction, generateRequestId} from "sprotty/lib"; -import { inject, injectable } from "inversify"; +import { RequestAction, ResponseAction, generateRequestId } from "sprotty/lib"; +import { inject } from "inversify"; import { matchesKeystroke } from "sprotty/lib/utils/keyboard"; import { EditLabelUI } from "sprotty/lib"; import { GLSPActionDispatcher } from "@glsp/sprotty-client/lib"; -import {TYPES} from "@glsp/sprotty-client/lib"; +import { TYPES } from "@glsp/sprotty-client/lib"; export class AttributeTypesAction implements RequestAction { static readonly KIND = 'getAttributeTypes'; @@ -35,7 +35,6 @@ export class ReturnAttributeTypesAction implements ResponseAction { } } -injectable() export class EditLabelUIAutocomplete extends EditLabelUI { protected showAutocomplete: boolean = false; @@ -135,6 +134,16 @@ export class EditLabelUIAutocomplete extends EditLabelUI { this.listContainer.appendChild(element); } } + + // set max height for scrolling + const parent = this.outerDiv.parentElement; + if (parent) { + const parentHeight = parent.offsetHeight; + const parentPosY = parent.offsetTop; + const posY = this.outerDiv.offsetTop + this.inputElement.offsetHeight; + const maxHeight = parentHeight - (posY - parentPosY); + this.listContainer.style.maxHeight = `${maxHeight}px`; + } } protected addActive() { @@ -174,4 +183,4 @@ export class EditLabelUIAutocomplete extends EditLabelUI { this.showAutocomplete = false; this.closeAllLists(); } -} \ No newline at end of file +} diff --git a/client/theia-ecore/src/browser/diagram/ecore-diagram-configuration.ts b/client/theia-ecore/src/browser/diagram/ecore-diagram-configuration.ts index 5c47154..5bd7f4e 100644 --- a/client/theia-ecore/src/browser/diagram/ecore-diagram-configuration.ts +++ b/client/theia-ecore/src/browser/diagram/ecore-diagram-configuration.ts @@ -37,4 +37,4 @@ export class EcoreDiagramConfiguration implements DiagramConfiguration { registerDefaultTools(container); return container; } -} \ No newline at end of file +} From 5658d8799f75160d36b470ba2c08d6e6483b4606 Mon Sep 17 00:00:00 2001 From: Jonas Ebel Date: Sat, 23 Nov 2019 16:12:27 +0100 Subject: [PATCH 4/8] Resolves 57 - Specify a targetAnchorCorrection Value for ArrowEdges --- client/sprotty-ecore/src/di.config.ts | 4 ++-- client/sprotty-ecore/src/model.ts | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/client/sprotty-ecore/src/di.config.ts b/client/sprotty-ecore/src/di.config.ts index ca8589e..3a95b0f 100644 --- a/client/sprotty-ecore/src/di.config.ts +++ b/client/sprotty-ecore/src/di.config.ts @@ -70,7 +70,7 @@ import executeCommandModule from "@glsp/sprotty-client/lib/features/execute/di.c import { Container, ContainerModule } from "inversify"; import { LabelSelectionFeedback } from "./feedback"; -import { Icon, LabeledNode, SEditableLabel, SLabelNode } from "./model"; +import {ArrowEdge, Icon, LabeledNode, SEditableLabel, SLabelNode} from "./model"; import { ArrowEdgeView, ClassNodeView, CompositionEdgeView, IconView, InheritanceEdgeView, LabelNodeView } from "./views"; export default (containerId: string) => { @@ -96,7 +96,7 @@ export default (containerId: string) => { configureModelElement(context, 'html', HtmlRoot, HtmlRootView); configureModelElement(context, 'routing-point', SRoutingHandle, SRoutingHandleView); configureModelElement(context, 'volatile-routing-point', SRoutingHandle, SRoutingHandleView); - configureModelElement(context, 'edge:reference', SEdge, ArrowEdgeView); + configureModelElement(context, 'edge:reference', ArrowEdge, ArrowEdgeView); configureModelElement(context, 'edge:inheritance', SEdge, InheritanceEdgeView); configureModelElement(context, 'edge:composition', SEdge, CompositionEdgeView); configureModelElement(context, 'edge', SEdge, PolylineEdgeView); diff --git a/client/sprotty-ecore/src/model.ts b/client/sprotty-ecore/src/model.ts index eb549fd..1301e61 100644 --- a/client/sprotty-ecore/src/model.ts +++ b/client/sprotty-ecore/src/model.ts @@ -31,7 +31,8 @@ import { SLabel, SShapeElement, WithEditableLabel, - withEditLabelFeature + withEditLabelFeature, + SEdge } from "sprotty/lib"; @@ -84,3 +85,7 @@ export class SLabelNode extends SLabel implements EditableLabel { return (feature === selectFeature || feature === editLabelFeature || feature === popupFeature || feature === deletableFeature || feature === hoverFeedbackFeature || super.hasFeature(feature)); } } + +export class ArrowEdge extends SEdge { + public readonly targetAnchorCorrection = 3.3; +} From 957febe8864f1de5677d928f6a6ef8bc262770bc Mon Sep 17 00:00:00 2001 From: leodennis Date: Mon, 25 Nov 2019 14:15:06 +0100 Subject: [PATCH 5/8] fixed update issue Signed-off-by: leodennis --- .../src/features/edit-label-autocomplete.ts | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/client/sprotty-ecore/src/features/edit-label-autocomplete.ts b/client/sprotty-ecore/src/features/edit-label-autocomplete.ts index a02805b..811d376 100644 --- a/client/sprotty-ecore/src/features/edit-label-autocomplete.ts +++ b/client/sprotty-ecore/src/features/edit-label-autocomplete.ts @@ -13,12 +13,11 @@ * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ******************************************************************************/ -import { RequestAction, ResponseAction, generateRequestId } from "sprotty/lib"; -import { inject } from "inversify"; +import { RequestAction, ResponseAction, generateRequestId, SModelRoot } from "sprotty/lib"; +import { inject, injectable } from "inversify"; import { matchesKeystroke } from "sprotty/lib/utils/keyboard"; import { EditLabelUI } from "sprotty/lib"; -import { GLSPActionDispatcher } from "@glsp/sprotty-client/lib"; -import { TYPES } from "@glsp/sprotty-client/lib"; +import { GLSPActionDispatcher, TYPES } from "@glsp/sprotty-client/lib"; export class AttributeTypesAction implements RequestAction { static readonly KIND = 'getAttributeTypes'; @@ -35,6 +34,7 @@ export class ReturnAttributeTypesAction implements ResponseAction { } } +@injectable() export class EditLabelUIAutocomplete extends EditLabelUI { protected showAutocomplete: boolean = false; @@ -51,14 +51,6 @@ export class EditLabelUIAutocomplete extends EditLabelUI { protected initializeContents(containerElement: HTMLElement) { this.outerDiv = containerElement; super.initializeContents(containerElement); - - // request possible element types - this.actionDispatcher.requestUntil(new AttributeTypesAction()).then(response => { - if (response) { - const action: ReturnAttributeTypesAction = response; - this.types = action.types; - } - }); } protected handleKeyDown(event: KeyboardEvent) { @@ -171,6 +163,18 @@ export class EditLabelUIAutocomplete extends EditLabelUI { } } + protected onBeforeShow(containerElement: HTMLElement, root: Readonly, ...contextElementIds: string[]) { + super.onBeforeShow(containerElement, root, ...contextElementIds); + + // request possible element types + this.actionDispatcher.requestUntil(new AttributeTypesAction()).then(response => { + if (response) { + const action: ReturnAttributeTypesAction = response; + this.types = action.types; + } + }); + } + protected isAutoCompleteEnabled() { if (this.label) { return this.label.type === "node:attribute" && this.showAutocomplete; From b256eeba4cd1ef09ed3333616fd9eda297cefaa9 Mon Sep 17 00:00:00 2001 From: Jonas Ebel Date: Tue, 26 Nov 2019 09:57:02 +0100 Subject: [PATCH 6/8] Improve Inheritance and Composition edge's distance to classes * Remove unused getTargetCorrection methods from EdgeViews * SourceAnchorCorrection of 3.0 at CompositionEdge * TargetAnchorCorrection of 2.3 at InheritanceEdge --- client/sprotty-ecore/src/di.config.ts | 6 +++--- client/sprotty-ecore/src/model.ts | 8 ++++++++ client/sprotty-ecore/src/views.tsx | 18 ------------------ 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/client/sprotty-ecore/src/di.config.ts b/client/sprotty-ecore/src/di.config.ts index 3a95b0f..2d47ccd 100644 --- a/client/sprotty-ecore/src/di.config.ts +++ b/client/sprotty-ecore/src/di.config.ts @@ -70,7 +70,7 @@ import executeCommandModule from "@glsp/sprotty-client/lib/features/execute/di.c import { Container, ContainerModule } from "inversify"; import { LabelSelectionFeedback } from "./feedback"; -import {ArrowEdge, Icon, LabeledNode, SEditableLabel, SLabelNode} from "./model"; +import {ArrowEdge, CompositionEdge, Icon, InheritanceEdge, LabeledNode, SEditableLabel, SLabelNode} from "./model"; import { ArrowEdgeView, ClassNodeView, CompositionEdgeView, IconView, InheritanceEdgeView, LabelNodeView } from "./views"; export default (containerId: string) => { @@ -97,8 +97,8 @@ export default (containerId: string) => { configureModelElement(context, 'routing-point', SRoutingHandle, SRoutingHandleView); configureModelElement(context, 'volatile-routing-point', SRoutingHandle, SRoutingHandleView); configureModelElement(context, 'edge:reference', ArrowEdge, ArrowEdgeView); - configureModelElement(context, 'edge:inheritance', SEdge, InheritanceEdgeView); - configureModelElement(context, 'edge:composition', SEdge, CompositionEdgeView); + configureModelElement(context, 'edge:inheritance', InheritanceEdge, InheritanceEdgeView); + configureModelElement(context, 'edge:composition', CompositionEdge, CompositionEdgeView); configureModelElement(context, 'edge', SEdge, PolylineEdgeView); configureViewerOptions(context, { needsClientLayout: true, diff --git a/client/sprotty-ecore/src/model.ts b/client/sprotty-ecore/src/model.ts index 1301e61..441c5f1 100644 --- a/client/sprotty-ecore/src/model.ts +++ b/client/sprotty-ecore/src/model.ts @@ -89,3 +89,11 @@ export class SLabelNode extends SLabel implements EditableLabel { export class ArrowEdge extends SEdge { public readonly targetAnchorCorrection = 3.3; } + +export class CompositionEdge extends SEdge { + public readonly sourceAnchorCorrection = 3.0; +} + +export class InheritanceEdge extends SEdge { + public readonly targetAnchorCorrection = 2.3; +} diff --git a/client/sprotty-ecore/src/views.tsx b/client/sprotty-ecore/src/views.tsx index 2ebee94..eaaa04d 100644 --- a/client/sprotty-ecore/src/views.tsx +++ b/client/sprotty-ecore/src/views.tsx @@ -70,12 +70,6 @@ export class ArrowEdgeView extends PolylineEdgeView { ]; } - static readonly TARGET_CORRECTION = Math.sqrt(1 * 1 + 2.5 * 2.5); - - protected getTargetAnchorCorrection(edge: SEdge): number { - return ArrowEdgeView.TARGET_CORRECTION; - } - } @injectable() @@ -88,12 +82,6 @@ export class InheritanceEdgeView extends ArrowEdgeView { transform={`rotate(${angle(p2, p1)} ${p2.x} ${p2.y}) translate(${p2.x} ${p2.y})`} />, ]; } - - static readonly TARGET_CORRECTION = Math.sqrt(1 * 1 + 2.5 * 2.5); - - protected getTargetAnchorCorrection(edge: SEdge): number { - return ArrowEdgeView.TARGET_CORRECTION; - } } @injectable() @@ -109,12 +97,6 @@ abstract class DiamondEdgeView extends PolylineEdgeView { transform={`rotate(${firstEdgeAngle} ${p1.x} ${p1.y}) translate(${p1.x} ${p1.y})`} /> ]; } - - static readonly SOURCE_CORRECTION = Math.sqrt(1 * 1 + 2 * 2); - - protected getSourceAnchorCorrection(edge: SEdge): number { - return CompositionEdgeView.SOURCE_CORRECTION; - } protected isComposition(): boolean { return false; } From 48a68d80c988e6994977c84437f80fe2528f6995 Mon Sep 17 00:00:00 2001 From: Jonas Ebel Date: Wed, 27 Nov 2019 13:59:02 +0100 Subject: [PATCH 7/8] Enable Autoform on opening ecore file without notation (#65) --- .../com/eclipsesource/glsp/ecore/EcoreFacade.java | 10 ++++++++++ .../handler/EcoreComputedBoundsActionHandler.java | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/server/src/main/java/com/eclipsesource/glsp/ecore/EcoreFacade.java b/server/src/main/java/com/eclipsesource/glsp/ecore/EcoreFacade.java index 4925ab5..29e229c 100644 --- a/server/src/main/java/com/eclipsesource/glsp/ecore/EcoreFacade.java +++ b/server/src/main/java/com/eclipsesource/glsp/ecore/EcoreFacade.java @@ -30,6 +30,7 @@ import com.eclipsesource.glsp.ecore.enotation.NotationElement; import com.eclipsesource.glsp.ecore.enotation.SemanticProxy; import com.eclipsesource.glsp.ecore.enotation.Shape; +import com.eclipsesource.glsp.ecore.model.EcoreModelState; import com.eclipsesource.glsp.graph.GEdge; import com.eclipsesource.glsp.graph.GModelElement; import com.eclipsesource.glsp.graph.GModelRoot; @@ -44,6 +45,8 @@ public class EcoreFacade { private final Resource notationResource; private final EPackage ePackage; + private boolean diagramIsNewlyCreated = false; + private Diagram diagram; private EcoreModelIndex modelIndex; @@ -94,6 +97,12 @@ public Diagram initialize(Diagram diagram, GModelRoot gRoot) { return diagram; } + public boolean diagramNeedsAutoLayout() { + boolean oldValue = this.diagramIsNewlyCreated; + this.diagramIsNewlyCreated = false; + return oldValue; + } + public Optional initializeNotationElement(GModelElement gModelElement) { Optional result = Optional.empty(); if (gModelElement instanceof GNode) { @@ -114,6 +123,7 @@ private Diagram createDiagram() { Diagram diagram = EnotationFactory.eINSTANCE.createDiagram(); diagram.setSemanticElement(createProxy(ePackage)); notationResource.getContents().add(diagram); + diagramIsNewlyCreated = true; return diagram; } diff --git a/server/src/main/java/com/eclipsesource/glsp/ecore/handler/EcoreComputedBoundsActionHandler.java b/server/src/main/java/com/eclipsesource/glsp/ecore/handler/EcoreComputedBoundsActionHandler.java index f22395f..da8a5c0 100644 --- a/server/src/main/java/com/eclipsesource/glsp/ecore/handler/EcoreComputedBoundsActionHandler.java +++ b/server/src/main/java/com/eclipsesource/glsp/ecore/handler/EcoreComputedBoundsActionHandler.java @@ -18,7 +18,10 @@ import java.util.Optional; import com.eclipsesource.glsp.api.action.Action; +import com.eclipsesource.glsp.api.action.ActionMessage; +import com.eclipsesource.glsp.api.action.ActionProcessor; import com.eclipsesource.glsp.api.action.kind.ComputedBoundsAction; +import com.eclipsesource.glsp.api.action.kind.LayoutAction; import com.eclipsesource.glsp.api.model.GraphicalModelState; import com.eclipsesource.glsp.api.types.ElementAndBounds; import com.eclipsesource.glsp.api.utils.LayoutUtil; @@ -28,8 +31,13 @@ import com.eclipsesource.glsp.graph.GModelRoot; import com.eclipsesource.glsp.graph.GPoint; import com.eclipsesource.glsp.server.actionhandler.ComputedBoundsActionHandler; +import com.google.inject.Inject; public class EcoreComputedBoundsActionHandler extends ComputedBoundsActionHandler { + + @Inject + private ActionProcessor actionProcessor; + @Override public Optional execute(Action action, GraphicalModelState graphicalModelState) { ComputedBoundsAction computedBoundsAction = (ComputedBoundsAction) action; @@ -44,6 +52,10 @@ public Optional execute(Action action, GraphicalModelState graphicalMode GModelRoot model = modelState.getRoot(); if (model != null && model.getRevision() == computedBoundsAction.getRevision()) { LayoutUtil.applyBounds(model, computedBoundsAction, graphicalModelState); + if (modelState.getEditorContext().getEcoreFacade().diagramNeedsAutoLayout()) { + ActionMessage layoutMessage = new ActionMessage(clientId, new LayoutAction()); + actionProcessor.process(layoutMessage); + } return submissionHandler.doSubmitModel(false, modelState); } } From 1e683855a070ae972375b9cd0d6b86ad227b435a Mon Sep 17 00:00:00 2001 From: simonGraband Date: Mon, 25 Nov 2019 12:55:52 +0100 Subject: [PATCH 8/8] Resolves Issue #51 Dark theme is now supported by the diagram editor and the InputField for renaming Attributes/Classes is now better readable in both Themes. Light Theme, does not have a white background anymore, due to the way the theme colors in theia work. A follow-up issue will be submitted. Inheritance edges now have the same color as other edges. Signed-off-by: simonGraband --- client/sprotty-ecore/css/diagram.css | 37 +++++++++++++++++++--------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/client/sprotty-ecore/css/diagram.css b/client/sprotty-ecore/css/diagram.css index 839a54f..bfd3281 100644 --- a/client/sprotty-ecore/css/diagram.css +++ b/client/sprotty-ecore/css/diagram.css @@ -1,10 +1,21 @@ +:root { + --sprotty-background: var(--theia-layout-color3); + --sprotty-edge: var(--theia-ui-font-color1); + --sprotty-border: var(--theia-border-color2); +} + svg { margin-top: 15px; width: 100%; height: 500px; border-style: solid; border-width: 1px; - border-color: #bbb; + border-color: var(--sprotty-border); +} + +.label-edit input { + background: rgba(255, 255, 255, 0.5); + color: black; } .sprotty { @@ -14,7 +25,7 @@ svg { .sprotty-graph { font-size: 15pt; height: 100%; - background: #fff + background: var(--sprotty-background); } .ecore-node { @@ -94,10 +105,18 @@ svg { .ecore-edge { fill: none; - stroke: black; + stroke: var(--sprotty-edge); stroke-width: 2px; } +.ecore-edge>.sprotty-label { + stroke-width: 0; + width: inherit; + fill: var(--sprotty-edge); + font-weight: inherit; + font-size: 100%; +} + .feedback-edge { stroke-width: 2px; stroke: black; @@ -146,23 +165,19 @@ svg { } .ecore-edge>.triangle.inheritance { - fill: white; -} - -.ecore-edge.inheritance { - stroke: #888888; + fill: var(--sprotty-background); } .ecore-edge.aggregation .ecore-edge.composition { - stroke: black; + stroke: var(--sprotty-edge); } .ecore-edge>.diamond.aggregation { - fill: white; + fill: var(--sprotty-background); } .ecore-edge>.diamond.composition { - fill: black; + fill: var(--sprotty-edge); } .ecore-edge.selected {