@itwin/tree-widget-react 4.0.0-alpha.13 → 4.0.0-alpha.15

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 (121) hide show
  1. package/CHANGELOG.md +62 -1
  2. package/README.md +50 -2
  3. package/lib/esm/tree-widget-react/components/TreeWidgetUiItemsProvider.js.map +1 -1
  4. package/lib/esm/tree-widget-react/components/tree-header/WidgetHeader.css +1 -1
  5. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.d.ts +2 -2
  6. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js +2 -2
  7. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTree.js.map +1 -1
  8. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.d.ts +1 -1
  9. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeComponent.js.map +1 -1
  10. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.d.ts +1 -0
  11. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +25 -19
  12. package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
  13. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js +3 -5
  14. package/lib/esm/tree-widget-react/components/trees/categories-tree/UseCategoriesTree.js.map +1 -1
  15. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +7 -7
  16. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +21 -17
  17. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
  18. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeVisibilityHandler.d.ts +0 -2
  19. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeVisibilityHandler.js +352 -311
  20. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeVisibilityHandler.js.map +1 -1
  21. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/UseFilteredPaths.js +4 -3
  22. package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/UseFilteredPaths.js.map +1 -1
  23. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTree.d.ts +2 -2
  24. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTree.js +4 -3
  25. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTree.js.map +1 -1
  26. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeComponent.d.ts +1 -1
  27. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeComponent.js +2 -2
  28. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeComponent.js.map +1 -1
  29. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeDefinition.d.ts +10 -1
  30. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeDefinition.js +268 -0
  31. package/lib/esm/tree-widget-react/components/trees/classifications-tree/ClassificationsTreeDefinition.js.map +1 -1
  32. package/lib/esm/tree-widget-react/components/trees/classifications-tree/UseClassificationsTree.d.ts +3 -2
  33. package/lib/esm/tree-widget-react/components/trees/classifications-tree/UseClassificationsTree.js +46 -8
  34. package/lib/esm/tree-widget-react/components/trees/classifications-tree/UseClassificationsTree.js.map +1 -1
  35. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeIdsCache.d.ts +20 -7
  36. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeIdsCache.js +96 -20
  37. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeIdsCache.js.map +1 -1
  38. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeNode.d.ts +2 -2
  39. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeNode.js.map +1 -1
  40. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeVisibilityHandler.d.ts +3 -1
  41. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeVisibilityHandler.js +410 -253
  42. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/ClassificationsTreeVisibilityHandler.js.map +1 -1
  43. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/FilteredTree.d.ts +37 -0
  44. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/FilteredTree.js +193 -0
  45. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/FilteredTree.js.map +1 -0
  46. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/UseFilteredPaths.d.ts +18 -0
  47. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/UseFilteredPaths.js +51 -0
  48. package/lib/esm/tree-widget-react/components/trees/classifications-tree/internal/UseFilteredPaths.js.map +1 -0
  49. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.d.ts +4 -0
  50. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +20 -17
  51. package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
  52. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyVisibility.d.ts +2 -2
  53. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyVisibility.js +1 -1
  54. package/lib/esm/tree-widget-react/components/trees/common/UseHierarchyVisibility.js.map +1 -1
  55. package/lib/esm/tree-widget-react/components/trees/common/Utils.d.ts +4 -0
  56. package/lib/esm/tree-widget-react/components/trees/common/Utils.js +49 -0
  57. package/lib/esm/tree-widget-react/components/trees/common/Utils.js.map +1 -1
  58. package/lib/esm/tree-widget-react/components/trees/common/components/BaseTreeRenderer.d.ts +1 -1
  59. package/lib/esm/tree-widget-react/components/trees/common/components/BaseTreeRenderer.js +2 -2
  60. package/lib/esm/tree-widget-react/components/trees/common/components/BaseTreeRenderer.js.map +1 -1
  61. package/lib/esm/tree-widget-react/components/trees/common/components/EmptyTree.d.ts +6 -0
  62. package/lib/esm/tree-widget-react/components/trees/common/components/EmptyTree.js +4 -0
  63. package/lib/esm/tree-widget-react/components/trees/common/components/EmptyTree.js.map +1 -1
  64. package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeVisibilityButton.d.ts +23 -3
  65. package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeVisibilityButton.js +26 -5
  66. package/lib/esm/tree-widget-react/components/trees/common/components/TreeNodeVisibilityButton.js.map +1 -1
  67. package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.d.ts +1 -1
  68. package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.js +7 -8
  69. package/lib/esm/tree-widget-react/components/trees/common/components/TreeRenderer.js.map +1 -1
  70. package/lib/esm/tree-widget-react/components/trees/common/components/UseVisibilityButtonHandler.d.ts +3 -3
  71. package/lib/esm/tree-widget-react/components/trees/common/components/UseVisibilityButtonHandler.js.map +1 -1
  72. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.d.ts +2 -2
  73. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTree.js.map +1 -1
  74. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.d.ts +3 -3
  75. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.js +10 -9
  76. package/lib/esm/tree-widget-react/components/trees/common/components/VisibilityTreeRenderer.js.map +1 -1
  77. package/lib/esm/tree-widget-react/components/trees/common/internal/ModelCategoryElementsCountCache.js +49 -34
  78. package/lib/esm/tree-widget-react/components/trees/common/internal/ModelCategoryElementsCountCache.js.map +1 -1
  79. package/lib/esm/tree-widget-react/components/trees/common/internal/UseIModelAccess.js.map +1 -1
  80. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.d.ts +7 -17
  81. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js +26 -16
  82. package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js.map +1 -1
  83. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityUtils.d.ts +5 -5
  84. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityUtils.js +3 -2
  85. package/lib/esm/tree-widget-react/components/trees/common/internal/VisibilityUtils.js.map +1 -1
  86. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.d.ts +2 -2
  87. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js +2 -2
  88. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTree.js.map +1 -1
  89. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeComponent.d.ts +1 -1
  90. package/lib/esm/tree-widget-react/components/trees/external-sources-tree/ExternalSourcesTreeComponent.js.map +1 -1
  91. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.d.ts +2 -2
  92. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js +2 -2
  93. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTree.js.map +1 -1
  94. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeComponent.d.ts +1 -1
  95. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeComponent.js +1 -1
  96. package/lib/esm/tree-widget-react/components/trees/imodel-content-tree/IModelContentTreeComponent.js.map +1 -1
  97. package/lib/esm/tree-widget-react/components/trees/index.d.ts +2 -0
  98. package/lib/esm/tree-widget-react/components/trees/index.js +3 -0
  99. package/lib/esm/tree-widget-react/components/trees/index.js.map +1 -1
  100. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.d.ts +2 -2
  101. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.js +3 -2
  102. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTree.js.map +1 -1
  103. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.d.ts +1 -1
  104. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeComponent.js.map +1 -1
  105. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +12 -10
  106. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +33 -29
  107. package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
  108. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.d.ts +19 -1
  109. package/lib/esm/tree-widget-react/components/trees/models-tree/UseModelsTree.js +12 -5
  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/internal/ModelsTreeIdsCache.d.ts +6 -4
  112. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +24 -11
  113. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
  114. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.d.ts +35 -44
  115. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +373 -186
  116. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
  117. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/UseFilteredPaths.d.ts +11 -2
  118. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/UseFilteredPaths.js +88 -34
  119. package/lib/esm/tree-widget-react/components/trees/models-tree/internal/UseFilteredPaths.js.map +1 -1
  120. package/lib/public/locales/en/TreeWidget.json +11 -1
  121. package/package.json +12 -12
