diff --git a/python/core/qgsfeaturefiltermodel.sip b/python/core/qgsfeaturefiltermodel.sip index 689378efae9..f347ad6a230 100644 --- a/python/core/qgsfeaturefiltermodel.sip +++ b/python/core/qgsfeaturefiltermodel.sip @@ -141,6 +141,17 @@ class QgsFeatureFilterModel : QAbstractItemModel :rtype: bool %End + bool allowNull() const; +%Docstring + Add a NULL entry to the list. + :rtype: bool +%End + + void setAllowNull( bool allowNull ); +%Docstring + Add a NULL entry to the list. +%End + signals: void sourceLayerChanged(); @@ -211,6 +222,11 @@ class QgsFeatureFilterModel : QAbstractItemModel Notification that the model change is finished. Will always be emitted in sync with beginUpdate. %End + void allowNullChanged(); +%Docstring + Add a NULL entry to the list. +%End + }; /************************************************************************ diff --git a/python/gui/qgsfeaturelistcombobox.sip b/python/gui/qgsfeaturelistcombobox.sip index 00b22b7b3af..d99544ac04a 100644 --- a/python/gui/qgsfeaturelistcombobox.sip +++ b/python/gui/qgsfeaturelistcombobox.sip @@ -92,8 +92,6 @@ class QgsFeatureListComboBox : QComboBox bool allowNull() const; %Docstring Determines if a NULL value should be available in the list. - - TODO! :rtype: bool %End diff --git a/src/core/qgsfeaturefiltermodel.cpp b/src/core/qgsfeaturefiltermodel.cpp index c270e442d5d..a466d2d1459 100644 --- a/src/core/qgsfeaturefiltermodel.cpp +++ b/src/core/qgsfeaturefiltermodel.cpp @@ -165,12 +165,18 @@ void QgsFeatureFilterModel::updateCompleter() } mShouldReloadCurrentFeature = false; + + if ( mFilterValue.isEmpty() ) + reload(); } else { // We got strings for a filter selection std::sort( entries.begin(), entries.end(), []( const Entry & a, const Entry & b ) { return a.value.localeAwareCompare( b.value ) < 0; } ); + if ( mAllowNull ) + entries.prepend( Entry( QVariant( QVariant::Int ), tr( "NULL" ) ) ); + int newEntriesSize = entries.size(); // Find the index of the extra entry in the new list @@ -196,6 +202,8 @@ void QgsFeatureFilterModel::updateCompleter() int firstRow = 0; + QgsDebugMsg( QStringLiteral( "Entries 1: %1 " ).arg( mEntries.size() ) ); + // Move the extra entry to the first position if ( mExtraIdentifierValueIndex != -1 ) { @@ -213,13 +221,18 @@ void QgsFeatureFilterModel::updateCompleter() firstRow = 1; } + QgsDebugMsg( QStringLiteral( "Entries 2: %1 " ).arg( mEntries.size() ) ); + // Remove all entries (except for extra entry if existent) beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow ); mEntries.remove( firstRow, mEntries.size() - firstRow ); endRemoveRows(); + QgsDebugMsg( QStringLiteral( "Entries 3: %1 " ).arg( mEntries.size() ) ); + if ( currentEntryInNewList == -1 ) { + QgsDebugMsg( QStringLiteral( "Current value is NOT in new list" ) ); beginInsertRows( QModelIndex(), 1, entries.size() + 1 ); mEntries += entries; endInsertRows(); @@ -227,6 +240,7 @@ void QgsFeatureFilterModel::updateCompleter() } else { + QgsDebugMsg( QStringLiteral( "Current value is in new list" ) ); if ( currentEntryInNewList != 0 ) { beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 ); @@ -335,7 +349,7 @@ void QgsFeatureFilterModel::setExtraIdentifierValueUnguarded( const QVariant &ex int index = 0; for ( const Entry &entry : entries ) { - if ( entry.identifierValue == extraIdentifierValue ) + if ( entry.identifierValue == extraIdentifierValue && entry.identifierValue.isNull() == extraIdentifierValue.isNull() && entry.identifierValue.isValid() == extraIdentifierValue.isValid() ) { setExtraIdentifierValueIndex( index ); break; @@ -348,7 +362,10 @@ void QgsFeatureFilterModel::setExtraIdentifierValueUnguarded( const QVariant &ex if ( mExtraIdentifierValueIndex != index ) { beginInsertRows( QModelIndex(), 0, 0 ); - mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral( "(%1)" ).arg( extraIdentifierValue.toString() ) ) ); + if ( extraIdentifierValue.isNull() ) + mEntries.prepend( Entry( QVariant( QVariant::Int ), QStringLiteral( "%1" ).arg( tr( "NULL" ) ) ) ); + else + mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral( "(%1)" ).arg( extraIdentifierValue.toString() ) ) ); endInsertRows(); setExtraIdentifierValueIndex( 0 ); @@ -356,6 +373,22 @@ void QgsFeatureFilterModel::setExtraIdentifierValueUnguarded( const QVariant &ex } } +bool QgsFeatureFilterModel::allowNull() const +{ + return mAllowNull; +} + +void QgsFeatureFilterModel::setAllowNull( bool allowNull ) +{ + if ( mAllowNull == allowNull ) + return; + + mAllowNull = allowNull; + emit allowNullChanged(); + + reload(); +} + bool QgsFeatureFilterModel::extraValueDoesNotExist() const { return mExtraValueDoesNotExist; @@ -401,7 +434,7 @@ QVariant QgsFeatureFilterModel::extraIdentifierValue() const void QgsFeatureFilterModel::setExtraIdentifierValue( const QVariant &extraIdentifierValue ) { - if ( extraIdentifierValue == mExtraIdentifierValue && extraIdentifierValue.isNull() == mExtraIdentifierValue.isNull() ) + if ( extraIdentifierValue == mExtraIdentifierValue && extraIdentifierValue.isNull() == mExtraIdentifierValue.isNull() && mExtraIdentifierValue.isValid() ) return; setExtraIdentifierValueUnguarded( extraIdentifierValue ); diff --git a/src/core/qgsfeaturefiltermodel.h b/src/core/qgsfeaturefiltermodel.h index 85da80df60b..71badfa367f 100644 --- a/src/core/qgsfeaturefiltermodel.h +++ b/src/core/qgsfeaturefiltermodel.h @@ -37,6 +37,7 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel Q_PROPERTY( QString displayExpression READ displayExpression WRITE setDisplayExpression NOTIFY displayExpressionChanged ) Q_PROPERTY( QString filterValue READ filterValue WRITE setFilterValue NOTIFY filterValueChanged ) Q_PROPERTY( QString filterExpression READ filterExpression WRITE setFilterExpression NOTIFY filterExpressionChanged ) + Q_PROPERTY( bool allowNull READ allowNull WRITE setAllowNull NOTIFY allowNullChanged ) Q_PROPERTY( bool isLoading READ isLoading NOTIFY isLoadingChanged ) /** @@ -167,6 +168,16 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel */ bool extraValueDoesNotExist() const; + /** + * Add a NULL entry to the list. + */ + bool allowNull() const; + + /** + * Add a NULL entry to the list. + */ + void setAllowNull( bool allowNull ); + signals: /** @@ -237,6 +248,11 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel */ void endUpdate(); + /** + * Add a NULL entry to the list. + */ + void allowNullChanged(); + private slots: void updateCompleter(); void gathererThreadFinished(); @@ -274,6 +290,7 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel QTimer mReloadTimer; bool mShouldReloadCurrentFeature = false; bool mExtraValueDoesNotExist = false; + bool mAllowNull = false; QString mIdentifierField; diff --git a/src/gui/editorwidgets/qgsrelationreferencewidget.cpp b/src/gui/editorwidgets/qgsrelationreferencewidget.cpp index 21590f3f96a..51b8bd9068c 100644 --- a/src/gui/editorwidgets/qgsrelationreferencewidget.cpp +++ b/src/gui/editorwidgets/qgsrelationreferencewidget.cpp @@ -677,8 +677,7 @@ void QgsRelationReferenceWidget::mapIdentification() void QgsRelationReferenceWidget::comboReferenceChanged( int index ) { - QgsFeatureId fid = mComboBox->itemData( index, QgsAttributeTableModel::FeatureIdRole ).value(); - mReferencedLayer->getFeatures( QgsFeatureRequest().setFilterFid( fid ) ).nextFeature( mFeature ); + mReferencedLayer->getFeatures( mComboBox->currentFeatureRequest() ).nextFeature( mFeature ); highlightFeature( mFeature ); updateAttributeEditorFrame( mFeature ); emit foreignKeyChanged( mFeature.attribute( mReferencedFieldIdx ) ); diff --git a/src/gui/qgsfeaturelistcombobox.cpp b/src/gui/qgsfeaturelistcombobox.cpp index f74575d7fbf..1bc11e91b70 100644 --- a/src/gui/qgsfeaturelistcombobox.cpp +++ b/src/gui/qgsfeaturelistcombobox.cpp @@ -38,6 +38,7 @@ QgsFeatureListComboBox::QgsFeatureListComboBox( QWidget *parent ) connect( mModel, &QgsFeatureFilterModel::filterExpressionChanged, this, &QgsFeatureListComboBox::filterExpressionChanged ); connect( mModel, &QgsFeatureFilterModel::isLoadingChanged, this, &QgsFeatureListComboBox::onLoadingChanged ); connect( mModel, &QgsFeatureFilterModel::filterJobCompleted, this, &QgsFeatureListComboBox::onFilterUpdateCompleted ); + connect( mModel, &QgsFeatureFilterModel::allowNullChanged, this, &QgsFeatureListComboBox::allowNullChanged ); connect( mModel, &QgsFeatureFilterModel::extraIdentifierValueChanged, this, &QgsFeatureListComboBox::identifierValueChanged ); connect( mModel, &QgsFeatureFilterModel::extraIdentifierValueIndexChanged, this, &QgsFeatureListComboBox::setCurrentIndex ); connect( mModel, &QgsFeatureFilterModel::identifierFieldChanged, this, &QgsFeatureListComboBox::identifierFieldChanged ); @@ -45,6 +46,7 @@ QgsFeatureListComboBox::QgsFeatureListComboBox( QWidget *parent ) connect( mCompleter, static_cast( &QCompleter::activated ), this, &QgsFeatureListComboBox::onActivated ); connect( mModel, &QgsFeatureFilterModel::beginUpdate, this, &QgsFeatureListComboBox::storeLineEditState ); connect( mModel, &QgsFeatureFilterModel::endUpdate, this, &QgsFeatureListComboBox::restoreLineEditState ); + connect( mModel, &QgsFeatureFilterModel::dataChanged, this, &QgsFeatureListComboBox::onDataChanged ); connect( this, static_cast( &QgsFeatureListComboBox::currentIndexChanged ), this, &QgsFeatureListComboBox::onCurrentIndexChanged ); @@ -55,10 +57,7 @@ QgsFeatureListComboBox::QgsFeatureListComboBox( QWidget *parent ) connect( mLineEdit, &QgsFilterLineEdit::textEdited, this, &QgsFeatureListComboBox::onCurrentTextChanged ); - connect( mLineEdit, &QgsFilterLineEdit::textChanged, this, []( const QString & text ) - { - QgsDebugMsg( QStringLiteral( "Edit text changed to %1" ).arg( text ) ); - } ); + setToolTip( tr( "Just start typing what you are looking for." ) ); } QgsVectorLayer *QgsFeatureListComboBox::sourceLayer() const @@ -83,6 +82,7 @@ void QgsFeatureListComboBox::setDisplayExpression( const QString &expression ) void QgsFeatureListComboBox::onCurrentTextChanged( const QString &text ) { + mIsCurrentlyEdited = true; mPopupRequested = true; mModel->setFilterValue( text ); } @@ -107,6 +107,7 @@ void QgsFeatureListComboBox::onItemSelected( const QModelIndex &index ) void QgsFeatureListComboBox::onCurrentIndexChanged( int i ) { + mIsCurrentlyEdited = false; QModelIndex modelIndex = mModel->index( i, 0, QModelIndex() ); mModel->setExtraIdentifierValue( mModel->data( modelIndex, QgsFeatureFilterModel::IdentifierValueRole ) ); mLineEdit->setText( mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() ); @@ -115,19 +116,33 @@ void QgsFeatureListComboBox::onCurrentIndexChanged( int i ) void QgsFeatureListComboBox::onActivated( QModelIndex modelIndex ) { setIdentifierValue( mModel->data( modelIndex, QgsFeatureFilterModel::IdentifierValueRole ) ); - QgsDebugMsg( QStringLiteral( "Activated index" ) ); - QgsDebugMsg( QStringLiteral( "%1 %2" ).arg( QString::number( modelIndex.row() ), mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() ) ); mLineEdit->setText( mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() ); } void QgsFeatureListComboBox::storeLineEditState() { - mLineEditState.store( mLineEdit ); + if ( mIsCurrentlyEdited ) + mLineEditState.store( mLineEdit ); } void QgsFeatureListComboBox::restoreLineEditState() { - mLineEditState.restore( mLineEdit ); + if ( mIsCurrentlyEdited ) + mLineEditState.restore( mLineEdit ); +} + +void QgsFeatureListComboBox::onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles ) +{ + Q_UNUSED( roles ) + if ( !mIsCurrentlyEdited ) + { + const int currentIndex = mModel->extraIdentifierValueIndex(); + if ( currentIndex >= topLeft.row() && currentIndex <= bottomRight.row() ) + { + QModelIndex modelIndex = mModel->index( currentIndex, 0, QModelIndex() ); + mLineEdit->setText( mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() ); + } + } } QString QgsFeatureListComboBox::identifierField() const @@ -163,16 +178,12 @@ void QgsFeatureListComboBox::keyPressEvent( QKeyEvent *event ) bool QgsFeatureListComboBox::allowNull() const { - return mAllowNull; + return mModel->allowNull(); } void QgsFeatureListComboBox::setAllowNull( bool allowNull ) { - if ( mAllowNull == allowNull ) - return; - - mAllowNull = allowNull; - emit allowNullChanged(); + mModel->setAllowNull( allowNull ); } QVariant QgsFeatureListComboBox::identifierValue() const @@ -187,7 +198,10 @@ void QgsFeatureListComboBox::setIdentifierValue( const QVariant &identifierValue QgsFeatureRequest QgsFeatureListComboBox::currentFeatureRequest() const { - return QgsFeatureRequest().setFilterExpression( QStringLiteral( "%1 = %2" ).arg( QgsExpression::quotedColumnRef( mModel->identifierField() ), QgsExpression::quotedValue( mModel->extraIdentifierValue() ) ) ); + if ( mModel->extraIdentifierValue().isNull() ) + return QgsFeatureRequest().setFilterFids( QgsFeatureIds() ); // NULL: Return a request that's guaranteed to not return anything + else + return QgsFeatureRequest().setFilterExpression( QStringLiteral( "%1 = %2" ).arg( QgsExpression::quotedColumnRef( mModel->identifierField() ), QgsExpression::quotedValue( mModel->extraIdentifierValue() ) ) ); } QString QgsFeatureListComboBox::filterExpression() const diff --git a/src/gui/qgsfeaturelistcombobox.h b/src/gui/qgsfeaturelistcombobox.h index e7f00530eb7..db5eee9e7f3 100644 --- a/src/gui/qgsfeaturelistcombobox.h +++ b/src/gui/qgsfeaturelistcombobox.h @@ -48,6 +48,7 @@ class GUI_EXPORT QgsFeatureListComboBox : public QComboBox Q_PROPERTY( bool allowNull READ allowNull WRITE setAllowNull NOTIFY allowNullChanged ) public: + /** * Create a new QgsFeatureListComboBox, optionally specifying a \a parent. */ @@ -109,8 +110,6 @@ class GUI_EXPORT QgsFeatureListComboBox : public QComboBox /** * Determines if a NULL value should be available in the list. - * - * TODO! */ bool allowNull() const; @@ -185,6 +184,7 @@ class GUI_EXPORT QgsFeatureListComboBox : public QComboBox void onActivated( QModelIndex index ); void storeLineEditState(); void restoreLineEditState(); + void onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector() ); private: struct LineEditState @@ -202,7 +202,6 @@ class GUI_EXPORT QgsFeatureListComboBox : public QComboBox QCompleter *mCompleter; QString mDisplayExpression; QgsFilterLineEdit *mLineEdit; - bool mAllowNull = true; bool mPopupRequested = false; bool mIsCurrentlyEdited = false; LineEditState mLineEditState;