@itwin/map-layers 4.0.0-dev.7 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/CHANGELOG.md +746 -848
  2. package/README.md +32 -32
  3. package/lib/cjs/MapLayerPreferences.d.ts +88 -88
  4. package/lib/cjs/MapLayerPreferences.js +312 -312
  5. package/lib/cjs/MapLayerPreferences.js.map +1 -1
  6. package/lib/cjs/map-layers.d.ts +6 -6
  7. package/lib/cjs/map-layers.js +22 -22
  8. package/lib/cjs/mapLayers.d.ts +26 -44
  9. package/lib/cjs/mapLayers.d.ts.map +1 -1
  10. package/lib/cjs/mapLayers.js +34 -63
  11. package/lib/cjs/mapLayers.js.map +1 -1
  12. package/lib/cjs/ui/FeatureInfoUiItemsProvider.d.ts +16 -11
  13. package/lib/cjs/ui/FeatureInfoUiItemsProvider.d.ts.map +1 -1
  14. package/lib/cjs/ui/FeatureInfoUiItemsProvider.js +47 -52
  15. package/lib/cjs/ui/FeatureInfoUiItemsProvider.js.map +1 -1
  16. package/lib/cjs/ui/Interfaces.d.ts +50 -50
  17. package/lib/cjs/ui/Interfaces.js +2 -2
  18. package/lib/cjs/ui/Interfaces.js.map +1 -1
  19. package/lib/cjs/ui/MapFeatureInfoTool.d.ts +13 -13
  20. package/lib/cjs/ui/MapFeatureInfoTool.d.ts.map +1 -1
  21. package/lib/cjs/ui/MapFeatureInfoTool.js +50 -50
  22. package/lib/cjs/ui/MapFeatureInfoTool.js.map +1 -1
  23. package/lib/cjs/ui/MapLayersUiItemsProvider.d.ts +8 -8
  24. package/lib/cjs/ui/MapLayersUiItemsProvider.d.ts.map +1 -1
  25. package/lib/cjs/ui/MapLayersUiItemsProvider.js +35 -38
  26. package/lib/cjs/ui/MapLayersUiItemsProvider.js.map +1 -1
  27. package/lib/cjs/ui/widget/AttachLayerPopupButton.d.ts +13 -14
  28. package/lib/cjs/ui/widget/AttachLayerPopupButton.d.ts.map +1 -1
  29. package/lib/cjs/ui/widget/AttachLayerPopupButton.js +338 -338
  30. package/lib/cjs/ui/widget/AttachLayerPopupButton.js.map +1 -1
  31. package/lib/cjs/ui/widget/BasemapPanel.d.ts +7 -8
  32. package/lib/cjs/ui/widget/BasemapPanel.d.ts.map +1 -1
  33. package/lib/cjs/ui/widget/BasemapPanel.js +156 -156
  34. package/lib/cjs/ui/widget/BasemapPanel.js.map +1 -1
  35. package/lib/cjs/ui/widget/BasemapPanel.scss +87 -87
  36. package/lib/cjs/ui/widget/ConfirmMessageDialog.d.ts +20 -21
  37. package/lib/cjs/ui/widget/ConfirmMessageDialog.d.ts.map +1 -1
  38. package/lib/cjs/ui/widget/ConfirmMessageDialog.js +25 -25
  39. package/lib/cjs/ui/widget/ConfirmMessageDialog.js.map +1 -1
  40. package/lib/cjs/ui/widget/FeatureInfoDataProvider.d.ts +35 -40
  41. package/lib/cjs/ui/widget/FeatureInfoDataProvider.d.ts.map +1 -1
  42. package/lib/cjs/ui/widget/FeatureInfoDataProvider.js +140 -139
  43. package/lib/cjs/ui/widget/FeatureInfoDataProvider.js.map +1 -1
  44. package/lib/cjs/ui/widget/FeatureInfoWidget.d.ts +6 -7
  45. package/lib/cjs/ui/widget/FeatureInfoWidget.d.ts.map +1 -1
  46. package/lib/cjs/ui/widget/FeatureInfoWidget.js +76 -71
  47. package/lib/cjs/ui/widget/FeatureInfoWidget.js.map +1 -1
  48. package/lib/cjs/ui/widget/MapLayerDroppable.d.ts +18 -19
  49. package/lib/cjs/ui/widget/MapLayerDroppable.d.ts.map +1 -1
  50. package/lib/cjs/ui/widget/MapLayerDroppable.js +88 -88
  51. package/lib/cjs/ui/widget/MapLayerDroppable.js.map +1 -1
  52. package/lib/cjs/ui/widget/MapLayerManager.d.ts +26 -26
  53. package/lib/cjs/ui/widget/MapLayerManager.js +403 -403
  54. package/lib/cjs/ui/widget/MapLayerManager.js.map +1 -1
  55. package/lib/cjs/ui/widget/MapLayerManager.scss +409 -409
  56. package/lib/cjs/ui/widget/MapLayerSettingsMenu.d.ts +11 -12
  57. package/lib/cjs/ui/widget/MapLayerSettingsMenu.d.ts.map +1 -1
  58. package/lib/cjs/ui/widget/MapLayerSettingsMenu.js +83 -83
  59. package/lib/cjs/ui/widget/MapLayerSettingsMenu.js.map +1 -1
  60. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.d.ts +6 -7
  61. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.d.ts.map +1 -1
  62. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.js +65 -65
  63. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.js.map +1 -1
  64. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.scss +20 -20
  65. package/lib/cjs/ui/widget/MapLayersWidget.d.ts +10 -11
  66. package/lib/cjs/ui/widget/MapLayersWidget.d.ts.map +1 -1
  67. package/lib/cjs/ui/widget/MapLayersWidget.js +31 -31
  68. package/lib/cjs/ui/widget/MapLayersWidget.js.map +1 -1
  69. package/lib/cjs/ui/widget/MapManagerSettings.d.ts +2 -3
  70. package/lib/cjs/ui/widget/MapManagerSettings.d.ts.map +1 -1
  71. package/lib/cjs/ui/widget/MapManagerSettings.js +200 -200
  72. package/lib/cjs/ui/widget/MapManagerSettings.js.map +1 -1
  73. package/lib/cjs/ui/widget/MapManagerSettings.scss +29 -29
  74. package/lib/cjs/ui/widget/MapUrlDialog.d.ts +22 -23
  75. package/lib/cjs/ui/widget/MapUrlDialog.d.ts.map +1 -1
  76. package/lib/cjs/ui/widget/MapUrlDialog.js +533 -527
  77. package/lib/cjs/ui/widget/MapUrlDialog.js.map +1 -1
  78. package/lib/cjs/ui/widget/MapUrlDialog.scss +99 -100
  79. package/lib/cjs/ui/widget/SelectMapFormat.d.ts +17 -18
  80. package/lib/cjs/ui/widget/SelectMapFormat.d.ts.map +1 -1
  81. package/lib/cjs/ui/widget/SelectMapFormat.js +59 -59
  82. package/lib/cjs/ui/widget/SelectMapFormat.js.map +1 -1
  83. package/lib/cjs/ui/widget/SubLayersDataProvider.d.ts +18 -20
  84. package/lib/cjs/ui/widget/SubLayersDataProvider.d.ts.map +1 -1
  85. package/lib/cjs/ui/widget/SubLayersDataProvider.js +75 -76
  86. package/lib/cjs/ui/widget/SubLayersDataProvider.js.map +1 -1
  87. package/lib/cjs/ui/widget/SubLayersPopupButton.d.ts +9 -10
  88. package/lib/cjs/ui/widget/SubLayersPopupButton.d.ts.map +1 -1
  89. package/lib/cjs/ui/widget/SubLayersPopupButton.js +40 -40
  90. package/lib/cjs/ui/widget/SubLayersPopupButton.js.map +1 -1
  91. package/lib/cjs/ui/widget/SubLayersTree.d.ts +14 -15
  92. package/lib/cjs/ui/widget/SubLayersTree.d.ts.map +1 -1
  93. package/lib/cjs/ui/widget/SubLayersTree.js +419 -419
  94. package/lib/cjs/ui/widget/SubLayersTree.js.map +1 -1
  95. package/lib/cjs/ui/widget/SubLayersTree.scss +70 -69
  96. package/lib/cjs/ui/widget/TransparencyPopupButton.d.ts +13 -14
  97. package/lib/cjs/ui/widget/TransparencyPopupButton.d.ts.map +1 -1
  98. package/lib/cjs/ui/widget/TransparencyPopupButton.js +47 -47
  99. package/lib/cjs/ui/widget/TransparencyPopupButton.js.map +1 -1
  100. package/lib/cjs/ui/widget/TransparencyPopupButton.scss +35 -36
  101. package/lib/esm/MapLayerPreferences.d.ts +88 -88
  102. package/lib/esm/MapLayerPreferences.js +308 -308
  103. package/lib/esm/MapLayerPreferences.js.map +1 -1
  104. package/lib/esm/map-layers.d.ts +6 -6
  105. package/lib/esm/map-layers.js +10 -10
  106. package/lib/esm/mapLayers.d.ts +26 -44
  107. package/lib/esm/mapLayers.d.ts.map +1 -1
  108. package/lib/esm/mapLayers.js +30 -59
  109. package/lib/esm/mapLayers.js.map +1 -1
  110. package/lib/esm/ui/FeatureInfoUiItemsProvider.d.ts +16 -11
  111. package/lib/esm/ui/FeatureInfoUiItemsProvider.d.ts.map +1 -1
  112. package/lib/esm/ui/FeatureInfoUiItemsProvider.js +43 -48
  113. package/lib/esm/ui/FeatureInfoUiItemsProvider.js.map +1 -1
  114. package/lib/esm/ui/Interfaces.d.ts +50 -50
  115. package/lib/esm/ui/Interfaces.js +1 -1
  116. package/lib/esm/ui/Interfaces.js.map +1 -1
  117. package/lib/esm/ui/MapFeatureInfoTool.d.ts +13 -13
  118. package/lib/esm/ui/MapFeatureInfoTool.d.ts.map +1 -1
  119. package/lib/esm/ui/MapFeatureInfoTool.js +45 -45
  120. package/lib/esm/ui/MapFeatureInfoTool.js.map +1 -1
  121. package/lib/esm/ui/MapLayersUiItemsProvider.d.ts +8 -8
  122. package/lib/esm/ui/MapLayersUiItemsProvider.d.ts.map +1 -1
  123. package/lib/esm/ui/MapLayersUiItemsProvider.js +31 -34
  124. package/lib/esm/ui/MapLayersUiItemsProvider.js.map +1 -1
  125. package/lib/esm/ui/widget/AttachLayerPopupButton.d.ts +13 -14
  126. package/lib/esm/ui/widget/AttachLayerPopupButton.d.ts.map +1 -1
  127. package/lib/esm/ui/widget/AttachLayerPopupButton.js +334 -334
  128. package/lib/esm/ui/widget/AttachLayerPopupButton.js.map +1 -1
  129. package/lib/esm/ui/widget/BasemapPanel.d.ts +7 -8
  130. package/lib/esm/ui/widget/BasemapPanel.d.ts.map +1 -1
  131. package/lib/esm/ui/widget/BasemapPanel.js +152 -152
  132. package/lib/esm/ui/widget/BasemapPanel.js.map +1 -1
  133. package/lib/esm/ui/widget/BasemapPanel.scss +87 -87
  134. package/lib/esm/ui/widget/ConfirmMessageDialog.d.ts +20 -21
  135. package/lib/esm/ui/widget/ConfirmMessageDialog.d.ts.map +1 -1
  136. package/lib/esm/ui/widget/ConfirmMessageDialog.js +21 -21
  137. package/lib/esm/ui/widget/ConfirmMessageDialog.js.map +1 -1
  138. package/lib/esm/ui/widget/FeatureInfoDataProvider.d.ts +35 -40
  139. package/lib/esm/ui/widget/FeatureInfoDataProvider.d.ts.map +1 -1
  140. package/lib/esm/ui/widget/FeatureInfoDataProvider.js +136 -135
  141. package/lib/esm/ui/widget/FeatureInfoDataProvider.js.map +1 -1
  142. package/lib/esm/ui/widget/FeatureInfoWidget.d.ts +6 -7
  143. package/lib/esm/ui/widget/FeatureInfoWidget.d.ts.map +1 -1
  144. package/lib/esm/ui/widget/FeatureInfoWidget.js +72 -67
  145. package/lib/esm/ui/widget/FeatureInfoWidget.js.map +1 -1
  146. package/lib/esm/ui/widget/MapLayerDroppable.d.ts +18 -19
  147. package/lib/esm/ui/widget/MapLayerDroppable.d.ts.map +1 -1
  148. package/lib/esm/ui/widget/MapLayerDroppable.js +84 -84
  149. package/lib/esm/ui/widget/MapLayerDroppable.js.map +1 -1
  150. package/lib/esm/ui/widget/MapLayerManager.d.ts +26 -26
  151. package/lib/esm/ui/widget/MapLayerManager.js +398 -398
  152. package/lib/esm/ui/widget/MapLayerManager.js.map +1 -1
  153. package/lib/esm/ui/widget/MapLayerManager.scss +409 -409
  154. package/lib/esm/ui/widget/MapLayerSettingsMenu.d.ts +11 -12
  155. package/lib/esm/ui/widget/MapLayerSettingsMenu.d.ts.map +1 -1
  156. package/lib/esm/ui/widget/MapLayerSettingsMenu.js +79 -79
  157. package/lib/esm/ui/widget/MapLayerSettingsMenu.js.map +1 -1
  158. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.d.ts +6 -7
  159. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.d.ts.map +1 -1
  160. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.js +61 -61
  161. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.js.map +1 -1
  162. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.scss +20 -20
  163. package/lib/esm/ui/widget/MapLayersWidget.d.ts +10 -11
  164. package/lib/esm/ui/widget/MapLayersWidget.d.ts.map +1 -1
  165. package/lib/esm/ui/widget/MapLayersWidget.js +27 -27
  166. package/lib/esm/ui/widget/MapLayersWidget.js.map +1 -1
  167. package/lib/esm/ui/widget/MapManagerSettings.d.ts +2 -3
  168. package/lib/esm/ui/widget/MapManagerSettings.d.ts.map +1 -1
  169. package/lib/esm/ui/widget/MapManagerSettings.js +196 -196
  170. package/lib/esm/ui/widget/MapManagerSettings.js.map +1 -1
  171. package/lib/esm/ui/widget/MapManagerSettings.scss +29 -29
  172. package/lib/esm/ui/widget/MapUrlDialog.d.ts +22 -23
  173. package/lib/esm/ui/widget/MapUrlDialog.d.ts.map +1 -1
  174. package/lib/esm/ui/widget/MapUrlDialog.js +529 -523
  175. package/lib/esm/ui/widget/MapUrlDialog.js.map +1 -1
  176. package/lib/esm/ui/widget/MapUrlDialog.scss +99 -100
  177. package/lib/esm/ui/widget/SelectMapFormat.d.ts +17 -18
  178. package/lib/esm/ui/widget/SelectMapFormat.d.ts.map +1 -1
  179. package/lib/esm/ui/widget/SelectMapFormat.js +55 -55
  180. package/lib/esm/ui/widget/SelectMapFormat.js.map +1 -1
  181. package/lib/esm/ui/widget/SubLayersDataProvider.d.ts +18 -20
  182. package/lib/esm/ui/widget/SubLayersDataProvider.d.ts.map +1 -1
  183. package/lib/esm/ui/widget/SubLayersDataProvider.js +71 -72
  184. package/lib/esm/ui/widget/SubLayersDataProvider.js.map +1 -1
  185. package/lib/esm/ui/widget/SubLayersPopupButton.d.ts +9 -10
  186. package/lib/esm/ui/widget/SubLayersPopupButton.d.ts.map +1 -1
  187. package/lib/esm/ui/widget/SubLayersPopupButton.js +36 -36
  188. package/lib/esm/ui/widget/SubLayersPopupButton.js.map +1 -1
  189. package/lib/esm/ui/widget/SubLayersTree.d.ts +14 -15
  190. package/lib/esm/ui/widget/SubLayersTree.d.ts.map +1 -1
  191. package/lib/esm/ui/widget/SubLayersTree.js +414 -414
  192. package/lib/esm/ui/widget/SubLayersTree.js.map +1 -1
  193. package/lib/esm/ui/widget/SubLayersTree.scss +70 -69
  194. package/lib/esm/ui/widget/TransparencyPopupButton.d.ts +13 -14
  195. package/lib/esm/ui/widget/TransparencyPopupButton.d.ts.map +1 -1
  196. package/lib/esm/ui/widget/TransparencyPopupButton.js +43 -43
  197. package/lib/esm/ui/widget/TransparencyPopupButton.js.map +1 -1
  198. package/lib/esm/ui/widget/TransparencyPopupButton.scss +35 -36
  199. package/package.json +39 -38