@@ -2,18 +2,19 @@
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, defaultIfEmpty, defer, distinct, EMPTY, filter, firstValueFrom, forkJoin, from, fromEventPattern, map, merge, mergeAll, mergeMap, of, reduce, shareReplay, startWith, Subject, take, takeUntil, tap, toArray, } from "rxjs";
5
+ import { concat, concatAll, defaultIfEmpty, defer, 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
9
  import { AlwaysAndNeverDrawnElementInfo } from "../../common/internal/AlwaysAndNeverDrawnElementInfo.js";
10
10
  import { toVoidPromise } from "../../common/internal/Rxjs.js";
11
11
  import { createVisibilityStatus } from "../../common/internal/Tooltip.js";
12
- import { setDifference, setIntersection } from "../../common/internal/Utils.js";
12
+ import { getSetFromId64Arg, releaseMainThreadOnItemsCount, setDifference, setIntersection } from "../../common/internal/Utils.js";
13
13
  import { createVisibilityChangeEventListener } from "../../common/internal/VisibilityChangeEventListener.js";
14
- import { changeElementStateNoChildrenOperator, enableCategoryDisplay, getElementOverriddenVisibility, getElementVisibility, getSubModeledElementsVisibilityStatus, getVisibilityFromAlwaysAndNeverDrawnElementsImpl, mergeVisibilityStatuses, } from "../../common/internal/VisibilityUtils.js";
14
+ import { changeElementStateNoChildrenOperator, enableCategoryDisplay, getVisibilityFromAlwaysAndNeverDrawnElementsImpl, mergeVisibilityStatuses, } from "../../common/internal/VisibilityUtils.js";
15
15
  import { createVisibilityHandlerResult } from "../../common/UseHierarchyVisibility.js";
16
16
  import { ClassificationsTreeNode } from "./ClassificationsTreeNode.js";
17
+ import { createFilteredTree } from "./FilteredTree.js";
17
18
  /**
18
19
  * Creates an instance if `ClassificationsTreeVisibilityHandler`.
19
20
  * @internal
@@ -26,6 +27,7 @@ class ClassificationsTreeVisibilityHandlerImpl {
26
27
  _eventListener;
27
28
  _alwaysAndNeverDrawnElements;
28
29
  _idsCache;
30
+ _filteredTree;
29
31
  _elementChangeQueue = new Subject();
30
32
  _subscriptions = [];
31
33
  _changeRequest = new Subject();
@@ -41,6 +43,13 @@ class ClassificationsTreeVisibilityHandlerImpl {
41
43
  });
42
44
  this._alwaysAndNeverDrawnElements = new AlwaysAndNeverDrawnElementInfo(_props.viewport);
43
45
  this._idsCache = this._props.idsCache;
46
+ if (_props.filteredPaths) {
47
+ this._filteredTree = createFilteredTree({
48
+ idsCache: this._idsCache,
49
+ filteringPaths: _props.filteredPaths,
50
+ imodelAccess: this._props.imodelAccess,
51
+ });
52
+ }
44
53
  this._subscriptions.push(this._elementChangeQueue.pipe(concatAll()).subscribe());
45
54
  }
46
55
  [Symbol.dispose]() {
@@ -80,306 +89,341 @@ class ClassificationsTreeVisibilityHandlerImpl {
80
89
  return toVoidPromise(changeObservable);
81
90
  }
82
91
  getVisibilityStatusObs(node) {
92
+ if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
93
+ return this.getFilteredNodeVisibility({ node });
94
+ }
83
95
  if (!HierarchyNode.isInstancesNode(node)) {
84
96
  return EMPTY;
85
97
  }
86
98
  if (ClassificationsTreeNode.isClassificationTableNode(node)) {
87
- return this.getClassificationTableDisplayStatus({
99
+ return this.getClassificationTablesVisibilityStatus({
88
100
  classificationTableIds: node.key.instanceKeys.map((instanceKey) => instanceKey.id),
89
101
  });
90
102
  }
91
103
  if (ClassificationsTreeNode.isClassificationNode(node)) {
92
- return this.getClassificationDisplayStatus({
104
+ return this.getClassificationsVisibilityStatus({
93
105
  classificationIds: node.key.instanceKeys.map((instanceKey) => instanceKey.id),
94
106
  });
95
107
  }
96
- return this.getGeometricElementDisplayStatus({
97
- elementId: (() => {
98
- assert(node.key.instanceKeys.length === 1);
99
- return node.key.instanceKeys[0].id;
100
- })(),
108
+ return this.getElementsVisibilityStatus({
109
+ elementIds: node.key.instanceKeys.map((instanceKey) => instanceKey.id),
101
110
  modelId: ClassificationsTreeNode.getModelId(node),
102
111
  categoryId: ClassificationsTreeNode.getCategoryId(node),
103
- elementType: node.extendedData?.type,
112
+ type: node.extendedData?.type,
104
113
  });
105
114
  }
106
- getClassificationTableDisplayStatus(props) {
115
+ getFilteredNodeVisibility(props) {
116
+ return from(this.getVisibilityChangeTargets(props)).pipe(mergeMap(({ classificationIds, classificationTableIds, elements2d, elements3d }) => {
117
+ const observables = new Array();
118
+ if (classificationTableIds?.size) {
119
+ observables.push(this.getClassificationTablesVisibilityStatus({ classificationTableIds }));
120
+ }
121
+ if (classificationIds?.size) {
122
+ observables.push(this.getClassificationsVisibilityStatus({ classificationIds }));
123
+ }
124
+ if (elements2d?.length) {
125
+ observables.push(from(elements2d).pipe(releaseMainThreadOnItemsCount(50), mergeMap(({ modelId, categoryId, elementIds }) => {
126
+ return from(elementIds).pipe(releaseMainThreadOnItemsCount(1000), mergeMap((elementId) => this.getElementsVisibilityStatus({ modelId, categoryId, elementIds: elementId, type: "GeometricElement2d" })));
127
+ })));
128
+ }
129
+ if (elements3d?.length) {
130
+ observables.push(from(elements3d).pipe(releaseMainThreadOnItemsCount(50), mergeMap(({ modelId, categoryId, elementIds }) => {
131
+ return from(elementIds).pipe(releaseMainThreadOnItemsCount(1000), mergeMap((elementId) => this.getElementsVisibilityStatus({ modelId, categoryId, elementIds: elementId, type: "GeometricElement3d" })));
132
+ })));
133
+ }
134
+ return merge(...observables);
135
+ }), mergeVisibilityStatuses);
136
+ }
137
+ async getVisibilityChangeTargets({ node }) {
138
+ const filteredTree = await this._filteredTree;
139
+ return filteredTree ? filteredTree.getVisibilityChangeTargets(node) : {};
140
+ }
141
+ getClassificationTablesVisibilityStatus(props) {
107
142
  const result = defer(() => {
108
- return from(this._idsCache.getAllContainedCategories(props.classificationTableIds)).pipe(mergeMap(({ drawing, spatial }) => merge(of(drawing).pipe(mergeMap((categoryIds) => this.getCategoryDisplayStatus({ categoryIds, type: "DrawingCategory" }))), of(spatial).pipe(mergeMap((categoryIds) => this.getCategoryDisplayStatus({ categoryIds, type: "SpatialCategory" }))))), mergeVisibilityStatuses);
143
+ return from(this._idsCache.getAllContainedCategories(props.classificationTableIds)).pipe(mergeMap(({ drawing, spatial }) => merge(of(drawing).pipe(mergeMap((categoryIds) => this.getCategoriesVisibilityStatus({ modelId: undefined, categoryIds, type: "DrawingCategory" }))), of(spatial).pipe(mergeMap((categoryIds) => this.getCategoriesVisibilityStatus({ modelId: undefined, categoryIds, type: "SpatialCategory" }))))), mergeVisibilityStatuses);
109
144
  });
110
145
  return createVisibilityHandlerResult(this, props, result, undefined);
111
146
  }
112
- getClassificationDisplayStatus(props) {
147
+ getClassificationsVisibilityStatus(props) {
113
148
  const result = defer(() => {
114
- return from(this._idsCache.getAllContainedCategories(props.classificationIds)).pipe(mergeMap(({ drawing, spatial }) => merge(of(drawing).pipe(mergeMap((categoryIds) => this.getCategoryDisplayStatus({ categoryIds, type: "DrawingCategory" }))), of(spatial).pipe(mergeMap((categoryIds) => this.getCategoryDisplayStatus({ categoryIds, type: "SpatialCategory" }))))), mergeVisibilityStatuses);
149
+ return from(this._idsCache.getAllContainedCategories(props.classificationIds)).pipe(mergeMap(({ drawing, spatial }) => merge(of(drawing).pipe(mergeMap((categoryIds) => this.getCategoriesVisibilityStatus({ modelId: undefined, categoryIds, type: "DrawingCategory" }))), of(spatial).pipe(mergeMap((categoryIds) => this.getCategoriesVisibilityStatus({ modelId: undefined, categoryIds, type: "SpatialCategory" }))))), mergeVisibilityStatuses);
115
150
  });
116
151
  return createVisibilityHandlerResult(this, props, result, undefined);
117
152
  }
118
- getModelVisibilityStatus({ modelIds }) {
153
+ getModelsVisibilityStatus({ modelIds }) {
119
154
  const result = defer(() => {
120
- const viewport = this._props.viewport;
121
- return from(modelIds).pipe(distinct(), mergeMap((modelId) => {
122
- if (!viewport.view.viewsModel(modelId)) {
123
- return from(this._idsCache.getModelCategoryIds(modelId)).pipe(mergeMap(({ drawing, spatial }) => merge(drawing, spatial)), toArray(), mergeMap((categoryIds) => from(this._idsCache.getCategoriesModeledElements(modelId, categoryIds))), getSubModeledElementsVisibilityStatus({
124
- parentNodeVisibilityStatus: createVisibilityStatus("hidden"),
125
- getModelVisibilityStatus: (modelProps) => this.getModelVisibilityStatus(modelProps),
155
+ return from(Id64.iterable(modelIds)).pipe(mergeMap((modelId) => {
156
+ // For hidden models we only need to check subModels
157
+ if (!this._props.viewport.view.viewsModel(modelId)) {
158
+ return this.getSubModels({ modelIds: modelId }).pipe(mergeMap(({ subModels }) => {
159
+ if (subModels && Id64.sizeOf(subModels) > 0) {
160
+ return this.getModelsVisibilityStatus({ modelIds: subModels }).pipe(map((subModelsVisibilityStatus) => subModelsVisibilityStatus.state !== "hidden" ? createVisibilityStatus("partial") : createVisibilityStatus("hidden")));
161
+ }
162
+ return of(createVisibilityStatus("hidden"));
126
163
  }));
127
164
  }
128
- return from(this._idsCache.getModelCategoryIds(modelId)).pipe(mergeMap(({ drawing, spatial }) => merge(of(drawing).pipe(mergeMap((categoryIds) => this.getCategoryDisplayStatus({ modelId, categoryIds, type: "DrawingCategory" }))), of(spatial).pipe(mergeMap((categoryIds) => this.getCategoryDisplayStatus({ modelId, categoryIds, type: "SpatialCategory" }))))), mergeVisibilityStatuses);
165
+ // For visible models we need to check all categories
166
+ return this.getCategories({ modelIds: modelId }).pipe(mergeMap(({ drawingCategories, spatialCategories }) => merge(drawingCategories
167
+ ? of(drawingCategories).pipe(mergeMap((categoryIds) => this.getCategoriesVisibilityStatus({ modelId, categoryIds, type: "DrawingCategory" })))
168
+ : EMPTY, spatialCategories
169
+ ? of(spatialCategories).pipe(mergeMap((categoryIds) => this.getCategoriesVisibilityStatus({ modelId, categoryIds, type: "SpatialCategory" })))
170
+ : EMPTY)), defaultIfEmpty(createVisibilityStatus("visible")));
129
171
  }), mergeVisibilityStatuses);
130
172
  });
131
- return createVisibilityHandlerResult(this, { ids: modelIds }, result, undefined);
173
+ return createVisibilityHandlerResult(this, { modelIds }, result, undefined);
132
174
  }
133
- getDefaultModelsCategoryVisibilityStatus({ modelId, categoryIds }) {
134
- const viewport = this._props.viewport;
135
- if (!viewport.view.viewsModel(modelId)) {
136
- return createVisibilityStatus("hidden");
137
- }
138
- let visibleCount = 0;
139
- let hiddenCount = 0;
140
- let visibleThroughCategorySelectorCount = 0;
141
- for (const categoryId of categoryIds) {
142
- if (viewport.view.viewsCategory(categoryId)) {
143
- ++visibleThroughCategorySelectorCount;
144
- }
145
- const override = this._props.viewport.perModelCategoryVisibility.getOverride(modelId, categoryId);
146
- if (override === PerModelCategoryVisibility.Override.Show) {
147
- ++visibleCount;
148
- continue;
175
+ getVisibleModelCategoriesVisibilityStatus({ modelId, categoryIds }) {
176
+ return merge(this.getVisibilityFromAlwaysAndNeverDrawnElements({
177
+ queryProps: { modelId, categoryIds },
178
+ defaultStatus: () => this.getVisibleModelDefaultCategoriesVisibilityStatus({ modelId, categoryIds }),
179
+ }), this.getSubModels({ modelId, categoryIds }).pipe(mergeMap(({ subModels }) => {
180
+ if (subModels && Id64.sizeOf(subModels) > 0) {
181
+ return this.getModelsVisibilityStatus({ modelIds: subModels });
149
182
  }
150
- if (override === PerModelCategoryVisibility.Override.Hide) {
151
- ++hiddenCount;
152
- continue;
183
+ return EMPTY;
184
+ }))).pipe(mergeVisibilityStatuses);
185
+ }
186
+ getVisibileCategorySubCategoriesVisibilityStatus(props) {
187
+ const { subCategoryIds } = props;
188
+ let subCategoryVisiblity = "unknown";
189
+ for (const subCategoryId of Id64.iterable(subCategoryIds)) {
190
+ const isSubCategoryVisible = this._props.viewport.isSubCategoryVisible(subCategoryId);
191
+ if (isSubCategoryVisible && subCategoryVisiblity === "hidden") {
192
+ return createVisibilityStatus("partial");
153
193
  }
154
- if (visibleCount > 0 && hiddenCount > 0) {
194
+ if (!isSubCategoryVisible && subCategoryVisiblity === "visible") {
155
195
  return createVisibilityStatus("partial");
156
196
  }
197
+ subCategoryVisiblity = isSubCategoryVisible ? "visible" : "hidden";
157
198
  }
158
- if (hiddenCount + visibleCount > 0) {
159
- return createVisibilityStatus(hiddenCount > 0 ? "hidden" : "visible");
160
- }
161
- return createVisibilityStatus(visibleThroughCategorySelectorCount > 0 ? "visible" : "hidden");
162
- }
163
- getDefaultCategoryVisibilityStatus({ categoryIds }) {
164
- const result = from(categoryIds).pipe(mergeMap(async (categoryId) => {
165
- let visibility = "unknown";
166
- const categoryModels = [...(await this._idsCache.getCategoriesElementModels([categoryId], true)).values()].flat();
167
- let nonDefaultModelDisplayStatesCount = 0;
168
- for (const modelId of categoryModels) {
169
- if (!this._props.viewport.view.viewsModel(modelId)) {
170
- if (visibility === "visible") {
171
- return createVisibilityStatus("partial");
199
+ // If visibility is unknown, no subCategories were provided,
200
+ // Since category is visible we return visible
201
+ return createVisibilityStatus(subCategoryVisiblity === "unknown" ? "visible" : subCategoryVisiblity);
202
+ }
203
+ getSubCategoriesVisibilityStatus(props) {
204
+ const result = defer(() => {
205
+ return (props.modelId ? of({ id: props.categoryId, models: props.modelId }) : from(this.getModels({ categoryIds: props.categoryId }))).pipe(map(({ models }) => {
206
+ let visibility = "unknown";
207
+ let nonDefaultModelDisplayStatesCount = 0;
208
+ for (const modelId of Id64.iterable(models ?? [])) {
209
+ if (!this._props.viewport.view.viewsModel(modelId)) {
210
+ if (visibility === "visible") {
211
+ return createVisibilityStatus("partial");
212
+ }
213
+ visibility = "hidden";
214
+ ++nonDefaultModelDisplayStatesCount;
215
+ continue;
172
216
  }
173
- visibility = "hidden";
174
- ++nonDefaultModelDisplayStatesCount;
175
- continue;
176
- }
177
- const override = this._props.viewport.perModelCategoryVisibility.getOverride(modelId, categoryId);
178
- if (override === PerModelCategoryVisibility.Override.Show) {
179
- if (visibility === "hidden") {
180
- return createVisibilityStatus("partial");
217
+ const override = this._props.viewport.perModelCategoryVisibility.getOverride(modelId, props.categoryId);
218
+ if (override === PerModelCategoryVisibility.Override.Show) {
219
+ if (visibility === "hidden") {
220
+ return createVisibilityStatus("partial");
221
+ }
222
+ visibility = "visible";
223
+ ++nonDefaultModelDisplayStatesCount;
224
+ continue;
225
+ }
226
+ if (override === PerModelCategoryVisibility.Override.Hide) {
227
+ if (visibility === "visible") {
228
+ return createVisibilityStatus("partial");
229
+ }
230
+ visibility = "hidden";
231
+ ++nonDefaultModelDisplayStatesCount;
232
+ continue;
181
233
  }
182
- visibility = "visible";
183
- ++nonDefaultModelDisplayStatesCount;
184
- continue;
185
234
  }
186
- if (override === PerModelCategoryVisibility.Override.Hide) {
187
- if (visibility === "visible") {
235
+ if (models && Id64.sizeOf(models) > 0 && nonDefaultModelDisplayStatesCount === Id64.sizeOf(models)) {
236
+ assert(visibility === "visible" || visibility === "hidden");
237
+ return createVisibilityStatus(visibility);
238
+ }
239
+ if (!this._props.viewport.view.viewsCategory(props.categoryId)) {
240
+ return createVisibilityStatus(visibility === "visible" ? "partial" : "hidden");
241
+ }
242
+ if (Id64.sizeOf(props.subCategoryIds) === 0) {
243
+ if (visibility === "hidden") {
188
244
  return createVisibilityStatus("partial");
189
245
  }
190
- visibility = "hidden";
191
- ++nonDefaultModelDisplayStatesCount;
192
- continue;
246
+ return createVisibilityStatus("visible");
193
247
  }
248
+ const subCategoriesVisibility = this.getVisibileCategorySubCategoriesVisibilityStatus({ subCategoryIds: props.subCategoryIds });
249
+ return subCategoriesVisibility.state === visibility || visibility === "unknown" ? subCategoriesVisibility : createVisibilityStatus("partial");
250
+ }), mergeVisibilityStatuses);
251
+ });
252
+ return createVisibilityHandlerResult(this, props, result, undefined);
253
+ }
254
+ getVisibleModelDefaultCategoriesVisibilityStatus({ modelId, categoryIds }) {
255
+ const viewport = this._props.viewport;
256
+ let visibleCount = 0;
257
+ for (const categoryId of Id64.iterable(categoryIds)) {
258
+ const override = this._props.viewport.perModelCategoryVisibility.getOverride(modelId, categoryId);
259
+ if (override === PerModelCategoryVisibility.Override.Show ||
260
+ (override === PerModelCategoryVisibility.Override.None && viewport.view.viewsCategory(categoryId))) {
261
+ ++visibleCount;
262
+ continue;
194
263
  }
195
- if (categoryModels.length > 0 && nonDefaultModelDisplayStatesCount === categoryModels.length) {
196
- assert(visibility === "visible" || visibility === "hidden");
197
- return createVisibilityStatus(visibility);
198
- }
199
- if (!this._props.viewport.view.viewsCategory(categoryId)) {
200
- return createVisibilityStatus(visibility === "visible" ? "partial" : "hidden");
201
- }
202
- if (visibility === "hidden") {
264
+ if (visibleCount > 0) {
203
265
  return createVisibilityStatus("partial");
204
266
  }
205
- return createVisibilityStatus("visible");
206
- }), mergeVisibilityStatuses);
207
- return result;
267
+ }
268
+ return visibleCount > 0 ? createVisibilityStatus("visible") : createVisibilityStatus("hidden");
208
269
  }
209
- getCategoryDisplayStatus(props) {
270
+ getCategoriesVisibilityStatus(props) {
210
271
  const result = defer(() => {
211
- if (props.categoryIds.length === 0) {
272
+ const { categoryIds, modelId: modelIdFromProps, type } = props;
273
+ if (Id64.sizeOf(categoryIds) === 0) {
212
274
  return EMPTY;
213
275
  }
214
- const isSupportedInView = (this._props.viewport.view.is3d() && props.type === "SpatialCategory") || (this._props.viewport.view.is2d() && props.type === "DrawingCategory");
276
+ const isSupportedInView = (this._props.viewport.view.is3d() && type === "SpatialCategory") || (this._props.viewport.view.is2d() && type === "DrawingCategory");
215
277
  if (!isSupportedInView) {
216
278
  return of(createVisibilityStatus("disabled"));
217
279
  }
218
- const modelsObservable = props.modelId
219
- ? of(new Map(props.categoryIds.map((id) => [id, [props.modelId]])))
220
- : from(this._idsCache.getCategoriesElementModels(props.categoryIds));
221
- return merge(
222
- // get visibility status from always and never drawn elements
223
- modelsObservable.pipe(mergeMap((categoryModelsMap) => {
224
- if (categoryModelsMap.size === 0) {
225
- return props.modelId
226
- ? of(this.getDefaultModelsCategoryVisibilityStatus({ modelId: props.modelId, categoryIds: props.categoryIds }))
227
- : from(this.getDefaultCategoryVisibilityStatus({ categoryIds: props.categoryIds }));
280
+ return (modelIdFromProps
281
+ ? from(Id64.iterable(categoryIds)).pipe(map((categoryId) => ({ id: categoryId, models: modelIdFromProps })))
282
+ : this.getModels({ categoryIds })).pipe(map(({ id, models }) => {
283
+ const acc = { categoryId: id, visibleModels: new Array(), hiddenModels: new Array() };
284
+ if (!models) {
285
+ return acc;
228
286
  }
229
- return from(categoryModelsMap).pipe(mergeMap(([category, models]) => from(models).pipe(mergeMap((model) => {
230
- if (this._props.viewport.view.viewsModel(model)) {
231
- return this.getVisibilityFromAlwaysAndNeverDrawnElements({
232
- queryProps: props,
233
- defaultStatus: () => this.getDefaultModelsCategoryVisibilityStatus({ modelId: model, categoryIds: [category] }),
234
- }).pipe(mergeMap((visibilityStatusAlwaysAndNeverDraw) => {
235
- return from(this._idsCache.getCategoriesModeledElements(model, [category])).pipe(getSubModeledElementsVisibilityStatus({
236
- parentNodeVisibilityStatus: visibilityStatusAlwaysAndNeverDraw,
237
- getModelVisibilityStatus: (modelProps) => this.getModelVisibilityStatus(modelProps),
238
- }));
239
- }));
287
+ for (const modelId of Id64.iterable(models)) {
288
+ if (this._props.viewport.view.viewsModel(modelId)) {
289
+ acc.visibleModels.push(modelId);
240
290
  }
241
- return from(this._idsCache.getCategoriesModeledElements(model, [category])).pipe(getSubModeledElementsVisibilityStatus({
242
- parentNodeVisibilityStatus: createVisibilityStatus("hidden"),
243
- getModelVisibilityStatus: (modelProps) => this.getModelVisibilityStatus(modelProps),
244
- }));
245
- }))), mergeVisibilityStatuses);
246
- }), map((visibilityStatus) => {
247
- return { visibilityStatus, type: 0 };
248
- })),
249
- // get category status
250
- (props.modelId
251
- ? of(this.getDefaultModelsCategoryVisibilityStatus({ modelId: props.modelId, categoryIds: props.categoryIds }))
252
- : from(this.getDefaultCategoryVisibilityStatus({ categoryIds: props.categoryIds }))).pipe(map((visibilityStatus) => {
253
- return { visibilityStatus, type: 1 };
254
- }))).pipe(toArray(), mergeMap(async (visibilityStatusesInfo) => {
255
- let defaultStatus;
256
- let alwaysNeverDrawStatus;
257
- visibilityStatusesInfo.forEach((visibilityStatusInfo) => {
258
- switch (visibilityStatusInfo.type) {
259
- case 0:
260
- alwaysNeverDrawStatus = visibilityStatusInfo.visibilityStatus;
261
- break;
262
- case 1:
263
- defaultStatus = visibilityStatusInfo.visibilityStatus;
264
- break;
291
+ else {
292
+ acc.hiddenModels.push(modelId);
265
293
  }
266
- });
267
- assert(defaultStatus !== undefined);
268
- if (defaultStatus.state === "partial") {
269
- return defaultStatus;
270
- }
271
- // This can happen if:
272
- // a) showElements is set to false
273
- // b) root category does not have any elements (that dont have Parent)
274
- // In both cases we don't need to look at modeled elements visibility
275
- if (alwaysNeverDrawStatus === undefined) {
276
- return defaultStatus;
277
- }
278
- // In cases where Category has model (it means that category is under hidden subModel)
279
- // We don't need to look at default category status, it is already accounted for in always/never drawn visibility
280
- if (props.modelId) {
281
- return alwaysNeverDrawStatus;
282
294
  }
283
- if (alwaysNeverDrawStatus.state === "partial" || alwaysNeverDrawStatus.state !== defaultStatus.state) {
284
- return createVisibilityStatus("partial");
285
- }
286
- return alwaysNeverDrawStatus;
287
- }));
295
+ return acc;
296
+ }), mergeMap(({ categoryId, visibleModels, hiddenModels }) => {
297
+ return merge(
298
+ // For hidden models we only need to check subModels
299
+ hiddenModels.length > 0
300
+ ? this.getSubModels({ modelIds: hiddenModels }).pipe(mergeMap(({ subModels }) => {
301
+ if (subModels && Id64.sizeOf(subModels) > 0) {
302
+ return this.getModelsVisibilityStatus({
303
+ modelIds: subModels,
304
+ }).pipe(map((subModelsVisibilityStatus) => subModelsVisibilityStatus.state !== "hidden" ? createVisibilityStatus("partial") : createVisibilityStatus("hidden")));
305
+ }
306
+ return of(createVisibilityStatus("hidden"));
307
+ }))
308
+ : EMPTY,
309
+ // For visible models we need to check all categories
310
+ visibleModels.length > 0
311
+ ? from(visibleModels).pipe(mergeMap((modelId) => this.getVisibleModelCategoriesVisibilityStatus({
312
+ modelId,
313
+ categoryIds: categoryId,
314
+ })))
315
+ : EMPTY,
316
+ // We need to check subCategories as well
317
+ this.getSubCategories({ categoryIds: categoryId }).pipe(mergeMap(({ subCategories }) => {
318
+ if (subCategories && Id64.sizeOf(subCategories) > 0) {
319
+ return this.getSubCategoriesVisibilityStatus({ categoryId, modelId: modelIdFromProps, subCategoryIds: subCategories });
320
+ }
321
+ return EMPTY;
322
+ }))).pipe(defaultIfEmpty(createVisibilityStatus(this._props.viewport.view.viewsCategory(categoryId) ? "visible" : "hidden")));
323
+ }), mergeVisibilityStatuses);
288
324
  });
289
325
  return createVisibilityHandlerResult(this, props, result, undefined);
290
326
  }
291
- getVisibilityFromAlwaysAndNeverDrawnElements(props) {
292
- const viewport = this._props.viewport;
293
- if (viewport.isAlwaysDrawnExclusive) {
294
- if (!viewport?.alwaysDrawn?.size) {
295
- return of(createVisibilityStatus("hidden"));
296
- }
297
- }
298
- else if (!viewport?.neverDrawn?.size && !viewport?.alwaysDrawn?.size) {
299
- return of(props.defaultStatus());
300
- }
301
- if ("elements" in props) {
302
- return of(getVisibilityFromAlwaysAndNeverDrawnElementsImpl({
303
- ...props,
304
- alwaysDrawn: viewport.alwaysDrawn?.size ? setIntersection(props.elements, viewport.alwaysDrawn) : undefined,
305
- neverDrawn: viewport.neverDrawn?.size ? setIntersection(props.elements, viewport.neverDrawn) : undefined,
306
- totalCount: props.elements.size,
307
- viewport,
308
- }));
309
- }
310
- const { modelId, categoryIds } = props.queryProps;
311
- const totalCount = (modelId ? of(new Map(categoryIds.map((categoryId) => [categoryId, [modelId]]))) : from(this._idsCache.getCategoriesElementModels(categoryIds))).pipe(mergeMap((categoriesMap) => from(categoriesMap)), mergeMap(([categoryId, modelIds]) => {
312
- return from(modelIds).pipe(mergeMap((modelOfCategory) => from(this._idsCache.getCategoryElementsCount(modelOfCategory, categoryId))), reduce((acc, specificModelCategoryCount) => acc + specificModelCategoryCount, 0));
313
- }));
314
- return forkJoin({
315
- totalCount,
316
- alwaysDrawn: this._alwaysAndNeverDrawnElements.getAlwaysDrawnElements(props.queryProps),
317
- neverDrawn: this._alwaysAndNeverDrawnElements.getNeverDrawnElements(props.queryProps),
318
- }).pipe(map((state) => {
319
- return getVisibilityFromAlwaysAndNeverDrawnElementsImpl({
320
- ...props,
321
- ...state,
322
- viewport,
323
- });
324
- }));
325
- }
326
- getGeometricElementDisplayStatus(props) {
327
+ getElementsVisibilityStatus(props) {
327
328
  const result = defer(() => {
328
- const viewport = this._props.viewport;
329
- const { elementId, modelId, categoryId, elementType } = props;
330
- const isSupportedInView = (viewport.view.is3d() && elementType === "GeometricElement3d") || (viewport.view.is2d() && elementType === "GeometricElement2d");
329
+ const { elementIds, modelId, categoryId, type } = props;
330
+ const isSupportedInView = (this._props.viewport.view.is3d() && type === "GeometricElement3d") || (this._props.viewport.view.is2d() && type === "GeometricElement2d");
331
331
  if (!isSupportedInView) {
332
332
  return of(createVisibilityStatus("disabled"));
333
333
  }
334
- const viewsModel = viewport.view.viewsModel(modelId);
335
- const elementStatus = getElementOverriddenVisibility({
336
- elementId,
337
- viewport,
338
- });
339
- return from(this._idsCache.hasSubModel(elementId)).pipe(mergeMap((hasSubModel) => (hasSubModel ? this.getModelVisibilityStatus({ modelIds: [elementId] }) : of(undefined))), map((subModelVisibilityStatus) => getElementVisibility(viewsModel, elementStatus, this.getDefaultModelsCategoryVisibilityStatus({ categoryIds: [categoryId], modelId }), subModelVisibilityStatus)));
334
+ // TODO: check child elements that are subModels
335
+ if (!this._props.viewport.view.viewsModel(modelId)) {
336
+ return from(elementIds).pipe(mergeMap((elementId) => from(this._idsCache.hasSubModel(elementId)).pipe(mergeMap((isSubModel) => {
337
+ if (isSubModel) {
338
+ return this.getModelsVisibilityStatus({
339
+ modelIds: elementId,
340
+ }).pipe(map((subModelVisibilityStatus) => subModelVisibilityStatus.state !== "hidden" ? createVisibilityStatus("partial") : createVisibilityStatus("hidden")));
341
+ }
342
+ return of(createVisibilityStatus("hidden"));
343
+ }))), mergeVisibilityStatuses);
344
+ }
345
+ // TODO: check child elements
346
+ // TODO: check child element categories
347
+ // TODO: check child elements that are subModels
348
+ return this.getVisibilityFromAlwaysAndNeverDrawnElements({
349
+ elements: elementIds,
350
+ defaultStatus: () => this.getVisibleModelDefaultCategoriesVisibilityStatus({ categoryIds: categoryId, modelId }),
351
+ }).pipe(mergeMap((visibilityStatusAlwaysAndNeverDraw) => {
352
+ return from(Id64.iterable(elementIds)).pipe(mergeMap((elementId) => from(this._idsCache.hasSubModel(elementId)).pipe(mergeMap((isSubModel) => {
353
+ if (isSubModel) {
354
+ return this.getModelsVisibilityStatus({
355
+ modelIds: elementId,
356
+ }).pipe(map((subModelVisibilityStatus) => subModelVisibilityStatus.state !== visibilityStatusAlwaysAndNeverDraw.state
357
+ ? createVisibilityStatus("partial")
358
+ : visibilityStatusAlwaysAndNeverDraw));
359
+ }
360
+ return of(visibilityStatusAlwaysAndNeverDraw);
361
+ }))), mergeVisibilityStatuses);
362
+ }));
340
363
  });
341
364
  return createVisibilityHandlerResult(this, props, result, undefined);
342
365
  }
343
366
  changeVisibilityObs(node, on) {
367
+ if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget) {
368
+ return this.changeFilteredNodeVisibility({ node, on });
369
+ }
344
370
  if (!HierarchyNode.isInstancesNode(node)) {
345
371
  return EMPTY;
346
372
  }
347
373
  if (ClassificationsTreeNode.isClassificationTableNode(node)) {
348
- return this.changeClassificationTableDisplayState({
374
+ return this.changeClassificationTablesVisibilityStatus({
349
375
  classificationTableIds: node.key.instanceKeys.map((instanceKey) => instanceKey.id),
350
376
  on,
351
377
  });
352
378
  }
353
379
  if (ClassificationsTreeNode.isClassificationNode(node)) {
354
- return this.changeClassificationDisplayState({
380
+ return this.changeClassificationsVisibilityStatus({
355
381
  classificationIds: node.key.instanceKeys.map((instanceKey) => instanceKey.id),
356
382
  on,
357
383
  });
358
384
  }
359
- return this.changeGeometricElementsDisplayState({
360
- elementIds: new Set([...node.key.instanceKeys.map(({ id }) => id)]),
385
+ return this.changeElementsVisibilityStatus({
386
+ elementIds: node.key.instanceKeys.map(({ id }) => id),
361
387
  modelId: ClassificationsTreeNode.getModelId(node),
362
388
  categoryId: ClassificationsTreeNode.getCategoryId(node),
363
389
  on,
364
390
  });
365
391
  }
366
- changeClassificationTableDisplayState(props) {
392
+ changeFilteredNodeVisibility({ on, ...props }) {
393
+ return from(this.getVisibilityChangeTargets(props)).pipe(mergeMap(({ classificationTableIds, classificationIds, elements2d, elements3d }) => {
394
+ const observables = new Array();
395
+ if (classificationTableIds?.size) {
396
+ observables.push(this.changeClassificationTablesVisibilityStatus({ classificationTableIds, on }));
397
+ }
398
+ if (classificationIds?.size) {
399
+ observables.push(this.changeClassificationsVisibilityStatus({ classificationIds, on }));
400
+ }
401
+ if (elements2d?.length) {
402
+ observables.push(from(elements2d).pipe(mergeMap(({ modelId, categoryId, elementIds }) => {
403
+ return this.changeElementsVisibilityStatus({ modelId, categoryId, elementIds, on });
404
+ })));
405
+ }
406
+ if (elements3d?.length) {
407
+ observables.push(from(elements3d).pipe(mergeMap(({ modelId, categoryId, elementIds }) => {
408
+ return this.changeElementsVisibilityStatus({ modelId, categoryId, elementIds, on });
409
+ })));
410
+ }
411
+ return merge(...observables);
412
+ }));
413
+ }
414
+ changeClassificationTablesVisibilityStatus(props) {
367
415
  const result = defer(() => {
368
- return from(this._idsCache.getAllContainedCategories(props.classificationTableIds)).pipe(mergeMap(({ drawing, spatial }) => merge(drawing, spatial)), toArray(), mergeMap((categoryIds) => {
369
- return this.changeCategoryDisplayState({ categoryIds, on: props.on });
370
- }));
416
+ return from(this._idsCache.getAllContainedCategories(props.classificationTableIds)).pipe(mergeMap(({ drawing, spatial }) => merge(drawing, spatial)), toArray(), mergeMap((categoryIds) => this.changeCategoriesVisibilityStatus({ modelId: undefined, categoryIds, on: props.on })));
371
417
  });
372
418
  return createVisibilityHandlerResult(this, props, result, undefined);
373
419
  }
374
- changeClassificationDisplayState(props) {
420
+ changeClassificationsVisibilityStatus(props) {
375
421
  const result = defer(() => {
376
- return from(this._idsCache.getAllContainedCategories(props.classificationIds)).pipe(mergeMap(({ drawing, spatial }) => merge(drawing, spatial)), toArray(), mergeMap((categoryIds) => {
377
- return this.changeCategoryDisplayState({ categoryIds, on: props.on });
378
- }));
422
+ return from(this._idsCache.getAllContainedCategories(props.classificationIds)).pipe(mergeMap(({ drawing, spatial }) => merge(drawing, spatial)), toArray(), mergeMap((categoryIds) => this.changeCategoriesVisibilityStatus({ modelId: undefined, categoryIds, on: props.on })));
379
423
  });
380
424
  return createVisibilityHandlerResult(this, props, result, undefined);
381
425
  }
382
- changeModelDisplayState(props) {
426
+ changeModelsVisibilityStatus(props) {
383
427
  const { modelIds, on } = props;
384
428
  if (Id64.sizeOf(modelIds) === 0) {
385
429
  return EMPTY;
@@ -387,37 +431,44 @@ class ClassificationsTreeVisibilityHandlerImpl {
387
431
  const result = defer(() => {
388
432
  const viewport = this._props.viewport;
389
433
  viewport.perModelCategoryVisibility.clearOverrides(modelIds);
390
- const idsObs = from(Id64.iterable(modelIds));
391
434
  if (!on) {
392
435
  viewport.changeModelDisplay(modelIds, false);
393
- return idsObs.pipe(mergeMap(async (modelId) => ({ modelId, categoryIds: await this._idsCache.getModelCategoryIds(modelId) })), mergeMap(({ modelId, categoryIds }) => from(this._idsCache.getCategoriesModeledElements(modelId, [...categoryIds.drawing, ...categoryIds.spatial]))), mergeMap((modeledElementIds) => this.changeModelDisplayState({ modelIds: modeledElementIds, on })));
436
+ return this.getSubModels({ modelIds }).pipe(mergeMap(({ subModels }) => (subModels ? this.changeModelsVisibilityStatus({ modelIds: subModels, on }) : EMPTY)));
394
437
  }
395
- return concat(from(viewport.addViewedModels(modelIds)), idsObs.pipe(mergeMap((modelId) => {
396
- return from(this._idsCache.getModelCategoryIds(modelId)).pipe(mergeMap(({ drawing, spatial }) => merge(drawing, spatial)), mergeMap((categoryId) => this.changeCategoryDisplayState({ categoryIds: [categoryId], modelId, on })));
438
+ return concat(from(viewport.addViewedModels(modelIds)), this.getCategories({ modelIds }).pipe(mergeMap(({ id, drawingCategories, spatialCategories }) => {
439
+ return merge(drawingCategories ? this.changeCategoriesVisibilityStatus({ categoryIds: drawingCategories, modelId: id, on }) : EMPTY, spatialCategories ? this.changeCategoriesVisibilityStatus({ categoryIds: spatialCategories, modelId: id, on }) : EMPTY);
397
440
  })));
398
441
  });
399
442
  return createVisibilityHandlerResult(this, props, result, undefined);
400
443
  }
401
- showModelWithoutAnyCategoriesOrElements(modelId) {
444
+ showModelWithoutAnyCategoriesOrElements(modelId, categoriesToNotOverride) {
402
445
  const viewport = this._props.viewport;
403
446
  return forkJoin({
404
- categories: this._idsCache.getModelCategoryIds(modelId),
405
- alwaysDrawnElements: this._alwaysAndNeverDrawnElements.getAlwaysDrawnElements({ modelId }),
406
- }).pipe(mergeMap(async ({ categories, alwaysDrawnElements }) => {
447
+ allModelCategories: this.getCategories({ modelIds: modelId }).pipe(reduce((acc, { drawingCategories, spatialCategories }) => {
448
+ for (const category of Id64.iterable(drawingCategories ?? [])) {
449
+ acc.add(category);
450
+ }
451
+ for (const category of Id64.iterable(spatialCategories ?? [])) {
452
+ acc.add(category);
453
+ }
454
+ return acc;
455
+ }, new Set())),
456
+ modelAlwaysDrawnElements: this._alwaysAndNeverDrawnElements.getAlwaysDrawnElements({ modelId }),
457
+ }).pipe(mergeMap(async ({ allModelCategories, modelAlwaysDrawnElements }) => {
407
458
  const alwaysDrawn = this._props.viewport.alwaysDrawn;
408
- if (alwaysDrawn && alwaysDrawnElements) {
409
- viewport.setAlwaysDrawn(setDifference(alwaysDrawn, alwaysDrawnElements));
459
+ if (alwaysDrawn && modelAlwaysDrawnElements) {
460
+ viewport.setAlwaysDrawn(setDifference(alwaysDrawn, modelAlwaysDrawnElements));
410
461
  }
411
- categories.drawing.forEach((categoryId) => {
412
- this.changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, false);
413
- });
414
- categories.spatial.forEach((categoryId) => {
415
- this.changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, false);
462
+ const categoriesToOverride = categoriesToNotOverride
463
+ ? setDifference(allModelCategories, getSetFromId64Arg(categoriesToNotOverride))
464
+ : allModelCategories;
465
+ categoriesToOverride.forEach((categoryId) => {
466
+ this.changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, false, false);
416
467
  });
417
468
  await viewport.addViewedModels(modelId);
418
469
  }));
419
470
  }
420
- changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, on) {
471
+ changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, on, changeSubCategories) {
421
472
  const viewport = this._props.viewport;
422
473
  const isDisplayedInSelector = viewport.view.viewsCategory(categoryId);
423
474
  const override = on === isDisplayedInSelector
@@ -429,44 +480,88 @@ class ClassificationsTreeVisibilityHandlerImpl {
429
480
  if (override === PerModelCategoryVisibility.Override.None && on) {
430
481
  // we took off the override which means the category is displayed in selector, but
431
482
  // doesn't mean all its subcategories are displayed - this call ensures that
432
- viewport.changeCategoryDisplay(categoryId, true);
483
+ viewport.changeCategoryDisplay(categoryId, true, changeSubCategories);
433
484
  }
434
485
  }
435
- changeCategoryDisplayState(props) {
486
+ changeCategoriesVisibilityStatus(props) {
436
487
  const result = defer(() => {
437
- const { modelId, categoryIds, on } = props;
488
+ const { modelId: modelIdFromProps, categoryIds, on } = props;
438
489
  const viewport = this._props.viewport;
439
- const modelIdsObservable = modelId
440
- ? of(new Map(categoryIds.map((id) => [id, [modelId]])))
441
- : from(this._idsCache.getCategoriesElementModels(categoryIds, true));
442
- return concat(modelId ? EMPTY : from(enableCategoryDisplay(viewport, categoryIds, on)), on
443
- ? modelIdsObservable.pipe(mergeMap((categoriesMap) => from(categoriesMap.values())), mergeAll(), filter((modelIdToCheck) => !viewport.view.viewsModel(modelIdToCheck)), mergeMap((modelIdToCheck) => this.showModelWithoutAnyCategoriesOrElements(modelIdToCheck)))
444
- : EMPTY, modelIdsObservable.pipe(mergeMap((categoriesMap) => from(categoriesMap.entries())), mergeMap(([categoryId, modelIds]) => {
445
- return from(modelIds).pipe(mergeMap((modelOfCategory) => {
446
- this.changeCategoryStateInViewportAccordingToModelVisibility(modelOfCategory, categoryId, on);
447
- return this._alwaysAndNeverDrawnElements.clearAlwaysAndNeverDrawnElements({ modelId: modelOfCategory, categoryIds: [categoryId] });
448
- }));
449
- })), modelIdsObservable.pipe(mergeMap((categoriesMap) => from(categoriesMap.entries())), mergeMap(([categoryId, modelIds]) => {
450
- return from(modelIds).pipe(mergeMap((modelOfCategory) => from(this._idsCache.getCategoriesModeledElements(modelOfCategory, [categoryId])).pipe(mergeMap((modeledElementIds) => this.changeModelDisplayState({ modelIds: modeledElementIds, on })))));
451
- })));
490
+ const modelIdsObservable = (modelIdFromProps
491
+ ? of(new Map([[modelIdFromProps, getSetFromId64Arg(categoryIds)]]))
492
+ : this.getModels({ categoryIds }).pipe(reduce((acc, { id, models }) => {
493
+ if (!models) {
494
+ return acc;
495
+ }
496
+ for (const modelId of Id64.iterable(models)) {
497
+ let entry = acc.get(modelId);
498
+ if (!entry) {
499
+ entry = new Set();
500
+ acc.set(modelId, entry);
501
+ }
502
+ entry.add(id);
503
+ }
504
+ return acc;
505
+ }, new Map()))).pipe(mergeMap((modelCategoriesMap) => modelCategoriesMap.entries()), shareReplay());
506
+ return concat(
507
+ // If modelId was provided: add override
508
+ // If modelId was not provided: change categoryDisplay and remove categories per model overrides
509
+ modelIdFromProps
510
+ ? of(viewport.perModelCategoryVisibility.setOverride(modelIdFromProps, categoryIds, on ? PerModelCategoryVisibility.Override.Show : PerModelCategoryVisibility.Override.Hide))
511
+ : concat(from(enableCategoryDisplay(viewport, categoryIds, on, on)), modelIdsObservable.pipe(map(([modelId, modelCategories]) => {
512
+ viewport.perModelCategoryVisibility.setOverride(modelId, modelCategories, PerModelCategoryVisibility.Override.None);
513
+ }))),
514
+ // If categories visibility needs to be turned on, we need to turn on models without turning on unrelated elements or categories for that model
515
+ on
516
+ ? modelIdsObservable.pipe(mergeMap(([modelId, categories]) => {
517
+ if (!viewport.view.viewsModel(modelId)) {
518
+ return this.showModelWithoutAnyCategoriesOrElements(modelId, categories);
519
+ }
520
+ return EMPTY;
521
+ }))
522
+ : EMPTY, this._alwaysAndNeverDrawnElements.clearAlwaysAndNeverDrawnElements({ categoryIds, modelId: modelIdFromProps }), this.getSubModels({ categoryIds, modelId: modelIdFromProps }).pipe(mergeMap(({ subModels }) => (subModels ? this.changeModelsVisibilityStatus({ modelIds: subModels, on }) : EMPTY))));
452
523
  });
453
524
  return createVisibilityHandlerResult(this, props, result, undefined);
454
525
  }
455
- changeGeometricElementsDisplayState(props) {
456
- const { modelId, categoryId, elementIds, on } = props;
457
- const viewport = this._props.viewport;
458
- const result = concat(on && !viewport.view.viewsModel(modelId) ? this.showModelWithoutAnyCategoriesOrElements(modelId) : EMPTY, defer(() => {
459
- const categoryVisibility = this.getDefaultModelsCategoryVisibilityStatus({ categoryIds: [categoryId], modelId });
460
- const isDisplayedByDefault = categoryVisibility.state === "visible";
461
- return this.queueElementsVisibilityChange(elementIds, on, isDisplayedByDefault);
462
- }), from(elementIds).pipe(mergeMap(async (elementId) => ({ elementId, isSubModel: await this._idsCache.hasSubModel(elementId) })), filter(({ isSubModel }) => isSubModel), map(({ elementId }) => elementId), toArray(), mergeMap((subModelIds) => this.changeModelDisplayState({ modelIds: subModelIds, on }))));
526
+ changeElementsVisibilityStatus(props) {
527
+ const result = defer(() => {
528
+ const { modelId, categoryId, elementIds, on } = props;
529
+ const viewport = this._props.viewport;
530
+ // TODO: change child elements
531
+ // TODO: change child element categories
532
+ // TODO: change child subModels
533
+ return concat(
534
+ // Change elements state
535
+ defer(() => {
536
+ if (!viewport.view.viewsModel(modelId)) {
537
+ if (!on) {
538
+ return this.queueElementsVisibilityChange(elementIds, on, false);
539
+ }
540
+ return this.showModelWithoutAnyCategoriesOrElements(modelId).pipe(mergeMap(() => {
541
+ const defaultVisibility = this.getVisibleModelDefaultCategoriesVisibilityStatus({ categoryIds: categoryId, modelId });
542
+ const displayedByDefault = defaultVisibility.state === "visible";
543
+ return this.queueElementsVisibilityChange(elementIds, on, displayedByDefault);
544
+ }));
545
+ }
546
+ const categoryVisibility = this.getVisibleModelDefaultCategoriesVisibilityStatus({ categoryIds: categoryId, modelId });
547
+ const isDisplayedByDefault = categoryVisibility.state === "visible";
548
+ return this.queueElementsVisibilityChange(elementIds, on, isDisplayedByDefault);
549
+ }),
550
+ // Change visibility of elements that are models
551
+ from(Id64.iterable(elementIds)).pipe(mergeMap((elementId) => from(this._idsCache.hasSubModel(elementId)).pipe(mergeMap((isSubModel) => {
552
+ if (isSubModel) {
553
+ return this.changeModelsVisibilityStatus({ modelIds: elementId, on });
554
+ }
555
+ return EMPTY;
556
+ })))));
557
+ });
463
558
  return createVisibilityHandlerResult(this, props, result, undefined);
464
559
  }
465
560
  queueElementsVisibilityChange(elementIds, on, visibleByDefault) {
466
561
  const finishedSubject = new Subject();
467
562
  // observable to track if visibility change is finished/cancelled
468
563
  const changeFinished = finishedSubject.pipe(startWith(false), shareReplay(1), filter((finished) => finished));
469
- const changeObservable = from(elementIds).pipe(
564
+ const changeObservable = from(Id64.iterable(elementIds)).pipe(
470
565
  // check if visibility change is not finished (cancelled) due to change overall change request being cancelled
471
566
  takeUntil(changeFinished), changeElementStateNoChildrenOperator({ on, isDisplayedByDefault: visibleByDefault, viewport: this._props.viewport }), tap({
472
567
  next: () => {
@@ -484,5 +579,67 @@ class ClassificationsTreeVisibilityHandlerImpl {
484
579
  },
485
580
  }), map(() => undefined));
486
581
  }
582
+ getVisibilityFromAlwaysAndNeverDrawnElements(props) {
583
+ const viewport = this._props.viewport;
584
+ if (viewport.isAlwaysDrawnExclusive) {
585
+ if (!viewport?.alwaysDrawn?.size) {
586
+ return of(createVisibilityStatus("hidden"));
587
+ }
588
+ }
589
+ else if (!viewport?.neverDrawn?.size && !viewport?.alwaysDrawn?.size) {
590
+ return of(props.defaultStatus());
591
+ }
592
+ if ("elements" in props) {
593
+ return of(getVisibilityFromAlwaysAndNeverDrawnElementsImpl({
594
+ ...props,
595
+ alwaysDrawn: viewport.alwaysDrawn?.size ? setIntersection(Id64.iterable(props.elements), viewport.alwaysDrawn) : undefined,
596
+ neverDrawn: viewport.neverDrawn?.size ? setIntersection(Id64.iterable(props.elements), viewport.neverDrawn) : undefined,
597
+ totalCount: Id64.sizeOf(props.elements),
598
+ viewport,
599
+ }));
600
+ }
601
+ const { modelId, categoryIds } = props.queryProps;
602
+ const totalCount = from(Id64.iterable(categoryIds)).pipe(mergeMap((categoryId) => this.getElementsCount({ modelId, categoryId })), reduce((acc, specificModelCategoryCount) => {
603
+ return acc + specificModelCategoryCount;
604
+ }, 0));
605
+ return forkJoin({
606
+ totalCount,
607
+ alwaysDrawn: this._alwaysAndNeverDrawnElements.getAlwaysDrawnElements(props.queryProps),
608
+ neverDrawn: this._alwaysAndNeverDrawnElements.getNeverDrawnElements(props.queryProps),
609
+ }).pipe(map((state) => {
610
+ return getVisibilityFromAlwaysAndNeverDrawnElementsImpl({
611
+ ...props,
612
+ ...state,
613
+ viewport,
614
+ });
615
+ }));
616
+ }
617
+ getCategories(props) {
618
+ return from(Id64.iterable(props.modelIds)).pipe(mergeMap((modelId) => from(this._props.idsCache.getModelCategoryIds(modelId)).pipe(map(({ spatial, drawing }) => ({ id: modelId, drawingCategories: drawing, spatialCategories: spatial })))));
619
+ }
620
+ getElementsCount(props) {
621
+ return from(this._props.idsCache.getCategoryElementsCount(props.modelId, props.categoryId));
622
+ }
623
+ getModels(props) {
624
+ return from(Id64.iterable(props.categoryIds)).pipe(mergeMap((categoryId) => from(this._props.idsCache.getCategoriesElementModels(categoryId, true)).pipe(mergeMap((categoryModelsMap) => (categoryModelsMap.size > 0 ? categoryModelsMap.values() : of(new Array()))), map((categoryModels) => ({ id: categoryId, models: categoryModels })))));
625
+ }
626
+ getSubCategories(props) {
627
+ return from(Id64.iterable(props.categoryIds)).pipe(map((categoryId) => ({ id: categoryId, subCategories: undefined })));
628
+ }
629
+ getSubModels(props) {
630
+ if ("modelIds" in props) {
631
+ return from(Id64.iterable(props.modelIds)).pipe(mergeMap((modelId) => from(this._props.idsCache.getModelCategoryIds(modelId)).pipe(mergeMap(({ drawing, spatial }) => merge(drawing, spatial)), toArray(), mergeMap((categoryIds) => from(this._props.idsCache.getCategoriesModeledElements(modelId, categoryIds))), map((subModels) => ({ id: modelId, subModels })))));
632
+ }
633
+ if (props.modelId) {
634
+ return from(Id64.iterable(props.categoryIds)).pipe(mergeMap((categoryId) => from(this._props.idsCache.getCategoriesModeledElements(props.modelId, categoryId)).pipe(map((subModels) => ({ id: categoryId, subModels })))));
635
+ }
636
+ return from(Id64.iterable(props.categoryIds)).pipe(mergeMap((categoryId) => from(this._props.idsCache.getCategoriesElementModels(categoryId)).pipe(mergeMap((categoryModelsMap) => {
637
+ const models = categoryModelsMap.get(categoryId);
638
+ if (!models) {
639
+ return of({ id: categoryId, subModels: undefined });
640
+ }
641
+ return from(models).pipe(mergeMap((modelId) => from(this._props.idsCache.getCategoriesModeledElements(modelId, categoryId))), map((subModels) => ({ id: categoryId, subModels })));
642
+ }))));
643
+ }
487
644
  }
488
645
  //# sourceMappingURL=ClassificationsTreeVisibilityHandler.js.map