33 * See LICENSE.md in the project root for license terms and full copyright notice.
44 *--------------------------------------------------------------------------------------------*/
55
6- import { assert } from "@itwin/core-bentley" ;
7- import { HierarchyFilteringPath , HierarchyNodeIdentifier , HierarchyNodeKey } from "@itwin/presentation-hierarchies" ;
6+ import { assert , Id64 } from "@itwin/core-bentley" ;
7+ import { HierarchyFilteringPath , HierarchyNode , HierarchyNodeIdentifier , HierarchyNodeKey } from "@itwin/presentation-hierarchies" ;
88
9- import type { Id64String } from "@itwin/core-bentley" ;
10- import type { HierarchyNode } from "@itwin/presentation-hierarchies" ;
11- import type { ECClassHierarchyInspector , InstanceKey } from "@itwin/presentation-shared" ;
9+ import type { Id64Arg , Id64String } from "@itwin/core-bentley" ;
10+ import type { ClassGroupingNodeKey , InstancesNodeKey } from "@itwin/presentation-hierarchies" ;
11+ import type { ECClassHierarchyInspector } from "@itwin/presentation-shared" ;
1212
1313interface FilteredTreeRootNode {
1414 children : Map < Id64String , FilteredTreeNode > ;
@@ -37,8 +37,9 @@ interface ElementFilteredTreeNode extends BaseFilteredTreeNode {
3737
3838type FilteredTreeNode = GenericFilteredTreeNode | CategoryFilteredTreeNode | ElementFilteredTreeNode ;
3939
40+ /** @internal */
4041export interface FilteredTree {
41- getVisibilityChangeTargets ( node : HierarchyNode ) : VisibilityChangeTargets ;
42+ getVisibilityChangeTargets ( node : HierarchyNode & { key : ClassGroupingNodeKey | InstancesNodeKey } ) : VisibilityChangeTargets ;
4243}
4344
4445export const SUBJECT_CLASS_NAME = "BisCore.Subject" as const ;
@@ -52,18 +53,21 @@ function createCategoryKey(modelId: string, categoryId: string): CategoryKey {
5253 return `${ modelId } -${ categoryId } ` ;
5354}
5455
56+ /** @internal */
5557export function parseCategoryKey ( key : CategoryKey ) {
5658 const [ modelId , categoryId ] = key . split ( "-" ) ;
5759 return { modelId, categoryId } ;
5860}
5961
60- interface VisibilityChangeTargets {
62+ /** @internal */
63+ export interface VisibilityChangeTargets {
6164 subjects ?: Set < Id64String > ;
6265 models ?: Set < Id64String > ;
6366 categories ?: Set < CategoryKey > ;
64- elements ?: Map < CategoryKey , Set < Id64String > > ;
67+ elements ?: Map < CategoryKey , Map < Id64String , { isFilterTarget : boolean } > > ;
6568}
6669
70+ /** @internal */
6771export async function createFilteredTree ( imodelAccess : ECClassHierarchyInspector , filteringPaths : HierarchyFilteringPath [ ] ) : Promise < FilteredTree > {
6872 const root : FilteredTreeRootNode = {
6973 children : new Map ( ) ,
@@ -102,19 +106,14 @@ export async function createFilteredTree(imodelAccess: ECClassHierarchyInspector
102106 }
103107
104108 return {
105- getVisibilityChangeTargets : ( node : HierarchyNode ) => getVisibilityChangeTargets ( root , node ) ,
109+ getVisibilityChangeTargets : ( node ) => getVisibilityChangeTargets ( root , node ) ,
106110 } ;
107111}
108112
109- function getVisibilityChangeTargets ( root : FilteredTreeRootNode , node : HierarchyNode ) {
110- let lookupParents : Array < { children ?: Map < Id64String , FilteredTreeNode > } > = [ root ] ;
113+ function getVisibilityChangeTargets ( root : FilteredTreeRootNode , node : HierarchyNode & { key : ClassGroupingNodeKey | InstancesNodeKey } ) {
114+ let lookupParents : Array < FilteredTreeRootNode | FilteredTreeNode > = [ root ] ;
111115 const changeTargets : VisibilityChangeTargets = { } ;
112116
113- const nodeKey = node . key ;
114- if ( ! HierarchyNodeKey . isInstances ( nodeKey ) ) {
115- return changeTargets ;
116- }
117-
118117 // find the filtered parent nodes of the `node`
119118 for ( const parentKey of node . parentKeys ) {
120119 if ( ! HierarchyNodeKey . isInstances ( parentKey ) ) {
@@ -123,15 +122,18 @@ function getVisibilityChangeTargets(root: FilteredTreeRootNode, node: HierarchyN
123122
124123 // tree node might be merged from multiple instances. As filtered tree stores only one instance per node, we need to find all matching nodes
125124 // and use them when checking for matching node in one level deeper.
126- const parentNodes = findMatchingFilteredNodes ( lookupParents , parentKey . instanceKeys ) ;
125+ const parentNodes = findMatchingFilteredNodes (
126+ lookupParents ,
127+ parentKey . instanceKeys . map ( ( key ) => key . id ) ,
128+ ) ;
127129 if ( parentNodes . length === 0 ) {
128130 return changeTargets ;
129131 }
130132 lookupParents = parentNodes ;
131133 }
132-
134+ const ids = HierarchyNode . isInstancesNode ( node ) ? node . key . instanceKeys . map ( ( { id } ) => id ) : node . groupedInstanceKeys . map ( ( { id } ) => id ) ;
133135 // find filtered nodes that match the `node`
134- const filteredNodes = findMatchingFilteredNodes ( lookupParents , nodeKey . instanceKeys ) ;
136+ const filteredNodes = findMatchingFilteredNodes ( lookupParents , ids ) ;
135137 if ( filteredNodes . length === 0 ) {
136138 return changeTargets ;
137139 }
@@ -140,10 +142,17 @@ function getVisibilityChangeTargets(root: FilteredTreeRootNode, node: HierarchyN
140142 return changeTargets ;
141143}
142144
143- function findMatchingFilteredNodes ( lookupParents : Array < { children ?: Map < Id64String , FilteredTreeNode > } > , keys : InstanceKey [ ] ) {
144- return lookupParents
145- . flatMap ( ( lookup ) => keys . map ( ( key ) => lookup . children ?. get ( key . id ) ) )
146- . filter ( ( lookupNode ) : lookupNode is FilteredTreeNode => lookupNode !== undefined ) ;
145+ function findMatchingFilteredNodes ( lookupParents : Array < FilteredTreeRootNode | FilteredTreeNode > , ids : Id64Arg ) : Array < FilteredTreeNode > {
146+ return lookupParents . flatMap ( ( lookup ) => {
147+ const childrenArray = Array < FilteredTreeNode > ( ) ;
148+ for ( const id of Id64 . iterable ( ids ) ) {
149+ const node = lookup . children ?. get ( id ) ;
150+ if ( node ) {
151+ childrenArray . push ( node ) ;
152+ }
153+ }
154+ return childrenArray ;
155+ } ) ;
147156}
148157
149158function collectVisibilityChangeTargets ( changeTargets : VisibilityChangeTargets , node : FilteredTreeNode ) {
@@ -181,11 +190,10 @@ function addTarget(filterTargets: VisibilityChangeTargets, node: FilteredTreeNod
181190 const categoryKey = createCategoryKey ( node . modelId , node . categoryId ) ;
182191 const elements = ( filterTargets . elements ??= new Map ( ) ) . get ( categoryKey ) ;
183192 if ( elements ) {
184- elements . add ( node . id ) ;
185- return ;
193+ elements . set ( node . id , { isFilterTarget : node . isFilterTarget } ) ;
194+ } else {
195+ filterTargets . elements . set ( categoryKey , new Map ( [ [ node . id , { isFilterTarget : node . isFilterTarget } ] ] ) ) ;
186196 }
187- filterTargets . elements . set ( categoryKey , new Set ( [ node . id ] ) ) ;
188- return ;
189197 }
190198}
191199
0 commit comments