Skip to content

Commit

Permalink
Allow using NULL values
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Oct 26, 2017
1 parent 2a185a0 commit c661ab1
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 25 deletions.
16 changes: 16 additions & 0 deletions python/core/qgsfeaturefiltermodel.sip
Expand Up @@ -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();
Expand Down Expand Up @@ -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

};

/************************************************************************
Expand Down
2 changes: 0 additions & 2 deletions python/gui/qgsfeaturelistcombobox.sip
Expand Up @@ -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

Expand Down
39 changes: 36 additions & 3 deletions src/core/qgsfeaturefiltermodel.cpp
Expand Up @@ -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
Expand All @@ -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 )
{
Expand All @@ -213,20 +221,26 @@ 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();
setExtraIdentifierValueIndex( 0 );
}
else
{
QgsDebugMsg( QStringLiteral( "Current value is in new list" ) );
if ( currentEntryInNewList != 0 )
{
beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
Expand Down Expand Up @@ -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;
Expand All @@ -348,14 +362,33 @@ 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 );

reloadCurrentFeature();
}
}

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;
Expand Down Expand Up @@ -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 );
Expand Down
17 changes: 17 additions & 0 deletions src/core/qgsfeaturefiltermodel.h
Expand Up @@ -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 )

/**
Expand Down Expand Up @@ -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:

/**
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -274,6 +290,7 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel
QTimer mReloadTimer;
bool mShouldReloadCurrentFeature = false;
bool mExtraValueDoesNotExist = false;
bool mAllowNull = false;

QString mIdentifierField;

Expand Down
3 changes: 1 addition & 2 deletions src/gui/editorwidgets/qgsrelationreferencewidget.cpp
Expand Up @@ -677,8 +677,7 @@ void QgsRelationReferenceWidget::mapIdentification()

void QgsRelationReferenceWidget::comboReferenceChanged( int index )
{
QgsFeatureId fid = mComboBox->itemData( index, QgsAttributeTableModel::FeatureIdRole ).value<QgsFeatureId>();
mReferencedLayer->getFeatures( QgsFeatureRequest().setFilterFid( fid ) ).nextFeature( mFeature );
mReferencedLayer->getFeatures( mComboBox->currentFeatureRequest() ).nextFeature( mFeature );
highlightFeature( mFeature );
updateAttributeEditorFrame( mFeature );
emit foreignKeyChanged( mFeature.attribute( mReferencedFieldIdx ) );
Expand Down
44 changes: 29 additions & 15 deletions src/gui/qgsfeaturelistcombobox.cpp
Expand Up @@ -38,13 +38,15 @@ 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 );
connect( mCompleter, static_cast<void( QCompleter::* )( const QModelIndex & )>( &QCompleter::highlighted ), this, &QgsFeatureListComboBox::onItemSelected );
connect( mCompleter, static_cast<void( QCompleter::* )( const QModelIndex & )>( &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<void( QgsFeatureListComboBox::* )( int )>( &QgsFeatureListComboBox::currentIndexChanged ), this, &QgsFeatureListComboBox::onCurrentIndexChanged );

Expand All @@ -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
Expand All @@ -83,6 +82,7 @@ void QgsFeatureListComboBox::setDisplayExpression( const QString &expression )

void QgsFeatureListComboBox::onCurrentTextChanged( const QString &text )
{
mIsCurrentlyEdited = true;
mPopupRequested = true;
mModel->setFilterValue( text );
}
Expand All @@ -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() );
Expand All @@ -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<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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
5 changes: 2 additions & 3 deletions src/gui/qgsfeaturelistcombobox.h
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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<int> &roles = QVector<int>() );

private:
struct LineEditState
Expand All @@ -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;
Expand Down

0 comments on commit c661ab1

Please sign in to comment.