@itwin/unified-selection 1.3.0 → 1.4.0
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/CHANGELOG.md +19 -0
- package/README.md +26 -134
- package/lib/cjs/unified-selection/CachingHiliteSetProvider.d.ts +3 -1
- package/lib/cjs/unified-selection/CachingHiliteSetProvider.d.ts.map +1 -1
- package/lib/cjs/unified-selection/CachingHiliteSetProvider.js +3 -1
- package/lib/cjs/unified-selection/CachingHiliteSetProvider.js.map +1 -1
- package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts +18 -10
- package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts.map +1 -1
- package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.js +40 -16
- package/lib/cjs/unified-selection/EnableUnifiedSelectionSyncWithIModel.js.map +1 -1
- package/lib/cjs/unified-selection/SelectionScope.d.ts +11 -4
- package/lib/cjs/unified-selection/SelectionScope.d.ts.map +1 -1
- package/lib/cjs/unified-selection/SelectionScope.js.map +1 -1
- package/lib/cjs/unified-selection.d.ts +1 -1
- package/lib/cjs/unified-selection.d.ts.map +1 -1
- package/lib/cjs/unified-selection.js.map +1 -1
- package/lib/esm/unified-selection/CachingHiliteSetProvider.d.ts +3 -1
- package/lib/esm/unified-selection/CachingHiliteSetProvider.d.ts.map +1 -1
- package/lib/esm/unified-selection/CachingHiliteSetProvider.js +3 -1
- package/lib/esm/unified-selection/CachingHiliteSetProvider.js.map +1 -1
- package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts +18 -10
- package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.d.ts.map +1 -1
- package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.js +40 -16
- package/lib/esm/unified-selection/EnableUnifiedSelectionSyncWithIModel.js.map +1 -1
- package/lib/esm/unified-selection/SelectionScope.d.ts +11 -4
- package/lib/esm/unified-selection/SelectionScope.d.ts.map +1 -1
- package/lib/esm/unified-selection/SelectionScope.js.map +1 -1
- package/lib/esm/unified-selection.d.ts +1 -1
- package/lib/esm/unified-selection.d.ts.map +1 -1
- package/lib/esm/unified-selection.js.map +1 -1
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @itwin/unified-selection
|
|
2
2
|
|
|
3
|
+
## 1.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#901](https://github.com/iTwin/presentation/pull/901): Export `SelectionScope` type to make it easier for consumers to define "active scope" type.
|
|
8
|
+
|
|
9
|
+
APIs that use this type:
|
|
10
|
+
|
|
11
|
+
- The `scope` prop of `computeSelection` function.
|
|
12
|
+
- Return type of `activeScopeProvider` callback prop of `enableUnifiedSelectionSyncWithIModel` function.
|
|
13
|
+
|
|
14
|
+
- [#895](https://github.com/iTwin/presentation/pull/895): `createCachingHiliteSetProvider`: Added a `createHiliteSetProvider` prop to allow using custom hilite sets for given iModel selections.
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- [#884](https://github.com/iTwin/presentation/pull/884): Fix `enableUnifiedSelectionSyncWithIModel` not properly syncing `SelectionSet` and `SelectionStorage` with 4.x `itwinjs-core`.
|
|
19
|
+
|
|
20
|
+
When the selection change was made by a tool in graphics view (through the `SelectionSet`), the `SelectionStorage` was updated correctly, but the `IModelConnection.hiliteSet` - wasn't. As a result, clearing selection through graphics view wouldn't clear the hilite set and keep the elements hilited.
|
|
21
|
+
|
|
3
22
|
## 1.3.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Copyright © Bentley Systems, Incorporated. All rights reserved. See LICENSE.md for license terms and full copyright notice.
|
|
4
4
|
|
|
5
|
-
The `@itwin/unified-selection` package
|
|
5
|
+
The purpose of the `@itwin/unified-selection` package and unified selection in general is to act as a single source of truth of what is selected in an [iTwin.js](https://www.itwinjs.org/) application.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Concepts
|
|
8
8
|
|
|
9
9
|
The API consists of a few very basic concepts:
|
|
10
10
|
|
|
@@ -23,21 +23,22 @@ The API consists of a few very basic concepts:
|
|
|
23
23
|
|
|
24
24
|
The package delivers the `createStorage()` function to create an instance of `SelectionStorage`. Consumers are also expected to call `SelectionStorage.clearStorage` whenever an iModel is closed to free up memory.
|
|
25
25
|
|
|
26
|
-
##
|
|
26
|
+
## Usage example
|
|
27
27
|
|
|
28
28
|
```ts
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
// Create a global selection store (generally, somewhere in main.ts or similar). This store
|
|
30
|
+
// must be shared across all the application's components to ensure unified selection experience.
|
|
31
|
+
import { createStorage } from "@itwin/unified-selection";
|
|
32
|
+
const unifiedSelection = createStorage();
|
|
32
33
|
|
|
33
|
-
//
|
|
34
|
+
// The store should to be cleaned up when iModels are closed to free up memory, e.g.:
|
|
34
35
|
import { IModelConnection } from "@itwin/core-frontend";
|
|
35
36
|
import { createIModelKey } from "@itwin/presentation-core-interop";
|
|
36
37
|
IModelConnection.onClose.addListener((imodel) => {
|
|
37
|
-
unifiedSelection.clearStorage(createIModelKey(imodel));
|
|
38
|
+
unifiedSelection.clearStorage({ imodelKey: createIModelKey(imodel) });
|
|
38
39
|
});
|
|
39
40
|
|
|
40
|
-
//
|
|
41
|
+
// A demo selection listener logs selection changes to the console:
|
|
41
42
|
import { Selectables } from "@itwin/unified-selection";
|
|
42
43
|
unifiedSelection.selectionChangeEvent.addListener(({ imodelKey, source, changeType, selectables }) => {
|
|
43
44
|
const suffix = `in ${imodelKey} iModel from ${source} component`;
|
|
@@ -58,137 +59,28 @@ unifiedSelection.selectionChangeEvent.addListener(({ imodelKey, source, changeTy
|
|
|
58
59
|
}
|
|
59
60
|
});
|
|
60
61
|
|
|
61
|
-
// in
|
|
62
|
+
// An interactive component that allows selecting elements, representing something in an iModel, may want to
|
|
63
|
+
// add that something to unified selection:
|
|
62
64
|
MyComponent.onECInstanceSelected((imodel: IModelConnection, key: { className: string; id: Id64String }) => {
|
|
63
65
|
unifiedSelection.addToSelection({ imodelKey: createIModelKey(imodel), source: "MyComponent", selectables: [key] });
|
|
64
66
|
});
|
|
65
67
|
```
|
|
66
68
|
|
|
67
|
-
##
|
|
69
|
+
## Learning
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
Are you migrating from `SelectionManager` in `@itwin/presentation-frontend`? Check out our [Migrating from `SelectionManager`](./learning/MigrationGuide.md) learning page!
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
Below is a list of learning material related integrating unified selection into your components:
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
- General topics:
|
|
76
|
+
- [Selection levels](./learning/SelectionLevels.md)
|
|
77
|
+
- [Selection scopes](./learning/SelectionScopes.md)
|
|
78
|
+
- [Hilite sets](./learning/HiliteSets.md)
|
|
79
|
+
- [Caveats](./learning/Caveats.md)
|
|
80
|
+
- Integrating with iTwin.js components:
|
|
81
|
+
- [Viewport / iModel](./learning/SyncWithIModelConnection.md)
|
|
82
|
+
- [Tree](./learning/SyncWithTree.md)
|
|
83
|
+
- [Property grid](./learning/SyncWithPropertyGrid.md)
|
|
84
|
+
- [Table](./learning/SyncWithTable.md)
|
|
74
85
|
|
|
75
|
-
|
|
76
|
-
- _Component B_ shows a list of elements selected in _Component A_ and allows selecting them individually. Selecting an individual element should not change selection in _Component A_ or content in _Component B_ itself.
|
|
77
|
-
- _Component C_ shows properties of elements selected either in _Component A_ or _Component B_.
|
|
78
|
-
|
|
79
|
-
The behavior described above can't be achieved using just one level of selection, because as soon as selection is made in _Component B_, that selection would get represented in _Component A_, and _Component B_ would change what it's displaying to the individual element.
|
|
80
|
-
|
|
81
|
-
That can be fixed by introducing another selection level, but before the components can be configured, here are a few key facts about selection levels:
|
|
82
|
-
|
|
83
|
-
- Higher level selection has lower index. So top level selection is 0, lower level is 1, and so on.
|
|
84
|
-
- Changing higher level selection clears all lower level selections.
|
|
85
|
-
- Lower level selection doesn't have to be a sub-set of higher level selection.
|
|
86
|
-
|
|
87
|
-
With that in mind, the above components _A_, _B_ and _C_ can be configured as follows:
|
|
88
|
-
|
|
89
|
-
- _Component A_ only cares about top level selection. Whenever something is selected in the component, unified selection is updated at the top level. Similarly, whenever unified selection changes, the component only reacts if that happened at the top level.
|
|
90
|
-
- _Component B_ reloads its content if the selection changes at the top level. Row selection is handled using lower level, so selecting a row doesn't affect _Component A's_ selection or _Component B's_ content.
|
|
91
|
-
- _Component C_ reloads its content no matter the selection level.
|
|
92
|
-
|
|
93
|
-
### Hilite sets
|
|
94
|
-
|
|
95
|
-
> **Note:** hilite = highlight
|
|
96
|
-
|
|
97
|
-
`@itwin/core-frontend` contains a concept called the [HiliteSet](https://www.itwinjs.org/reference/core-frontend/selectionset/hiliteset/). This concept is tightly related to unified selection, because, generally, we want selected elements to be highlighted in the application's graphics views. The `HiliteSet` object contains IDs of 3 types of elements: [GeometricModel](https://www.itwinjs.org/reference/core-backend/models/geometricmodel/), [SubCategory](https://www.itwinjs.org/reference/core-backend/imodels/subcategory/) and [GeometricElement](https://www.itwinjs.org/reference/core-backend/elements/geometricelement/). On the other hand, the unified selection API allows selecting other kinds of elements too, so IDs of these elements need to be mapped to the supported ones. The rules are as follows:
|
|
98
|
-
|
|
99
|
-
- for `BisCore.Subject` return IDs of all geometric models that are recursively under that Subject,
|
|
100
|
-
- for `BisCore.Model` just return its ID,
|
|
101
|
-
- for `BisCore.PhysicalPartition` just return ID of a model that models it,
|
|
102
|
-
- for `BisCore.Category` return IDs of all its _SubCategories_,
|
|
103
|
-
- for `BisCore.SubCategory` just return its ID,
|
|
104
|
-
- for `BisCore.GeometricElement` return ID of its own and all its child elements recursively.
|
|
105
|
-
|
|
106
|
-
So for example when unified selection contains a Subject, the hilite set for it will contain all models under that Subject, it's child Subjects, their child Subjects, etc. Given such hilite set, the viewport component hilites all elements in those models.
|
|
107
|
-
|
|
108
|
-
The `@itwin/unified-selection` package delivers APIs for creating a `HiliteSet` or retrieving it for _current_ selection in a `SelectionStorage`:
|
|
109
|
-
|
|
110
|
-
```ts
|
|
111
|
-
// Components may want to get a hilite set for arbitrary set of Selectables - use `createHiliteSetProvider` for that.
|
|
112
|
-
import { IModelConnection } from "@itwin/core-frontend";
|
|
113
|
-
import { createECSqlQueryExecutor, createECSchemaProvider } from "@itwin/presentation-core-interop";
|
|
114
|
-
import { createHiliteSetProvider } from "@itwin/unified-selection";
|
|
115
|
-
|
|
116
|
-
const imodel: IModelConnection; // initialized elsewhere
|
|
117
|
-
const hiliteProvider = createHiliteSetProvider({
|
|
118
|
-
imodelAccess: {
|
|
119
|
-
...createECSchemaProvider(imodel),
|
|
120
|
-
...createECSqlQueryExecutor(imodel),
|
|
121
|
-
},
|
|
122
|
-
});
|
|
123
|
-
const hiliteSet = await hiliteProvider.getHiliteSet({ selectables });
|
|
124
|
-
|
|
125
|
-
// Some others may want to get a hilite set for _current_ selection for specific iModel in storage - use `createCachingHiliteSetProvider`
|
|
126
|
-
// for that. It's recommended to keep a single instance of this provider per application as it caches hilite sets per each iModel's selection.
|
|
127
|
-
import { createCachingHiliteSetProvider } from "@itwin/unified-selection";
|
|
128
|
-
import { createIModelKey } from "@itwin/presentation-core-interop";
|
|
129
|
-
|
|
130
|
-
// Note the use of `using` keyword here. The caching provider registers a selection change listener and should be disposed, in case
|
|
131
|
-
// its lifetime is shorter than that of `SelectionStorage`, to unregister the listener. The `using` keyword ensures that the provider
|
|
132
|
-
// is disposed when it goes out of scope.
|
|
133
|
-
using selectionHiliteProvider = createCachingHiliteSetProvider({
|
|
134
|
-
selectionStorage,
|
|
135
|
-
// this is called to get iModel access based on the iModel key, used to get hilite set for that iModel (see below)
|
|
136
|
-
imodelProvider: (imodelKey) => getIModelByKey(imodelKey),
|
|
137
|
-
});
|
|
138
|
-
const selectionHiliteSet = await selectionHiliteProvider.getHiliteSet({ imodelKey: createIModelKey(imodel) });
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### Selection scopes
|
|
142
|
-
|
|
143
|
-
Selection scopes allow decoupling of what gets picked and what gets selected. Without selection scopes, whenever a user picks an element in the viewport, its ID goes straight into unified selection storage. With selection scopes we can modify that and add something different. The input to the selection scopes' processor is a query executor, element IDs, and the scope to apply, and the output is an iterator of `SelectableInstanceKey`. We get the input when the user picks some elements in the viewport, run that through the selection scope processor and put the output into unified selection storage.
|
|
144
|
-
|
|
145
|
-
Here are the scopes we support at the moment:
|
|
146
|
-
|
|
147
|
-
- `element` - return key of selected element.
|
|
148
|
-
- `category` - return key of geometric element's category.
|
|
149
|
-
- `model` - return key of element's model.
|
|
150
|
-
- `functional` - return key of element's related functional element. For `BisCore.GeometricElement3d` the related functional element is found using the `Functional.PhysicalElementFulfillsFunction` relationship. For `BisCore.GeometricElement2d` the nearest functional element is searched for using the `Functional.DrawingGraphicRepresentsFunctionalElement` relationship - if the given element has a related functional element, it will be returned, otherwise the element's parent will be checked and if it also does not have a related functional, then the parent of the parent will be checked until no more ancestors can be traversed or a functional element is found. Regardless whether it is an `BisCore.GeometricElement2d` or `BisCore.GeometricElement3d` if no functional element is found then the element itself will be returned.
|
|
151
|
-
|
|
152
|
-
The `@itwin/unified-selection` package delivers a `computeSelection` function for computing which elements should be added into unified selection storage based on the given element ID's and a specified selection scope:
|
|
153
|
-
|
|
154
|
-
```ts
|
|
155
|
-
import { computeSelection } from "@itwin/unified-selection";
|
|
156
|
-
import { IModelConnection } from "@itwin/core-frontend";
|
|
157
|
-
import { createECSqlQueryExecutor } from "@itwin/presentation-core-interop";
|
|
158
|
-
const queryExecutor = createECSqlQueryExecutor(imodel);
|
|
159
|
-
const selection = computeSelection({ queryExecutor, elementIds, scope: "element" });
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
`element` and `functional` scopes additionally allow selecting assembly elements by specifying the `ancestorLevel` property in the selection scope argument of `computeSelection` function. The `ancestorLevel` property specifies how far "up" we should walk to find the target element. When not specified or `0`, the target element matches the request element. When set to `1`, the target element matches the direct parent element. When `2`, the target element is the parent of the parent element, and so on. In all situations when this is `> 0`, we're not walking further than the last existing element, for example, when `ancestorLevel = 1` (direct parent element is requested), but the request element doesn't have a parent, the request element is returned as the result. A negative value would result in the top-most element to be returned.
|
|
163
|
-
|
|
164
|
-
For the `functional` scope, the `ancestorLevel` property is used as follows: if an element is a `BisCore.GeometricElement3d` element, its ancestor is selected based on the given `ancestorLevel` the same as with non-functional elements, and then the resulting element's related functional element will be returned (using the `Functional.PhysicalElementFulfillsFunction` relationship), or if it does not have one, then the resulting element will be returned. For `BisCore.GeometricElement2d` elements, the nearest related functional element is found in the same way it is done when the `ancestorLevel` property is not provided, and then the ancestor of that element is returned (based on the provided value of `ancestorLevel`).
|
|
165
|
-
|
|
166
|
-
```ts
|
|
167
|
-
import { computeSelection } from "@itwin/unified-selection";
|
|
168
|
-
import { IModelConnection } from "@itwin/core-frontend";
|
|
169
|
-
import { createECSqlQueryExecutor } from "@itwin/presentation-core-interop";
|
|
170
|
-
const queryExecutor = createECSqlQueryExecutor(imodel);
|
|
171
|
-
// Returns the parent element, or the element itself if it does not have a parent, for each element specified in `elementIds` argument.
|
|
172
|
-
const selection = computeSelection({ queryExecutor, elementIds, scope: { id: "element", ancestorLevel: 1 } });
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## iModel selection synchronization with unified selection
|
|
176
|
-
|
|
177
|
-
The `@itwin/unified-selection` package delivers a `enableUnifiedSelectionSyncWithIModel` function to enable selection synchronization between an iModel and a `SelectionStorage`. When called, it returns a cleanup function that should be used to disable the synchronization. There should only be one active synchronization between a single iModel and a `SelectionStorage` at a given time. For example, this function could be used inside a `useEffect` hook in a component that holds an iModel:
|
|
178
|
-
|
|
179
|
-
```ts
|
|
180
|
-
import { createECSqlQueryExecutor, createECSchemaProvider, createIModelKey } from "@itwin/presentation-core-interop";
|
|
181
|
-
useEffect(() => {
|
|
182
|
-
return enableUnifiedSelectionSyncWithIModel({
|
|
183
|
-
imodelAccess: {
|
|
184
|
-
...createECSqlQueryExecutor(imodel),
|
|
185
|
-
...createECSchemaProvider(imodel),
|
|
186
|
-
key: createIModelKey(imodel),
|
|
187
|
-
hiliteSet: imodel.hilited,
|
|
188
|
-
selectionSet: imodel.selectionSet,
|
|
189
|
-
},
|
|
190
|
-
selectionStorage,
|
|
191
|
-
activeScopeProvider: () => "element",
|
|
192
|
-
});
|
|
193
|
-
}, [imodel]);
|
|
194
|
-
```
|
|
86
|
+
Do you think something is missing in the above list? Let us know by [creating an issue](https://github.com/iTwin/presentation/issues/new?assignees=&labels=documentation%2C+presentation&projects=&template=learning-material-request.md&title=)!
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./DisposePolyfill.js";
|
|
2
2
|
import { ECClassHierarchyInspector, ECSqlQueryExecutor } from "@itwin/presentation-shared";
|
|
3
|
-
import { HiliteSet } from "./HiliteSetProvider.js";
|
|
3
|
+
import { createHiliteSetProvider, HiliteSet } from "./HiliteSetProvider.js";
|
|
4
4
|
import { SelectionStorage } from "./SelectionStorage.js";
|
|
5
5
|
/**
|
|
6
6
|
* Props for creating a `CachingHiliteSetProvider` instance.
|
|
@@ -11,6 +11,8 @@ export interface CachingHiliteSetProviderProps {
|
|
|
11
11
|
selectionStorage: SelectionStorage;
|
|
12
12
|
/** A callback that should return iModel access by iModel key. */
|
|
13
13
|
imodelProvider: (imodelKey: string) => ECClassHierarchyInspector & ECSqlQueryExecutor;
|
|
14
|
+
/** An optional hilite set provider factory. If not provided, defaults to `createHiliteSetProvider` from this package. */
|
|
15
|
+
createHiliteSetProvider?: typeof createHiliteSetProvider;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Defines return value of `createCachingHiliteSetProvider`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CachingHiliteSetProvider.d.ts","sourceRoot":"","sources":["../../../src/unified-selection/CachingHiliteSetProvider.ts"],"names":[],"mappings":"AAKA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,
|
|
1
|
+
{"version":3,"file":"CachingHiliteSetProvider.d.ts","sourceRoot":"","sources":["../../../src/unified-selection/CachingHiliteSetProvider.ts"],"names":[],"mappings":"AAKA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAqB,MAAM,wBAAwB,CAAC;AAE/F,OAAO,EAAuC,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9F;;;GAGG;AACH,MAAM,WAAW,6BAA6B;IAC5C,8DAA8D;IAC9D,gBAAgB,EAAE,gBAAgB,CAAC;IAEnC,iEAAiE;IACjE,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,yBAAyB,GAAG,kBAAkB,CAAC;IAEtF,yHAAyH;IACzH,uBAAuB,CAAC,EAAE,OAAO,uBAAuB,CAAC;CAC1D;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,YAAY,CAAC,KAAK,EAAE;QAClB,mCAAmC;QACnC,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAErC;;;;;OAKG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC;IAE9B;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,6BAA6B,GAAG,wBAAwB,GAAG;IAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,CAEhJ"}
|
|
@@ -24,6 +24,7 @@ class CachingHiliteSetProviderImpl {
|
|
|
24
24
|
_cache = new Map();
|
|
25
25
|
_removeListener;
|
|
26
26
|
_imodelProvider;
|
|
27
|
+
_createHiliteSetProvider;
|
|
27
28
|
constructor(props) {
|
|
28
29
|
this._selectionStorage = props.selectionStorage;
|
|
29
30
|
this._imodelProvider = props.imodelProvider;
|
|
@@ -33,6 +34,7 @@ class CachingHiliteSetProviderImpl {
|
|
|
33
34
|
this._hiliteSetProviders.delete(args.imodelKey);
|
|
34
35
|
}
|
|
35
36
|
});
|
|
37
|
+
this._createHiliteSetProvider = props.createHiliteSetProvider ?? /* c8 ignore next */ HiliteSetProvider_js_1.createHiliteSetProvider;
|
|
36
38
|
}
|
|
37
39
|
getHiliteSet({ imodelKey }) {
|
|
38
40
|
const imodelAccess = this._imodelProvider(imodelKey);
|
|
@@ -57,7 +59,7 @@ class CachingHiliteSetProviderImpl {
|
|
|
57
59
|
getHiliteSetProvider(imodelKey, imodelAccess) {
|
|
58
60
|
let provider = this._hiliteSetProviders.get(imodelKey);
|
|
59
61
|
if (!provider) {
|
|
60
|
-
provider =
|
|
62
|
+
provider = this._createHiliteSetProvider({ imodelAccess });
|
|
61
63
|
this._hiliteSetProviders.set(imodelKey, provider);
|
|
62
64
|
}
|
|
63
65
|
return provider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CachingHiliteSetProvider.js","sourceRoot":"","sources":["../../../src/unified-selection/CachingHiliteSetProvider.ts"],"names":[],"mappings":";AAAA;;;gGAGgG;;
|
|
1
|
+
{"version":3,"file":"CachingHiliteSetProvider.js","sourceRoot":"","sources":["../../../src/unified-selection/CachingHiliteSetProvider.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\n\nimport \"./DisposePolyfill.js\";\nimport { from, Observable, shareReplay } from \"rxjs\";\nimport { eachValueFrom } from \"rxjs-for-await\";\nimport { ECClassHierarchyInspector, ECSqlQueryExecutor } from \"@itwin/presentation-shared\";\nimport { createHiliteSetProvider, HiliteSet, HiliteSetProvider } from \"./HiliteSetProvider.js\";\nimport { StorageSelectionChangeEventArgs } from \"./SelectionChangeEvent.js\";\nimport { IMODEL_CLOSE_SELECTION_CLEAR_SOURCE, SelectionStorage } from \"./SelectionStorage.js\";\n\n/**\n * Props for creating a `CachingHiliteSetProvider` instance.\n * @public\n */\nexport interface CachingHiliteSetProviderProps {\n /** Selection storage to use for retrieving the hilite set. */\n selectionStorage: SelectionStorage;\n\n /** A callback that should return iModel access by iModel key. */\n imodelProvider: (imodelKey: string) => ECClassHierarchyInspector & ECSqlQueryExecutor;\n\n /** An optional hilite set provider factory. If not provided, defaults to `createHiliteSetProvider` from this package. */\n createHiliteSetProvider?: typeof createHiliteSetProvider;\n}\n\n/**\n * Defines return value of `createCachingHiliteSetProvider`.\n *\n * **Warning:** Used in public API as a return value. Not expected to be created / extended by package\n * consumers, may be supplemented with required attributes any time.\n *\n * @see `createCachingHiliteSetProvider`\n * @public\n */\nexport interface CachingHiliteSetProvider {\n /** Get the current hilite set iterator for the specified imodel */\n getHiliteSet(props: {\n /** iModel to get hilite set for */\n imodelKey: string;\n }): AsyncIterableIterator<HiliteSet>;\n\n /**\n * Disposes the cache.\n *\n * Optional to avoid breaking the API. Will be made required when the deprecated\n * `dispose` is removed.\n */\n [Symbol.dispose]?: () => void;\n\n /**\n * Disposes the cache.\n * @deprecated in 1.2. Use `[Symbol.dispose]` instead.\n */\n dispose(): void;\n}\n\n/**\n * Creates a hilite set provider that caches hilite set for current selection for given iModel so any subsequent\n * hilite set requests for the same iModel don't cost until selection in given selection storage changes.\n * @public\n */\nexport function createCachingHiliteSetProvider(props: CachingHiliteSetProviderProps): CachingHiliteSetProvider & { [Symbol.dispose]: () => void } {\n return new CachingHiliteSetProviderImpl(props);\n}\n\nclass CachingHiliteSetProviderImpl implements CachingHiliteSetProvider {\n private _selectionStorage: SelectionStorage;\n private _hiliteSetProviders = new Map<string, HiliteSetProvider>();\n private _cache = new Map<string, Observable<HiliteSet>>();\n private _removeListener: () => void;\n private _imodelProvider: (imodelKey: string) => ECClassHierarchyInspector & ECSqlQueryExecutor;\n private _createHiliteSetProvider: typeof createHiliteSetProvider;\n\n constructor(props: CachingHiliteSetProviderProps) {\n this._selectionStorage = props.selectionStorage;\n this._imodelProvider = props.imodelProvider;\n this._removeListener = this._selectionStorage.selectionChangeEvent.addListener((args: StorageSelectionChangeEventArgs) => {\n this._cache.delete(args.imodelKey);\n if (args.changeType === \"clear\" && args.source === IMODEL_CLOSE_SELECTION_CLEAR_SOURCE) {\n this._hiliteSetProviders.delete(args.imodelKey);\n }\n });\n this._createHiliteSetProvider = props.createHiliteSetProvider ?? /* c8 ignore next */ createHiliteSetProvider;\n }\n\n public getHiliteSet({ imodelKey }: { imodelKey: string }): AsyncIterableIterator<HiliteSet> {\n const imodelAccess = this._imodelProvider(imodelKey);\n const provider = this.getHiliteSetProvider(imodelKey, imodelAccess);\n let hiliteSet = this._cache.get(imodelKey);\n\n if (!hiliteSet) {\n const selectables = this._selectionStorage.getSelection({ imodelKey });\n hiliteSet = from(provider.getHiliteSet({ selectables })).pipe(shareReplay({ refCount: true }));\n this._cache.set(imodelKey, hiliteSet);\n }\n\n return eachValueFrom(hiliteSet);\n }\n\n public [Symbol.dispose](): void {\n this._removeListener();\n this._hiliteSetProviders = new Map();\n this._cache = new Map();\n }\n\n /* c8 ignore next 3 */\n public dispose(): void {\n this[Symbol.dispose]();\n }\n\n private getHiliteSetProvider(imodelKey: string, imodelAccess: ECClassHierarchyInspector & ECSqlQueryExecutor) {\n let provider = this._hiliteSetProviders.get(imodelKey);\n if (!provider) {\n provider = this._createHiliteSetProvider({ imodelAccess });\n this._hiliteSetProviders.set(imodelKey, provider);\n }\n return provider;\n }\n}\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import "./DisposePolyfill.js";
|
|
2
2
|
import { ECClassHierarchyInspector, ECSqlQueryExecutor } from "@itwin/presentation-shared";
|
|
3
3
|
import { CachingHiliteSetProvider } from "./CachingHiliteSetProvider.js";
|
|
4
|
-
import {
|
|
4
|
+
import { HiliteSetProvider } from "./HiliteSetProvider.js";
|
|
5
|
+
import { SelectionScope } from "./SelectionScope.js";
|
|
5
6
|
import { SelectionStorage } from "./SelectionStorage.js";
|
|
6
7
|
import { CoreIModelHiliteSet, CoreIModelSelectionSet } from "./types/IModel.js";
|
|
7
8
|
/**
|
|
@@ -11,8 +12,9 @@ import { CoreIModelHiliteSet, CoreIModelSelectionSet } from "./types/IModel.js";
|
|
|
11
12
|
export interface EnableUnifiedSelectionSyncWithIModelProps {
|
|
12
13
|
/**
|
|
13
14
|
* Provides access to different iModel's features: query executing, class hierarchy, selection and hilite sets.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
15
|
+
*
|
|
16
|
+
* It's recommended to use `@itwin/presentation-core-interop` to create `key`, `ECSqlQueryExecutor` and `ECSchemaProvider` from
|
|
17
|
+
* [IModelConnection](https://www.itwinjs.org/reference/core-frontend/imodelconnection/imodelconnection/), and map its
|
|
16
18
|
* `hilited` and `selectionSet` attributes like this:
|
|
17
19
|
*
|
|
18
20
|
* ```ts
|
|
@@ -28,7 +30,7 @@ export interface EnableUnifiedSelectionSyncWithIModelProps {
|
|
|
28
30
|
* hiliteSet: imodel.hilited,
|
|
29
31
|
* selectionSet: imodel.selectionSet,
|
|
30
32
|
* };
|
|
31
|
-
*
|
|
33
|
+
* ```
|
|
32
34
|
*/
|
|
33
35
|
imodelAccess: ECSqlQueryExecutor & ECClassHierarchyInspector & {
|
|
34
36
|
/** Key of the iModel. Generally taken from `IModelConnection.key`. */
|
|
@@ -38,10 +40,13 @@ export interface EnableUnifiedSelectionSyncWithIModelProps {
|
|
|
38
40
|
/** The set of currently selected elements taken from `IModelConnection.selectionSet`. */
|
|
39
41
|
readonly selectionSet: CoreIModelSelectionSet;
|
|
40
42
|
};
|
|
41
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Unified selection storage to synchronize IModel's tool selection with. The storage should be shared
|
|
45
|
+
* across all components in the application to ensure unified selection experience.
|
|
46
|
+
*/
|
|
42
47
|
selectionStorage: SelectionStorage;
|
|
43
|
-
/** Active scope provider. */
|
|
44
|
-
activeScopeProvider: () =>
|
|
48
|
+
/** Active selection scope provider. */
|
|
49
|
+
activeScopeProvider: () => SelectionScope;
|
|
45
50
|
/**
|
|
46
51
|
* A caching hilite set provider used to retrieve hilite sets for an iModel. If not provided, a new `CachingHiliteSetProvider`
|
|
47
52
|
* will be created for the given iModel using the provided `imodelAccess`.
|
|
@@ -62,8 +67,9 @@ export interface EnableUnifiedSelectionSyncWithIModelProps {
|
|
|
62
67
|
*/
|
|
63
68
|
export declare function enableUnifiedSelectionSyncWithIModel(props: EnableUnifiedSelectionSyncWithIModelProps): () => void;
|
|
64
69
|
/**
|
|
65
|
-
* A handler that syncs selection between unified selection storage
|
|
66
|
-
*
|
|
70
|
+
* A handler that syncs selection between unified selection storage (`SelectionStorage`) and
|
|
71
|
+
* an iModel (`iModel.selectionSet`, `iModel.hilited`).
|
|
72
|
+
*
|
|
67
73
|
* @internal
|
|
68
74
|
*/
|
|
69
75
|
export declare class IModelSelectionHandler {
|
|
@@ -78,7 +84,9 @@ export declare class IModelSelectionHandler {
|
|
|
78
84
|
private _unregisterUnifiedSelectionListener;
|
|
79
85
|
private _unregisterIModelSelectionSetListener;
|
|
80
86
|
private _hasCustomCachingHiliteSetProvider;
|
|
81
|
-
constructor(props: EnableUnifiedSelectionSyncWithIModelProps
|
|
87
|
+
constructor(props: EnableUnifiedSelectionSyncWithIModelProps & {
|
|
88
|
+
hiliteSetProvider?: HiliteSetProvider;
|
|
89
|
+
});
|
|
82
90
|
[Symbol.dispose](): void;
|
|
83
91
|
/** Temporarily suspends tool selection synchronization until the returned disposable object is disposed. */
|
|
84
92
|
suspendIModelToolSelectionSync(): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnableUnifiedSelectionSyncWithIModel.d.ts","sourceRoot":"","sources":["../../../src/unified-selection/EnableUnifiedSelectionSyncWithIModel.ts"],"names":[],"mappings":"AAKA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"EnableUnifiedSelectionSyncWithIModel.d.ts","sourceRoot":"","sources":["../../../src/unified-selection/EnableUnifiedSelectionSyncWithIModel.ts"],"names":[],"mappings":"AAKA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,OAAO,EAAE,wBAAwB,EAAkC,MAAM,+BAA+B,CAAC;AACzG,OAAO,EAAsC,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG/F,OAAO,EAAoB,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAA6E,MAAM,mBAAmB,CAAC;AAG3J;;;GAGG;AACH,MAAM,WAAW,yCAAyC;IACxD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,YAAY,EAAE,kBAAkB,GAC9B,yBAAyB,GAAG;QAC1B,sEAAsE;QACtE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,mFAAmF;QACnF,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC;QACxC,yFAAyF;QACzF,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAC;KAC/C,CAAC;IAEJ;;;OAGG;IACH,gBAAgB,EAAE,gBAAgB,CAAC;IAEnC,uCAAuC;IACvC,mBAAmB,EAAE,MAAM,cAAc,CAAC;IAE1C;;;;;;;;OAQG;IACH,wBAAwB,CAAC,EAAE,wBAAwB,GAAG,CAAC,IAAI,CAAC,wBAAwB,EAAE,SAAS,CAAC,GAAG;QAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC,CAAC;CACtI;AAED;;;;GAIG;AACH,wBAAgB,oCAAoC,CAAC,KAAK,EAAE,yCAAyC,GAAG,MAAM,IAAI,CAGjH;AAED;;;;;GAKG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,oBAAoB,CAAU;IAEtC,OAAO,CAAC,aAAa,CAA4D;IACjF,OAAO,CAAC,iBAAiB,CAAmB;IAC5C,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,yBAAyB,CAAqF;IACtH,OAAO,CAAC,oBAAoB,CAAuB;IAEnD,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,mCAAmC,CAAa;IACxD,OAAO,CAAC,qCAAqC,CAAa;IAC1D,OAAO,CAAC,kCAAkC,CAAU;gBAEjC,KAAK,EAAE,yCAAyC,GAAG;QAAE,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;KAAE;IA0BxG,CAAC,MAAM,CAAC,OAAO,CAAC;IAUvB,4GAA4G;IACrG,8BAA8B;;;IAUrC,OAAO,CAAC,4BAA4B;IAsCpC,OAAO,CAAC,yBAAyB,CAU/B;IAEF,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,wBAAwB,CAmB9B;YAEY,2BAA2B;IAiBzC,OAAO,CAAC,wBAAwB;CAcjC"}
|
|
@@ -75,8 +75,9 @@ function enableUnifiedSelectionSyncWithIModel(props) {
|
|
|
75
75
|
return () => selectionHandler[Symbol.dispose]();
|
|
76
76
|
}
|
|
77
77
|
/**
|
|
78
|
-
* A handler that syncs selection between unified selection storage
|
|
79
|
-
*
|
|
78
|
+
* A handler that syncs selection between unified selection storage (`SelectionStorage`) and
|
|
79
|
+
* an iModel (`iModel.selectionSet`, `iModel.hilited`).
|
|
80
|
+
*
|
|
80
81
|
* @internal
|
|
81
82
|
*/
|
|
82
83
|
class IModelSelectionHandler {
|
|
@@ -96,22 +97,28 @@ class IModelSelectionHandler {
|
|
|
96
97
|
this._selectionStorage = props.selectionStorage;
|
|
97
98
|
this._activeScopeProvider = props.activeScopeProvider;
|
|
98
99
|
this._isSuspended = false;
|
|
100
|
+
this._hiliteSetProvider = props.hiliteSetProvider ?? (0, HiliteSetProvider_js_1.createHiliteSetProvider)({ imodelAccess: this._imodelAccess });
|
|
99
101
|
this._hasCustomCachingHiliteSetProvider = !!props.cachingHiliteSetProvider;
|
|
100
102
|
this._cachingHiliteSetProvider =
|
|
101
|
-
props.cachingHiliteSetProvider ??
|
|
102
|
-
(0, CachingHiliteSetProvider_js_1.createCachingHiliteSetProvider)({
|
|
103
|
+
props.cachingHiliteSetProvider /* c8 ignore next */ ??
|
|
104
|
+
/* c8 ignore next 4 */ (0, CachingHiliteSetProvider_js_1.createCachingHiliteSetProvider)({
|
|
103
105
|
selectionStorage: this._selectionStorage,
|
|
104
106
|
imodelProvider: () => this._imodelAccess,
|
|
107
|
+
createHiliteSetProvider: () => this._hiliteSetProvider,
|
|
105
108
|
});
|
|
106
|
-
this._hiliteSetProvider = (0, HiliteSetProvider_js_1.createHiliteSetProvider)({ imodelAccess: this._imodelAccess });
|
|
107
109
|
this._unregisterIModelSelectionSetListener = this._imodelAccess.selectionSet.onChanged.addListener(this.onIModelSelectionChanged);
|
|
108
110
|
this._unregisterUnifiedSelectionListener = this._selectionStorage.selectionChangeEvent.addListener(this.onUnifiedSelectionChanged);
|
|
109
|
-
this.
|
|
111
|
+
if (!is5xSelectionSet(this._imodelAccess.selectionSet)) {
|
|
112
|
+
// itwinjs-core@4: stop imodel from syncing tool selection with hilited list - we want to manage that sync ourselves
|
|
113
|
+
this._imodelAccess.hiliteSet.wantSyncWithSelectionSet = false;
|
|
114
|
+
}
|
|
115
|
+
this.applyCurrentHiliteSet({ activeSelectionAction: "clearAll" });
|
|
110
116
|
}
|
|
111
117
|
[Symbol.dispose]() {
|
|
112
118
|
this._cancelOngoingChanges.next();
|
|
113
119
|
this._unregisterIModelSelectionSetListener();
|
|
114
120
|
this._unregisterUnifiedSelectionListener();
|
|
121
|
+
/* c8 ignore next 3 */
|
|
115
122
|
if (!this._hasCustomCachingHiliteSetProvider) {
|
|
116
123
|
(0, Utils_js_1.safeDispose)(this._cachingHiliteSetProvider);
|
|
117
124
|
}
|
|
@@ -129,8 +136,18 @@ class IModelSelectionHandler {
|
|
|
129
136
|
handleUnifiedSelectionChange(changeType, selectables, source) {
|
|
130
137
|
switch (changeType) {
|
|
131
138
|
case "clear":
|
|
139
|
+
return this.applyCurrentHiliteSet({ activeSelectionAction: "clearAll" });
|
|
132
140
|
case "replace":
|
|
133
|
-
return this.applyCurrentHiliteSet({
|
|
141
|
+
return this.applyCurrentHiliteSet({
|
|
142
|
+
activeSelectionAction: source === this._selectionSourceName
|
|
143
|
+
? is5xSelectionSet(this._imodelAccess.selectionSet)
|
|
144
|
+
? // with 5x core we don't need to clear anything when event is triggered by a Tool (hilite and selection sets are in sync already)
|
|
145
|
+
"keep"
|
|
146
|
+
: // with 4x core we need to clear hilite set, because it's not synced with selection set
|
|
147
|
+
"clearHilited"
|
|
148
|
+
: // when event is triggered not by a Tool, we need to clear everything
|
|
149
|
+
"clearAll",
|
|
150
|
+
});
|
|
134
151
|
case "add":
|
|
135
152
|
return void (0, rxjs_1.from)(this._hiliteSetProvider.getHiliteSet({ selectables }))
|
|
136
153
|
.pipe((0, rxjs_1.takeUntil)(this._cancelOngoingChanges))
|
|
@@ -163,12 +180,16 @@ class IModelSelectionHandler {
|
|
|
163
180
|
this.handleUnifiedSelectionChange(args.changeType, args.selectables, args.source);
|
|
164
181
|
};
|
|
165
182
|
applyCurrentHiliteSet({ activeSelectionAction }) {
|
|
166
|
-
if (activeSelectionAction
|
|
183
|
+
if (activeSelectionAction !== "keep") {
|
|
167
184
|
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
168
185
|
try {
|
|
169
186
|
const _dispose = __addDisposableResource(env_1, this.suspendIModelToolSelectionSync(), false);
|
|
170
|
-
this._imodelAccess.
|
|
171
|
-
|
|
187
|
+
if (!is5xSelectionSet(this._imodelAccess.selectionSet)) {
|
|
188
|
+
this._imodelAccess.hiliteSet.clear();
|
|
189
|
+
}
|
|
190
|
+
if (activeSelectionAction === "clearAll") {
|
|
191
|
+
this._imodelAccess.selectionSet.emptyAll();
|
|
192
|
+
}
|
|
172
193
|
}
|
|
173
194
|
catch (e_1) {
|
|
174
195
|
env_1.error = e_1;
|
|
@@ -190,9 +211,8 @@ class IModelSelectionHandler {
|
|
|
190
211
|
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
191
212
|
try {
|
|
192
213
|
const _dispose = __addDisposableResource(env_2, this.suspendIModelToolSelectionSync(), false);
|
|
193
|
-
if (
|
|
194
|
-
//
|
|
195
|
-
// in selection set - we can simply add the set as a whole
|
|
214
|
+
if (is5xSelectionSet(this._imodelAccess.selectionSet)) {
|
|
215
|
+
// with 5.x core we can simply add the set as a whole
|
|
196
216
|
this._imodelAccess.selectionSet.add({
|
|
197
217
|
models: set.models,
|
|
198
218
|
subcategories: set.subCategories,
|
|
@@ -208,6 +228,7 @@ class IModelSelectionHandler {
|
|
|
208
228
|
this._imodelAccess.hiliteSet.subcategories.addIds(set.subCategories);
|
|
209
229
|
}
|
|
210
230
|
if (set.elements.length) {
|
|
231
|
+
this._imodelAccess.hiliteSet.elements.addIds(set.elements);
|
|
211
232
|
this._imodelAccess.selectionSet.add(set.elements);
|
|
212
233
|
}
|
|
213
234
|
}
|
|
@@ -224,9 +245,8 @@ class IModelSelectionHandler {
|
|
|
224
245
|
const env_3 = { stack: [], error: void 0, hasError: false };
|
|
225
246
|
try {
|
|
226
247
|
const _dispose = __addDisposableResource(env_3, this.suspendIModelToolSelectionSync(), false);
|
|
227
|
-
if (
|
|
228
|
-
//
|
|
229
|
-
// in selection set - we can simply remove the set as a whole
|
|
248
|
+
if (is5xSelectionSet(this._imodelAccess.selectionSet)) {
|
|
249
|
+
// with 5.x core we can simply remove the set as a whole
|
|
230
250
|
this._imodelAccess.selectionSet.remove({
|
|
231
251
|
models: set.models,
|
|
232
252
|
subcategories: set.subCategories,
|
|
@@ -241,6 +261,7 @@ class IModelSelectionHandler {
|
|
|
241
261
|
this._imodelAccess.hiliteSet.subcategories.deleteIds(set.subCategories);
|
|
242
262
|
}
|
|
243
263
|
if (set.elements.length) {
|
|
264
|
+
this._imodelAccess.hiliteSet.elements.deleteIds(set.elements);
|
|
244
265
|
this._imodelAccess.selectionSet.remove(set.elements);
|
|
245
266
|
}
|
|
246
267
|
}
|
|
@@ -295,4 +316,7 @@ class IModelSelectionHandler {
|
|
|
295
316
|
}
|
|
296
317
|
}
|
|
297
318
|
exports.IModelSelectionHandler = IModelSelectionHandler;
|
|
319
|
+
function is5xSelectionSet(selectionSet) {
|
|
320
|
+
return "active" in selectionSet;
|
|
321
|
+
}
|
|
298
322
|
//# sourceMappingURL=EnableUnifiedSelectionSyncWithIModel.js.map
|