@itwin/tree-widget-react 3.15.0 → 3.16.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.
Files changed (126) hide show
  1. package/CHANGELOG.md +22 -2
  2. package/lib/cjs/tree-widget-react/TreeWidget.d.ts +1 -2
  3. package/lib/cjs/tree-widget-react/TreeWidget.js +12 -12
  4. package/lib/cjs/tree-widget-react/TreeWidget.js.map +1 -1
  5. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.d.ts +2 -3
  6. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js +5 -4
  7. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  8. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +4 -7
  9. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +39 -31
  10. package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  11. package/lib/cjs/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +6 -2
  12. package/lib/cjs/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  13. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +3 -11
  14. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +45 -36
  15. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
  16. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.d.ts +1 -3
  17. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +30 -30
  18. package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
  19. package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.d.ts +2 -7
  20. package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +8 -21
  21. package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
  22. package/lib/cjs/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.d.ts +3 -0
  23. package/lib/cjs/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.js +7 -7
  24. package/lib/cjs/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.js.map +1 -1
  25. package/lib/cjs/tree-widget-react/components/trees/common/useGuid.d.ts +2 -0
  26. package/lib/cjs/tree-widget-react/components/trees/common/useGuid.js +14 -0
  27. package/lib/cjs/tree-widget-react/components/trees/common/useGuid.js.map +1 -0
  28. package/lib/cjs/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js +4 -1
  29. package/lib/cjs/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js.map +1 -1
  30. package/lib/cjs/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.d.ts +4 -6
  31. package/lib/cjs/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js +31 -26
  32. package/lib/cjs/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js.map +1 -1
  33. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.d.ts +1 -1
  34. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js +4 -2
  35. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js.map +1 -1
  36. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.d.ts +1 -5
  37. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js +44 -44
  38. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js.map +1 -1
  39. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.d.ts +3 -6
  40. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js +20 -16
  41. package/lib/cjs/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js.map +1 -1
  42. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js +3 -1
  43. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  44. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +6 -10
  45. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +107 -64
  46. package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  47. package/lib/cjs/tree-widget-react/components/trees/models-tree/UseModelsTree.js +18 -8
  48. package/lib/cjs/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
  49. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.d.ts +24 -0
  50. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js +46 -0
  51. package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
  52. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.d.ts +40 -9
  53. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +68 -39
  54. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
  55. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +13 -5
  56. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +20 -14
  57. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
  58. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +5 -13
  59. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +70 -60
  60. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  61. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.d.ts +6 -2
  62. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +189 -197
  63. package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  64. package/lib/esm/tree-widget-react/TreeWidget.d.ts +1 -2
  65. package/lib/esm/tree-widget-react/TreeWidget.js +12 -12
  66. package/lib/esm/tree-widget-react/TreeWidget.js.map +1 -1
  67. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.d.ts +2 -3
  68. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js +5 -3
  69. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeButtons.js.map +1 -1
  70. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +4 -7
  71. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +39 -31
  72. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  73. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +6 -2
  74. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  75. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +3 -11
  76. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +45 -36
  77. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
  78. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.d.ts +1 -3
  79. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +30 -30
  80. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
  81. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.d.ts +2 -7
  82. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +8 -20
  83. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
  84. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.d.ts +3 -0
  85. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.js +7 -7
  86. package/lib/esm/tree-widget-react/components/trees/common/internal/useTreeHooks/UseIdsCache.js.map +1 -1
  87. package/lib/esm/tree-widget-react/components/trees/common/useGuid.d.ts +2 -0
  88. package/lib/esm/tree-widget-react/components/trees/common/useGuid.js +11 -0
  89. package/lib/esm/tree-widget-react/components/trees/common/useGuid.js.map +1 -0
  90. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js +4 -1
  91. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js.map +1 -1
  92. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.d.ts +4 -6
  93. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js +31 -26
  94. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeDefinition.js.map +1 -1
  95. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.d.ts +1 -1
  96. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js +4 -2
  97. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js.map +1 -1
  98. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.d.ts +1 -5
  99. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js +44 -44
  100. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeDefinition.js.map +1 -1
  101. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.d.ts +3 -6
  102. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js +21 -17
  103. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/internal/IModelContentTreeIdsCache.js.map +1 -1
  104. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js +3 -1
  105. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeButtons.js.map +1 -1
  106. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +6 -10
  107. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +107 -64
  108. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  109. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js +18 -8
  110. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js.map +1 -1
  111. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.d.ts +24 -0
  112. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js +44 -0
  113. package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
  114. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.d.ts +40 -9
  115. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +70 -41
  116. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
  117. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +13 -5
  118. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +22 -16
  119. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
  120. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +5 -13
  121. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +71 -61
  122. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  123. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.d.ts +6 -2
  124. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +192 -200
  125. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  126. package/package.json +8 -8
@@ -2,15 +2,15 @@
2
2
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
3
  * See LICENSE.md in the project root for license terms and full copyright notice.
4
4
  *--------------------------------------------------------------------------------------------*/
5
- import { concat, concatAll, defer, distinct, EMPTY, filter, firstValueFrom, forkJoin, from, fromEventPattern, map, merge, mergeMap, of, reduce, shareReplay, startWith, Subject, take, takeUntil, tap, toArray, } from "rxjs";
5
+ import { concat, concatAll, defaultIfEmpty, defer, distinct, EMPTY, filter, firstValueFrom, forkJoin, from, fromEventPattern, map, merge, mergeMap, of, reduce, shareReplay, startWith, Subject, take, takeUntil, tap, toArray, } from "rxjs";
6
6
  import { assert, Id64 } from "@itwin/core-bentley";
7
7
  import { PerModelCategoryVisibility } from "@itwin/core-frontend";
8
8
  import { HierarchyNode, HierarchyNodeKey } from "@itwin/presentation-hierarchies";
9
- import { toggleAllCategories } from "../../common/CategoriesVisibilityUtils.js";
9
+ import { enableCategoryDisplay, loadCategoriesFromViewport } from "../../common/CategoriesVisibilityUtils.js";
10
10
  import { reduceWhile, toVoidPromise } from "../../common/Rxjs.js";
11
11
  import { createVisibilityStatus } from "../../common/Tooltip.js";
12
12
  import { createVisibilityHandlerResult } from "../../common/UseHierarchyVisibility.js";
13
- import { releaseMainThreadOnItemsCount } from "../Utils.js";
13
+ import { getIdsFromChildrenTree, releaseMainThreadOnItemsCount } from "../Utils.js";
14
14
  import { AlwaysAndNeverDrawnElementInfo } from "./AlwaysAndNeverDrawnElementInfo.js";
15
15
  import { createFilteredTree, parseCategoryKey } from "./FilteredTree.js";
16
16
  import { ModelsTreeNode } from "./ModelsTreeNode.js";
