@itwin/tree-widget-react 3.17.0 → 3.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -2
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +3 -2
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +3 -3
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +22 -21
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +57 -107
- package/lib/cjs/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +22 -12
- package/lib/cjs/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/common/internal/Utils.d.ts +25 -0
- package/lib/cjs/tree-widget-react/components/trees/common/internal/Utils.js +83 -0
- package/lib/cjs/tree-widget-react/components/trees/common/internal/Utils.js.map +1 -0
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +1 -0
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +78 -23
- package/lib/cjs/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.d.ts +5 -3
- package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js +5 -14
- package/lib/cjs/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +5 -4
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +7 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +52 -0
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +15 -0
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +134 -3
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +241 -120
- package/lib/cjs/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
- package/lib/cjs/tree-widget-react-internal.d.ts +1 -1
- package/lib/cjs/tree-widget-react-internal.js +1 -1
- package/lib/cjs/tree-widget-react-internal.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js +3 -2
- package/lib/esm/tree-widget-react/components/trees/categories-tree/CategoriesTreeDefinition.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.d.ts +3 -3
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js +23 -22
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesTreeIdsCache.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js +59 -109
- package/lib/esm/tree-widget-react/components/trees/categories-tree/internal/CategoriesVisibilityHandler.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js +23 -13
- package/lib/esm/tree-widget-react/components/trees/common/CategoriesVisibilityUtils.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.d.ts +25 -0
- package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js +74 -0
- package/lib/esm/tree-widget-react/components/trees/common/internal/Utils.js.map +1 -0
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.d.ts +1 -0
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js +74 -19
- package/lib/esm/tree-widget-react/components/trees/models-tree/ModelsTreeDefinition.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.d.ts +5 -3
- package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js +4 -13
- package/lib/esm/tree-widget-react/components/trees/models-tree/Utils.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js +4 -3
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/AlwaysAndNeverDrawnElementInfo.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.d.ts +7 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js +52 -0
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/FilteredTree.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.d.ts +15 -0
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js +133 -2
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeIdsCache.js.map +1 -1
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js +224 -103
- package/lib/esm/tree-widget-react/components/trees/models-tree/internal/ModelsTreeVisibilityHandler.js.map +1 -1
- package/lib/esm/tree-widget-react-internal.d.ts +1 -1
- package/lib/esm/tree-widget-react-internal.js +1 -1
- package/lib/esm/tree-widget-react-internal.js.map +1 -1
- package/package.json +1 -1
|
@@ -7,10 +7,11 @@ 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 { enableCategoryDisplay, loadCategoriesFromViewport } from "../../common/CategoriesVisibilityUtils.js";
|
|
10
|
-
import {
|
|
10
|
+
import { getTooltipOptions, mergeVisibilityStatuses, releaseMainThreadOnItemsCount, setDifference, setIntersection } from "../../common/internal/Utils.js";
|
|
11
|
+
import { toVoidPromise } from "../../common/Rxjs.js";
|
|
11
12
|
import { createVisibilityStatus } from "../../common/Tooltip.js";
|
|
12
13
|
import { createVisibilityHandlerResult } from "../../common/UseHierarchyVisibility.js";
|
|
13
|
-
import { getIdsFromChildrenTree
|
|
14
|
+
import { getIdsFromChildrenTree } from "../Utils.js";
|
|
14
15
|
import { AlwaysAndNeverDrawnElementInfo } from "./AlwaysAndNeverDrawnElementInfo.js";
|
|
15
16
|
import { createFilteredTree, parseCategoryKey } from "./FilteredTree.js";
|
|
16
17
|
import { ModelsTreeNode } from "./ModelsTreeNode.js";
|
|
@@ -88,7 +89,9 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
88
89
|
if (!HierarchyNode.isInstancesNode(node)) {
|
|
89
90
|
return of(createVisibilityStatus("disabled"));
|
|
90
91
|
}
|
|
91
|
-
|
|
92
|
+
// Only call getFilteredNodeVisibility when node is not a filter target, is not a child of filter target and has filtered children.
|
|
93
|
+
// Otherwise, it can be handled normally.
|
|
94
|
+
if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget && !node.filtering.hasFilterTargetAncestor) {
|
|
92
95
|
return this.getFilteredNodeVisibility({ node });
|
|
93
96
|
}
|
|
94
97
|
if (ModelsTreeNode.isSubjectNode(node)) {
|
|
@@ -109,13 +112,18 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
109
112
|
});
|
|
110
113
|
}
|
|
111
114
|
const categoryId = ModelsTreeNode.getCategoryId(node);
|
|
115
|
+
const rootCategoryIds = getRootCategoryIds({ parentKeys: node.parentKeys, modelId });
|
|
116
|
+
assert(rootCategoryIds !== undefined);
|
|
112
117
|
if (!categoryId) {
|
|
113
118
|
return of(createVisibilityStatus("disabled"));
|
|
114
119
|
}
|
|
115
120
|
return this.getElementDisplayStatus({
|
|
116
121
|
elementIds: node.key.instanceKeys.map(({ id }) => id),
|
|
122
|
+
parentKeys: node.parentKeys,
|
|
123
|
+
rootCategoryIds,
|
|
117
124
|
modelId,
|
|
118
125
|
categoryId,
|
|
126
|
+
totalChildrenCount: node.extendedData?.childrenCount ?? 0,
|
|
119
127
|
});
|
|
120
128
|
}
|
|
121
129
|
getFilteredNodeVisibility(props) {
|
|
@@ -135,14 +143,53 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
135
143
|
})));
|
|
136
144
|
}
|
|
137
145
|
if (elements?.size) {
|
|
138
|
-
|
|
146
|
+
const filterTargetElements = new Array();
|
|
147
|
+
elements.forEach((elementsMap) => elementsMap.forEach(({ isFilterTarget }, elementId) => {
|
|
148
|
+
if (isFilterTarget) {
|
|
149
|
+
filterTargetElements.push(elementId);
|
|
150
|
+
}
|
|
151
|
+
}));
|
|
152
|
+
let childrenCountMapObs;
|
|
153
|
+
if (HierarchyNode.isClassGroupingNode(props.node)) {
|
|
154
|
+
const groupingNodesFilterTargets = props.node.extendedData?.filterTargets;
|
|
155
|
+
const nestedFilterTargetElements = filterTargetElements.filter((filterTarget) => !groupingNodesFilterTargets?.has(filterTarget));
|
|
156
|
+
// Only need to request children count for indirect children filter targets.
|
|
157
|
+
// Direct children filter targets already have children count stored in grouping nodes extended data.
|
|
158
|
+
childrenCountMapObs = this.#idsCache.getAllChildrenCount({ elementIds: nestedFilterTargetElements });
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
childrenCountMapObs = this.#idsCache.getAllChildrenCount({ elementIds: filterTargetElements });
|
|
162
|
+
}
|
|
163
|
+
observables.push(childrenCountMapObs.pipe(
|
|
164
|
+
// Get children count for all filter target elements.
|
|
165
|
+
map((elementCountMap) => {
|
|
166
|
+
if (!HierarchyNode.isClassGroupingNode(props.node) || !props.node.extendedData?.filterTargets) {
|
|
167
|
+
return elementCountMap;
|
|
168
|
+
}
|
|
169
|
+
// Need to add children count (stored in grouping nodes' extended data) of direct children filter targets.
|
|
170
|
+
const groupingNodesFilterTargets = props.node.extendedData.filterTargets;
|
|
171
|
+
groupingNodesFilterTargets.forEach((value, key) => elementCountMap.set(key, value.childrenCount));
|
|
172
|
+
return elementCountMap;
|
|
173
|
+
}), mergeMap((elementCountMap) => from(elements).pipe(releaseMainThreadOnItemsCount(50), mergeMap(([categoryKey, elementsMap]) => {
|
|
139
174
|
const { modelId, categoryId } = parseCategoryKey(categoryKey);
|
|
175
|
+
let totalChildrenCount = 0;
|
|
176
|
+
elementsMap.forEach((_, elementId) => {
|
|
177
|
+
const childCount = elementCountMap.get(elementId);
|
|
178
|
+
if (childCount) {
|
|
179
|
+
totalChildrenCount += childCount;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
const parentElementIdsPath = getParentElementsIdsPath({ parentKeys: props.node.parentKeys, modelId });
|
|
183
|
+
const rootCategoryIds = getRootCategoryIds({ parentKeys: props.node.parentKeys, modelId });
|
|
140
184
|
return this.getElementsDisplayStatus({
|
|
141
185
|
elementIds: [...elementsMap.keys()],
|
|
186
|
+
rootCategoryIds: rootCategoryIds ?? categoryId,
|
|
187
|
+
parentElementIdsPath,
|
|
142
188
|
modelId,
|
|
143
189
|
categoryId,
|
|
190
|
+
childrenCount: totalChildrenCount,
|
|
144
191
|
});
|
|
145
|
-
})));
|
|
192
|
+
})))));
|
|
146
193
|
}
|
|
147
194
|
return merge(...observables);
|
|
148
195
|
}), mergeVisibilityStatuses());
|
|
@@ -264,25 +311,33 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
264
311
|
return createVisibilityHandlerResult(this, props, result, this.#props.overrides?.getCategoryDisplayStatus);
|
|
265
312
|
}
|
|
266
313
|
getClassGroupingNodeDisplayStatus(node) {
|
|
267
|
-
const { elementIds, modelId, categoryId } = this.getGroupingNodeInfo(node);
|
|
314
|
+
const { elementIds, modelId, categoryId, childrenCount } = this.getGroupingNodeInfo(node);
|
|
315
|
+
const rootCategoryIds = getRootCategoryIds({ parentKeys: node.parentKeys, modelId });
|
|
316
|
+
assert(rootCategoryIds !== undefined);
|
|
268
317
|
const result = this.getElementsDisplayStatus({
|
|
269
318
|
elementIds,
|
|
270
319
|
modelId,
|
|
271
320
|
categoryId,
|
|
321
|
+
rootCategoryIds,
|
|
322
|
+
parentElementIdsPath: getParentElementsIdsPath({ parentKeys: node.parentKeys, modelId }),
|
|
323
|
+
childrenCount: childrenCount ?? 0,
|
|
272
324
|
});
|
|
273
325
|
return createVisibilityHandlerResult(this, { node }, result, this.#props.overrides?.getElementGroupingNodeDisplayStatus);
|
|
274
326
|
}
|
|
275
|
-
getElementDisplayStatus({ elementIds, modelId, categoryId, }) {
|
|
327
|
+
getElementDisplayStatus({ parentKeys, totalChildrenCount, elementIds, modelId, rootCategoryIds, categoryId, }) {
|
|
276
328
|
const result = this.getElementsDisplayStatus({
|
|
329
|
+
rootCategoryIds,
|
|
277
330
|
elementIds,
|
|
278
331
|
modelId,
|
|
279
332
|
categoryId,
|
|
333
|
+
parentElementIdsPath: getParentElementsIdsPath({ parentKeys, modelId }),
|
|
334
|
+
childrenCount: totalChildrenCount,
|
|
280
335
|
});
|
|
281
336
|
return createVisibilityHandlerResult(this, { elementId: elementIds[0], modelId, categoryId }, result, this.#props.overrides?.getElementDisplayStatus);
|
|
282
337
|
}
|
|
283
338
|
getElementsDisplayStatus(props) {
|
|
284
339
|
return defer(() => {
|
|
285
|
-
const { modelId, categoryId, elementIds } = props;
|
|
340
|
+
const { modelId, categoryId, elementIds, parentElementIdsPath, childrenCount, rootCategoryIds } = props;
|
|
286
341
|
if (!this.#props.viewport.view.viewsModel(modelId)) {
|
|
287
342
|
return of(elementIds).pipe(this.getSubModeledElementsVisibilityStatus({
|
|
288
343
|
tooltips: {
|
|
@@ -296,6 +351,10 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
296
351
|
}
|
|
297
352
|
return this.getVisibilityFromAlwaysAndNeverDrawnElements({
|
|
298
353
|
elements: elementIds,
|
|
354
|
+
parentElementIdsPath,
|
|
355
|
+
modelIds: modelId,
|
|
356
|
+
rootCategoryIds,
|
|
357
|
+
childrenCount,
|
|
299
358
|
defaultStatus: () => {
|
|
300
359
|
const status = this.getDefaultCategoryVisibilityStatus({ categoryIds: categoryId, modelId, ignoreTooltip: true });
|
|
301
360
|
return createVisibilityStatus(status.state, getTooltipOptions(`modelsTree.groupingNode.${status.state}ThroughCategory`));
|
|
@@ -331,7 +390,9 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
331
390
|
if (!HierarchyNode.isInstancesNode(node)) {
|
|
332
391
|
return EMPTY;
|
|
333
392
|
}
|
|
334
|
-
|
|
393
|
+
// Only call changeFilteredNodeVisibility when node is not a filter target, is not a child of filter target and has filtered children.
|
|
394
|
+
// Otherwise, it can be handled normally.
|
|
395
|
+
if (node.filtering?.filteredChildrenIdentifierPaths?.length && !node.filtering.isFilterTarget && !node.filtering.hasFilterTargetAncestor) {
|
|
335
396
|
return this.changeFilteredNodeVisibility({ node, on });
|
|
336
397
|
}
|
|
337
398
|
if (ModelsTreeNode.isSubjectNode(node)) {
|
|
@@ -355,12 +416,18 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
355
416
|
if (!categoryId) {
|
|
356
417
|
return EMPTY;
|
|
357
418
|
}
|
|
358
|
-
|
|
359
|
-
|
|
419
|
+
const elementIds = new Set(node.key.instanceKeys.map(({ id }) => id));
|
|
420
|
+
return this.#idsCache.getChildrenTree({ elementIds }).pipe(map((childrenTree) => {
|
|
421
|
+
// Children tree contains provided elementIds, they are at the root of this tree.
|
|
422
|
+
// We want to skip them and only get ids of children.
|
|
423
|
+
return getIdsFromChildrenTree({ tree: childrenTree, predicate: ({ depth }) => depth > 0 });
|
|
424
|
+
}), mergeMap((children) => this.changeElementsState({
|
|
425
|
+
elementIds,
|
|
360
426
|
modelId,
|
|
427
|
+
children: children.size > 0 ? children : undefined,
|
|
361
428
|
categoryId,
|
|
362
429
|
on,
|
|
363
|
-
});
|
|
430
|
+
})));
|
|
364
431
|
});
|
|
365
432
|
if (this.#props.viewport.isAlwaysDrawnExclusive) {
|
|
366
433
|
return concat(this.removeAlwaysDrawnExclusive(), changeObs);
|
|
@@ -369,7 +436,7 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
369
436
|
}
|
|
370
437
|
changeFilteredNodeVisibility({ on, ...props }) {
|
|
371
438
|
assert(this.#filteredTree !== undefined);
|
|
372
|
-
return from(this.#filteredTree).pipe(map((filteredTree) => filteredTree.getVisibilityChangeTargets(props.node)), mergeMap(({ subjects,
|
|
439
|
+
return from(this.#filteredTree).pipe(map((filteredTree) => filteredTree.getVisibilityChangeTargets(props.node)), mergeMap(({ subjects, categories, elements, models }) => {
|
|
373
440
|
const observables = new Array();
|
|
374
441
|
if (subjects?.size) {
|
|
375
442
|
observables.push(this.changeSubjectNodeState([...subjects], on));
|
|
@@ -384,10 +451,24 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
384
451
|
})));
|
|
385
452
|
}
|
|
386
453
|
if (elements?.size) {
|
|
387
|
-
|
|
454
|
+
const filterTargetElements = new Array();
|
|
455
|
+
const elementsSet = new Set();
|
|
456
|
+
elements.forEach((elementsMap) => elementsMap.forEach(({ isFilterTarget }, elementId) => {
|
|
457
|
+
elementsSet.add(elementId);
|
|
458
|
+
if (isFilterTarget) {
|
|
459
|
+
filterTargetElements.push(elementId);
|
|
460
|
+
}
|
|
461
|
+
}));
|
|
462
|
+
observables.push(this.#idsCache.getChildrenTree({ elementIds: filterTargetElements }).pipe(map((childrenTree) => getIdsFromChildrenTree({ tree: childrenTree })), map((childrenIds) => setDifference(childrenIds, elementsSet)), mergeMap((childElementIds) => from(elements).pipe(mergeMap(([categoryKey, elementsMap]) => {
|
|
388
463
|
const { modelId, categoryId } = parseCategoryKey(categoryKey);
|
|
389
|
-
return this.changeElementsState({
|
|
390
|
-
|
|
464
|
+
return this.changeElementsState({
|
|
465
|
+
modelId,
|
|
466
|
+
categoryId,
|
|
467
|
+
elementIds: new Set([...elementsMap.keys()]),
|
|
468
|
+
on,
|
|
469
|
+
children: childElementIds.size > 0 ? childElementIds : undefined,
|
|
470
|
+
});
|
|
471
|
+
})))));
|
|
391
472
|
}
|
|
392
473
|
return merge(...observables);
|
|
393
474
|
}));
|
|
@@ -422,9 +503,7 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
422
503
|
const idsObs = from(Id64.iterable(ids));
|
|
423
504
|
if (!on) {
|
|
424
505
|
viewport.changeModelDisplay(ids, false);
|
|
425
|
-
return idsObs.pipe(mergeMap((modelId) => this.#idsCache.getModelCategories(modelId)
|
|
426
|
-
return { modelId, categoryIds };
|
|
427
|
-
}))), mergeMap(({ modelId, categoryIds }) => this.#idsCache.getCategoriesModeledElements(modelId, categoryIds)), mergeMap((modeledElementIds) => this.changeModelState({ ids: modeledElementIds, on })));
|
|
506
|
+
return idsObs.pipe(mergeMap((modelId) => forkJoin({ categoryIds: this.#idsCache.getModelCategories(modelId), modelId: of(modelId) })), mergeMap(({ modelId, categoryIds }) => this.#idsCache.getCategoriesModeledElements(modelId, categoryIds)), mergeMap((modeledElementIds) => this.changeModelState({ ids: modeledElementIds, on })));
|
|
428
507
|
}
|
|
429
508
|
return concat(defer(() => {
|
|
430
509
|
viewport.perModelCategoryVisibility.clearOverrides(ids);
|
|
@@ -440,15 +519,12 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
440
519
|
return forkJoin({
|
|
441
520
|
categories: this.#idsCache.getModelCategories(modelId),
|
|
442
521
|
alwaysDrawnElements: this.getAlwaysOrNeverDrawnElements({ modelIds: modelId, setType: "always" }),
|
|
443
|
-
}).pipe(mergeMap(
|
|
522
|
+
}).pipe(mergeMap(({ categories, alwaysDrawnElements }) => {
|
|
444
523
|
const alwaysDrawn = this.#props.viewport.alwaysDrawn;
|
|
445
524
|
if (alwaysDrawn && alwaysDrawnElements) {
|
|
446
525
|
viewport.setAlwaysDrawn(setDifference(alwaysDrawn, alwaysDrawnElements));
|
|
447
526
|
}
|
|
448
|
-
categories.
|
|
449
|
-
this.changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, false);
|
|
450
|
-
});
|
|
451
|
-
await viewport.addViewedModels(modelId);
|
|
527
|
+
return concat(from(Id64.iterable(categories)).pipe(releaseMainThreadOnItemsCount(300), map((categoryId) => this.changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, false))), defer(async () => viewport.addViewedModels(modelId)));
|
|
452
528
|
}));
|
|
453
529
|
}
|
|
454
530
|
changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, on) {
|
|
@@ -470,12 +546,7 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
470
546
|
const result = defer(() => {
|
|
471
547
|
const viewport = this.#props.viewport;
|
|
472
548
|
const { modelId, categoryIds, on } = props;
|
|
473
|
-
return concat(props.on && !viewport.view.viewsModel(modelId) ? this.showModelWithoutAnyCategoriesOrElements(modelId) : EMPTY,
|
|
474
|
-
for (const categoryId of Id64.iterable(categoryIds)) {
|
|
475
|
-
this.changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, on);
|
|
476
|
-
}
|
|
477
|
-
return this.clearAlwaysAndNeverDrawnElements(props);
|
|
478
|
-
}), this.#idsCache
|
|
549
|
+
return concat(props.on && !viewport.view.viewsModel(modelId) ? this.showModelWithoutAnyCategoriesOrElements(modelId) : EMPTY, from(Id64.iterable(categoryIds)).pipe(releaseMainThreadOnItemsCount(300), map((categoryId) => this.changeCategoryStateInViewportAccordingToModelVisibility(modelId, categoryId, on))), this.clearAlwaysAndNeverDrawnElements(props), this.#idsCache
|
|
479
550
|
.getCategoriesModeledElements(modelId, categoryIds)
|
|
480
551
|
.pipe(mergeMap((modeledElementIds) => this.changeModelState({ ids: modeledElementIds, on }))));
|
|
481
552
|
});
|
|
@@ -483,12 +554,25 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
483
554
|
}
|
|
484
555
|
doChangeElementsState(props) {
|
|
485
556
|
return defer(() => {
|
|
486
|
-
const { modelId, categoryId, elementIds, on } = props;
|
|
557
|
+
const { modelId, categoryId, elementIds, on, children } = props;
|
|
487
558
|
const viewport = this.#props.viewport;
|
|
488
559
|
return concat(on && !viewport.view.viewsModel(modelId) ? this.showModelWithoutAnyCategoriesOrElements(modelId) : EMPTY, defer(() => {
|
|
489
560
|
const categoryVisibility = this.getDefaultCategoryVisibilityStatus({ categoryIds: categoryId, modelId, ignoreTooltip: true });
|
|
490
|
-
const
|
|
491
|
-
|
|
561
|
+
const isCategoryVisible = categoryVisibility.state === "visible";
|
|
562
|
+
// Make sure to add all children to always/never drawn list.
|
|
563
|
+
const isDisplayedByDefault =
|
|
564
|
+
// When category is visible and elements need to be turned off, or when category is hidden and elements need to be turned on,
|
|
565
|
+
// We can set isDisplayedByDefault to isCategoryVisible. This allows to not check if each element is in the elementIds list or not.
|
|
566
|
+
isCategoryVisible === !on
|
|
567
|
+
? () => isCategoryVisible
|
|
568
|
+
: (elementId) => {
|
|
569
|
+
if (elementIds.has(elementId)) {
|
|
570
|
+
return isCategoryVisible;
|
|
571
|
+
}
|
|
572
|
+
return !on;
|
|
573
|
+
};
|
|
574
|
+
const elementsToChange = children ? [...elementIds, ...(typeof children === "string" ? [children] : children)] : elementIds;
|
|
575
|
+
return this.queueElementsVisibilityChange(elementsToChange, on, isDisplayedByDefault);
|
|
492
576
|
}), from(elementIds).pipe(mergeMap((elementId) => forkJoin({
|
|
493
577
|
elementId: of(elementId),
|
|
494
578
|
isSubModel: this.#idsCache.hasSubModel(elementId),
|
|
@@ -500,7 +584,14 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
500
584
|
* @see `changeElementState`
|
|
501
585
|
*/
|
|
502
586
|
changeElementGroupingNodeState(node, on) {
|
|
503
|
-
const
|
|
587
|
+
const { modelId, categoryId, elementIds } = this.getGroupingNodeInfo(node);
|
|
588
|
+
const result = this.#idsCache.getChildrenTree({ elementIds }).pipe(map((childrenTree) => getIdsFromChildrenTree({ tree: childrenTree, predicate: ({ depth }) => depth > 0 })), mergeMap((children) => this.doChangeElementsState({
|
|
589
|
+
modelId,
|
|
590
|
+
categoryId,
|
|
591
|
+
elementIds,
|
|
592
|
+
children: children.size > 0 ? children : undefined,
|
|
593
|
+
on,
|
|
594
|
+
})));
|
|
504
595
|
return createVisibilityHandlerResult(this, { node, on }, result, this.#props.overrides?.changeElementGroupingNodeState);
|
|
505
596
|
}
|
|
506
597
|
/**
|
|
@@ -515,7 +606,7 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
515
606
|
const finishedSubject = new Subject();
|
|
516
607
|
// observable to track if visibility change is finished/cancelled
|
|
517
608
|
const changeFinished = finishedSubject.pipe(startWith(false), shareReplay(1), filter((finished) => finished));
|
|
518
|
-
const changeObservable = from(elementIds).pipe(
|
|
609
|
+
const changeObservable = from(Id64.iterable(elementIds)).pipe(
|
|
519
610
|
// check if visibility change is not finished (cancelled) due to change overall change request being cancelled
|
|
520
611
|
takeUntil(changeFinished), this.changeElementStateNoChildrenOperator({ on, isDisplayedByDefault: visibleByDefault }), tap({
|
|
521
612
|
next: () => {
|
|
@@ -546,7 +637,7 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
546
637
|
const wasRemoved = acc.neverDrawn.delete(elementId);
|
|
547
638
|
acc.changedNeverDrawn ||= wasRemoved;
|
|
548
639
|
// If exclusive mode is enabled, we must add the element to the always drawn list.
|
|
549
|
-
if ((!isDisplayedByDefault || isAlwaysDrawnExclusive) && !acc.alwaysDrawn.has(elementId)) {
|
|
640
|
+
if ((!isDisplayedByDefault(elementId) || isAlwaysDrawnExclusive) && !acc.alwaysDrawn.has(elementId)) {
|
|
550
641
|
acc.alwaysDrawn.add(elementId);
|
|
551
642
|
acc.changedAlwaysDrawn = true;
|
|
552
643
|
}
|
|
@@ -555,7 +646,7 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
555
646
|
const wasRemoved = acc.alwaysDrawn.delete(elementId);
|
|
556
647
|
acc.changedAlwaysDrawn ||= wasRemoved;
|
|
557
648
|
// If exclusive mode is not enabled, we have to add the element to the never drawn list.
|
|
558
|
-
if (isDisplayedByDefault && !isAlwaysDrawnExclusive && !acc.neverDrawn.has(elementId)) {
|
|
649
|
+
if (isDisplayedByDefault(elementId) && !isAlwaysDrawnExclusive && !acc.neverDrawn.has(elementId)) {
|
|
559
650
|
acc.neverDrawn.add(elementId);
|
|
560
651
|
acc.changedNeverDrawn = true;
|
|
561
652
|
}
|
|
@@ -577,20 +668,22 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
577
668
|
if (totalCount === 0) {
|
|
578
669
|
return props.defaultStatus();
|
|
579
670
|
}
|
|
580
|
-
|
|
671
|
+
const neverDrawnSize = neverDrawn ? Id64.sizeOf(neverDrawn) : undefined;
|
|
672
|
+
const alwaysDrawnSize = alwaysDrawn ? Id64.sizeOf(alwaysDrawn) : undefined;
|
|
673
|
+
if (neverDrawnSize === totalCount) {
|
|
581
674
|
return createVisibilityStatus("hidden", getTooltipOptions(props.tooltips.allElementsInNeverDrawnList, ignoreTooltip));
|
|
582
675
|
}
|
|
583
|
-
if (
|
|
676
|
+
if (alwaysDrawnSize === totalCount) {
|
|
584
677
|
return createVisibilityStatus("visible", getTooltipOptions(props.tooltips.allElementsInAlwaysDrawnList, ignoreTooltip));
|
|
585
678
|
}
|
|
586
679
|
const viewport = this.#props.viewport;
|
|
587
680
|
if (viewport.isAlwaysDrawnExclusive && viewport.alwaysDrawn?.size) {
|
|
588
|
-
return
|
|
681
|
+
return alwaysDrawnSize
|
|
589
682
|
? createVisibilityStatus("partial", getTooltipOptions(props.tooltips.elementsInBothAlwaysAndNeverDrawn, ignoreTooltip))
|
|
590
683
|
: createVisibilityStatus("hidden", getTooltipOptions(props.tooltips.noElementsInExclusiveAlwaysDrawnList, ignoreTooltip));
|
|
591
684
|
}
|
|
592
685
|
const status = props.defaultStatus();
|
|
593
|
-
if ((status.state === "visible" &&
|
|
686
|
+
if ((status.state === "visible" && neverDrawnSize) || (status.state === "hidden" && alwaysDrawnSize)) {
|
|
594
687
|
return createVisibilityStatus("partial", getTooltipOptions(undefined, ignoreTooltip));
|
|
595
688
|
}
|
|
596
689
|
return status;
|
|
@@ -606,21 +699,41 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
606
699
|
return of(props.defaultStatus());
|
|
607
700
|
}
|
|
608
701
|
if ("elements" in props) {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
702
|
+
const parentElementIdsPath = [...props.parentElementIdsPath, props.elements];
|
|
703
|
+
return forkJoin({
|
|
704
|
+
childAlwaysDrawn: this.getAlwaysOrNeverDrawnElements({
|
|
705
|
+
modelIds: props.modelIds,
|
|
706
|
+
categoryIds: props.rootCategoryIds,
|
|
707
|
+
parentElementIdsPath,
|
|
708
|
+
setType: "always",
|
|
709
|
+
}),
|
|
710
|
+
childNeverDrawn: this.getAlwaysOrNeverDrawnElements({
|
|
711
|
+
modelIds: props.modelIds,
|
|
712
|
+
categoryIds: props.rootCategoryIds,
|
|
713
|
+
parentElementIdsPath,
|
|
714
|
+
setType: "never",
|
|
715
|
+
}),
|
|
716
|
+
}).pipe(map(({ childAlwaysDrawn, childNeverDrawn }) => {
|
|
717
|
+
const alwaysDrawn = new Set([...childAlwaysDrawn, ...(viewport.alwaysDrawn?.size ? setIntersection(props.elements, viewport.alwaysDrawn) : [])]);
|
|
718
|
+
const neverDrawn = new Set([...childNeverDrawn, ...(viewport.neverDrawn?.size ? setIntersection(props.elements, viewport.neverDrawn) : [])]);
|
|
719
|
+
return this.getVisibilityFromAlwaysAndNeverDrawnElementsImpl({
|
|
720
|
+
...props,
|
|
721
|
+
alwaysDrawn: alwaysDrawn.size > 0 ? alwaysDrawn : undefined,
|
|
722
|
+
neverDrawn: neverDrawn.size > 0 ? neverDrawn : undefined,
|
|
723
|
+
totalCount: props.childrenCount + Id64.sizeOf(props.elements),
|
|
724
|
+
ignoreTooltip,
|
|
725
|
+
});
|
|
615
726
|
}));
|
|
616
727
|
}
|
|
617
728
|
const { modelId, categoryIds } = props.categoryProps;
|
|
618
|
-
return from(Id64.iterable(categoryIds)).pipe(mergeMap((categoryId) =>
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
729
|
+
return from(Id64.iterable(categoryIds)).pipe(releaseMainThreadOnItemsCount(100), mergeMap((categoryId) => {
|
|
730
|
+
return forkJoin({
|
|
731
|
+
categoryId: of(categoryId),
|
|
732
|
+
totalCount: this.#idsCache.getCategoryElementsCount(modelId, categoryId),
|
|
733
|
+
alwaysDrawn: this.getAlwaysOrNeverDrawnElements({ modelIds: modelId, categoryIds: categoryId, setType: "always" }),
|
|
734
|
+
neverDrawn: this.getAlwaysOrNeverDrawnElements({ modelIds: modelId, categoryIds: categoryId, setType: "never" }),
|
|
735
|
+
});
|
|
736
|
+
}),
|
|
624
737
|
// There is a known bug:
|
|
625
738
|
// Categories that don't have root elements will make visibility result incorrect
|
|
626
739
|
// E.g.:
|
|
@@ -639,9 +752,31 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
639
752
|
}), mergeVisibilityStatuses());
|
|
640
753
|
}
|
|
641
754
|
getAlwaysOrNeverDrawnElements(props) {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
755
|
+
if (!this.#filteredTree) {
|
|
756
|
+
return this.#alwaysAndNeverDrawnElements
|
|
757
|
+
.getElementsTree(props)
|
|
758
|
+
.pipe(map((childrenTree) => getIdsFromChildrenTree({ tree: childrenTree, predicate: ({ treeEntry }) => treeEntry.isInAlwaysOrNeverDrawnSet })));
|
|
759
|
+
}
|
|
760
|
+
// When filtered tree is present, children tree retrieved from alwaysAndNeverDrawnElements may include elements that are not present in filtered tree.
|
|
761
|
+
// Need to filter out such elements.
|
|
762
|
+
return forkJoin({
|
|
763
|
+
filteredTree: from(this.#filteredTree),
|
|
764
|
+
childrenTree: this.#alwaysAndNeverDrawnElements.getElementsTree(props),
|
|
765
|
+
}).pipe(map(({ filteredTree, childrenTree }) => {
|
|
766
|
+
const parentIdsPath = [props.modelIds];
|
|
767
|
+
if ("categoryIds" in props) {
|
|
768
|
+
parentIdsPath.push(props.categoryIds);
|
|
769
|
+
if ("parentElementIdsPath" in props) {
|
|
770
|
+
props.parentElementIdsPath.forEach((parentElementIds) => parentIdsPath.push(parentElementIds));
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
// Get all ids that exist in filtered tree.
|
|
774
|
+
const elements = filteredTree.getElementsFromUnfilteredChildrenTree({ parentIdsPath, childrenTree });
|
|
775
|
+
return elements
|
|
776
|
+
? // Need to filter elements that are in always/never drawn set.
|
|
777
|
+
setIntersection(elements, getIdsFromChildrenTree({ tree: childrenTree, predicate: ({ treeEntry }) => treeEntry.isInAlwaysOrNeverDrawnSet }))
|
|
778
|
+
: new Set();
|
|
779
|
+
}));
|
|
645
780
|
}
|
|
646
781
|
clearAlwaysAndNeverDrawnElements(props) {
|
|
647
782
|
return forkJoin({
|
|
@@ -662,7 +797,9 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
662
797
|
const categoryId = ModelsTreeNode.getCategoryId(node);
|
|
663
798
|
assert(!!modelId && !!categoryId);
|
|
664
799
|
const elementIds = new Set(node.groupedInstanceKeys.map((key) => key.id));
|
|
665
|
-
|
|
800
|
+
const childrenCount = node.extendedData?.childrenCount;
|
|
801
|
+
const isFiltered = node.extendedData?.isFiltered;
|
|
802
|
+
return { modelId, categoryId, elementIds, childrenCount, isFiltered };
|
|
666
803
|
}
|
|
667
804
|
getSubModeledElementsVisibilityStatus({ parentNodeVisibilityStatus, haveSubModel, tooltips, ignoreTooltips, }) {
|
|
668
805
|
return (obs) => {
|
|
@@ -672,7 +809,7 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
672
809
|
if (haveSubModel === "yes") {
|
|
673
810
|
return of(modeledElementIds);
|
|
674
811
|
}
|
|
675
|
-
return from(Id64.iterable(modeledElementIds)).pipe(mergeMap((elementId) => forkJoin({
|
|
812
|
+
return from(Id64.iterable(modeledElementIds)).pipe(releaseMainThreadOnItemsCount(100), mergeMap((elementId) => forkJoin({
|
|
676
813
|
hasSubModel: this.#idsCache.hasSubModel(elementId),
|
|
677
814
|
elementId: of(elementId),
|
|
678
815
|
})), filter(({ hasSubModel }) => hasSubModel), map(({ elementId }) => elementId), toArray());
|
|
@@ -682,51 +819,11 @@ class ModelsTreeVisibilityHandlerImpl {
|
|
|
682
819
|
if (Id64.sizeOf(modeledElementIds) === 0) {
|
|
683
820
|
return of(parentNodeVisibilityStatus);
|
|
684
821
|
}
|
|
685
|
-
return this.getModelVisibilityStatus({ modelIds: modeledElementIds }).pipe(startWith(parentNodeVisibilityStatus), mergeVisibilityStatuses(tooltips, ignoreTooltips));
|
|
822
|
+
return this.getModelVisibilityStatus({ modelIds: typeof modeledElementIds === "string" ? [modeledElementIds] : modeledElementIds }).pipe(startWith(parentNodeVisibilityStatus), mergeVisibilityStatuses(tooltips, ignoreTooltips));
|
|
686
823
|
}));
|
|
687
824
|
};
|
|
688
825
|
}
|
|
689
826
|
}
|
|
690
|
-
function mergeVisibilities(obs) {
|
|
691
|
-
return obs.pipe(reduceWhile((x) => x.allVisible || x.allHidden, (acc, val) => {
|
|
692
|
-
acc.allVisible &&= val === "visible";
|
|
693
|
-
acc.allHidden &&= val === "hidden";
|
|
694
|
-
return acc;
|
|
695
|
-
}, { allVisible: true, allHidden: true }), map((x) => {
|
|
696
|
-
if (!x) {
|
|
697
|
-
return "empty";
|
|
698
|
-
}
|
|
699
|
-
return x.allVisible ? "visible" : x.allHidden ? "hidden" : "partial";
|
|
700
|
-
}));
|
|
701
|
-
}
|
|
702
|
-
function mergeVisibilityStatuses(tooltipMap, ignoreTooltip) {
|
|
703
|
-
return (obs) => {
|
|
704
|
-
return obs.pipe(map((visibilityStatus) => visibilityStatus.state), mergeVisibilities, map((visibility) => {
|
|
705
|
-
if (visibility === "empty") {
|
|
706
|
-
visibility = "visible";
|
|
707
|
-
}
|
|
708
|
-
return createVisibilityStatus(visibility, getTooltipOptions(tooltipMap?.[visibility], ignoreTooltip));
|
|
709
|
-
}));
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
function setDifference(lhs, rhs) {
|
|
713
|
-
const result = new Set();
|
|
714
|
-
for (const x of lhs) {
|
|
715
|
-
if (!rhs.has(x)) {
|
|
716
|
-
result.add(x);
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
return result;
|
|
720
|
-
}
|
|
721
|
-
function setIntersection(lhs, rhs) {
|
|
722
|
-
const result = new Set();
|
|
723
|
-
for (const x of lhs) {
|
|
724
|
-
if (rhs.has(x)) {
|
|
725
|
-
result.add(x);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
return result;
|
|
729
|
-
}
|
|
730
827
|
/**
|
|
731
828
|
* Enables display of all given models. Also enables display of all categories and clears always and
|
|
732
829
|
* never drawn lists in the viewport.
|
|
@@ -793,9 +890,33 @@ export async function toggleModels(models, enable, viewport) {
|
|
|
793
890
|
export function areAllModelsVisible(models, viewport) {
|
|
794
891
|
return models.length !== 0 ? models.every((id) => viewport.viewsModel(id)) : false;
|
|
795
892
|
}
|
|
796
|
-
function
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
893
|
+
function getParentElementsIdsPath(props) {
|
|
894
|
+
const parentElementIdsPath = new Array();
|
|
895
|
+
const modelIndex = props.parentKeys.findIndex((parentKey) => HierarchyNodeKey.isInstances(parentKey) && parentKey.instanceKeys.some((instanceKey) => instanceKey.id === props.modelId));
|
|
896
|
+
if (modelIndex === -1) {
|
|
897
|
+
return parentElementIdsPath;
|
|
898
|
+
}
|
|
899
|
+
// Hierarchy is model -> category -> root elements.
|
|
900
|
+
// Root elements index is 2 more than models'.
|
|
901
|
+
const firstParentIndex = modelIndex + 2;
|
|
902
|
+
for (let i = firstParentIndex; i < props.parentKeys.length; ++i) {
|
|
903
|
+
const parentKey = props.parentKeys[i];
|
|
904
|
+
if (!HierarchyNodeKey.isInstances(parentKey)) {
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
parentElementIdsPath.push(parentKey.instanceKeys.map(({ id }) => id));
|
|
908
|
+
}
|
|
909
|
+
return parentElementIdsPath;
|
|
910
|
+
}
|
|
911
|
+
function getRootCategoryIds(props) {
|
|
912
|
+
const modelIndex = props.parentKeys.findIndex((parentKey) => HierarchyNodeKey.isInstances(parentKey) && parentKey.instanceKeys.some((instanceKey) => instanceKey.id === props.modelId));
|
|
913
|
+
if (modelIndex === -1 || modelIndex + 1 === props.parentKeys.length) {
|
|
914
|
+
return undefined;
|
|
915
|
+
}
|
|
916
|
+
const rootCategoryKeys = props.parentKeys[modelIndex + 1];
|
|
917
|
+
if (!HierarchyNodeKey.isInstances(rootCategoryKeys)) {
|
|
918
|
+
return undefined;
|
|
919
|
+
}
|
|
920
|
+
return rootCategoryKeys.instanceKeys.map(({ id }) => id);
|
|
800
921
|
}
|
|
801
922
|
//# sourceMappingURL=ModelsTreeVisibilityHandler.js.map
|