Allow using NULL values

This commit is contained in:
Matthias Kuhn 2017-10-26 15:30:03 +02:00
parent 2a185a0c9b
commit c661ab1090
No known key found for this signature in database
GPG Key ID: A0E766808764D73F
7 changed files with 101 additions and 25 deletions

View File

@ -141,6 +141,17 @@ class QgsFeatureFilterModel : QAbstractItemModel
:rtype: bool :rtype: bool
%End %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: signals:
void sourceLayerChanged(); void sourceLayerChanged();
@ -211,6 +222,11 @@ class QgsFeatureFilterModel : QAbstractItemModel
Notification that the model change is finished. Will always be emitted in sync with beginUpdate. Notification that the model change is finished. Will always be emitted in sync with beginUpdate.
%End %End
void allowNullChanged();
%Docstring
Add a NULL entry to the list.
%End
}; };
/************************************************************************ /************************************************************************

View File

@ -92,8 +92,6 @@ class QgsFeatureListComboBox : QComboBox
bool allowNull() const; bool allowNull() const;
%Docstring %Docstring
Determines if a NULL value should be available in the list. Determines if a NULL value should be available in the list.
TODO!
:rtype: bool :rtype: bool
%End %End

View File

@ -165,12 +165,18 @@ void QgsFeatureFilterModel::updateCompleter()
} }
mShouldReloadCurrentFeature = false; mShouldReloadCurrentFeature = false;
if ( mFilterValue.isEmpty() )
reload();
} }
else else
{ {
// We got strings for a filter selection // 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; } ); 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(); int newEntriesSize = entries.size();
// Find the index of the extra entry in the new list // Find the index of the extra entry in the new list
@ -196,6 +202,8 @@ void QgsFeatureFilterModel::updateCompleter()
int firstRow = 0; int firstRow = 0;
QgsDebugMsg( QStringLiteral( "Entries 1: %1 " ).arg( mEntries.size() ) );
// Move the extra entry to the first position // Move the extra entry to the first position
if ( mExtraIdentifierValueIndex != -1 ) if ( mExtraIdentifierValueIndex != -1 )
{ {
@ -213,13 +221,18 @@ void QgsFeatureFilterModel::updateCompleter()
firstRow = 1; firstRow = 1;
} }
QgsDebugMsg( QStringLiteral( "Entries 2: %1 " ).arg( mEntries.size() ) );
// Remove all entries (except for extra entry if existent) // Remove all entries (except for extra entry if existent)
beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow ); beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow );
mEntries.remove( firstRow, mEntries.size() - firstRow ); mEntries.remove( firstRow, mEntries.size() - firstRow );
endRemoveRows(); endRemoveRows();
QgsDebugMsg( QStringLiteral( "Entries 3: %1 " ).arg( mEntries.size() ) );
if ( currentEntryInNewList == -1 ) if ( currentEntryInNewList == -1 )
{ {
QgsDebugMsg( QStringLiteral( "Current value is NOT in new list" ) );
beginInsertRows( QModelIndex(), 1, entries.size() + 1 ); beginInsertRows( QModelIndex(), 1, entries.size() + 1 );
mEntries += entries; mEntries += entries;
endInsertRows(); endInsertRows();
@ -227,6 +240,7 @@ void QgsFeatureFilterModel::updateCompleter()
} }
else else
{ {
QgsDebugMsg( QStringLiteral( "Current value is in new list" ) );
if ( currentEntryInNewList != 0 ) if ( currentEntryInNewList != 0 )
{ {
beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 ); beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
@ -335,7 +349,7 @@ void QgsFeatureFilterModel::setExtraIdentifierValueUnguarded( const QVariant &ex
int index = 0; int index = 0;
for ( const Entry &entry : entries ) 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 ); setExtraIdentifierValueIndex( index );
break; break;
@ -348,6 +362,9 @@ void QgsFeatureFilterModel::setExtraIdentifierValueUnguarded( const QVariant &ex
if ( mExtraIdentifierValueIndex != index ) if ( mExtraIdentifierValueIndex != index )
{ {
beginInsertRows( QModelIndex(), 0, 0 ); beginInsertRows( QModelIndex(), 0, 0 );
if ( extraIdentifierValue.isNull() )
mEntries.prepend( Entry( QVariant( QVariant::Int ), QStringLiteral( "%1" ).arg( tr( "NULL" ) ) ) );
else
mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral( "(%1)" ).arg( extraIdentifierValue.toString() ) ) ); mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral( "(%1)" ).arg( extraIdentifierValue.toString() ) ) );
endInsertRows(); endInsertRows();
setExtraIdentifierValueIndex( 0 ); 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 bool QgsFeatureFilterModel::extraValueDoesNotExist() const
{ {
return mExtraValueDoesNotExist; return mExtraValueDoesNotExist;
@ -401,7 +434,7 @@ QVariant QgsFeatureFilterModel::extraIdentifierValue() const
void QgsFeatureFilterModel::setExtraIdentifierValue( const QVariant &extraIdentifierValue ) void QgsFeatureFilterModel::setExtraIdentifierValue( const QVariant &extraIdentifierValue )
{ {
if ( extraIdentifierValue == mExtraIdentifierValue && extraIdentifierValue.isNull() == mExtraIdentifierValue.isNull() ) if ( extraIdentifierValue == mExtraIdentifierValue && extraIdentifierValue.isNull() == mExtraIdentifierValue.isNull() && mExtraIdentifierValue.isValid() )
return; return;
setExtraIdentifierValueUnguarded( extraIdentifierValue ); setExtraIdentifierValueUnguarded( extraIdentifierValue );

View File

@ -37,6 +37,7 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel
Q_PROPERTY( QString displayExpression READ displayExpression WRITE setDisplayExpression NOTIFY displayExpressionChanged ) Q_PROPERTY( QString displayExpression READ displayExpression WRITE setDisplayExpression NOTIFY displayExpressionChanged )
Q_PROPERTY( QString filterValue READ filterValue WRITE setFilterValue NOTIFY filterValueChanged ) Q_PROPERTY( QString filterValue READ filterValue WRITE setFilterValue NOTIFY filterValueChanged )
Q_PROPERTY( QString filterExpression READ filterExpression WRITE setFilterExpression NOTIFY filterExpressionChanged ) 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 ) Q_PROPERTY( bool isLoading READ isLoading NOTIFY isLoadingChanged )
/** /**
@ -167,6 +168,16 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel
*/ */
bool extraValueDoesNotExist() const; 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: signals:
/** /**
@ -237,6 +248,11 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel
*/ */
void endUpdate(); void endUpdate();
/**
* Add a NULL entry to the list.
*/
void allowNullChanged();
private slots: private slots:
void updateCompleter(); void updateCompleter();
void gathererThreadFinished(); void gathererThreadFinished();
@ -274,6 +290,7 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel
QTimer mReloadTimer; QTimer mReloadTimer;
bool mShouldReloadCurrentFeature = false; bool mShouldReloadCurrentFeature = false;
bool mExtraValueDoesNotExist = false; bool mExtraValueDoesNotExist = false;
bool mAllowNull = false;
QString mIdentifierField; QString mIdentifierField;

