devexpress-diagram
Version:
DevExpress Diagram Control
253 lines (229 loc) • 11.2 kB
text/typescript
import { MouseHandler } from "../MouseHandler";
import { DiagramDraggingEvent } from "../../Render/Toolbox/Toolbox";
import { DiagramMouseEvent, MouseEventElementType } from "../Event";
import { IShapeDescriptionManager } from "../../Model/Shapes/Descriptions/ShapeDescriptionManager";
import { Point } from "@devexpress/utils/lib/geometry/point";
import { AddShapeHistoryItem } from "../../History/Common/AddShapeHistoryItem";
import { SetSelectionHistoryItem } from "../../History/Common/SetSelectionHistoryItem";
import { MouseHandlerDraggingState } from "./MouseHandlerDraggingState";
import { History } from "../../History/History";
import { Selection } from "../../Selection/Selection";
import { DeleteShapeHistoryItem } from "../../History/Common/DeleteShapeHistoryItem";
import { ModelUtils } from "../../Model/ModelUtils";
import { DiagramModel } from "../../Model/Model";
import { MouseHandlerCancellableState } from "./MouseHandlerStateBase";
import { ItemKey } from "../../Model/DiagramItem";
import { IVisualizerManager } from "../Visualizers/VisualizersManager";
import { Shape } from "../../Model/Shapes/Shape";
import { DiagramModelOperation } from "../../ModelOperationSettings";
const NON_DOCUMENT_TIMER = 500;
const LOCK_UPDATEPAGESIZE_TIMER = 300;
export class MouseHandlerBeforeToolboxDraggingState extends MouseHandlerCancellableState {
dragging: DiagramDraggingEvent;
nonPageAreaTimer: number;
savedEvt: DiagramMouseEvent;
isModelEmpty: boolean;
constructor(handler: MouseHandler,
protected history: History,
protected model: DiagramModel,
protected selection: Selection,
protected visualizerManager: IVisualizerManager,
protected shapeDescriptionManager: IShapeDescriptionManager) {
super(handler);
this.isModelEmpty = model.items.length === 0;
}
cancelChanges() {
this.tryRemoveTimer();
}
onDragStart(evt: DiagramDraggingEvent) {
this.dragging = evt;
}
onDragEnd(evt: DiagramMouseEvent) {
this.cancelChanges();
this.handler.switchToDefaultState();
}
onMouseMove(evt: DiagramMouseEvent) {
if(evt.source.type > MouseEventElementType.Background) {
this.tryRemoveTimer();
this.switchToDraggingState(evt, false);
}
else if(evt.source.type === MouseEventElementType.Background && !this.isModelEmpty) {
this.savedEvt = evt;
if(this.nonPageAreaTimer === undefined)
this.nonPageAreaTimer = setTimeout(() => this.switchToDraggingState(this.savedEvt, true), NON_DOCUMENT_TIMER);
}
else if(this.nonPageAreaTimer !== undefined)
this.tryRemoveTimer();
}
switchToDraggingState(evt: DiagramMouseEvent, skipLockUpdatePageSize: boolean) {
this.handler.switchState(
new MouseHandlerToolboxDraggingState(this.handler, this.history, this.model, this.selection,
this.visualizerManager, this.shapeDescriptionManager, skipLockUpdatePageSize)
);
this.handler.state.onDragStart(this.dragging);
this.handler.state.onMouseMove(evt);
}
tryRemoveTimer() {
if(this.nonPageAreaTimer !== undefined) {
clearTimeout(this.nonPageAreaTimer);
delete this.nonPageAreaTimer;
}
}
finish() {
this.tryRemoveTimer();
}
}
export class MouseHandlerToolboxDraggingState extends MouseHandlerDraggingState {
startPoint: Point;
startShapePosition: Point;
dragging: DiagramDraggingEvent;
shapeKey: ItemKey;
deleteHistoryItem: DeleteShapeHistoryItem;
updatePageSizeTimer: number;
connectorsWithoutBeginItemInfo: any[];
connectorsWithoutEndItemInfo: any[];
constructor(handler: MouseHandler, history: History,
protected model: DiagramModel,
protected selection: Selection,
protected visualizerManager: IVisualizerManager,
protected shapeDescriptionManager: IShapeDescriptionManager,
skipLockUpdatePageSize: boolean) {
super(handler, history);
if(!skipLockUpdatePageSize)
this.updatePageSizeTimer = setTimeout(() => {
this.processAndRemoveUpdatePageSizeTimer();
}, LOCK_UPDATEPAGESIZE_TIMER);
}
cancelChanges() {
this.tryRemoveUpdatePageSizeTimer();
super.cancelChanges();
}
tryRemoveUpdatePageSizeTimer() {
if(this.updatePageSizeTimer !== undefined) {
clearTimeout(this.updatePageSizeTimer);
delete this.updatePageSizeTimer;
}
}
processAndRemoveUpdatePageSizeTimer() {
if(this.updatePageSizeTimer !== undefined) {
this.handler.tryUpdateModelSize();
delete this.updatePageSizeTimer;
}
}
onMouseMove(evt: DiagramMouseEvent) {
super.onMouseMove(evt);
const shape = this.model.findShape(this.shapeKey);
if(shape) {
this.visualizerManager.setExtensionLines([shape]);
const container = ModelUtils.findContainerByEventKey(this.model, this.selection, evt.source.key);
if(container && this.allowInsertToContainer(evt, shape, container))
this.visualizerManager.setContainerTarget(container, evt.source.type);
else
this.visualizerManager.resetContainerTarget();
}
}
getDraggingElementKeys(): ItemKey[] {
return this.shapeKey === undefined ? [] : [this.shapeKey];
}
onApplyChanges(evt: DiagramMouseEvent) {
if(evt.source.type === MouseEventElementType.Undefined) {
this.dragging.onCaptured(false);
if(this.shapeKey !== undefined && !this.deleteHistoryItem) {
const shape = this.model.findShape(this.shapeKey);
ModelUtils.detachConnectors(this.history, shape);
ModelUtils.removeFromContainer(this.history, this.model, shape);
this.deleteHistoryItem = new DeleteShapeHistoryItem(this.shapeKey, true);
this.history.addAndRedo(this.deleteHistoryItem);
}
}
else {
this.dragging.onCaptured(true);
if(this.shapeKey === undefined) {
this.startPoint = evt.modelPoint;
this.shapeKey = this.insertToolboxItem(evt);
const shape = this.model.findShape(this.shapeKey);
if(shape)
this.handler.addInteractingItem(shape, DiagramModelOperation.AddShape);
}
if(this.deleteHistoryItem) {
this.history.undoTransactionTo(this.deleteHistoryItem);
delete this.deleteHistoryItem;
}
const pos = this.getPosition(evt, this.startShapePosition);
const shape = this.model.findShape(this.shapeKey);
ModelUtils.setShapePosition(this.history, this.model, shape, pos);
ModelUtils.updateMovingShapeConnections(this.history, shape,
this.connectorsWithoutBeginItemInfo, this.connectorsWithoutEndItemInfo,
() => {
this.visualizerManager.resetConnectionTarget();
this.visualizerManager.resetConnectionPoints();
},
(shape, connectionPointIndex) => {
this.visualizerManager.setConnectionTarget(shape, MouseEventElementType.Shape);
this.visualizerManager.setConnectionPoints(shape, MouseEventElementType.Shape, connectionPointIndex, true);
},
(connector) => this.handler.addInteractingItem(connector)
);
ModelUtils.updateShapeAttachedConnectors(this.history, this.model, shape);
const container = ModelUtils.findContainerByEventKey(this.model, this.selection, evt.source.key);
if(shape && container && this.allowInsertToContainer(evt, shape, container))
ModelUtils.insertToContainer(this.history, this.model, shape, container);
else
ModelUtils.removeFromContainer(this.history, this.model, shape);
if(this.updatePageSizeTimer === undefined)
this.handler.tryUpdateModelSize((offsetLeft, offsetTop) => {
this.connectorsWithoutBeginItemInfo.forEach(pi => {
pi.point.x += offsetLeft;
pi.point.y += offsetTop;
});
this.connectorsWithoutEndItemInfo.forEach(pi => {
pi.point.x += offsetLeft;
pi.point.y += offsetTop;
});
});
}
}
onFinishWithChanges() {
if(!this.deleteHistoryItem)
this.history.addAndRedo(new SetSelectionHistoryItem(this.selection, [this.shapeKey]));
}
onDragStart(evt: DiagramDraggingEvent) {
this.dragging = evt;
this.connectorsWithoutBeginItemInfo = ModelUtils.getConnectorsWithoutBeginItemInfo(this.model);
this.connectorsWithoutEndItemInfo = ModelUtils.getConnectorsWithoutEndItemInfo(this.model);
}
onDragEnd(evt: DiagramMouseEvent) {
if(this.shapeKey !== undefined && evt.source.type === MouseEventElementType.Undefined)
this.cancelChanges();
this.handler.switchToDefaultState();
}
finish() {
this.visualizerManager.resetExtensionLines();
this.visualizerManager.resetContainerTarget();
this.visualizerManager.resetConnectionTarget();
this.visualizerManager.resetConnectionPoints();
this.processAndRemoveUpdatePageSizeTimer();
this.dragging.onFinishDragging();
super.finish();
}
insertToolboxItem(evt: DiagramMouseEvent): ItemKey {
const description = this.shapeDescriptionManager.get(this.dragging.data);
this.startShapePosition = this.getSnappedPoint(evt,
new Point(evt.modelPoint.x - description.defaultSize.width / 2, evt.modelPoint.y - description.defaultSize.height / 2)
);
const historyItem = new AddShapeHistoryItem(description, this.startShapePosition);
this.history.addAndRedo(historyItem);
ModelUtils.updateNewShapeProperties(this.history, this.selection, historyItem.shapeKey);
return historyItem.shapeKey;
}
private allowInsertToContainer(evt: DiagramMouseEvent, item: Shape, container: Shape): boolean {
if(this.handler.canMultipleSelection(evt))
return false;
return container && container.expanded && ModelUtils.canInsertToContainer(this.model, item, container);
}
private getPosition(evt: DiagramMouseEvent, basePoint: Point): Point {
return this.getSnappedPoint(evt, new Point(
basePoint.x + evt.modelPoint.x - this.startPoint.x,
basePoint.y + evt.modelPoint.y - this.startPoint.y));
}
}