Skip to content
Permalink
Browse files

Merge pull request #5688 from m-kuhn/fix17496

Relation reference widget: apply conditional styles
  • Loading branch information
m-kuhn committed Nov 22, 2017
2 parents 880af67 + a374ebe commit ade6b60955fc9a98c97fb74794cf66d4af956804
@@ -98,6 +98,7 @@ Implicit sharing was added in 2.14
%End



QgsExpression();
%Docstring
Create an empty expression.
@@ -218,6 +218,11 @@ QgsExpression &QgsExpression::operator=( const QgsExpression &other )
return *this;
}

QgsExpression::operator QString() const
{
return d->mExp;
}

QgsExpression::QgsExpression()
: d( new QgsExpressionPrivate )
{
@@ -137,6 +137,13 @@ class CORE_EXPORT QgsExpression
*/
QgsExpression &operator=( const QgsExpression &other );

/**
* Automatically convert this expression to a string where requested.
*
* \since QGIS 3.0
*/
operator QString() const SIP_SKIP;

/**
* Create an empty expression.
*
@@ -16,6 +16,8 @@
#include "qgsfeaturefiltermodel.h"
#include "qgsfeaturefiltermodel_p.h"

#include "qgsconditionalstyle.h"

QgsFeatureFilterModel::QgsFeatureFilterModel( QObject *parent )
: QAbstractItemModel( parent )
{
@@ -42,21 +44,22 @@ void QgsFeatureFilterModel::setSourceLayer( QgsVectorLayer *sourceLayer )
return;

mSourceLayer = sourceLayer;
mExpressionContext = sourceLayer->createExpressionContext();
reload();
emit sourceLayerChanged();
}

QString QgsFeatureFilterModel::displayExpression() const
{
return mDisplayExpression;
return mDisplayExpression.expression();
}

void QgsFeatureFilterModel::setDisplayExpression( const QString &displayExpression )
{
if ( mDisplayExpression == displayExpression )
if ( mDisplayExpression.expression() == displayExpression )
return;

mDisplayExpression = displayExpression;
mDisplayExpression = QgsExpression( displayExpression );
reload();
emit displayExpressionChanged();
}
@@ -136,24 +139,51 @@ QVariant QgsFeatureFilterModel::data( const QModelIndex &index, int role ) const
case IdentifierValueRole:
return mEntries.value( index.row() ).identifierValue;

case Qt::ForegroundRole:
case Qt::BackgroundColorRole:
FALLTHROUGH;
case Qt::TextColorRole:
FALLTHROUGH;
case Qt::FontRole:
{
if ( mEntries.value( index.row() ).identifierValue.isNull() )
{
return QBrush( QColor( Qt::gray ) );
// Representation for NULL value
if ( role == Qt::TextColorRole )
{
return QBrush( QColor( Qt::gray ) );
}
else if ( role == Qt::FontRole )
{
QFont font = QFont();
if ( index.row() == mExtraIdentifierValueIndex )
font.setBold( true );

if ( mEntries.value( index.row() ).identifierValue.isNull() )
{
font.setItalic( true );
}
return font;
}
}
break;

case Qt::FontRole:
QFont font = QFont();
if ( index.row() == mExtraIdentifierValueIndex )
font.setBold( true );

if ( mEntries.value( index.row() ).identifierValue.isNull() )
else
{
font.setItalic( true );
// Respect conditional style
const QgsConditionalStyle style = featureStyle( mEntries.value( index.row() ).feature );

if ( style.isValid() )
{
if ( role == Qt::BackgroundColorRole && style.validBackgroundColor() )
return style.backgroundColor();
if ( role == Qt::TextColorRole && style.validTextColor() )
return style.textColor();
if ( role == Qt::DecorationRole )
return style.icon();
if ( role == Qt::FontRole )
return style.font();
}
}
return font;
break;
}
}

return QVariant();
@@ -193,7 +223,7 @@ void QgsFeatureFilterModel::updateCompleter()
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" ) ) );
entries.prepend( Entry( QVariant( QVariant::Int ), tr( "NULL" ), QgsFeature() ) );

const int newEntriesSize = entries.size();

@@ -340,6 +370,31 @@ void QgsFeatureFilterModel::scheduledReload()
emit isLoadingChanged();
}

QSet<QString> QgsFeatureFilterModel::requestedAttributes() const
{
QSet<QString> requestedAttrs;

const auto rowStyles = mSourceLayer->conditionalStyles()->rowStyles();

for ( const QgsConditionalStyle &style : rowStyles )
{
QgsExpression exp( style.rule() );
requestedAttrs += exp.referencedColumns();
}

if ( mDisplayExpression.isField() )
{
QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
Q_FOREACH ( const QgsConditionalStyle &style, mSourceLayer->conditionalStyles()->fieldStyles( fieldName ) )
{
QgsExpression exp( style.rule() );
requestedAttrs += exp.referencedColumns();
}
}

return requestedAttrs;
}

void QgsFeatureFilterModel::setExtraIdentifierValueIndex( int index )
{
if ( mExtraIdentifierValueIndex == index )
@@ -376,16 +431,49 @@ void QgsFeatureFilterModel::setExtraIdentifierValueUnguarded( const QVariant &ex
{
beginInsertRows( QModelIndex(), 0, 0 );
if ( extraIdentifierValue.isNull() )
mEntries.prepend( Entry( QVariant( QVariant::Int ), QStringLiteral( "%1" ).arg( tr( "NULL" ) ) ) );
mEntries.prepend( Entry( QVariant( QVariant::Int ), QStringLiteral( "%1" ).arg( tr( "NULL" ) ), QgsFeature() ) );
else
mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral( "(%1)" ).arg( extraIdentifierValue.toString() ) ) );
mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral( "(%1)" ).arg( extraIdentifierValue.toString() ), QgsFeature() ) );
endInsertRows();
setExtraIdentifierValueIndex( 0 );

reloadCurrentFeature();
}
}

QgsConditionalStyle QgsFeatureFilterModel::featureStyle( const QgsFeature &feature ) const
{
if ( !mSourceLayer )
return QgsConditionalStyle();

QgsVectorLayer *layer = mSourceLayer;
QgsFeatureId fid = feature.id();
mExpressionContext.setFeature( feature );
QgsConditionalStyle style;

if ( mEntryStylesMap.contains( fid ) )
{
style = mEntryStylesMap.value( fid );
}

auto styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );

if ( mDisplayExpression.isField() )
{
// Style specific for this field
QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
const auto allStyles = layer->conditionalStyles()->fieldStyles( fieldName );
const auto matchingFieldStyles = QgsConditionalStyle::matchingConditionalStyles( allStyles, feature.attribute( fieldName ), mExpressionContext );

styles += matchingFieldStyles;

style = QgsConditionalStyle::compressStyles( styles );
mEntryStylesMap.insert( fid, style );
}

return style;
}

bool QgsFeatureFilterModel::allowNull() const
{
return mAllowNull;
@@ -19,6 +19,7 @@
#include <QAbstractItemModel>

#include "qgsvectorlayer.h"
#include "qgsconditionalstyle.h"

class QgsFieldExpressionValuesGatherer;

@@ -259,6 +260,7 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel
void scheduledReload();

private:
QSet<QString> requestedAttributes() const;
void setExtraIdentifierValueIndex( int index );
void setExtraValueDoesNotExist( bool extraValueDoesNotExist );
void reload();
@@ -268,22 +270,28 @@ class CORE_EXPORT QgsFeatureFilterModel : public QAbstractItemModel
{
Entry() = default;

Entry( QVariant _identifierValue, const QString &_value )
Entry( QVariant _identifierValue, const QString &_value, const QgsFeature &_feature )
: identifierValue( _identifierValue )
, value( _value )
, feature( _feature )
{}

QVariant identifierValue;
QString value;
QgsFeature feature;

bool operator()( const Entry &lhs, const Entry &rhs ) const;
};

QgsConditionalStyle featureStyle( const QgsFeature &feature ) const;

QgsVectorLayer *mSourceLayer = nullptr;
QString mDisplayExpression;
QgsExpression mDisplayExpression;
QString mFilterValue;
QString mFilterExpression;

mutable QgsExpressionContext mExpressionContext;
mutable QMap< QgsFeatureId, QgsConditionalStyle > mEntryStylesMap;
QVector<Entry> mEntries;
QgsFieldExpressionValuesGatherer *mGatherer = nullptr;
QTimer mReloadTimer;
@@ -60,7 +60,7 @@ class QgsFieldExpressionValuesGatherer: public QThread
while ( mIterator.nextFeature( feat ) )
{
mExpressionContext.setFeature( feat );
mEntries.append( QgsFeatureFilterModel::Entry( feat.attribute( attribute ), mDisplayExpression.evaluate( &mExpressionContext ).toString() ) );
mEntries.append( QgsFeatureFilterModel::Entry( feat.attribute( attribute ), mDisplayExpression.evaluate( &mExpressionContext ).toString(), feat ) );

if ( mWasCanceled )
return;
@@ -501,30 +501,6 @@ void QgsRelationReferenceWidget::init()
mFilterContainer->hide();
}

QgsExpression displayExpression( mReferencedLayer->displayExpression() );

requestedAttrs += displayExpression.referencedColumns();
requestedAttrs << mRelation.fieldPairs().at( 0 ).second;

Q_FOREACH ( const QgsConditionalStyle &style, mReferencedLayer->conditionalStyles()->rowStyles() )
{
QgsExpression exp( style.rule() );
requestedAttrs += exp.referencedColumns();
}

if ( displayExpression.isField() )
{
Q_FOREACH ( const QgsConditionalStyle &style, mReferencedLayer->conditionalStyles()->fieldStyles( *displayExpression.referencedColumns().constBegin() ) )
{
QgsExpression exp( style.rule() );
requestedAttrs += exp.referencedColumns();
}
}

QgsAttributeList attributes;
Q_FOREACH ( const QString &attr, requestedAttrs )
attributes << mReferencedLayer->fields().lookupField( attr );

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

0 comments on commit ade6b60

Please sign in to comment.
You can’t perform that action at this time.