Skip to content

Commit

Permalink
Make QgsRelationReferenceWidget background threaded
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Oct 26, 2017
1 parent e903017 commit 5c32db9
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 121 deletions.
143 changes: 41 additions & 102 deletions src/gui/editorwidgets/qgsrelationreferencewidget.cpp
Expand Up @@ -39,22 +39,10 @@
#include "qgsattributetablemodel.h"
#include "qgsmaptoolidentifyfeature.h"
#include "qgsfeatureiterator.h"
#include "qgsfeaturelistcombobox.h"

QgsRelationReferenceWidget::QgsRelationReferenceWidget( QWidget *parent )
: QWidget( parent )
, mEditorContext( QgsAttributeEditorContext() )
, mReferencedFieldIdx( -1 )
, mReferencingFieldIdx( -1 )
, mAllowNull( true )
, mShown( false )
, mIsEditable( true )
, mEmbedForm( false )
, mReadOnlySelector( false )
, mAllowMapIdentification( false )
, mOrderByValue( false )
, mOpenFormButtonVisible( true )
, mChainFilters( false )
, mAllowAddFeatures( false )
{
mTopLayout = new QVBoxLayout( this );
mTopLayout->setContentsMargins( 0, 0, 0, 0 );
Expand All @@ -79,8 +67,7 @@ QgsRelationReferenceWidget::QgsRelationReferenceWidget( QWidget *parent )
mChooserContainer->setLayout( chooserLayout );
chooserLayout->addWidget( mFilterContainer );

// combobox (for non-geometric relation)
mComboBox = new QComboBox();
mComboBox = new QgsFeatureListComboBox();
mChooserContainer->layout()->addWidget( mComboBox );

// read-only line edit
Expand Down Expand Up @@ -180,6 +167,10 @@ void QgsRelationReferenceWidget::setRelation( const QgsRelation &relation, bool
mReferencingLayer = relation.referencingLayer();
mRelationName = relation.name();
mReferencedLayer = relation.referencedLayer();
mReferencedField = relation.fieldPairs().at( 0 ).second;
if ( mComboBox )
mComboBox->setIdentifierField( mReferencedField );

mReferencedFieldIdx = mReferencedLayer->fields().lookupField( relation.fieldPairs().at( 0 ).second );
mReferencingFieldIdx = mReferencingLayer->fields().lookupField( relation.fieldPairs().at( 0 ).first );
mAttributeEditorFrame->setObjectName( QStringLiteral( "referencing/" ) + relation.name() );
Expand Down Expand Up @@ -236,24 +227,24 @@ void QgsRelationReferenceWidget::setForeignKey( const QVariant &value )
if ( !mReferencedLayer )
return;

// Attributes from the referencing layer
QgsAttributes attrs = QgsAttributes( mReferencingLayer->fields().count() );
// Set the value on the foreign key field of the referencing record
attrs[ mReferencingLayer->fields().lookupField( mRelation.fieldPairs().at( 0 ).first )] = value;
if ( mReadOnlySelector )
{
// Attributes from the referencing layer
QgsAttributes attrs = QgsAttributes( mReferencingLayer->fields().count() );
// Set the value on the foreign key field of the referencing record
attrs[ mReferencingLayer->fields().lookupField( mRelation.fieldPairs().at( 0 ).first )] = value;

QgsFeatureRequest request = mRelation.getReferencedFeatureRequest( attrs );
QgsFeatureRequest request = mRelation.getReferencedFeatureRequest( attrs );

mReferencedLayer->getFeatures( request ).nextFeature( mFeature );
mReferencedLayer->getFeatures( request ).nextFeature( mFeature );

if ( !mFeature.isValid() )
{
return;
}
if ( !mFeature.isValid() )
{
return;
}

mForeignKey = mFeature.attribute( mReferencedFieldIdx );
mForeignKey = mFeature.attribute( mReferencedFieldIdx );

if ( mReadOnlySelector )
{
QgsExpression expr( mReferencedLayer->displayExpression() );
QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( mReferencedLayer ) );
context.setFeature( mFeature );
Expand All @@ -266,41 +257,17 @@ void QgsRelationReferenceWidget::setForeignKey( const QVariant &value )
}
else
{
QVariant nullValue = QgsApplication::nullRepresentation();

if ( mChainFilters && mFeature.isValid() && mFilterComboBoxes.count() >= mFilterFields.count() )
{
QgsFeature feature = mFeature;

for ( int i = 0; i < mFilterFields.size(); i++ )
{
QVariant v = feature.attribute( mFilterFields[i] );
QString f = v.isNull() ? nullValue.toString() : v.toString();
mFilterComboBoxes.at( i )->setCurrentIndex( mFilterComboBoxes.at( i )->findText( f ) );
}
}

int i = mComboBox->findData( mFeature.id(), QgsAttributeTableModel::FeatureIdRole );
if ( i == -1 && mAllowNull )
{
mComboBox->setCurrentIndex( 0 );
}
else
{
mComboBox->setCurrentIndex( i );
}
mComboBox->setIdentifierValue( value );
}

mRemoveFKButton->setEnabled( mIsEditable );
highlightFeature( mFeature );
highlightFeature( mFeature ); // TODO : make this async
updateAttributeEditorFrame( mFeature );
emit foreignKeyChanged( foreignKey() );
}

void QgsRelationReferenceWidget::deleteForeignKey()
{
QVariant nullValue = QgsApplication::nullRepresentation();

// deactivate filter comboboxes
if ( mChainFilters && !mFilterComboBoxes.isEmpty() )
{
Expand All @@ -311,25 +278,20 @@ void QgsRelationReferenceWidget::deleteForeignKey()

if ( mReadOnlySelector )
{
const QString nullValue = QgsApplication::nullRepresentation();

QString nullText;
if ( mAllowNull )
{
nullText = tr( "%1 (no selection)" ).arg( nullValue.toString() );
nullText = tr( "%1 (no selection)" ).arg( nullValue );
}
mLineEdit->setText( nullText );
mForeignKey = QVariant();
mFeature.setValid( false );
}
else
{
if ( mAllowNull )
{
mComboBox->setCurrentIndex( 0 );
}
else
{
mComboBox->setCurrentIndex( -1 );
}
mComboBox->setIdentifierValue( QVariant() );
}
mRemoveFKButton->setEnabled( false );
updateAttributeEditorFrame( QgsFeature() );
Expand All @@ -341,16 +303,16 @@ QgsFeature QgsRelationReferenceWidget::referencedFeature() const
QgsFeature f;
if ( mReferencedLayer )
{
QgsFeatureId fid;
QgsFeatureRequest request;
if ( mReadOnlySelector )
{
fid = mFeature.id();
request = QgsFeatureRequest().setFilterFid( mFeature.id() );
}
else
{
fid = mComboBox->currentData( QgsAttributeTableModel::FeatureIdRole ).value<QgsFeatureId>();
request = mComboBox->currentFeatureRequest();
}
mReferencedLayer->getFeatures( QgsFeatureRequest().setFilterFid( fid ) ).nextFeature( f );
mReferencedLayer->getFeatures( request ).nextFeature( f );
}
return f;
}
Expand All @@ -363,7 +325,7 @@ void QgsRelationReferenceWidget::showIndeterminateState()
}
else
{
whileBlocking( mComboBox )->setCurrentIndex( -1 );
whileBlocking( mComboBox )->setIdentifierValue( QVariant() );
}
mRemoveFKButton->setEnabled( false );
updateAttributeEditorFrame( QgsFeature() );
Expand Down Expand Up @@ -463,14 +425,12 @@ void QgsRelationReferenceWidget::showEvent( QShowEvent *e )

void QgsRelationReferenceWidget::init()
{
if ( !mReadOnlySelector && mComboBox->count() == 0 && mReferencedLayer )
if ( !mReadOnlySelector && mReferencedLayer )
{
QApplication::setOverrideCursor( Qt::WaitCursor );

QSet<QString> requestedAttrs;

QgsVectorLayerCache *layerCache = new QgsVectorLayerCache( mReferencedLayer, 100000, this );

if ( !mFilterFields.isEmpty() )
{
Q_FOREACH ( const QString &fieldName, mFilterFields )
Expand Down Expand Up @@ -508,7 +468,7 @@ void QgsRelationReferenceWidget::init()
QVariant nullValue = QgsApplication::nullRepresentation();

QgsFeature ft;
QgsFeatureIterator fit = layerCache->getFeatures();
QgsFeatureIterator fit = mReferencedLayer->getFeatures();
while ( fit.nextFeature( ft ) )
{
for ( int i = 0; i < mFilterComboBoxes.count() - 1; ++i )
Expand Down Expand Up @@ -558,30 +518,10 @@ void QgsRelationReferenceWidget::init()
Q_FOREACH ( const QString &attr, requestedAttrs )
attributes << mReferencedLayer->fields().lookupField( attr );

layerCache->setCacheSubsetOfAttributes( attributes );
mMasterModel = new QgsAttributeTableModel( layerCache, this );
mMasterModel->setRequest( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( requestedAttrs, mReferencedLayer->fields() ) );
mFilterModel = new QgsAttributeTableFilterModel( mCanvas, mMasterModel, mMasterModel );
mFeatureListModel = new QgsFeatureListModel( mFilterModel, this );
mFeatureListModel->setDisplayExpression( mReferencedLayer->displayExpression() );

mMasterModel->loadLayer();

mFeatureListModel->setInjectNull( mAllowNull );
if ( mOrderByValue )
{
mFilterModel->sort( mReferencedLayer->displayExpression() );
}

mComboBox->setModel( mFeatureListModel );

delete mComboBox->completer();
QCompleter *completer = new QCompleter( mComboBox->model(), mComboBox );
completer->setModel( mComboBox->model() );
completer->setFilterMode( Qt::MatchContains );
completer->setCaseSensitivity( Qt::CaseInsensitive );
mComboBox->setCompleter( completer );

mComboBox->setSourceLayer( mReferencedLayer );
mComboBox->setDisplayExpression( mReferencedLayer->displayExpression() );
mComboBox->setAllowNull( mAllowNull );
mComboBox->setIdentifierField( mReferencedField );

QVariant nullValue = QgsApplication::nullRepresentation();

Expand All @@ -595,9 +535,6 @@ void QgsRelationReferenceWidget::init()
}
}

QVariant featId = mFeature.isValid() ? mFeature.id() : QVariant( QVariant::Int );
mComboBox->setCurrentIndex( mComboBox->findData( featId, QgsAttributeTableModel::FeatureIdRole ) );

// Only connect after iterating, to have only one iterator on the referenced table at once
connect( mComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRelationReferenceWidget::comboReferenceChanged );
updateAttributeEditorFrame( mFeature );
Expand Down Expand Up @@ -889,6 +826,7 @@ void QgsRelationReferenceWidget::filterChanged()
QStringList texts;
Q_FOREACH ( const QString &txt, mFilterCache[ccb->property( "Field" ).toString()][ccb->currentText()] )
{
#if 0
QMap<QString, QString> filtersAttrs = filters;
filtersAttrs[fieldName] = QgsExpression::createFieldEqualityExpression( fieldName, txt );
QString expression = filtersAttrs.values().join( QStringLiteral( " AND " ) );
Expand All @@ -909,6 +847,7 @@ void QgsRelationReferenceWidget::filterChanged()

// item is only provided if at least 1 feature exists
if ( found )
#endif
texts << txt;
}

Expand All @@ -922,7 +861,7 @@ void QgsRelationReferenceWidget::filterChanged()
}
}
}