View File

@ -677,8 +677,7 @@ void QgsRelationReferenceWidget::mapIdentification()
void QgsRelationReferenceWidget::comboReferenceChanged( int index ) void QgsRelationReferenceWidget::comboReferenceChanged( int index )
{ {
QgsFeatureId fid = mComboBox->itemData( index, QgsAttributeTableModel::FeatureIdRole ).value<QgsFeatureId>(); mReferencedLayer->getFeatures( mComboBox->currentFeatureRequest() ).nextFeature( mFeature );
mReferencedLayer->getFeatures( QgsFeatureRequest().setFilterFid( fid ) ).nextFeature( mFeature );
highlightFeature( mFeature ); highlightFeature( mFeature );
updateAttributeEditorFrame( mFeature ); updateAttributeEditorFrame( mFeature );
emit foreignKeyChanged( mFeature.attribute( mReferencedFieldIdx ) ); emit foreignKeyChanged( mFeature.attribute( mReferencedFieldIdx ) );

View File

@ -38,6 +38,7 @@ QgsFeatureListComboBox::QgsFeatureListComboBox( QWidget *parent )
connect( mModel, &QgsFeatureFilterModel::filterExpressionChanged, this, &QgsFeatureListComboBox::filterExpressionChanged ); connect( mModel, &QgsFeatureFilterModel::filterExpressionChanged, this, &QgsFeatureListComboBox::filterExpressionChanged );
connect( mModel, &QgsFeatureFilterModel::isLoadingChanged, this, &QgsFeatureListComboBox::onLoadingChanged ); connect( mModel, &QgsFeatureFilterModel::isLoadingChanged, this, &QgsFeatureListComboBox::onLoadingChanged );
connect( mModel, &QgsFeatureFilterModel::filterJobCompleted, this, &QgsFeatureListComboBox::onFilterUpdateCompleted ); connect( mModel, &QgsFeatureFilterModel::filterJobCompleted, this, &QgsFeatureListComboBox::onFilterUpdateCompleted );
connect( mModel, &QgsFeatureFilterModel::allowNullChanged, this, &QgsFeatureListComboBox::allowNullChanged );
connect( mModel, &QgsFeatureFilterModel::extraIdentifierValueChanged, this, &QgsFeatureListComboBox::identifierValueChanged ); connect( mModel, &QgsFeatureFilterModel::extraIdentifierValueChanged, this, &QgsFeatureListComboBox::identifierValueChanged );
connect( mModel, &QgsFeatureFilterModel::extraIdentifierValueIndexChanged, this, &QgsFeatureListComboBox::setCurrentIndex ); connect( mModel, &QgsFeatureFilterModel::extraIdentifierValueIndexChanged, this, &QgsFeatureListComboBox::setCurrentIndex );
connect( mModel, &QgsFeatureFilterModel::identifierFieldChanged, this, &QgsFeatureListComboBox::identifierFieldChanged ); connect( mModel, &QgsFeatureFilterModel::identifierFieldChanged, this, &QgsFeatureListComboBox::identifierFieldChanged );
@ -45,6 +46,7 @@ QgsFeatureListComboBox::QgsFeatureListComboBox( QWidget *parent )
connect( mCompleter, static_cast<void( QCompleter::* )( const QModelIndex & )>( &QCompleter::activated ), this, &QgsFeatureListComboBox::onActivated ); connect( mCompleter, static_cast<void( QCompleter::* )( const QModelIndex & )>( &QCompleter::activated ), this, &QgsFeatureListComboBox::onActivated );
connect( mModel, &QgsFeatureFilterModel::beginUpdate, this, &QgsFeatureListComboBox::storeLineEditState ); connect( mModel, &QgsFeatureFilterModel::beginUpdate, this, &QgsFeatureListComboBox::storeLineEditState );
connect( mModel, &QgsFeatureFilterModel::endUpdate, this, &QgsFeatureListComboBox::restoreLineEditState ); connect( mModel, &QgsFeatureFilterModel::endUpdate, this, &QgsFeatureListComboBox::restoreLineEditState );
connect( mModel, &QgsFeatureFilterModel::dataChanged, this, &QgsFeatureListComboBox::onDataChanged );
connect( this, static_cast<void( QgsFeatureListComboBox::* )( int )>( &QgsFeatureListComboBox::currentIndexChanged ), this, &QgsFeatureListComboBox::onCurrentIndexChanged ); connect( this, static_cast<void( QgsFeatureListComboBox::* )( int )>( &QgsFeatureListComboBox::currentIndexChanged ), this, &QgsFeatureListComboBox::onCurrentIndexChanged );
@ -55,10 +57,7 @@ QgsFeatureListComboBox::QgsFeatureListComboBox( QWidget *parent )
connect( mLineEdit, &QgsFilterLineEdit::textEdited, this, &QgsFeatureListComboBox::onCurrentTextChanged ); connect( mLineEdit, &QgsFilterLineEdit::textEdited, this, &QgsFeatureListComboBox::onCurrentTextChanged );
connect( mLineEdit, &QgsFilterLineEdit::textChanged, this, []( const QString & text ) setToolTip( tr( "Just start typing what you are looking for." ) );
{
QgsDebugMsg( QStringLiteral( "Edit text changed to %1" ).arg( text ) );
} );
} }
QgsVectorLayer *QgsFeatureListComboBox::sourceLayer() const QgsVectorLayer *QgsFeatureListComboBox::sourceLayer() const
@ -83,6 +82,7 @@ void QgsFeatureListComboBox::setDisplayExpression( const QString &expression )
void QgsFeatureListComboBox::onCurrentTextChanged( const QString &text ) void QgsFeatureListComboBox::onCurrentTextChanged( const QString &text )
{ {
mIsCurrentlyEdited = true;
mPopupRequested = true; mPopupRequested = true;
mModel->setFilterValue( text ); mModel->setFilterValue( text );
} }
@ -107,6 +107,7 @@ void QgsFeatureListComboBox::onItemSelected( const QModelIndex &index )
void QgsFeatureListComboBox::onCurrentIndexChanged( int i ) void QgsFeatureListComboBox::onCurrentIndexChanged( int i )
{ {
mIsCurrentlyEdited = false;
QModelIndex modelIndex = mModel->index( i, 0, QModelIndex() ); QModelIndex modelIndex = mModel->index( i, 0, QModelIndex() );
mModel->setExtraIdentifierValue( mModel->data( modelIndex, QgsFeatureFilterModel::IdentifierValueRole ) ); mModel->setExtraIdentifierValue( mModel->data( modelIndex, QgsFeatureFilterModel::IdentifierValueRole ) );
mLineEdit->setText( mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() ); mLineEdit->setText( mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() );
@ -115,21 +116,35 @@ void QgsFeatureListComboBox::onCurrentIndexChanged( int i )
void QgsFeatureListComboBox::onActivated( QModelIndex modelIndex ) void QgsFeatureListComboBox::onActivated( QModelIndex modelIndex )
{ {
setIdentifierValue( mModel->data( modelIndex, QgsFeatureFilterModel::IdentifierValueRole ) ); 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() ); mLineEdit->setText( mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() );
} }
void QgsFeatureListComboBox::storeLineEditState() void QgsFeatureListComboBox::storeLineEditState()
{ {
if ( mIsCurrentlyEdited )
mLineEditState.store( mLineEdit ); mLineEditState.store( mLineEdit );
} }
void QgsFeatureListComboBox::restoreLineEditState() void QgsFeatureListComboBox::restoreLineEditState()
{ {
if ( mIsCurrentlyEdited )
mLineEditState.restore( mLineEdit ); mLineEditState.restore( mLineEdit );
} }
void QgsFeatureListComboBox::onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &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 QString QgsFeatureListComboBox::identifierField() const
{ {
return mModel->identifierField(); return mModel->identifierField();
@ -163,16 +178,12 @@ void QgsFeatureListComboBox::keyPressEvent( QKeyEvent *event )
bool QgsFeatureListComboBox::allowNull() const bool QgsFeatureListComboBox::allowNull() const
{ {
return mAllowNull; return mModel->allowNull();
} }
void QgsFeatureListComboBox::setAllowNull( bool allowNull ) void QgsFeatureListComboBox::setAllowNull( bool allowNull )
{ {
if ( mAllowNull == allowNull ) mModel->setAllowNull( allowNull );
return;
mAllowNull = allowNull;
emit allowNullChanged();
} }
QVariant QgsFeatureListComboBox::identifierValue() const QVariant QgsFeatureListComboBox::identifierValue() const
@ -187,6 +198,9 @@ void QgsFeatureListComboBox::setIdentifierValue( const QVariant &identifierValue
QgsFeatureRequest QgsFeatureListComboBox::currentFeatureRequest() const QgsFeatureRequest QgsFeatureListComboBox::currentFeatureRequest() const
{ {
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() ) ) ); return QgsFeatureRequest().setFilterExpression( QStringLiteral( "%1 = %2" ).arg( QgsExpression::quotedColumnRef( mModel->identifierField() ), QgsExpression::quotedValue( mModel->extraIdentifierValue() ) ) );
} }

View File

@ -48,6 +48,7 @@ class GUI_EXPORT QgsFeatureListComboBox : public QComboBox
Q_PROPERTY( bool allowNull READ allowNull WRITE setAllowNull NOTIFY allowNullChanged ) Q_PROPERTY( bool allowNull READ allowNull WRITE setAllowNull NOTIFY allowNullChanged )
public: public:
/** /**
* Create a new QgsFeatureListComboBox, optionally specifying a \a parent. * 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. * Determines if a NULL value should be available in the list.
*
* TODO!
*/ */
bool allowNull() const; bool allowNull() const;
@ -185,6 +184,7 @@ class GUI_EXPORT QgsFeatureListComboBox : public QComboBox
void onActivated( QModelIndex index ); void onActivated( QModelIndex index );
void storeLineEditState(); void storeLineEditState();
void restoreLineEditState(); void restoreLineEditState();
void onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>() );
private: private:
struct LineEditState struct LineEditState
@ -202,7 +202,6 @@ class GUI_EXPORT QgsFeatureListComboBox : public QComboBox
QCompleter *mCompleter; QCompleter *mCompleter;
QString mDisplayExpression; QString mDisplayExpression;
QgsFilterLineEdit *mLineEdit; QgsFilterLineEdit *mLineEdit;
bool mAllowNull = true;
bool mPopupRequested = false; bool mPopupRequested = false;
bool mIsCurrentlyEdited = false; bool mIsCurrentlyEdited = false;
LineEditState mLineEditState; LineEditState mLineEditState;