@@ -23,49 +23,49 @@ export function createModelsTreeVisibilityHandler(props) {
23
23
  return new ModelsTreeVisibilityHandlerImpl(props);
24
24
  }
25
25
  class ModelsTreeVisibilityHandlerImpl {
26
- _props;
27
- _eventListener;
28
- _alwaysAndNeverDrawnElements;
29
- _idsCache;
30
- _filteredTree;
31
- _elementChangeQueue = new Subject();
32
- _subscriptions = [];
33
- _changeRequest = new Subject();
34
- constructor(_props) {
35
- this._props = _props;
36
- this._eventListener = createVisibilityChangeEventListener(_props.viewport);
37
- this._alwaysAndNeverDrawnElements = new AlwaysAndNeverDrawnElementInfo(_props.viewport);
38
- this._idsCache = this._props.idsCache;
39
- this._filteredTree = _props.filteredPaths ? createFilteredTree(this._props.imodelAccess, _props.filteredPaths) : undefined;
40
- this._subscriptions.push(this._elementChangeQueue.pipe(concatAll()).subscribe());
26
+ #eventListener;
27
+ #alwaysAndNeverDrawnElements;
28
+ #idsCache;
29
+ #filteredTree;
30
+ #elementChangeQueue = new Subject();
31
+ #subscriptions = [];
32
+ #changeRequest = new Subject();
33
+ #props;
34
+ constructor(props) {
35
+ this.#props = props;
36
+ this.#eventListener = createVisibilityChangeEventListener(this.#props.viewport);
37
+ this.#alwaysAndNeverDrawnElements = new AlwaysAndNeverDrawnElementInfo(this.#props.viewport, this.#props.componentId);
38
+ this.#idsCache = this.#props.idsCache;
39
+ this.#filteredTree = this.#props.filteredPaths ? createFilteredTree(this.#props.imodelAccess, this.#props.filteredPaths) : undefined;
40
+ this.#subscriptions.push(this.#elementChangeQueue.pipe(concatAll()).subscribe());
41
41
  }
42
42
  get onVisibilityChange() {
43
- return this._eventListener.onVisibilityChange;
43
+ return this.#eventListener.onVisibilityChange;
44
44
  }
45
45
  async getVisibilityStatus(node) {
46
46
  return firstValueFrom(this.getVisibilityStatusObs(node).pipe(
47
47
  // unsubscribe from the observable if the change request for this node is received
48
- takeUntil(this._changeRequest.pipe(filter(({ key, depth }) => depth === node.parentKeys.length && HierarchyNodeKey.equals(node.key, key)))),
48
+ takeUntil(this.#changeRequest.pipe(filter(({ key, depth }) => depth === node.parentKeys.length && HierarchyNodeKey.equals(node.key, key)))),
49
49
  // unsubscribe if visibility changes
50
50
  takeUntil(fromEventPattern((handler) => {
51
- this._eventListener.onVisibilityChange.addListener(handler);
51
+ this.#eventListener.onVisibilityChange.addListener(handler);
52
52
  }, (handler) => {
53
- this._eventListener.onVisibilityChange.removeListener(handler);
54
- }))));
53
+ this.#eventListener.onVisibilityChange.removeListener(handler);
54
+ })), defaultIfEmpty(createVisibilityStatus("hidden"))));
55
55
  }
