From 42f2771da898a0757c65dc8d2bb53da3f323035e Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 29 Feb 2024 11:52:16 +0700 Subject: [PATCH 1/5] Add vector layer properties' tracking session UI --- qfieldsync/gui/map_layer_config_widget.py | 37 +-- qfieldsync/ui/map_layer_config_widget.ui | 292 ++++++++++++++++++---- 2 files changed, 258 insertions(+), 71 deletions(-) diff --git a/qfieldsync/gui/map_layer_config_widget.py b/qfieldsync/gui/map_layer_config_widget.py index 5b3103b6..c0d483ad 100644 --- a/qfieldsync/gui/map_layer_config_widget.py +++ b/qfieldsync/gui/map_layer_config_widget.py @@ -74,6 +74,14 @@ def __init__(self, layer, canvas, parent): self.layer_source.action, ) + self.attachmentNamingTable = AttachmentNamingTableWidget() + self.attachmentNamingTable.addLayerFields(self.layer_source) + self.attachmentNamingTable.setLayerColumnHidden(True) + + self.relationshipConfigurationTable = RelationshipConfigurationTableWidget() + self.relationshipConfigurationTable.addLayerFields(self.layer_source) + self.relationshipConfigurationTable.setLayerColumnHidden(True) + if layer.type() == QgsMapLayer.VectorLayer: prop = QgsProperty.fromExpression( self.layer_source.geometry_locked_expression @@ -100,17 +108,9 @@ def __init__(self, layer, canvas, parent): self.isGeometryLockedCheckBox.setChecked( self.layer_source.is_geometry_locked ) - else: - self.isGeometryLockedDDButton.setVisible(False) - self.isGeometryLockedCheckBox.setVisible(False) - self.attachmentNamingTable = AttachmentNamingTableWidget() - self.attachmentNamingTable.addLayerFields(self.layer_source) - self.attachmentNamingTable.setLayerColumnHidden(True) - - # append the attachment naming table to the layout - if layer.type() == QgsMapLayer.VectorLayer: - self.layout().insertRow( + # append the attachment naming table to the layout + self.attachmentsRelationsLayout.insertRow( -1, self.tr("Attachment\nnaming"), self.attachmentNamingTable ) tip = QLabel( @@ -119,18 +119,13 @@ def __init__(self, layer, canvas, parent): ) ) tip.setWordWrap(True) - self.layout().insertRow(-1, "", tip) + self.attachmentsRelationsLayout.insertRow(-1, "", tip) self.attachmentNamingTable.setEnabled( self.attachmentNamingTable.rowCount() > 0 ) - self.relationshipConfigurationTable = RelationshipConfigurationTableWidget() - self.relationshipConfigurationTable.addLayerFields(self.layer_source) - self.relationshipConfigurationTable.setLayerColumnHidden(True) - - # append the relationship configuration table to the layout - if layer.type() == QgsMapLayer.VectorLayer: - self.layout().insertRow( + # append the relationship configuration table to the layout + self.attachmentsRelationsLayout.insertRow( -1, self.tr("Relationship\nconfiguration"), self.relationshipConfigurationTable, @@ -138,6 +133,12 @@ def __init__(self, layer, canvas, parent): self.relationshipConfigurationTable.setEnabled( self.relationshipConfigurationTable.rowCount() > 0 ) + else: + self.isGeometryLockedDDButton.setVisible(False) + self.isGeometryLockedCheckBox.setVisible(False) + + self.attachmentsRelationsGroupBox.setVisible(False) + self.trackingSessionGroupBox.setVisible(False) def apply(self): old_layer_action = self.layer_source.action diff --git a/qfieldsync/ui/map_layer_config_widget.ui b/qfieldsync/ui/map_layer_config_widget.ui index d57601bb..f98f61c6 100644 --- a/qfieldsync/ui/map_layer_config_widget.ui +++ b/qfieldsync/ui/map_layer_config_widget.ui @@ -13,76 +13,262 @@ Form - - - - - - 0 - 0 - + + + + + General Settings + + + + + + 0 + 0 + + + + + + + + Cloud layer action + + + + + + + Cable layer action + + + + + + + + + When enabled, this option disables adding and deleting features, as well as modifying the geometries of existing features. + + + Lock geometries + + + + + + + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + - - - - Cloud layer action + + + + Attachments and Relationships Settings + + - - - - Cable layer action + + + + Tracking Session + + true + + + false + + + true + + + + + + When enabled, QField will automatically start a tracking session upon successfully loading the project. + + + true + + + + + + + Requirement Settings + + + + + + Enable time requirement + + + + + + + + 1 + 0 + + + + seconds + + + 1 + + + 600 + + + 30 + + + true + + + 30 + + + + + + + Enable distance requirement + + + + + + + + 1 + 0 + + + + meters + + + 1 + + + 1000 + + + 30 + + + true + + + 30 + + + + + + + Enable sensor data requirement + + + + + + + Wait for all active requirements + + + + + + + + + + General Settings + + + + + + Enable erroneous distance safeguard + + + + + + + Measure (M) value attached to vertices + + + true + + + + + + + + 1 + 0 + + + + + + + + - - - - - - When enabled, this option disables adding and deleting features, as well as modifying the geometries of existing features. - - - Lock geometries - - - - - - - - - - - - - - Qt::Horizontal - - - - 20 - 20 - - - - - - - - - + + QgsCollapsibleGroupBox + QGroupBox +
qgscollapsiblegroupbox.h
+ 1 +
QgsPropertyOverrideButton QToolButton
qgspropertyoverridebutton.h
+ + QgsSpinBox + QSpinBox +
qgsspinbox.h
+
From 603dc486474877e17a03f865cd7ff3bb9aa41ce3 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 29 Feb 2024 14:25:09 +0700 Subject: [PATCH 2/5] Plug in layer tracking properties into the UI --- qfieldsync/gui/map_layer_config_widget.py | 85 +++++++++++++++++++---- qfieldsync/ui/map_layer_config_widget.ui | 4 +- requirements.txt | 2 +- 3 files changed, 75 insertions(+), 16 deletions(-) diff --git a/qfieldsync/gui/map_layer_config_widget.py b/qfieldsync/gui/map_layer_config_widget.py index c0d483ad..b8285c13 100644 --- a/qfieldsync/gui/map_layer_config_widget.py +++ b/qfieldsync/gui/map_layer_config_widget.py @@ -82,6 +82,18 @@ def __init__(self, layer, canvas, parent): self.relationshipConfigurationTable.addLayerFields(self.layer_source) self.relationshipConfigurationTable.setLayerColumnHidden(True) + self.measurementTypeComboBox.addItem( + "Elapsed time (seconds since start of tracking)" + ) + self.measurementTypeComboBox.addItem("Timestamp (milliseconds since epoch)") + self.measurementTypeComboBox.addItem("Ground speed") + self.measurementTypeComboBox.addItem("Bearing") + self.measurementTypeComboBox.addItem("Horizontal accuracy") + self.measurementTypeComboBox.addItem("Vertical accuracy") + self.measurementTypeComboBox.addItem("PDOP") + self.measurementTypeComboBox.addItem("HDOP") + self.measurementTypeComboBox.addItem("VDOP") + if layer.type() == QgsMapLayer.VectorLayer: prop = QgsProperty.fromExpression( self.layer_source.geometry_locked_expression @@ -133,6 +145,34 @@ def __init__(self, layer, canvas, parent): self.relationshipConfigurationTable.setEnabled( self.relationshipConfigurationTable.rowCount() > 0 ) + + self.trackingSessionGroupBox.setChecked( + self.layer_source.tracking_session_active + ) + self.timeRequirementCheckBox.setChecked( + self.layer_source.tracking_time_requirement_active + ) + self.timeRequirementIntervalSecondsSpinBox.setValue( + self.layer_source.tracking_time_requirement_interval_seconds + ) + self.distanceRequirementCheckBox.setChecked( + self.layer_source.tracking_distance_requirement_active + ) + self.distanceRequirementMinimumMetersSpinBox.setValue( + self.layer_source.tracking_distance_requirement_minimum_meters + ) + self.sensorDataRequirementCheckBox.setChecked( + self.layer_source.tracking_sensor_data_requirement_active + ) + self.allRequirementsCheckBox.setChecked( + self.layer_source.tracking_all_requirements_active + ) + self.erroneousDistanceSafeguardCheckBox.setChecked( + self.layer_source.tracking_erroneous_distance_safeguard_active + ) + self.measurementTypeComboBox.setCurrentIndex( + self.layer_source.tracking_measurement_type + ) else: self.isGeometryLockedDDButton.setVisible(False) self.isGeometryLockedCheckBox.setVisible(False) @@ -141,9 +181,9 @@ def __init__(self, layer, canvas, parent): self.trackingSessionGroupBox.setVisible(False) def apply(self): - old_layer_action = self.layer_source.action - old_layer_cloud_action = self.layer_source.cloud_action - old_is_geometry_locked = self.layer_source.is_geometry_locked + self.layer_source.action + self.layer_source.cloud_action + self.layer_source.is_geometry_locked self.layer_source.cloud_action = self.cloudLayerActionComboBox.itemData( self.cloudLayerActionComboBox.currentIndex() @@ -158,15 +198,34 @@ def apply(self): self.attachmentNamingTable.syncLayerSourceValues() self.relationshipConfigurationTable.syncLayerSourceValues() - # apply always the attachment naming (to store default values on first apply as well) - if ( - self.layer_source.action != old_layer_action - or self.layer_source.cloud_action != old_layer_cloud_action - or self.layer_source.is_geometry_locked != old_is_geometry_locked - or self.attachmentNamingTable.rowCount() > 0 - or self.relationshipConfigurationTable.rowCount() > 0 - ): - self.layer_source.apply() - self.project.setDirty(True) + self.layer_source.tracking_session_active = ( + self.trackingSessionGroupBox.isChecked() + ) + self.layer_source.tracking_time_requirement_active = ( + self.timeRequirementCheckBox.isChecked() + ) + self.layer_source.tracking_time_requirement_interval_seconds = ( + self.timeRequirementIntervalSecondsSpinBox.value() + ) + self.layer_source.tracking_distance_requirement_active = ( + self.distanceRequirementCheckBox.isChecked() + ) + self.layer_source.tracking_distance_requirement_minimum_meters = ( + self.distanceRequirementMinimumMetersSpinBox.value() + ) + self.layer_source.tracking_sensor_data_requirement_active = ( + self.sensorDataRequirementCheckBox.isChecked() + ) + self.layer_source.tracking_all_requirements_active = ( + self.allRequirementsCheckBox.isChecked() + ) + self.layer_source.tracking_erroneous_distance_safeguard_active = ( + self.erroneousDistanceSafeguardCheckBox.isChecked() + ) + self.layer_source.tracking_measurement_type = ( + self.measurementTypeComboBox.currentIndex() + ) + if self.layer_source.apply(): + self.project.setDirty(True) message_bus.messaged.emit("layer_config_saved") diff --git a/qfieldsync/ui/map_layer_config_widget.ui b/qfieldsync/ui/map_layer_config_widget.ui index f98f61c6..0a408eb4 100644 --- a/qfieldsync/ui/map_layer_config_widget.ui +++ b/qfieldsync/ui/map_layer_config_widget.ui @@ -225,7 +225,7 @@
- + Measure (M) value attached to vertices @@ -235,7 +235,7 @@ - + 1 diff --git a/requirements.txt b/requirements.txt index 677cbc3d..507e0c6b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,4 @@ future transifex-client # NOTE `libqfielsync` version should be defined in the `*.tar.gz` format, not `git+https://` to make `wheel` happy -libqfieldsync @ https://github.com/opengisch/libqfieldsync/archive/3c0b0c4903d0a5e6944779d4d43a64e29542bd87.tar.gz +libqfieldsync @ https://github.com/opengisch/libqfieldsync/archive/1cd354bb1c73f2cb30ea16104dca3ade0c8a242c.tar.gz From f89a32db32524ae237b334d043046ac2e8ad2b74 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 29 Feb 2024 14:57:51 +0700 Subject: [PATCH 3/5] Insure combobox won't require too much horizontal space --- qfieldsync/ui/map_layer_config_widget.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qfieldsync/ui/map_layer_config_widget.ui b/qfieldsync/ui/map_layer_config_widget.ui index 0a408eb4..fbe2f7d4 100644 --- a/qfieldsync/ui/map_layer_config_widget.ui +++ b/qfieldsync/ui/map_layer_config_widget.ui @@ -242,6 +242,9 @@ 0 + + QComboBox::AdjustToMinimumContentsLengthWithIcon +
From cf52479fea6acfb055c448452f546bb102134709 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 29 Feb 2024 14:59:38 +0700 Subject: [PATCH 4/5] Insure combobox items are translatable --- qfieldsync/gui/map_layer_config_widget.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/qfieldsync/gui/map_layer_config_widget.py b/qfieldsync/gui/map_layer_config_widget.py index b8285c13..2bd1e068 100644 --- a/qfieldsync/gui/map_layer_config_widget.py +++ b/qfieldsync/gui/map_layer_config_widget.py @@ -85,14 +85,16 @@ def __init__(self, layer, canvas, parent): self.measurementTypeComboBox.addItem( "Elapsed time (seconds since start of tracking)" ) - self.measurementTypeComboBox.addItem("Timestamp (milliseconds since epoch)") - self.measurementTypeComboBox.addItem("Ground speed") - self.measurementTypeComboBox.addItem("Bearing") - self.measurementTypeComboBox.addItem("Horizontal accuracy") - self.measurementTypeComboBox.addItem("Vertical accuracy") - self.measurementTypeComboBox.addItem("PDOP") - self.measurementTypeComboBox.addItem("HDOP") - self.measurementTypeComboBox.addItem("VDOP") + self.measurementTypeComboBox.addItem( + self.tr("Timestamp (milliseconds since epoch)") + ) + self.measurementTypeComboBox.addItem(self.tr("Ground speed")) + self.measurementTypeComboBox.addItem(self.tr("Bearing")) + self.measurementTypeComboBox.addItem(self.tr("Horizontal accuracy")) + self.measurementTypeComboBox.addItem(self.tr("Vertical accuracy")) + self.measurementTypeComboBox.addItem(self.tr("PDOP")) + self.measurementTypeComboBox.addItem(self.tr("HDOP")) + self.measurementTypeComboBox.addItem(self.tr("VDOP")) if layer.type() == QgsMapLayer.VectorLayer: prop = QgsProperty.fromExpression( From f2de8c8e588e24d1c5c2921965ae72c2e37e7a92 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 29 Feb 2024 22:29:52 +0700 Subject: [PATCH 5/5] Add missing maximum distance (in meters) UI --- qfieldsync/gui/map_layer_config_widget.py | 6 +++++ qfieldsync/ui/map_layer_config_widget.ui | 30 ++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/qfieldsync/gui/map_layer_config_widget.py b/qfieldsync/gui/map_layer_config_widget.py index 2bd1e068..103deac6 100644 --- a/qfieldsync/gui/map_layer_config_widget.py +++ b/qfieldsync/gui/map_layer_config_widget.py @@ -172,6 +172,9 @@ def __init__(self, layer, canvas, parent): self.erroneousDistanceSafeguardCheckBox.setChecked( self.layer_source.tracking_erroneous_distance_safeguard_active ) + self.erroneousDistanceSafeguardMaximumMetersSpinBox.setValue( + self.layer_source.tracking_erroneous_distance_safeguard_maximum_meters + ) self.measurementTypeComboBox.setCurrentIndex( self.layer_source.tracking_measurement_type ) @@ -224,6 +227,9 @@ def apply(self): self.layer_source.tracking_erroneous_distance_safeguard_active = ( self.erroneousDistanceSafeguardCheckBox.isChecked() ) + self.layer_source.tracking_erroneous_distance_safeguard_maximum_meters = ( + self.erroneousDistanceSafeguardMaximumMetersSpinBox.value() + ) self.layer_source.tracking_measurement_type = ( self.measurementTypeComboBox.currentIndex() ) diff --git a/qfieldsync/ui/map_layer_config_widget.ui b/qfieldsync/ui/map_layer_config_widget.ui index fbe2f7d4..6a06d695 100644 --- a/qfieldsync/ui/map_layer_config_widget.ui +++ b/qfieldsync/ui/map_layer_config_widget.ui @@ -217,13 +217,41 @@ General Settings - + Enable erroneous distance safeguard + + + + + 1 + 0 + + + + meters + + + 1 + + + 1000 + + + 100 + + + true + + + 100 + + +