From 206d713f382943044116ae37fb07af09e6c9113e Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 25 Jun 2026 09:42:30 +0700 Subject: [PATCH 1/6] Use a QVariantList for the MultiFeatureListModel selectedFeatures property --- src/core/multifeaturelistmodel.cpp | 15 +++++++++++++++ src/core/multifeaturelistmodel.h | 7 ++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/core/multifeaturelistmodel.cpp b/src/core/multifeaturelistmodel.cpp index d36eca227c..e9c3ea0e1b 100644 --- a/src/core/multifeaturelistmodel.cpp +++ b/src/core/multifeaturelistmodel.cpp @@ -219,6 +219,21 @@ QList MultiFeatureListModel::selectedFeatures() return mSourceModel->selectedFeatures(); } +QVariantList MultiFeatureListModel::selectedFeaturesVariant() +{ + QVariantList featuresVariant; + const QList features = mSourceModel->selectedFeatures(); + + featuresVariant.reserve( features.size() ); + for ( const QgsFeature &feature : features ) + { + // Pack the custom QgsFeature object into a QVariant safely + featuresVariant.append( QVariant::fromValue( feature ) ); + } + + return featuresVariant; +} + QgsVectorLayer *MultiFeatureListModel::selectedLayer() { return mFilterLayer.data(); diff --git a/src/core/multifeaturelistmodel.h b/src/core/multifeaturelistmodel.h index 66b975f7eb..b1b7e929b2 100644 --- a/src/core/multifeaturelistmodel.h +++ b/src/core/multifeaturelistmodel.h @@ -33,7 +33,7 @@ class MultiFeatureListModel : public QSortFilterProxyModel Q_OBJECT Q_PROPERTY( int count READ count NOTIFY countChanged ) - Q_PROPERTY( QList selectedFeatures READ selectedFeatures NOTIFY selectedCountChanged ) + Q_PROPERTY( QVariantList selectedFeatures READ selectedFeaturesVariant NOTIFY selectedCountChanged ) Q_PROPERTY( QgsVectorLayer *selectedLayer READ selectedLayer NOTIFY selectedLayerChanged ) Q_PROPERTY( int selectedCount READ selectedCount NOTIFY selectedCountChanged ) Q_PROPERTY( bool canEditAttributesSelection READ canEditAttributesSelection NOTIFY selectedCountChanged ) @@ -175,6 +175,11 @@ class MultiFeatureListModel : public QSortFilterProxyModel */ QList selectedFeatures(); + /** + * Returns the list of currently selected features as a QVariantList object. + */ + QVariantList selectedFeaturesVariant(); + /** * Returns the vector layer within which one or more features are currently selected */ From e3d13f66a6e3e74e9a822b0debe8df09fbeb554b Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 25 Jun 2026 09:48:14 +0700 Subject: [PATCH 2/6] Use QVariantList for the GridModel annotations property --- src/core/gridmodel.cpp | 8 ++++---- src/core/gridmodel.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/gridmodel.cpp b/src/core/gridmodel.cpp index 003e1da49d..48536be6ff 100644 --- a/src/core/gridmodel.cpp +++ b/src/core/gridmodel.cpp @@ -449,11 +449,11 @@ void GridModel::update() { if ( currentLine.intersects( topBorder, &intersectionPoint ) ) { - mAnnotations << GridAnnotation( GridAnnotation::Top, intersectionPoint, xPos ); + mAnnotations << QVariant::fromValue( GridAnnotation( GridAnnotation::Top, intersectionPoint, xPos ) ); } if ( currentLine.intersects( bottomBorder, &intersectionPoint ) ) { - mAnnotations << GridAnnotation( GridAnnotation::Bottom, intersectionPoint, xPos ); + mAnnotations << QVariant::fromValue( GridAnnotation( GridAnnotation::Bottom, intersectionPoint, xPos ) ); } } @@ -478,11 +478,11 @@ void GridModel::update() { if ( currentLine.intersects( leftBorder, &intersectionPoint ) ) { - mAnnotations << GridAnnotation( GridAnnotation::Left, intersectionPoint, yPos ); + mAnnotations << QVariant::fromValue( GridAnnotation( GridAnnotation::Left, intersectionPoint, yPos ) ); } if ( currentLine.intersects( rightBorder, &intersectionPoint ) ) { - mAnnotations << GridAnnotation( GridAnnotation::Right, intersectionPoint, yPos ); + mAnnotations << QVariant::fromValue( GridAnnotation( GridAnnotation::Right, intersectionPoint, yPos ) ); } } diff --git a/src/core/gridmodel.h b/src/core/gridmodel.h index 6e29b137ed..2690bb3a01 100644 --- a/src/core/gridmodel.h +++ b/src/core/gridmodel.h @@ -77,7 +77,7 @@ class QFIELD_CORE_EXPORT GridModel : public QObject Q_PROPERTY( QString majorLinesPath READ majorLinesPath NOTIFY majorLinesChanged ) Q_PROPERTY( QString minorLinesPath READ minorLinesPath NOTIFY minorLinesChanged ) Q_PROPERTY( QString markersPath READ markersPath NOTIFY markersChanged ) - Q_PROPERTY( QList annotations READ annotations NOTIFY annotationsChanged ) + Q_PROPERTY( QVariantList annotations READ annotations NOTIFY annotationsChanged ) Q_PROPERTY( bool autoColor READ autoColor WRITE setAutoColor NOTIFY autoColorChanged ) Q_PROPERTY( QColor majorLineColor READ majorLineColor WRITE setMajorLineColor NOTIFY majorLineColorChanged ) @@ -169,7 +169,7 @@ class QFIELD_CORE_EXPORT GridModel : public QObject void setPrepareAnnotations( bool prepare ); //! Returns the grid annotations - QList annotations() const { return mAnnotations; } + QVariantList annotations() const { return mAnnotations; } /** * Returns whether grid line and marker colors will be automatically assigned to @@ -320,7 +320,7 @@ class QFIELD_CORE_EXPORT GridModel : public QObject QString mMarkersPath; bool mPrepareAnnotations = false; - QList mAnnotations; + QVariantList mAnnotations; bool mAutoColor = false; QColor mMajorLineColor = QColor( 0, 0, 0, 100 ); From 3217826ef34c9a1a2be212bd23044a34048cebfd Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 25 Jun 2026 10:06:45 +0700 Subject: [PATCH 3/6] Transform remaining QList properties to QVariantList --- src/core/featuremodel.cpp | 30 +++++++++++++++++++++ src/core/featuremodel.h | 6 ++++- src/core/processing/processingalgorithm.cpp | 30 +++++++++++++++++++++ src/core/processing/processingalgorithm.h | 12 ++++++++- src/core/trackingmodel.cpp | 16 +++++++++++ src/core/trackingmodel.h | 4 ++- src/qml/FeatureListForm.qml | 4 +-- 7 files changed, 97 insertions(+), 5 deletions(-) diff --git a/src/core/featuremodel.cpp b/src/core/featuremodel.cpp index 7ed7efa072..e532f577f4 100644 --- a/src/core/featuremodel.cpp +++ b/src/core/featuremodel.cpp @@ -126,6 +126,36 @@ void FeatureModel::setFeatures( const QList &features ) endResetModel(); } +QVariantList FeatureModel::featuresVariant() const +{ + QVariantList featuresVariant; + + featuresVariant.reserve( mFeatures.size() ); + for ( const QgsFeature &feature : mFeatures ) + { + // Pack the custom QgsFeature object into a QVariant safely + featuresVariant.append( QVariant::fromValue( feature ) ); + } + + return featuresVariant; +} + +void FeatureModel::setFeaturesVariant( const QVariantList &features ) +{ + QList featuresList; + featuresList.reserve( features.size() ); + + for ( const QVariant &variant : features ) + { + if ( variant.canConvert() ) + { + featuresList.append( variant.value() ); + } + } + + setFeatures( featuresList ); +} + void FeatureModel::setCurrentLayer( QgsVectorLayer *layer ) { if ( layer == mLayer ) diff --git a/src/core/featuremodel.h b/src/core/featuremodel.h index b52abdf8a3..d7334db7d6 100644 --- a/src/core/featuremodel.h +++ b/src/core/featuremodel.h @@ -35,7 +35,7 @@ class FeatureModel : public QAbstractListModel Q_OBJECT Q_PROPERTY( FeatureModel::ModelModes modelMode READ modelMode WRITE setModelMode NOTIFY modelModeChanged ) Q_PROPERTY( QgsFeature feature READ feature WRITE setFeature NOTIFY featureChanged ) - Q_PROPERTY( QList features READ features WRITE setFeatures NOTIFY featuresChanged ) + Q_PROPERTY( QVariantList features READ featuresVariant WRITE setFeaturesVariant NOTIFY featuresChanged ) Q_PROPERTY( QgsFeature linkedParentFeature READ linkedParentFeature WRITE setLinkedParentFeature NOTIFY linkedParentFeatureChanged ) Q_PROPERTY( QgsRelation linkedRelation READ linkedRelation WRITE setLinkedRelation NOTIFY linkedRelationChanged ) Q_PROPERTY( QString linkedRelationOrderingField READ linkedRelationOrderingField WRITE setLinkedRelationOrderingField NOTIFY linkedRelationOrderingFieldChanged ) @@ -91,6 +91,10 @@ class FeatureModel : public QAbstractListModel void setFeatures( const QList &features ); + QVariantList featuresVariant() const; + + void setFeaturesVariant( const QVariantList &features ); + /** * Return the features list for passing it around in QML */ diff --git a/src/core/processing/processingalgorithm.cpp b/src/core/processing/processingalgorithm.cpp index bf1ff24356..4529e3482b 100644 --- a/src/core/processing/processingalgorithm.cpp +++ b/src/core/processing/processingalgorithm.cpp @@ -91,6 +91,36 @@ void ProcessingAlgorithm::setInPlaceFeatures( const QList &features } } +QVariantList ProcessingAlgorithm::inPlaceFeaturesVariant() const +{ + QVariantList featuresVariant; + + featuresVariant.reserve( mInPlaceFeatures.size() ); + for ( const QgsFeature &feature : mInPlaceFeatures ) + { + // Pack the custom QgsFeature object into a QVariant safely + featuresVariant.append( QVariant::fromValue( feature ) ); + } + + return featuresVariant; +} + +void ProcessingAlgorithm::setInPlaceFeaturesVariant( const QVariantList &features ) +{ + QList featuresList; + featuresList.reserve( features.size() ); + + for ( const QVariant &variant : features ) + { + if ( variant.canConvert() ) + { + featuresList.append( variant.value() ); + } + } + + setInPlaceFeatures( featuresList ); +} + void ProcessingAlgorithm::setParameters( const QVariantMap ¶meters ) { if ( mAlgorithmParameters == parameters ) diff --git a/src/core/processing/processingalgorithm.h b/src/core/processing/processingalgorithm.h index 138348d1a3..649569347b 100644 --- a/src/core/processing/processingalgorithm.h +++ b/src/core/processing/processingalgorithm.h @@ -45,7 +45,7 @@ class ProcessingAlgorithm : public QObject Q_PROPERTY( QVariantMap parameters READ parameters WRITE setParameters NOTIFY parametersChanged ) Q_PROPERTY( QgsVectorLayer *inPlaceLayer READ inPlaceLayer WRITE setInPlaceLayer NOTIFY inPlaceLayerChanged ) - Q_PROPERTY( QList inPlaceFeatures READ inPlaceFeatures WRITE setInPlaceFeatures NOTIFY inPlaceFeaturesChanged ) + Q_PROPERTY( QVariantList inPlaceFeatures READ inPlaceFeaturesVariant WRITE setInPlaceFeaturesVariant NOTIFY inPlaceFeaturesChanged ) Q_PROPERTY( bool preview READ preview WRITE setPreview NOTIFY previewChanged ) Q_PROPERTY( QList previewGeometries READ previewGeometries NOTIFY previewGeometriesChanged ) @@ -98,6 +98,16 @@ class ProcessingAlgorithm : public QObject */ void setInPlaceFeatures( const QList &features ); + /** + * Returns the vector \a layer for in-place algorithm filter as a QVariantList. + */ + QVariantList inPlaceFeaturesVariant() const; + + /** + * Sets the vector \a layer for in-place algorithm filter from a QVariantList. + */ + void setInPlaceFeaturesVariant( const QVariantList &features ); + /** * Returns the algorithm parameters as a map of parameter names as keys and values. */ diff --git a/src/core/trackingmodel.cpp b/src/core/trackingmodel.cpp index 2588c0ad93..452debddc8 100644 --- a/src/core/trackingmodel.cpp +++ b/src/core/trackingmodel.cpp @@ -102,6 +102,22 @@ bool TrackingModel::featureInTracking( QgsVectorLayer *layer, const QgsFeatureId return false; } +bool TrackingModel::featuresInTracking( QgsVectorLayer *layer, const QVariantList &features ) +{ + QList featuresList; + + featuresList.reserve( features.size() ); + for ( const QVariant &variant : features ) + { + if ( variant.canConvert() ) + { + featuresList.append( variant.value() ); + } + } + + return featuresInTracking( layer, featuresList ); +} + bool TrackingModel::featuresInTracking( QgsVectorLayer *layer, const QList &features ) { auto it = trackerIterator( layer ); diff --git a/src/core/trackingmodel.h b/src/core/trackingmodel.h index cd08d655e7..7956a5bb81 100644 --- a/src/core/trackingmodel.h +++ b/src/core/trackingmodel.h @@ -64,7 +64,9 @@ class TrackingModel : public QAbstractItemModel //! Returns TRUE if the \a featureId is attached to a vector \a layer tracking session. Q_INVOKABLE bool featureInTracking( QgsVectorLayer *layer, QgsFeatureId featureId ); //! Returns TRUE if the list of \a features is attached to a vector \a layer tracking session. - Q_INVOKABLE bool featuresInTracking( QgsVectorLayer *layer, const QList &features ); + Q_INVOKABLE bool featuresInTracking( QgsVectorLayer *layer, const QVariantList &features ); + //! Returns TRUE if the list of \a features is attached to a vector \a layer tracking session. + bool featuresInTracking( QgsVectorLayer *layer, const QList &features ); //! Returns TRUE if the vector \a layer has a tracking session. Q_INVOKABLE bool layerInTracking( QgsVectorLayer *layer ) const; //! Returns TRUE if the vector \a layer has an active tracking session. diff --git a/src/qml/FeatureListForm.qml b/src/qml/FeatureListForm.qml index 51f733e592..648b79bcea 100644 --- a/src/qml/FeatureListForm.qml +++ b/src/qml/FeatureListForm.qml @@ -666,8 +666,8 @@ Pane { } onDeleteClicked: { - var selectedFeatures = featureFormList.selection.model.selectedFeatures; - var selectedFeature = selectedFeatures && selectedFeatures.length > 0 ? selectedFeatures[0] : null; + let selectedFeatures = featureFormList.selection.model.selectedFeatures; + let selectedFeature = selectedFeatures && selectedFeatures.length > 0 ? selectedFeatures[0] : null; if (selectedFeature && featureFormList.selection.focusedLayer && trackingModel.featureInTracking(featureFormList.selection.focusedLayer, selectedFeature)) { displayToast(qsTr("A number of features are being tracked, stop tracking to delete those")); } else { From cdb8a272615a4f93fcff07c8d27e668e21188439 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 25 Jun 2026 10:15:58 +0700 Subject: [PATCH 4/6] Make the ProcessingAlgorithm previewGeometries property a QVariantList --- src/core/processing/processingalgorithm.cpp | 4 ++-- src/core/processing/processingalgorithm.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/processing/processingalgorithm.cpp b/src/core/processing/processingalgorithm.cpp index 4529e3482b..06309b98fc 100644 --- a/src/core/processing/processingalgorithm.cpp +++ b/src/core/processing/processingalgorithm.cpp @@ -235,7 +235,7 @@ bool ProcessingAlgorithm::run( bool previewMode ) { for ( const QgsFeature &outputFeature : outputFeatures ) { - mPreviewGeometries << outputFeature.geometry(); + mPreviewGeometries << QVariant::fromValue( outputFeature.geometry() ); } emit previewGeometriesChanged(); @@ -326,7 +326,7 @@ bool ProcessingAlgorithm::run( bool previewMode ) { for ( const QgsFeature &previewFeature : outputFeatures ) { - mPreviewGeometries << previewFeature.geometry(); + mPreviewGeometries << QVariant::fromValue( previewFeature.geometry() ); } emit previewGeometriesChanged(); diff --git a/src/core/processing/processingalgorithm.h b/src/core/processing/processingalgorithm.h index 649569347b..fbdcfaf847 100644 --- a/src/core/processing/processingalgorithm.h +++ b/src/core/processing/processingalgorithm.h @@ -48,7 +48,7 @@ class ProcessingAlgorithm : public QObject Q_PROPERTY( QVariantList inPlaceFeatures READ inPlaceFeaturesVariant WRITE setInPlaceFeaturesVariant NOTIFY inPlaceFeaturesChanged ) Q_PROPERTY( bool preview READ preview WRITE setPreview NOTIFY previewChanged ) - Q_PROPERTY( QList previewGeometries READ previewGeometries NOTIFY previewGeometriesChanged ) + Q_PROPERTY( QVariantList previewGeometries READ previewGeometries NOTIFY previewGeometriesChanged ) public: explicit ProcessingAlgorithm( QObject *parent = nullptr ); @@ -133,7 +133,7 @@ class ProcessingAlgorithm : public QObject /** * Returns a list of geometries previewing the algorithm result using current parameters. */ - QList previewGeometries() const { return mPreviewGeometries; } + QVariantList previewGeometries() const { return mPreviewGeometries; } /** * Executes the algorithm. @@ -180,7 +180,7 @@ class ProcessingAlgorithm : public QObject QList mInPlaceFeatures; bool mPreview = false; - QList mPreviewGeometries; + QVariantList mPreviewGeometries; }; #endif // PROCESSINGALGORITHM From c16a3d2c1f148810d7e3f82bfdfb8569c5f27455 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 25 Jun 2026 10:21:46 +0700 Subject: [PATCH 5/6] Make the QFieldCloudConnection availableProviders property a QVariantList --- src/core/qfieldcloud/qfieldcloudconnection.cpp | 13 +++++++++++-- src/core/qfieldcloud/qfieldcloudconnection.h | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/core/qfieldcloud/qfieldcloudconnection.cpp b/src/core/qfieldcloud/qfieldcloudconnection.cpp index 525169412e..2a7aec99cd 100644 --- a/src/core/qfieldcloud/qfieldcloudconnection.cpp +++ b/src/core/qfieldcloud/qfieldcloudconnection.cpp @@ -305,9 +305,18 @@ bool QFieldCloudConnection::isFetchingAvailableProviders() const return mIsFetchingAvailableProviders; } -QList QFieldCloudConnection::availableProviders() const +QVariantList QFieldCloudConnection::availableProviders() const { - return mAvailableProviders.values(); + const QList providers = mAvailableProviders.values(); + QVariantList providersVariant; + providersVariant.reserve( providers.size() ); + + for ( const AuthenticationProvider &provider : providers ) + { + providersVariant.append( QVariant::fromValue( provider ) ); + } + + return providersVariant; } void QFieldCloudConnection::getServerInformation() diff --git a/src/core/qfieldcloud/qfieldcloudconnection.h b/src/core/qfieldcloud/qfieldcloudconnection.h index 2df1668bb1..ca4c0fca27 100644 --- a/src/core/qfieldcloud/qfieldcloudconnection.h +++ b/src/core/qfieldcloud/qfieldcloudconnection.h @@ -83,7 +83,7 @@ class QFieldCloudConnection : public QObject Q_PROPERTY( CloudUserInformation userInformation READ userInformation NOTIFY userInformationChanged ) - Q_PROPERTY( QList availableProviders READ availableProviders NOTIFY availableProvidersChanged ) + Q_PROPERTY( QVariantList availableProviders READ availableProviders NOTIFY availableProvidersChanged ) Q_PROPERTY( bool isFetchingAvailableProviders READ isFetchingAvailableProviders NOTIFY isFetchingAvailableProvidersChanged ) Q_PROPERTY( CloudServerInformation serverInformation READ serverInformation NOTIFY serverInformationChanged ) @@ -175,7 +175,7 @@ class QFieldCloudConnection : public QObject Q_INVOKABLE void getSubscriptionInformation( const QString &user ); Q_INVOKABLE void getServerInformation(); - QList availableProviders() const; + QVariantList availableProviders() const; bool isFetchingAvailableProviders() const; CloudServerInformation serverInformation() const { return mServerInformation; } From f6eeab60b6263253ff6e8c057e963c4e21bfd0a3 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Thu, 25 Jun 2026 10:39:05 +0700 Subject: [PATCH 6/6] Copy audio analyzer arrays to safeguard from crash --- src/qml/editorwidgets/ExternalResource.qml | 2 +- .../editorwidgets/relationeditors/gallery_relation_editor.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qml/editorwidgets/ExternalResource.qml b/src/qml/editorwidgets/ExternalResource.qml index 4d377de739..f472209d3c 100644 --- a/src/qml/editorwidgets/ExternalResource.qml +++ b/src/qml/editorwidgets/ExternalResource.qml @@ -187,7 +187,7 @@ EditorWidgetBase { id: audioAnalyzer barCount: 80 onReady: bars => { - audioWaveformRepeater.model = bars; + audioWaveformRepeater.model = Array.from(bars); } } diff --git a/src/qml/editorwidgets/relationeditors/gallery_relation_editor.qml b/src/qml/editorwidgets/relationeditors/gallery_relation_editor.qml index f9726e1589..4b6f371626 100644 --- a/src/qml/editorwidgets/relationeditors/gallery_relation_editor.qml +++ b/src/qml/editorwidgets/relationeditors/gallery_relation_editor.qml @@ -188,7 +188,7 @@ RelationEditorBase { } onReady: bars => { - availableBars[currentProcess] = bars; + availableBars[currentProcess] = Array.from(bars); availableBarsChanged(); processQueue(); }