diff --git a/lizmap/dialogs/dock_html_preview.py b/lizmap/dialogs/dock_html_preview.py
new file mode 100644
index 00000000..5b0aa302
--- /dev/null
+++ b/lizmap/dialogs/dock_html_preview.py
@@ -0,0 +1,153 @@
+__copyright__ = 'Copyright 2023, 3Liz'
+__license__ = 'GPL version 3'
+__email__ = 'info@3liz.org'
+
+import logging
+
+from qgis.core import (
+ Qgis,
+ QgsApplication,
+ QgsExpression,
+ QgsExpressionContext,
+ QgsExpressionContextUtils,
+ QgsMapLayerProxyModel,
+ QgsProject,
+)
+
+if Qgis.QGIS_VERSION_INT >= 31400:
+ from qgis.gui import QgsFeaturePickerWidget
+
+from qgis.gui import QgsMapLayerComboBox
+from qgis.PyQt.QtCore import QDateTime, QLocale, QUrl
+from qgis.PyQt.QtGui import QIcon
+from qgis.PyQt.QtWidgets import (
+ QDockWidget,
+ QHBoxLayout,
+ QLabel,
+ QPushButton,
+ QSizePolicy,
+ QVBoxLayout,
+ QWidget,
+)
+from qgis.utils import iface
+
+from lizmap.qgis_plugin_tools.tools.i18n import tr
+from lizmap.qgis_plugin_tools.tools.resources import resources_path
+
+try:
+ from qgis.PyQt.QtWebKitWidgets import QWebView
+ WEBKIT_AVAILABLE = True
+except ModuleNotFoundError:
+ WEBKIT_AVAILABLE = False
+
+LOGGER = logging.getLogger('Lizmap')
+
+
+class HtmlPreview(QDockWidget):
+
+ # noinspection PyArgumentList
+ def __init__(self, parent, *__args):
+ """ Constructor. """
+ super().__init__(parent, *__args)
+ self.setWindowTitle("Lizmap HTML Maptip Preview")
+
+ self.dock = QWidget(parent)
+ self.layout = QVBoxLayout(self.dock)
+
+ if Qgis.QGIS_VERSION_INT < 31400:
+ self.label = QLabel('You must install at least QGIS 3.14')
+ self.label.setWordWrap(True)
+ self.layout.addWidget(self.label)
+ return
+
+ if not WEBKIT_AVAILABLE:
+ self.label = QLabel(tr('You must install Qt Webkit to enable this feature.'))
+ else:
+ self.label = QLabel(tr("This only a preview of the HTML maptip. Lizmap will add more CSS classes."))
+
+ self.label.setWordWrap(True)
+ self.layout.addWidget(self.label)
+
+ if not WEBKIT_AVAILABLE:
+ return
+
+ horizontal = QHBoxLayout(self.dock)
+
+ self.layer = QgsMapLayerComboBox(self.dock)
+ horizontal.addWidget(self.layer)
+
+ self.feature = QgsFeaturePickerWidget(self.dock)
+ horizontal.addWidget(self.feature)
+
+ self.layout.addLayout(horizontal)
+
+ horizontal = QHBoxLayout(self.dock)
+
+ self.refresh = QPushButton(self.dock)
+ self.refresh.setIcon(QIcon(QgsApplication.iconPath('mActionRefresh.svg')))
+ # noinspection PyUnresolvedReferences
+ self.refresh.clicked.connect(self.update_html)
+ horizontal.addWidget(self.refresh)
+
+ self.label = QLabel()
+ horizontal.addWidget(self.label)
+
+ self.layout.addLayout(horizontal)
+
+ self.web_view = QWebView(self.dock)
+ size_policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding)
+ size_policy.setHorizontalStretch(0)
+ size_policy.setVerticalStretch(0)
+ size_policy.setHeightForWidth(self.web_view.sizePolicy().hasHeightForWidth())
+ self.web_view.setSizePolicy(size_policy)
+ self.layout.addWidget(self.web_view)
+
+ self.setWidget(self.dock)
+
+ self.layer.setFilters(QgsMapLayerProxyModel.VectorLayer)
+ # noinspection PyUnresolvedReferences
+ self.layer.layerChanged.connect(self.current_layer_changed)
+ self.current_layer_changed()
+ # noinspection PyUnresolvedReferences
+ self.feature.featureChanged.connect(self.update_html)
+ self.feature.setShowBrowserButtons(True)
+
+ # We don't have a better signal to listen to
+ QgsProject.instance().dirtySet.connect(self.update_html)
+
+ self.update_html()
+
+ def current_layer_changed(self):
+ """ When the layer has changed. """
+ self.feature.setLayer(self.layer.currentLayer())
+ # Need to disconnect all layers before ?
+ # self.layer.currentLayer().repaintRequested.connect(self.update_html())
+
+ # noinspection PyArgumentList
+ def update_html(self):
+ """ Update the HTML preview. """
+ layer = self.layer.currentLayer()
+ feature = self.feature.feature()
+ if not layer:
+ return
+
+ if iface.activeLayer() != layer:
+ # This function is called when the project is "setDirty",
+ # because it means maybe the vector layer properties has been "applied"
+ return
+
+ if not feature:
+ return
+
+ now = QDateTime.currentDateTime()
+ now_str = now.toString(QLocale.c().timeFormat(QLocale.ShortFormat))
+ self.label.setText(tr("Last update") + " " + now_str)
+
+ exp_context = QgsExpressionContext()
+ exp_context.appendScope(QgsExpressionContextUtils.globalScope())
+ exp_context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
+ exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))
+ exp_context.setFeature(feature)
+ html_string = QgsExpression.replaceExpressionText(layer.mapTipTemplate(), exp_context)
+ base_url = QUrl.fromLocalFile(resources_path('images', 'non_existing_file.png'))
+ self.web_view.setHtml(html_string, base_url)
diff --git a/lizmap/plugin.py b/lizmap/plugin.py
index ef24ecc3..6a54cc8a 100755
--- a/lizmap/plugin.py
+++ b/lizmap/plugin.py
@@ -97,6 +97,7 @@
from lizmap.definitions.time_manager import TimeManagerDefinitions
from lizmap.definitions.tooltip import ToolTipDefinitions
from lizmap.definitions.warnings import Warnings
+from lizmap.dialogs.dock_html_preview import HtmlPreview
from lizmap.dialogs.html_editor import HtmlEditorDialog
from lizmap.dialogs.html_maptip import HtmlMapTipDialog
from lizmap.dialogs.lizmap_popup import LizmapPopupDialog
@@ -223,6 +224,7 @@ def __init__(self, iface):
self.version = version()
self.is_dev_version = any(item in self.version for item in UNSTABLE_VERSION_PREFIX)
self.dlg = LizmapDialog(is_dev_version=self.is_dev_version)
+ self.dock_html_preview = None
self.version_checker = None
if self.is_dev_version:
@@ -962,6 +964,13 @@ def initGui(self):
# noinspection PyUnresolvedReferences
self.action.triggered.connect(self.run)
+ self.dock_html_preview = HtmlPreview(None)
+ self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock_html_preview)
+ self.dock_html_preview.setVisible(False)
+ self.dlg.button_maptip_preview.setText('')
+ self.dlg.button_maptip_preview.setIcon(QIcon(":images/themes/default/mActionShowAllLayers.svg"))
+ self.dlg.button_maptip_preview.clicked.connect(self.open_dock_preview_maptip)
+
if self.is_dev_version:
label = 'Lizmap dev'
self.action_debug_pg_qgis = QAction(icon, "Add PostgreSQL connection from datasource")
@@ -1360,6 +1369,10 @@ def unload(self):
self.iface.webMenu().removeAction(self.action)
self.iface.removeWebToolBarIcon(self.action)
+ if self.dock_html_preview:
+ self.iface.removeDockWidget(self.dock_html_preview)
+ del self.dock_html_preview
+
if self.help_action:
self.iface.pluginHelpMenu().removeAction(self.help_action)
del self.help_action
@@ -1378,6 +1391,7 @@ def enable_popup_source_button(self):
data = self.layer_options_list['popupSource']['widget'].currentData()
self.dlg.btConfigurePopup.setVisible(data in ('lizmap', 'qgis'))
self.dlg.widget_qgis_maptip.setVisible(data == 'qgis')
+ self.dlg.button_maptip_preview.setVisible(data == 'qgis')
if data == 'lizmap':
layer = self._current_selected_layer()
@@ -4018,6 +4032,13 @@ def on_project_read(self):
self.reinit_default_properties()
self.dlg.close()
+ def open_dock_preview_maptip(self):
+ if self.dock_html_preview.isVisible():
+ return
+
+ self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock_html_preview)
+ self.dock_html_preview.setVisible(True)
+
def run(self) -> bool:
"""Plugin run method : launch the GUI."""
self.dlg.check_action_file_exists()
diff --git a/lizmap/resources/ui/ui_lizmap.ui b/lizmap/resources/ui/ui_lizmap.ui
index 47736065..ff95796b 100755
--- a/lizmap/resources/ui/ui_lizmap.ui
+++ b/lizmap/resources/ui/ui_lizmap.ui
@@ -1735,6 +1735,13 @@ This is different to the map maximum extent (defined in QGIS project properties,
+ -
+
+
+ PREVIEW
+
+
+
-