Skip to content

Commit

Permalink
Merge branch 'main' into type_hinting
Browse files Browse the repository at this point in the history
  • Loading branch information
koebi committed May 15, 2024
2 parents c8db1d3 + 0e0ad02 commit d4e94cc
Show file tree
Hide file tree
Showing 15 changed files with 4,909 additions and 4,727 deletions.
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,19 @@ RELEASING:
## Unreleased

### Fixed
- Improved documentation of type hints
- QGis crashes when selecting more than two vertices for deletion ([#230](https://github.com/GIScience/orstools-qgis-plugin/issues/230))
- Vertices on canvas not depicted fully with n having more than one digit in length ([#235](https://github.com/GIScience/orstools-qgis-plugin/issues/235))
- Replace qt QSettings with QgsSettings for centralized configuration management ([#239](https://github.com/GIScience/orstools-qgis-plugin/issues/239))
- Fix: Point Annotations stay after saving project and not deleting them manually([#229](https://github.com/GIScience/orstools-qgis-plugin/issues/229))
- Improved type hints

### Added
- Add support for decimal ranges with isochrones([#237](https://github.com/GIScience/orstools-qgis-plugin/issues/237))
- Add hint for joining with `Layer ID Field` ([#143](https://github.com/GIScience/orstools-qgis-plugin/issues/143))
- Add option to export order of optimization route points ([#145](https://github.com/GIScience/orstools-qgis-plugin/issues/145))

### Changed
- Rename `Ok` button in configuration window to `Save` for clarification([#241](https://github.com/GIScience/orstools-qgis-plugin/issues/241))

## [1.7.1] - 2024-01-15

Expand Down
6 changes: 3 additions & 3 deletions ORStools/ORStoolsPlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
"""

from qgis.gui import QgisInterface
from qgis.core import QgsApplication
from PyQt5.QtCore import QTranslator, QSettings, qVersion, QCoreApplication
from qgis.core import QgsApplication, QgsSettings
from PyQt5.QtCore import QTranslator, qVersion, QCoreApplication
import os.path

from .gui import ORStoolsDialog
Expand All @@ -56,7 +56,7 @@ def __init__(self, iface: QgisInterface) -> None:
self.plugin_dir = os.path.dirname(__file__)

# initialize locale
locale = QSettings().value("locale/userLocale")[0:2]
locale = QgsSettings().value("locale/userLocale")[0:2]
locale_path = os.path.join(self.plugin_dir, "i18n", "orstools_{}.qm".format(locale))

if os.path.exists(locale_path):
Expand Down
47 changes: 36 additions & 11 deletions ORStools/gui/ORStoolsDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@
QgsPointXY,
QgsGeometry,
QgsCoordinateReferenceSystem,
QgsSettings,
)
from qgis.gui import QgsMapCanvasAnnotationItem

from PyQt5.QtCore import QSizeF, QPointF, QCoreApplication, QSettings
from PyQt5.QtCore import QSizeF, QPointF, QCoreApplication
from PyQt5.QtGui import QIcon, QTextDocument
from PyQt5.QtWidgets import (
QAction,
Expand Down Expand Up @@ -258,10 +259,10 @@ def run_gui_control(self) -> None:

# add ors svg path
my_new_path = os.path.join(basepath, "img/svg")
svg_paths = QSettings().value("svg/searchPathsForSVG") or []
svg_paths = QgsSettings().value("svg/searchPathsForSVG") or []
if my_new_path not in svg_paths:
svg_paths.append(my_new_path)
QSettings().setValue("svg/searchPathsForSVG", svg_paths)
QgsSettings().setValue("svg/searchPathsForSVG", svg_paths)

# style output layer
qml_path = os.path.join(basepath, "linestyle.qml")
Expand Down Expand Up @@ -330,6 +331,29 @@ def run_gui_control(self) -> None:
)
return
response = clnt.request("/optimization", {}, post_json=params)

if self.dlg.export_jobs_order.isChecked():
items = list()
for route in response["routes"]:
for i, step in enumerate(route["steps"]):
location = step["location"]
items.append(location)

point_layer = QgsVectorLayer(
"point?crs=epsg:4326&field=ID:integer", "Steps", "memory"
)

point_layer.updateFields()
for idx, coords in enumerate(items):
x, y = coords
feature = QgsFeature()
feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(x, y)))
feature.setAttributes([idx])

point_layer.dataProvider().addFeature(feature)
QgsProject.instance().addMapLayer(point_layer)
self.dlg._iface.mapCanvas().refresh()

feat = directions_core.get_output_features_optimization(
response, params["vehicles"][0]["profile"]
)
Expand Down Expand Up @@ -466,6 +490,8 @@ def __init__(self, iface: QgisInterface, parent=None) -> None:
self.routing_fromline_list.model().rowsMoved.connect(self._reindex_list_items)
self.routing_fromline_list.model().rowsRemoved.connect(self._reindex_list_items)

self.annotation_canvas = self._iface.mapCanvas()

def _save_vertices_to_layer(self) -> None:
"""Saves the vertices list to a temp layer"""
items = [
Expand Down Expand Up @@ -505,12 +531,12 @@ def _on_clear_listwidget_click(self) -> None:
"""Clears the contents of the QgsListWidget and the annotations."""
items = self.routing_fromline_list.selectedItems()
if items:
rows = [self.routing_fromline_list.row(item) for item in items]
# if items are selected, only clear those
for item in items:
row = self.routing_fromline_list.row(item)
self.routing_fromline_list.takeItem(row)
for row in sorted(rows, reverse=True):
if self.annotations:
self.project.annotationManager().removeAnnotation(self.annotations.pop(row))
self.routing_fromline_list.takeItem(row)
else:
# else clear all items and annotations
self.routing_fromline_list.clear()
Expand All @@ -534,16 +560,17 @@ def _linetool_annotate_point(

annotation.setDocument(c)

annotation.setFrameSizeMm(QSizeF(7, 5))
annotation.setFrameSizeMm(QSizeF(8, 5))
annotation.setFrameOffsetFromReferencePointMm(QPointF(1.3, 1.3))
annotation.setMapPosition(point)
annotation.setMapPositionCrs(crs)

return QgsMapCanvasAnnotationItem(annotation, self._iface.mapCanvas()).annotation()
return QgsMapCanvasAnnotationItem(annotation, self.annotation_canvas).annotation()

def _clear_annotations(self) -> None:
"""Clears annotations"""
for annotation in self.annotations:
for annotation_item in self.annotation_canvas.annotationItems():
annotation = annotation_item.annotation()
if annotation in self.project.annotationManager().annotations():
self.project.annotationManager().removeAnnotation(annotation)
self.annotations = []
Expand Down Expand Up @@ -575,7 +602,6 @@ def _on_linetool_map_click(self, point: QgsPointXY, idx: int) -> None:
self.routing_fromline_list.addItem(f"Point {idx}: {point_wgs.x():.6f}, {point_wgs.y():.6f}")

annotation = self._linetool_annotate_point(point, idx)
self.annotations.append(annotation)
self.project.annotationManager().addAnnotation(annotation)

def _reindex_list_items(self) -> None:
Expand All @@ -595,7 +621,6 @@ def _reindex_list_items(self) -> None:

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) -> None:
Expand Down
5 changes: 4 additions & 1 deletion ORStools/gui/ORStoolsDialogConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

from PyQt5 import QtWidgets
from PyQt5.QtCore import QMetaObject
from PyQt5.QtWidgets import QDialog, QInputDialog, QLineEdit
from PyQt5.QtWidgets import QDialog, QInputDialog, QLineEdit, QDialogButtonBox
from PyQt5.QtGui import QIntValidator

from ORStools.utils import configmanager
Expand Down Expand Up @@ -59,6 +59,9 @@ def __init__(self, parent=None) -> None:
self.provider_add.clicked.connect(self._add_provider)
self.provider_remove.clicked.connect(self._remove_provider)

# Change OK to Save in config window
self.buttonBox.button(QDialogButtonBox.Ok).setText(self.tr("Save"))

def accept(self) -> None:
"""When the OK Button is clicked, in-memory temp_config is updated and written to config.yml"""

Expand Down
57 changes: 31 additions & 26 deletions ORStools/gui/ORStoolsDialogUI.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# -*- 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.15.4
# Created by: PyQt5 UI code generator 5.15.10
#
# 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.
Expand All @@ -14,7 +14,7 @@
class Ui_ORStoolsDialogBase(object):
def setupUi(self, ORStoolsDialogBase):
ORStoolsDialogBase.setObjectName("ORStoolsDialogBase")
ORStoolsDialogBase.resize(412, 686)
ORStoolsDialogBase.resize(412, 868)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
Expand Down Expand Up @@ -205,7 +205,7 @@ def setupUi(self, ORStoolsDialogBase):
self.save_vertices.setSizePolicy(sizePolicy)
self.save_vertices.setText("")
icon4 = QtGui.QIcon()
icon4.addPixmap(QtGui.QPixmap(":/plugins/ORStools/img/save_vertices.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon4.addPixmap(QtGui.QPixmap(":/plugins/ORStools/img/icon_save.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.save_vertices.setIcon(icon4)
self.save_vertices.setObjectName("save_vertices")
self.gridLayout.addWidget(self.save_vertices, 2, 0, 1, 1)
Expand Down Expand Up @@ -241,33 +241,36 @@ def setupUi(self, ORStoolsDialogBase):
self.gridLayout_2 = QtWidgets.QGridLayout(self.optimization_group)
self.gridLayout_2.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
self.gridLayout_2.setObjectName("gridLayout_2")
self.fix_both = QtWidgets.QRadioButton(self.optimization_group)
self.fix_both.setChecked(False)
self.fix_both.setObjectName("fix_both")
self.optimize_button_group = QtWidgets.QButtonGroup(ORStoolsDialogBase)
self.optimize_button_group.setObjectName("optimize_button_group")
self.optimize_button_group.addButton(self.fix_both)
self.gridLayout_2.addWidget(self.fix_both, 2, 3, 1, 1)
self.label_4 = QtWidgets.QLabel(self.optimization_group)
self.label_4.setEnabled(False)
self.label_4.setObjectName("label_4")
self.gridLayout_2.addWidget(self.label_4, 0, 0, 1, 4)
self.fix_start = QtWidgets.QRadioButton(self.optimization_group)
self.fix_start.setObjectName("fix_start")
self.optimize_button_group = QtWidgets.QButtonGroup(ORStoolsDialogBase)
self.optimize_button_group.setObjectName("optimize_button_group")
self.optimize_button_group.addButton(self.fix_start)
self.gridLayout_2.addWidget(self.fix_start, 2, 1, 1, 1)
self.label_5 = QtWidgets.QLabel(self.optimization_group)
self.label_5.setObjectName("label_5")
self.gridLayout_2.addWidget(self.label_5, 1, 0, 1, 3, QtCore.Qt.AlignHCenter)
self.fix_end = QtWidgets.QRadioButton(self.optimization_group)
self.fix_end.setObjectName("fix_end")
self.optimize_button_group.addButton(self.fix_end)
self.gridLayout_2.addWidget(self.fix_end, 2, 2, 1, 1)
self.label_5 = QtWidgets.QLabel(self.optimization_group)
self.label_5.setObjectName("label_5")
self.gridLayout_2.addWidget(self.label_5, 1, 0, 1, 3, QtCore.Qt.AlignHCenter)
self.fix_both = QtWidgets.QRadioButton(self.optimization_group)
self.fix_both.setChecked(False)
self.fix_both.setObjectName("fix_both")
self.optimize_button_group.addButton(self.fix_both)
self.gridLayout_2.addWidget(self.fix_both, 2, 3, 1, 1)
self.fix_start = QtWidgets.QRadioButton(self.optimization_group)
self.fix_start.setObjectName("fix_start")
self.optimize_button_group.addButton(self.fix_start)
self.gridLayout_2.addWidget(self.fix_start, 2, 1, 1, 1)
self.round_trip = QtWidgets.QRadioButton(self.optimization_group)
self.round_trip.setChecked(True)
self.round_trip.setObjectName("round_trip")
self.optimize_button_group.addButton(self.round_trip)
self.gridLayout_2.addWidget(self.round_trip, 2, 0, 1, 1)
self.export_jobs_order = QtWidgets.QCheckBox(self.optimization_group)
self.export_jobs_order.setObjectName("export_jobs_order")
self.gridLayout_2.addWidget(self.export_jobs_order, 3, 1, 1, 2)
self.verticalLayout_3.addWidget(self.optimization_group)
self.routing_avoid_tags_group = QgsCollapsibleGroupBox(self.advances_group)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
Expand Down Expand Up @@ -464,8 +467,8 @@ def setupUi(self, ORStoolsDialogBase):

self.retranslateUi(ORStoolsDialogBase)
self.tabWidget.setCurrentIndex(0)
self.global_buttons.accepted.connect(ORStoolsDialogBase.accept)
self.global_buttons.rejected.connect(ORStoolsDialogBase.reject)
self.global_buttons.accepted.connect(ORStoolsDialogBase.accept) # type: ignore
self.global_buttons.rejected.connect(ORStoolsDialogBase.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(ORStoolsDialogBase)

def retranslateUi(self, ORStoolsDialogBase):
Expand All @@ -488,20 +491,22 @@ def retranslateUi(self, ORStoolsDialogBase):
self.advances_group.setTitle(_translate("ORStoolsDialogBase", "Advanced Configuration"))
self.optimization_group.setToolTip(_translate("ORStoolsDialogBase", "<html><head/><body><p>Enabling Traveling Salesman will omit all other advanced configuration and assume the preference to be <span style=\" font-weight:600;\">fastest</span>.</p></body></html>"))
self.optimization_group.setTitle(_translate("ORStoolsDialogBase", "Traveling Salesman"))
self.fix_both.setToolTip(_translate("ORStoolsDialogBase", "<html><head/><body><p>First and last waypoints are not optimized.</p></body></html>"))
self.fix_both.setText(_translate("ORStoolsDialogBase", "Fix Both"))
self.label_4.setText(_translate("ORStoolsDialogBase", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Ubuntu\'; font-size:11pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" padding: 10px; -qt-block-indent:0; text-indent:0px ; background-color:#e7f2fa; color: #999999\"><img stype=\"margin: 10px\" src=\":/plugins/ORStools/img/icon_about.png\" width=16 height=16 /> All other configuration will be omitted</p></body></html>"))
self.fix_start.setToolTip(_translate("ORStoolsDialogBase", "<html><head/><body><p>First waypoint won\'t be optimized.</p></body></html>"))
self.fix_start.setText(_translate("ORStoolsDialogBase", "Fix Start"))
self.label_5.setText(_translate("ORStoolsDialogBase", "<html><head/><body><p><span style=\" font-weight:600;\">Other Options</span></p></body></html>"))
self.fix_end.setToolTip(_translate("ORStoolsDialogBase", "<html><head/><body><p>Last waypoint won\'t be optimized.</p></body></html>"))
self.fix_end.setText(_translate("ORStoolsDialogBase", "Fix End"))
self.label_5.setText(_translate("ORStoolsDialogBase", "<html><head/><body><p><span style=\" font-weight:600;\">Other Options</span></p></body></html>"))
self.fix_both.setToolTip(_translate("ORStoolsDialogBase", "<html><head/><body><p>First and last waypoints are not optimized.</p></body></html>"))
self.fix_both.setText(_translate("ORStoolsDialogBase", "Fix Both"))
self.fix_start.setToolTip(_translate("ORStoolsDialogBase", "<html><head/><body><p>First waypoint won\'t be optimized.</p></body></html>"))
self.fix_start.setText(_translate("ORStoolsDialogBase", "Fix Start"))
self.round_trip.setToolTip(_translate("ORStoolsDialogBase", "<html><head/><body><p>Return to first waypoint after last waypoint.</p></body></html>"))
self.round_trip.setText(_translate("ORStoolsDialogBase", "Round Trip"))
self.export_jobs_order.setToolTip(_translate("ORStoolsDialogBase", "<html><body><p>Create a point layer with the order in which the waypoints are traversed.</p></body></html>"))
self.export_jobs_order.setText(_translate("ORStoolsDialogBase", "Export order of jobs"))
self.routing_avoid_tags_group.setToolTip(_translate("ORStoolsDialogBase", "Avoid certain road attributes."))
self.routing_avoid_tags_group.setTitle(_translate("ORStoolsDialogBase", "Avoid tags"))
self.routing_avoid_highways_3.setText(_translate("ORStoolsDialogBase", "highways"))
Expand Down Expand Up @@ -533,4 +538,4 @@ def retranslateUi(self, ORStoolsDialogBase):
from qgscollapsiblegroupbox import QgsCollapsibleGroupBox
from qgsfilterlineedit import QgsFilterLineEdit
from qgsmaplayercombobox import QgsMapLayerComboBox
# import resources_rc
from . import resources_rc
Loading

0 comments on commit d4e94cc

Please sign in to comment.