@eclipse-glsp/client
Version:
A sprotty-based client for GLSP
262 lines • 13.9 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var EdgeEditTool_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EdgeEditListener = exports.EdgeEditTool = void 0;
/********************************************************************************
* Copyright (c) 2019-2024 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
********************************************************************************/
const sprotty_1 = require("@eclipse-glsp/sprotty");
const inversify_1 = require("inversify");
const drag_aware_mouse_listener_1 = require("../../../base/drag-aware-mouse-listener");
const css_feedback_1 = require("../../../base/feedback/css-feedback");
const selection_service_1 = require("../../../base/selection-service");
const gmodel_util_1 = require("../../../utils/gmodel-util");
const model_1 = require("../../reconnect/model");
const base_tools_1 = require("../base-tools");
const dangling_edge_feedback_1 = require("../edge-creation/dangling-edge-feedback");
const edge_edit_tool_feedback_1 = require("./edge-edit-tool-feedback");
let EdgeEditTool = EdgeEditTool_1 = class EdgeEditTool extends base_tools_1.BaseEditTool {
get id() {
return EdgeEditTool_1.ID;
}
enable() {
this.edgeEditListener = new EdgeEditListener(this);
// install feedback move mouse listener for client-side move updates
this.feedbackEdgeSourceMovingListener = new edge_edit_tool_feedback_1.FeedbackEdgeSourceMovingMouseListener(this.anchorRegistry, this.feedbackDispatcher);
this.feedbackEdgeTargetMovingListener = new edge_edit_tool_feedback_1.FeedbackEdgeTargetMovingMouseListener(this.anchorRegistry, this.feedbackDispatcher);
this.feedbackMovingListener = new edge_edit_tool_feedback_1.FeedbackEdgeRouteMovingMouseListener(this.changeBoundsManager, this.edgeRouterRegistry);
this.toDisposeOnDisable.push(this.edgeEditListener, this.mouseTool.registerListener(this.edgeEditListener), this.feedbackEdgeSourceMovingListener, this.feedbackEdgeTargetMovingListener, this.feedbackMovingListener, this.selectionService.addListener(this.edgeEditListener));
}
registerFeedbackListeners() {
this.mouseTool.register(this.feedbackMovingListener);
this.mouseTool.register(this.feedbackEdgeSourceMovingListener);
this.mouseTool.register(this.feedbackEdgeTargetMovingListener);
}
deregisterFeedbackListeners() {
this.feedbackEdgeSourceMovingListener.dispose();
this.feedbackEdgeTargetMovingListener.dispose();
this.mouseTool.deregister(this.feedbackEdgeSourceMovingListener);
this.mouseTool.deregister(this.feedbackEdgeTargetMovingListener);
this.mouseTool.deregister(this.feedbackMovingListener);
}
};
exports.EdgeEditTool = EdgeEditTool;
EdgeEditTool.ID = 'glsp.edge-edit-tool';
__decorate([
(0, inversify_1.inject)(selection_service_1.SelectionService),
__metadata("design:type", selection_service_1.SelectionService)
], EdgeEditTool.prototype, "selectionService", void 0);
__decorate([
(0, inversify_1.inject)(sprotty_1.AnchorComputerRegistry),
__metadata("design:type", sprotty_1.AnchorComputerRegistry)
], EdgeEditTool.prototype, "anchorRegistry", void 0);
__decorate([
(0, inversify_1.inject)(sprotty_1.EdgeRouterRegistry),
(0, inversify_1.optional)(),
__metadata("design:type", sprotty_1.EdgeRouterRegistry)
], EdgeEditTool.prototype, "edgeRouterRegistry", void 0);
__decorate([
(0, inversify_1.inject)(sprotty_1.TYPES.IChangeBoundsManager),
__metadata("design:type", Object)
], EdgeEditTool.prototype, "changeBoundsManager", void 0);
exports.EdgeEditTool = EdgeEditTool = EdgeEditTool_1 = __decorate([
(0, inversify_1.injectable)()
], EdgeEditTool);
class EdgeEditListener extends drag_aware_mouse_listener_1.DragAwareMouseListener {
constructor(tool) {
super();
this.tool = tool;
this.cursorFeedback = this.tool.createFeedbackEmitter();
this.editFeedback = this.tool.createFeedbackEmitter();
}
isValidEdge(edge) {
return edge !== undefined && edge.id !== (0, dangling_edge_feedback_1.feedbackEdgeId)(edge.root) && (0, sprotty_1.isSelected)(edge);
}
setEdgeSelected(edge) {
this.edge = edge;
// note: order is important here as we want the reconnect handles to cover the routing handles
if ((0, sprotty_1.canEditRouting)(edge)) {
this.editFeedback.add(edge_edit_tool_feedback_1.SwitchRoutingModeAction.create({ elementsToActivate: [this.edge.id] }), edge_edit_tool_feedback_1.SwitchRoutingModeAction.create({ elementsToDeactivate: [this.edge.id] }));
}
if ((0, model_1.isReconnectable)(edge)) {
this.editFeedback.add(edge_edit_tool_feedback_1.ShowEdgeReconnectHandlesFeedbackAction.create(this.edge.id), edge_edit_tool_feedback_1.HideEdgeReconnectHandlesFeedbackAction.create());
}
this.editFeedback.submit();
}
isEdgeSelected() {
return this.edge !== undefined && (0, sprotty_1.isSelected)(this.edge);
}
setReconnectHandleSelected(edge, reconnectHandle) {
if (this.edge && this.edge.target && this.edge.source) {
this.editFeedback.dispose();
if ((0, model_1.isSourceRoutingHandle)(edge, reconnectHandle)) {
this.editFeedback
.add((0, css_feedback_1.cursorFeedbackAction)(css_feedback_1.CursorCSS.EDGE_RECONNECT), (0, css_feedback_1.cursorFeedbackAction)())
.add(edge_edit_tool_feedback_1.DrawFeedbackEdgeSourceAction.create({ elementTypeId: this.edge.type, targetId: this.edge.targetId }), dangling_edge_feedback_1.RemoveFeedbackEdgeAction.create())
.submit();
this.reconnectMode = 'NEW_SOURCE';
}
else if ((0, model_1.isTargetRoutingHandle)(edge, reconnectHandle)) {
this.editFeedback
.add((0, css_feedback_1.cursorFeedbackAction)(css_feedback_1.CursorCSS.EDGE_CREATION_TARGET), (0, css_feedback_1.cursorFeedbackAction)())
.add(dangling_edge_feedback_1.DrawFeedbackEdgeAction.create({ elementTypeId: this.edge.type, sourceId: this.edge.sourceId }), dangling_edge_feedback_1.RemoveFeedbackEdgeAction.create())
.submit();
this.reconnectMode = 'NEW_TARGET';
}
}
}
isReconnecting() {
return this.reconnectMode !== undefined;
}
isReconnectingNewSource() {
return this.reconnectMode === 'NEW_SOURCE';
}
setRoutingHandleSelected(edge, routingHandle) {
if (this.edge && this.edge.target && this.edge.source) {
this.routingHandle = routingHandle;
}
}
requiresReconnect(sourceId, targetId) {
return this.edge !== undefined && (this.edge.sourceId !== sourceId || this.edge.targetId !== targetId);
}
setNewConnectable(connectable) {
this.newConnectable = connectable;
}
isReadyToReconnect() {
return this.edge && this.isReconnecting() && this.newConnectable !== undefined;
}
isReadyToReroute() {
return this.routingHandle !== undefined;
}
mouseDown(target, event) {
const result = super.mouseDown(target, event);
if (event.button === 0) {
const reconnectHandle = (0, sprotty_1.findParentByFeature)(target, model_1.isReconnectHandle);
const routingHandle = !reconnectHandle ? (0, sprotty_1.findParentByFeature)(target, gmodel_util_1.isRoutingHandle) : undefined;
const edge = (0, sprotty_1.findParentByFeature)(target, gmodel_util_1.isRoutable);
if (this.isEdgeSelected() && edge && reconnectHandle) {
// PHASE 2 Reconnect: Select reconnect handle on selected edge
this.setReconnectHandleSelected(edge, reconnectHandle);
}
else if (this.isEdgeSelected() && edge && routingHandle) {
// PHASE 2 Reroute: Select routing handle on selected edge
this.setRoutingHandleSelected(edge, routingHandle);
}
else if (this.isValidEdge(edge)) {
// PHASE 1: Select edge
this.dispose();
this.tool.registerFeedbackListeners();
this.setEdgeSelected(edge);
}
}
else if (event.button === 2) {
this.dispose();
}
return result;
}
draggingMouseMove(target, event) {
// reset any selected connectables when we are dragging, maybe the user is just panning
this.setNewConnectable(undefined);
return super.draggingMouseMove(target, event);
}
mouseUp(target, event) {
const result = super.mouseUp(target, event);
if (!this.isReadyToReconnect() && !this.isReadyToReroute()) {
return result;
}
if (this.edge && this.newConnectable) {
const sourceElementId = this.isReconnectingNewSource() ? this.newConnectable.id : this.edge.sourceId;
const targetElementId = this.isReconnectingNewSource() ? this.edge.targetId : this.newConnectable.id;
if (this.requiresReconnect(sourceElementId, targetElementId)) {
result.push(sprotty_1.ReconnectEdgeOperation.create({ edgeElementId: this.edge.id, sourceElementId, targetElementId }));
}
this.dispose();
}
else if (this.edge && this.routingHandle) {
// we need to re-retrieve the edge as it might have changed due to a server update since we do not reset the state between
// reroute actions
const latestEdge = target.index.getById(this.edge.id);
if (latestEdge && (0, gmodel_util_1.isRoutable)(latestEdge)) {
const newRoutingPoints = (0, gmodel_util_1.calcElementAndRoutingPoints)(latestEdge, this.tool.edgeRouterRegistry);
result.push(sprotty_1.ChangeRoutingPointsOperation.create([newRoutingPoints]));
this.routingHandle = undefined;
}
}
return result;
}
mouseOver(target, _event) {
if (this.edge && this.isReconnecting()) {
const currentTarget = (0, sprotty_1.findParentByFeature)(target, sprotty_1.isConnectable);
if (!this.newConnectable || currentTarget !== this.newConnectable) {
this.setNewConnectable(currentTarget);
if (currentTarget) {
if ((this.reconnectMode === 'NEW_SOURCE' && currentTarget.canConnect(this.edge, 'source')) ||
(this.reconnectMode === 'NEW_TARGET' && currentTarget.canConnect(this.edge, 'target'))) {
this.cursorFeedback.add((0, css_feedback_1.cursorFeedbackAction)(css_feedback_1.CursorCSS.EDGE_RECONNECT), (0, css_feedback_1.cursorFeedbackAction)()).submit();
return [];
}
}
this.cursorFeedback.add((0, css_feedback_1.cursorFeedbackAction)(css_feedback_1.CursorCSS.OPERATION_NOT_ALLOWED), (0, css_feedback_1.cursorFeedbackAction)()).submit();
}
}
return [];
}
selectionChanged(root, selectedElements) {
if (this.edge) {
if (selectedElements.indexOf(this.edge.id) > -1) {
// our active edge is still selected, nothing to do
return;
}
if (this.isReconnecting()) {
// we are reconnecting, so we may have clicked on a potential target
return;
}
// try to find some other selected element and mark that active
for (const elementId of selectedElements.reverse()) {
const element = root.index.getById(elementId);
if (element) {
const edge = (0, sprotty_1.findParentByFeature)(element, gmodel_util_1.isRoutable);
if (this.isValidEdge(edge)) {
// PHASE 1: Select edge
this.setEdgeSelected(edge);
return;
}
}
}
this.dispose();
}
}
dispose() {
this.edge = undefined;
this.reconnectMode = undefined;
this.newConnectable = undefined;
this.routingHandle = undefined;
this.cursorFeedback.dispose();
this.editFeedback.dispose();
this.tool.deregisterFeedbackListeners();
super.dispose();
}
}
exports.EdgeEditListener = EdgeEditListener;
//# sourceMappingURL=edge-edit-tool.js.map