From 4ea3a16f2930d34713b85f39ecaed5005ae48694 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 3 May 2024 12:43:57 +1000 Subject: [PATCH] Attempt to patch layer style --- felt/core/api_client.py | 22 +++++++++++++++++++++ felt/core/layer_exporter.py | 39 +++++++++++++------------------------ felt/core/layer_style.py | 6 +++++- felt/core/map_uploader.py | 22 ++++++++++++++++++++- 4 files changed, 62 insertions(+), 27 deletions(-) diff --git a/felt/core/api_client.py b/felt/core/api_client.py index 79e5771..e7d1296 100644 --- a/felt/core/api_client.py +++ b/felt/core/api_client.py @@ -63,6 +63,7 @@ class FeltApiClient: USAGE_ENDPOINT = '/internal/reports' RECENT_MAPS_ENDPOINT = '/maps/recent' UPLOAD_V2_ENDPOINT = '/maps/{}/upload' + PATCH_STYLE_ENDPOINT = '/maps/{}/layers/{}/style' def __init__(self): # default headers to add to all requests @@ -418,6 +419,27 @@ def finalize_layer_upload(self, json_data.encode() ) + def patch_style(self, + map_id: str, + layer_id: str, + data: Dict) \ + -> QNetworkReply: + """ + Patches a layer's style + """ + request = self._build_request( + self.PATCH_STYLE_ENDPOINT.format(map_id, layer_id), + {'Content-Type': 'application/json'} + ) + + json_data = json.dumps(data) + print(json_data) + return QgsNetworkAccessManager.instance().sendCustomRequest( + request, + b"PATCH", + json_data.encode() + ) + def report_usage(self, content: str, usage_type: UsageType = UsageType.Info) -> QNetworkReply: diff --git a/felt/core/layer_exporter.py b/felt/core/layer_exporter.py index 2cf05c5..0a93f88 100644 --- a/felt/core/layer_exporter.py +++ b/felt/core/layer_exporter.py @@ -72,6 +72,10 @@ from .layer_style import LayerStyle from .logger import Logger from .map import Map +from .fsl_converter import ( + FslConverter, + ConversionContext +) @dataclass @@ -207,31 +211,16 @@ def representative_layer_style(layer: QgsVectorLayer) -> LayerStyle: if not layer.isSpatial() or not layer.renderer(): return LayerStyle() - if isinstance(layer.renderer(), QgsSingleSymbolRenderer): - return LayerExporter.symbol_to_layer_style( - layer.renderer().symbol() - ) - if isinstance(layer.renderer(), QgsCategorizedSymbolRenderer) and \ - layer.renderer().categories(): - first_category = layer.renderer().categories()[0] - return LayerExporter.symbol_to_layer_style( - first_category.symbol() - ) - if isinstance(layer.renderer(), QgsGraduatedSymbolRenderer) and \ - layer.renderer().ranges(): - first_range = layer.renderer().ranges()[0] - return LayerExporter.symbol_to_layer_style( - first_range.symbol() - ) - if isinstance(layer.renderer(), QgsRuleBasedRenderer) and \ - layer.renderer().rootRule().children(): - for child in layer.renderer().rootRule().children(): - if child.symbol(): - return LayerExporter.symbol_to_layer_style( - child.symbol() - ) - - return LayerStyle() + context = ConversionContext() + fsl = FslConverter.vector_renderer_to_fsl( + layer.renderer(), context, layer.opacity() + ) + if fsl: + fsl['version'] = '2.1' + # TODO -- labeling + return LayerStyle( + fsl=fsl + ) @staticmethod def symbol_to_layer_style(symbol: QgsSymbol) -> LayerStyle: diff --git a/felt/core/layer_style.py b/felt/core/layer_style.py index b85f608..74c5391 100644 --- a/felt/core/layer_style.py +++ b/felt/core/layer_style.py @@ -14,7 +14,10 @@ __revision__ = '$Format:%H$' from dataclasses import dataclass -from typing import Optional +from typing import ( + Optional, + Dict +) from qgis.PyQt.QtGui import QColor @@ -26,3 +29,4 @@ class LayerStyle: """ fill_color: Optional[QColor] = None stroke_color: Optional[QColor] = None + fsl: Optional[Dict[str, object]] = None diff --git a/felt/core/map_uploader.py b/felt/core/map_uploader.py index 2abf7fa..ff16ffb 100644 --- a/felt/core/map_uploader.py +++ b/felt/core/map_uploader.py @@ -27,7 +27,8 @@ QDate, pyqtSignal, QThread, - QSize + QSize, + QEventLoop ) from qgis.PyQt.QtNetwork import ( QNetworkReply, @@ -474,6 +475,25 @@ def _upload_progress(sent, total): if self.isCanceled(): return False + layer_id = upload_details.get('data', {}).get('attributes', {}).get('first_layer_id') + if details.style.fsl is not None: + if not layer_id: + Logger.instance().log_error_json( + { + 'type': Logger.S3_UPLOAD, + 'error': 'Didn\'t get layer id to use for patching style' + } + ) + else: + reply = API_CLIENT.patch_style( + map_id=self.associated_map.id, + layer_id=layer_id, + data=details.style.fsl + ) + loop = QEventLoop() + reply.finished.connect(loop.exit) + loop.exec() + multi_step_feedback.step_finished() return True