qwc2 2025.3.31
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/LICENSE +28 -0
- package/README.md +68 -0
- package/actions/display.js +7 -0
- package/actions/editing.js +7 -0
- package/actions/layerinfo.js +7 -0
- package/actions/layers.js +8 -0
- package/actions/localConfig.js +7 -0
- package/actions/locale.js +10 -0
- package/actions/locate.js +8 -0
- package/actions/logging.js +7 -0
- package/actions/map.js +15 -0
- package/actions/measurement.js +8 -0
- package/actions/processNotifications.js +7 -0
- package/actions/redlining.js +7 -0
- package/actions/redliningPick.js +7 -0
- package/actions/serviceinfo.js +7 -0
- package/actions/task.js +9 -0
- package/actions/theme.js +24 -0
- package/actions/windows.js +10 -0
- package/components/AppMenu.js +8 -0
- package/components/AttributeForm.js +34 -0
- package/components/AutoEditForm.js +8 -0
- package/components/CoordinateDisplayer.js +7 -0
- package/components/EditComboField.js +10 -0
- package/components/EditUploadField.js +8 -0
- package/components/FullscreenSwitcher.js +8 -0
- package/components/Icon.js +7 -0
- package/components/IdentifyViewer.js +16 -0
- package/components/ImportLayer.js +25 -0
- package/components/LayerInfoWindow.js +7 -0
- package/components/LinkFeatureForm.js +10 -0
- package/components/MapSelection.js +13 -0
- package/components/NumericInputWindow.js +7 -0
- package/components/PickFeature.js +7 -0
- package/components/PluginsContainer.js +8 -0
- package/components/PrintSelection.js +54 -0
- package/components/QtDesignerForm.js +30 -0
- package/components/ResizeableWindow.js +12 -0
- package/components/SearchBox.js +26 -0
- package/components/ServiceInfoWindow.js +7 -0
- package/components/SideBar.js +9 -0
- package/components/StandardApp.js +35 -0
- package/components/Swipeable.js +1 -0
- package/components/TaskBar.js +7 -0
- package/components/ThemeLayersListWindow.js +9 -0
- package/components/ThemeList.js +12 -0
- package/components/Toolbar.js +7 -0
- package/components/WindowManager.js +7 -0
- package/components/map/OlLayer.js +12 -0
- package/components/map/OlLocate.css +56 -0
- package/components/map/OlLocate.js +17 -0
- package/components/map/OlMap.js +11 -0
- package/components/map/layers/BingLayer.js +8 -0
- package/components/map/layers/GoogleLayer.js +27 -0
- package/components/map/layers/GraticuleLayer.js +8 -0
- package/components/map/layers/ImageLayer.js +8 -0
- package/components/map/layers/MVTLayer.js +7 -0
- package/components/map/layers/OSMLayer.js +8 -0
- package/components/map/layers/OverlayLayer.js +10 -0
- package/components/map/layers/VectorLayer.js +14 -0
- package/components/map/layers/WFSLayer.js +11 -0
- package/components/map/layers/WMSLayer.js +11 -0
- package/components/map/layers/WMTSLayer.js +9 -0
- package/components/map/layers/XYZLayer.js +7 -0
- package/components/map/layers/index.js +8 -0
- package/components/map3d/BottomBar3D.js +7 -0
- package/components/map3d/Compare3D.js +12 -0
- package/components/map3d/Draw3D.js +10 -0
- package/components/map3d/ExportObjects3D.js +17 -0
- package/components/map3d/HeightProfile3D.js +8 -0
- package/components/map3d/HideObjects3D.js +12 -0
- package/components/map3d/Identify3D.js +13 -0
- package/components/map3d/LayerTree3D.js +8 -0
- package/components/map3d/Map3D.js +29 -0
- package/components/map3d/Map3DLight.js +10 -0
- package/components/map3d/MapControls3D.js +20 -0
- package/components/map3d/MapExport3D.js +11 -0
- package/components/map3d/Measure3D.js +23 -0
- package/components/map3d/OverviewMap3D.js +9 -0
- package/components/map3d/SearchField3D.js +16 -0
- package/components/map3d/TopBar3D.js +7 -0
- package/components/map3d/View3DSwitcher.js +7 -0
- package/components/map3d/drawtool/CreateTool3D.js +9 -0
- package/components/map3d/drawtool/EditTool3D.js +9 -0
- package/components/map3d/drawtool/NumericInput3D.js +7 -0
- package/components/map3d/img/viewcone.svg +124 -0
- package/components/map3d/layers/VectorLayer3D.js +7 -0
- package/components/map3d/layers/WFSLayer3D.js +8 -0
- package/components/map3d/layers/WMSLayer3D.js +7 -0
- package/components/map3d/layers/WMTSLayer3D.js +9 -0
- package/components/map3d/layers/index.js +8 -0
- package/components/map3d/models/arrow.glb +0 -0
- package/components/map3d/models/pin.glb +0 -0
- package/components/map3d/slices/map3d.js +1 -0
- package/components/map3d/style/BottomBar3D.css +67 -0
- package/components/map3d/style/Compare3D.css +57 -0
- package/components/map3d/style/Draw3D.css +7 -0
- package/components/map3d/style/HideObjects3D.css +29 -0
- package/components/map3d/style/LayerTree3D.css +126 -0
- package/components/map3d/style/Map3D.css +42 -0
- package/components/map3d/style/Map3DLight.css +72 -0
- package/components/map3d/style/MapControls3D.css +56 -0
- package/components/map3d/style/MapExport3D.css +25 -0
- package/components/map3d/style/OverviewMap3D.css +37 -0
- package/components/map3d/style/SearchField3D.css +7 -0
- package/components/map3d/style/View3DSwitcher.css +27 -0
- package/components/map3d/utils/Tiles3DStyle.js +1 -0
- package/components/share/ShareLink.js +7 -0
- package/components/share/ShareQRCode.js +8 -0
- package/components/share/ShareSocials.js +9 -0
- package/components/share/style/ShareLink.css +13 -0
- package/components/share/style/ShareSocials.css +9 -0
- package/components/style/App.css +229 -0
- package/components/style/AppMenu.css +162 -0
- package/components/style/AttributeForm.css +57 -0
- package/components/style/AutoEditForm.css +64 -0
- package/components/style/DefaultColorScheme.css +60 -0
- package/components/style/EditUploadField.css +103 -0
- package/components/style/FullscreenSwitcher.css +25 -0
- package/components/style/Icon.css +26 -0
- package/components/style/IdentifyViewer.css +249 -0
- package/components/style/ImportLayer.css +28 -0
- package/components/style/LayerInfoWindow.css +46 -0
- package/components/style/LinkFeatureForm.css +48 -0
- package/components/style/NumericInputWindow.css +11 -0
- package/components/style/PickFeature.css +25 -0
- package/components/style/PluginsContainer.css +4 -0
- package/components/style/QtDesignerForm.css +225 -0
- package/components/style/ResizeableWindow.css +178 -0
- package/components/style/SearchBox.css +159 -0
- package/components/style/ServiceInfoWindow.css +34 -0
- package/components/style/SideBar.css +100 -0
- package/components/style/TaskBar.css +35 -0
- package/components/style/ThemeLayersListWindow.css +47 -0
- package/components/style/ThemeList.css +200 -0
- package/components/style/Toolbar.css +20 -0
- package/components/style/WindowManager.css +50 -0
- package/components/timeline/FixedTimeline.js +10 -0
- package/components/timeline/InfiniteTimeline.js +13 -0
- package/components/timeline/TimelineFeaturesSlider.js +10 -0
- package/components/timeline/style/FixedTimeline.css +76 -0
- package/components/timeline/style/InfiniteTimeline.css +94 -0
- package/components/timeline/style/TimelineFeaturesSlider.css +131 -0
- package/components/widgets/AccordeonWidget.js +7 -0
- package/components/widgets/ButtonBar.js +7 -0
- package/components/widgets/ColorButton.js +8 -0
- package/components/widgets/ComboBox.js +7 -0
- package/components/widgets/CopyButton.js +7 -0
- package/components/widgets/DateTimeInput.js +8 -0
- package/components/widgets/EditableSelect.js +8 -0
- package/components/widgets/FileSelector.js +9 -0
- package/components/widgets/Input.js +7 -0
- package/components/widgets/InputContainer.js +7 -0
- package/components/widgets/LayerCatalogWidget.js +3 -0
- package/components/widgets/MenuButton.js +1 -0
- package/components/widgets/ModalDialog.js +7 -0
- package/components/widgets/NavBar.js +7 -0
- package/components/widgets/NumberInput.js +9 -0
- package/components/widgets/PopupMenu.js +1 -0
- package/components/widgets/Primitives.js +7 -0
- package/components/widgets/ReCaptchaWidget.js +1 -0
- package/components/widgets/SearchWidget.js +7 -0
- package/components/widgets/Spinner.js +6 -0
- package/components/widgets/SuggestionInput.js +7 -0
- package/components/widgets/TextInput.js +7 -0
- package/components/widgets/ToggleSwitch.js +7 -0
- package/components/widgets/VectorLayerPicker.js +8 -0
- package/components/widgets/style/AccordeonWidget.css +22 -0
- package/components/widgets/style/ButtonBar.css +88 -0
- package/components/widgets/style/ColorButton.css +88 -0
- package/components/widgets/style/ComboBox.css +83 -0
- package/components/widgets/style/CopyButton.css +21 -0
- package/components/widgets/style/EditableSelect.css +47 -0
- package/components/widgets/style/FileSelector.css +14 -0
- package/components/widgets/style/InputContainer.css +34 -0
- package/components/widgets/style/LayerCatalogWidget.css +59 -0
- package/components/widgets/style/MenuButton.css +122 -0
- package/components/widgets/style/ModalDialog.css +50 -0
- package/components/widgets/style/NavBar.css +12 -0
- package/components/widgets/style/NumberInput.css +76 -0
- package/components/widgets/style/SearchWidget.css +43 -0
- package/components/widgets/style/Spinner.css +32 -0
- package/components/widgets/style/SuggestionInput.css +8 -0
- package/components/widgets/style/TextInput.css +94 -0
- package/components/widgets/style/ToggleSwitch.css +61 -0
- package/components/widgets/style/VectorLayerPicker.css +3 -0
- package/icons/2d.svg +70 -0
- package/icons/3d.svg +70 -0
- package/icons/3d2d.svg +92 -0
- package/icons/after.svg +76 -0
- package/icons/arrow-down.svg +60 -0
- package/icons/arrow-up.svg +60 -0
- package/icons/before.svg +76 -0
- package/icons/bglayer.svg +71 -0
- package/icons/bookmark.svg +170 -0
- package/icons/box.svg +63 -0
- package/icons/buffer.svg +67 -0
- package/icons/camera.svg +118 -0
- package/icons/catalog.svg +62 -0
- package/icons/checked.svg +80 -0
- package/icons/chevron-down.svg +60 -0
- package/icons/chevron-left.svg +59 -0
- package/icons/chevron-right.svg +60 -0
- package/icons/chevron-up.svg +60 -0
- package/icons/circle.svg +70 -0
- package/icons/clear.svg +62 -0
- package/icons/clock.svg +71 -0
- package/icons/cog.svg +60 -0
- package/icons/collapse.svg +73 -0
- package/icons/compare.svg +72 -0
- package/icons/cone.svg +58 -0
- package/icons/confirm.svg +62 -0
- package/icons/copy.svg +60 -0
- package/icons/cuboid.svg +58 -0
- package/icons/cyclomedia.svg +47 -0
- package/icons/cylinder.svg +58 -0
- package/icons/dataimport.svg +116 -0
- package/icons/detach.svg +79 -0
- package/icons/dock.svg +82 -0
- package/icons/dock_bottom.svg +82 -0
- package/icons/dock_left.svg +84 -0
- package/icons/dock_right.svg +84 -0
- package/icons/dock_top.svg +84 -0
- package/icons/draw.svg +78 -0
- package/icons/editdraw.svg +84 -0
- package/icons/edited.svg +78 -0
- package/icons/editing.svg +118 -0
- package/icons/ellipse.svg +72 -0
- package/icons/embed.svg +88 -0
- package/icons/expand.svg +73 -0
- package/icons/export.svg +126 -0
- package/icons/eye.svg +127 -0
- package/icons/featureform.svg +115 -0
- package/icons/fill.svg +62 -0
- package/icons/filter.svg +69 -0
- package/icons/folder-open.svg +60 -0
- package/icons/freehand.svg +82 -0
- package/icons/group.svg +76 -0
- package/icons/home.svg +60 -0
- package/icons/identify_radius.svg +71 -0
- package/icons/identify_region.svg +71 -0
- package/icons/import.svg +62 -0
- package/icons/info-sign.svg +60 -0
- package/icons/info.svg +80 -0
- package/icons/layers.svg +71 -0
- package/icons/light.svg +77 -0
- package/icons/line.svg +61 -0
- package/icons/line_buffer.svg +65 -0
- package/icons/link.svg +75 -0
- package/icons/list-alt.svg +111 -0
- package/icons/lock.svg +54 -0
- package/icons/login.svg +56 -0
- package/icons/logout.svg +56 -0
- package/icons/map3d.svg +51 -0
- package/icons/maximize.svg +84 -0
- package/icons/measure.svg +82 -0
- package/icons/measure_line.svg +87 -0
- package/icons/measure_polygon.svg +88 -0
- package/icons/menu-hamburger.svg +60 -0
- package/icons/minimize.svg +76 -0
- package/icons/minus-sign.svg +60 -0
- package/icons/minus.svg +61 -0
- package/icons/nav-end.svg +74 -0
- package/icons/nav-left.svg +74 -0
- package/icons/nav-right.svg +74 -0
- package/icons/nav-start.svg +73 -0
- package/icons/new.svg +84 -0
- package/icons/nodetool.svg +68 -0
- package/icons/numericinput.svg +86 -0
- package/icons/ok.svg +60 -0
- package/icons/open.svg +79 -0
- package/icons/open_link.svg +74 -0
- package/icons/paint.svg +75 -0
- package/icons/pen.svg +41 -0
- package/icons/person.svg +44 -0
- package/icons/pick.svg +67 -0
- package/icons/pick_point.svg +74 -0
- package/icons/pick_region.svg +71 -0
- package/icons/plus.svg +60 -0
- package/icons/point.svg +67 -0
- package/icons/point_buffer.svg +74 -0
- package/icons/polygon.svg +61 -0
- package/icons/print.svg +60 -0
- package/icons/pyramid.svg +58 -0
- package/icons/radio_checked.svg +78 -0
- package/icons/radio_tristate.svg +75 -0
- package/icons/radio_unchecked.svg +72 -0
- package/icons/rasterexport.svg +124 -0
- package/icons/rect.svg +63 -0
- package/icons/refresh.svg +44 -0
- package/icons/remove.svg +60 -0
- package/icons/report.svg +84 -0
- package/icons/routing-bicycle.svg +40 -0
- package/icons/routing-bus.svg +40 -0
- package/icons/routing-cablecar.svg +40 -0
- package/icons/routing-car.svg +40 -0
- package/icons/routing-ship.svg +40 -0
- package/icons/routing-train.svg +40 -0
- package/icons/routing-tram.svg +40 -0
- package/icons/routing-truck.svg +40 -0
- package/icons/routing-walking.svg +40 -0
- package/icons/routing.svg +68 -0
- package/icons/save.svg +190 -0
- package/icons/scale.svg +62 -0
- package/icons/screenshot.svg +60 -0
- package/icons/search.svg +60 -0
- package/icons/selectbox.svg +79 -0
- package/icons/share.svg +64 -0
- package/icons/snap_edge.svg +79 -0
- package/icons/snap_vertex.svg +79 -0
- package/icons/sphere.svg +58 -0
- package/icons/square.svg +68 -0
- package/icons/sync.svg +72 -0
- package/icons/text.svg +68 -0
- package/icons/themes.svg +81 -0
- package/icons/tilt-down.svg +67 -0
- package/icons/tilt-left.svg +48 -0
- package/icons/tilt-right.svg +48 -0
- package/icons/tilt-up.svg +67 -0
- package/icons/today.svg +45 -0
- package/icons/tools.svg +77 -0
- package/icons/transformtool.svg +74 -0
- package/icons/transparency.svg +132 -0
- package/icons/trash.svg +60 -0
- package/icons/tree_minus.svg +81 -0
- package/icons/tree_plus.svg +81 -0
- package/icons/triangle-down.svg +59 -0
- package/icons/triangle-left.svg +60 -0
- package/icons/triangle-right.svg +60 -0
- package/icons/triangle-up.svg +59 -0
- package/icons/tristate.svg +79 -0
- package/icons/unchecked.svg +74 -0
- package/icons/undock.svg +82 -0
- package/icons/undock_bottom.svg +82 -0
- package/icons/undock_left.svg +82 -0
- package/icons/undock_right.svg +84 -0
- package/icons/undock_top.svg +84 -0
- package/icons/unmaximize.svg +84 -0
- package/icons/unminimize.svg +76 -0
- package/icons/up-down-arrow.svg +66 -0
- package/icons/warning.svg +72 -0
- package/icons/wedge.svg +58 -0
- package/icons/zoom.svg +60 -0
- package/icons/zoomin.svg +71 -0
- package/icons/zoomout.svg +80 -0
- package/libs/openlayers.js +11 -0
- package/package.json +135 -0
- package/plugins/API.js +114 -0
- package/plugins/AttributeTable.js +25 -0
- package/plugins/Authentication.js +13 -0
- package/plugins/BackgroundSwitcher.js +10 -0
- package/plugins/Bookmark.js +13 -0
- package/plugins/BottomBar.js +10 -0
- package/plugins/CookiePopup.js +9 -0
- package/plugins/Cyclomedia.js +11 -0
- package/plugins/Editing.js +21 -0
- package/plugins/FeatureForm.js +21 -0
- package/plugins/FeatureSearch.js +11 -0
- package/plugins/GeometryDigitizer.js +43 -0
- package/plugins/HeightProfile.js +26 -0
- package/plugins/Help.js +11 -0
- package/plugins/HomeButton.js +9 -0
- package/plugins/Identify.js +18 -0
- package/plugins/LayerCatalog.js +45 -0
- package/plugins/LayerTree.js +15 -0
- package/plugins/LocateButton.js +10 -0
- package/plugins/Map.js +22 -0
- package/plugins/MapCompare.js +11 -0
- package/plugins/MapCopyright.js +11 -0
- package/plugins/MapExport.js +23 -0
- package/plugins/MapFilter.js +20 -0
- package/plugins/MapInfoTooltip.js +32 -0
- package/plugins/MapLegend.js +14 -0
- package/plugins/MapTip.js +15 -0
- package/plugins/Measure.js +10 -0
- package/plugins/NewsPopup.js +12 -0
- package/plugins/Panoramax.js +10 -0
- package/plugins/Portal.js +10 -0
- package/plugins/Print.js +22 -0
- package/plugins/ProcessNotifications.js +11 -0
- package/plugins/Redlining.js +12 -0
- package/plugins/Reports.js +15 -0
- package/plugins/Routing.js +23 -0
- package/plugins/ScratchDrawing.js +15 -0
- package/plugins/Settings.js +12 -0
- package/plugins/Share.js +11 -0
- package/plugins/StartupMarker.js +12 -0
- package/plugins/TaskButton.js +9 -0
- package/plugins/ThemeSwitcher.js +10 -0
- package/plugins/TimeManager.js +21 -0
- package/plugins/TopBar.js +13 -0
- package/plugins/ValueTool.js +11 -0
- package/plugins/View3D.js +34 -0
- package/plugins/ZoomButtons.js +11 -0
- package/plugins/map/EditingSupport.js +13 -0
- package/plugins/map/LocateSupport.js +14 -0
- package/plugins/map/MeasurementSupport.js +15 -0
- package/plugins/map/OverviewSupport.js +14 -0
- package/plugins/map/RedliningPickSupport.js +12 -0
- package/plugins/map/RedliningSupport.js +28 -0
- package/plugins/map/ScaleBarSupport.js +10 -0
- package/plugins/map/SnapInteraction.js +1 -0
- package/plugins/map/SnapSupport.js +7 -0
- package/plugins/map/SnappingSupport.js +23 -0
- package/plugins/map/style/OverviewSupport.css +42 -0
- package/plugins/map/style/ScaleBarSupport.css +18 -0
- package/plugins/map/style/SnappingSupport.css +33 -0
- package/plugins/redlining/RedliningBufferSupport.js +8 -0
- package/plugins/style/AttributeTable.css +220 -0
- package/plugins/style/Authentication.css +16 -0
- package/plugins/style/BackgroundSwitcher.css +99 -0
- package/plugins/style/Bookmark.css +62 -0
- package/plugins/style/BottomBar.css +53 -0
- package/plugins/style/Buttons.css +68 -0
- package/plugins/style/CookiePopup.css +24 -0
- package/plugins/style/Cyclomedia.css +66 -0
- package/plugins/style/Editing.css +40 -0
- package/plugins/style/FeatureForm.css +21 -0
- package/plugins/style/FeatureSearch.css +71 -0
- package/plugins/style/GeometryDigitizer.css +28 -0
- package/plugins/style/HeightProfile.css +26 -0
- package/plugins/style/Identify.css +4 -0
- package/plugins/style/LayerCatalog.css +8 -0
- package/plugins/style/LayerTree.css +316 -0
- package/plugins/style/Map.css +43 -0
- package/plugins/style/MapCompare.css +27 -0
- package/plugins/style/MapCopyright.css +17 -0
- package/plugins/style/MapExport.css +55 -0
- package/plugins/style/MapFilter.css +101 -0
- package/plugins/style/MapInfoTooltip.css +78 -0
- package/plugins/style/MapLegend.css +36 -0
- package/plugins/style/MapTip.css +22 -0
- package/plugins/style/Measure.css +23 -0
- package/plugins/style/NewsPopup.css +87 -0
- package/plugins/style/Panoramax.css +15 -0
- package/plugins/style/Portal.css +115 -0
- package/plugins/style/Print.css +116 -0
- package/plugins/style/ProcessNotifications.css +55 -0
- package/plugins/style/Redlining.css +101 -0
- package/plugins/style/Reports.css +11 -0
- package/plugins/style/Routing.css +243 -0
- package/plugins/style/ScratchDrawing.css +8 -0
- package/plugins/style/Settings.css +11 -0
- package/plugins/style/Share.css +59 -0
- package/plugins/style/ThemeSwitcher.css +7 -0
- package/plugins/style/TimeManager.css +91 -0
- package/plugins/style/TopBar.css +50 -0
- package/plugins/style/ValueTool.css +60 -0
- package/reducers/display.js +7 -0
- package/reducers/editing.js +8 -0
- package/reducers/index.js +7 -0
- package/reducers/layerinfo.js +7 -0
- package/reducers/layers.js +14 -0
- package/reducers/localConfig.js +8 -0
- package/reducers/locale.js +8 -0
- package/reducers/locate.js +8 -0
- package/reducers/map.js +11 -0
- package/reducers/measurement.js +8 -0
- package/reducers/processNotifications.js +7 -0
- package/reducers/redlining.js +7 -0
- package/reducers/redliningPick.js +7 -0
- package/reducers/serviceinfo.js +7 -0
- package/reducers/task.js +7 -0
- package/reducers/theme.js +7 -0
- package/reducers/windows.js +7 -0
- package/scripts/dist.sh +16 -0
- package/scripts/gen-plugin-docs.js +9 -0
- package/scripts/makeIconkit.js +7 -0
- package/scripts/package-commands.bat +8 -0
- package/scripts/package-commands.sh +22 -0
- package/scripts/themesConfig.js +48 -0
- package/scripts/themesConfig.py +659 -0
- package/scripts/translateui.sh +51 -0
- package/scripts/updateTranslations.js +17 -0
- package/scripts/wmts_config_generator.py +169 -0
- package/selectors/searchproviders.js +12 -0
- package/static/translations/bg-BG.json +709 -0
- package/static/translations/ca-ES.json +709 -0
- package/static/translations/cs-CZ.json +709 -0
- package/static/translations/de-CH.json +709 -0
- package/static/translations/de-DE.json +709 -0
- package/static/translations/en-US.json +709 -0
- package/static/translations/es-ES.json +709 -0
- package/static/translations/fi-FI.json +709 -0
- package/static/translations/fr-FR.json +709 -0
- package/static/translations/hu-HU.json +709 -0
- package/static/translations/it-IT.json +709 -0
- package/static/translations/ja-JP.json +709 -0
- package/static/translations/nl-NL.json +709 -0
- package/static/translations/no-NO.json +709 -0
- package/static/translations/pl-PL.json +709 -0
- package/static/translations/pt-BR.json +709 -0
- package/static/translations/pt-PT.json +709 -0
- package/static/translations/ro-RO.json +709 -0
- package/static/translations/ru-RU.json +709 -0
- package/static/translations/sv-SE.json +709 -0
- package/static/translations/tr-TR.json +709 -0
- package/static/translations/tsconfig.json +606 -0
- package/stores/StandardStore.js +8 -0
- package/utils/ConfigUtils.js +9 -0
- package/utils/CoordinatesUtils.js +29 -0
- package/utils/DxfUtils.js +10 -0
- package/utils/EditingInterface.js +67 -0
- package/utils/EditingUtils.js +11 -0
- package/utils/FeatureStyles.js +10 -0
- package/utils/IdentifyUtils.js +12 -0
- package/utils/ImageEditor.js +15 -0
- package/utils/LayerUtils.js +57 -0
- package/utils/LocaleUtils.js +9 -0
- package/utils/MapUtils.js +66 -0
- package/utils/MeasureUtils.js +9 -0
- package/utils/MiscUtils.js +15 -0
- package/utils/PermaLinkUtils.js +11 -0
- package/utils/ResourceRegistry.js +7 -0
- package/utils/RoutingInterface.js +12 -0
- package/utils/SearchProviders.js +19 -0
- package/utils/ServiceLayerUtils.js +20 -0
- package/utils/Signal.js +2 -0
- package/utils/ThemeUtils.js +12 -0
- package/utils/VectorLayerUtils.js +20 -0
- package/utils/expr_grammar/README.md +3 -0
- package/utils/expr_grammar/grammar.js +3 -0
- package/utils/expr_grammar/grammar.ne +118 -0
- package/utils/expr_grammar/test.js +13 -0
- package/utils/img/README.markers +1 -0
- package/utils/img/arrowhead.svg +4 -0
- package/utils/img/marker-icon.png +0 -0
- package/utils/img/measurehead.svg +4 -0
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
#!/bin/python
|
|
2
|
+
|
|
3
|
+
# Copyright 2017-2024 Sourcepole AG
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# This source code is licensed under the BSD-style license found in the
|
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
try:
|
|
11
|
+
from urllib import request
|
|
12
|
+
except:
|
|
13
|
+
import urllib2 as request
|
|
14
|
+
try:
|
|
15
|
+
from urllib.parse import quote, urljoin, urlparse, parse_qsl, urlencode, urlunparse
|
|
16
|
+
except:
|
|
17
|
+
from urllib import quote
|
|
18
|
+
from urlparse import urljoin
|
|
19
|
+
from xml.dom.minidom import parseString
|
|
20
|
+
import json
|
|
21
|
+
import traceback
|
|
22
|
+
import socket
|
|
23
|
+
import re
|
|
24
|
+
import uuid
|
|
25
|
+
|
|
26
|
+
baseUrl = "http://" + socket.getfqdn()
|
|
27
|
+
qwc2_path = "."
|
|
28
|
+
themesConfig = os.environ.get("QWC2_THEMES_CONFIG", "static/themesConfig.json")
|
|
29
|
+
|
|
30
|
+
usedThemeIds = []
|
|
31
|
+
autogenExternalLayers = []
|
|
32
|
+
|
|
33
|
+
def uniqueThemeId(themeName):
|
|
34
|
+
if not themeName:
|
|
35
|
+
return str(uuid.uuid1())
|
|
36
|
+
if themeName in usedThemeIds:
|
|
37
|
+
i = 1
|
|
38
|
+
while ("%s%d") % (themeName, i) in usedThemeIds:
|
|
39
|
+
i += 1
|
|
40
|
+
usedThemeIds.append(("%s%d") % (themeName, i))
|
|
41
|
+
return usedThemeIds[-1]
|
|
42
|
+
else:
|
|
43
|
+
usedThemeIds.append(themeName)
|
|
44
|
+
return usedThemeIds[-1]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def getUrlOpener(configItem):
|
|
48
|
+
auth = configItem.get('wmsBasicAuth')
|
|
49
|
+
if auth:
|
|
50
|
+
manager = request.HTTPPasswordMgrWithDefaultRealm()
|
|
51
|
+
manager.add_password(None, configItem["url"], auth['username'], auth['password'])
|
|
52
|
+
auth_handler = request.HTTPBasicAuthHandler(manager)
|
|
53
|
+
opener = request.build_opener(auth_handler).open
|
|
54
|
+
else:
|
|
55
|
+
opener = request.urlopen
|
|
56
|
+
return opener
|
|
57
|
+
|
|
58
|
+
def update_params(url,params):
|
|
59
|
+
url_parse = urlparse(url)
|
|
60
|
+
query = url_parse.query
|
|
61
|
+
url_dict = dict(parse_qsl(query))
|
|
62
|
+
url_dict.update(params)
|
|
63
|
+
url_new_query = urlencode(url_dict)
|
|
64
|
+
new_url = url_parse._replace(query=url_new_query).geturl()
|
|
65
|
+
return new_url
|
|
66
|
+
|
|
67
|
+
# load thumbnail from file or GetMap
|
|
68
|
+
def getThumbnail(configItem, resultItem, layers, crs, extent):
|
|
69
|
+
if "thumbnail" in configItem:
|
|
70
|
+
if os.path.exists(qwc2_path + "/static/assets/img/mapthumbs/" + configItem["thumbnail"]):
|
|
71
|
+
resultItem["thumbnail"] = "img/mapthumbs/" + configItem["thumbnail"]
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
print("Using WMS GetMap to generate thumbnail for " + configItem["url"])
|
|
75
|
+
|
|
76
|
+
# WMS GetMap request
|
|
77
|
+
url = update_params(urljoin(baseUrl, configItem["url"]), {'SERVICE': 'WMS', 'VERSION': '1.3.0', 'REQUEST': 'GetMap', 'FORMAT': 'image/png', 'STYLES': '', 'WIDTH': '200', 'HEIGHT': '100', 'CRS': crs})
|
|
78
|
+
bboxw = extent[2] - extent[0]
|
|
79
|
+
bboxh = extent[3] - extent[1]
|
|
80
|
+
bboxcx = 0.5 * (extent[0] + extent[2])
|
|
81
|
+
bboxcy = 0.5 * (extent[1] + extent[3])
|
|
82
|
+
imgratio = 200. / 100.
|
|
83
|
+
if bboxw > bboxh:
|
|
84
|
+
bboxratio = bboxw / bboxh
|
|
85
|
+
if bboxratio > imgratio:
|
|
86
|
+
bboxh = bboxw / imgratio
|
|
87
|
+
else:
|
|
88
|
+
bboxw = bboxh * imgratio
|
|
89
|
+
else:
|
|
90
|
+
bboxw = bboxh * imgratio
|
|
91
|
+
adjustedExtent = [bboxcx - 0.5 * bboxw, bboxcy - 0.5 * bboxh,
|
|
92
|
+
bboxcx + 0.5 * bboxw, bboxcy + 0.5 * bboxh]
|
|
93
|
+
url += "&BBOX=" + (",".join(map(str, adjustedExtent)))
|
|
94
|
+
url += "&LAYERS=" + quote(",".join(layers).encode('utf-8'))
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
opener = getUrlOpener(configItem)
|
|
98
|
+
reply = opener(url).read()
|
|
99
|
+
basename = configItem["url"].rsplit("/")[-1].rstrip("?") + ".png"
|
|
100
|
+
try:
|
|
101
|
+
os.makedirs(qwc2_path + "/static/assets/img/genmapthumbs/")
|
|
102
|
+
except Exception as e:
|
|
103
|
+
if not isinstance(e, FileExistsError): raise e
|
|
104
|
+
thumbnail = qwc2_path + "/static/assets/img/genmapthumbs/" + basename
|
|
105
|
+
with open(thumbnail, "wb") as fh:
|
|
106
|
+
fh.write(reply)
|
|
107
|
+
resultItem["thumbnail"] = "img/genmapthumbs/" + basename
|
|
108
|
+
except Exception as e:
|
|
109
|
+
print("ERROR generating thumbnail for WMS " + configItem["url"] + ":\n" + str(e))
|
|
110
|
+
resultItem["thumbnail"] = "img/mapthumbs/default.jpg"
|
|
111
|
+
traceback.print_exc()
|
|
112
|
+
|
|
113
|
+
def getEditConfig(editConfig):
|
|
114
|
+
if not editConfig:
|
|
115
|
+
return None
|
|
116
|
+
elif isinstance(editConfig, dict):
|
|
117
|
+
return editConfig
|
|
118
|
+
elif os.path.isabs(editConfig) and os.path.exists(editConfig):
|
|
119
|
+
with open(editConfig, encoding='utf-8') as fh:
|
|
120
|
+
config = json.load(fh)
|
|
121
|
+
return config
|
|
122
|
+
else:
|
|
123
|
+
dirname = os.path.dirname(themesConfig)
|
|
124
|
+
if not dirname:
|
|
125
|
+
dirname = "."
|
|
126
|
+
filename = os.path.join(dirname, editConfig)
|
|
127
|
+
if os.path.exists(filename):
|
|
128
|
+
with open(filename, encoding='utf-8') as fh:
|
|
129
|
+
config = json.load(fh)
|
|
130
|
+
return config
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
def getDirectChildElements(parent, tagname):
|
|
134
|
+
return [node for node in parent.childNodes if node.nodeName.split(':')[-1] == tagname]
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def getChildElement(parent, path):
|
|
138
|
+
for part in path.split("/"):
|
|
139
|
+
for node in parent.childNodes:
|
|
140
|
+
if node.nodeName.split(':')[-1] == part:
|
|
141
|
+
parent = node
|
|
142
|
+
break
|
|
143
|
+
else:
|
|
144
|
+
return None
|
|
145
|
+
return parent
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def getElementValue(element):
|
|
149
|
+
return element.firstChild.nodeValue if element and element.firstChild else ""
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def getChildElementValue(parent, path):
|
|
153
|
+
return getElementValue(getChildElement(parent, path))
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# recursively get layer tree
|
|
157
|
+
def getLayerTree(layer, resultLayers, visibleLayers, printLayers, level, collapseBelowLevel, titleNameMap, featureReports, externalLayers):
|
|
158
|
+
name = getChildElementValue(layer, "Name")
|
|
159
|
+
title = getChildElementValue(layer, "Title")
|
|
160
|
+
layers = getDirectChildElements(layer, "Layer")
|
|
161
|
+
treeName = getChildElementValue(layer, "TreeName")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# skip print layers
|
|
165
|
+
for printLayer in printLayers:
|
|
166
|
+
if type(printLayer) is list:
|
|
167
|
+
for entry in printLayer:
|
|
168
|
+
if entry["name"] == name:
|
|
169
|
+
return
|
|
170
|
+
elif printLayer == name:
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
layerEntry = {"name": name, "title": title}
|
|
174
|
+
|
|
175
|
+
if not layers:
|
|
176
|
+
if layer.getAttribute("geometryType") == "WKBNoGeometry" or layer.getAttribute("geometryType") == "NoGeometry":
|
|
177
|
+
# skip layers without geometry
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
# layer
|
|
181
|
+
layerEntry["geometryType"] = layer.getAttribute("geometryType")
|
|
182
|
+
if layer.getAttribute("visibilityChecked") != "":
|
|
183
|
+
layerEntry["visibility"] = layer.getAttribute("visibilityChecked") == "1"
|
|
184
|
+
else:
|
|
185
|
+
layerEntry["visibility"] = layer.getAttribute("visible") == "1"
|
|
186
|
+
if layerEntry["visibility"]:
|
|
187
|
+
# collect visible layers
|
|
188
|
+
visibleLayers.append(name)
|
|
189
|
+
|
|
190
|
+
layerEntry["queryable"] = layer.getAttribute("queryable") == "1"
|
|
191
|
+
if layerEntry["queryable"] and layer.getAttribute("displayField"):
|
|
192
|
+
layerEntry["displayField"] = layer.getAttribute("displayField")
|
|
193
|
+
|
|
194
|
+
try:
|
|
195
|
+
onlineResource = getChildElement(layer, "Attribution/OnlineResource")
|
|
196
|
+
layerEntry["attribution"] = {
|
|
197
|
+
"Title": getChildElementValue(layer, "Attribution/Title"),
|
|
198
|
+
"OnlineResource": onlineResource.getAttribute("xlink:href") if onlineResource else ""
|
|
199
|
+
}
|
|
200
|
+
except:
|
|
201
|
+
pass
|
|
202
|
+
try:
|
|
203
|
+
layerEntry["abstract"] = getChildElementValue(layer, "Abstract")
|
|
204
|
+
except:
|
|
205
|
+
pass
|
|
206
|
+
try:
|
|
207
|
+
onlineResource = getChildElement(layer, "DataURL/OnlineResource")
|
|
208
|
+
layerEntry["dataUrl"] = onlineResource.getAttribute("xlink:href")
|
|
209
|
+
if layerEntry["dataUrl"].startswith("wms:"):
|
|
210
|
+
externalLayers.append({"internalLayer": name, "name": layerEntry["dataUrl"]})
|
|
211
|
+
layerEntry["dataUrl"] = ""
|
|
212
|
+
except:
|
|
213
|
+
pass
|
|
214
|
+
try:
|
|
215
|
+
onlineResource = getChildElement(layer, "MetadataURL/OnlineResource")
|
|
216
|
+
layerEntry["metadataUrl"] = onlineResource.getAttribute("xlink:href")
|
|
217
|
+
except:
|
|
218
|
+
pass
|
|
219
|
+
try:
|
|
220
|
+
keywords = []
|
|
221
|
+
for keyword in getChildElement(layer, "KeywordList").getElementsByTagName("Keyword"):
|
|
222
|
+
keywords.append(getElementValue(keyword))
|
|
223
|
+
layerEntry["keywords"] = ", ".join(keywords)
|
|
224
|
+
except:
|
|
225
|
+
pass
|
|
226
|
+
|
|
227
|
+
styles = {}
|
|
228
|
+
for style in layer.getElementsByTagName("Style"):
|
|
229
|
+
name = getChildElementValue(style, "Name")
|
|
230
|
+
title = getChildElementValue(style, "Title")
|
|
231
|
+
styles[name] = title
|
|
232
|
+
layerEntry["styles"] = styles
|
|
233
|
+
layerEntry['style'] = 'default' if 'default' in styles else (list(styles)[0] if len(styles) > 0 else '')
|
|
234
|
+
|
|
235
|
+
if layer.getAttribute("transparency"):
|
|
236
|
+
layerEntry["opacity"] = 255 - int(float(layer.getAttribute("transparency")) * 255)
|
|
237
|
+
elif layer.getAttribute("opacity"):
|
|
238
|
+
layerEntry["opacity"] = int(float(layer.getAttribute("opacity")) * 255)
|
|
239
|
+
else:
|
|
240
|
+
layerEntry["opacity"] = 255
|
|
241
|
+
minScale = getChildElementValue(layer, "MinScaleDenominator")
|
|
242
|
+
maxScale = getChildElementValue(layer, "MaxScaleDenominator")
|
|
243
|
+
if minScale and maxScale:
|
|
244
|
+
layerEntry["minScale"] = int(float(minScale))
|
|
245
|
+
layerEntry["maxScale"] = int(float(maxScale))
|
|
246
|
+
# use geographic bounding box, as default CRS may have inverted axis order with WMS 1.3.0
|
|
247
|
+
geoBBox = getChildElement(layer, "EX_GeographicBoundingBox")
|
|
248
|
+
if geoBBox:
|
|
249
|
+
layerEntry["bbox"] = {
|
|
250
|
+
"crs": "EPSG:4326",
|
|
251
|
+
"bounds": [
|
|
252
|
+
float(getChildElementValue(geoBBox, "westBoundLongitude")),
|
|
253
|
+
float(getChildElementValue(geoBBox, "southBoundLatitude")),
|
|
254
|
+
float(getChildElementValue(geoBBox, "eastBoundLongitude")),
|
|
255
|
+
float(getChildElementValue(geoBBox, "northBoundLatitude"))
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
if name in featureReports:
|
|
259
|
+
layerEntry["featureReport"] = featureReports[name]
|
|
260
|
+
|
|
261
|
+
layerEntry["dimensions"] = []
|
|
262
|
+
for dim in getDirectChildElements(layer, "Dimension"):
|
|
263
|
+
layerEntry["dimensions"].append({
|
|
264
|
+
"units": dim.getAttribute("units"),
|
|
265
|
+
"name": dim.getAttribute("name"),
|
|
266
|
+
"multiple": dim.getAttribute("multipleValues") == "1",
|
|
267
|
+
"value": getElementValue(dim),
|
|
268
|
+
"fieldName": dim.getAttribute("fieldName"),
|
|
269
|
+
"endFieldName": dim.getAttribute("endFieldName")
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
else:
|
|
273
|
+
# group
|
|
274
|
+
layerEntry["mutuallyExclusive"] = layer.getAttribute("mutuallyExclusive") == "1"
|
|
275
|
+
if layer.getAttribute("visibilityChecked") != "":
|
|
276
|
+
layerEntry["visibility"] = layer.getAttribute("visibilityChecked") == "1"
|
|
277
|
+
else:
|
|
278
|
+
layerEntry["visibility"] = layer.getAttribute("visible") == "1"
|
|
279
|
+
layerEntry["sublayers"] = []
|
|
280
|
+
if layer.getAttribute("expanded") == "0":
|
|
281
|
+
layerEntry["expanded"] = False
|
|
282
|
+
else:
|
|
283
|
+
layerEntry["expanded"] = False if collapseBelowLevel >= 0 and level >= collapseBelowLevel else True
|
|
284
|
+
for sublayer in layers:
|
|
285
|
+
getLayerTree(sublayer, layerEntry["sublayers"], visibleLayers, printLayers, level + 1, collapseBelowLevel, titleNameMap, featureReports, externalLayers)
|
|
286
|
+
|
|
287
|
+
if not layerEntry["sublayers"]:
|
|
288
|
+
# skip empty groups
|
|
289
|
+
return
|
|
290
|
+
|
|
291
|
+
resultLayers.append(layerEntry)
|
|
292
|
+
titleNameMap[treeName] = name
|
|
293
|
+
|
|
294
|
+
# parse GetCapabilities for theme
|
|
295
|
+
def getTheme(config, configItem, result, resultItem):
|
|
296
|
+
global autogenExternalLayers
|
|
297
|
+
|
|
298
|
+
url = update_params(urljoin(baseUrl, configItem["url"]), {'SERVICE': 'WMS', 'VERSION': '1.3.0', 'REQUEST': 'GetProjectSettings'})
|
|
299
|
+
|
|
300
|
+
try:
|
|
301
|
+
opener = getUrlOpener(configItem)
|
|
302
|
+
reply = opener(url).read()
|
|
303
|
+
capabilities = parseString(reply)
|
|
304
|
+
capabilities = capabilities.getElementsByTagName("WMS_Capabilities")[0]
|
|
305
|
+
print("Parsing WMS GetProjectSettings of " + configItem["url"])
|
|
306
|
+
|
|
307
|
+
topLayer = getChildElement(getChildElement(capabilities, "Capability"), "Layer")
|
|
308
|
+
wmsName = re.sub(r".*/", "", configItem["url"]).rstrip("?")
|
|
309
|
+
|
|
310
|
+
# use name from config or fallback to WMS title
|
|
311
|
+
wmsTitle = configItem.get("title") or getChildElementValue(capabilities, "Service/Title") or getChildElementValue(topLayer, "Title") or wmsName
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
# keywords
|
|
315
|
+
keywords = []
|
|
316
|
+
keywordList = getChildElement(capabilities, "Service/KeywordList")
|
|
317
|
+
if keywordList:
|
|
318
|
+
for keyword in keywordList.getElementsByTagName("Keyword"):
|
|
319
|
+
value = getElementValue(keyword)
|
|
320
|
+
if value != "infoMapAccessService":
|
|
321
|
+
keywords.append(value)
|
|
322
|
+
|
|
323
|
+
# collect WMS layers for printing
|
|
324
|
+
printLayers = configItem["extraPrintLayers"] if "extraPrintLayers" in configItem else []
|
|
325
|
+
if "backgroundLayers" in configItem:
|
|
326
|
+
printLayers = [entry["printLayer"] for entry in configItem["backgroundLayers"] if "printLayer" in entry]
|
|
327
|
+
|
|
328
|
+
# layer tree and visible layers
|
|
329
|
+
collapseLayerGroupsBelowLevel = -1
|
|
330
|
+
if "collapseLayerGroupsBelowLevel" in configItem:
|
|
331
|
+
collapseLayerGroupsBelowLevel = configItem["collapseLayerGroupsBelowLevel"]
|
|
332
|
+
|
|
333
|
+
layerTree = []
|
|
334
|
+
visibleLayers = []
|
|
335
|
+
titleNameMap = {}
|
|
336
|
+
featureReports = configItem["featureReport"] if "featureReport" in configItem else {}
|
|
337
|
+
externalLayers = []
|
|
338
|
+
getLayerTree(topLayer, layerTree, visibleLayers, printLayers, 1, collapseLayerGroupsBelowLevel, titleNameMap, featureReports, externalLayers)
|
|
339
|
+
autogenExternalLayers += list(map(lambda entry: entry["name"], externalLayers))
|
|
340
|
+
if "externalLayers" in configItem:
|
|
341
|
+
externalLayers += configItem["externalLayers"]
|
|
342
|
+
visibleLayers.reverse()
|
|
343
|
+
|
|
344
|
+
# print templates
|
|
345
|
+
printTemplates = []
|
|
346
|
+
composerTemplates = getChildElement(capabilities, "Capability/ComposerTemplates")
|
|
347
|
+
if composerTemplates:
|
|
348
|
+
|
|
349
|
+
composerTemplateMap = {}
|
|
350
|
+
for composerTemplate in composerTemplates.getElementsByTagName("ComposerTemplate"):
|
|
351
|
+
composerMap = getChildElement(composerTemplate, "ComposerMap")
|
|
352
|
+
if composerMap:
|
|
353
|
+
composerTemplateMap[composerTemplate.getAttribute("name")] = composerTemplate;
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
for composerTemplate in composerTemplateMap.values():
|
|
357
|
+
templateName = composerTemplate.getAttribute("name")
|
|
358
|
+
if templateName.endswith("_legend") and templateName[:-7] in composerTemplateMap:
|
|
359
|
+
continue
|
|
360
|
+
|
|
361
|
+
composerMap = getChildElement(composerTemplate, "ComposerMap")
|
|
362
|
+
printTemplate = {
|
|
363
|
+
"name": templateName,
|
|
364
|
+
"map": {
|
|
365
|
+
"name": composerMap.getAttribute("name"),
|
|
366
|
+
"width": float(composerMap.getAttribute("width")),
|
|
367
|
+
"height": float(composerMap.getAttribute("height"))
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if printTemplate["name"] + "_legend" in composerTemplateMap:
|
|
371
|
+
printTemplate["legendLayout"] = printTemplate["name"] + "_legend";
|
|
372
|
+
|
|
373
|
+
composerLabels = composerTemplate.getElementsByTagName("ComposerLabel")
|
|
374
|
+
labels = [composerLabel.getAttribute("name") for composerLabel in composerLabels]
|
|
375
|
+
if "printLabelBlacklist" in configItem:
|
|
376
|
+
labels = list(filter(lambda label: label not in configItem["printLabelBlacklist"], labels))
|
|
377
|
+
printTemplate['default'] = printTemplate['name'] == configItem.get('defaultPrintLayout')
|
|
378
|
+
|
|
379
|
+
if labels:
|
|
380
|
+
printTemplate["labels"] = labels
|
|
381
|
+
if composerTemplate.getAttribute('atlasEnabled') == '1':
|
|
382
|
+
atlasLayer = composerTemplate.getAttribute('atlasCoverageLayer')
|
|
383
|
+
try:
|
|
384
|
+
layers = capabilities.getElementsByTagName("Layer")
|
|
385
|
+
pk = getChildElementValue(list(filter(lambda l: getChildElementValue(l, "Name") == atlasLayer, layers))[0], "PrimaryKey/PrimaryKeyAttribute")
|
|
386
|
+
printTemplate["atlasCoverageLayer"] = atlasLayer
|
|
387
|
+
printTemplate["atlas_pk"] = pk
|
|
388
|
+
except:
|
|
389
|
+
print("Failed to determine primary key for atlas layer " + atlasLayer)
|
|
390
|
+
|
|
391
|
+
printTemplates.append(printTemplate)
|
|
392
|
+
|
|
393
|
+
# drawing order
|
|
394
|
+
drawingOrder = getChildElementValue(capabilities, "Capability/LayerDrawingOrder").split(",")
|
|
395
|
+
drawingOrder = list(map(lambda title: titleNameMap[title] if title in titleNameMap else title, drawingOrder))
|
|
396
|
+
|
|
397
|
+
# getmap formats
|
|
398
|
+
availableFormats = []
|
|
399
|
+
for format in getChildElement(capabilities, "Capability/Request/GetMap").getElementsByTagName("Format"):
|
|
400
|
+
availableFormats.append(getElementValue(format))
|
|
401
|
+
|
|
402
|
+
# update theme config
|
|
403
|
+
resultItem["url"] = configItem["url"]
|
|
404
|
+
resultItem["id"] = uniqueThemeId(wmsName)
|
|
405
|
+
resultItem["name"] = getChildElementValue(topLayer, "Name")
|
|
406
|
+
resultItem["title"] = wmsTitle
|
|
407
|
+
resultItem["description"] = configItem["description"] if "description" in configItem else ""
|
|
408
|
+
resultItem["attribution"] = {
|
|
409
|
+
"Title": configItem["attribution"] if "attribution" in configItem else "",
|
|
410
|
+
"OnlineResource": configItem["attributionUrl"] if "attributionUrl" in configItem else ""
|
|
411
|
+
}
|
|
412
|
+
# service info
|
|
413
|
+
resultItem["abstract"] = getChildElementValue(capabilities, "Service/Abstract")
|
|
414
|
+
resultItem["keywords"] = ", ".join(keywords)
|
|
415
|
+
resultItem["onlineResource"] = getChildElement(capabilities, "Service/OnlineResource").getAttribute("xlink:href")
|
|
416
|
+
resultItem["contact"] = {
|
|
417
|
+
"person": getChildElementValue(capabilities, "Service/ContactInformation/ContactPersonPrimary/ContactPerson"),
|
|
418
|
+
"organization": getChildElementValue(capabilities, "Service/ContactInformation/ContactPersonPrimary/ContactOrganization"),
|
|
419
|
+
"position": getChildElementValue(capabilities, "Service/ContactInformation/ContactPosition"),
|
|
420
|
+
"phone": getChildElementValue(capabilities, "Service/ContactInformation/ContactVoiceTelephone"),
|
|
421
|
+
"email": getChildElementValue(capabilities, "Service/ContactInformation/ContactElectronicMailAddress")
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if "format" in configItem:
|
|
425
|
+
resultItem["format"] = configItem["format"]
|
|
426
|
+
resultItem["availableFormats"] = availableFormats
|
|
427
|
+
if "tiled" in configItem:
|
|
428
|
+
resultItem["tiled"] = configItem["tiled"]
|
|
429
|
+
if "tileSize" in configItem:
|
|
430
|
+
resultItem["tileSize"] = configItem["tileSize"]
|
|
431
|
+
if "version" in configItem:
|
|
432
|
+
resultItem["version"] = configItem["version"]
|
|
433
|
+
elif "defaultWMSVersion" in config:
|
|
434
|
+
resultItem["version"] = config["defaultWMSVersion"]
|
|
435
|
+
resultItem["infoFormats"] = [getElementValue(format) for format in getChildElement(capabilities, "Capability/Request/GetFeatureInfo").getElementsByTagName("Format")]
|
|
436
|
+
# use geographic bounding box for theme, as default CRS may have inverted axis order with WMS 1.3.0
|
|
437
|
+
bounds = [
|
|
438
|
+
float(getChildElementValue(topLayer, "EX_GeographicBoundingBox/westBoundLongitude")),
|
|
439
|
+
float(getChildElementValue(topLayer, "EX_GeographicBoundingBox/southBoundLatitude")),
|
|
440
|
+
float(getChildElementValue(topLayer, "EX_GeographicBoundingBox/eastBoundLongitude")),
|
|
441
|
+
float(getChildElementValue(topLayer, "EX_GeographicBoundingBox/northBoundLatitude"))
|
|
442
|
+
]
|
|
443
|
+
resultItem["bbox"] = {
|
|
444
|
+
"crs": "EPSG:4326",
|
|
445
|
+
"bounds": bounds
|
|
446
|
+
}
|
|
447
|
+
if "extent" in configItem:
|
|
448
|
+
resultItem["initialBbox"] = {
|
|
449
|
+
"crs": configItem["mapCrs"] if "mapCrs" in configItem else result["themes"]["defaultMapCrs"],
|
|
450
|
+
"bounds": configItem["extent"]
|
|
451
|
+
}
|
|
452
|
+
else:
|
|
453
|
+
resultItem["initialBbox"] = resultItem["bbox"]
|
|
454
|
+
if "scales" in configItem:
|
|
455
|
+
resultItem["scales"] = configItem["scales"]
|
|
456
|
+
if "printScales" in configItem:
|
|
457
|
+
resultItem["printScales"] = configItem["printScales"]
|
|
458
|
+
if "printResolutions" in configItem:
|
|
459
|
+
resultItem["printResolutions"] = configItem["printResolutions"]
|
|
460
|
+
if "printGrid" in configItem:
|
|
461
|
+
resultItem["printGrid"] = configItem["printGrid"]
|
|
462
|
+
# NOTE: skip root WMS layer
|
|
463
|
+
resultItem["sublayers"] = layerTree[0]["sublayers"] if len(layerTree) > 0 and "sublayers" in layerTree[0] else []
|
|
464
|
+
resultItem["expanded"] = True
|
|
465
|
+
if "backgroundLayers" in configItem:
|
|
466
|
+
resultItem["backgroundLayers"] = configItem["backgroundLayers"]
|
|
467
|
+
resultItem["externalLayers"] = externalLayers
|
|
468
|
+
if "pluginData" in configItem:
|
|
469
|
+
resultItem["pluginData"] = configItem["pluginData"]
|
|
470
|
+
if "predefinedFilters" in configItem:
|
|
471
|
+
resultItem["predefinedFilters"] = configItem["predefinedFilters"]
|
|
472
|
+
if "snapping" in configItem:
|
|
473
|
+
resultItem["snapping"] = configItem["snapping"]
|
|
474
|
+
if "minSearchScaleDenom" in configItem:
|
|
475
|
+
resultItem["minSearchScaleDenom"] = configItem["minSearchScaleDenom"]
|
|
476
|
+
elif "minSearchScale" in configItem: # Legacy name
|
|
477
|
+
resultItem["minSearchScaleDenom"] = configItem["minSearchScale"]
|
|
478
|
+
if "themeInfoLinks" in configItem:
|
|
479
|
+
resultItem["themeInfoLinks"] = configItem["themeInfoLinks"]
|
|
480
|
+
if "layerTreeHiddenSublayers" in configItem:
|
|
481
|
+
resultItem["layerTreeHiddenSublayers"] = configItem["layerTreeHiddenSublayers"]
|
|
482
|
+
resultItem["searchProviders"] = configItem["searchProviders"] if "searchProviders" in configItem else []
|
|
483
|
+
if "additionalMouseCrs" in configItem:
|
|
484
|
+
resultItem["additionalMouseCrs"] = configItem["additionalMouseCrs"]
|
|
485
|
+
if "mapCrs" in configItem:
|
|
486
|
+
resultItem["mapCrs"] = configItem["mapCrs"]
|
|
487
|
+
else:
|
|
488
|
+
resultItem["mapCrs"] = result["themes"]["defaultMapCrs"]
|
|
489
|
+
if printTemplates:
|
|
490
|
+
resultItem["print"] = printTemplates
|
|
491
|
+
resultItem["drawingOrder"] = drawingOrder
|
|
492
|
+
if "extraDxfParameters" in configItem:
|
|
493
|
+
resultItem["extraDxfParameters"] = configItem["extraDxfParameters"]
|
|
494
|
+
if "extraPrintParameters" in configItem:
|
|
495
|
+
resultItem["extraPrintParameters"] = configItem["extraPrintParameters"]
|
|
496
|
+
extraLegenParams = configItem["extraLegendParameters"] if "extraLegendParameters" in configItem else ""
|
|
497
|
+
if "legendUrl" in configItem:
|
|
498
|
+
resultItem["legendUrl"] = configItem["legendUrl"]
|
|
499
|
+
else:
|
|
500
|
+
resultItem["legendUrl"] = getChildElement(capabilities, "Capability/Request/GetLegendGraphic/DCPType/HTTP/Get/OnlineResource").getAttribute("xlink:href").rstrip("?") + "?" + extraLegenParams
|
|
501
|
+
if "featureInfoUrl" in configItem:
|
|
502
|
+
resultItem["featureInfoUrl"] = configItem["featureInfoUrl"]
|
|
503
|
+
else:
|
|
504
|
+
resultItem["featureInfoUrl"] = getChildElement(capabilities, "Capability/Request/GetFeatureInfo/DCPType/HTTP/Get/OnlineResource").getAttribute("xlink:href").rstrip("?") + "?"
|
|
505
|
+
if "printUrl" in configItem:
|
|
506
|
+
resultItem["printUrl"] = configItem["printUrl"]
|
|
507
|
+
else:
|
|
508
|
+
resultItem["printUrl"] = getChildElement(capabilities, "Capability/Request/GetPrint/DCPType/HTTP/Get/OnlineResource").getAttribute("xlink:href").rstrip("?") + "?"
|
|
509
|
+
if "printLabelForSearchResult" in configItem:
|
|
510
|
+
resultItem["printLabelForSearchResult"] = configItem["printLabelForSearchResult"]
|
|
511
|
+
if "printLabelForAttribution" in configItem:
|
|
512
|
+
resultItem["printLabelForAttribution"] = configItem["printLabelForAttribution"]
|
|
513
|
+
if "printLabelConfig" in configItem:
|
|
514
|
+
resultItem["printLabelConfig"] = configItem["printLabelConfig"]
|
|
515
|
+
|
|
516
|
+
if "watermark" in configItem:
|
|
517
|
+
resultItem["watermark"] = configItem["watermark"]
|
|
518
|
+
|
|
519
|
+
if "skipEmptyFeatureAttributes" in configItem:
|
|
520
|
+
resultItem["skipEmptyFeatureAttributes"] = configItem["skipEmptyFeatureAttributes"]
|
|
521
|
+
|
|
522
|
+
if "config" in configItem:
|
|
523
|
+
resultItem["config"] = configItem["config"]
|
|
524
|
+
|
|
525
|
+
if "flags" in configItem:
|
|
526
|
+
resultItem["flags"] = configItem["flags"]
|
|
527
|
+
|
|
528
|
+
if "mapTips" in configItem:
|
|
529
|
+
resultItem["mapTips"] = configItem["mapTips"]
|
|
530
|
+
|
|
531
|
+
if "userMap" in configItem:
|
|
532
|
+
resultItem["userMap"] = configItem["userMap"]
|
|
533
|
+
|
|
534
|
+
if "map3d" in configItem:
|
|
535
|
+
resultItem["map3d"] = configItem["map3d"]
|
|
536
|
+
|
|
537
|
+
resultItem["editConfig"] = getEditConfig(configItem["editConfig"] if "editConfig" in configItem else None)
|
|
538
|
+
|
|
539
|
+
# set default theme
|
|
540
|
+
if configItem.get("default", False) or not result["themes"]["defaultTheme"]:
|
|
541
|
+
result["themes"]["defaultTheme"] = resultItem["id"]
|
|
542
|
+
|
|
543
|
+
# use first CRS for thumbnail request which is not CRS:84
|
|
544
|
+
for item in topLayer.getElementsByTagName("CRS"):
|
|
545
|
+
crs = getElementValue(item)
|
|
546
|
+
if crs != "CRS:84":
|
|
547
|
+
break
|
|
548
|
+
extent = None
|
|
549
|
+
for bbox in topLayer.getElementsByTagName("BoundingBox"):
|
|
550
|
+
if bbox.getAttribute("CRS") == crs:
|
|
551
|
+
extent = [
|
|
552
|
+
float(bbox.getAttribute("minx")),
|
|
553
|
+
float(bbox.getAttribute("miny")),
|
|
554
|
+
float(bbox.getAttribute("maxx")),
|
|
555
|
+
float(bbox.getAttribute("maxy"))
|
|
556
|
+
]
|
|
557
|
+
break
|
|
558
|
+
if extent:
|
|
559
|
+
getThumbnail(configItem, resultItem, visibleLayers, crs, extent)
|
|
560
|
+
|
|
561
|
+
except Exception as e:
|
|
562
|
+
print("ERROR reading WMS GetProjectSettings of " + configItem["url"] + ":\n" + str(e))
|
|
563
|
+
resultItem["error"] = "Could not read GetProjectSettings"
|
|
564
|
+
resultItem["title"] = "Error"
|
|
565
|
+
traceback.print_exc()
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
# recursively get themes for groups
|
|
569
|
+
def getGroupThemes(config, configGroup, result, resultGroup, groupCounter):
|
|
570
|
+
for item in configGroup["items"]:
|
|
571
|
+
itemEntry = {}
|
|
572
|
+
getTheme(config, item, result, itemEntry)
|
|
573
|
+
if itemEntry:
|
|
574
|
+
resultGroup["items"].append(itemEntry)
|
|
575
|
+
|
|
576
|
+
if "groups" in configGroup:
|
|
577
|
+
for group in configGroup["groups"]:
|
|
578
|
+
groupCounter += 1
|
|
579
|
+
groupEntry = {
|
|
580
|
+
"id": "g%d" % groupCounter,
|
|
581
|
+
"title": group["title"],
|
|
582
|
+
"items": [],
|
|
583
|
+
"subdirs": []
|
|
584
|
+
}
|
|
585
|
+
getGroupThemes(config, group, result, groupEntry, groupCounter)
|
|
586
|
+
resultGroup["subdirs"].append(groupEntry)
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
def reformatAttribution(entry):
|
|
590
|
+
entry["attribution"] = {
|
|
591
|
+
"Title": entry["attribution"] if "attribution" in entry else None,
|
|
592
|
+
"OnlineResource": entry["attributionUrl"] if "attributionUrl" in entry else None
|
|
593
|
+
}
|
|
594
|
+
entry.pop("attributionUrl", None)
|
|
595
|
+
return entry
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
def genThemes(themesConfig):
|
|
599
|
+
# load themesConfig.json
|
|
600
|
+
try:
|
|
601
|
+
with open(themesConfig, encoding='utf-8') as fh:
|
|
602
|
+
config = json.load(fh)
|
|
603
|
+
except:
|
|
604
|
+
return {"error": "Failed to read themesConfig.json"}
|
|
605
|
+
|
|
606
|
+
result = {
|
|
607
|
+
"themes": {
|
|
608
|
+
"title": "root",
|
|
609
|
+
"subdirs": [],
|
|
610
|
+
"items": [],
|
|
611
|
+
"defaultTheme": config["defaultTheme"] if "defaultTheme" in config else None,
|
|
612
|
+
"defaultMapCrs": config["defaultMapCrs"] if "defaultMapCrs" in config else "EPSG:3857",
|
|
613
|
+
"defaultScales": config["defaultScales"],
|
|
614
|
+
"defaultPrintScales": config["defaultPrintScales"] if "defaultPrintScales" in config else None,
|
|
615
|
+
"defaultPrintResolutions": config["defaultPrintResolutions"] if "defaultPrintResolutions" in config else None,
|
|
616
|
+
"defaultPrintGrid": config["defaultPrintGrid"] if "defaultPrintGrid" in config else None,
|
|
617
|
+
"defaultSearchProviders": config["defaultSearchProviders"] if "defaultSearchProviders" in config else None,
|
|
618
|
+
"defaultBackgroundLayers": config["defaultBackgroundLayers"] if "defaultBackgroundLayers" in config else [],
|
|
619
|
+
"pluginData": config["themes"]["pluginData"] if "pluginData" in config["themes"] else [],
|
|
620
|
+
"themeInfoLinks": config["themes"]["themeInfoLinks"] if "themeInfoLinks" in config["themes"] else [],
|
|
621
|
+
"externalLayers": config["themes"]["externalLayers"] if "externalLayers" in config["themes"] else [],
|
|
622
|
+
"backgroundLayers": list(map(reformatAttribution, config["themes"]["backgroundLayers"])),
|
|
623
|
+
"defaultWMSVersion": config["defaultWMSVersion"] if "defaultWMSVersion" in config else None
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
groupCounter = 0
|
|
627
|
+
getGroupThemes(config, config["themes"], result, result["themes"], groupCounter)
|
|
628
|
+
|
|
629
|
+
for entry in autogenExternalLayers:
|
|
630
|
+
cpos = entry.find(":")
|
|
631
|
+
hpos = entry.rfind('#')
|
|
632
|
+
type = entry[0:cpos]
|
|
633
|
+
url = entry[cpos+1:hpos]
|
|
634
|
+
layername = entry[hpos+1:]
|
|
635
|
+
result["themes"]["externalLayers"].append({
|
|
636
|
+
"name": entry,
|
|
637
|
+
"type": type,
|
|
638
|
+
"url": url,
|
|
639
|
+
"params": {"LAYERS": layername},
|
|
640
|
+
"infoFormats": ["text/plain"]
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
if "backgroundLayers" in result["themes"]:
|
|
644
|
+
# get thumbnails for background layers
|
|
645
|
+
for backgroundLayer in result["themes"]["backgroundLayers"]:
|
|
646
|
+
imgPath = "img/mapthumbs/" + backgroundLayer.get("thumbnail", "default.jpg")
|
|
647
|
+
if not os.path.isfile(qwc2_path + "/static/assets/" + imgPath):
|
|
648
|
+
imgPath = "img/mapthumbs/default.jpg"
|
|
649
|
+
backgroundLayer["thumbnail"] = imgPath
|
|
650
|
+
|
|
651
|
+
return result
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
if __name__ == '__main__':
|
|
655
|
+
print("Reading " + themesConfig)
|
|
656
|
+
themes = genThemes(themesConfig)
|
|
657
|
+
# write config file
|
|
658
|
+
with open("./static/themes.json", "w") as fh:
|
|
659
|
+
json.dump(themes, fh, indent=2, separators=(',', ': '), sort_keys=True)
|