56
56
  async changeVisibility(node, shouldDisplay) {
57
57
  // notify about new change request
58
- this._changeRequest.next({ key: node.key, depth: node.parentKeys.length });
58
+ this.#changeRequest.next({ key: node.key, depth: node.parentKeys.length });
59
59
  const changeObservable = this.changeVisibilityObs(node, shouldDisplay).pipe(
60
60
  // unsubscribe from the observable if the change request for this node is received
61
- takeUntil(this._changeRequest.pipe(filter(({ key, depth }) => depth === node.parentKeys.length && HierarchyNodeKey.equals(node.key, key)))), tap({
61
+ takeUntil(this.#changeRequest.pipe(filter(({ key, depth }) => depth === node.parentKeys.length && HierarchyNodeKey.equals(node.key, key)))), tap({
62
62
  subscribe: () => {
63
- this._eventListener.suppressChangeEvents();
64
- this._alwaysAndNeverDrawnElements.suppressChangeEvents();
63
+ this.#eventListener.suppressChangeEvents();
64
+ this.#alwaysAndNeverDrawnElements.suppressChangeEvents();
65
65
  },
66
66
  finalize: () => {
67
- this._eventListener.resumeChangeEvents();
68
- this._alwaysAndNeverDrawnElements.resumeChangeEvents();
67
+ this.#eventListener.resumeChangeEvents();
68
+ this.#alwaysAndNeverDrawnElements.resumeChangeEvents();
69
69
  },
70
70
  }));
71
71
  return toVoidPromise(changeObservable);
@@ -74,20 +74,23 @@ class ModelsTreeVisibilityHandlerImpl {
74
74
  this[Symbol.dispose]();
75
75
  }
76
76
  [Symbol.dispose]() {
77
- this._eventListener[Symbol.dispose]();
78
- this._alwaysAndNeverDrawnElements[Symbol.dispose]();
79
- this._subscriptions.forEach((x) => x.unsubscribe());
77
+ this.#eventListener[Symbol.dispose]();
78
+ this.#alwaysAndNeverDrawnElements[Symbol.dispose]();
79
+ this.#subscriptions.forEach((x) => x.unsubscribe());
80
80
  }
81
81
  getVisibilityStatusObs(node) {
82
- if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
83
- return this.getFilteredNodeVisibility({ node });
84
- }
85
82
  if (HierarchyNode.isClassGroupingNode(node)) {
83
+ if (node.extendedData?.hasDirectNonFilteredTargets && !node.filtering?.hasFilterTargetAncestor) {
84
+ return this.getFilteredNodeVisibility({ node });
85
+ }
86
86
  return this.getClassGroupingNodeDisplayStatus(node);
87
87
  }
88
88
  if (!HierarchyNode.isInstancesNode(node)) {
89
89
  return of(createVisibilityStatus("disabled"));
90
90
  }
91
+ if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
92
+ return this.getFilteredNodeVisibility({ node });
93
+ }
91
94
  if (ModelsTreeNode.isSubjectNode(node)) {
92
95
  // note: subject nodes may be merged to represent multiple subject instances
93
96
  return this.getSubjectNodeVisibilityStatus({ subjectIds: node.key.instanceKeys.map((key) => key.id) });
@@ -110,13 +113,14 @@ class ModelsTreeVisibilityHandlerImpl {
110
113
  return of(createVisibilityStatus("disabled"));
111
114
  }
112
115
  return this.getElementDisplayStatus({
113
- elementId: node.key.instanceKeys[0].id,
116
+ elementIds: node.key.instanceKeys.map(({ id }) => id),
114
117
  modelId,
115
118
  categoryId,
116
119
  });
117
120
  }
118
121
  getFilteredNodeVisibility(props) {
119
- return from(this.getVisibilityChangeTargets(props)).pipe(mergeMap(({ subjects, models, categories, elements }) => {
122
+ assert(this.#filteredTree !== undefined);
123
+ return from(this.#filteredTree).pipe(map((filteredTree) => filteredTree.getVisibilityChangeTargets(props.node)), mergeMap(({ subjects, models, categories, elements }) => {
120
124
  const observables = new Array();
121
125
  if (subjects?.size) {
122
126
  observables.push(this.getSubjectNodeVisibilityStatus({ subjectIds: [...subjects], ignoreTooltip: true }));
@@ -131,9 +135,13 @@ class ModelsTreeVisibilityHandlerImpl {
131
135
  })));
132
136
  }
133
137
  if (elements?.size) {
134
- observables.push(from(elements).pipe(releaseMainThreadOnItemsCount(50), mergeMap(([categoryKey, elementIds]) => {
138
+ observables.push(from(elements).pipe(releaseMainThreadOnItemsCount(50), mergeMap(([categoryKey, elementsMap]) => {
135
139
  const { modelId, categoryId } = parseCategoryKey(categoryKey);
136
- return from(elementIds).pipe(releaseMainThreadOnItemsCount(1000), mergeMap((elementId) => this.getElementDisplayStatus({ modelId, categoryId, elementId, ignoreTooltip: true })));
140
+ return this.getElementsDisplayStatus({
141
+ elementIds: [...elementsMap.keys()],
142
+ modelId,
143
+ categoryId,
144
+ });
137
145
  })));
138
146
  }
139
147
  return merge(...observables);
@@ -141,49 +149,49 @@ class ModelsTreeVisibilityHandlerImpl {
141
149
  }
142
150
  getSubjectNodeVisibilityStatus({ subjectIds, ignoreTooltip }) {
143
151
  const result = defer(() => {
144
- if (!this._props.viewport.view.isSpatialView()) {
152
+ if (!this.#props.viewport.view.isSpatialView()) {
145
153
  return of(createVisibilityStatus("disabled", getTooltipOptions("modelsTree.subject.nonSpatialView", ignoreTooltip)));
146
154
  }
147
- return from(this._idsCache.getSubjectModelIds(subjectIds)).pipe(mergeMap((modelIds) => this.getModelVisibilityStatus({ modelIds, ignoreTooltip: true })), mergeVisibilityStatuses({
155
+ return from(this.#idsCache.getSubjectModelIds(subjectIds)).pipe(mergeMap((modelIds) => this.getModelVisibilityStatus({ modelIds, ignoreTooltip: true })), mergeVisibilityStatuses({
148
156
  visible: "modelsTree.subject.allModelsVisible",
149
157
  hidden: "modelsTree.subject.allModelsHidden",
150
158
  partial: "modelsTree.subject.someModelsHidden",
151
159
  }, ignoreTooltip));
152
160
  });
153
- return createVisibilityHandlerResult(this, { ids: subjectIds }, result, this._props.overrides?.getSubjectNodeVisibility);
161
+ return createVisibilityHandlerResult(this, { ids: subjectIds }, result, this.#props.overrides?.getSubjectNodeVisibility);
154
162
  }
155
163
  getModelVisibilityStatus({ modelIds, ignoreTooltip }) {
156
164
  const result = defer(() => {
157
- const viewport = this._props.viewport;
165
+ const viewport = this.#props.viewport;
158
166
  if (!viewport.view.isSpatialView()) {
159
167
  return of(createVisibilityStatus("disabled", getTooltipOptions("modelsTree.model.nonSpatialView", ignoreTooltip)));
160
168
  }
161
- return from(modelIds).pipe(distinct(), mergeMap((modelId) => {
169
+ return from(Id64.iterable(modelIds)).pipe(distinct(), mergeMap((modelId) => {
162
170
  if (!viewport.view.viewsModel(modelId)) {
163
- return from(this._idsCache.getModelCategories(modelId)).pipe(mergeMap((categoryIds) => from(this._idsCache.getCategoriesModeledElements(modelId, categoryIds))), this.getSubModeledElementsVisibilityStatus({
171
+ return from(this.#idsCache.getModelCategories(modelId)).pipe(mergeMap((categoryIds) => from(this.#idsCache.getCategoriesModeledElements(modelId, categoryIds))), this.getSubModeledElementsVisibilityStatus({
164
172
  ignoreTooltips: ignoreTooltip,
165
173
  haveSubModel: "yes",
166
174
  tooltips: { visible: undefined, hidden: "modelsTree.model.hiddenThroughModelSelector", partial: "modelsTree.model.someSubModelsVisible" },
167
175
  parentNodeVisibilityStatus: createVisibilityStatus("hidden"),
168
176
  }));
169
177
  }
170
- return from(this._idsCache.getModelCategories(modelId)).pipe(mergeMap((categoryIds) => categoryIds.length === 0 ? of(createVisibilityStatus("visible")) : this.getCategoryDisplayStatus({ modelId, categoryIds, ignoreTooltip: true })), mergeVisibilityStatuses({
178
+ return from(this.#idsCache.getModelCategories(modelId)).pipe(mergeMap((categoryIds) => categoryIds.length === 0 ? of(createVisibilityStatus("visible")) : this.getCategoryDisplayStatus({ modelId, categoryIds, ignoreTooltip: true })), mergeVisibilityStatuses({
171
179
  visible: "modelsTree.model.allCategoriesVisible",
172
180
  partial: "modelsTree.model.someCategoriesHidden",
173
181
  hidden: "modelsTree.model.allCategoriesHidden",
174
182
  }));
175
183
  }), mergeVisibilityStatuses());
176
184
  });
177
- return createVisibilityHandlerResult(this, { ids: modelIds }, result, this._props.overrides?.getModelDisplayStatus);
185
+ return createVisibilityHandlerResult(this, { ids: modelIds }, result, this.#props.overrides?.getModelDisplayStatus);
178
186
  }
179
187
  getDefaultCategoryVisibilityStatus({ modelId, categoryIds, ignoreTooltip, }) {
180
- const viewport = this._props.viewport;
188
+ const viewport = this.#props.viewport;
181
189
  if (!viewport.view.viewsModel(modelId) || Id64.sizeOf(categoryIds) === 0) {
182
190
  return createVisibilityStatus("hidden", getTooltipOptions("modelsTree.category.hiddenThroughModel", ignoreTooltip));
183
191
  }
184
192
  let visibility = "unknown";
185
193
  for (const categoryId of Id64.iterable(categoryIds)) {
186
- const override = this._props.viewport.perModelCategoryVisibility.getOverride(modelId, categoryId);
194
+ const override = this.#props.viewport.perModelCategoryVisibility.getOverride(modelId, categoryId);
187
195
  if (override === PerModelCategoryVisibility.Override.Show) {
188
196
  if (visibility === "hidden") {
189
197
  return createVisibilityStatus("partial");
@@ -212,8 +220,8 @@ class ModelsTreeVisibilityHandlerImpl {
212
220
  }
213
221
  getCategoryDisplayStatus({ ignoreTooltip, ...props }) {
214
222
  const result = defer(() => {
215
- if (!this._props.viewport.view.viewsModel(props.modelId)) {
216
- return from(this._idsCache.getCategoriesModeledElements(props.modelId, props.categoryIds)).pipe(this.getSubModeledElementsVisibilityStatus({
223
+ if (!this.#props.viewport.view.viewsModel(props.modelId)) {
224
+ return from(this.#idsCache.getCategoriesModeledElements(props.modelId, props.categoryIds)).pipe(this.getSubModeledElementsVisibilityStatus({
217
225
  ignoreTooltips: ignoreTooltip,
218
226
  parentNodeVisibilityStatus: createVisibilityStatus("hidden"),
219
227
  tooltips: {
@@ -237,7 +245,7 @@ class ModelsTreeVisibilityHandlerImpl {
237
245
  : this.getDefaultCategoryVisibilityStatus({ modelId: props.modelId, categoryIds: props.categoryIds }),
238
246
  ignoreTooltip,
239
247
  }).pipe(mergeMap((visibilityStatusAlwaysAndNeverDraw) => {
240
- return from(this._idsCache.getCategoriesModeledElements(props.modelId, props.categoryIds)).pipe(this.getSubModeledElementsVisibilityStatus({
248
+ return from(this.#idsCache.getCategoriesModeledElements(props.modelId, props.categoryIds)).pipe(this.getSubModeledElementsVisibilityStatus({
241
249
  tooltips: {
242
250
  visible: undefined,
243
251
  hidden: "modelsTree.category.allElementsAndSubModelsHidden",
@@ -249,14 +257,30 @@ class ModelsTreeVisibilityHandlerImpl {
249
257
  }));
250
258
  }));
251
259
  });
252
- return createVisibilityHandlerResult(this, props, result, this._props.overrides?.getCategoryDisplayStatus);
260
+ return createVisibilityHandlerResult(this, props, result, this.#props.overrides?.getCategoryDisplayStatus);
253
261
  }
254
262
  getClassGroupingNodeDisplayStatus(node) {
255
- const result = defer(() => {
256
- const info = this.getGroupingNodeInfo(node);
257
- const { modelId, categoryId, elementIds } = info;
258
- if (!this._props.viewport.view.viewsModel(modelId)) {
259
- return of([...elementIds]).pipe(this.getSubModeledElementsVisibilityStatus({
263
+ const { elementIds, modelId, categoryId } = this.getGroupingNodeInfo(node);
264
+ const result = this.getElementsDisplayStatus({
265
+ elementIds,
266
+ modelId,
267
+ categoryId,
268
+ });
269
+ return createVisibilityHandlerResult(this, { node }, result, this.#props.overrides?.getElementGroupingNodeDisplayStatus);
270
+ }
271
+ getElementDisplayStatus({ elementIds, modelId, categoryId, }) {
272
+ const result = this.getElementsDisplayStatus({
273
+ elementIds,
274
+ modelId,
275
+ categoryId,
276
+ });
277
+ return createVisibilityHandlerResult(this, { elementId: elementIds[0], modelId, categoryId }, result, this.#props.overrides?.getElementDisplayStatus);
278
+ }
279
+ getElementsDisplayStatus(props) {
280
+ return defer(() => {
281
+ const { modelId, categoryId, elementIds } = props;
282
+ if (!this.#props.viewport.view.viewsModel(modelId)) {
283
+ return of(elementIds).pipe(this.getSubModeledElementsVisibilityStatus({
260
284
  tooltips: {
261
285
  visible: undefined,
262
286
  hidden: undefined,
@@ -279,7 +303,7 @@ class ModelsTreeVisibilityHandlerImpl {
279
303
  noElementsInExclusiveAlwaysDrawnList: "modelsTree.groupingNode.allElementsHidden",
280
304
  },
281
305
  }).pipe(mergeMap((visibilityStatusAlwaysAndNeverDraw) => {
282
- return of([...elementIds]).pipe(this.getSubModeledElementsVisibilityStatus({
306
+ return of(elementIds).pipe(this.getSubModeledElementsVisibilityStatus({
283
307
  tooltips: {
284
308
  visible: undefined,
285
309
  hidden: "modelsTree.groupingNode.allElementsAndSubModelsHidden",
@@ -290,113 +314,58 @@ class ModelsTreeVisibilityHandlerImpl {
290
314
  }));
291
315
  }));
292
316
  });
293
- return createVisibilityHandlerResult(this, { node }, result, this._props.overrides?.getElementGroupingNodeDisplayStatus);
294
317
  }
295
- getElementOverriddenVisibility(elementId, ignoreTooltip) {
296
- const viewport = this._props.viewport;
297
- if (viewport.neverDrawn?.has(elementId)) {
298
- return createVisibilityStatus("hidden", getTooltipOptions("modelsTree.element.hiddenThroughNeverDrawnList", ignoreTooltip));
299
- }
300
- if (viewport.alwaysDrawn?.size) {
301
- if (viewport.alwaysDrawn.has(elementId)) {
302
- return createVisibilityStatus("visible", getTooltipOptions("modelsTree.element.displayedThroughAlwaysDrawnList", ignoreTooltip));
318
+ /** Changes visibility of the items represented by the tree node. */
319
+ changeVisibilityObs(node, on) {
320
+ const changeObs = defer(() => {
321
+ if (HierarchyNode.isClassGroupingNode(node)) {
322
+ if (node.extendedData?.hasDirectNonFilteredTargets && !node.filtering?.hasFilterTargetAncestor) {
323
+ return this.changeFilteredNodeVisibility({ node, on });
324
+ }
325
+ return this.changeElementGroupingNodeState(node, on);
303
326
  }
304
- if (viewport.isAlwaysDrawnExclusive) {
305
- return createVisibilityStatus("hidden", getTooltipOptions("modelsTree.element.hiddenDueToOtherElementsExclusivelyAlwaysDrawn", ignoreTooltip));
327
+ if (!HierarchyNode.isInstancesNode(node)) {
328
+ return EMPTY;
306
329
  }
307
- }
308
- return undefined;
309
- }
310
- getElementVisibility(ignoreTooltip, viewsModel, overriddenVisibility, categoryVisibility, subModelVisibilityStatus) {
311
- if (subModelVisibilityStatus === undefined) {
312
- if (!viewsModel) {
313
- return createVisibilityStatus("hidden", getTooltipOptions("modelsTree.element.hiddenThroughModel", ignoreTooltip));
330
+ if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
331
+ return this.changeFilteredNodeVisibility({ node, on });
314
332
  }
315
- if (overriddenVisibility) {
316
- return overriddenVisibility;
333
+ if (ModelsTreeNode.isSubjectNode(node)) {
334
+ return this.changeSubjectNodeState(node.key.instanceKeys.map((key) => key.id), on);
317
335
  }
318
- return createVisibilityStatus(categoryVisibility.state, getTooltipOptions(categoryVisibility.state === "visible" ? undefined : "modelsTree.element.hiddenThroughCategory", ignoreTooltip));
319
- }
320
- if (subModelVisibilityStatus.state === "partial") {
321
- return createVisibilityStatus("partial", getTooltipOptions("modelsTree.element.someElementsAreHidden", ignoreTooltip));
322
- }
323
- if (subModelVisibilityStatus.state === "visible") {
324
- if (!viewsModel || overriddenVisibility?.state === "hidden" || (categoryVisibility.state === "hidden" && !overriddenVisibility)) {
325
- return createVisibilityStatus("partial", getTooltipOptions("modelsTree.element.partialThroughSubModel", ignoreTooltip));
336
+ if (ModelsTreeNode.isModelNode(node)) {
337
+ return this.changeModelState({ ids: node.key.instanceKeys.map(({ id }) => id), on });
326
338
  }
327
- return createVisibilityStatus("visible", getTooltipOptions(undefined, ignoreTooltip));
328
- }
329
- if (!viewsModel) {
330
- return createVisibilityStatus("hidden", getTooltipOptions("modelsTree.element.hiddenThroughModel", ignoreTooltip));
331
- }
332
- if (overriddenVisibility) {
333
- if (overriddenVisibility.state === "hidden") {
334
- return overriddenVisibility;
339
+ const modelId = ModelsTreeNode.getModelId(node);
340
+ if (!modelId) {
341
+ return EMPTY;
335
342
  }
336
- return createVisibilityStatus("partial", getTooltipOptions("modelsTree.element.partialThroughElement", ignoreTooltip));
337
- }
338
- if (categoryVisibility.state === "visible") {
339
- return createVisibilityStatus("partial", getTooltipOptions("modelsTree.element.partialThroughCategory", ignoreTooltip));
340
- }
341
- return createVisibilityStatus("hidden", getTooltipOptions("modelsTree.element.hiddenThroughCategory", ignoreTooltip));
342
- }
343
- getElementDisplayStatus({ ignoreTooltip, ...props }) {
344
- const result = defer(() => {
345
- const viewport = this._props.viewport;
346
- const { elementId, modelId, categoryId } = props;
347
- const viewsModel = viewport.view.viewsModel(modelId);
348
- const elementStatus = this.getElementOverriddenVisibility(elementId, ignoreTooltip);
349
- return from(this._idsCache.hasSubModel(elementId)).pipe(mergeMap((hasSubModel) => (hasSubModel ? this.getModelVisibilityStatus({ modelIds: [elementId] }) : of(undefined))), map((subModelVisibilityStatus) => this.getElementVisibility(ignoreTooltip, viewsModel, elementStatus,
350
- // Single category will always return "visible" or "hidden"
351
- this.getDefaultCategoryVisibilityStatus({ categoryIds: categoryId, modelId, ignoreTooltip: true }), subModelVisibilityStatus)));
352
- });
353
- return createVisibilityHandlerResult(this, props, result, this._props.overrides?.getElementDisplayStatus);
354
- }
355
- /** Changes visibility of the items represented by the tree node. */
356
- changeVisibilityObs(node, on) {
357
- if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
358
- return this.changeFilteredNodeVisibility({ node, on });
359
- }
360
- if (HierarchyNode.isClassGroupingNode(node)) {
361
- return this.changeElementGroupingNodeState(node, on);
362
- }
363
- if (!HierarchyNode.isInstancesNode(node)) {
364
- return EMPTY;
365
- }
366
- if (ModelsTreeNode.isSubjectNode(node)) {
367
- return this.changeSubjectNodeState(node.key.instanceKeys.map((key) => key.id), on);
368
- }
369
- if (ModelsTreeNode.isModelNode(node)) {
370
- return this.changeModelState({ ids: node.key.instanceKeys.map(({ id }) => id), on });
371
- }
372
- const modelId = ModelsTreeNode.getModelId(node);
373
- if (!modelId) {
374
- return EMPTY;
375
- }
376
- if (ModelsTreeNode.isCategoryNode(node)) {
377
- return this.changeCategoryState({
378
- categoryIds: node.key.instanceKeys.map(({ id }) => id),
343
+ if (ModelsTreeNode.isCategoryNode(node)) {
344
+ return this.changeCategoryState({
345
+ categoryIds: node.key.instanceKeys.map(({ id }) => id),
346
+ modelId,
347
+ on,
348
+ });
349
+ }
350
+ const categoryId = ModelsTreeNode.getCategoryId(node);
351
+ if (!categoryId) {
352
+ return EMPTY;
353
+ }
354
+ return this.changeElementsState({
355
+ elementIds: new Set([...node.key.instanceKeys.map(({ id }) => id)]),
379
356
  modelId,
357
+ categoryId,
380
358
  on,
381
359
  });
382
- }
383
- const categoryId = ModelsTreeNode.getCategoryId(node);
384
- if (!categoryId) {
385
- return EMPTY;
386
- }
387
- return this.changeElementsState({
388
- elementIds: new Set([...node.key.instanceKeys.map(({ id }) => id)]),
389
- modelId,
390
- categoryId,
391
- on,
392
360
  });
393
- }
394
- async getVisibilityChangeTargets({ node }) {
395
- const filteredTree = await this._filteredTree;
396
- return filteredTree ? filteredTree.getVisibilityChangeTargets(node) : {};
361
+ if (this.#props.viewport.isAlwaysDrawnExclusive) {
362
+ return concat(this.removeAlwaysDrawnExclusive(), changeObs);
363
+ }
364
+ return changeObs;
397
365
  }
398
366
  changeFilteredNodeVisibility({ on, ...props }) {
399
- return from(this.getVisibilityChangeTargets(props)).pipe(mergeMap(({ subjects, models, categories, elements }) => {
367
+ assert(this.#filteredTree !== undefined);
368
+ return from(this.#filteredTree).pipe(map((filteredTree) => filteredTree.getVisibilityChangeTargets(props.node)), mergeMap(({ subjects, models, categories, elements }) => {
400
369
  const observables = new Array();
401
370
  if (subjects?.size) {
402
371
  observables.push(this.changeSubjectNodeState([...subjects], on));
@@ -411,22 +380,30 @@ class ModelsTreeVisibilityHandlerImpl {
411
380
  })));
412
381
  }
413
382
  if (elements?.size) {
414
- observables.push(from(elements).pipe(mergeMap(([categoryKey, elementIds]) => {
383
+ observables.push(from(elements).pipe(mergeMap(([categoryKey, elementsMap]) => {
415
384
  const { modelId, categoryId } = parseCategoryKey(categoryKey);
416
- return this.changeElementsState({ modelId, categoryId, elementIds, on });
385
+ return this.changeElementsState({ modelId, categoryId, elementIds: new Set([...elementsMap.keys()]), on });
417
386
  })));
418
387
  }
419
388
  return merge(...observables);
420
389
  }));
421
390
  }
391
+ removeAlwaysDrawnExclusive() {
392
+ return from(this.#idsCache.getAllCategories()).pipe(map((categoryIds) => {
393
+ this.#props.viewport.changeCategoryDisplay(categoryIds, false, false);
394
+ this.#props.viewport.clearNeverDrawn();
395
+ this.#props.viewport.perModelCategoryVisibility.clearOverrides();
396
+ this.#props.viewport.setAlwaysDrawn(this.#props.viewport.alwaysDrawn ?? new Set());
397
+ }));
398
+ }
422
399
  changeSubjectNodeState(ids, on) {
423
400
  const result = defer(() => {
424
- if (!this._props.viewport.view.isSpatialView()) {
401
+ if (!this.#props.viewport.view.isSpatialView()) {
425
402
  return EMPTY;
426
403
  }
427
- return from(this._idsCache.getSubjectModelIds(ids)).pipe(mergeMap((modelIds) => this.changeModelState({ ids: modelIds, on })));
404
+ return from(this.#idsCache.getSubjectModelIds(ids)).pipe(mergeMap((modelIds) => this.changeModelState({ ids: modelIds, on })));
428
405
  });
429
- return createVisibilityHandlerResult(this, { ids, on }, result, this._props.overrides?.changeSubjectNodeState);
406
+ return createVisibilityHandlerResult(this, { ids, on }, result, this.#props.overrides?.changeSubjectNodeState);
430
407
  }
431
408
  changeModelState(props) {
432
409
  const { ids, on } = props;
@@ -434,31 +411,31 @@ class ModelsTreeVisibilityHandlerImpl {
434
411
  return EMPTY;
435
412
  }
436
413
  const result = defer(() => {
437
- const viewport = this._props.viewport;
414
+ const viewport = this.#props.viewport;
438
415
  if (!viewport.view.isSpatialView()) {
439
416
  return EMPTY;
440
417
  }
441
418
  const idsObs = from(Id64.iterable(ids));
442
419
  if (!on) {
443
420
  viewport.changeModelDisplay(ids, false);
444
- return idsObs.pipe(mergeMap(async (modelId) => ({ modelId, categoryIds: await this._idsCache.getModelCategories(modelId) })), mergeMap(({ modelId, categoryIds }) => from(this._idsCache.getCategoriesModeledElements(modelId, categoryIds))), mergeMap((modeledElementIds) => this.changeModelState({ ids: modeledElementIds, on })));
421
+ return idsObs.pipe(mergeMap(async (modelId) => ({ modelId, categoryIds: await this.#idsCache.getModelCategories(modelId) })), mergeMap(({ modelId, categoryIds }) => from(this.#idsCache.getCategoriesModeledElements(modelId, categoryIds))), mergeMap((modeledElementIds) => this.changeModelState({ ids: modeledElementIds, on })));
445
422
  }
446
423
  return concat(defer(() => {
447
424
  viewport.perModelCategoryVisibility.clearOverrides(ids);
448
425
  return from(viewport.addViewedModels(ids));
449
426
  }), idsObs.pipe(mergeMap((modelId) => {
450
- return from(this._idsCache.getModelCategories(modelId)).pipe(mergeMap((categoryIds) => this.changeCategoryState({ categoryIds, modelId, on: true })));
427
+ return from(this.#idsCache.getModelCategories(modelId)).pipe(mergeMap((categoryIds) => this.changeCategoryState({ categoryIds, modelId, on: true })));
451
428
  })));
452
429
  });
453
- return createVisibilityHandlerResult(this, props, result, this._props.overrides?.changeModelState);
430
+ return createVisibilityHandlerResult(this, props, result, this.#props.overrides?.changeModelState);
454
431
  }
455
432
  showModelWithoutAnyCategoriesOrElements(modelId) {
456
- const viewport = this._props.viewport;
433
+ const viewport = this.#props.viewport;
457
434
  return forkJoin({
458
- categories: this._idsCache.getModelCategories(modelId),
459
- alwaysDrawnElements: this.getAlwaysDrawnElements({ modelId }),
435
+ categories: this.#idsCache.getModelCategories(modelId),
436
+ alwaysDrawnElements: this.getAlwaysOrNeverDrawnElements({ modelIds: modelId, setType: "always" }),
460
437
  }).pipe(mergeMap(async ({ categories, alwaysDrawnElements }) => {
461
- const alwaysDrawn = this._props.viewport.alwaysDrawn;
438
+ const alwaysDrawn = this.#props.viewport.alwaysDrawn;
462
439
  if (alwaysDrawn && alwaysDrawnElements) {
463
440
  viewport.setAlwaysDrawn(setDifference(alwaysDrawn, alwaysDrawnElements));
464
441
  }
@@ -469,7 +446,7 @@ class ModelsTreeVisibilityHandlerImpl {
469
446
  }));
470
447
  }
471
448
  changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, on) {
472
- const viewport = this._props.viewport;
449
+ const viewport = this.#props.viewport;
473
450
  const isDisplayedInSelector = viewport.view.viewsCategory(categoryId);
474
451
  const override = on === isDisplayedInSelector
475
452
  ? PerModelCategoryVisibility.Override.None
@@ -485,26 +462,26 @@ class ModelsTreeVisibilityHandlerImpl {
485
462
  }
486
463
  changeCategoryState(props) {
487
464
  const result = defer(() => {
488
- const viewport = this._props.viewport;
465
+ const viewport = this.#props.viewport;
489
466
  const { modelId, categoryIds, on } = props;
490
467
  return concat(props.on && !viewport.view.viewsModel(modelId) ? this.showModelWithoutAnyCategoriesOrElements(modelId) : EMPTY, defer(() => {
491
468
  for (const categoryId of Id64.iterable(categoryIds)) {
492
469
  this.changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, on);
493
470
  }
494
471
  return this.clearAlwaysAndNeverDrawnElements(props);
495
- }), from(this._idsCache.getCategoriesModeledElements(modelId, categoryIds)).pipe(mergeMap((modeledElementIds) => this.changeModelState({ ids: modeledElementIds, on }))));
472
+ }), from(this.#idsCache.getCategoriesModeledElements(modelId, categoryIds)).pipe(mergeMap((modeledElementIds) => this.changeModelState({ ids: modeledElementIds, on }))));
496
473
  });
497
- return createVisibilityHandlerResult(this, props, result, this._props.overrides?.changeCategoryState);
474
+ return createVisibilityHandlerResult(this, props, result, this.#props.overrides?.changeCategoryState);
498
475
  }
499
476
  doChangeElementsState(props) {
500
477
  return defer(() => {
501
478
  const { modelId, categoryId, elementIds, on } = props;
502
- const viewport = this._props.viewport;
479
+ const viewport = this.#props.viewport;
503
480
  return concat(on && !viewport.view.viewsModel(modelId) ? this.showModelWithoutAnyCategoriesOrElements(modelId) : EMPTY, defer(() => {
504
481
  const categoryVisibility = this.getDefaultCategoryVisibilityStatus({ categoryIds: categoryId, modelId, ignoreTooltip: true });
505
482
  const isDisplayedByDefault = categoryVisibility.state === "visible";
506
483
  return this.queueElementsVisibilityChange(elementIds, on, isDisplayedByDefault);
507
- }), from(elementIds).pipe(mergeMap(async (elementId) => ({ elementId, isSubModel: await this._idsCache.hasSubModel(elementId) })), filter(({ isSubModel }) => isSubModel), map(({ elementId }) => elementId), toArray(), mergeMap((subModelIds) => this.changeModelState({ ids: subModelIds, on }))));
484
+ }), from(elementIds).pipe(mergeMap(async (elementId) => ({ elementId, isSubModel: await this.#idsCache.hasSubModel(elementId) })), filter(({ isSubModel }) => isSubModel), map(({ elementId }) => elementId), toArray(), mergeMap((subModelIds) => this.changeModelState({ ids: subModelIds, on }))));
508
485
  });
509
486
  }
510
487
  /**
@@ -513,7 +490,7 @@ class ModelsTreeVisibilityHandlerImpl {
513
490
  */
514
491
  changeElementGroupingNodeState(node, on) {
515
492
  const result = this.doChangeElementsState({ ...this.getGroupingNodeInfo(node), on });
516
- return createVisibilityHandlerResult(this, { node, on }, result, this._props.overrides?.changeElementGroupingNodeState);
493
+ return createVisibilityHandlerResult(this, { node, on }, result, this.#props.overrides?.changeElementGroupingNodeState);
517
494
  }
518
495
  /**
519
496
  * Updates visibility of an element and all its child elements by adding them to the always/never drawn list.
@@ -521,7 +498,7 @@ class ModelsTreeVisibilityHandlerImpl {
521
498
  */
522
499
  changeElementsState(props) {
523
500
  const result = this.doChangeElementsState(props);
524
- return createVisibilityHandlerResult(this, props, result, this._props.overrides?.changeElementsState);
501
+ return createVisibilityHandlerResult(this, props, result, this.#props.overrides?.changeElementsState);
525
502
  }
526
503
  queueElementsVisibilityChange(elementIds, on, visibleByDefault) {
527
504
  const finishedSubject = new Subject();
@@ -536,7 +513,7 @@ class ModelsTreeVisibilityHandlerImpl {
536
513
  },
537
514
  }));
538
515
  // queue visibility change. `changeObservable` will be subscribed to when other queue changes are finished
539
- this._elementChangeQueue.next(changeObservable);
516
+ this.#elementChangeQueue.next(changeObservable);
540
517
  // return observable that will emit when visibility change is finished
541
518
  return changeFinished.pipe(take(1), tap({
542
519
  unsubscribe: () => {
@@ -548,11 +525,11 @@ class ModelsTreeVisibilityHandlerImpl {
548
525
  changeElementStateNoChildrenOperator(props) {
549
526
  return (elementIds) => {
550
527
  const { on, isDisplayedByDefault } = props;
551
- const isAlwaysDrawnExclusive = this._props.viewport.isAlwaysDrawnExclusive;
528
+ const isAlwaysDrawnExclusive = this.#props.viewport.isAlwaysDrawnExclusive;
552
529
  return elementIds.pipe(releaseMainThreadOnItemsCount(500), reduce((acc, elementId) => {
553
530
  if (acc.alwaysDrawn === undefined || acc.neverDrawn === undefined) {
554
- acc.alwaysDrawn = new Set(this._props.viewport.alwaysDrawn || []);
555
- acc.neverDrawn = new Set(this._props.viewport.neverDrawn || []);
531
+ acc.alwaysDrawn = new Set(this.#props.viewport.alwaysDrawn || []);
532
+ acc.neverDrawn = new Set(this.#props.viewport.neverDrawn || []);
556
533
  }
557
534
  if (on) {
558
535
  const wasRemoved = acc.neverDrawn.delete(elementId);
@@ -579,8 +556,8 @@ class ModelsTreeVisibilityHandlerImpl {
579
556
  neverDrawn: undefined,
580
557
  alwaysDrawn: undefined,
581
558
  }), map((state) => {
582
- state.changedNeverDrawn && state.neverDrawn && this._props.viewport.setNeverDrawn(state.neverDrawn);
583
- state.changedAlwaysDrawn && state.alwaysDrawn && this._props.viewport.setAlwaysDrawn(state.alwaysDrawn, this._props.viewport.isAlwaysDrawnExclusive);
559
+ state.changedNeverDrawn && state.neverDrawn && this.#props.viewport.setNeverDrawn(state.neverDrawn);
560
+ state.changedAlwaysDrawn && state.alwaysDrawn && this.#props.viewport.setAlwaysDrawn(state.alwaysDrawn, this.#props.viewport.isAlwaysDrawnExclusive);
584
561
  }));
585
562
  };
586
563
  }
@@ -595,7 +572,7 @@ class ModelsTreeVisibilityHandlerImpl {
595
572
  if (alwaysDrawn?.size === totalCount) {
596
573
  return createVisibilityStatus("visible", getTooltipOptions(props.tooltips.allElementsInAlwaysDrawnList, ignoreTooltip));
597
574
  }
598
- const viewport = this._props.viewport;
575
+ const viewport = this.#props.viewport;
599
576
  if (viewport.isAlwaysDrawnExclusive && viewport.alwaysDrawn?.size) {
600
577
  return alwaysDrawn?.size
601
578
  ? createVisibilityStatus("partial", getTooltipOptions(props.tooltips.elementsInBothAlwaysAndNeverDrawn, ignoreTooltip))
@@ -608,7 +585,7 @@ class ModelsTreeVisibilityHandlerImpl {
608
585
  return status;
609
586
  }
610
587
  getVisibilityFromAlwaysAndNeverDrawnElements({ ignoreTooltip, ...props }) {
611
- const viewport = this._props.viewport;
588
+ const viewport = this.#props.viewport;
612
589
  if (viewport.isAlwaysDrawnExclusive) {
613
590
  if (!viewport?.alwaysDrawn?.size) {
614
591
  return of(createVisibilityStatus("hidden", getTooltipOptions(props.tooltips.noElementsInExclusiveAlwaysDrawnList, ignoreTooltip)));
@@ -622,17 +599,17 @@ class ModelsTreeVisibilityHandlerImpl {
622
599
  ...props,
623
600
  alwaysDrawn: viewport.alwaysDrawn?.size ? setIntersection(props.elements, viewport.alwaysDrawn) : undefined,
624
601
  neverDrawn: viewport.neverDrawn?.size ? setIntersection(props.elements, viewport.neverDrawn) : undefined,
625
- totalCount: props.elements.size,
602
+ totalCount: Id64.sizeOf(props.elements),
626
603
  ignoreTooltip,
627
604
  }));
628
605
  }
629
606
  const { modelId, categoryIds } = props.categoryProps;
630
607
  return from(Id64.iterable(categoryIds)).pipe(mergeMap((categoryId) => {
631
- const totalCount = this._idsCache.getCategoryElementsCount(modelId, categoryId);
608
+ const totalCount = this.#idsCache.getCategoryElementsCount(modelId, categoryId);
632
609
  return forkJoin({
633
610
  totalCount,
634
- alwaysDrawn: this.getAlwaysDrawnElements({ categoryIds: categoryId, modelId }),
635
- neverDrawn: this.getNeverDrawnElements({ categoryIds: categoryId, modelId }),
611
+ alwaysDrawn: this.getAlwaysOrNeverDrawnElements({ modelIds: modelId, categoryIds: categoryId, setType: "always" }),
612
+ neverDrawn: this.getAlwaysOrNeverDrawnElements({ modelIds: modelId, categoryIds: categoryId, setType: "never" }),
636
613
  }).pipe(
637
614
  // There is a known bug:
638
615
  // Categories that don't have root elements will make visibility result incorrect
@@ -652,18 +629,17 @@ class ModelsTreeVisibilityHandlerImpl {
652
629
  }));
653
630
  }), mergeVisibilityStatuses());
654
631
  }
655
- getAlwaysDrawnElements(props) {
656
- return this._alwaysAndNeverDrawnElements.getElements({ modelId: props.modelId, categoryIds: props.categoryIds, setType: "always" });
657
- }
658
- getNeverDrawnElements(props) {
659
- return this._alwaysAndNeverDrawnElements.getElements({ modelId: props.modelId, categoryIds: props.categoryIds, setType: "never" });
632
+ getAlwaysOrNeverDrawnElements(props) {
633
+ return this.#alwaysAndNeverDrawnElements
634
+ .getElementsTree(props)
635
+ .pipe(map((childrenTree) => getIdsFromChildrenTree({ tree: childrenTree, predicate: ({ treeEntry }) => treeEntry.isInAlwaysOrNeverDrawnSet })));
660
636
  }
661
637
  clearAlwaysAndNeverDrawnElements(props) {
662
638
  return forkJoin({
663
- alwaysDrawn: this.getAlwaysDrawnElements(props),
664
- neverDrawn: this.getNeverDrawnElements(props),
639
+ alwaysDrawn: this.getAlwaysOrNeverDrawnElements({ modelIds: props.modelId, categoryIds: props.categoryIds, setType: "always" }),
640
+ neverDrawn: this.getAlwaysOrNeverDrawnElements({ modelIds: props.modelId, categoryIds: props.categoryIds, setType: "never" }),
665
641
  }).pipe(map(({ alwaysDrawn, neverDrawn }) => {
666
- const viewport = this._props.viewport;
642
+ const viewport = this.#props.viewport;
667
643
  if (viewport.alwaysDrawn?.size && alwaysDrawn.size) {
668
644
  viewport.setAlwaysDrawn(setDifference(viewport.alwaysDrawn, alwaysDrawn));
669
645
  }
@@ -687,11 +663,11 @@ class ModelsTreeVisibilityHandlerImpl {
687
663
  if (haveSubModel === "yes") {
688
664
  return of(modeledElementIds);
689
665
  }
690
- return from(modeledElementIds).pipe(mergeMap(async (elementId) => ({ elementId, hasSubModel: await this._idsCache.hasSubModel(elementId) })), filter(({ hasSubModel }) => hasSubModel), map(({ elementId }) => elementId), toArray());
666
+ return from(Id64.iterable(modeledElementIds)).pipe(mergeMap(async (elementId) => ({ elementId, hasSubModel: await this.#idsCache.hasSubModel(elementId) })), filter(({ hasSubModel }) => hasSubModel), map(({ elementId }) => elementId), toArray());
691
667
  }),
692
668
  // combine visibility status of sub-models with visibility status of parent node
693
669
  mergeMap((modeledElementIds) => {
694
- if (modeledElementIds.length === 0) {
670
+ if (Id64.sizeOf(modeledElementIds) === 0) {
695
671
  return of(parentNodeVisibilityStatus);
696
672
  }
697
673
  return this.getModelVisibilityStatus({ modelIds: modeledElementIds }).pipe(startWith(parentNodeVisibilityStatus), mergeVisibilityStatuses(tooltips, ignoreTooltips));
@@ -723,24 +699,40 @@ function mergeVisibilityStatuses(tooltipMap, ignoreTooltip) {
723
699
  }
724
700
  function setDifference(lhs, rhs) {
725
701
  const result = new Set();
726
- lhs.forEach((x) => !rhs.has(x) && result.add(x));
702
+ for (const x of lhs) {
703
+ if (!rhs.has(x)) {
704
+ result.add(x);
705
+ }
706
+ }
727
707
  return result;
728
708
  }
729
709
  function setIntersection(lhs, rhs) {
730
710
  const result = new Set();
731
- lhs.forEach((x) => rhs.has(x) && result.add(x));
711
+ for (const x of lhs) {
712
+ if (rhs.has(x)) {
713
+ result.add(x);
714
+ }
715
+ }
732
716
  return result;
733
717
  }
734
718
  /**
735
719
  * Enables display of all given models. Also enables display of all categories and clears always and
736
720
  * never drawn lists in the viewport.
721
+ *
722
+ * @param componentId Optional unique id of the component that consumes this function.
723
+ * It can be any string, as long as it is not shared across different components.
737
724
  * @public
738
725
  */
739
- export async function showAllModels(models, viewport) {
726
+ export async function showAllModels(models, viewport, componentId) {
740
727
  await viewport.addViewedModels(models);
741
728
  viewport.clearNeverDrawn();
742
729
  viewport.clearAlwaysDrawn();
743
- await toggleAllCategories(viewport, true);
730
+ const categories = await loadCategoriesFromViewport(viewport, componentId);
731
+ if (categories.length === 0) {
732
+ return;
733
+ }
734
+ const ids = categories.map((category) => category.categoryId);
735
+ await enableCategoryDisplay(viewport, ids, true);
744
736
  }
745
737
  /**
746
738
  * Disables display of all given models.