devexpress-diagram
Version:
DevExpress Diagram Control
156 lines (146 loc) • 9.01 kB
text/typescript
import { Connector, ConnectorPosition } from "../../Model/Connectors/Connector";
import { DiagramMouseEvent, MouseEventElementType } from "../Event";
import { MouseHandlerDraggingState } from "./MouseHandlerDraggingState";
import { DeleteConnectionHistoryItem } from "../../History/Common/DeleteConnectionHistoryItem";
import { AddConnectionHistoryItem } from "../../History/Common/AddConnectionHistoryItem";
import { MouseHandler } from "../MouseHandler";
import { History } from "../../History/History";
import { DiagramModel } from "../../Model/Model";
import { ItemKey, DiagramItem } from "../../Model/DiagramItem";
import { ModelUtils } from "../../Model/ModelUtils";
import { IVisualizerManager } from "../Visualizers/VisualizersManager";
import { ConnectionPointInfo } from "../Visualizers/ConnectionPointsVisualizer";
import { ConnectionTargetInfo } from "../Visualizers/ConnectionTargetVisualizer";
export abstract class MouseHandlerMoveConnectorPointStateBase extends MouseHandlerDraggingState {
connector: Connector;
pointIndex: number;
pointPosition: ConnectorPosition;
oppositePointPosition: ConnectorPosition;
oppositeItem: DiagramItem;
oppositeConnectionPointIndex: number;
targetItem: DiagramItem;
constructor(handler: MouseHandler, history: History,
protected model: DiagramModel,
protected visualizerManager: IVisualizerManager) {
super(handler, history);
}
finish(): void {
this.visualizerManager.resetConnectionTarget();
this.visualizerManager.resetConnectionPoints();
super.finish();
}
onMouseDown(evt: DiagramMouseEvent): void {
super.onMouseDown(evt);
if(this.connector)
this.handler.addInteractingItem(this.connector);
}
onMouseMove(evt: DiagramMouseEvent): void {
super.onMouseMove(evt);
if(!this.allowAttachToObjects(evt, false, false)) {
this.visualizerManager.resetConnectionTarget();
this.visualizerManager.resetConnectionPoints();
}
else if(this.connector) {
let item = this.connector.getExtremeItem(this.pointPosition);
this.visualizerManager.setConnectionTarget(item, evt.source.type);
const pointIndex = this.connector.getExtremeConnectionPointIndex(this.pointPosition);
if(!item && this.oppositeConnectionPointIndex !== -1 || !this.allowAttachToObjects(evt, true, false))
item = this.model.findItem(evt.source.key);
this.visualizerManager.setConnectionPoints(item, evt.source.type, pointIndex, true);
}
}
onApplyChanges(evt: DiagramMouseEvent): void {
let point = this.getSnappedPoint(evt, evt.modelPoint);
if(this.pointPosition !== undefined) {
if(this.oppositePointPosition === undefined) {
this.oppositePointPosition = this.getOppositePointPosition();
this.oppositeItem = this.connector.getExtremeItem(this.oppositePointPosition);
this.oppositeConnectionPointIndex = this.connector.getExtremeConnectionPointIndex(this.oppositePointPosition);
}
this.targetItem = this.model.findItem(evt.source.key);
const item = this.allowAttachToObjects(evt, true, true) ? this.targetItem : undefined;
let connectionPointIndex = -1;
if(evt.source.type === MouseEventElementType.ShapeConnectionPoint)
connectionPointIndex = parseInt(evt.source.value);
if(item && (evt.source.type === MouseEventElementType.Shape || evt.source.type === MouseEventElementType.ShapeConnectionPoint) &&
(this.connector.getExtremeItem(this.oppositePointPosition) !== item ||
(connectionPointIndex !== -1 && this.oppositeConnectionPointIndex !== -1 &&
connectionPointIndex !== this.oppositeConnectionPointIndex))) {
if(this.connector.getExtremeItem(this.pointPosition) !== item ||
this.connector.getExtremeConnectionPointIndex(this.pointPosition) !== connectionPointIndex) {
if(this.connector.getExtremeItem(this.pointPosition))
this.history.addAndRedo(new DeleteConnectionHistoryItem(this.connector, this.pointPosition));
this.history.addAndRedo(new AddConnectionHistoryItem(this.connector, item, connectionPointIndex, this.pointPosition));
if(this.oppositeItem)
this.updateOppositeItemConnectionPointIndex(connectionPointIndex);
}
point = item.getConnectionPointPosition(connectionPointIndex,
this.connector.points[this.pointIndex + (this.pointPosition === ConnectorPosition.End ? -1 : 1)]
);
this.visualizerManager.setConnectionPointIndex(connectionPointIndex);
}
else if(this.connector.getExtremeItem(this.pointPosition)) {
this.history.addAndRedo(new DeleteConnectionHistoryItem(this.connector, this.pointPosition));
if(this.oppositeItem)
this.updateOppositeItemConnectionPointIndex(this.oppositeConnectionPointIndex);
}
}
ModelUtils.moveConnectorPoint(this.history, this.connector, this.pointIndex, point);
ModelUtils.updateConnectorAttachedPoints(this.history, this.model, this.connector);
this.handler.tryUpdateModelSize();
}
updateOppositeItemConnectionPointIndex(connectionPointIndex: number): void {
const pointIndex = connectionPointIndex === -1 ? -1 : this.oppositeConnectionPointIndex;
if(pointIndex !== this.connector.getExtremeConnectionPointIndex(this.oppositePointPosition)) {
this.history.addAndRedo(new DeleteConnectionHistoryItem(this.connector, this.oppositePointPosition));
this.history.addAndRedo(new AddConnectionHistoryItem(this.connector, this.oppositeItem,
pointIndex, this.oppositePointPosition));
}
}
onFinishWithChanges(): void {
ModelUtils.updateConnectorContainer(this.history, this.model, this.connector);
ModelUtils.deleteConnectorUnnecessaryPoints(this.history, this.connector);
this.handler.tryUpdateModelSize();
}
getDraggingElementKeys(): ItemKey[] {
return this.connector ? [this.connector.key] : [];
}
private getOppositePointPosition() {
return this.pointPosition === ConnectorPosition.Begin ? ConnectorPosition.End : ConnectorPosition.Begin;
}
private allowAttachToObjects(evt: DiagramMouseEvent, checkContainers: boolean, checkOppositeItem: boolean) {
if(this.handler.canMultipleSelection(evt))
return false;
const connector = this.connector;
if(connector && evt.source.type === MouseEventElementType.Shape) {
const targetItem = this.model.findItem(evt.source.key);
if(checkContainers && this.model.findItemContainerCore(connector, c => c === targetItem))
return false;
if(checkContainers && this.oppositeItem && this.model.findItemContainerCore(this.oppositeItem, c => c === targetItem))
return false;
if(checkOppositeItem && this.oppositeItem === targetItem && this.oppositeConnectionPointIndex === -1)
return false;
}
return true;
}
onConnectionPointsShow(key: string, points: ConnectionPointInfo[]): void {
if(this.connector && this.pointPosition !== undefined && (this.connector.endItem && this.connector.endItem.key === key || this.connector.beginItem && this.connector.beginItem.key === key)) {
const position = this.connector.beginItem && this.connector.beginItem.key === key ? ConnectorPosition.Begin : ConnectorPosition.End;
points.forEach((point, index) => {
point.allowed = this.handler.canPerformChangeConnectionOnUpdateUI(
this.connector,
{ item: this.connector.getExtremeItem(position), position: position, connectionPointIndex: index }
);
});
}
}
onConnectionTargetShow(key: string, info: ConnectionTargetInfo): void {
if(this.connector && this.pointPosition !== undefined && (this.connector.endItem && this.connector.endItem.key === key || this.connector.beginItem && this.connector.beginItem.key === key)) {
const position = this.connector.beginItem && this.connector.beginItem.key === key ? ConnectorPosition.Begin : ConnectorPosition.End;
info.allowed = this.handler.canPerformChangeConnectionOnUpdateUI(
this.connector,
{ item: this.connector.getExtremeItem(position), position: position, connectionPointIndex: -1 }
);
}
}
}