sprotty
Version:
A next-gen framework for graphical views
295 lines • 13.3 kB
JavaScript
;
/********************************************************************************
* Copyright (c) 2017-2022 TypeFox 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
********************************************************************************/
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 __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UpdateModelCommand = void 0;
const inversify_1 = require("inversify");
const actions_1 = require("sprotty-protocol/lib/actions");
const geometry_1 = require("sprotty-protocol/lib/utils/geometry");
const animation_1 = require("../../base/animations/animation");
const command_1 = require("../../base/commands/command");
const fade_1 = require("../fade/fade");
const smodel_1 = require("../../base/model/smodel");
const move_1 = require("../move/move");
const model_1 = require("../fade/model");
const model_2 = require("../move/model");
const model_3 = require("../bounds/model");
const viewport_root_1 = require("../viewport/viewport-root");
const model_4 = require("../select/model");
const model_matching_1 = require("./model-matching");
const resize_1 = require("../bounds/resize");
const types_1 = require("../../base/types");
const model_5 = require("../viewport/model");
const routing_1 = require("../routing/routing");
const model_6 = require("../routing/model");
const smodel_utils_1 = require("../../base/model/smodel-utils");
let UpdateModelCommand = class UpdateModelCommand extends command_1.Command {
constructor(action) {
super();
this.action = action;
}
execute(context) {
let newRoot;
if (this.action.newRoot !== undefined) {
newRoot = context.modelFactory.createRoot(this.action.newRoot);
}
else {
newRoot = context.modelFactory.createRoot(context.root);
if (this.action.matches !== undefined)
this.applyMatches(newRoot, this.action.matches, context);
}
this.oldRoot = context.root;
this.newRoot = newRoot;
return this.performUpdate(this.oldRoot, this.newRoot, context);
}
performUpdate(oldRoot, newRoot, context) {
if ((this.action.animate === undefined || this.action.animate) && oldRoot.id === newRoot.id) {
let matchResult;
if (this.action.matches === undefined) {
const matcher = new model_matching_1.ModelMatcher();
matchResult = matcher.match(oldRoot, newRoot);
}
else {
matchResult = this.convertToMatchResult(this.action.matches, oldRoot, newRoot);
}
const animationOrRoot = this.computeAnimation(newRoot, matchResult, context);
if (animationOrRoot instanceof animation_1.Animation)
return animationOrRoot.start();
else
return animationOrRoot;
}
else {
if (oldRoot.type === newRoot.type && geometry_1.Dimension.isValid(oldRoot.canvasBounds))
newRoot.canvasBounds = oldRoot.canvasBounds;
if ((0, model_5.isViewport)(oldRoot) && (0, model_5.isViewport)(newRoot)) {
newRoot.zoom = oldRoot.zoom;
newRoot.scroll = oldRoot.scroll;
}
return newRoot;
}
}
applyMatches(root, matches, context) {
const index = root.index;
for (const match of matches) {
if (match.left !== undefined) {
const element = index.getById(match.left.id);
if (element instanceof smodel_1.SChildElementImpl)
element.parent.remove(element);
}
}
for (const match of matches) {
if (match.right !== undefined) {
const element = context.modelFactory.createElement(match.right);
let parent;
if (match.rightParentId !== undefined)
parent = index.getById(match.rightParentId);
if (parent instanceof smodel_1.SParentElementImpl)
parent.add(element);
else
root.add(element);
}
}
}
convertToMatchResult(matches, leftRoot, rightRoot) {
const result = {};
for (const match of matches) {
const converted = {};
let id = undefined;
if (match.left !== undefined) {
id = match.left.id;
converted.left = leftRoot.index.getById(id);
converted.leftParentId = match.leftParentId;
}
if (match.right !== undefined) {
id = match.right.id;
converted.right = rightRoot.index.getById(id);
converted.rightParentId = match.rightParentId;
}
if (id !== undefined)
result[id] = converted;
}
return result;
}
computeAnimation(newRoot, matchResult, context) {
const animationData = {
fades: []
};
(0, model_matching_1.forEachMatch)(matchResult, (id, match) => {
if (match.left !== undefined && match.right !== undefined) {
// The element is still there, but may have been moved
this.updateElement(match.left, match.right, animationData);
}
else if (match.right !== undefined) {
// An element has been added
const right = match.right;
if ((0, model_1.isFadeable)(right)) {
right.opacity = 0;
animationData.fades.push({
element: right,
type: 'in'
});
}
}
else if (match.left instanceof smodel_1.SChildElementImpl) {
// An element has been removed
const left = match.left;
if ((0, model_1.isFadeable)(left) && match.leftParentId !== undefined) {
if (!(0, smodel_utils_1.containsSome)(newRoot, left)) {
const parent = newRoot.index.getById(match.leftParentId);
if (parent instanceof smodel_1.SParentElementImpl) {
const leftCopy = context.modelFactory.createElement(left);
parent.add(leftCopy);
animationData.fades.push({
element: leftCopy,
type: 'out'
});
}
}
}
}
});
const animations = this.createAnimations(animationData, newRoot, context);
if (animations.length >= 2) {
return new animation_1.CompoundAnimation(newRoot, context, animations);
}
else if (animations.length === 1) {
return animations[0];
}
else {
return newRoot;
}
}
updateElement(left, right, animationData) {
if ((0, model_2.isLocateable)(left) && (0, model_2.isLocateable)(right)) {
const leftPos = left.position;
const rightPos = right.position;
if (!(0, geometry_1.almostEquals)(leftPos.x, rightPos.x) || !(0, geometry_1.almostEquals)(leftPos.y, rightPos.y)) {
if (animationData.moves === undefined)
animationData.moves = [];
animationData.moves.push({
element: right,
fromPosition: leftPos,
toPosition: rightPos
});
right.position = leftPos;
}
}
if ((0, model_3.isSizeable)(left) && (0, model_3.isSizeable)(right)) {
if (!geometry_1.Dimension.isValid(right.bounds)) {
right.bounds = {
x: right.bounds.x,
y: right.bounds.y,
width: left.bounds.width,
height: left.bounds.height
};
}
else if (!(0, geometry_1.almostEquals)(left.bounds.width, right.bounds.width)
|| !(0, geometry_1.almostEquals)(left.bounds.height, right.bounds.height)) {
if (animationData.resizes === undefined)
animationData.resizes = [];
animationData.resizes.push({
element: right,
fromDimension: {
width: left.bounds.width,
height: left.bounds.height,
},
toDimension: {
width: right.bounds.width,
height: right.bounds.height,
}
});
}
}
if (left instanceof model_6.SRoutableElementImpl && right instanceof model_6.SRoutableElementImpl && this.edgeRouterRegistry) {
if (animationData.edgeMementi === undefined)
animationData.edgeMementi = [];
animationData.edgeMementi.push({
edge: right,
before: this.takeSnapshot(left),
after: this.takeSnapshot(right),
});
}
if ((0, model_4.isSelectable)(left) && (0, model_4.isSelectable)(right)) {
right.selected = left.selected;
}
if (left instanceof smodel_1.SModelRootImpl && right instanceof smodel_1.SModelRootImpl) {
right.canvasBounds = left.canvasBounds;
}
if (left instanceof viewport_root_1.ViewportRootElementImpl && right instanceof viewport_root_1.ViewportRootElementImpl) {
right.scroll = left.scroll;
right.zoom = left.zoom;
}
}
takeSnapshot(edge) {
const router = this.edgeRouterRegistry.get(edge.routerKind);
return router.takeSnapshot(edge);
}
createAnimations(data, root, context) {
const animations = [];
if (data.fades.length > 0) {
animations.push(new fade_1.FadeAnimation(root, data.fades, context, true));
}
if (data.moves !== undefined && data.moves.length > 0) {
const movesMap = new Map;
for (const move of data.moves) {
movesMap.set(move.element.id, move);
}
animations.push(new move_1.MoveAnimation(root, movesMap, context, false));
}
if (data.resizes !== undefined && data.resizes.length > 0) {
const resizesMap = new Map;
for (const resize of data.resizes) {
resizesMap.set(resize.element.id, resize);
}
animations.push(new resize_1.ResizeAnimation(root, resizesMap, context, false));
}
if (data.edgeMementi !== undefined && data.edgeMementi.length > 0) {
animations.push(new move_1.MorphEdgesAnimation(root, data.edgeMementi, context, false));
}
return animations;
}
undo(context) {
return this.performUpdate(this.newRoot, this.oldRoot, context);
}
redo(context) {
return this.performUpdate(this.oldRoot, this.newRoot, context);
}
};
exports.UpdateModelCommand = UpdateModelCommand;
UpdateModelCommand.KIND = actions_1.UpdateModelAction.KIND;
__decorate([
(0, inversify_1.inject)(routing_1.EdgeRouterRegistry),
(0, inversify_1.optional)(),
__metadata("design:type", routing_1.EdgeRouterRegistry)
], UpdateModelCommand.prototype, "edgeRouterRegistry", void 0);
exports.UpdateModelCommand = UpdateModelCommand = __decorate([
(0, inversify_1.injectable)(),
__param(0, (0, inversify_1.inject)(types_1.TYPES.Action)),
__metadata("design:paramtypes", [Object])
], UpdateModelCommand);
//# sourceMappingURL=update-model.js.map