devexpress-diagram
Version:
DevExpress Diagram Control
241 lines (222 loc) • 11.7 kB
text/typescript
import { Shape } from "../Shapes/Shape";
import { DiagramItem } from "../DiagramItem";
import { EventDispatcher } from "../../Utils";
import { Point } from "@devexpress/utils/lib/geometry/point";
import { ModelOperationSettings, DiagramModelOperation } from "../../ModelOperationSettings";
import { Connector, ConnectorPosition } from "../Connectors/Connector";
import { RequestedEntity } from "./Entities/RequestedEntity";
import { AddShapeRequestedEntity, AddShapeEventArgs } from "./Entities/AddShape";
import { DeleteShapeRequestedEntity, DeleteShapeEventArgs } from "./Entities/DeleteShape";
import { DeleteConnectorRequestedEntity, DeleteConnectorEventArgs } from "./Entities/DeleteConnector";
import { AddShapeFromToolboxRequestedEntity, AddShapeFromToolboxEventArgs } from "./Entities/AddShapeFromToolbox";
import { ChangeConnectionRequestedEntity, ChangeConnectionEventArgs } from "./Entities/ChangeConnection";
import { ChangeConnectorPointsRequestedEntity, ChangeConnectorPointsEventArgs } from "./Entities/ChangeConnectorPoints";
import { BeforeChangeShapeTextRequestedEntity, BeforeChangeShapeTextEventArgs } from "./Entities/BeforeChangeShapeText";
import { BeforeChangeConnectorTextRequestedEntity } from "./Entities/BeforeChangeConnectorText";
import { ChangeShapeTextEventArgs, ChangeShapeTextRequestedEntity } from "./Entities/ChangeShapeText";
import { ChangeConnectorTextRequestedEntity } from "./Entities/ChangeConnectorText";
import { PermissionsProviderStorage } from "./PermissionsProviderStorage";
import { ResizeShapeRequestedEntity, IResizeShapeInfo } from "./Entities/ResizeShape";
import { IApiController } from "../../Api/ApiController";
import { ISelectionChangesListener, Selection } from "../../Selection/Selection";
import { IMoveShapeInfo, MoveShapeRequestedEntity } from "./Entities/MoveShape";
import { IModelChangesListener } from "../ModelManipulator";
import { ItemChange } from "../ModelChange";
import { Size } from "@devexpress/utils/lib/geometry/size";
export class PermissionsProvider implements ISelectionChangesListener, IModelChangesListener {
apiController: IApiController;
operationSettings: ModelOperationSettings;
storage: PermissionsProviderStorage;
onRequestOperation: EventDispatcher<IPermissionRequestListener> = new EventDispatcher();
private cache: RequestedEntity[] = [];
private permissionsLockCount: number = 0;
private requestDeleteItems: {[key: string]: DiagramItem} = {};
private updateUICount: number = 0;
constructor(apiController: IApiController) {
this.apiController = apiController;
this.operationSettings = new ModelOperationSettings();
this.storage = new PermissionsProviderStorage();
}
notifySelectionChanged(_selection: Selection): void {
this.clearCache();
}
notifyModelChanged(changes: ItemChange[]) {
this.clearCache();
}
notifyPageColorChanged(color: number) {}
notifyPageSizeChanged(pageSize: Size, pageLandscape: boolean) {}
clearCache(operation?: DiagramModelOperation): void {
if(operation !== undefined)
this.cache = this.cache.filter(entry => entry.operation !== operation);
else
this.cache = [];
}
canDeleteItems(items: DiagramItem[]): boolean {
let allowed = true;
items.forEach((item) => {
let entity: RequestedEntity;
if(item instanceof Shape)
entity = new DeleteShapeRequestedEntity(this.apiController, item);
if(item instanceof Connector)
entity = new DeleteConnectorRequestedEntity(this.apiController, item);
allowed = allowed && this.requestOperation(entity);
});
return allowed;
}
canAddItems(items: DiagramItem[]): boolean {
let allowed = true;
items.forEach((item) => {
if(item instanceof Shape)
allowed = allowed && this.requestOperation(new AddShapeRequestedEntity(this.apiController, item));
if(item instanceof Connector) {
allowed = allowed && this.canChangeConnection(item, item.beginItem, undefined, ConnectorPosition.Begin, item.beginConnectionPointIndex);
allowed = allowed && this.canChangeConnection(item, item.endItem, undefined, ConnectorPosition.End, item.endConnectionPointIndex);
}
});
return allowed;
}
canAddShapeFromToolbox(itemType: string): boolean {
return this.requestOperation(new AddShapeFromToolboxRequestedEntity(this.apiController, itemType));
}
canChangeConnection(connector: Connector, item: DiagramItem, oldItem: DiagramItem, position: ConnectorPosition, connectionPointIndex: number): boolean {
if(connector && this.requestDeleteItems[connector.key])
return true;
if(item === undefined || item === null || item instanceof Shape)
return this.requestOperation(new ChangeConnectionRequestedEntity(this.apiController, connector, item as Shape, oldItem as Shape, position, connectionPointIndex));
return true;
}
canChangeConnectorPoints(connector: Connector, oldPoints: Point[], points: Point[]): boolean {
if(connector && this.requestDeleteItems[connector.key])
return true;
return this.requestOperation(new ChangeConnectorPointsRequestedEntity(this.apiController, connector, oldPoints, points));
}
canChangeShapeText(shape: Shape): boolean {
return this.requestOperation(new BeforeChangeShapeTextRequestedEntity(this.apiController, shape));
}
canChangeConnectorText(connector: Connector, position: number): boolean {
return this.requestOperation(new BeforeChangeConnectorTextRequestedEntity(this.apiController, connector, position));
}
canApplyShapeTextChange(shape: Shape, textToApply: string): boolean {
return this.requestOperation(new ChangeShapeTextRequestedEntity(this.apiController, shape, textToApply));
}
canApplyConnectorTextChange(connector: Connector, position: number, textToApply: string): boolean {
return this.requestOperation(new ChangeConnectorTextRequestedEntity(this.apiController, connector, position, textToApply));
}
canResizeShapes(shapeInfo: IResizeShapeInfo[]): boolean {
let allowed = true;
shapeInfo.forEach((info) => {
allowed = allowed && this.requestOperation(new ResizeShapeRequestedEntity(this.apiController, info.shape, info.oldSize, info.size));
});
return allowed;
}
canMoveShapes(shapeInfo: IMoveShapeInfo[]): boolean {
let allowed = true;
shapeInfo.forEach((info) => {
allowed = allowed && this.requestOperation(new MoveShapeRequestedEntity(this.apiController, info.shape, info.oldPosition, info.position));
});
return allowed;
}
private requestOperation(entity: RequestedEntity): boolean {
let allowed = true;
if(!this.permissionsLockCount) {
let cachedEntity;
if(this.updateUICount > 0)
this.cache.forEach(item => {
if(item.equals(entity)) {
cachedEntity = item;
return;
}
});
if(cachedEntity)
allowed = cachedEntity.allowed;
else {
this.requestOperationCore(entity);
if(this.updateUICount > 0)
this.cache.push(entity);
allowed = entity.allowed;
}
if(this.updateUICount === 0 && this.storage.needStorePermissions()) {
this.storage.storePermission(entity.storageKey, allowed);
return this.storage.isStoredPermissionsGranted();
}
}
return allowed;
}
private requestOperationCore(entity: RequestedEntity) {
entity.eventArgs.allowed = this.operationSettings[entity.settingsKey];
entity.eventArgs.updateUI = this.updateUICount > 0;
if(entity.allowed)
this.onRequestOperation.raise("notifyRequestOperation", entity.operation, entity.eventArgs);
}
lockPermissions(): void {
this.permissionsLockCount++;
}
unlockPermissions(): void {
this.permissionsLockCount--;
}
beginDeleteItems(items: DiagramItem[]): void {
items.forEach(item => this.requestDeleteItems[item.key] = item);
}
endDeleteItems(): void {
this.requestDeleteItems = {};
}
beginUpdateUI(): void {
this.updateUICount++;
}
endUpdateUI(): void {
this.updateUICount--;
}
addInteractingItem(item: DiagramItem, operation?: DiagramModelOperation): void {
this.storage.addInteractingItem(item, operation);
}
getInteractingItem(item: DiagramItem, operation?: DiagramModelOperation): DiagramItem {
return this.storage.getInteractingItem(item, operation);
}
getInteractingItemCount(): number {
return this.storage.getInteractingItemCount();
}
clearInteractingItems(): void {
this.storage.clearInteractingItems();
}
beginStorePermissions(): void {
this.storage.beginStorePermissions();
}
endStorePermissions(): void {
this.storage.endStorePermissions();
}
isStoredPermissionsGranted(): boolean {
return this.permissionsLockCount > 0 || this.storage.isStoredPermissionsGranted();
}
}
export interface IPermissionsProvider {
lockPermissions(): void;
unlockPermissions(): void;
beginDeleteItems(items: DiagramItem[]): void;
endDeleteItems(): void;
beginUpdateUI(): void;
endUpdateUI(): void;
canDeleteItems(items: DiagramItem[]): boolean;
canAddItems(items: DiagramItem[]): boolean;
canAddShapeFromToolbox(itemType: string): boolean;
canChangeConnection(connector: Connector, item: DiagramItem, oldItem: DiagramItem, position: ConnectorPosition, connectionPointIndex: number): boolean;
canChangeConnectorPoints(connector: Connector, oldPoints: Point[], points: Point[]): boolean;
canChangeShapeText(shape: Shape): boolean;
canChangeConnectorText(connector: Connector, position: number): boolean;
canApplyShapeTextChange(shape: Shape, textToApply: string): boolean;
canApplyConnectorTextChange(connector: Connector, position: number, textToApply: string): boolean;
canResizeShapes(shapeInfo: IResizeShapeInfo[]): boolean;
canMoveShapes(shapeInfo: IMoveShapeInfo[]): boolean;
addInteractingItem(item: DiagramItem, operation?: DiagramModelOperation);
getInteractingItem(item: DiagramItem, operation?: DiagramModelOperation): DiagramItem;
getInteractingItemCount(): number;
clearInteractingItems();
beginStorePermissions(): void;
endStorePermissions(): void;
isStoredPermissionsGranted(): boolean;
}
export interface IPermissionRequestListener {
notifyRequestOperation(operation: DiagramModelOperation, args: RequestOperationEventArgs);
}
export type RequestOperationEventArgs = DeleteShapeEventArgs | DeleteConnectorEventArgs | AddShapeFromToolboxEventArgs |
AddShapeEventArgs | ChangeConnectionEventArgs | ChangeConnectorPointsEventArgs |
BeforeChangeShapeTextEventArgs | BeforeChangeShapeTextEventArgs | ChangeShapeTextEventArgs;