devexpress-diagram
Version:
DevExpress Diagram Control
214 lines (188 loc) • 10.3 kB
text/typescript
import { ConnectorPosition, Connector } from "../../Model/Connectors/Connector";
import { DiagramMouseEvent } from "../Event";
import { AddConnectionHistoryItem } from "../../History/Common/AddConnectionHistoryItem";
import { AddConnectorHistoryItem } from "../../History/Common/AddConnectorHistoryItem";
import { DiagramItem, ConnectionPointSide } from "../../Model/DiagramItem";
import { MouseHandlerMoveConnectorPointStateBase } from "./MouseHandlerMoveConnectorPointStateBase";
import { SetSelectionHistoryItem } from "../../History/Common/SetSelectionHistoryItem";
import { MouseHandler } from "../MouseHandler";
import { History } from "../../History/History";
import { Selection } from "../../Selection/Selection";
import { DiagramModel } from "../../Model/Model";
import { IVisualizerManager } from "../Visualizers/VisualizersManager";
import { Point } from "@devexpress/utils/lib/geometry/point";
import { AddShapeHistoryItem } from "../../History/Common/AddShapeHistoryItem";
import { ModelUtils } from "../../Model/ModelUtils";
import { Shape } from "../../Model/Shapes/Shape";
import { IShapeDescriptionManager } from "../../Model/Shapes/Descriptions/ShapeDescriptionManager";
import { DeleteConnectionHistoryItem } from "../../History/Common/DeleteConnectionHistoryItem";
import { DeleteConnectorHistoryItem } from "../../History/Common/DeleteConnectorHistoryItem";
export class MouseHandlerCreateConnectorState extends MouseHandlerMoveConnectorPointStateBase {
connectionPointIndex: number;
connectedItem: DiagramItem;
constructor(handler: MouseHandler, history: History, model: DiagramModel, visualizerManager: IVisualizerManager,
protected shapeDescriptionManager: IShapeDescriptionManager,
protected selection: Selection,
connectionPointIndex?: number) {
super(handler, history, model, visualizerManager);
this.connectionPointIndex = connectionPointIndex;
}
onMouseDown(evt: DiagramMouseEvent) {
if(this.connectionPointIndex === undefined)
this.connectionPointIndex = parseInt(evt.source.value);
this.connectedItem = this.model.findItem(evt.source.key);
this.pointIndex = 1;
this.pointPosition = ConnectorPosition.End;
super.onMouseDown(evt);
}
onMouseUp(evt: DiagramMouseEvent) {
if(this.connector && !this.connector.endItem)
this.createNewShapeAtConnectorEnd(evt);
super.onMouseUp(evt);
}
onApplyChanges(evt: DiagramMouseEvent) {
const point = this.getSnappedPoint(evt, evt.modelPoint);
if(!this.connector) {
const historyItem = new AddConnectorHistoryItem([this.connectedItem.getConnectionPointPosition(this.connectionPointIndex, point), point]);
this.history.addAndRedo(historyItem);
this.connector = this.model.findConnector(historyItem.connectorKey);
this.handler.addInteractingItem(this.connector);
this.history.addAndRedo(
new AddConnectionHistoryItem(this.connector, this.connectedItem, this.connectionPointIndex, ConnectorPosition.Begin)
);
ModelUtils.updateNewConnectorProperties(this.history, this.selection, this.connector.key);
}
else super.onApplyChanges(evt);
}
checkStoredPermissionsOnFinish() {
if(this.connector && this.connector.endItem)
super.checkStoredPermissionsOnFinish();
}
onFinishWithChanges() {
super.onFinishWithChanges();
this.history.addAndRedo(new SetSelectionHistoryItem(this.selection, [this.connector.key]));
}
private createNewShapeAtConnectorEnd(evt: DiagramMouseEvent) {
const beginShape = this.connector && <Shape> this.connector.beginItem;
if(!beginShape) return;
if(this.connector && !this.handler.canPerformChangeConnection(this.connector,
{ position: ConnectorPosition.End, connectionPointIndex: -1 })) {
this.cancelChanges();
return;
}
const side = this.getNewShapeSide(this.connector);
const point = this.getSnappedPoint(evt, evt.modelPoint);
const category = this.shapeDescriptionManager.getCategoryByDescription(beginShape.description);
const getPositionToInsertShapeTo = (shape: Shape): Point => {
const clonedShape = shape.clone();
clonedShape.position = point.clone();
const position = this.getNewShapePosition(clonedShape, side);
return this.handler.getSnappedPointOnDragPoint(evt, position);
};
this.handler.showContextToolbox(point, getPositionToInsertShapeTo, side, category, (shapeType: string) => {
if(!shapeType)
return;
this.handler.beginStorePermissions();
this.history.beginTransaction();
const historyItem = new AddShapeHistoryItem(this.shapeDescriptionManager.get(shapeType), point);
this.history.addAndRedo(historyItem);
const shape = this.model.findShape(historyItem.shapeKey);
const container = this.targetItem && this.model.findNearestContainer(this.targetItem.key);
if(container)
ModelUtils.insertToContainer(this.history, this.model, shape, container);
const newPosition = this.getNewShapePosition(shape, side);
ModelUtils.setShapePosition(this.history, this.model, shape, this.getSnappedPoint(evt, newPosition));
ModelUtils.updateNewShapeProperties(this.history, this.selection, shape.key);
this.history.addAndRedo(new AddConnectionHistoryItem(this.connector, shape,
shape.getConnectionPointIndexForSide(side), ConnectorPosition.End));
if(container)
ModelUtils.updateConnectorContainer(this.history, this.model, this.connector);
ModelUtils.updateShapeAttachedConnectors(this.history, this.model, shape);
if(!this.handler.isStoredPermissionsGranted()) {
this.handler.lockPermissions();
this.history.undoTransaction();
this.handler.unlockPermissions();
this.checkNewConnectorPermissions();
}
else {
this.handler.tryUpdateModelSize();
this.history.addAndRedo(new SetSelectionHistoryItem(this.selection, [shape.key]));
}
this.history.endTransaction();
this.handler.endStorePermissions();
this.handler.hideContextToolbox(true);
}, () => {
this.checkNewConnectorPermissions();
});
}
private checkNewConnectorPermissions() {
if(this.connector && !this.handler.canPerformChangeConnection(this.connector,
{ position: ConnectorPosition.End, connectionPointIndex: -1 })) {
this.handler.lockPermissions();
this.history.beginTransaction();
this.history.addAndRedo(new SetSelectionHistoryItem(this.selection, []));
if(this.connector.beginItem)
this.history.addAndRedo(new DeleteConnectionHistoryItem(this.connector, ConnectorPosition.Begin));
if(this.connector.endItem)
this.history.addAndRedo(new DeleteConnectionHistoryItem(this.connector, ConnectorPosition.End));
this.history.addAndRedo(new DeleteConnectorHistoryItem(this.connector.key));
this.history.endTransaction();
this.handler.unlockPermissions();
}
}
private getNewShapePosition(shape: Shape, side: ConnectionPointSide): Point {
switch(side) {
case ConnectionPointSide.North:
return shape.position.clone().offset(-shape.size.width / 2, 0);
case ConnectionPointSide.South:
return shape.position.clone().offset(-shape.size.width / 2, -shape.size.height);
case ConnectionPointSide.East:
return shape.position.clone().offset(-shape.size.width, -shape.size.height / 2);
case ConnectionPointSide.West:
return shape.position.clone().offset(0, -shape.size.height / 2);
}
}
private getNewShapeSide(connector: Connector): ConnectionPointSide {
const renderPoints = connector.getRenderPoints();
return MouseHandlerCreateConnectorState.getNewShapeSideByConnectorPoints(
renderPoints[renderPoints.length - 1],
renderPoints[renderPoints.length - 2]
);
}
protected getSourceItem(): DiagramItem {
return this.connectedItem;
}
static getNewShapeSideByConnectorPoints(point: Point, directionPoint: Point): ConnectionPointSide {
if(point.x === directionPoint.x)
if(point.y > directionPoint.y)
return ConnectionPointSide.North;
else
return ConnectionPointSide.South;
else if(point.x > directionPoint.x)
if(point.y === directionPoint.y)
return ConnectionPointSide.West;
else if(point.y > directionPoint.y)
if(Math.abs(point.x - directionPoint.x) > Math.abs(point.y - directionPoint.y))
return ConnectionPointSide.West;
else
return ConnectionPointSide.North;
else
if(Math.abs(point.x - directionPoint.x) > Math.abs(point.y - directionPoint.y))
return ConnectionPointSide.West;
else
return ConnectionPointSide.South;
else
if(point.y === directionPoint.y)
return ConnectionPointSide.East;
else if(point.y > directionPoint.y)
if(Math.abs(point.x - directionPoint.x) > Math.abs(point.y - directionPoint.y))
return ConnectionPointSide.East;
else
return ConnectionPointSide.North;
else
if(Math.abs(point.x - directionPoint.x) > Math.abs(point.y - directionPoint.y))
return ConnectionPointSide.East;
else
return ConnectionPointSide.South;
}
}