Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lizmap/config/models.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
from types import MappingProxyType
from typing import (
Any,
NotRequired,
Sequence,
TypedDict,
)

# Works on Python 3.11+
try:
from typing import NotRequired
except ImportError:
# Fallback for Python < 3.11 (or if you want to ensure typing_extensions is used)
from typing_extensions import NotRequired

from qgis.core import Qgis

MappingQgisGeometryType = MappingProxyType(
Expand Down
1 change: 1 addition & 0 deletions lizmap/definitions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class InputType(Enum):
SpinBox = 'SpinBox' # QSpinbox
Text = 'Text' # QLineEdit
MultiLine = 'MultiLine' # QPlainTextEdit or QgsCodeEditorHTML
Scale = 'Scale' # QgsScaleWidget


class BaseDefinitions:
Expand Down
30 changes: 16 additions & 14 deletions lizmap/definitions/online_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,21 @@ class Panels:
AttributeTable = 4
Editing = 5
Layouts = 6
DxfExport = 7
FormFiltering = 8
Dataviz = 9
FilteredLayers = 10
Actions = 11
TimeManager = 12
Atlas = 13
LocateByLayer = 14
ToolTip = 15
Checks = 16
AutoFix = 17
Settings = 18
Upload = 19
Training = 20
Portfolio = 7
DxfExport = 8
FormFiltering = 9
Dataviz = 10
FilteredLayers = 11
Actions = 12
TimeManager = 13
Atlas = 14
LocateByLayer = 15
ToolTip = 16
Checks = 17
AutoFix = 18
Settings = 19
Upload = 20
Training = 21


MAPPING_INDEX_DOC = {
Expand All @@ -88,6 +89,7 @@ class Panels:
Panels.Upload: None,
Panels.Training: None,
Panels.DxfExport: 'publish/lizmap_plugin/dxf_export.html',
Panels.Portfolio: 'publish/lizmap_plugin/portfolio.html',
}


Expand Down
148 changes: 148 additions & 0 deletions lizmap/definitions/portfolio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
"""Definitions for portfolio."""

from enum import Enum, unique
from typing import (
Dict,
)

from lizmap.definitions.base import BaseDefinitions, InputType
from lizmap.toolbelt.i18n import tr


def represent_layouts(data: Dict) -> str:
"""Generate HTMl string for the tooltip instead of JSON representation."""
html = '<ul>'

for template in data:
layout = template.get('layout')
theme = template.get('theme')
zoom_method = template.get('zoom_method')
scale = template.get('scale')
margin = template.get('margin')
html += f'<li>{layout} - {theme}'
for z in ZoomMethodType:
if z.value.data == zoom_method:
html += f' - {z.value.label}'
if zoom_method == ZoomMethodType.FixScale.value.data:
html += f' - {scale}'
elif zoom_method == ZoomMethodType.Margin.value.data:
html += f' - {margin}'
break
html += '</li>\n'

html += '</ul>\n'
return html


@unique
class GeometryType(Enum):
Point = {
'data': 'point',
'label': tr('Point'),
}
Line = {
'data': 'line',
'label': tr('Line'),
}
Polygon = {
'data': 'polygon',
'label': tr('Polygon'),
}


@unique
class ZoomMethodType(Enum):
FixScale = {
'data': 'fix_scale',
'label': tr('Fix scale'),
}
Margin = {
'data': 'margin',
'label': tr('Margin'),
}
BestScale = {
'data': 'best_scale',
'label': tr('Best scale'),
}


class PortfolioDefinitions(BaseDefinitions):

def __init__(self):
super().__init__()
self._layer_config['title'] = {
'type': InputType.Text,
'header': tr('Title'),
'default': '',
'tooltip': tr('The title of the portfolio, when displayed in the portfolio dock'),
}
self._layer_config['description'] = {
'type': InputType.HtmlWysiwyg,
'header': tr('Description'),
'default': '',
'tooltip': tr('The description of the portfolio. HTML is supported.'),
}
self._layer_config['drawing_geometry'] = {
'type': InputType.List,
'header': tr('Geometry'),
'items': GeometryType,
'default': GeometryType.Point,
'tooltip': tr('The geometry type of the portfolio.')
}
self._layer_config['layouts'] = {
'type': InputType.Collection,
'header': tr('Layouts'),
'tooltip': tr('Textual representations of layout tuples'),
'items': [
'layout',
'theme',
'zoom_method',
'fix_scale',
'margin',
],
'represent_value': represent_layouts,
}
self._layer_config['layout'] = {
'plural': 'layout_{}',
'type': InputType.List,
'header': tr('Layout'),
'tooltip': tr('The zoom to geometry method, depends on the geometry type.')
}
self._layer_config['theme'] = {
'plural': 'theme_{}',
'type': InputType.List,
'header': tr('Theme'),
'tooltip': tr('The zoom to geometry method, depends on the geometry type.')
}
self._layer_config['zoom_method'] = {
'plural': 'zoom_method_{}',
'type': InputType.List,
'header': tr('Zoom method'),
'items': ZoomMethodType,
'default': ZoomMethodType.FixScale,
'tooltip': tr('The zoom to geometry method, depends on the geometry type.')
}
self._layer_config['fix_scale'] = {
'plural': 'fix_scale_{}',
'type': InputType.Scale,
'header': tr('Fix scale'),
'default': 5000,
'tooltip': tr('The scale of the portfolio for point geometry.')
}
self._layer_config['margin'] = {
'plural': 'margin_{}',
'type': InputType.SpinBox,
'header': tr('Margin'),
'default': 10,
'tooltip': tr('The margin around line or polygon geometry.')
}

@staticmethod
def primary_keys() -> tuple:
return tuple()

def key(self) -> str:
return 'portfolioLayers'

def help_path(self) -> str:
return 'publish/lizmap_plugin/portfolio.html'
16 changes: 15 additions & 1 deletion lizmap/forms/base_edition_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
QMessageBox,
QPlainTextEdit,
)
from qgis.utils import iface

