From 3a82861f0443eae4131640b049dacceed58f79b6 Mon Sep 17 00:00:00 2001 From: Till Frankenbach <81414045+Merydian@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:51:19 +0100 Subject: [PATCH] feat: add drag-and-drop for points in GUI --- CHANGELOG.md | 1 + ORStools/gui/ORStoolsDialog.py | 41 ++++++++++++++++++++++++++++---- ORStools/gui/ORStoolsDialogUI.py | 40 +++++++++++++++++-------------- ORStools/gui/ORStoolsDialogUI.ui | 13 ++++++---- 4 files changed, 68 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff378dc4..cb459e3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ RELEASING: - Additional parameter for the "smoothing factor" to isochrones processing algorithms ([#172](https://github.com/GIScience/orstools-qgis-plugin/issues/172)) - Mention omission of configuration options when using traveling salesman - option to set location type for isochrones ([#191](https://github.com/GIScience/orstools-qgis-plugin/pull/191)) +- make items in centroid list drag and droppable ([#144](https://github.com/GIScience/orstools-qgis-plugin/issues/144)) ## [1.6.0] - 2023-07-25 diff --git a/ORStools/gui/ORStoolsDialog.py b/ORStools/gui/ORStoolsDialog.py index 39e119b7..0d879c5e 100644 --- a/ORStools/gui/ORStoolsDialog.py +++ b/ORStools/gui/ORStoolsDialog.py @@ -31,7 +31,14 @@ import os import processing import webbrowser -from qgis.core import QgsProject, QgsVectorLayer, QgsTextAnnotation, QgsMapLayerProxyModel +from qgis.core import ( + QgsProject, + QgsVectorLayer, + QgsTextAnnotation, + QgsMapLayerProxyModel, + QgsCoordinateReferenceSystem, + QgsPointXY, +) from qgis.gui import QgsMapCanvasAnnotationItem from PyQt5.QtCore import QSizeF, QPointF, QCoreApplication @@ -422,6 +429,10 @@ def __init__(self, iface, parent=None): lambda: processing.execAlgorithmDialog(f"{PLUGIN_NAME}:matrix_from_layers") ) + # Reset index of list items every time something is moved or deleted + self.routing_fromline_list.model().rowsMoved.connect(self._reindex_list_items) + self.routing_fromline_list.model().rowsRemoved.connect(self._reindex_list_items) + def _on_prov_refresh_click(self): """Populates provider dropdown with fresh list from config.yml""" @@ -445,8 +456,10 @@ def _on_clear_listwidget_click(self): self.routing_fromline_list.clear() self._clear_annotations() - def _linetool_annotate_point(self, point, idx): - map_crs = self._iface.mapCanvas().mapSettings().destinationCrs() + def _linetool_annotate_point(self, point, idx, crs=None): + if not crs: + crs = self._iface.mapCanvas().mapSettings().destinationCrs() + annotation = QgsTextAnnotation() c = QTextDocument() @@ -458,7 +471,7 @@ def _linetool_annotate_point(self, point, idx): annotation.setFrameSizeMm(QSizeF(7, 5)) annotation.setFrameOffsetFromReferencePointMm(QPointF(1.3, 1.3)) annotation.setMapPosition(point) - annotation.setMapPositionCrs(map_crs) + annotation.setMapPositionCrs(crs) return QgsMapCanvasAnnotationItem(annotation, self._iface.mapCanvas()).annotation() @@ -495,6 +508,26 @@ def _on_linetool_map_click(self, point, idx): self.annotations.append(annotation) self.project.annotationManager().addAnnotation(annotation) + def _reindex_list_items(self): + """Resets the index when an item in the list is moved""" + items = [ + self.routing_fromline_list.item(x).text() + for x in range(self.routing_fromline_list.count()) + ] + self.routing_fromline_list.clear() + self._clear_annotations() + crs = QgsCoordinateReferenceSystem(f"EPSG:{4326}") + for idx, x in enumerate(items): + coords = x.split(":")[1] + item = f"Point {idx}:{coords}" + x, y = (float(i) for i in coords.split(", ")) + point = QgsPointXY(x, y) + + self.routing_fromline_list.addItem(item) + annotation = self._linetool_annotate_point(point, idx, crs) + self.annotations.append(annotation) + self.project.annotationManager().addAnnotation(annotation) + def _on_linetool_map_doubleclick(self): """ Populate line list widget with coordinates, end line drawing and show dialog again. diff --git a/ORStools/gui/ORStoolsDialogUI.py b/ORStools/gui/ORStoolsDialogUI.py index 2f4f2429..ab727b0e 100644 --- a/ORStools/gui/ORStoolsDialogUI.py +++ b/ORStools/gui/ORStoolsDialogUI.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'ORStoolsDialogUI.ui' +# Form implementation generated from reading ui file 'ORSToolsDialogUI.ui' # -# Created by: PyQt5 UI code generator 5.14.1 +# Created by: PyQt5 UI code generator 5.15.4 # -# WARNING! All changes made in this file will be lost! +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. from PyQt5 import QtCore, QtGui, QtWidgets @@ -191,18 +192,19 @@ def setupUi(self, ORStoolsDialogBase): self.routing_fromline_list.setMinimumSize(QtCore.QSize(0, 0)) self.routing_fromline_list.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.routing_fromline_list.setFrameShadow(QtWidgets.QFrame.Sunken) + self.routing_fromline_list.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) self.routing_fromline_list.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) self.routing_fromline_list.setResizeMode(QtWidgets.QListView.Fixed) self.routing_fromline_list.setObjectName("routing_fromline_list") self.gridLayout.addWidget(self.routing_fromline_list, 0, 2, 3, 1) self.verticalLayout_7.addWidget(self.widget) - self.advances_group = gui.QgsCollapsibleGroupBox(self.qwidget) + self.advances_group = QgsCollapsibleGroupBox(self.qwidget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.advances_group.sizePolicy().hasHeightForWidth()) self.advances_group.setSizePolicy(sizePolicy) - self.advances_group.setMaximumSize(QtCore.QSize(16777215, 23)) + self.advances_group.setMaximumSize(QtCore.QSize(16777215, 20)) self.advances_group.setCheckable(False) self.advances_group.setChecked(False) self.advances_group.setCollapsed(True) @@ -211,14 +213,14 @@ def setupUi(self, ORStoolsDialogBase): self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.advances_group) self.verticalLayout_3.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) self.verticalLayout_3.setObjectName("verticalLayout_3") - self.optimization_group = gui.QgsCollapsibleGroupBox(self.advances_group) + self.optimization_group = QgsCollapsibleGroupBox(self.advances_group) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.optimization_group.sizePolicy().hasHeightForWidth()) self.optimization_group.setSizePolicy(sizePolicy) self.optimization_group.setMinimumSize(QtCore.QSize(0, 0)) - self.optimization_group.setMaximumSize(QtCore.QSize(16777215, 23)) + self.optimization_group.setMaximumSize(QtCore.QSize(16777215, 20)) self.optimization_group.setCheckable(True) self.optimization_group.setChecked(False) self.optimization_group.setCollapsed(True) @@ -255,7 +257,7 @@ def setupUi(self, ORStoolsDialogBase): self.optimize_button_group.addButton(self.round_trip) self.gridLayout_2.addWidget(self.round_trip, 2, 0, 1, 1) self.verticalLayout_3.addWidget(self.optimization_group) - self.routing_avoid_tags_group = gui.QgsCollapsibleGroupBox(self.advances_group) + self.routing_avoid_tags_group = QgsCollapsibleGroupBox(self.advances_group) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -285,13 +287,13 @@ def setupUi(self, ORStoolsDialogBase): self.routing_avoid_tracks_3.setObjectName("routing_avoid_tracks_3") self.gridLayout_4.addWidget(self.routing_avoid_tracks_3, 2, 0, 1, 1) self.verticalLayout_3.addWidget(self.routing_avoid_tags_group) - self.routing_avoid_countries_group = gui.QgsCollapsibleGroupBox(self.advances_group) + self.routing_avoid_countries_group = QgsCollapsibleGroupBox(self.advances_group) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.routing_avoid_countries_group.sizePolicy().hasHeightForWidth()) self.routing_avoid_countries_group.setSizePolicy(sizePolicy) - self.routing_avoid_countries_group.setMaximumSize(QtCore.QSize(16777215, 23)) + self.routing_avoid_countries_group.setMaximumSize(QtCore.QSize(16777215, 20)) self.routing_avoid_countries_group.setCheckable(True) self.routing_avoid_countries_group.setChecked(False) self.routing_avoid_countries_group.setCollapsed(True) @@ -299,18 +301,18 @@ def setupUi(self, ORStoolsDialogBase): self.routing_avoid_countries_group.setObjectName("routing_avoid_countries_group") self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.routing_avoid_countries_group) self.verticalLayout_4.setObjectName("verticalLayout_4") - self.countries_text = gui.QgsFilterLineEdit(self.routing_avoid_countries_group) + self.countries_text = QgsFilterLineEdit(self.routing_avoid_countries_group) self.countries_text.setProperty("qgisRelation", "") self.countries_text.setObjectName("countries_text") self.verticalLayout_4.addWidget(self.countries_text) self.verticalLayout_3.addWidget(self.routing_avoid_countries_group) - self.avoidpolygon_group = gui.QgsCollapsibleGroupBox(self.advances_group) + self.avoidpolygon_group = QgsCollapsibleGroupBox(self.advances_group) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.avoidpolygon_group.sizePolicy().hasHeightForWidth()) self.avoidpolygon_group.setSizePolicy(sizePolicy) - self.avoidpolygon_group.setMaximumSize(QtCore.QSize(16777215, 23)) + self.avoidpolygon_group.setMaximumSize(QtCore.QSize(16777215, 20)) self.avoidpolygon_group.setCheckable(True) self.avoidpolygon_group.setChecked(False) self.avoidpolygon_group.setCollapsed(True) @@ -318,7 +320,7 @@ def setupUi(self, ORStoolsDialogBase): self.avoidpolygon_group.setObjectName("avoidpolygon_group") self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.avoidpolygon_group) self.verticalLayout_6.setObjectName("verticalLayout_6") - self.avoidpolygon_dropdown = gui.QgsMapLayerComboBox(self.avoidpolygon_group) + self.avoidpolygon_dropdown = QgsMapLayerComboBox(self.avoidpolygon_group) self.avoidpolygon_dropdown.setShowCrs(False) self.avoidpolygon_dropdown.setObjectName("avoidpolygon_dropdown") self.verticalLayout_6.addWidget(self.avoidpolygon_dropdown) @@ -381,14 +383,14 @@ def setupUi(self, ORStoolsDialogBase): self.verticalLayout.addItem(spacerItem) self.tabWidget.addTab(self.batch_tab, "") self.verticalLayout_5.addWidget(self.tabWidget) - self.ors_log_group = gui.QgsCollapsibleGroupBox(ORStoolsDialogBase) + self.ors_log_group = QgsCollapsibleGroupBox(ORStoolsDialogBase) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.ors_log_group.sizePolicy().hasHeightForWidth()) self.ors_log_group.setSizePolicy(sizePolicy) self.ors_log_group.setMinimumSize(QtCore.QSize(0, 0)) - self.ors_log_group.setMaximumSize(QtCore.QSize(16777215, 23)) + self.ors_log_group.setMaximumSize(QtCore.QSize(16777215, 20)) self.ors_log_group.setFlat(True) self.ors_log_group.setCollapsed(True) self.ors_log_group.setSaveCollapsedState(False) @@ -515,5 +517,7 @@ def retranslateUi(self, ORStoolsDialogBase): self.debug_text.setPlaceholderText(_translate("ORStoolsDialogBase", "Queries and errors will be printed here.")) self.help_button.setText(_translate("ORStoolsDialogBase", " Help")) self.about_button.setText(_translate("ORStoolsDialogBase", "About")) -from qgis import gui -from . import resources_rc +from qgscollapsiblegroupbox import QgsCollapsibleGroupBox +from qgsfilterlineedit import QgsFilterLineEdit +from qgsmaplayercombobox import QgsMapLayerComboBox +# import resources_rc diff --git a/ORStools/gui/ORStoolsDialogUI.ui b/ORStools/gui/ORStoolsDialogUI.ui index f838897b..b076bd9a 100644 --- a/ORStools/gui/ORStoolsDialogUI.ui +++ b/ORStools/gui/ORStoolsDialogUI.ui @@ -330,6 +330,9 @@ QFrame::Sunken + + QAbstractItemView::InternalMove + QAbstractItemView::MultiSelection @@ -352,7 +355,7 @@ 16777215 - 23 + 20 @@ -391,7 +394,7 @@ 16777215 - 23 + 20 @@ -577,7 +580,7 @@ p, li { white-space: pre-wrap; } 16777215 - 23 + 20 @@ -623,7 +626,7 @@ p, li { white-space: pre-wrap; } 16777215 - 23 + 20 @@ -789,7 +792,7 @@ p, li { white-space: pre-wrap; } 16777215 - 23 + 20