@@ -1,420 +1,420 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SubLayersTree = exports.SubLayersPanel = void 0;
4
- /*---------------------------------------------------------------------------------------------
5
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
6
- * See LICENSE.md in the project root for license terms and full copyright notice.
7
- *--------------------------------------------------------------------------------------------*/
8
- const appui_abstract_1 = require("@itwin/appui-abstract");
9
- const components_react_1 = require("@itwin/components-react");
10
- const core_common_1 = require("@itwin/core-common");
11
- const core_frontend_1 = require("@itwin/core-frontend");
12
- const core_react_1 = require("@itwin/core-react");
13
- const itwinui_react_1 = require("@itwin/itwinui-react");
14
- const React = require("react");
15
- const SubLayersDataProvider_1 = require("./SubLayersDataProvider");
16
- require("./SubLayersTree.scss");
17
- const mapLayers_1 = require("../../mapLayers");
18
- const getWindow = () => {
19
- return typeof window === "undefined" ? undefined : window;
20
- };
21
- const useResizeObserver = (onResize) => {
22
- const resizeObserver = React.useRef();
23
- const elementRef = React.useCallback((element) => {
24
- var _a, _b, _c;
25
- if (!((_a = getWindow()) === null || _a === void 0 ? void 0 : _a.ResizeObserver)) {
26
- return;
27
- }
28
- (_b = resizeObserver.current) === null || _b === void 0 ? void 0 : _b.disconnect();
29
- if (element) {
30
- resizeObserver.current = new ResizeObserver(([{ contentRect }]) => onResize(contentRect));
31
- (_c = resizeObserver.current) === null || _c === void 0 ? void 0 : _c.observe(element);
32
- }
33
- }, [onResize]);
34
- return [elementRef, resizeObserver.current];
35
- };
36
- /**
37
- Mimic processing of `react-resize-detector` to return width and height.
38
- * @internal
39
- */
40
- function useResizeDetector() {
41
- const [width, setWidth] = React.useState();
42
- const [height, setHeight] = React.useState();
43
- const [ref] = useResizeObserver(React.useCallback((size) => {
44
- setWidth(size.width);
45
- setHeight(size.height);
46
- }, []));
47
- return { width, height, ref };
48
- }
49
- // eslint-disable-next-line @typescript-eslint/naming-convention
50
- function Toolbar(props) {
51
- return (React.createElement("div", { className: "map-manager-sublayer-tree-toolbar" },
52
- React.createElement("div", { className: "tree-toolbar-action-buttons" }, props.children),
53
- props.searchField && React.createElement("div", { className: "tree-toolbar-searchbox" }, props.searchField)));
54
- }
55
- // eslint-disable-next-line @typescript-eslint/naming-convention
56
- function SubLayersPanel({ mapLayer, viewport }) {
57
- const [noneAvailableLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:SubLayers.NoSubLayers"));
58
- if (!viewport || (undefined === mapLayer.subLayers || 0 === mapLayer.subLayers.length)) {
59
- return React.createElement("div", { className: "map-manager-sublayer-panel" },
60
- React.createElement("div", null, noneAvailableLabel));
61
- }
62
- return (React.createElement(SubLayersTree, { mapLayer: mapLayer }));
63
- }
64
- exports.SubLayersPanel = SubLayersPanel;
65
- function getSubLayerProps(subLayerSettings) {
66
- return subLayerSettings.map((subLayer) => subLayer.toJSON());
67
- }
68
- function getStyleMapLayerSettings(settings, isOverlay, layerIndex, treeVisibility) {
69
- return {
70
- visible: settings.visible,
71
- name: settings.name,
72
- source: settings.source,
73
- transparency: settings.transparency,
74
- transparentBackground: settings.transparentBackground,
75
- subLayers: settings.subLayers ? getSubLayerProps(settings.subLayers) : undefined,
76
- showSubLayers: true,
77
- isOverlay,
78
- layerIndex,
79
- provider: core_frontend_1.IModelApp.mapLayerFormatRegistry.createImageryProvider(settings),
80
- treeVisibility,
81
- };
82
- }
83
- /**
84
- * Tree Control that displays sub-layer hierarchy
85
- * @internal
86
- */
87
- // eslint-disable-next-line @typescript-eslint/naming-convention
88
- function SubLayersTree(props) {
89
- var _a;
90
- const [placeholderLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:SubLayers.SearchPlaceholder"));
91
- const [allOnLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:SubLayers.AllOn"));
92
- const [allOffLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:SubLayers.AllOff"));
93
- const [mapLayer, setMapLayer] = React.useState(props.mapLayer);
94
- const [layerFilterString, setLayerFilterString] = React.useState("");
95
- // create data provider to get some nodes to show in tree
96
- // `React.useMemo' is used avoid creating new object on each render cycle
97
- const dataProvider = React.useMemo(() => new SubLayersDataProvider_1.SubLayersDataProvider(mapLayer), [mapLayer]);
98
- const { modelSource, nodeLoader, nodeHighlightingProps, } = useTreeFiltering(dataProvider, layerFilterString);
99
- // create custom event handler. It handles all tree event same as `TreeEventHandler` but additionally
100
- // it selects/deselects node when checkbox is checked/unchecked and vice versa.
101
- // `useDisposable` takes care of disposing old event handler when new is created in case 'nodeLoader' has changed
102
- // `React.useCallback` is used to avoid creating new callback that creates handler on each render
103
- const eventHandler = (0, core_react_1.useDisposable)(React.useCallback(() => new SubLayerCheckboxHandler(mapLayer, nodeLoader), [nodeLoader, mapLayer]));
104
- // Get an immutable tree model from the model source. The model is regenerated every time the model source
105
- // emits the `onModelChanged` event.
106
- const treeModel = (0, components_react_1.useTreeModel)(modelSource);
107
- const showAll = React.useCallback(async () => {
108
- const vp = core_frontend_1.IModelApp.viewManager.selectedView;
109
- const displayStyle = vp === null || vp === void 0 ? void 0 : vp.displayStyle;
110
- if (displayStyle && vp) {
111
- const indexInDisplayStyle = displayStyle ? displayStyle.findMapLayerIndexByNameAndSource(mapLayer.name, mapLayer.source, mapLayer.isOverlay) : -1;
112
- displayStyle.changeMapSubLayerProps({ visible: true }, -1, indexInDisplayStyle, mapLayer.isOverlay);
113
- vp.invalidateRenderPlan();
114
- const updatedMapLayer = displayStyle.mapLayerAtIndex(indexInDisplayStyle, mapLayer.isOverlay);
115
- if (updatedMapLayer) {
116
- if (updatedMapLayer instanceof core_common_1.ImageMapLayerSettings) {
117
- const treeVisibility = vp.getMapLayerScaleRangeVisibility(indexInDisplayStyle, mapLayer.isOverlay);
118
- setMapLayer(getStyleMapLayerSettings(updatedMapLayer, mapLayer.isOverlay, indexInDisplayStyle, treeVisibility));
119
- }
120
- }
121
- }
122
- }, [mapLayer]);
123
- const hideAll = React.useCallback(async () => {
124
- const vp = core_frontend_1.IModelApp.viewManager.selectedView;
125
- const displayStyle = vp === null || vp === void 0 ? void 0 : vp.displayStyle;
126
- if (displayStyle && vp) {
127
- const indexInDisplayStyle = displayStyle ? displayStyle.findMapLayerIndexByNameAndSource(mapLayer.name, mapLayer.source, mapLayer.isOverlay) : -1;
128
- displayStyle.changeMapSubLayerProps({ visible: false }, -1, indexInDisplayStyle, mapLayer.isOverlay);
129
- const updatedMapLayer = displayStyle.mapLayerAtIndex(indexInDisplayStyle, mapLayer.isOverlay);
130
- if (updatedMapLayer && updatedMapLayer instanceof core_common_1.ImageMapLayerSettings) {
131
- const treeVisibility = vp.getMapLayerScaleRangeVisibility(indexInDisplayStyle, mapLayer.isOverlay);
132
- setMapLayer(getStyleMapLayerSettings(updatedMapLayer, mapLayer.isOverlay, indexInDisplayStyle, treeVisibility));
133
- }
134
- vp.invalidateRenderPlan();
135
- }
136
- }, [mapLayer]);
137
- const handleFilterTextChanged = React.useCallback((event) => {
138
- setLayerFilterString(event.target.value);
139
- }, []);
140
- const { width, height, ref: containerRef } = useResizeDetector();
141
- return React.createElement(React.Fragment, null,
142
- React.createElement("div", { className: "map-manager-sublayer-tree" },
143
- React.createElement(Toolbar, { searchField: React.createElement(itwinui_react_1.Input, { type: "text", className: "map-manager-source-list-filter", placeholder: placeholderLabel, value: layerFilterString, onChange: handleFilterTextChanged, size: "small" }) }, ((_a = mapLayer.provider) === null || _a === void 0 ? void 0 : _a.mutualExclusiveSubLayer) ? undefined : [
144
- React.createElement(itwinui_react_1.Button, { size: "small", styleType: "borderless", key: "show-all-btn", title: allOnLabel, onClick: showAll },
145
- React.createElement(core_react_1.WebFontIcon, { iconName: "icon-visibility" })),
146
- React.createElement(itwinui_react_1.Button, { size: "small", styleType: "borderless", key: "hide-all-btn", title: allOffLabel, onClick: hideAll },
147
- React.createElement(core_react_1.WebFontIcon, { iconName: "icon-visibility-hide-2" })),
148
- ]),
149
- React.createElement("div", { ref: containerRef, className: "map-manager-sublayer-tree-content" }, width !== undefined && height !== undefined && React.createElement(components_react_1.ControlledTree, { nodeLoader: nodeLoader, selectionMode: components_react_1.SelectionMode.None, eventsHandler: eventHandler, model: treeModel, treeRenderer: nodeWithEyeCheckboxTreeRenderer, nodeHighlightingProps: nodeHighlightingProps, width: width, height: height }))));
150
- }
151
- exports.SubLayersTree = SubLayersTree;
152
- /** TreeEventHandler derived class that handler processing changes to subLayer visibility */
153
- class SubLayerCheckboxHandler extends components_react_1.TreeEventHandler {
154
- constructor(_mapLayer, nodeLoader) {
155
- super({ modelSource: nodeLoader.modelSource, nodeLoader, collapsedChildrenDisposalEnabled: true });
156
- this._mapLayer = _mapLayer;
157
- //-----------------------------------------------------------------------
158
- // Listen to model changes
159
- //------------------------------------------------------------------------
160
- // This is required because nodes are delay loaded in the model until
161
- // they are made visible (i.e. parent node is expanded). So even though
162
- // you might have created nodes in the data provided with a proper
163
- // initial state, by the time it gets loaded, their state might have became
164
- // out of date in the TreeView's active model. So whenever a node
165
- // is added, when must confirm its state matches the current model
166
- // (i.e. state of their parent.)
167
- this.onModelChanged = (args) => {
168
- this.modelSource.modifyModel((model) => {
169
- const addedNodes = args[1].addedNodeIds.map((id) => model.getNode(id));
170
- addedNodes.forEach((node) => {
171
- if (!node)
172
- return;
173
- this.syncNodeStateWithParent(model, node);
174
- });
175
- });
176
- };
177
- this._removeModelChangedListener = this.modelSource.onModelChanged.addListener(this.onModelChanged);
178
- }
179
- dispose() {
180
- this._removeModelChangedListener();
181
- super.dispose();
182
- }
183
- // Cascade state
184
- // Children on unnamed groups must get disabled in the tree view, because
185
- // they get rendered anyway.
186
- cascadeStateToAllChildren(model, parentId) {
187
- const children = model.getChildren(parentId);
188
- if (children === undefined)
189
- return;
190
- for (const childID of children) {
191
- const childNode = childID ? model.getNode(childID) : undefined;
192
- if (childNode)
193
- this.syncNodeStateWithParent(model, childNode);
194
- // Drill down the tree.
195
- this.cascadeStateToAllChildren(model, childID);
196
- }
197
- }
198
- applyMutualExclusiveState(model, nodeId) {
199
- const changedNode = model.getNode(nodeId);
200
- if ((changedNode === null || changedNode === void 0 ? void 0 : changedNode.checkbox.state) === core_react_1.CheckBoxState.Off)
201
- return;
202
- for (const node of model.iterateTreeModelNodes()) {
203
- if (node.id === (changedNode === null || changedNode === void 0 ? void 0 : changedNode.id))
204
- continue;
205
- if (node && node.checkbox.state === core_react_1.CheckBoxState.On)
206
- node.checkbox.state = core_react_1.CheckBoxState.Off;
207
- }
208
- }
209
- static isUnnamedGroup(subLayer) {
210
- if (!subLayer)
211
- return false;
212
- return (!subLayer.name || subLayer.name.length === 0) && (subLayer.children !== undefined && subLayer.children.length > 0);
213
- }
214
- // Ensure the state of changed node matches the state of its parent.
215
- syncNodeStateWithParent(model, changedNode) {
216
- var _a, _b, _c, _d, _e, _f;
217
- // Lookup node parent. If non exists, I assume thats the root node,
218
- // and it must have a proper initial state.
219
- const parentNode = changedNode.parentId ? model.getNode(changedNode.parentId) : undefined;
220
- if (!parentNode)
221
- return;
222
- if (!changedNode.checkbox)
223
- return; // don't see why this would happen, but if there is no checkbox, we cant do much here.
224
- const parentLayerId = undefined !== ((_a = parentNode.item.extendedData) === null || _a === void 0 ? void 0 : _a.subLayerId) ? (_b = parentNode.item.extendedData) === null || _b === void 0 ? void 0 : _b.subLayerId : parentNode.item.id;
225
- const parentSubLayer = (_c = this._mapLayer.subLayers) === null || _c === void 0 ? void 0 : _c.find((subLayer) => subLayer.id === parentLayerId);
226
- // If parent is disabled, then children must be too.
227
- // Also, Non-visible unnamed group must have their children disabled (unamed groups have visibility inherence)
228
- if (parentNode.checkbox.isDisabled || (SubLayerCheckboxHandler.isUnnamedGroup(parentSubLayer) && parentNode.checkbox.state === core_react_1.CheckBoxState.Off)) {
229
- changedNode.checkbox.isDisabled = true;
230
- changedNode.checkbox.state = core_react_1.CheckBoxState.Off;
231
- }
232
- else {
233
- // Visibility state from StyleMapLayerSettings applies
234
- const subLayerId = undefined !== ((_d = changedNode.item.extendedData) === null || _d === void 0 ? void 0 : _d.subLayerId) ? (_e = changedNode.item.extendedData) === null || _e === void 0 ? void 0 : _e.subLayerId : changedNode.item.id;
235
- const foundSubLayer = (_f = this._mapLayer.subLayers) === null || _f === void 0 ? void 0 : _f.find((subLayer) => subLayer.id === subLayerId);
236
- changedNode.checkbox.isDisabled = false;
237
- changedNode.checkbox.state = (foundSubLayer === null || foundSubLayer === void 0 ? void 0 : foundSubLayer.visible) ? core_react_1.CheckBoxState.On : core_react_1.CheckBoxState.Off;
238
- }
239
- }
240
- /** Changes nodes checkboxes states until event is handled or handler is disposed */
241
- onCheckboxStateChanged({ stateChanges }) {
242
- // call base checkbox handling
243
- const baseHandling = super.onCheckboxStateChanged({ stateChanges });
244
- // subscribe to checkbox state changes to new checkbox states and do some additional work with them
245
- const selectionHandling = stateChanges.subscribe({
246
- next: (changes) => {
247
- const vp = core_frontend_1.IModelApp.viewManager.selectedView;
248
- const displayStyle = vp === null || vp === void 0 ? void 0 : vp.displayStyle;
249
- const indexInDisplayStyle = displayStyle ? displayStyle.findMapLayerIndexByNameAndSource(this._mapLayer.name, this._mapLayer.source, this._mapLayer.isOverlay) : -1;
250
- changes.forEach((change) => {
251
- var _a, _b, _c, _d, _e;
252
- const isSelected = (change.newState === core_react_1.CheckBoxState.On);
253
- const subLayerId = undefined !== ((_a = change.nodeItem.extendedData) === null || _a === void 0 ? void 0 : _a.subLayerId) ? (_b = change.nodeItem.extendedData) === null || _b === void 0 ? void 0 : _b.subLayerId : change.nodeItem.id;
254
- // Get the previously visible node if any
255
- let prevVisibleLayer;
256
- if ((_c = this._mapLayer.provider) === null || _c === void 0 ? void 0 : _c.mutualExclusiveSubLayer) {
257
- prevVisibleLayer = (_d = this._mapLayer.subLayers) === null || _d === void 0 ? void 0 : _d.find((subLayer) => subLayer.visible && subLayer.id !== subLayerId);
258
- }
259
- // Update sublayer object, otherwise state would get out of sync with DisplayStyle each time the TreeView is re-rendered
260
- const foundSubLayer = (_e = this._mapLayer.subLayers) === null || _e === void 0 ? void 0 : _e.find((subLayer) => subLayer.id === subLayerId);
261
- if (foundSubLayer)
262
- foundSubLayer.visible = isSelected;
263
- if (prevVisibleLayer === null || prevVisibleLayer === void 0 ? void 0 : prevVisibleLayer.visible)
264
- prevVisibleLayer.visible = false;
265
- // Update displaystyle state
266
- if (-1 !== indexInDisplayStyle && displayStyle) {
267
- if (prevVisibleLayer && prevVisibleLayer.id !== undefined)
268
- displayStyle.changeMapSubLayerProps({ visible: false }, prevVisibleLayer.id, indexInDisplayStyle, this._mapLayer.isOverlay);
269
- displayStyle.changeMapSubLayerProps({ visible: isSelected }, subLayerId, indexInDisplayStyle, this._mapLayer.isOverlay);
270
- }
271
- // Cascade state
272
- this.modelSource.modifyModel((model) => {
273
- var _a;
274
- if ((_a = this._mapLayer.provider) === null || _a === void 0 ? void 0 : _a.mutualExclusiveSubLayer)
275
- this.applyMutualExclusiveState(model, change.nodeItem.id);
276
- this.cascadeStateToAllChildren(model, change.nodeItem.id);
277
- });
278
- });
279
- if (vp)
280
- vp.invalidateRenderPlan();
281
- },
282
- });
283
- // stop handling selection when checkboxes handling is stopped
284
- baseHandling === null || baseHandling === void 0 ? void 0 : baseHandling.add(selectionHandling);
285
- return baseHandling;
286
- }
287
- }
288
- /** Custom checkbox renderer that renders checkbox as an eye */
289
- const eyeCheckboxRenderer = (props) => (React.createElement(core_react_1.ImageCheckBox, { checked: props.checked, disabled: props.disabled, imageOn: "icon-visibility", imageOff: "icon-visibility-hide-2", onClick: props.onChange, tooltip: props.title }));
290
- /** Custom node renderer. It uses default 'TreeNodeRenderer' but overrides default checkbox renderer to render checkbox as an eye */
291
- const imageLoader = new components_react_1.TreeImageLoader();
292
- const nodeWithEyeCheckboxRenderer = (props) => (React.createElement(components_react_1.TreeNodeRenderer, { ...props, checkboxRenderer: eyeCheckboxRenderer, imageLoader: imageLoader }));
293
- /** Custom tree renderer. It uses default `TreeRenderer` but overrides default node renderer to render node with custom checkbox */
294
- const nodeWithEyeCheckboxTreeRenderer = (props) => (React.createElement(components_react_1.TreeRenderer, { ...props, nodeRenderer: nodeWithEyeCheckboxRenderer }));
295
- function useTreeFiltering(dataProvider, filter) {
296
- const nodeLoader = useFilteredProvider(dataProvider, filter);
297
- const nodeHighlightingProps = useNodeHighlightingProps(filter);
298
- return {
299
- nodeLoader,
300
- modelSource: nodeLoader.modelSource,
301
- nodeHighlightingProps,
302
- };
303
- }
304
- function useFilteredProvider(dataProvider, filter) {
305
- const filteredProvider = React.useMemo(() => {
306
- return new FilteredTreeDataProvider(dataProvider, filter);
307
- }, [dataProvider, filter]);
308
- const nodeLoader = React.useMemo(() => {
309
- return new components_react_1.TreeNodeLoader(filteredProvider, new components_react_1.TreeModelSource());
310
- }, [filteredProvider]);
311
- return nodeLoader;
312
- }
313
- function useNodeHighlightingProps(filter) {
314
- const [nodeHighlightingProps, setNodeHighlightingProps] = React.useState();
315
- React.useEffect(() => {
316
- if (filter === "") {
317
- setNodeHighlightingProps(undefined);
318
- return;
319
- }
320
- setNodeHighlightingProps({
321
- searchText: filter,
322
- activeMatch: undefined,
323
- });
324
- }, [filter]);
325
- return nodeHighlightingProps;
326
- }
327
- class FullTreeHierarchy {
328
- constructor(dataProvider) {
329
- this._hierarchy = new Map();
330
- this._dataProvider = dataProvider;
331
- this._init = (async () => {
332
- await this.initNode();
333
- })();
334
- }
335
- async initNode(parent) {
336
- const nodes = await this._dataProvider.getNodes(parent);
337
- this._hierarchy.set(parent === null || parent === void 0 ? void 0 : parent.id, nodes);
338
- for (const node of nodes) {
339
- await this.initNode(node);
340
- }
341
- }
342
- async getHierarchy() {
343
- await this._init;
344
- return this._hierarchy;
345
- }
346
- }
347
- class FilteredTreeHierarchy {
348
- constructor(dataProvider, filter) {
349
- this._filtered = new Map();
350
- this._fullHierarchy = new FullTreeHierarchy(dataProvider);
351
- this._filter = filter;
352
- this._init = (async () => {
353
- await this.init();
354
- })();
355
- }
356
- async init() {
357
- const hierarchy = await this._fullHierarchy.getHierarchy();
358
- if (this._filter === "") {
359
- this._filtered = hierarchy;
360
- return;
361
- }
362
- this.filterNodes(hierarchy);
363
- }
364
- /** Initializes `this._filtered` field. Returns a node if it matches a filter. */
365
- filterNodes(hierarchy, current) {
366
- const matches = current ? this.matchesFilter(current) : false;
367
- const children = hierarchy.get(current === null || current === void 0 ? void 0 : current.id);
368
- if (!children)
369
- return matches ? current : undefined;
370
- const matchedChildren = new Array();
371
- for (const child of children) {
372
- const matchedChild = this.filterNodes(hierarchy, child);
373
- matchedChild && matchedChildren.push(matchedChild);
374
- }
375
- const hasChildren = matchedChildren.length > 0;
376
- const included = matches || hasChildren;
377
- let filtered;
378
- if (included) {
379
- this._filtered.set(current === null || current === void 0 ? void 0 : current.id, matchedChildren);
380
- // Return a modified copy of current node (to persist initial hierarchy when filter is cleared).
381
- if (current) {
382
- filtered = {
383
- ...current,
384
- hasChildren,
385
- autoExpand: hasChildren ? true : current.autoExpand,
386
- };
387
- }
388
- }
389
- return filtered;
390
- }
391
- matchesFilter(node) {
392
- var _a;
393
- if (node.label.value.valueFormat !== appui_abstract_1.PropertyValueFormat.Primitive)
394
- return false;
395
- const value = (_a = node.label.value.displayValue) === null || _a === void 0 ? void 0 : _a.toLowerCase();
396
- if (!value)
397
- return false;
398
- return value.includes(this._filter.toLowerCase());
399
- }
400
- async getHierarchy() {
401
- await this._init;
402
- return this._filtered;
403
- }
404
- }
405
- class FilteredTreeDataProvider {
406
- constructor(parentDataProvider, filter) {
407
- this._hierarchy = new FilteredTreeHierarchy(parentDataProvider, filter);
408
- }
409
- async getNodes(parent) {
410
- const hierarchy = await this._hierarchy.getHierarchy();
411
- const nodes = hierarchy.get(parent === null || parent === void 0 ? void 0 : parent.id);
412
- return nodes || [];
413
- }
414
- async getNodesCount(parent) {
415
- const hierarchy = await this._hierarchy.getHierarchy();
416
- const nodes = hierarchy.get(parent === null || parent === void 0 ? void 0 : parent.id);
417
- return (nodes === null || nodes === void 0 ? void 0 : nodes.length) || 0;
418
- }
419
- }
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SubLayersTree = exports.SubLayersPanel = void 0;
4
+ /*---------------------------------------------------------------------------------------------
5
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
6
+ * See LICENSE.md in the project root for license terms and full copyright notice.
7
+ *--------------------------------------------------------------------------------------------*/
8
+ const appui_abstract_1 = require("@itwin/appui-abstract");
9
+ const components_react_1 = require("@itwin/components-react");
10
+ const core_common_1 = require("@itwin/core-common");
11
+ const core_frontend_1 = require("@itwin/core-frontend");
12
+ const core_react_1 = require("@itwin/core-react");
13
+ const itwinui_react_1 = require("@itwin/itwinui-react");
14
+ const React = require("react");
15
+ const SubLayersDataProvider_1 = require("./SubLayersDataProvider");
16
+ require("./SubLayersTree.scss");
17
+ const mapLayers_1 = require("../../mapLayers");
18
+ const getWindow = () => {
19
+ return typeof window === "undefined" ? undefined : window;
20
+ };
21
+ const useResizeObserver = (onResize) => {
22
+ const resizeObserver = React.useRef();
23
+ const elementRef = React.useCallback((element) => {
24
+ var _a, _b, _c;
25
+ if (!((_a = getWindow()) === null || _a === void 0 ? void 0 : _a.ResizeObserver)) {
26
+ return;
27
+ }
28
+ (_b = resizeObserver.current) === null || _b === void 0 ? void 0 : _b.disconnect();
29
+ if (element) {
30
+ resizeObserver.current = new ResizeObserver(([{ contentRect }]) => onResize(contentRect));
31
+ (_c = resizeObserver.current) === null || _c === void 0 ? void 0 : _c.observe(element);
32
+ }
33
+ }, [onResize]);
34
+ return [elementRef, resizeObserver.current];
35
+ };
36
+ /**
37
+ Mimic processing of `react-resize-detector` to return width and height.
38
+ * @internal
39
+ */
40
+ function useResizeDetector() {
41
+ const [width, setWidth] = React.useState();
42
+ const [height, setHeight] = React.useState();
43
+ const [ref] = useResizeObserver(React.useCallback((size) => {
44
+ setWidth(size.width);
45
+ setHeight(size.height);
46
+ }, []));
47
+ return { width, height, ref };
48
+ }
49
+ // eslint-disable-next-line @typescript-eslint/naming-convention
50
+ function Toolbar(props) {
51
+ return (React.createElement("div", { className: "map-manager-sublayer-tree-toolbar" },
52
+ React.createElement("div", { className: "tree-toolbar-action-buttons" }, props.children),
53
+ props.searchField && React.createElement("div", { className: "tree-toolbar-searchbox" }, props.searchField)));
54
+ }
55
+ // eslint-disable-next-line @typescript-eslint/naming-convention
56
+ function SubLayersPanel({ mapLayer, viewport }) {
57
+ const [noneAvailableLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:SubLayers.NoSubLayers"));
58
+ if (!viewport || (undefined === mapLayer.subLayers || 0 === mapLayer.subLayers.length)) {
59
+ return React.createElement("div", { className: "map-manager-sublayer-panel" },
60
+ React.createElement("div", null, noneAvailableLabel));
61
+ }
62
+ return (React.createElement(SubLayersTree, { mapLayer: mapLayer }));
63
+ }
64
+ exports.SubLayersPanel = SubLayersPanel;
65
+ function getSubLayerProps(subLayerSettings) {
66
+ return subLayerSettings.map((subLayer) => subLayer.toJSON());
67
+ }
68
+ function getStyleMapLayerSettings(settings, isOverlay, layerIndex, treeVisibility) {
69
+ return {
70
+ visible: settings.visible,
71
+ name: settings.name,
72
+ source: settings.source,
73
+ transparency: settings.transparency,
74
+ transparentBackground: settings.transparentBackground,
75
+ subLayers: settings.subLayers ? getSubLayerProps(settings.subLayers) : undefined,
76
+ showSubLayers: true,
77
+ isOverlay,
78
+ layerIndex,
79
+ provider: core_frontend_1.IModelApp.mapLayerFormatRegistry.createImageryProvider(settings),
80
+ treeVisibility,
81
+ };
82
+ }
83
+ /**
84
+ * Tree Control that displays sub-layer hierarchy
85
+ * @internal
86
+ */
87
+ // eslint-disable-next-line @typescript-eslint/naming-convention
88
+ function SubLayersTree(props) {
89
+ var _a;
90
+ const [placeholderLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:SubLayers.SearchPlaceholder"));
91
+ const [allOnLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:SubLayers.AllOn"));
92
+ const [allOffLabel] = React.useState(mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:SubLayers.AllOff"));
93
+ const [mapLayer, setMapLayer] = React.useState(props.mapLayer);
94
+ const [layerFilterString, setLayerFilterString] = React.useState("");
95
+ // create data provider to get some nodes to show in tree
96
+ // `React.useMemo' is used avoid creating new object on each render cycle
97
+ const dataProvider = React.useMemo(() => new SubLayersDataProvider_1.SubLayersDataProvider(mapLayer), [mapLayer]);
98
+ const { modelSource, nodeLoader, nodeHighlightingProps, } = useTreeFiltering(dataProvider, layerFilterString);
99
+ // create custom event handler. It handles all tree event same as `TreeEventHandler` but additionally
100
+ // it selects/deselects node when checkbox is checked/unchecked and vice versa.
101
+ // `useDisposable` takes care of disposing old event handler when new is created in case 'nodeLoader' has changed
102
+ // `React.useCallback` is used to avoid creating new callback that creates handler on each render
103
+ const eventHandler = (0, core_react_1.useDisposable)(React.useCallback(() => new SubLayerCheckboxHandler(mapLayer, nodeLoader), [nodeLoader, mapLayer]));
104
+ // Get an immutable tree model from the model source. The model is regenerated every time the model source
105
+ // emits the `onModelChanged` event.
106
+ const treeModel = (0, components_react_1.useTreeModel)(modelSource);
107
+ const showAll = React.useCallback(async () => {
108
+ const vp = core_frontend_1.IModelApp.viewManager.selectedView;
109
+ const displayStyle = vp === null || vp === void 0 ? void 0 : vp.displayStyle;
110
+ if (displayStyle && vp) {
111
+ const indexInDisplayStyle = displayStyle ? displayStyle.findMapLayerIndexByNameAndSource(mapLayer.name, mapLayer.source, mapLayer.isOverlay) : -1;
112
+ displayStyle.changeMapSubLayerProps({ visible: true }, -1, indexInDisplayStyle, mapLayer.isOverlay);
113
+ vp.invalidateRenderPlan();
114
+ const updatedMapLayer = displayStyle.mapLayerAtIndex(indexInDisplayStyle, mapLayer.isOverlay);
115
+ if (updatedMapLayer) {
116
+ if (updatedMapLayer instanceof core_common_1.ImageMapLayerSettings) {
117
+ const treeVisibility = vp.getMapLayerScaleRangeVisibility(indexInDisplayStyle, mapLayer.isOverlay);
118
+ setMapLayer(getStyleMapLayerSettings(updatedMapLayer, mapLayer.isOverlay, indexInDisplayStyle, treeVisibility));
119
+ }
120
+ }
121
+ }
122
+ }, [mapLayer]);
123
+ const hideAll = React.useCallback(async () => {
124
+ const vp = core_frontend_1.IModelApp.viewManager.selectedView;
125
+ const displayStyle = vp === null || vp === void 0 ? void 0 : vp.displayStyle;
126
+ if (displayStyle && vp) {
127
+ const indexInDisplayStyle = displayStyle ? displayStyle.findMapLayerIndexByNameAndSource(mapLayer.name, mapLayer.source, mapLayer.isOverlay) : -1;
128
+ displayStyle.changeMapSubLayerProps({ visible: false }, -1, indexInDisplayStyle, mapLayer.isOverlay);
129
+ const updatedMapLayer = displayStyle.mapLayerAtIndex(indexInDisplayStyle, mapLayer.isOverlay);
130
+ if (updatedMapLayer && updatedMapLayer instanceof core_common_1.ImageMapLayerSettings) {
131
+ const treeVisibility = vp.getMapLayerScaleRangeVisibility(indexInDisplayStyle, mapLayer.isOverlay);
132
+ setMapLayer(getStyleMapLayerSettings(updatedMapLayer, mapLayer.isOverlay, indexInDisplayStyle, treeVisibility));
133
+ }
134
+ vp.invalidateRenderPlan();
135
+ }
136
+ }, [mapLayer]);
137
+ const handleFilterTextChanged = React.useCallback((event) => {
138
+ setLayerFilterString(event.target.value);
139
+ }, []);
140
+ const { width, height, ref: containerRef } = useResizeDetector();
141
+ return React.createElement(React.Fragment, null,
142
+ React.createElement("div", { className: "map-manager-sublayer-tree" },
143
+ React.createElement(Toolbar, { searchField: React.createElement(itwinui_react_1.Input, { type: "text", className: "map-manager-source-list-filter", placeholder: placeholderLabel, value: layerFilterString, onChange: handleFilterTextChanged, size: "small" }) }, ((_a = mapLayer.provider) === null || _a === void 0 ? void 0 : _a.mutualExclusiveSubLayer) ? undefined : [
144
+ React.createElement(itwinui_react_1.Button, { size: "small", styleType: "borderless", key: "show-all-btn", title: allOnLabel, onClick: showAll },
145
+ React.createElement(core_react_1.WebFontIcon, { iconName: "icon-visibility" })),
146
+ React.createElement(itwinui_react_1.Button, { size: "small", styleType: "borderless", key: "hide-all-btn", title: allOffLabel, onClick: hideAll },
147
+ React.createElement(core_react_1.WebFontIcon, { iconName: "icon-visibility-hide-2" })),
148
+ ]),
149
+ React.createElement("div", { ref: containerRef, className: "map-manager-sublayer-tree-content" }, width !== undefined && height !== undefined && React.createElement(components_react_1.ControlledTree, { nodeLoader: nodeLoader, selectionMode: components_react_1.SelectionMode.None, eventsHandler: eventHandler, model: treeModel, treeRenderer: nodeWithEyeCheckboxTreeRenderer, nodeHighlightingProps: nodeHighlightingProps, width: width, height: height }))));
150
+ }
151
+ exports.SubLayersTree = SubLayersTree;
152
+ /** TreeEventHandler derived class that handler processing changes to subLayer visibility */
153
+ class SubLayerCheckboxHandler extends components_react_1.TreeEventHandler {
154
+ constructor(_mapLayer, nodeLoader) {
155
+ super({ modelSource: nodeLoader.modelSource, nodeLoader, collapsedChildrenDisposalEnabled: true });
156
+ this._mapLayer = _mapLayer;
157
+ //-----------------------------------------------------------------------
158
+ // Listen to model changes
159
+ //------------------------------------------------------------------------
160
+ // This is required because nodes are delay loaded in the model until
161
+ // they are made visible (i.e. parent node is expanded). So even though
162
+ // you might have created nodes in the data provided with a proper
163
+ // initial state, by the time it gets loaded, their state might have became
164
+ // out of date in the TreeView's active model. So whenever a node
165
+ // is added, when must confirm its state matches the current model
166
+ // (i.e. state of their parent.)
167
+ this.onModelChanged = (args) => {
168
+ this.modelSource.modifyModel((model) => {
169
+ const addedNodes = args[1].addedNodeIds.map((id) => model.getNode(id));
170
+ addedNodes.forEach((node) => {
171
+ if (!node)
172
+ return;
173
+ this.syncNodeStateWithParent(model, node);
174
+ });
175
+ });
176
+ };
177
+ this._removeModelChangedListener = this.modelSource.onModelChanged.addListener(this.onModelChanged);
178
+ }
179
+ dispose() {
180
+ this._removeModelChangedListener();
181
+ super.dispose();
182
+ }
183
+ // Cascade state
184
+ // Children on unnamed groups must get disabled in the tree view, because
185
+ // they get rendered anyway.
186
+ cascadeStateToAllChildren(model, parentId) {
187
+ const children = model.getChildren(parentId);
188
+ if (children === undefined)
189
+ return;
190
+ for (const childID of children) {
191
+ const childNode = childID ? model.getNode(childID) : undefined;
192
+ if (childNode)
193
+ this.syncNodeStateWithParent(model, childNode);
194
+ // Drill down the tree.
195
+ this.cascadeStateToAllChildren(model, childID);
196
+ }
197
+ }
198
+ applyMutualExclusiveState(model, nodeId) {
199
+ const changedNode = model.getNode(nodeId);
200
+ if ((changedNode === null || changedNode === void 0 ? void 0 : changedNode.checkbox.state) === core_react_1.CheckBoxState.Off)
201
+ return;
202
+ for (const node of model.iterateTreeModelNodes()) {
203
+ if (node.id === (changedNode === null || changedNode === void 0 ? void 0 : changedNode.id))
204
+ continue;
205
+ if (node && node.checkbox.state === core_react_1.CheckBoxState.On)
206
+ node.checkbox.state = core_react_1.CheckBoxState.Off;
207
+ }
208
+ }
209
+ static isUnnamedGroup(subLayer) {
210
+ if (!subLayer)
211
+ return false;
212
+ return (!subLayer.name || subLayer.name.length === 0) && (subLayer.children !== undefined && subLayer.children.length > 0);
213
+ }
214
+ // Ensure the state of changed node matches the state of its parent.
215
+ syncNodeStateWithParent(model, changedNode) {
216
+ var _a, _b, _c, _d, _e, _f;
217
+ // Lookup node parent. If non exists, I assume thats the root node,
218
+ // and it must have a proper initial state.
219
+ const parentNode = changedNode.parentId ? model.getNode(changedNode.parentId) : undefined;
220
+ if (!parentNode)
221
+ return;
222
+ if (!changedNode.checkbox)
223
+ return; // don't see why this would happen, but if there is no checkbox, we cant do much here.
224
+ const parentLayerId = undefined !== ((_a = parentNode.item.extendedData) === null || _a === void 0 ? void 0 : _a.subLayerId) ? (_b = parentNode.item.extendedData) === null || _b === void 0 ? void 0 : _b.subLayerId : parentNode.item.id;
225
+ const parentSubLayer = (_c = this._mapLayer.subLayers) === null || _c === void 0 ? void 0 : _c.find((subLayer) => subLayer.id === parentLayerId);
226
+ // If parent is disabled, then children must be too.
227
+ // Also, Non-visible unnamed group must have their children disabled (unamed groups have visibility inherence)
228
+ if (parentNode.checkbox.isDisabled || (SubLayerCheckboxHandler.isUnnamedGroup(parentSubLayer) && parentNode.checkbox.state === core_react_1.CheckBoxState.Off)) {
229
+ changedNode.checkbox.isDisabled = true;
230
+ changedNode.checkbox.state = core_react_1.CheckBoxState.Off;
231
+ }
232
+ else {
233
+ // Visibility state from StyleMapLayerSettings applies
234
+ const subLayerId = undefined !== ((_d = changedNode.item.extendedData) === null || _d === void 0 ? void 0 : _d.subLayerId) ? (_e = changedNode.item.extendedData) === null || _e === void 0 ? void 0 : _e.subLayerId : changedNode.item.id;
235
+ const foundSubLayer = (_f = this._mapLayer.subLayers) === null || _f === void 0 ? void 0 : _f.find((subLayer) => subLayer.id === subLayerId);
236
+ changedNode.checkbox.isDisabled = false;
237
+ changedNode.checkbox.state = (foundSubLayer === null || foundSubLayer === void 0 ? void 0 : foundSubLayer.visible) ? core_react_1.CheckBoxState.On : core_react_1.CheckBoxState.Off;
238
+ }
239
+ }
240
+ /** Changes nodes checkboxes states until event is handled or handler is disposed */
241
+ onCheckboxStateChanged({ stateChanges }) {
242
+ // call base checkbox handling
243
+ const baseHandling = super.onCheckboxStateChanged({ stateChanges });
244
+ // subscribe to checkbox state changes to new checkbox states and do some additional work with them
245
+ const selectionHandling = stateChanges.subscribe({
246
+ next: (changes) => {
247
+ const vp = core_frontend_1.IModelApp.viewManager.selectedView;
248
+ const displayStyle = vp === null || vp === void 0 ? void 0 : vp.displayStyle;
249
+ const indexInDisplayStyle = displayStyle ? displayStyle.findMapLayerIndexByNameAndSource(this._mapLayer.name, this._mapLayer.source, this._mapLayer.isOverlay) : -1;
250
+ changes.forEach((change) => {
251
+ var _a, _b, _c, _d, _e;
252
+ const isSelected = (change.newState === core_react_1.CheckBoxState.On);
253
+ const subLayerId = undefined !== ((_a = change.nodeItem.extendedData) === null || _a === void 0 ? void 0 : _a.subLayerId) ? (_b = change.nodeItem.extendedData) === null || _b === void 0 ? void 0 : _b.subLayerId : change.nodeItem.id;
254
+ // Get the previously visible node if any
255
+ let prevVisibleLayer;
256
+ if ((_c = this._mapLayer.provider) === null || _c === void 0 ? void 0 : _c.mutualExclusiveSubLayer) {
257
+ prevVisibleLayer = (_d = this._mapLayer.subLayers) === null || _d === void 0 ? void 0 : _d.find((subLayer) => subLayer.visible && subLayer.id !== subLayerId);
258
+ }
259
+ // Update sublayer object, otherwise state would get out of sync with DisplayStyle each time the TreeView is re-rendered
260
+ const foundSubLayer = (_e = this._mapLayer.subLayers) === null || _e === void 0 ? void 0 : _e.find((subLayer) => subLayer.id === subLayerId);
261
+ if (foundSubLayer)
262
+ foundSubLayer.visible = isSelected;
263
+ if (prevVisibleLayer === null || prevVisibleLayer === void 0 ? void 0 : prevVisibleLayer.visible)
264
+ prevVisibleLayer.visible = false;
265
+ // Update displaystyle state
266
+ if (-1 !== indexInDisplayStyle && displayStyle) {
267
+ if (prevVisibleLayer && prevVisibleLayer.id !== undefined)
268
+ displayStyle.changeMapSubLayerProps({ visible: false }, prevVisibleLayer.id, indexInDisplayStyle, this._mapLayer.isOverlay);
269
+ displayStyle.changeMapSubLayerProps({ visible: isSelected }, subLayerId, indexInDisplayStyle, this._mapLayer.isOverlay);
270
+ }
271
+ // Cascade state
272
+ this.modelSource.modifyModel((model) => {
273
+ var _a;
274
+ if ((_a = this._mapLayer.provider) === null || _a === void 0 ? void 0 : _a.mutualExclusiveSubLayer)
275
+ this.applyMutualExclusiveState(model, change.nodeItem.id);
276
+ this.cascadeStateToAllChildren(model, change.nodeItem.id);
277
+ });
278
+ });
279
+ if (vp)
280
+ vp.invalidateRenderPlan();
281
+ },
282
+ });
283
+ // stop handling selection when checkboxes handling is stopped
284
+ baseHandling === null || baseHandling === void 0 ? void 0 : baseHandling.add(selectionHandling);
285
+ return baseHandling;
286
+ }
287
+ }
288
+ /** Custom checkbox renderer that renders checkbox as an eye */
289
+ const eyeCheckboxRenderer = (props) => (React.createElement(core_react_1.ImageCheckBox, { checked: props.checked, disabled: props.disabled, imageOn: "icon-visibility", imageOff: "icon-visibility-hide-2", onClick: props.onChange, tooltip: props.title }));
290
+ /** Custom node renderer. It uses default 'TreeNodeRenderer' but overrides default checkbox renderer to render checkbox as an eye */
291
+ const imageLoader = new components_react_1.TreeImageLoader();
292
+ const nodeWithEyeCheckboxRenderer = (props) => (React.createElement(components_react_1.TreeNodeRenderer, { ...props, checkboxRenderer: eyeCheckboxRenderer, imageLoader: imageLoader }));
293
+ /** Custom tree renderer. It uses default `TreeRenderer` but overrides default node renderer to render node with custom checkbox */
294
+ const nodeWithEyeCheckboxTreeRenderer = (props) => (React.createElement(components_react_1.TreeRenderer, { ...props, nodeRenderer: nodeWithEyeCheckboxRenderer }));
295
+ function useTreeFiltering(dataProvider, filter) {
296
+ const nodeLoader = useFilteredProvider(dataProvider, filter);
297
+ const nodeHighlightingProps = useNodeHighlightingProps(filter);
298
+ return {
299
+ nodeLoader,
300
+ modelSource: nodeLoader.modelSource,
301
+ nodeHighlightingProps,
302
+ };
303
+ }
304
+ function useFilteredProvider(dataProvider, filter) {
305
+ const filteredProvider = React.useMemo(() => {
306
+ return new FilteredTreeDataProvider(dataProvider, filter);
307
+ }, [dataProvider, filter]);
308
+ const nodeLoader = React.useMemo(() => {
309
+ return new components_react_1.TreeNodeLoader(filteredProvider, new components_react_1.TreeModelSource());
310
+ }, [filteredProvider]);
311
+ return nodeLoader;
312
+ }
313
+ function useNodeHighlightingProps(filter) {
314
+ const [nodeHighlightingProps, setNodeHighlightingProps] = React.useState();
315
+ React.useEffect(() => {
316
+ if (filter === "") {
317
+ setNodeHighlightingProps(undefined);
318
+ return;
319
+ }
320
+ setNodeHighlightingProps({
321
+ searchText: filter,
322
+ activeMatch: undefined,
323
+ });
324
+ }, [filter]);
325
+ return nodeHighlightingProps;
326
+ }
327
+ class FullTreeHierarchy {
328
+ constructor(dataProvider) {
329
+ this._hierarchy = new Map();
330
+ this._dataProvider = dataProvider;
331
+ this._init = (async () => {
332
+ await this.initNode();
333
+ })();
334
+ }
335
+ async initNode(parent) {
336
+ const nodes = await this._dataProvider.getNodes(parent);
337
+ this._hierarchy.set(parent === null || parent === void 0 ? void 0 : parent.id, nodes);
338
+ for (const node of nodes) {
339
+ await this.initNode(node);
340
+ }
341
+ }
342
+ async getHierarchy() {
343
+ await this._init;
344
+ return this._hierarchy;
345
+ }
346
+ }
347
+ class FilteredTreeHierarchy {
348
+ constructor(dataProvider, filter) {
349
+ this._filtered = new Map();
350
+ this._fullHierarchy = new FullTreeHierarchy(dataProvider);
351
+ this._filter = filter;
352
+ this._init = (async () => {
353
+ await this.init();
354
+ })();
355
+ }
356
+ async init() {
357
+ const hierarchy = await this._fullHierarchy.getHierarchy();
358
+ if (this._filter === "") {
359
+ this._filtered = hierarchy;
360
+ return;
361
+ }
362
+ this.filterNodes(hierarchy);
363
+ }
364
+ /** Initializes `this._filtered` field. Returns a node if it matches a filter. */
365
+ filterNodes(hierarchy, current) {
366
+ const matches = current ? this.matchesFilter(current) : false;
367
+ const children = hierarchy.get(current === null || current === void 0 ? void 0 : current.id);
368
+ if (!children)
369
+ return matches ? current : undefined;
370
+ const matchedChildren = new Array();
371
+ for (const child of children) {
372
+ const matchedChild = this.filterNodes(hierarchy, child);
373
+ matchedChild && matchedChildren.push(matchedChild);
374
+ }
375
+ const hasChildren = matchedChildren.length > 0;
376
+ const included = matches || hasChildren;
377
+ let filtered;
378
+ if (included) {
379
+ this._filtered.set(current === null || current === void 0 ? void 0 : current.id, matchedChildren);
380
+ // Return a modified copy of current node (to persist initial hierarchy when filter is cleared).
381
+ if (current) {
382
+ filtered = {
383
+ ...current,
384
+ hasChildren,
385
+ autoExpand: hasChildren ? true : current.autoExpand,
386
+ };
387
+ }
388
+ }
389
+ return filtered;
390
+ }
391
+ matchesFilter(node) {
392
+ var _a;
393
+ if (node.label.value.valueFormat !== appui_abstract_1.PropertyValueFormat.Primitive)
394
+ return false;
395
+ const value = (_a = node.label.value.displayValue) === null || _a === void 0 ? void 0 : _a.toLowerCase();
396
+ if (!value)
397
+ return false;
398
+ return value.includes(this._filter.toLowerCase());
399
+ }
400
+ async getHierarchy() {
401
+ await this._init;
402
+ return this._filtered;
403
+ }
404
+ }
405
+ class FilteredTreeDataProvider {
406
+ constructor(parentDataProvider, filter) {
407
+ this._hierarchy = new FilteredTreeHierarchy(parentDataProvider, filter);
408
+ }
409
+ async getNodes(parent) {
410
+ const hierarchy = await this._hierarchy.getHierarchy();
411
+ const nodes = hierarchy.get(parent === null || parent === void 0 ? void 0 : parent.id);
412
+ return nodes || [];
413
+ }
414
+ async getNodesCount(parent) {
415
+ const hierarchy = await this._hierarchy.getHierarchy();
416
+ const nodes = hierarchy.get(parent === null || parent === void 0 ? void 0 : parent.id);
417
+ return (nodes === null || nodes === void 0 ? void 0 : nodes.length) || 0;
418
+ }
419
+ }
420
420
  //# sourceMappingURL=SubLayersTree.js.map