from lizmap.definitions.base import InputType
from lizmap.definitions.definitions import LwcVersions, ServerComboData
Expand Down Expand Up @@ -123,9 +124,18 @@ def setup_ui(self):
widget.setSuffix(unit)

default = layer_config.get('default')
if unit:
if unit: # TO FIX replaced by default
widget.setValue(default)

if layer_config['type'] == InputType.Scale:
if widget is not None:
widget.setShowCurrentScaleButton(True)
widget.setMapCanvas(iface.mapCanvas())
widget.setAllowNull(False)
default = layer_config.get('default')
if default:
widget.setScale(default)

if layer_config['type'] == InputType.Color:
if widget is not None:
if layer_config['default'] == '':
Expand Down Expand Up @@ -386,6 +396,8 @@ def load_form(self, data: OrderedDict) -> None:
definition['widget'].setCurrentIndex(index)
elif definition['type'] == InputType.SpinBox:
definition['widget'].setValue(value)
elif definition['type'] == InputType.Scale:
widget.setScale(value)
elif definition['type'] == InputType.Text:
definition['widget'].setText(value)
elif definition['type'] == InputType.Json:
Expand Down Expand Up @@ -443,6 +455,8 @@ def save_form(self) -> OrderedDict:
value = definition['widget'].currentData()
elif definition['type'] == InputType.SpinBox:
value = definition['widget'].value()
elif definition['type'] == InputType.Scale:
value = definition['widget'].scale()
elif definition['type'] == InputType.Text:
value = definition['widget'].text().strip(' \t')
elif definition['type'] == InputType.MultiLine:
Expand Down
111 changes: 111 additions & 0 deletions lizmap/forms/layout_portfolio_edition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""Dialog for layout portfolio edition."""
from collections import OrderedDict

from qgis.core import QgsProject
from qgis.PyQt.QtWidgets import QDialog, QDialogButtonBox

from lizmap.definitions.base import InputType
from lizmap.definitions.portfolio import (
GeometryType,
PortfolioDefinitions,
ZoomMethodType,
)
from lizmap.toolbelt.resources import load_ui

__copyright__ = 'Copyright 2020, 3Liz'
__license__ = 'GPL version 3'
__email__ = 'info@3liz.org'


CLASS = load_ui('ui_portfolio_layout.ui')


class LayouPortfolioEditionDialog(QDialog, CLASS):

def __init__(self, parent, geometry, uniques):
super().__init__(parent)
self.config = PortfolioDefinitions()
self._geometry = geometry
self.uniques = uniques
self.setupUi(self)

self.config.add_layer_widget('layout', self.layout)
self.config.add_layer_widget('theme', self.theme)
self.config.add_layer_widget('zoom_method', self.zoom_method)
self.config.add_layer_widget('fix_scale', self.fix_scale)
self.config.add_layer_widget('margin', self.margin)

self.config.add_layer_label('layout', self.label_layout)
self.config.add_layer_label('theme', self.label_theme)
self.config.add_layer_label('zoom_method', self.label_zoom_method)
self.config.add_layer_label('fix_scale', self.label_fix_scale)
self.config.add_layer_label('margin', self.label_margin)

layout_manager = QgsProject.instance().layoutManager()
for layout in layout_manager.printLayouts():
if layout.atlas().enabled():
continue
self.layout.addItem(layout.name(), layout.name())

theme_collection = QgsProject.instance().mapThemeCollection()
for theme_name in theme_collection.mapThemes():
self.theme.addItem(theme_name, theme_name)

if self._geometry == GeometryType.Point.value['data']:
fix_scale = ZoomMethodType.FixScale
self.zoom_method.addItem(fix_scale.value['label'], fix_scale.value['data'])
self.zoom_method.setCurrentText(fix_scale.value['data'])
self.zoom_method.setEnabled(False)
else:
for item_type in ZoomMethodType:
if item_type == ZoomMethodType.FixScale:
continue
self.zoom_method.addItem(item_type.value['label'], item_type.value['data'])

# connect
self.zoom_method.currentTextChanged.connect(self.zoom_method_changed)

self.button_box.button(QDialogButtonBox.StandardButton.Cancel).clicked.connect(self.close)
self.button_box.button(QDialogButtonBox.StandardButton.Ok).clicked.connect(self.accept)
self.error.setVisible(False)

self.zoom_method_changed()

def zoom_method_changed(self):
"""Enable or disable scale and margin widgets."""
zoom_method = self.zoom_method.currentData()
enable_margin = False
enable_fix_scale = False
if zoom_method == ZoomMethodType.Margin.value['data']:
enable_margin = True
elif zoom_method == ZoomMethodType.FixScale.value['data']:
enable_fix_scale = True

self.margin.setEnabled(enable_margin)
self.fix_scale.setEnabled(enable_fix_scale)

def save_form(self) -> OrderedDict:
"""Save the form into a dictionary."""
data = OrderedDict()

for key in self.config.layer_config['layouts']['items']:
definition = self.config.layer_config[key]
if definition['type'] == InputType.List:
value = definition['widget'].currentData()
elif definition['type'] == InputType.Scale:
value = definition['widget'].scale()
elif definition['type'] == InputType.SpinBox:
value = definition['widget'].value()
else:
raise Exception('InputType "{}" not implemented'.format(definition['type']))

data[key] = value

if data['zoom_method'] == ZoomMethodType.BestScale.value['data']:
del data['fix_scale']
del data['margin']
elif data['zoom_method'] == ZoomMethodType.Margin.value['data']:
del data['fix_scale']
elif data['zoom_method'] == ZoomMethodType.FixScale.value['data']:
del data['margin']
return data
Loading
Loading