#if 0
if ( !mChainFilters || ( mChainFilters && !filtered ) )
{
filterExpression = filters.values().join( QStringLiteral( " AND " ) );
Expand All @@ -940,6 +879,7 @@ void QgsRelationReferenceWidget::filterChanged()
}

mFilterModel->setFilteredFeatures( featureIds );
#endif
}

void QgsRelationReferenceWidget::addEntry()
Expand All @@ -960,8 +900,7 @@ void QgsRelationReferenceWidget::addEntry()

if ( mEditorContext.vectorLayerTools()->addFeature( mReferencedLayer, attributes, QgsGeometry(), &f ) )
{
int i = mComboBox->findData( f.id(), QgsAttributeTableModel::FeatureIdRole );
mComboBox->setCurrentIndex( i );
mComboBox->setIdentifierValue( f.attribute( mReferencingFieldIdx ) );
mAddEntryButton->setEnabled( false );
}
}
Expand Down
34 changes: 15 additions & 19 deletions src/gui/editorwidgets/qgsrelationreferencewidget.h
Expand Up @@ -34,9 +34,7 @@ class QgsMessageBar;
class QgsHighlight;
class QgsMapToolIdentifyFeature;
class QgsMessageBarItem;
class QgsAttributeTableModel;
class QgsAttributeTableFilterModel;
class QgsFeatureListModel;
class QgsFeatureListComboBox;
class QgsCollapsibleGroupBox;
class QLabel;

