@itwin/presentation-frontend 4.0.0-dev.21 → 4.0.0-dev.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/presentation-frontend/ConnectivityInformationProvider.d.ts +29 -29
- package/lib/cjs/presentation-frontend/ConnectivityInformationProvider.js +47 -47
- package/lib/cjs/presentation-frontend/ConnectivityInformationProvider.js.map +1 -1
- package/lib/cjs/presentation-frontend/Diagnostics.d.ts +14 -14
- package/lib/cjs/presentation-frontend/Diagnostics.js +61 -61
- package/lib/cjs/presentation-frontend/Diagnostics.js.map +1 -1
- package/lib/cjs/presentation-frontend/FrontendLoggerCategory.d.ts +12 -12
- package/lib/cjs/presentation-frontend/FrontendLoggerCategory.js +20 -20
- package/lib/cjs/presentation-frontend/FrontendLoggerCategory.js.map +1 -1
- package/lib/cjs/presentation-frontend/IpcRequestsHandler.d.ts +10 -10
- package/lib/cjs/presentation-frontend/IpcRequestsHandler.js +41 -41
- package/lib/cjs/presentation-frontend/IpcRequestsHandler.js.map +1 -1
- package/lib/cjs/presentation-frontend/LocalizationHelper.d.ts +10 -10
- package/lib/cjs/presentation-frontend/LocalizationHelper.js +31 -31
- package/lib/cjs/presentation-frontend/LocalizationHelper.js.map +1 -1
- package/lib/cjs/presentation-frontend/Presentation.d.ts +73 -73
- package/lib/cjs/presentation-frontend/Presentation.js +160 -160
- package/lib/cjs/presentation-frontend/Presentation.js.map +1 -1
- package/lib/cjs/presentation-frontend/PresentationManager.d.ts +186 -186
- package/lib/cjs/presentation-frontend/PresentationManager.js +436 -436
- package/lib/cjs/presentation-frontend/PresentationManager.js.map +1 -1
- package/lib/cjs/presentation-frontend/RulesetManager.d.ts +63 -63
- package/lib/cjs/presentation-frontend/RulesetManager.js +85 -85
- package/lib/cjs/presentation-frontend/RulesetManager.js.map +1 -1
- package/lib/cjs/presentation-frontend/RulesetVariablesManager.d.ts +143 -143
- package/lib/cjs/presentation-frontend/RulesetVariablesManager.js +195 -195
- package/lib/cjs/presentation-frontend/RulesetVariablesManager.js.map +1 -1
- package/lib/cjs/presentation-frontend/StateTracker.d.ts +38 -38
- package/lib/cjs/presentation-frontend/StateTracker.js +129 -129
- package/lib/cjs/presentation-frontend/StateTracker.js.map +1 -1
- package/lib/cjs/presentation-frontend/favorite-properties/FavoritePropertiesManager.d.ts +132 -132
- package/lib/cjs/presentation-frontend/favorite-properties/FavoritePropertiesManager.js +525 -525
- package/lib/cjs/presentation-frontend/favorite-properties/FavoritePropertiesManager.js.map +1 -1
- package/lib/cjs/presentation-frontend/favorite-properties/FavoritePropertiesStorage.d.ts +111 -111
- package/lib/cjs/presentation-frontend/favorite-properties/FavoritePropertiesStorage.js +293 -293
- package/lib/cjs/presentation-frontend/favorite-properties/FavoritePropertiesStorage.js.map +1 -1
- package/lib/cjs/presentation-frontend/selection/HiliteRules.json +172 -172
- package/lib/cjs/presentation-frontend/selection/HiliteSetProvider.d.ts +52 -52
- package/lib/cjs/presentation-frontend/selection/HiliteSetProvider.js +97 -97
- package/lib/cjs/presentation-frontend/selection/HiliteSetProvider.js.map +1 -1
- package/lib/cjs/presentation-frontend/selection/ISelectionProvider.d.ts +19 -19
- package/lib/cjs/presentation-frontend/selection/ISelectionProvider.js +9 -9
- package/lib/cjs/presentation-frontend/selection/ISelectionProvider.js.map +1 -1
- package/lib/cjs/presentation-frontend/selection/SelectionChangeEvent.d.ts +52 -52
- package/lib/cjs/presentation-frontend/selection/SelectionChangeEvent.js +33 -33
- package/lib/cjs/presentation-frontend/selection/SelectionChangeEvent.js.map +1 -1
- package/lib/cjs/presentation-frontend/selection/SelectionHandler.d.ts +103 -103
- package/lib/cjs/presentation-frontend/selection/SelectionHandler.js +108 -108
- package/lib/cjs/presentation-frontend/selection/SelectionHandler.js.map +1 -1
- package/lib/cjs/presentation-frontend/selection/SelectionHelper.d.ts +17 -17
- package/lib/cjs/presentation-frontend/selection/SelectionHelper.js +40 -40
- package/lib/cjs/presentation-frontend/selection/SelectionHelper.js.map +1 -1
- package/lib/cjs/presentation-frontend/selection/SelectionManager.d.ts +139 -139
- package/lib/cjs/presentation-frontend/selection/SelectionManager.js +414 -414
- package/lib/cjs/presentation-frontend/selection/SelectionManager.js.map +1 -1
- package/lib/cjs/presentation-frontend/selection/SelectionScopesManager.d.ts +59 -59
- package/lib/cjs/presentation-frontend/selection/SelectionScopesManager.js +91 -91
- package/lib/cjs/presentation-frontend/selection/SelectionScopesManager.js.map +1 -1
- package/lib/cjs/presentation-frontend.d.ts +34 -34
- package/lib/cjs/presentation-frontend.js +50 -50
- package/lib/cjs/presentation-frontend.js.map +1 -1
- package/lib/esm/presentation-frontend/ConnectivityInformationProvider.d.ts +29 -29
- package/lib/esm/presentation-frontend/ConnectivityInformationProvider.js +43 -43
- package/lib/esm/presentation-frontend/ConnectivityInformationProvider.js.map +1 -1
- package/lib/esm/presentation-frontend/Diagnostics.d.ts +14 -14
- package/lib/esm/presentation-frontend/Diagnostics.js +56 -56
- package/lib/esm/presentation-frontend/Diagnostics.js.map +1 -1
- package/lib/esm/presentation-frontend/FrontendLoggerCategory.d.ts +12 -12
- package/lib/esm/presentation-frontend/FrontendLoggerCategory.js +17 -17
- package/lib/esm/presentation-frontend/FrontendLoggerCategory.js.map +1 -1
- package/lib/esm/presentation-frontend/IpcRequestsHandler.d.ts +10 -10
- package/lib/esm/presentation-frontend/IpcRequestsHandler.js +37 -37
- package/lib/esm/presentation-frontend/IpcRequestsHandler.js.map +1 -1
- package/lib/esm/presentation-frontend/LocalizationHelper.d.ts +10 -10
- package/lib/esm/presentation-frontend/LocalizationHelper.js +27 -27
- package/lib/esm/presentation-frontend/LocalizationHelper.js.map +1 -1
- package/lib/esm/presentation-frontend/Presentation.d.ts +73 -73
- package/lib/esm/presentation-frontend/Presentation.js +156 -156
- package/lib/esm/presentation-frontend/Presentation.js.map +1 -1
- package/lib/esm/presentation-frontend/PresentationManager.d.ts +186 -186
- package/lib/esm/presentation-frontend/PresentationManager.js +431 -431
- package/lib/esm/presentation-frontend/PresentationManager.js.map +1 -1
- package/lib/esm/presentation-frontend/RulesetManager.d.ts +63 -63
- package/lib/esm/presentation-frontend/RulesetManager.js +81 -81
- package/lib/esm/presentation-frontend/RulesetManager.js.map +1 -1
- package/lib/esm/presentation-frontend/RulesetVariablesManager.d.ts +143 -143
- package/lib/esm/presentation-frontend/RulesetVariablesManager.js +191 -191
- package/lib/esm/presentation-frontend/RulesetVariablesManager.js.map +1 -1
- package/lib/esm/presentation-frontend/StateTracker.d.ts +38 -38
- package/lib/esm/presentation-frontend/StateTracker.js +125 -125
- package/lib/esm/presentation-frontend/StateTracker.js.map +1 -1
- package/lib/esm/presentation-frontend/favorite-properties/FavoritePropertiesManager.d.ts +132 -132
- package/lib/esm/presentation-frontend/favorite-properties/FavoritePropertiesManager.js +519 -519
- package/lib/esm/presentation-frontend/favorite-properties/FavoritePropertiesManager.js.map +1 -1
- package/lib/esm/presentation-frontend/favorite-properties/FavoritePropertiesStorage.d.ts +111 -111
- package/lib/esm/presentation-frontend/favorite-properties/FavoritePropertiesStorage.js +285 -285
- package/lib/esm/presentation-frontend/favorite-properties/FavoritePropertiesStorage.js.map +1 -1
- package/lib/esm/presentation-frontend/selection/HiliteRules.json +172 -172
- package/lib/esm/presentation-frontend/selection/HiliteSetProvider.d.ts +52 -52
- package/lib/esm/presentation-frontend/selection/HiliteSetProvider.js +93 -93
- package/lib/esm/presentation-frontend/selection/HiliteSetProvider.js.map +1 -1
- package/lib/esm/presentation-frontend/selection/ISelectionProvider.d.ts +19 -19
- package/lib/esm/presentation-frontend/selection/ISelectionProvider.js +8 -8
- package/lib/esm/presentation-frontend/selection/ISelectionProvider.js.map +1 -1
- package/lib/esm/presentation-frontend/selection/SelectionChangeEvent.d.ts +52 -52
- package/lib/esm/presentation-frontend/selection/SelectionChangeEvent.js +29 -29
- package/lib/esm/presentation-frontend/selection/SelectionChangeEvent.js.map +1 -1
- package/lib/esm/presentation-frontend/selection/SelectionHandler.d.ts +103 -103
- package/lib/esm/presentation-frontend/selection/SelectionHandler.js +104 -104
- package/lib/esm/presentation-frontend/selection/SelectionHandler.js.map +1 -1
- package/lib/esm/presentation-frontend/selection/SelectionHelper.d.ts +17 -17
- package/lib/esm/presentation-frontend/selection/SelectionHelper.js +36 -36
- package/lib/esm/presentation-frontend/selection/SelectionHelper.js.map +1 -1
- package/lib/esm/presentation-frontend/selection/SelectionManager.d.ts +139 -139
- package/lib/esm/presentation-frontend/selection/SelectionManager.js +409 -409
- package/lib/esm/presentation-frontend/selection/SelectionManager.js.map +1 -1
- package/lib/esm/presentation-frontend/selection/SelectionScopesManager.d.ts +59 -59
- package/lib/esm/presentation-frontend/selection/SelectionScopesManager.js +85 -85
- package/lib/esm/presentation-frontend/selection/SelectionScopesManager.js.map +1 -1
- package/lib/esm/presentation-frontend.d.ts +34 -34
- package/lib/esm/presentation-frontend.js +38 -38
- package/lib/esm/presentation-frontend.js.map +1 -1
- package/package.json +14 -14
|
@@ -1,410 +1,410 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
/** @packageDocumentation
|
|
6
|
-
* @module UnifiedSelection
|
|
7
|
-
*/
|
|
8
|
-
import { Id64, using } from "@itwin/core-bentley";
|
|
9
|
-
import { IModelConnection, SelectionSetEventType } from "@itwin/core-frontend";
|
|
10
|
-
import { AsyncTasksTracker, KeySet } from "@itwin/presentation-common";
|
|
11
|
-
import { HiliteSetProvider } from "./HiliteSetProvider";
|
|
12
|
-
import { SelectionChangeEvent, SelectionChangeType } from "./SelectionChangeEvent";
|
|
13
|
-
import { createSelectionScopeProps } from "./SelectionScopesManager";
|
|
14
|
-
/**
|
|
15
|
-
* The selection manager which stores the overall selection.
|
|
16
|
-
* @public
|
|
17
|
-
*/
|
|
18
|
-
export class SelectionManager {
|
|
19
|
-
/**
|
|
20
|
-
* Creates an instance of SelectionManager.
|
|
21
|
-
*/
|
|
22
|
-
constructor(props) {
|
|
23
|
-
this._selectionContainerMap = new Map();
|
|
24
|
-
this._imodelToolSelectionSyncHandlers = new Map();
|
|
25
|
-
this._hiliteSetProviders = new Map();
|
|
26
|
-
this.selectionChange = new SelectionChangeEvent();
|
|
27
|
-
this.scopes = props.scopes;
|
|
28
|
-
IModelConnection.onClose.addListener((imodel) => {
|
|
29
|
-
this.onConnectionClose(imodel);
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
onConnectionClose(imodel) {
|
|
33
|
-
this.clearSelection("Connection Close Event", imodel);
|
|
34
|
-
this._selectionContainerMap.delete(imodel);
|
|
35
|
-
this._hiliteSetProviders.delete(imodel);
|
|
36
|
-
}
|
|
37
|
-
getContainer(imodel) {
|
|
38
|
-
let selectionContainer = this._selectionContainerMap.get(imodel);
|
|
39
|
-
if (!selectionContainer) {
|
|
40
|
-
selectionContainer = new SelectionContainer();
|
|
41
|
-
this._selectionContainerMap.set(imodel, selectionContainer);
|
|
42
|
-
}
|
|
43
|
-
return selectionContainer;
|
|
44
|
-
}
|
|
45
|
-
/** @internal */
|
|
46
|
-
// istanbul ignore next
|
|
47
|
-
getToolSelectionSyncHandler(imodel) { var _a; return (_a = this._imodelToolSelectionSyncHandlers.get(imodel)) === null || _a === void 0 ? void 0 : _a.handler; }
|
|
48
|
-
/**
|
|
49
|
-
* Request the manager to sync with imodel's tool selection (see `IModelConnection.selectionSet`).
|
|
50
|
-
*/
|
|
51
|
-
setSyncWithIModelToolSelection(imodel, sync = true) {
|
|
52
|
-
const registration = this._imodelToolSelectionSyncHandlers.get(imodel);
|
|
53
|
-
if (sync) {
|
|
54
|
-
if (!registration || registration.requestorsCount === 0) {
|
|
55
|
-
this._imodelToolSelectionSyncHandlers.set(imodel, { requestorsCount: 1, handler: new ToolSelectionSyncHandler(imodel, this) });
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
this._imodelToolSelectionSyncHandlers.set(imodel, { ...registration, requestorsCount: registration.requestorsCount + 1 });
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
if (registration && registration.requestorsCount > 0) {
|
|
63
|
-
const requestorsCount = registration.requestorsCount - 1;
|
|
64
|
-
if (requestorsCount > 0) {
|
|
65
|
-
this._imodelToolSelectionSyncHandlers.set(imodel, { ...registration, requestorsCount });
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
this._imodelToolSelectionSyncHandlers.delete(imodel);
|
|
69
|
-
registration.handler.dispose();
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Temporarily suspends tool selection synchronization until the returned `IDisposable`
|
|
76
|
-
* is disposed.
|
|
77
|
-
*/
|
|
78
|
-
suspendIModelToolSelectionSync(imodel) {
|
|
79
|
-
const registration = this._imodelToolSelectionSyncHandlers.get(imodel);
|
|
80
|
-
if (!registration)
|
|
81
|
-
return { dispose: () => { } };
|
|
82
|
-
const wasSuspended = registration.handler.isSuspended;
|
|
83
|
-
registration.handler.isSuspended = true;
|
|
84
|
-
return { dispose: () => (registration.handler.isSuspended = wasSuspended) };
|
|
85
|
-
}
|
|
86
|
-
/** Get the selection levels currently stored in this manager for the specified imodel */
|
|
87
|
-
getSelectionLevels(imodel) {
|
|
88
|
-
return this.getContainer(imodel).getSelectionLevels();
|
|
89
|
-
}
|
|
90
|
-
/** Get the selection currently stored in this manager */
|
|
91
|
-
getSelection(imodel, level = 0) {
|
|
92
|
-
return this.getContainer(imodel).getSelection(level);
|
|
93
|
-
}
|
|
94
|
-
handleEvent(evt) {
|
|
95
|
-
const container = this.getContainer(evt.imodel);
|
|
96
|
-
const selectedItemsSet = container.getSelection(evt.level);
|
|
97
|
-
const guidBefore = selectedItemsSet.guid;
|
|
98
|
-
switch (evt.changeType) {
|
|
99
|
-
case SelectionChangeType.Add:
|
|
100
|
-
selectedItemsSet.add(evt.keys);
|
|
101
|
-
break;
|
|
102
|
-
case SelectionChangeType.Remove:
|
|
103
|
-
selectedItemsSet.delete(evt.keys);
|
|
104
|
-
break;
|
|
105
|
-
case SelectionChangeType.Replace:
|
|
106
|
-
if (selectedItemsSet.size !== evt.keys.size || !selectedItemsSet.hasAll(evt.keys)) {
|
|
107
|
-
// note: the above check is only needed to avoid changing
|
|
108
|
-
// guid of the keyset if we're replacing keyset with the same keys
|
|
109
|
-
selectedItemsSet.clear().add(evt.keys);
|
|
110
|
-
}
|
|
111
|
-
break;
|
|
112
|
-
case SelectionChangeType.Clear:
|
|
113
|
-
selectedItemsSet.clear();
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
if (selectedItemsSet.guid === guidBefore)
|
|
117
|
-
return;
|
|
118
|
-
container.clear(evt.level + 1);
|
|
119
|
-
this.selectionChange.raiseEvent(evt, this);
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Add keys to the selection
|
|
123
|
-
* @param source Name of the selection source
|
|
124
|
-
* @param imodel iModel associated with the selection
|
|
125
|
-
* @param keys Keys to add
|
|
126
|
-
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
127
|
-
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
128
|
-
*/
|
|
129
|
-
addToSelection(source, imodel, keys, level = 0, rulesetId) {
|
|
130
|
-
const evt = {
|
|
131
|
-
source,
|
|
132
|
-
level,
|
|
133
|
-
imodel,
|
|
134
|
-
changeType: SelectionChangeType.Add,
|
|
135
|
-
keys: new KeySet(keys),
|
|
136
|
-
timestamp: new Date(),
|
|
137
|
-
rulesetId,
|
|
138
|
-
};
|
|
139
|
-
this.handleEvent(evt);
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Remove keys from current selection
|
|
143
|
-
* @param source Name of the selection source
|
|
144
|
-
* @param imodel iModel associated with the selection
|
|
145
|
-
* @param keys Keys to remove
|
|
146
|
-
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
147
|
-
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
148
|
-
*/
|
|
149
|
-
removeFromSelection(source, imodel, keys, level = 0, rulesetId) {
|
|
150
|
-
const evt = {
|
|
151
|
-
source,
|
|
152
|
-
level,
|
|
153
|
-
imodel,
|
|
154
|
-
changeType: SelectionChangeType.Remove,
|
|
155
|
-
keys: new KeySet(keys),
|
|
156
|
-
timestamp: new Date(),
|
|
157
|
-
rulesetId,
|
|
158
|
-
};
|
|
159
|
-
this.handleEvent(evt);
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Replace current selection
|
|
163
|
-
* @param source Name of the selection source
|
|
164
|
-
* @param imodel iModel associated with the selection
|
|
165
|
-
* @param keys Keys to add
|
|
166
|
-
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
167
|
-
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
168
|
-
*/
|
|
169
|
-
replaceSelection(source, imodel, keys, level = 0, rulesetId) {
|
|
170
|
-
const evt = {
|
|
171
|
-
source,
|
|
172
|
-
level,
|
|
173
|
-
imodel,
|
|
174
|
-
changeType: SelectionChangeType.Replace,
|
|
175
|
-
keys: new KeySet(keys),
|
|
176
|
-
timestamp: new Date(),
|
|
177
|
-
rulesetId,
|
|
178
|
-
};
|
|
179
|
-
this.handleEvent(evt);
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Clear current selection
|
|
183
|
-
* @param source Name of the selection source
|
|
184
|
-
* @param imodel iModel associated with the selection
|
|
185
|
-
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
186
|
-
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
187
|
-
*/
|
|
188
|
-
clearSelection(source, imodel, level = 0, rulesetId) {
|
|
189
|
-
const evt = {
|
|
190
|
-
source,
|
|
191
|
-
level,
|
|
192
|
-
imodel,
|
|
193
|
-
changeType: SelectionChangeType.Clear,
|
|
194
|
-
keys: new KeySet(),
|
|
195
|
-
timestamp: new Date(),
|
|
196
|
-
rulesetId,
|
|
197
|
-
};
|
|
198
|
-
this.handleEvent(evt);
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Add keys to selection after applying [selection scope]($docs/presentation/unified-selection/index#selection-scopes) on them.
|
|
202
|
-
* @param source Name of the selection source
|
|
203
|
-
* @param imodel iModel associated with the selection
|
|
204
|
-
* @param ids Element IDs to add
|
|
205
|
-
* @param scope Selection scope to apply
|
|
206
|
-
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
207
|
-
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
208
|
-
*/
|
|
209
|
-
async addToSelectionWithScope(source, imodel, ids, scope, level = 0, rulesetId) {
|
|
210
|
-
const scopedKeys = await this.scopes.computeSelection(imodel, ids, scope);
|
|
211
|
-
this.addToSelection(source, imodel, scopedKeys, level, rulesetId);
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Remove keys from current selection after applying [selection scope]($docs/presentation/unified-selection/index#selection-scopes) on them.
|
|
215
|
-
* @param source Name of the selection source
|
|
216
|
-
* @param imodel iModel associated with the selection
|
|
217
|
-
* @param ids Element IDs to remove
|
|
218
|
-
* @param scope Selection scope to apply
|
|
219
|
-
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
220
|
-
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
221
|
-
*/
|
|
222
|
-
async removeFromSelectionWithScope(source, imodel, ids, scope, level = 0, rulesetId) {
|
|
223
|
-
const scopedKeys = await this.scopes.computeSelection(imodel, ids, scope);
|
|
224
|
-
this.removeFromSelection(source, imodel, scopedKeys, level, rulesetId);
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Replace current selection with keys after applying [selection scope]($docs/presentation/unified-selection/index#selection-scopes) on them.
|
|
228
|
-
* @param source Name of the selection source
|
|
229
|
-
* @param imodel iModel associated with the selection
|
|
230
|
-
* @param ids Element IDs to replace with
|
|
231
|
-
* @param scope Selection scope to apply
|
|
232
|
-
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
233
|
-
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
234
|
-
*/
|
|
235
|
-
async replaceSelectionWithScope(source, imodel, ids, scope, level = 0, rulesetId) {
|
|
236
|
-
const scopedKeys = await this.scopes.computeSelection(imodel, ids, scope);
|
|
237
|
-
this.replaceSelection(source, imodel, scopedKeys, level, rulesetId);
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Get the current hilite set for the specified imodel
|
|
241
|
-
* @public
|
|
242
|
-
*/
|
|
243
|
-
async getHiliteSet(imodel) {
|
|
244
|
-
let provider = this._hiliteSetProviders.get(imodel);
|
|
245
|
-
if (!provider) {
|
|
246
|
-
provider = HiliteSetProvider.create({ imodel });
|
|
247
|
-
this._hiliteSetProviders.set(imodel, provider);
|
|
248
|
-
}
|
|
249
|
-
return provider.getHiliteSet(this.getSelection(imodel));
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
/** @internal */
|
|
253
|
-
class SelectionContainer {
|
|
254
|
-
constructor() {
|
|
255
|
-
this._selectedItemsSetMap = new Map();
|
|
256
|
-
}
|
|
257
|
-
getSelection(level) {
|
|
258
|
-
let selectedItemsSet = this._selectedItemsSetMap.get(level);
|
|
259
|
-
if (!selectedItemsSet) {
|
|
260
|
-
selectedItemsSet = new KeySet();
|
|
261
|
-
this._selectedItemsSetMap.set(level, selectedItemsSet);
|
|
262
|
-
}
|
|
263
|
-
return selectedItemsSet;
|
|
264
|
-
}
|
|
265
|
-
getSelectionLevels() {
|
|
266
|
-
const levels = new Array();
|
|
267
|
-
for (const entry of this._selectedItemsSetMap.entries()) {
|
|
268
|
-
if (!entry[1].isEmpty)
|
|
269
|
-
levels.push(entry[0]);
|
|
270
|
-
}
|
|
271
|
-
return levels.sort();
|
|
272
|
-
}
|
|
273
|
-
clear(level) {
|
|
274
|
-
const keys = this._selectedItemsSetMap.keys();
|
|
275
|
-
for (const key of keys) {
|
|
276
|
-
if (key >= level) {
|
|
277
|
-
const selectedItemsSet = this._selectedItemsSetMap.get(key);
|
|
278
|
-
selectedItemsSet.clear();
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
/** @internal */
|
|
284
|
-
export const TRANSIENT_ELEMENT_CLASSNAME = "/TRANSIENT";
|
|
285
|
-
/** @internal */
|
|
286
|
-
export class ToolSelectionSyncHandler {
|
|
287
|
-
constructor(imodel, logicalSelection) {
|
|
288
|
-
this._selectionSourceName = "Tool";
|
|
289
|
-
this._asyncsTracker = new AsyncTasksTracker();
|
|
290
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
291
|
-
this.onToolSelectionChanged = async (ev) => {
|
|
292
|
-
// ignore selection change event if the handler is suspended
|
|
293
|
-
if (this.isSuspended)
|
|
294
|
-
return;
|
|
295
|
-
// this component only cares about its own imodel
|
|
296
|
-
const imodel = ev.set.iModel;
|
|
297
|
-
if (imodel !== this._imodel)
|
|
298
|
-
return;
|
|
299
|
-
// determine the level of selection changes
|
|
300
|
-
// wip: may want to allow selecting at different levels?
|
|
301
|
-
const selectionLevel = 0;
|
|
302
|
-
let ids;
|
|
303
|
-
switch (ev.type) {
|
|
304
|
-
case SelectionSetEventType.Add:
|
|
305
|
-
ids = ev.added;
|
|
306
|
-
break;
|
|
307
|
-
case SelectionSetEventType.Replace:
|
|
308
|
-
ids = ev.set.elements;
|
|
309
|
-
break;
|
|
310
|
-
default:
|
|
311
|
-
ids = ev.removed;
|
|
312
|
-
break;
|
|
313
|
-
}
|
|
314
|
-
// we're always using scoped selection changer even if the scope is set to "element" - that
|
|
315
|
-
// makes sure we're adding to selection keys with concrete classes and not "BisCore:Element", which
|
|
316
|
-
// we can't because otherwise our keys compare fails (presentation components load data with
|
|
317
|
-
// concrete classes)
|
|
318
|
-
const changer = new ScopedSelectionChanger(this._selectionSourceName, this._imodel, this._logicalSelection, createSelectionScopeProps(this._logicalSelection.scopes.activeScope));
|
|
319
|
-
// we know what to do immediately on `clear` events
|
|
320
|
-
if (SelectionSetEventType.Clear === ev.type) {
|
|
321
|
-
await changer.clear(selectionLevel);
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
const parsedIds = parseIds(ids);
|
|
325
|
-
await using(this._asyncsTracker.trackAsyncTask(), async (_r) => {
|
|
326
|
-
switch (ev.type) {
|
|
327
|
-
case SelectionSetEventType.Add:
|
|
328
|
-
await changer.add(parsedIds.transient, parsedIds.persistent, selectionLevel);
|
|
329
|
-
break;
|
|
330
|
-
case SelectionSetEventType.Replace:
|
|
331
|
-
await changer.replace(parsedIds.transient, parsedIds.persistent, selectionLevel);
|
|
332
|
-
break;
|
|
333
|
-
case SelectionSetEventType.Remove:
|
|
334
|
-
await changer.remove(parsedIds.transient, parsedIds.persistent, selectionLevel);
|
|
335
|
-
break;
|
|
336
|
-
}
|
|
337
|
-
});
|
|
338
|
-
};
|
|
339
|
-
this._imodel = imodel;
|
|
340
|
-
this._logicalSelection = logicalSelection;
|
|
341
|
-
this._imodelToolSelectionListenerDisposeFunc = imodel.selectionSet.onChanged.addListener(this.onToolSelectionChanged);
|
|
342
|
-
}
|
|
343
|
-
dispose() {
|
|
344
|
-
this._imodelToolSelectionListenerDisposeFunc();
|
|
345
|
-
}
|
|
346
|
-
/** note: used only it tests */
|
|
347
|
-
get pendingAsyncs() { return this._asyncsTracker.pendingAsyncs; }
|
|
348
|
-
}
|
|
349
|
-
const parseIds = (ids) => {
|
|
350
|
-
let allPersistent = true;
|
|
351
|
-
let allTransient = true;
|
|
352
|
-
for (const id of Id64.iterable(ids)) {
|
|
353
|
-
if (Id64.isTransient(id))
|
|
354
|
-
allPersistent = false;
|
|
355
|
-
else
|
|
356
|
-
allTransient = false;
|
|
357
|
-
if (!allPersistent && !allTransient)
|
|
358
|
-
break;
|
|
359
|
-
}
|
|
360
|
-
// avoid making a copy if ids are only persistent or only transient
|
|
361
|
-
if (allPersistent) {
|
|
362
|
-
return { persistent: ids, transient: [] };
|
|
363
|
-
}
|
|
364
|
-
else if (allTransient) {
|
|
365
|
-
return { persistent: [], transient: ids };
|
|
366
|
-
}
|
|
367
|
-
// if `ids` contain mixed ids, we have to copy.. use Array instead of
|
|
368
|
-
// a Set for performance
|
|
369
|
-
const persistentElementIds = [];
|
|
370
|
-
const transientElementIds = [];
|
|
371
|
-
for (const id of Id64.iterable(ids)) {
|
|
372
|
-
if (Id64.isTransient(id))
|
|
373
|
-
transientElementIds.push(id);
|
|
374
|
-
else
|
|
375
|
-
persistentElementIds.push(id);
|
|
376
|
-
}
|
|
377
|
-
return { persistent: persistentElementIds, transient: transientElementIds };
|
|
378
|
-
};
|
|
379
|
-
function addTransientKeys(transientIds, keys) {
|
|
380
|
-
for (const id of Id64.iterable(transientIds))
|
|
381
|
-
keys.add({ className: TRANSIENT_ELEMENT_CLASSNAME, id });
|
|
382
|
-
}
|
|
383
|
-
/** @internal */
|
|
384
|
-
class ScopedSelectionChanger {
|
|
385
|
-
constructor(name, imodel, manager, scope) {
|
|
386
|
-
this.name = name;
|
|
387
|
-
this.imodel = imodel;
|
|
388
|
-
this.manager = manager;
|
|
389
|
-
this.scope = scope;
|
|
390
|
-
}
|
|
391
|
-
async clear(level) {
|
|
392
|
-
this.manager.clearSelection(this.name, this.imodel, level);
|
|
393
|
-
}
|
|
394
|
-
async add(transientIds, persistentIds, level) {
|
|
395
|
-
const keys = await this.manager.scopes.computeSelection(this.imodel, persistentIds, this.scope);
|
|
396
|
-
addTransientKeys(transientIds, keys);
|
|
397
|
-
this.manager.addToSelection(this.name, this.imodel, keys, level);
|
|
398
|
-
}
|
|
399
|
-
async remove(transientIds, persistentIds, level) {
|
|
400
|
-
const keys = await this.manager.scopes.computeSelection(this.imodel, persistentIds, this.scope);
|
|
401
|
-
addTransientKeys(transientIds, keys);
|
|
402
|
-
this.manager.removeFromSelection(this.name, this.imodel, keys, level);
|
|
403
|
-
}
|
|
404
|
-
async replace(transientIds, persistentIds, level) {
|
|
405
|
-
const keys = await this.manager.scopes.computeSelection(this.imodel, persistentIds, this.scope);
|
|
406
|
-
addTransientKeys(transientIds, keys);
|
|
407
|
-
this.manager.replaceSelection(this.name, this.imodel, keys, level);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
1
|
+
/*---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
/** @packageDocumentation
|
|
6
|
+
* @module UnifiedSelection
|
|
7
|
+
*/
|
|
8
|
+
import { Id64, using } from "@itwin/core-bentley";
|
|
9
|
+
import { IModelConnection, SelectionSetEventType } from "@itwin/core-frontend";
|
|
10
|
+
import { AsyncTasksTracker, KeySet } from "@itwin/presentation-common";
|
|
11
|
+
import { HiliteSetProvider } from "./HiliteSetProvider";
|
|
12
|
+
import { SelectionChangeEvent, SelectionChangeType } from "./SelectionChangeEvent";
|
|
13
|
+
import { createSelectionScopeProps } from "./SelectionScopesManager";
|
|
14
|
+
/**
|
|
15
|
+
* The selection manager which stores the overall selection.
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export class SelectionManager {
|
|
19
|
+
/**
|
|
20
|
+
* Creates an instance of SelectionManager.
|
|
21
|
+
*/
|
|
22
|
+
constructor(props) {
|
|
23
|
+
this._selectionContainerMap = new Map();
|
|
24
|
+
this._imodelToolSelectionSyncHandlers = new Map();
|
|
25
|
+
this._hiliteSetProviders = new Map();
|
|
26
|
+
this.selectionChange = new SelectionChangeEvent();
|
|
27
|
+
this.scopes = props.scopes;
|
|
28
|
+
IModelConnection.onClose.addListener((imodel) => {
|
|
29
|
+
this.onConnectionClose(imodel);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
onConnectionClose(imodel) {
|
|
33
|
+
this.clearSelection("Connection Close Event", imodel);
|
|
34
|
+
this._selectionContainerMap.delete(imodel);
|
|
35
|
+
this._hiliteSetProviders.delete(imodel);
|
|
36
|
+
}
|
|
37
|
+
getContainer(imodel) {
|
|
38
|
+
let selectionContainer = this._selectionContainerMap.get(imodel);
|
|
39
|
+
if (!selectionContainer) {
|
|
40
|
+
selectionContainer = new SelectionContainer();
|
|
41
|
+
this._selectionContainerMap.set(imodel, selectionContainer);
|
|
42
|
+
}
|
|
43
|
+
return selectionContainer;
|
|
44
|
+
}
|
|
45
|
+
/** @internal */
|
|
46
|
+
// istanbul ignore next
|
|
47
|
+
getToolSelectionSyncHandler(imodel) { var _a; return (_a = this._imodelToolSelectionSyncHandlers.get(imodel)) === null || _a === void 0 ? void 0 : _a.handler; }
|
|
48
|
+
/**
|
|
49
|
+
* Request the manager to sync with imodel's tool selection (see `IModelConnection.selectionSet`).
|
|
50
|
+
*/
|
|
51
|
+
setSyncWithIModelToolSelection(imodel, sync = true) {
|
|
52
|
+
const registration = this._imodelToolSelectionSyncHandlers.get(imodel);
|
|
53
|
+
if (sync) {
|
|
54
|
+
if (!registration || registration.requestorsCount === 0) {
|
|
55
|
+
this._imodelToolSelectionSyncHandlers.set(imodel, { requestorsCount: 1, handler: new ToolSelectionSyncHandler(imodel, this) });
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this._imodelToolSelectionSyncHandlers.set(imodel, { ...registration, requestorsCount: registration.requestorsCount + 1 });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
if (registration && registration.requestorsCount > 0) {
|
|
63
|
+
const requestorsCount = registration.requestorsCount - 1;
|
|
64
|
+
if (requestorsCount > 0) {
|
|
65
|
+
this._imodelToolSelectionSyncHandlers.set(imodel, { ...registration, requestorsCount });
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
this._imodelToolSelectionSyncHandlers.delete(imodel);
|
|
69
|
+
registration.handler.dispose();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Temporarily suspends tool selection synchronization until the returned `IDisposable`
|
|
76
|
+
* is disposed.
|
|
77
|
+
*/
|
|
78
|
+
suspendIModelToolSelectionSync(imodel) {
|
|
79
|
+
const registration = this._imodelToolSelectionSyncHandlers.get(imodel);
|
|
80
|
+
if (!registration)
|
|
81
|
+
return { dispose: () => { } };
|
|
82
|
+
const wasSuspended = registration.handler.isSuspended;
|
|
83
|
+
registration.handler.isSuspended = true;
|
|
84
|
+
return { dispose: () => (registration.handler.isSuspended = wasSuspended) };
|
|
85
|
+
}
|
|
86
|
+
/** Get the selection levels currently stored in this manager for the specified imodel */
|
|
87
|
+
getSelectionLevels(imodel) {
|
|
88
|
+
return this.getContainer(imodel).getSelectionLevels();
|
|
89
|
+
}
|
|
90
|
+
/** Get the selection currently stored in this manager */
|
|
91
|
+
getSelection(imodel, level = 0) {
|
|
92
|
+
return this.getContainer(imodel).getSelection(level);
|
|
93
|
+
}
|
|
94
|
+
handleEvent(evt) {
|
|
95
|
+
const container = this.getContainer(evt.imodel);
|
|
96
|
+
const selectedItemsSet = container.getSelection(evt.level);
|
|
97
|
+
const guidBefore = selectedItemsSet.guid;
|
|
98
|
+
switch (evt.changeType) {
|
|
99
|
+
case SelectionChangeType.Add:
|
|
100
|
+
selectedItemsSet.add(evt.keys);
|
|
101
|
+
break;
|
|
102
|
+
case SelectionChangeType.Remove:
|
|
103
|
+
selectedItemsSet.delete(evt.keys);
|
|
104
|
+
break;
|
|
105
|
+
case SelectionChangeType.Replace:
|
|
106
|
+
if (selectedItemsSet.size !== evt.keys.size || !selectedItemsSet.hasAll(evt.keys)) {
|
|
107
|
+
// note: the above check is only needed to avoid changing
|
|
108
|
+
// guid of the keyset if we're replacing keyset with the same keys
|
|
109
|
+
selectedItemsSet.clear().add(evt.keys);
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
case SelectionChangeType.Clear:
|
|
113
|
+
selectedItemsSet.clear();
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
if (selectedItemsSet.guid === guidBefore)
|
|
117
|
+
return;
|
|
118
|
+
container.clear(evt.level + 1);
|
|
119
|
+
this.selectionChange.raiseEvent(evt, this);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Add keys to the selection
|
|
123
|
+
* @param source Name of the selection source
|
|
124
|
+
* @param imodel iModel associated with the selection
|
|
125
|
+
* @param keys Keys to add
|
|
126
|
+
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
127
|
+
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
128
|
+
*/
|
|
129
|
+
addToSelection(source, imodel, keys, level = 0, rulesetId) {
|
|
130
|
+
const evt = {
|
|
131
|
+
source,
|
|
132
|
+
level,
|
|
133
|
+
imodel,
|
|
134
|
+
changeType: SelectionChangeType.Add,
|
|
135
|
+
keys: new KeySet(keys),
|
|
136
|
+
timestamp: new Date(),
|
|
137
|
+
rulesetId,
|
|
138
|
+
};
|
|
139
|
+
this.handleEvent(evt);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Remove keys from current selection
|
|
143
|
+
* @param source Name of the selection source
|
|
144
|
+
* @param imodel iModel associated with the selection
|
|
145
|
+
* @param keys Keys to remove
|
|
146
|
+
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
147
|
+
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
148
|
+
*/
|
|
149
|
+
removeFromSelection(source, imodel, keys, level = 0, rulesetId) {
|
|
150
|
+
const evt = {
|
|
151
|
+
source,
|
|
152
|
+
level,
|
|
153
|
+
imodel,
|
|
154
|
+
changeType: SelectionChangeType.Remove,
|
|
155
|
+
keys: new KeySet(keys),
|
|
156
|
+
timestamp: new Date(),
|
|
157
|
+
rulesetId,
|
|
158
|
+
};
|
|
159
|
+
this.handleEvent(evt);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Replace current selection
|
|
163
|
+
* @param source Name of the selection source
|
|
164
|
+
* @param imodel iModel associated with the selection
|
|
165
|
+
* @param keys Keys to add
|
|
166
|
+
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
167
|
+
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
168
|
+
*/
|
|
169
|
+
replaceSelection(source, imodel, keys, level = 0, rulesetId) {
|
|
170
|
+
const evt = {
|
|
171
|
+
source,
|
|
172
|
+
level,
|
|
173
|
+
imodel,
|
|
174
|
+
changeType: SelectionChangeType.Replace,
|
|
175
|
+
keys: new KeySet(keys),
|
|
176
|
+
timestamp: new Date(),
|
|
177
|
+
rulesetId,
|
|
178
|
+
};
|
|
179
|
+
this.handleEvent(evt);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Clear current selection
|
|
183
|
+
* @param source Name of the selection source
|
|
184
|
+
* @param imodel iModel associated with the selection
|
|
185
|
+
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
186
|
+
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
187
|
+
*/
|
|
188
|
+
clearSelection(source, imodel, level = 0, rulesetId) {
|
|
189
|
+
const evt = {
|
|
190
|
+
source,
|
|
191
|
+
level,
|
|
192
|
+
imodel,
|
|
193
|
+
changeType: SelectionChangeType.Clear,
|
|
194
|
+
keys: new KeySet(),
|
|
195
|
+
timestamp: new Date(),
|
|
196
|
+
rulesetId,
|
|
197
|
+
};
|
|
198
|
+
this.handleEvent(evt);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Add keys to selection after applying [selection scope]($docs/presentation/unified-selection/index#selection-scopes) on them.
|
|
202
|
+
* @param source Name of the selection source
|
|
203
|
+
* @param imodel iModel associated with the selection
|
|
204
|
+
* @param ids Element IDs to add
|
|
205
|
+
* @param scope Selection scope to apply
|
|
206
|
+
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
207
|
+
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
208
|
+
*/
|
|
209
|
+
async addToSelectionWithScope(source, imodel, ids, scope, level = 0, rulesetId) {
|
|
210
|
+
const scopedKeys = await this.scopes.computeSelection(imodel, ids, scope);
|
|
211
|
+
this.addToSelection(source, imodel, scopedKeys, level, rulesetId);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Remove keys from current selection after applying [selection scope]($docs/presentation/unified-selection/index#selection-scopes) on them.
|
|
215
|
+
* @param source Name of the selection source
|
|
216
|
+
* @param imodel iModel associated with the selection
|
|
217
|
+
* @param ids Element IDs to remove
|
|
218
|
+
* @param scope Selection scope to apply
|
|
219
|
+
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
220
|
+
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
221
|
+
*/
|
|
222
|
+
async removeFromSelectionWithScope(source, imodel, ids, scope, level = 0, rulesetId) {
|
|
223
|
+
const scopedKeys = await this.scopes.computeSelection(imodel, ids, scope);
|
|
224
|
+
this.removeFromSelection(source, imodel, scopedKeys, level, rulesetId);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Replace current selection with keys after applying [selection scope]($docs/presentation/unified-selection/index#selection-scopes) on them.
|
|
228
|
+
* @param source Name of the selection source
|
|
229
|
+
* @param imodel iModel associated with the selection
|
|
230
|
+
* @param ids Element IDs to replace with
|
|
231
|
+
* @param scope Selection scope to apply
|
|
232
|
+
* @param level Selection level (see [selection levels documentation section]($docs/presentation/unified-selection/index#selection-levels))
|
|
233
|
+
* @param rulesetId ID of the ruleset in case the selection was changed from a rules-driven control
|
|
234
|
+
*/
|
|
235
|
+
async replaceSelectionWithScope(source, imodel, ids, scope, level = 0, rulesetId) {
|
|
236
|
+
const scopedKeys = await this.scopes.computeSelection(imodel, ids, scope);
|
|
237
|
+
this.replaceSelection(source, imodel, scopedKeys, level, rulesetId);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get the current hilite set for the specified imodel
|
|
241
|
+
* @public
|
|
242
|
+
*/
|
|
243
|
+
async getHiliteSet(imodel) {
|
|
244
|
+
let provider = this._hiliteSetProviders.get(imodel);
|
|
245
|
+
if (!provider) {
|
|
246
|
+
provider = HiliteSetProvider.create({ imodel });
|
|
247
|
+
this._hiliteSetProviders.set(imodel, provider);
|
|
248
|
+
}
|
|
249
|
+
return provider.getHiliteSet(this.getSelection(imodel));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/** @internal */
|
|
253
|
+
class SelectionContainer {
|
|
254
|
+
constructor() {
|
|
255
|
+
this._selectedItemsSetMap = new Map();
|
|
256
|
+
}
|
|
257
|
+
getSelection(level) {
|
|
258
|
+
let selectedItemsSet = this._selectedItemsSetMap.get(level);
|
|
259
|
+
if (!selectedItemsSet) {
|
|
260
|
+
selectedItemsSet = new KeySet();
|
|
261
|
+
this._selectedItemsSetMap.set(level, selectedItemsSet);
|
|
262
|
+
}
|
|
263
|
+
return selectedItemsSet;
|
|
264
|
+
}
|
|
265
|
+
getSelectionLevels() {
|
|
266
|
+
const levels = new Array();
|
|
267
|
+
for (const entry of this._selectedItemsSetMap.entries()) {
|
|
268
|
+
if (!entry[1].isEmpty)
|
|
269
|
+
levels.push(entry[0]);
|
|
270
|
+
}
|
|
271
|
+
return levels.sort();
|
|
272
|
+
}
|
|
273
|
+
clear(level) {
|
|
274
|
+
const keys = this._selectedItemsSetMap.keys();
|
|
275
|
+
for (const key of keys) {
|
|
276
|
+
if (key >= level) {
|
|
277
|
+
const selectedItemsSet = this._selectedItemsSetMap.get(key);
|
|
278
|
+
selectedItemsSet.clear();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/** @internal */
|
|
284
|
+
export const TRANSIENT_ELEMENT_CLASSNAME = "/TRANSIENT";
|
|
285
|
+
/** @internal */
|
|
286
|
+
export class ToolSelectionSyncHandler {
|
|
287
|
+
constructor(imodel, logicalSelection) {
|
|
288
|
+
this._selectionSourceName = "Tool";
|
|
289
|
+
this._asyncsTracker = new AsyncTasksTracker();
|
|
290
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
291
|
+
this.onToolSelectionChanged = async (ev) => {
|
|
292
|
+
// ignore selection change event if the handler is suspended
|
|
293
|
+
if (this.isSuspended)
|
|
294
|
+
return;
|
|
295
|
+
// this component only cares about its own imodel
|
|
296
|
+
const imodel = ev.set.iModel;
|
|
297
|
+
if (imodel !== this._imodel)
|
|
298
|
+
return;
|
|
299
|
+
// determine the level of selection changes
|
|
300
|
+
// wip: may want to allow selecting at different levels?
|
|
301
|
+
const selectionLevel = 0;
|
|
302
|
+
let ids;
|
|
303
|
+
switch (ev.type) {
|
|
304
|
+
case SelectionSetEventType.Add:
|
|
305
|
+
ids = ev.added;
|
|
306
|
+
break;
|
|
307
|
+
case SelectionSetEventType.Replace:
|
|
308
|
+
ids = ev.set.elements;
|
|
309
|
+
break;
|
|
310
|
+
default:
|
|
311
|
+
ids = ev.removed;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
// we're always using scoped selection changer even if the scope is set to "element" - that
|
|
315
|
+
// makes sure we're adding to selection keys with concrete classes and not "BisCore:Element", which
|
|
316
|
+
// we can't because otherwise our keys compare fails (presentation components load data with
|
|
317
|
+
// concrete classes)
|
|
318
|
+
const changer = new ScopedSelectionChanger(this._selectionSourceName, this._imodel, this._logicalSelection, createSelectionScopeProps(this._logicalSelection.scopes.activeScope));
|
|
319
|
+
// we know what to do immediately on `clear` events
|
|
320
|
+
if (SelectionSetEventType.Clear === ev.type) {
|
|
321
|
+
await changer.clear(selectionLevel);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const parsedIds = parseIds(ids);
|
|
325
|
+
await using(this._asyncsTracker.trackAsyncTask(), async (_r) => {
|
|
326
|
+
switch (ev.type) {
|
|
327
|
+
case SelectionSetEventType.Add:
|
|
328
|
+
await changer.add(parsedIds.transient, parsedIds.persistent, selectionLevel);
|
|
329
|
+
break;
|
|
330
|
+
case SelectionSetEventType.Replace:
|
|
331
|
+
await changer.replace(parsedIds.transient, parsedIds.persistent, selectionLevel);
|
|
332
|
+
break;
|
|
333
|
+
case SelectionSetEventType.Remove:
|
|
334
|
+
await changer.remove(parsedIds.transient, parsedIds.persistent, selectionLevel);
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
};
|
|
339
|
+
this._imodel = imodel;
|
|
340
|
+
this._logicalSelection = logicalSelection;
|
|
341
|
+
this._imodelToolSelectionListenerDisposeFunc = imodel.selectionSet.onChanged.addListener(this.onToolSelectionChanged);
|
|
342
|
+
}
|
|
343
|
+
dispose() {
|
|
344
|
+
this._imodelToolSelectionListenerDisposeFunc();
|
|
345
|
+
}
|
|
346
|
+
/** note: used only it tests */
|
|
347
|
+
get pendingAsyncs() { return this._asyncsTracker.pendingAsyncs; }
|
|
348
|
+
}
|
|
349
|
+
const parseIds = (ids) => {
|
|
350
|
+
let allPersistent = true;
|
|
351
|
+
let allTransient = true;
|
|
352
|
+
for (const id of Id64.iterable(ids)) {
|
|
353
|
+
if (Id64.isTransient(id))
|
|
354
|
+
allPersistent = false;
|
|
355
|
+
else
|
|
356
|
+
allTransient = false;
|
|
357
|
+
if (!allPersistent && !allTransient)
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
// avoid making a copy if ids are only persistent or only transient
|
|
361
|
+
if (allPersistent) {
|
|
362
|
+
return { persistent: ids, transient: [] };
|
|
363
|
+
}
|
|
364
|
+
else if (allTransient) {
|
|
365
|
+
return { persistent: [], transient: ids };
|
|
366
|
+
}
|
|
367
|
+
// if `ids` contain mixed ids, we have to copy.. use Array instead of
|
|
368
|
+
// a Set for performance
|
|
369
|
+
const persistentElementIds = [];
|
|
370
|
+
const transientElementIds = [];
|
|
371
|
+
for (const id of Id64.iterable(ids)) {
|
|
372
|
+
if (Id64.isTransient(id))
|
|
373
|
+
transientElementIds.push(id);
|
|
374
|
+
else
|
|
375
|
+
persistentElementIds.push(id);
|
|
376
|
+
}
|
|
377
|
+
return { persistent: persistentElementIds, transient: transientElementIds };
|
|
378
|
+
};
|
|
379
|
+
function addTransientKeys(transientIds, keys) {
|
|
380
|
+
for (const id of Id64.iterable(transientIds))
|
|
381
|
+
keys.add({ className: TRANSIENT_ELEMENT_CLASSNAME, id });
|
|
382
|
+
}
|
|
383
|
+
/** @internal */
|
|
384
|
+
class ScopedSelectionChanger {
|
|
385
|
+
constructor(name, imodel, manager, scope) {
|
|
386
|
+
this.name = name;
|
|
387
|
+
this.imodel = imodel;
|
|
388
|
+
this.manager = manager;
|
|
389
|
+
this.scope = scope;
|
|
390
|
+
}
|
|
391
|
+
async clear(level) {
|
|
392
|
+
this.manager.clearSelection(this.name, this.imodel, level);
|
|
393
|
+
}
|
|
394
|
+
async add(transientIds, persistentIds, level) {
|
|
395
|
+
const keys = await this.manager.scopes.computeSelection(this.imodel, persistentIds, this.scope);
|
|
396
|
+
addTransientKeys(transientIds, keys);
|
|
397
|
+
this.manager.addToSelection(this.name, this.imodel, keys, level);
|
|
398
|
+
}
|
|
399
|
+
async remove(transientIds, persistentIds, level) {
|
|
400
|
+
const keys = await this.manager.scopes.computeSelection(this.imodel, persistentIds, this.scope);
|
|
401
|
+
addTransientKeys(transientIds, keys);
|
|
402
|
+
this.manager.removeFromSelection(this.name, this.imodel, keys, level);
|
|
403
|
+
}
|
|
404
|
+
async replace(transientIds, persistentIds, level) {
|
|
405
|
+
const keys = await this.manager.scopes.computeSelection(this.imodel, persistentIds, this.scope);
|
|
406
|
+
addTransientKeys(transientIds, keys);
|
|
407
|
+
this.manager.replaceSelection(this.name, this.imodel, keys, level);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
410
|
//# sourceMappingURL=SelectionManager.js.map
|