UNPKG

@itwin/unified-selection

Version:

Package for managing unified selection in iTwin.js applications.

146 lines 5.2 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { BeEvent } from "@itwin/core-bentley"; import { Selectables } from "./Selectable.js"; /** * Creates a selection storage which stores and allows managing application-level selection. * * **Note:** `clearSelection` should be called upon iModel close to free-up memory: * * ```ts * import { IModelConnection } from "@itwin/core-frontend"; * import { createIModelKey } from "@itwin/presentation-core-interop"; * * IModelConnection.onClose.addListener((imodel) => { * storage.clearStorage(createIModelKey(imodel)); * }); * ``` * * @public */ export function createStorage() { return new SelectionStorageImpl(); } /** @internal */ export const IMODEL_CLOSE_SELECTION_CLEAR_SOURCE = "Unified selection storage: clear"; class SelectionStorageImpl { _storage = new Map(); selectionChangeEvent; constructor() { this.selectionChangeEvent = new BeEvent(); } getSelectionLevels(props) { return this.getContainer(getIModelKey(props)).getSelectionLevels(); } getSelection(props) { return this.getContainer(getIModelKey(props)).getSelection(props.level ?? 0); } addToSelection(props) { this.handleChange({ ...props, changeType: "add" }); } removeFromSelection(props) { this.handleChange({ ...props, changeType: "remove" }); } replaceSelection(props) { this.handleChange({ ...props, changeType: "replace" }); } clearSelection(props) { this.handleChange({ ...props, changeType: "clear", selectables: [] }); } clearStorage(props) { const imodelKey = getIModelKey(props); this.clearSelection({ source: IMODEL_CLOSE_SELECTION_CLEAR_SOURCE, imodelKey }); this._storage.delete(imodelKey); } getContainer(imodelKey) { let selectionContainer = this._storage.get(imodelKey); if (!selectionContainer) { selectionContainer = new MultiLevelSelectablesContainer(); this._storage.set(imodelKey, selectionContainer); } return selectionContainer; } handleChange(props) { const { source, level: inLevel, changeType, selectables: change } = props; const imodelKey = getIModelKey(props); const container = this.getContainer(imodelKey); const level = inLevel ?? 0; const selectables = container.getSelection(level); const selected = Selectables.create(change); switch (changeType) { case "add": if (!Selectables.add(selectables, change)) { return; } break; case "remove": if (!Selectables.remove(selectables, change)) { return; } break; case "replace": if (Selectables.size(selectables) === Selectables.size(selected) && Selectables.hasAll(selectables, change)) { return; } Selectables.clear(selectables); Selectables.add(selectables, change); break; case "clear": if (!Selectables.clear(selectables)) { return; } break; } container.clear(level + 1); const event = { source, level, imodelKey, iModelKey: imodelKey, changeType, selectables: selected, timestamp: new Date(), storage: this, }; this.selectionChangeEvent.raiseEvent(event, this); } } function getIModelKey(props) { // eslint-disable-next-line @typescript-eslint/no-deprecated return "imodelKey" in props ? props.imodelKey : props.iModelKey; } class MultiLevelSelectablesContainer { _selectablesContainers; constructor() { this._selectablesContainers = new Map(); } getSelection(level) { let selectables = this._selectablesContainers.get(level); if (!selectables) { selectables = Selectables.create([]); this._selectablesContainers.set(level, selectables); } return selectables; } getSelectionLevels() { const levels = new Array(); for (const entry of this._selectablesContainers.entries()) { if (!Selectables.isEmpty(entry[1])) { levels.push(entry[0]); } } return levels.sort(); } clear(level) { const storedLevels = this._selectablesContainers.keys(); for (const storedLevel of storedLevels) { if (storedLevel >= level) { const selectables = this._selectablesContainers.get(storedLevel); Selectables.clear(selectables); } } } } //# sourceMappingURL=SelectionStorage.js.map