mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
[FEATURE] Add QgsFeatureListComboBox with live-filter-capabilities
This commit is contained in:
parent
d40447e7d0
commit
7811f38e48
@ -311,6 +311,7 @@
|
||||
%Include qgsfieldmodel.sip
|
||||
%Include qgsfieldproxymodel.sip
|
||||
%Include qgsfiledownloader.sip
|
||||
%Include qgsfeaturefiltermodel.sip
|
||||
%Include qgsgeometryvalidator.sip
|
||||
%Include qgsgml.sip
|
||||
%Include qgsgmlschema.sip
|
||||
|
118
python/core/qgsfeaturefiltermodel.sip
Normal file
118
python/core/qgsfeaturefiltermodel.sip
Normal file
@ -0,0 +1,118 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsfeaturefiltermodel.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsFeatureFilterModel : QAbstractItemModel
|
||||
{
|
||||
%Docstring
|
||||
Provides a list of features based on filter conditions.
|
||||
Features are fetched asynchronously.
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsfeaturefiltermodel.h"
|
||||
%End
|
||||
public:
|
||||
enum Role
|
||||
{
|
||||
IdentifierValueRole,
|
||||
ValueRole
|
||||
};
|
||||
|
||||
QgsFeatureFilterModel( QObject *parent = 0 );
|
||||
~QgsFeatureFilterModel();
|
||||
|
||||
QgsVectorLayer *sourceLayer() const;
|
||||
%Docstring
|
||||
:rtype: QgsVectorLayer
|
||||
%End
|
||||
void setSourceLayer( QgsVectorLayer *sourceLayer );
|
||||
|
||||
QString displayExpression() const;
|
||||
%Docstring
|
||||
:rtype: str
|
||||
%End
|
||||
void setDisplayExpression( const QString &displayExpression );
|
||||
|
||||
QString filterValue() const;
|
||||
%Docstring
|
||||
:rtype: str
|
||||
%End
|
||||
void setFilterValue( const QString &filterValue );
|
||||
|
||||
virtual QModelIndex index( int row, int column, const QModelIndex &parent ) const;
|
||||
virtual QModelIndex parent( const QModelIndex &child ) const;
|
||||
virtual int rowCount( const QModelIndex &parent ) const;
|
||||
virtual int columnCount( const QModelIndex &parent ) const;
|
||||
virtual QVariant data( const QModelIndex &index, int role ) const;
|
||||
|
||||
QString filterExpression() const;
|
||||
%Docstring
|
||||
An additional filter expression to apply, next to the filterValue.
|
||||
Can be used for spatial filtering etc.
|
||||
:rtype: str
|
||||
%End
|
||||
|
||||
void setFilterExpression( const QString &filterExpression );
|
||||
%Docstring
|
||||
An additional filter expression to apply, next to the filterValue.
|
||||
Can be used for spatial filtering etc.
|
||||
%End
|
||||
|
||||
bool isLoading() const;
|
||||
%Docstring
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
QString identifierField() const;
|
||||
%Docstring
|
||||
:rtype: str
|
||||
%End
|
||||
void setIdentifierField( const QString &identifierField );
|
||||
|
||||
QVariant extraIdentifierValue() const;
|
||||
%Docstring
|
||||
:rtype: QVariant
|
||||
%End
|
||||
void setExtraIdentifierValue( const QVariant &extraIdentifierValue );
|
||||
|
||||
int extraIdentifierValueIndex() const;
|
||||
%Docstring
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
bool extraValueDoesNotExist() const;
|
||||
%Docstring
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
signals:
|
||||
void sourceLayerChanged();
|
||||
void displayExpressionChanged();
|
||||
void filterValueChanged();
|
||||
void filterExpressionChanged();
|
||||
void isLoadingChanged();
|
||||
void identifierFieldChanged();
|
||||
void filterJobCompleted();
|
||||
void extraIdentifierValueChanged();
|
||||
void extraIdentifierValueIndexChanged( int index );
|
||||
void extraValueDoesNotExistChanged();
|
||||
void beginUpdate();
|
||||
void endUpdate();
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsfeaturefiltermodel.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -108,6 +108,7 @@
|
||||
%Include qgsfeatureselectiondlg.sip
|
||||
%Include qgsfieldcombobox.sip
|
||||
%Include qgsfieldexpressionwidget.sip
|
||||
%Include qgsfeaturelistcombobox.sip
|
||||
%Include qgsfieldvalidator.sip
|
||||
%Include qgsfieldvalueslineedit.sip
|
||||
%Include qgsfilewidget.sip
|
||||
|
104
python/gui/qgsfeaturelistcombobox.sip
Normal file
104
python/gui/qgsfeaturelistcombobox.sip
Normal file
@ -0,0 +1,104 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsfeaturelistcombobox.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsFeatureListComboBox : QComboBox
|
||||
{
|
||||
%Docstring
|
||||
*************************************************************************
|
||||
qgsfieldlistcombobox.h - QgsFieldListComboBox
|
||||
|
||||
---------------------
|
||||
begin : 10.3.2017
|
||||
copyright : (C) 2017 by Matthias Kuhn
|
||||
email : matthias@opengis.ch
|
||||
**************************************************************************
|
||||
*
|
||||
This program is free software; you can redistribute it and/or modify *
|
||||
it under the terms of the GNU General Public License as published by *
|
||||
the Free Software Foundation; either version 2 of the License, or *
|
||||
(at your option) any later version. *
|
||||
*
|
||||
**************************************************************************
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsfeaturelistcombobox.h"
|
||||
%End
|
||||
public:
|
||||
QgsFeatureListComboBox( QWidget *parent = 0 );
|
||||
|
||||
QgsVectorLayer *sourceLayer() const;
|
||||
%Docstring
|
||||
:rtype: QgsVectorLayer
|
||||
%End
|
||||
void setSourceLayer( QgsVectorLayer *sourceLayer );
|
||||
|
||||
QString displayExpression() const;
|
||||
%Docstring
|
||||
:rtype: str
|
||||
%End
|
||||
void setDisplayExpression( const QString &displayExpression );
|
||||
|
||||
QString filterExpression() const;
|
||||
%Docstring
|
||||
:rtype: str
|
||||
%End
|
||||
void setFilterExpression( const QString &filterExpression );
|
||||
|
||||
QVariant identifierValue() const;
|
||||
%Docstring
|
||||
:rtype: QVariant
|
||||
%End
|
||||
void setIdentifierValue( const QVariant &identifierValue );
|
||||
|
||||
QgsFeatureRequest currentFeatureRequest() const;
|
||||
%Docstring
|
||||
:rtype: QgsFeatureRequest
|
||||
%End
|
||||
|
||||
bool allowNull() const;
|
||||
%Docstring
|
||||
:rtype: bool
|
||||
%End
|
||||
void setAllowNull( bool allowNull );
|
||||
|
||||
QString identifierField() const;
|
||||
%Docstring
|
||||
:rtype: str
|
||||
%End
|
||||
void setIdentifierField( const QString &identifierField );
|
||||
|
||||
QModelIndex currentModelIndex() const;
|
||||
%Docstring
|
||||
:rtype: QModelIndex
|
||||
%End
|
||||
|
||||
virtual void focusOutEvent( QFocusEvent *event );
|
||||
|
||||
virtual void keyPressEvent( QKeyEvent *event );
|
||||
|
||||
signals:
|
||||
void sourceLayerChanged();
|
||||
void displayExpressionChanged();
|
||||
void filterExpressionChanged();
|
||||
void identifierValueChanged();
|
||||
void identifierFieldChanged();
|
||||
void allowNullChanged();
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/gui/qgsfeaturelistcombobox.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -175,6 +175,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgsfeaturesink.cpp
|
||||
qgsfeaturesource.cpp
|
||||
qgsfeaturestore.cpp
|
||||
qgsfeaturefiltermodel.cpp
|
||||
qgsfield.cpp
|
||||
qgsfieldconstraints.cpp
|
||||
qgsfieldformatter.cpp
|
||||
@ -590,6 +591,8 @@ SET(QGIS_CORE_MOC_HDRS
|
||||
qgsfieldmodel.h
|
||||
qgsfieldproxymodel.h
|
||||
qgsfiledownloader.h
|
||||
qgsfeaturefiltermodel.h
|
||||
qgsfeaturefiltermodel_p.h
|
||||
qgsgeometryvalidator.h
|
||||
qgsgml.h
|
||||
qgsgmlschema.h
|
||||
|
412
src/core/qgsfeaturefiltermodel.cpp
Normal file
412
src/core/qgsfeaturefiltermodel.cpp
Normal file
@ -0,0 +1,412 @@
|
||||
/***************************************************************************
|
||||
qgsfeaturefiltermodel.cpp - QgsFeatureFilterModel
|
||||
|
||||
---------------------
|
||||
begin : 10.3.2017
|
||||
copyright : (C) 2017 by Matthias Kuhn
|
||||
email : matthias@opengis.ch
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include "qgsfeaturefiltermodel.h"
|
||||
#include "qgsfeaturefiltermodel_p.h"
|
||||
|
||||
QgsFeatureFilterModel::QgsFeatureFilterModel( QObject *parent )
|
||||
: QAbstractItemModel( parent )
|
||||
, mSourceLayer( nullptr )
|
||||
{
|
||||
mReloadTimer.setInterval( 100 );
|
||||
mReloadTimer.setSingleShot( true );
|
||||
connect( &mReloadTimer, &QTimer::timeout, this, &QgsFeatureFilterModel::scheduledReload );
|
||||
setExtraIdentifierValueUnguarded( QVariant() );
|
||||
}
|
||||
|
||||
QgsFeatureFilterModel::~QgsFeatureFilterModel()
|
||||
{
|
||||
if ( mGatherer )
|
||||
connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished, mGatherer, &QgsFieldExpressionValuesGatherer::deleteLater );
|
||||
}
|
||||
|
||||
QgsVectorLayer *QgsFeatureFilterModel::sourceLayer() const
|
||||
{
|
||||
return mSourceLayer;
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::setSourceLayer( QgsVectorLayer *sourceLayer )
|
||||
{
|
||||
if ( mSourceLayer == sourceLayer )
|
||||
return;
|
||||
|
||||
mSourceLayer = sourceLayer;
|
||||
reload();
|
||||
emit sourceLayerChanged();
|
||||
}
|
||||
|
||||
QString QgsFeatureFilterModel::displayExpression() const
|
||||
{
|
||||
return mDisplayExpression;
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::setDisplayExpression( const QString &displayExpression )
|
||||
{
|
||||
if ( mDisplayExpression == displayExpression )
|
||||
return;
|
||||
|
||||
mDisplayExpression = displayExpression;
|
||||
reload();
|
||||
emit displayExpressionChanged();
|
||||
}
|
||||
|
||||
QString QgsFeatureFilterModel::filterValue() const
|
||||
{
|
||||
return mFilterValue;
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::setFilterValue( const QString &filterValue )
|
||||
{
|
||||
if ( mFilterValue == filterValue )
|
||||
return;
|
||||
|
||||
mFilterValue = filterValue;
|
||||
reload();
|
||||
emit filterValueChanged();
|
||||
}
|
||||
|
||||
QString QgsFeatureFilterModel::filterExpression() const
|
||||
{
|
||||
return mFilterExpression;
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::setFilterExpression( const QString &filterExpression )
|
||||
{
|
||||
if ( mFilterExpression == filterExpression )
|
||||
return;
|
||||
|
||||
mFilterExpression = filterExpression;
|
||||
reload();
|
||||
emit filterExpressionChanged();
|
||||
}
|
||||
|
||||
bool QgsFeatureFilterModel::isLoading() const
|
||||
{
|
||||
return mGatherer;
|
||||
}
|
||||
|
||||
QModelIndex QgsFeatureFilterModel::index( int row, int column, const QModelIndex &parent ) const
|
||||
{
|
||||
Q_UNUSED( parent )
|
||||
return createIndex( row, column, nullptr );
|
||||
}
|
||||
|
||||
QModelIndex QgsFeatureFilterModel::parent( const QModelIndex &child ) const
|
||||
{
|
||||
Q_UNUSED( child )
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int QgsFeatureFilterModel::rowCount( const QModelIndex &parent ) const
|
||||
{
|
||||
Q_UNUSED( parent );
|
||||
|
||||
return mEntries.size();
|
||||
}
|
||||
|
||||
int QgsFeatureFilterModel::columnCount( const QModelIndex &parent ) const
|
||||
{
|
||||
Q_UNUSED( parent )
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant QgsFeatureFilterModel::data( const QModelIndex &index, int role ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
return QVariant();
|
||||
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole:
|
||||
case ValueRole:
|
||||
return mEntries.value( index.row() ).value;
|
||||
|
||||
case IdentifierValueRole:
|
||||
return mEntries.value( index.row() ).identifierValue;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::updateCompleter()
|
||||
{
|
||||
emit beginUpdate();
|
||||
QVector<Entry> entries = mGatherer->entries();
|
||||
|
||||
if ( mExtraIdentifierValueIndex == -1 )
|
||||
setExtraIdentifierValueUnguarded( QVariant() );
|
||||
|
||||
// Only reloading the current entry?
|
||||
if ( mGatherer->data().toBool() )
|
||||
{
|
||||
if ( !entries.isEmpty() )
|
||||
{
|
||||
mEntries.replace( mExtraIdentifierValueIndex, entries.at( 0 ) );
|
||||
emit dataChanged( index( mExtraIdentifierValueIndex, 0, QModelIndex() ), index( mExtraIdentifierValueIndex, 0, QModelIndex() ) );
|
||||
mShouldReloadCurrentFeature = false;
|
||||
setExtraValueDoesNotExist( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
setExtraValueDoesNotExist( true );
|
||||
}
|
||||
|
||||
mShouldReloadCurrentFeature = false;
|
||||
}
|
||||
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; } );
|
||||
|
||||
int newEntriesSize = entries.size();
|
||||
|
||||
// Find the index of the extra entry in the new list
|
||||
int currentEntryInNewList = -1;
|
||||
if ( mExtraIdentifierValueIndex != -1 )
|
||||
{
|
||||
for ( int i = 0; i < newEntriesSize; ++i )
|
||||
{
|
||||
if ( entries.at( i ).identifierValue == mExtraIdentifierValue )
|
||||
{
|
||||
currentEntryInNewList = i;
|
||||
mEntries.replace( mExtraIdentifierValueIndex, entries.at( i ) );
|
||||
emit dataChanged( index( mExtraIdentifierValueIndex, 0, QModelIndex() ), index( mExtraIdentifierValueIndex, 0, QModelIndex() ) );
|
||||
setExtraValueDoesNotExist( false );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT_X( false, "QgsFeatureFilterModel::updateCompleter", "No extra identifier value generated. Should not get here." );
|
||||
}
|
||||
|
||||
int firstRow = 0;
|
||||
|
||||
// Move the extra entry to the first position
|
||||
if ( mExtraIdentifierValueIndex != -1 )
|
||||
{
|
||||
if ( mExtraIdentifierValueIndex != 0 )
|
||||
{
|
||||
beginMoveRows( QModelIndex(), mExtraIdentifierValueIndex, mExtraIdentifierValueIndex, QModelIndex(), 0 );
|
||||
mEntries.move( mExtraIdentifierValueIndex, 0 );
|
||||
endMoveRows();
|
||||
}
|
||||
firstRow = 1;
|
||||
}
|
||||
|
||||
// Remove all entries (except for extra entry if existant)
|
||||
beginRemoveRows( QModelIndex(), firstRow, mEntries.size() - firstRow );
|
||||
mEntries.remove( firstRow, mEntries.size() - firstRow );
|
||||
endRemoveRows();
|
||||
|
||||
if ( currentEntryInNewList == -1 )
|
||||
{
|
||||
beginInsertRows( QModelIndex(), 1, entries.size() + 1 );
|
||||
mEntries += entries;
|
||||
endInsertRows();
|
||||
setExtraIdentifierValueIndex( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( currentEntryInNewList != 0 )
|
||||
{
|
||||
beginInsertRows( QModelIndex(), 0, currentEntryInNewList - 1 );
|
||||
mEntries = entries.mid( 0, currentEntryInNewList );
|
||||
endInsertRows();
|
||||
}
|
||||
else
|
||||
{
|
||||
mEntries.replace( 0, entries.at( 0 ) );
|
||||
}
|
||||
|
||||
emit dataChanged( index( currentEntryInNewList, 0, QModelIndex() ), index( currentEntryInNewList, 0, QModelIndex() ) );
|
||||
|
||||
beginInsertRows( QModelIndex(), currentEntryInNewList + 1, newEntriesSize - currentEntryInNewList - 1 );
|
||||
mEntries += entries.mid( currentEntryInNewList + 1 );
|
||||
endInsertRows();
|
||||
setExtraIdentifierValueIndex( currentEntryInNewList );
|
||||
}
|
||||
|
||||
emit filterJobCompleted();
|
||||
}
|
||||
emit endUpdate();
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::gathererThreadFinished()
|
||||
{
|
||||
delete mGatherer;
|
||||
mGatherer = nullptr;
|
||||
emit isLoadingChanged();
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::scheduledReload()
|
||||
{
|
||||
if ( !mSourceLayer )
|
||||
return;
|
||||
|
||||
bool wasLoading = false;
|
||||
|
||||
if ( mGatherer )
|
||||
{
|
||||
// Send the gatherer thread to the graveyard:
|
||||
// forget about it, tell it to stop and delete when finished
|
||||
disconnect( mGatherer, &QgsFieldExpressionValuesGatherer::collectedValues, this, &QgsFeatureFilterModel::updateCompleter );
|
||||
disconnect( mGatherer, &QgsFieldExpressionValuesGatherer::finished, this, &QgsFeatureFilterModel::gathererThreadFinished );
|
||||
connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished, mGatherer, &QgsFieldExpressionValuesGatherer::deleteLater );
|
||||
mGatherer->stop();
|
||||
wasLoading = true;
|
||||
}
|
||||
|
||||
QgsFeatureRequest request;
|
||||
|
||||
if ( mShouldReloadCurrentFeature )
|
||||
{
|
||||
request.setFilterExpression( QStringLiteral( "%1 = %2" ).arg( QgsExpression::quotedColumnRef( mIdentifierField ), QgsExpression::quotedValue( mExtraIdentifierValue ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString filterClause;
|
||||
|
||||
if ( mFilterValue.isEmpty() && !mFilterExpression.isEmpty() )
|
||||
filterClause = mFilterExpression;
|
||||
else if ( mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
|
||||
filterClause = QStringLiteral( "(%1) ILIKE '\%%2\%'" ).arg( mDisplayExpression, mFilterValue );
|
||||
else if ( !mFilterExpression.isEmpty() && !mFilterValue.isEmpty() )
|
||||
filterClause = QStringLiteral( "(%1) AND ((%2) ILIKE '\%%3\%')" ).arg( mFilterExpression, mDisplayExpression, mFilterValue );
|
||||
|
||||
request.setFilterExpression( filterClause );
|
||||
}
|
||||
|
||||
request.setLimit( 100 );
|
||||
|
||||
mGatherer = new QgsFieldExpressionValuesGatherer( mSourceLayer, mDisplayExpression, mIdentifierField, request );
|
||||
mGatherer->setData( mShouldReloadCurrentFeature );
|
||||
|
||||
connect( mGatherer, &QgsFieldExpressionValuesGatherer::collectedValues, this, &QgsFeatureFilterModel::updateCompleter );
|
||||
connect( mGatherer, &QgsFieldExpressionValuesGatherer::finished, this, &QgsFeatureFilterModel::gathererThreadFinished );
|
||||
|
||||
mGatherer->start();
|
||||
if ( !wasLoading )
|
||||
emit isLoadingChanged();
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::setExtraIdentifierValueIndex( int index )
|
||||
{
|
||||
if ( mExtraIdentifierValueIndex == index )
|
||||
return;
|
||||
|
||||
mExtraIdentifierValueIndex = index;
|
||||
emit extraIdentifierValueIndexChanged( index );
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::reloadCurrentFeature()
|
||||
{
|
||||
mShouldReloadCurrentFeature = true;
|
||||
mReloadTimer.start();
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::setExtraIdentifierValueUnguarded( const QVariant &extraIdentifierValue )
|
||||
{
|
||||
const QVector<Entry> entries = mEntries;
|
||||
|
||||
int index = 0;
|
||||
for ( const Entry &entry : entries )
|
||||
{
|
||||
if ( entry.identifierValue == extraIdentifierValue )
|
||||
{
|
||||
setExtraIdentifierValueIndex( index );
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
// Value not found in current entries
|
||||
if ( mExtraIdentifierValueIndex != index )
|
||||
{
|
||||
beginInsertRows( QModelIndex(), 0, 0 );
|
||||
mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral( "(%1)" ).arg( extraIdentifierValue.toString() ) ) );
|
||||
endInsertRows();
|
||||
setExtraIdentifierValueIndex( 0 );
|
||||
|
||||
reloadCurrentFeature();
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsFeatureFilterModel::extraValueDoesNotExist() const
|
||||
{
|
||||
return mExtraValueDoesNotExist;
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::setExtraValueDoesNotExist( bool extraValueDoesNotExist )
|
||||
{
|
||||
if ( mExtraValueDoesNotExist == extraValueDoesNotExist )
|
||||
return;
|
||||
|
||||
mExtraValueDoesNotExist = extraValueDoesNotExist;
|
||||
emit extraValueDoesNotExistChanged();
|
||||
}
|
||||
|
||||
int QgsFeatureFilterModel::extraIdentifierValueIndex() const
|
||||
{
|
||||
return mExtraIdentifierValueIndex;
|
||||
}
|
||||
|
||||
QString QgsFeatureFilterModel::identifierField() const
|
||||
{
|
||||
return mIdentifierField;
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::setIdentifierField( const QString &identifierField )
|
||||
{
|
||||
if ( mIdentifierField == identifierField )
|
||||
return;
|
||||
|
||||
mIdentifierField = identifierField;
|
||||
emit identifierFieldChanged();
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::reload()
|
||||
{
|
||||
mReloadTimer.start();
|
||||
}
|
||||
|
||||
QVariant QgsFeatureFilterModel::extraIdentifierValue() const
|
||||
{
|
||||
return mExtraIdentifierValue;
|
||||
}
|
||||
|
||||
void QgsFeatureFilterModel::setExtraIdentifierValue( const QVariant &extraIdentifierValue )
|
||||
{
|
||||
if ( extraIdentifierValue == mExtraIdentifierValue && extraIdentifierValue.isNull() == mExtraIdentifierValue.isNull() )
|
||||
return;
|
||||
|
||||
setExtraIdentifierValueUnguarded( extraIdentifierValue );
|
||||
|
||||
mExtraIdentifierValue = extraIdentifierValue;
|
||||
emit extraIdentifierValueChanged();
|
||||
}
|
||||
|
||||
QVariant QgsFieldExpressionValuesGatherer::data() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
void QgsFieldExpressionValuesGatherer::setData( const QVariant &data )
|
||||
{
|
||||
mData = data;
|
||||
}
|
163
src/core/qgsfeaturefiltermodel.h
Normal file
163
src/core/qgsfeaturefiltermodel.h
Normal file
@ -0,0 +1,163 @@
|
||||
/***************************************************************************
|
||||
qgsfeaturefiltermodel.h - QgsFeatureFilterModel
|
||||
|
||||
---------------------
|
||||
begin : 10.3.2017
|
||||
copyright : (C) 2017 by Matthias Kuhn
|
||||
email : matthias@opengis.ch
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSFEATUREFILTERMODEL_H
|
||||
#define QGSFEATUREFILTERMODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include "qgsvectorlayer.h"
|
||||
|
||||
class QgsFieldExpressionValuesGatherer;
|
||||
|
||||
/**
|
||||
* Provides a list of features based on filter conditions.
|
||||
* Features are fetched asynchronously.
|
||||
*/
|
||||
class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( QgsVectorLayer *sourceLayer READ sourceLayer WRITE setSourceLayer NOTIFY sourceLayerChanged )
|
||||
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 isLoading READ isLoading NOTIFY isLoadingChanged )
|
||||
|
||||
/**
|
||||
* A field of sourceLayer that is unique and should be used to identify features.
|
||||
* Normally the primary key field.
|
||||
* Needs to match the identifierValue.
|
||||
*/
|
||||
Q_PROPERTY( QString identifierField READ identifierField WRITE setIdentifierField NOTIFY identifierFieldChanged )
|
||||
|
||||
/**
|
||||
* The value that identifies the current feature.
|
||||
*/
|
||||
Q_PROPERTY( QVariant extraIdentifierValue READ extraIdentifierValue WRITE setExtraIdentifierValue NOTIFY extraIdentifierValueChanged )
|
||||
|
||||
Q_PROPERTY( int extraIdentifierValueIndex READ extraIdentifierValueIndex NOTIFY extraIdentifierValueIndexChanged )
|
||||
|
||||
public:
|
||||
enum Role
|
||||
{
|
||||
IdentifierValueRole = Qt::UserRole,
|
||||
ValueRole
|
||||
};
|
||||
|
||||
QgsFeatureFilterModel( QObject *parent = nullptr );
|
||||
~QgsFeatureFilterModel();
|
||||
|
||||
QgsVectorLayer *sourceLayer() const;
|
||||
void setSourceLayer( QgsVectorLayer *sourceLayer );
|
||||
|
||||
QString displayExpression() const;
|
||||
void setDisplayExpression( const QString &displayExpression );
|
||||
|
||||
QString filterValue() const;
|
||||
void setFilterValue( const QString &filterValue );
|
||||
|
||||
virtual QModelIndex index( int row, int column, const QModelIndex &parent ) const override;
|
||||
virtual QModelIndex parent( const QModelIndex &child ) const override;
|
||||
virtual int rowCount( const QModelIndex &parent ) const override;
|
||||
virtual int columnCount( const QModelIndex &parent ) const override;
|
||||
virtual QVariant data( const QModelIndex &index, int role ) const override;
|
||||
|
||||
/**
|
||||
* An additional filter expression to apply, next to the filterValue.
|
||||
* Can be used for spatial filtering etc.
|
||||
*/
|
||||
QString filterExpression() const;
|
||||
|
||||
/**
|
||||
* An additional filter expression to apply, next to the filterValue.
|
||||
* Can be used for spatial filtering etc.
|
||||
*/
|
||||
void setFilterExpression( const QString &filterExpression );
|
||||
|
||||
bool isLoading() const;
|
||||
|
||||
QString identifierField() const;
|
||||
void setIdentifierField( const QString &identifierField );
|
||||
|
||||
QVariant extraIdentifierValue() const;
|
||||
void setExtraIdentifierValue( const QVariant &extraIdentifierValue );
|
||||
|
||||
int extraIdentifierValueIndex() const;
|
||||
|
||||
bool extraValueDoesNotExist() const;
|
||||
|
||||
signals:
|
||||
void sourceLayerChanged();
|
||||
void displayExpressionChanged();
|
||||
void filterValueChanged();
|
||||
void filterExpressionChanged();
|
||||
void isLoadingChanged();
|
||||
void identifierFieldChanged();
|
||||
void filterJobCompleted();
|
||||
void extraIdentifierValueChanged();
|
||||
void extraIdentifierValueIndexChanged( int index );
|
||||
void extraValueDoesNotExistChanged();
|
||||
void beginUpdate();
|
||||
void endUpdate();
|
||||
|
||||
private slots:
|
||||
void updateCompleter();
|
||||
void gathererThreadFinished();
|
||||
void scheduledReload();
|
||||
|
||||
private:
|
||||
void setExtraIdentifierValueIndex( int index );
|
||||
void setExtraValueDoesNotExist( bool extraValueDoesNotExist );
|
||||
void reload();
|
||||
void reloadCurrentFeature();
|
||||
void setExtraIdentifierValueUnguarded( const QVariant &extraIdentifierValue );
|
||||
struct Entry
|
||||
{
|
||||
Entry()
|
||||
{}
|
||||
|
||||
Entry( QVariant _identifierValue, const QString &_value )
|
||||
: identifierValue( _identifierValue )
|
||||
, value( _value )
|
||||
{}
|
||||
|
||||
QVariant identifierValue;
|
||||
QString value;
|
||||
|
||||
bool operator()( const Entry &lhs, const Entry &rhs ) const;
|
||||
};
|
||||
|
||||
QgsVectorLayer *mSourceLayer;
|
||||
QString mDisplayExpression;
|
||||
QString mFilterValue;
|
||||
QString mFilterExpression;
|
||||
|
||||
QVector<Entry> mEntries;
|
||||
QgsFieldExpressionValuesGatherer *mGatherer = nullptr;
|
||||
QTimer mReloadTimer;
|
||||
bool mShouldReloadCurrentFeature;
|
||||
bool mExtraValueDoesNotExist = false;
|
||||
|
||||
QString mIdentifierField;
|
||||
|
||||
QVariant mExtraIdentifierValue;
|
||||
|
||||
int mExtraIdentifierValueIndex = -1;
|
||||
|
||||
friend class QgsFieldExpressionValuesGatherer;
|
||||
};
|
||||
|
||||
#endif // QGSFEATUREFILTERMODEL_H
|
131
src/core/qgsfeaturefiltermodel_p.h
Normal file
131
src/core/qgsfeaturefiltermodel_p.h
Normal file
@ -0,0 +1,131 @@
|
||||
/***************************************************************************
|
||||
qgsfeaturefiltermodel_p - QgsFieldExpressionValuesGatherer
|
||||
|
||||
---------------------
|
||||
begin : 10.3.2017
|
||||
copyright : (C) 2017 by Matthias Kuhn
|
||||
email : matthias@opengis.ch
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSFEATUREFILTERMODEL_P_H
|
||||
#define QGSFEATUREFILTERMODEL_P_H
|
||||
|
||||
#include <QThread>
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsfeaturefiltermodel.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsvectorlayerfeatureiterator.h"
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
// just internal guff - definitely not for exposing to public API!
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* \class QgsFieldExpressionValuesGatherer
|
||||
* Gathers features with substring matching on an expression.
|
||||
*
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class QgsFieldExpressionValuesGatherer: public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsFieldExpressionValuesGatherer( QgsVectorLayer *layer, const QString &displayExpression, const QString &identifierField, const QgsFeatureRequest &request = QgsFeatureRequest() )
|
||||
: mSource( new QgsVectorLayerFeatureSource( layer ) )
|
||||
, mDisplayExpression( displayExpression )
|
||||
, mRequest( request )
|
||||
, mWasCanceled( false )
|
||||
, mIdentifierField( identifierField )
|
||||
{
|
||||
}
|
||||
|
||||
~QgsFieldExpressionValuesGatherer()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void run() override
|
||||
{
|
||||
mWasCanceled = false;
|
||||
|
||||
mIterator = mSource->getFeatures( mRequest );
|
||||
|
||||
QgsDebugMsg( QStringLiteral( "New gatherer: %1" ).arg( mRequest.filterExpression()->expression() ) );
|
||||
mDisplayExpression.prepare( &mExpressionContext );
|
||||
|
||||
QgsFeature feat;
|
||||
int attribute = mSource->fields().indexOf( mIdentifierField );
|
||||
|
||||
while ( mIterator.nextFeature( feat ) )
|
||||
{
|
||||
mExpressionContext.setFeature( feat );
|
||||
mEntries.append( QgsFeatureFilterModel::Entry( feat.attribute( attribute ), mDisplayExpression.evaluate( &mExpressionContext ).toString() ) );
|
||||
|
||||
if ( mWasCanceled )
|
||||
return;
|
||||
}
|
||||
|
||||
emit collectedValues();
|
||||
}
|
||||
|
||||
//! Informs the gatherer to immediately stop collecting values
|
||||
void stop()
|
||||
{
|
||||
mWasCanceled = true;
|
||||
}
|
||||
|
||||
//! Returns true if collection was canceled before completion
|
||||
bool wasCanceled() const { return mWasCanceled; }
|
||||
|
||||
QVector<QgsFeatureFilterModel::Entry> entries() const
|
||||
{
|
||||
return mEntries;
|
||||
}
|
||||
|
||||
QgsFeatureRequest request() const
|
||||
{
|
||||
return mRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal data, use for whatever you want. Defaults to -1.
|
||||
*/
|
||||
QVariant data() const;
|
||||
|
||||
/**
|
||||
* Internal data, use for whatever you want. Defaults to -1.
|
||||
*/
|
||||
void setData( const QVariant &data ); // TODO: Do we still need this???
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* Emitted when values have been collected
|
||||
* @param values list of unique matching string values
|
||||
*/
|
||||
void collectedValues();
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<QgsVectorLayerFeatureSource> mSource;
|
||||
QgsExpression mDisplayExpression;
|
||||
QgsExpressionContext mExpressionContext;
|
||||
QgsFeatureRequest mRequest;
|
||||
QgsFeatureIterator mIterator;
|
||||
bool mWasCanceled;
|
||||
QVector<QgsFeatureFilterModel::Entry> mEntries;
|
||||
QString mIdentifierField;
|
||||
QVariant mData;
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
||||
|
||||
#endif // QGSFEATUREFILTERMODEL_P_H
|
@ -241,6 +241,7 @@ SET(QGIS_GUI_SRCS
|
||||
qgsfeatureselectiondlg.cpp
|
||||
qgsfieldcombobox.cpp
|
||||
qgsfieldexpressionwidget.cpp
|
||||
qgsfeaturelistcombobox.cpp
|
||||
qgsfieldvalidator.cpp
|
||||
qgsfieldvalueslineedit.cpp
|
||||
qgsfilewidget.cpp
|
||||
@ -412,6 +413,7 @@ SET(QGIS_GUI_MOC_HDRS
|
||||
qgsfeatureselectiondlg.h
|
||||
qgsfieldcombobox.h
|
||||
qgsfieldexpressionwidget.h
|
||||
qgsfeaturelistcombobox.h
|
||||
qgsfieldvalidator.h
|
||||
qgsfieldvalueslineedit.h
|
||||
qgsfilewidget.h
|
||||
|
217
src/gui/qgsfeaturelistcombobox.cpp
Normal file
217
src/gui/qgsfeaturelistcombobox.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
/***************************************************************************
|
||||
qgsfieldlistcombobox.cpp - QgsFieldListComboBox
|
||||
|
||||
---------------------
|
||||
begin : 10.3.2017
|
||||
copyright : (C) 2017 by Matthias Kuhn
|
||||
email : matthias@opengis.ch
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include "qgsfeaturelistcombobox.h"
|
||||
|
||||
#include "qgsfeaturefiltermodel.h"
|
||||
#include "qgsanimatedicon.h"
|
||||
#include "qgsfilterlineedit.h"
|
||||
#include "qgslogger.h"
|
||||
|
||||
#include <QCompleter>
|
||||
#include <QLineEdit>
|
||||
#include <QKeyEvent>
|
||||
|
||||
QgsFeatureListComboBox::QgsFeatureListComboBox( QWidget *parent )
|
||||
: QComboBox( parent )
|
||||
, mModel( new QgsFeatureFilterModel( this ) )
|
||||
, mCompleter( new QCompleter( mModel ) )
|
||||
{
|
||||
mCompleter->setCaseSensitivity( Qt::CaseInsensitive );
|
||||
mCompleter->setFilterMode( Qt::MatchContains );
|
||||
setCompleter( mCompleter );
|
||||
mCompleter->setWidget( this );
|
||||
connect( mModel, &QgsFeatureFilterModel::sourceLayerChanged, this, &QgsFeatureListComboBox::sourceLayerChanged );
|
||||
connect( mModel, &QgsFeatureFilterModel::displayExpressionChanged, this, &QgsFeatureListComboBox::displayExpressionChanged );
|
||||
connect( mModel, &QgsFeatureFilterModel::filterExpressionChanged, this, &QgsFeatureListComboBox::filterExpressionChanged );
|
||||
connect( mModel, &QgsFeatureFilterModel::isLoadingChanged, this, &QgsFeatureListComboBox::onLoadingChanged );
|
||||
connect( mModel, &QgsFeatureFilterModel::filterJobCompleted, this, &QgsFeatureListComboBox::onFilterUpdateCompleted );
|
||||
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( this, static_cast<void( QgsFeatureListComboBox::* )( int )>( &QgsFeatureListComboBox::currentIndexChanged ), this, &QgsFeatureListComboBox::onCurrentIndexChanged );
|
||||
|
||||
mLineEdit = new QgsFilterLineEdit();
|
||||
setEditable( true );
|
||||
setLineEdit( mLineEdit );
|
||||
setModel( mModel );
|
||||
|
||||
connect( mLineEdit, &QgsFilterLineEdit::textEdited, this, &QgsFeatureListComboBox::onCurrentTextChanged );
|
||||
|
||||
connect( mLineEdit, &QgsFilterLineEdit::textChanged, this, []( const QString & text )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Edit text changed to %1" ).arg( text ) );
|
||||
} );
|
||||
}
|
||||
|
||||
QgsVectorLayer *QgsFeatureListComboBox::sourceLayer() const
|
||||
{
|
||||
return mModel->sourceLayer();
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::setSourceLayer( QgsVectorLayer *sourceLayer )
|
||||
{
|
||||
mModel->setSourceLayer( sourceLayer );
|
||||
}
|
||||
|
||||
QString QgsFeatureListComboBox::displayExpression() const
|
||||
{
|
||||
return mModel->displayExpression();
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::setDisplayExpression( const QString &expression )
|
||||
{
|
||||
mModel->setDisplayExpression( expression );
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::onCurrentTextChanged( const QString &text )
|
||||
{
|
||||
mPopupRequested = true;
|
||||
mModel->setFilterValue( text );
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::onFilterUpdateCompleted()
|
||||
{
|
||||
if ( mPopupRequested )
|
||||
mCompleter->complete();
|
||||
|
||||
mPopupRequested = false;
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::onLoadingChanged()
|
||||
{
|
||||
mLineEdit->setShowSpinner( mModel->isLoading() );
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::onItemSelected( const QModelIndex &index )
|
||||
{
|
||||
setCurrentIndex( index.row() );
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::onCurrentIndexChanged( int i )
|
||||
{
|
||||
QModelIndex modelIndex = mModel->index( i, 0, QModelIndex() );
|
||||
mModel->setExtraIdentifierValue( mModel->data( modelIndex, QgsFeatureFilterModel::IdentifierValueRole ) );
|
||||
mLineEdit->setText( mModel->data( modelIndex, QgsFeatureFilterModel::ValueRole ).toString() );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::restoreLineEditState()
|
||||
{
|
||||
mLineEditState.restore( mLineEdit );
|
||||
}
|
||||
|
||||
QString QgsFeatureListComboBox::identifierField() const
|
||||
{
|
||||
return mModel->identifierField();
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::setIdentifierField( const QString &identifierField )
|
||||
{
|
||||
mModel->setIdentifierField( identifierField );
|
||||
}
|
||||
|
||||
QModelIndex QgsFeatureListComboBox::currentModelIndex() const
|
||||
{
|
||||
return mModel->index( mModel->extraIdentifierValueIndex(), 0, QModelIndex() );
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::focusOutEvent( QFocusEvent *event )
|
||||
{
|
||||
Q_UNUSED( event )
|
||||
QComboBox::focusOutEvent( event );
|
||||
mLineEdit->setText( mModel->data( currentModelIndex(), QgsFeatureFilterModel::ValueRole ).toString() );
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::keyPressEvent( QKeyEvent *event )
|
||||
{
|
||||
if ( event->key() == Qt::Key_Escape )
|
||||
{
|
||||
mLineEdit->setText( mModel->data( currentModelIndex(), QgsFeatureFilterModel::ValueRole ).toString() );
|
||||
}
|
||||
QComboBox::keyReleaseEvent( event );
|
||||
}
|
||||
|
||||
bool QgsFeatureListComboBox::allowNull() const
|
||||
{
|
||||
return mAllowNull;
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::setAllowNull( bool allowNull )
|
||||
{
|
||||
if ( mAllowNull == allowNull )
|
||||
return;
|
||||
|
||||
mAllowNull = allowNull;
|
||||
emit allowNullChanged();
|
||||
}
|
||||
|
||||
QVariant QgsFeatureListComboBox::identifierValue() const
|
||||
{
|
||||
return mModel->extraIdentifierValue();
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::setIdentifierValue( const QVariant &identifierValue )
|
||||
{
|
||||
mModel->setExtraIdentifierValue( identifierValue );
|
||||
}
|
||||
|
||||
QgsFeatureRequest QgsFeatureListComboBox::currentFeatureRequest() const
|
||||
{
|
||||
return QgsFeatureRequest().setFilterExpression( QStringLiteral( "%1 = %2" ).arg( QgsExpression::quotedColumnRef( mModel->identifierField() ), QgsExpression::quotedValue( mModel->extraIdentifierValue() ) ) );
|
||||
}
|
||||
|
||||
QString QgsFeatureListComboBox::filterExpression() const
|
||||
{
|
||||
return mModel->filterExpression();
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::setFilterExpression( const QString &filterExpression )
|
||||
{
|
||||
mModel->setFilterExpression( filterExpression );
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::LineEditState::store( QLineEdit *lineEdit )
|
||||
{
|
||||
text = lineEdit->text();
|
||||
selectionStart = lineEdit->selectionStart();
|
||||
selectionLength = lineEdit->selectedText().length();
|
||||
cursorPosition = lineEdit->cursorPosition();
|
||||
|
||||
}
|
||||
|
||||
void QgsFeatureListComboBox::LineEditState::restore( QLineEdit *lineEdit ) const
|
||||
{
|
||||
lineEdit->setText( text );
|
||||
lineEdit->setCursorPosition( cursorPosition );
|
||||
lineEdit->setSelection( selectionStart, selectionLength );
|
||||
}
|
110
src/gui/qgsfeaturelistcombobox.h
Normal file
110
src/gui/qgsfeaturelistcombobox.h
Normal file
@ -0,0 +1,110 @@
|
||||
/***************************************************************************
|
||||
qgsfieldlistcombobox.h - QgsFieldListComboBox
|
||||
|
||||
---------------------
|
||||
begin : 10.3.2017
|
||||
copyright : (C) 2017 by Matthias Kuhn
|
||||
email : matthias@opengis.ch
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSFIELDLISTCOMBOBOX_H
|
||||
#define QGSFIELDLISTCOMBOBOX_H
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsfeaturerequest.h"
|
||||
#include "qgis_gui.h"
|
||||
|
||||
class QgsVectorLayer;
|
||||
class QgsFeatureFilterModel;
|
||||
class QgsAnimatedIcon;
|
||||
class QgsFilterLineEdit;
|
||||
|
||||
class GUI_EXPORT QgsFeatureListComboBox : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( QgsVectorLayer *sourceLayer READ sourceLayer WRITE setSourceLayer NOTIFY sourceLayerChanged )
|
||||
Q_PROPERTY( QString displayExpression READ displayExpression WRITE setDisplayExpression NOTIFY displayExpressionChanged )
|
||||
Q_PROPERTY( QString filterExpression READ filterExpression WRITE setFilterExpression NOTIFY filterExpressionChanged )
|
||||
Q_PROPERTY( QVariant identifierValue READ identifierValue WRITE setIdentifierValue NOTIFY identifierValueChanged )
|
||||
Q_PROPERTY( QString identifierField READ identifierField WRITE setIdentifierField NOTIFY identifierFieldChanged )
|
||||
Q_PROPERTY( bool allowNull READ allowNull WRITE setAllowNull NOTIFY allowNullChanged )
|
||||
|
||||
public:
|
||||
QgsFeatureListComboBox( QWidget *parent = nullptr );
|
||||
|
||||
QgsVectorLayer *sourceLayer() const;
|
||||
void setSourceLayer( QgsVectorLayer *sourceLayer );
|
||||
|
||||
QString displayExpression() const;
|
||||
void setDisplayExpression( const QString &displayExpression );
|
||||
|
||||
QString filterExpression() const;
|
||||
void setFilterExpression( const QString &filterExpression );
|
||||
|
||||
QVariant identifierValue() const;
|
||||
void setIdentifierValue( const QVariant &identifierValue );
|
||||
|
||||
QgsFeatureRequest currentFeatureRequest() const;
|
||||
|
||||
bool allowNull() const;
|
||||
void setAllowNull( bool allowNull );
|
||||
|
||||
QString identifierField() const;
|
||||
void setIdentifierField( const QString &identifierField );
|
||||
|
||||
QModelIndex currentModelIndex() const;
|
||||
|
||||
virtual void focusOutEvent( QFocusEvent *event ) override;
|
||||
|
||||
virtual void keyPressEvent( QKeyEvent *event ) override;
|
||||
|
||||
signals:
|
||||
void sourceLayerChanged();
|
||||
void displayExpressionChanged();
|
||||
void filterExpressionChanged();
|
||||
void identifierValueChanged();
|
||||
void identifierFieldChanged();
|
||||
void allowNullChanged();
|
||||
|
||||
private slots:
|
||||
void onCurrentTextChanged( const QString &text );
|
||||
void onFilterUpdateCompleted();
|
||||
void onLoadingChanged();
|
||||
void onItemSelected( const QModelIndex &index );
|
||||
void onCurrentIndexChanged( int i );
|
||||
void onActivated( QModelIndex index );
|
||||
void storeLineEditState();
|
||||
void restoreLineEditState();
|
||||
|
||||
private:
|
||||
struct LineEditState
|
||||
{
|
||||
void store( QLineEdit *lineEdit );
|
||||
void restore( QLineEdit *lineEdit ) const;
|
||||
|
||||
QString text;
|
||||
int selectionStart;
|
||||
int selectionLength;
|
||||
int cursorPosition;
|
||||
};
|
||||
|
||||
QgsFeatureFilterModel *mModel;
|
||||
QCompleter *mCompleter;
|
||||
QString mDisplayExpression;
|
||||
QgsFilterLineEdit *mLineEdit;
|
||||
bool mAllowNull = true;
|
||||
bool mPopupRequested = false;
|
||||
bool mIsCurrentlyEdited = false;
|
||||
LineEditState mLineEditState;
|
||||
};
|
||||
|
||||
#endif // QGSFIELDLISTCOMBOBOX_H
|
19
src/gui/qgsfeaturelistcombobox_p.h
Normal file
19
src/gui/qgsfeaturelistcombobox_p.h
Normal file
@ -0,0 +1,19 @@
|
||||
/***************************************************************************
|
||||
qgsfeaturelistcombobox_p.h
|
||||
|
||||
---------------------
|
||||
begin : 24.10.2017
|
||||
copyright : (C) 2017 by Matthias Kuhn
|
||||
email : matthias@opengis.ch
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSFEATURELISTCOMBOBOX_P_H
|
||||
#define QGSFEATURELISTCOMBOBOX_P_H
|
||||
|
||||
#endif // QGSFEATURELISTCOMBOBOX_P_H
|
Loading…
x
Reference in New Issue
Block a user