Expand Down Expand Up @@ -198,35 +196,34 @@ class GUI_EXPORT QgsRelationReferenceWidget : public QWidget
QVariant mForeignKey;
QgsFeature mFeature;
// Index of the referenced layer key
int mReferencedFieldIdx;
int mReferencingFieldIdx;
bool mAllowNull;
int mReferencedFieldIdx = -1;
QString mReferencedField;
int mReferencingFieldIdx = -1;
bool mAllowNull = true;
QgsHighlight *mHighlight = nullptr;
QgsMapToolIdentifyFeature *mMapTool = nullptr;
QgsMessageBarItem *mMessageBarItem = nullptr;
QString mRelationName;
QgsAttributeForm *mReferencedAttributeForm = nullptr;
QgsVectorLayer *mReferencedLayer = nullptr;
QgsVectorLayer *mReferencingLayer = nullptr;
QgsAttributeTableModel *mMasterModel = nullptr;
QgsAttributeTableFilterModel *mFilterModel = nullptr;
QgsFeatureListModel *mFeatureListModel = nullptr;
QgsFeatureListComboBox *mComboBox = nullptr;
QList<QComboBox *> mFilterComboBoxes;
QWidget *mWindowWidget = nullptr;
bool mShown;
bool mShown = false;
QgsRelation mRelation;
bool mIsEditable;
bool mIsEditable = true;
QStringList mFilterFields;
QMap<QString, QMap<QString, QSet<QString> > > mFilterCache;

// Q_PROPERTY
bool mEmbedForm;
bool mReadOnlySelector;
bool mAllowMapIdentification;
bool mOrderByValue;
bool mOpenFormButtonVisible;
bool mChainFilters;
bool mAllowAddFeatures;
bool mEmbedForm = false;
bool mReadOnlySelector = false;
bool mAllowMapIdentification = false;
bool mOrderByValue = false;
bool mOpenFormButtonVisible = true;
bool mChainFilters = false;
bool mAllowAddFeatures = false;

// UI
QVBoxLayout *mTopLayout = nullptr;
Expand All @@ -238,7 +235,6 @@ class GUI_EXPORT QgsRelationReferenceWidget : public QWidget
QAction *mHighlightFeatureAction = nullptr;
QAction *mScaleHighlightFeatureAction = nullptr;
QAction *mPanHighlightFeatureAction = nullptr;
QComboBox *mComboBox = nullptr;
QWidget *mChooserContainer = nullptr;
QWidget *mFilterContainer = nullptr;
QHBoxLayout *mFilterLayout = nullptr;
Expand Down

0 comments on commit 5c32db9

Please sign in to comment.