@@ -11,9 +11,18 @@ import type { Id64Set, Id64String } from "@itwin/core-bentley";
11
11
import type { HierarchyNode } from "@itwin/presentation-hierarchies" ;
12
12
import type { ECClassHierarchyInspector , InstanceKey } from "@itwin/presentation-shared" ;
13
13
import type { CategoryId , ElementId , ModelId , SubCategoryId } from "../../common/internal/Types.js" ;
14
- import type { FilteredTree , FilteredVisibilityTargets } from "../../common/internal/visibility/BaseFilteredTree.js" ;
14
+ import type { FilteredTree } from "../../common/internal/visibility/BaseFilteredTree.js" ;
15
15
import type { CategoriesTreeIdsCache } from "./CategoriesTreeIdsCache.js" ;
16
16
17
+ /** @internal */
18
+ export interface CategoriesTreeFilterTargets {
19
+ categories ?: Array < { modelId : Id64String | undefined ; categoryIds : Id64Set } > ;
20
+ elements ?: Array < { modelId : Id64String ; categoryId : Id64String ; elementIds : Id64Set } > ;
21
+ definitionContainerIds ?: Id64Set ;
22
+ modelIds ?: Id64Set ;
23
+ subCategories ?: Array < { categoryId : Id64String ; subCategoryIds : Id64Set } > ;
24
+ }
25
+
17
26
interface FilteredTreeRootNode {
18
27
children : Map < Id64String , FilteredTreeNode > ;
19
28
}
@@ -64,35 +73,6 @@ type TemporaryFilteredTreeNode =
64
73
| TemporaryElementFilteredNode
65
74
| ModelFilteredTreeNode ;
66
75
67
- type ModelCategoryKey = `${ModelId } -${CategoryId } `;
68
-
69
- function createModelCategoryKey ( modelId : Id64String , categoryId : Id64String ) : ModelCategoryKey {
70
- return `${ modelId } -${ categoryId } ` ;
71
- }
72
-
73
- /** @internal */
74
- function parseModelCategoryKey ( key : ModelCategoryKey ) : { modelId : Id64String ; categoryId : Id64String } {
75
- const [ modelId , categoryId ] = key . split ( "-" ) ;
76
- return { modelId, categoryId } ;
77
- }
78
-
79
- /** @internal */
80
- export interface CategoriesTreeFilterTargets {
81
- categories ?: Array < { modelId : Id64String | undefined ; categoryIds : Id64Set } > ;
82
- elements ?: Array < { modelId : Id64String ; categoryId : Id64String ; elementIds : Id64Set } > ;
83
- definitionContainerIds ?: Id64Set ;
84
- modelIds ?: Id64Set ;
85
- subCategories ?: Array < { categoryId : Id64String ; subCategoryIds : Id64Set } > ;
86
- }
87
-
88
- interface FilterTargetsInternal {
89
- elements ?: Map < ModelCategoryKey , Set < ElementId > > ;
90
- categories ?: Map < ModelId | undefined , Set < CategoryId > > ;
91
- definitionContainerIds ?: Id64Set ;
92
- modelIds ?: Id64Set ;
93
- subCategories ?: Map < CategoryId , Set < SubCategoryId > > ;
94
- }
95
-
96
76
/** @internal */
97
77
export async function createFilteredTree ( props : {
98
78
imodelAccess : ECClassHierarchyInspector ;
@@ -155,13 +135,13 @@ export async function createFilteredTree(props: {
155
135
} ;
156
136
}
157
137
158
- function getFilterTargets ( root : FilteredTreeRootNode , node : HierarchyNode ) : FilteredVisibilityTargets < CategoriesTreeFilterTargets > {
138
+ function getFilterTargets ( root : FilteredTreeRootNode , node : HierarchyNode ) : CategoriesTreeFilterTargets | undefined {
139
+ const filterTargetsHandler = new FilterTargetsHandler ( ) ;
159
140
let lookupParents : Array < { children ?: Map < Id64String , FilteredTreeNode > } > = [ root ] ;
160
- const filterTargets : FilterTargetsInternal = { } ;
161
141
162
142
const nodeKey = node . key ;
163
143
if ( ! HierarchyNodeKey . isInstances ( nodeKey ) ) {
164
- return { } ;
144
+ return undefined ;
165
145
}
166
146
167
147
// find the filtered parent nodes of the `node`
@@ -174,31 +154,43 @@ function getFilterTargets(root: FilteredTreeRootNode, node: HierarchyNode): Filt
174
154
// and use them when checking for matching node in one level deeper.
175
155
const parentNodes = findMatchingFilteredNodes ( lookupParents , parentKey . instanceKeys ) ;
176
156
if ( parentNodes . length === 0 ) {
177
- return { } ;
157
+ return undefined ;
178
158
}
179
159
lookupParents = parentNodes ;
180
160
}
181
161
182
162
// find filtered nodes that match the `node`
183
163
const filteredNodes = findMatchingFilteredNodes ( lookupParents , nodeKey . instanceKeys ) ;
184
164
if ( filteredNodes . length === 0 ) {
185
- return { } ;
165
+ return undefined ;
186
166
}
167
+ const filterTargets : FilterTargetsInternal = { } ;
187
168
188
- filteredNodes . forEach ( ( filteredNode ) => collectFilterTargets ( filterTargets , filteredNode ) ) ;
169
+ filteredNodes . forEach ( ( filteredNode ) => filterTargetsHandler . collectFilterTargets ( filterTargets , filteredNode ) ) ;
189
170
190
- if (
191
- ! filterTargets . categories &&
192
- ! filterTargets . definitionContainerIds &&
193
- ! filterTargets . elements &&
194
- ! filterTargets . modelIds &&
195
- ! filterTargets . subCategories
196
- ) {
197
- return { } ;
198
- }
171
+ return filterTargetsHandler . convertInternalFilterTargets ( filterTargets ) ;
172
+ }
199
173
200
- return {
201
- targets : {
174
+ interface FilterTargetsInternal {
175
+ elements ?: Map < ModelCategoryKey , Set < ElementId > > ;
176
+ categories ?: Map < ModelId | undefined , Set < CategoryId > > ;
177
+ definitionContainerIds ?: Id64Set ;
178
+ modelIds ?: Id64Set ;
179
+ subCategories ?: Map < CategoryId , Set < SubCategoryId > > ;
180
+ }
181
+
182
+ class FilterTargetsHandler {
183
+ public convertInternalFilterTargets ( filterTargets : FilterTargetsInternal ) : CategoriesTreeFilterTargets | undefined {
184
+ if (
185
+ ! filterTargets . categories &&
186
+ ! filterTargets . definitionContainerIds &&
187
+ ! filterTargets . elements &&
188
+ ! filterTargets . modelIds &&
189
+ ! filterTargets . subCategories
190
+ ) {
191
+ return undefined ;
192
+ }
193
+ return {
202
194
categories : filterTargets . categories
203
195
? [ ...filterTargets . categories . entries ( ) ] . map ( ( [ modelId , categoryIds ] ) => {
204
196
return { modelId, categoryIds } ;
@@ -217,72 +209,83 @@ function getFilterTargets(root: FilteredTreeRootNode, node: HierarchyNode): Filt
217
209
return { categoryId, subCategoryIds } ;
218
210
} )
219
211
: undefined ,
220
- } ,
221
- } ;
222
- }
223
-
224
- function findMatchingFilteredNodes ( lookupParents : Array < { children ?: Map < Id64String , FilteredTreeNode > } > , keys : InstanceKey [ ] ) {
225
- return lookupParents
226
- . flatMap ( ( lookup ) => keys . map ( ( key ) => lookup . children ?. get ( key . id ) ) )
227
- . filter ( ( lookupNode ) : lookupNode is FilteredTreeNode => lookupNode !== undefined ) ;
228
- }
229
-
230
- function collectFilterTargets ( changeTargets : FilterTargetsInternal , filteredNode : FilteredTreeNode ) {
231
- if ( filteredNode . isFilterTarget ) {
232
- addTarget ( changeTargets , filteredNode ) ;
233
- return ;
212
+ } ;
234
213
}
235
214
236
- if ( filteredNode . type === "element" ) {
237
- // need to add parent ids as filter target will be an element
238
- addTarget ( changeTargets , filteredNode ) ;
239
- }
215
+ public collectFilterTargets ( changeTargets : FilterTargetsInternal , filteredNode : FilteredTreeNode ) {
216
+ if ( filteredNode . isFilterTarget ) {
217
+ this . addTarget ( changeTargets , filteredNode ) ;
218
+ return ;
219
+ }
240
220
241
- if ( ! filteredNode . children ) {
242
- return ;
243
- }
221
+ if ( filteredNode . type === "element" ) {
222
+ // need to add parent ids as filter target will be an element
223
+ this . addTarget ( changeTargets , filteredNode ) ;
224
+ }
225
+
226
+ if ( ! filteredNode . children ) {
227
+ return ;
228
+ }
244
229
245
- for ( const child of filteredNode . children . values ( ) ) {
246
- collectFilterTargets ( changeTargets , child ) ;
230
+ for ( const child of filteredNode . children . values ( ) ) {
231
+ this . collectFilterTargets ( changeTargets , child ) ;
232
+ }
247
233
}
248
- }
249
234
250
- function addTarget ( filterTargets : FilterTargetsInternal , node : FilteredTreeNode ) {
251
- switch ( node . type ) {
252
- case "definitionContainer" :
253
- ( filterTargets . definitionContainerIds ??= new Set ( ) ) . add ( node . id ) ;
254
- return ;
255
- case "model" :
256
- ( filterTargets . modelIds ??= new Set ( ) ) . add ( node . id ) ;
257
- return ;
258
- case "subCategory" :
259
- const subCategories = ( filterTargets . subCategories ??= new Map ( ) ) . get ( node . categoryId ) ;
260
- if ( subCategories ) {
261
- subCategories . add ( node . id ) ;
235
+ private addTarget ( filterTargets : FilterTargetsInternal , node : FilteredTreeNode ) {
236
+ switch ( node . type ) {
237
+ case "definitionContainer" :
238
+ ( filterTargets . definitionContainerIds ??= new Set ( ) ) . add ( node . id ) ;
262
239
return ;
263
- }
264
- filterTargets . subCategories . set ( node . categoryId , new Set ( [ node . id ] ) ) ;
265
- return ;
266
- case "category" :
267
- const categories = ( filterTargets . categories ??= new Map ( ) ) . get ( node . modelId ) ;
268
- if ( ! categories ) {
269
- categories . add ( node . id ) ;
240
+ case "model" :
241
+ ( filterTargets . modelIds ??= new Set ( ) ) . add ( node . id ) ;
270
242
return ;
271
- }
272
- filterTargets . categories . set ( node . modelId , new Set ( [ node . id ] ) ) ;
273
- return ;
274
- case "element" :
275
- const modelCategoryKey = createModelCategoryKey ( node . modelId , node . categoryId ) ;
276
- const elements = ( filterTargets . elements ??= new Map ( ) ) . get ( modelCategoryKey ) ;
277
- if ( elements ) {
278
- elements . add ( node . id ) ;
243
+ case "subCategory" :
244
+ const subCategories = ( filterTargets . subCategories ??= new Map ( ) ) . get ( node . categoryId ) ;
245
+ if ( subCategories ) {
246
+ subCategories . add ( node . id ) ;
247
+ return ;
248
+ }
249
+ filterTargets . subCategories . set ( node . categoryId , new Set ( [ node . id ] ) ) ;
279
250
return ;
280
- }
281
- filterTargets . elements . set ( modelCategoryKey , new Set ( [ node . id ] ) ) ;
282
- return ;
251
+ case "category" :
252
+ const categories = ( filterTargets . categories ??= new Map ( ) ) . get ( node . modelId ) ;
253
+ if ( ! categories ) {
254
+ categories . add ( node . id ) ;
255
+ return ;
256
+ }
257
+ filterTargets . categories . set ( node . modelId , new Set ( [ node . id ] ) ) ;
258
+ return ;
259
+ case "element" :
260
+ const modelCategoryKey = createModelCategoryKey ( node . modelId , node . categoryId ) ;
261
+ const elements = ( filterTargets . elements ??= new Map ( ) ) . get ( modelCategoryKey ) ;
262
+ if ( elements ) {
263
+ elements . add ( node . id ) ;
264
+ return ;
265
+ }
266
+ filterTargets . elements . set ( modelCategoryKey , new Set ( [ node . id ] ) ) ;
267
+ return ;
268
+ }
283
269
}
284
270
}
285
271
272
+ type ModelCategoryKey = `${ModelId } -${CategoryId } `;
273
+
274
+ function createModelCategoryKey ( modelId : Id64String , categoryId : Id64String ) : ModelCategoryKey {
275
+ return `${ modelId } -${ categoryId } ` ;
276
+ }
277
+
278
+ function parseModelCategoryKey ( key : ModelCategoryKey ) : { modelId : Id64String ; categoryId : Id64String } {
279
+ const [ modelId , categoryId ] = key . split ( "-" ) ;
280
+ return { modelId, categoryId } ;
281
+ }
282
+
283
+ function findMatchingFilteredNodes ( lookupParents : Array < { children ?: Map < Id64String , FilteredTreeNode > } > , keys : InstanceKey [ ] ) {
284
+ return lookupParents
285
+ . flatMap ( ( lookup ) => keys . map ( ( key ) => lookup . children ?. get ( key . id ) ) )
286
+ . filter ( ( lookupNode ) : lookupNode is FilteredTreeNode => lookupNode !== undefined ) ;
287
+ }
288
+
286
289
function createFilteredTreeNode ( {
287
290
type,
288
291
id,
0 commit comments