Skip to content

Commit ade6b60

Browse files
authored
Merge pull request #5688 from m-kuhn/fix17496
Relation reference widget: apply conditional styles
2 parents 880af67 + a374ebe commit ade6b60

7 files changed

+130
-45
lines changed

python/core/expression/qgsexpression.sip

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ Implicit sharing was added in 2.14
9898
%End
9999

100100

101+
101102
QgsExpression();
102103
%Docstring
103104
Create an empty expression.

src/core/expression/qgsexpression.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ QgsExpression &QgsExpression::operator=( const QgsExpression &other )
218218
return *this;
219219
}
220220

221+
QgsExpression::operator QString() const
222+
{
223+
return d->mExp;
224+
}
225+
221226
QgsExpression::QgsExpression()
222227
: d( new QgsExpressionPrivate )
223228
{

src/core/expression/qgsexpression.h

+7
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,13 @@ class CORE_EXPORT QgsExpression
137137
*/
138138
QgsExpression &operator=( const QgsExpression &other );
139139

140+
/**
141+
* Automatically convert this expression to a string where requested.
142+
*
143+
* \since QGIS 3.0
144+
*/
145+
operator QString() const SIP_SKIP;
146+
140147
/**
141148
* Create an empty expression.
142149
*

src/core/qgsfeaturefiltermodel.cpp

+106-18
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "qgsfeaturefiltermodel.h"
1717
#include "qgsfeaturefiltermodel_p.h"
1818

19+
#include "qgsconditionalstyle.h"
20+
1921
QgsFeatureFilterModel::QgsFeatureFilterModel( QObject *parent )
2022
: QAbstractItemModel( parent )
2123
{
@@ -42,21 +44,22 @@ void QgsFeatureFilterModel::setSourceLayer( QgsVectorLayer *sourceLayer )
4244
return;
4345

4446
mSourceLayer = sourceLayer;
47+
mExpressionContext = sourceLayer->createExpressionContext();
4548
reload();
4649
emit sourceLayerChanged();
4750
}
4851

4952
QString QgsFeatureFilterModel::displayExpression() const
5053
{
51-
return mDisplayExpression;
54+
return mDisplayExpression.expression();
5255
}
5356

5457
void QgsFeatureFilterModel::setDisplayExpression( const QString &displayExpression )
5558
{
56-
if ( mDisplayExpression == displayExpression )
59+
if ( mDisplayExpression.expression() == displayExpression )
5760
return;
5861

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

139-
case Qt::ForegroundRole:
142+
case Qt::BackgroundColorRole:
143+
FALLTHROUGH;
144+
case Qt::TextColorRole:
145+
FALLTHROUGH;
146+
case Qt::FontRole:
147+
{
140148
if ( mEntries.value( index.row() ).identifierValue.isNull() )
141149
{
142-
return QBrush( QColor( Qt::gray ) );
150+
// Representation for NULL value
151+
if ( role == Qt::TextColorRole )
152+
{
153+
return QBrush( QColor( Qt::gray ) );
154+
}
155+
else if ( role == Qt::FontRole )
156+
{
157+
QFont font = QFont();
158+
if ( index.row() == mExtraIdentifierValueIndex )
159+
font.setBold( true );
160+
161+
if ( mEntries.value( index.row() ).identifierValue.isNull() )
162+
{
163+
font.setItalic( true );
164+
}
165+
return font;
166+
}
143167
}
144-
break;
145-
146-
case Qt::FontRole:
147-
QFont font = QFont();
148-
if ( index.row() == mExtraIdentifierValueIndex )
149-
font.setBold( true );
150-
151-
if ( mEntries.value( index.row() ).identifierValue.isNull() )
168+
else
152169
{
153-
font.setItalic( true );
170+
// Respect conditional style
171+
const QgsConditionalStyle style = featureStyle( mEntries.value( index.row() ).feature );
172+
173+
if ( style.isValid() )
174+
{
175+
if ( role == Qt::BackgroundColorRole && style.validBackgroundColor() )
176+
return style.backgroundColor();
177+
if ( role == Qt::TextColorRole && style.validTextColor() )
178+
return style.textColor();
179+
if ( role == Qt::DecorationRole )
180+
return style.icon();
181+
if ( role == Qt::FontRole )
182+
return style.font();
183+
}
154184
}
155-
return font;
156185
break;
186+
}
157187
}
158188

159189
return QVariant();
@@ -193,7 +223,7 @@ void QgsFeatureFilterModel::updateCompleter()
193223
std::sort( entries.begin(), entries.end(), []( const Entry & a, const Entry & b ) { return a.value.localeAwareCompare( b.value ) < 0; } );
194224

195225
if ( mAllowNull )
196-
entries.prepend( Entry( QVariant( QVariant::Int ), tr( "NULL" ) ) );
226+
entries.prepend( Entry( QVariant( QVariant::Int ), tr( "NULL" ), QgsFeature() ) );
197227

198228
const int newEntriesSize = entries.size();
199229

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

373+
QSet<QString> QgsFeatureFilterModel::requestedAttributes() const
374+
{
375+
QSet<QString> requestedAttrs;
376+
377+
const auto rowStyles = mSourceLayer->conditionalStyles()->rowStyles();
378+
379+
for ( const QgsConditionalStyle &style : rowStyles )
380+
{
381+
QgsExpression exp( style.rule() );
382+
requestedAttrs += exp.referencedColumns();
383+
}
384+
385+
if ( mDisplayExpression.isField() )
386+
{
387+
QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
388+
Q_FOREACH ( const QgsConditionalStyle &style, mSourceLayer->conditionalStyles()->fieldStyles( fieldName ) )
389+
{
390+
QgsExpression exp( style.rule() );
391+
requestedAttrs += exp.referencedColumns();
392+
}
393+
}
394+
395+
return requestedAttrs;
396+
}
397+
343398
void QgsFeatureFilterModel::setExtraIdentifierValueIndex( int index )
344399
{
345400
if ( mExtraIdentifierValueIndex == index )
@@ -376,16 +431,49 @@ void QgsFeatureFilterModel::setExtraIdentifierValueUnguarded( const QVariant &ex
376431
{
377432
beginInsertRows( QModelIndex(), 0, 0 );
378433
if ( extraIdentifierValue.isNull() )
379-
mEntries.prepend( Entry( QVariant( QVariant::Int ), QStringLiteral( "%1" ).arg( tr( "NULL" ) ) ) );
434+
mEntries.prepend( Entry( QVariant( QVariant::Int ), QStringLiteral( "%1" ).arg( tr( "NULL" ) ), QgsFeature() ) );
380435
else
381-
mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral( "(%1)" ).arg( extraIdentifierValue.toString() ) ) );
436+
mEntries.prepend( Entry( extraIdentifierValue, QStringLiteral( "(%1)" ).arg( extraIdentifierValue.toString() ), QgsFeature() ) );
382437
endInsertRows();
383438
setExtraIdentifierValueIndex( 0 );
384439

385440
reloadCurrentFeature();
386441
}
387442
}
388443

444+
QgsConditionalStyle QgsFeatureFilterModel::featureStyle( const QgsFeature &feature ) const
445+
{
446+
if ( !mSourceLayer )
447+
return QgsConditionalStyle();
448+
449+
QgsVectorLayer *layer = mSourceLayer;
450+
QgsFeatureId fid = feature.id();
451+
mExpressionContext.setFeature( feature );
452+
QgsConditionalStyle style;
453+
454+
if ( mEntryStylesMap.contains( fid ) )
455+
{
456+
style = mEntryStylesMap.value( fid );
457+
}
458+
459+
auto styles = QgsConditionalStyle::matchingConditionalStyles( layer->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
460+
461+
if ( mDisplayExpression.isField() )
462+
{
463+
// Style specific for this field
464+
QString fieldName = *mDisplayExpression.referencedColumns().constBegin();
465+
const auto allStyles = layer->conditionalStyles()->fieldStyles( fieldName );
466+
const auto matchingFieldStyles = QgsConditionalStyle::matchingConditionalStyles( allStyles, feature.attribute( fieldName ), mExpressionContext );
467+
468+
styles += matchingFieldStyles;
469+
470+
style = QgsConditionalStyle::compressStyles( styles );
471+
mEntryStylesMap.insert( fid, style );
472+
}
473+
474+
return style;
475+
}
476+
389477
bool QgsFeatureFilterModel::allowNull() const
390478
{
391479
return mAllowNull;

src/core/qgsfeaturefiltermodel.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <QAbstractItemModel>
2020

2121
#include "qgsvectorlayer.h"
22+
#include "qgsconditionalstyle.h"
2223

2324
class QgsFieldExpressionValuesGatherer;
2425

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

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

271-
Entry( QVariant _identifierValue, const QString &_value )
273+
Entry( QVariant _identifierValue, const QString &_value, const QgsFeature &_feature )
272274
: identifierValue( _identifierValue )
273275
, value( _value )
276+
, feature( _feature )
274277
{}
275278

276279
QVariant identifierValue;
277280
QString value;
281+
QgsFeature feature;
278282

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

286+
QgsConditionalStyle featureStyle( const QgsFeature &feature ) const;
287+
282288
QgsVectorLayer *mSourceLayer = nullptr;
283-
QString mDisplayExpression;
289+
QgsExpression mDisplayExpression;
284290
QString mFilterValue;
285291
QString mFilterExpression;
286292

293+
mutable QgsExpressionContext mExpressionContext;
294+
mutable QMap< QgsFeatureId, QgsConditionalStyle > mEntryStylesMap;
287295
QVector<Entry> mEntries;
288296
QgsFieldExpressionValuesGatherer *mGatherer = nullptr;
289297
QTimer mReloadTimer;

src/core/qgsfeaturefiltermodel_p.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class QgsFieldExpressionValuesGatherer: public QThread
6060
while ( mIterator.nextFeature( feat ) )
6161
{
6262
mExpressionContext.setFeature( feat );
63-
mEntries.append( QgsFeatureFilterModel::Entry( feat.attribute( attribute ), mDisplayExpression.evaluate( &mExpressionContext ).toString() ) );
63+
mEntries.append( QgsFeatureFilterModel::Entry( feat.attribute( attribute ), mDisplayExpression.evaluate( &mExpressionContext ).toString(), feat ) );
6464

6565
if ( mWasCanceled )
6666
return;

src/gui/editorwidgets/qgsrelationreferencewidget.cpp

-24
Original file line numberDiff line numberDiff line change
@@ -501,30 +501,6 @@ void QgsRelationReferenceWidget::init()
501501
mFilterContainer->hide();
502502
}
503503

504-
QgsExpression displayExpression( mReferencedLayer->displayExpression() );
505-
506-
requestedAttrs += displayExpression.referencedColumns();
507-
requestedAttrs << mRelation.fieldPairs().at( 0 ).second;
508-
509-
Q_FOREACH ( const QgsConditionalStyle &style, mReferencedLayer->conditionalStyles()->rowStyles() )
510-
{
511-
QgsExpression exp( style.rule() );
512-
requestedAttrs += exp.referencedColumns();
513-
}
514-
515-
if ( displayExpression.isField() )
516-
{
517-
Q_FOREACH ( const QgsConditionalStyle &style, mReferencedLayer->conditionalStyles()->fieldStyles( *displayExpression.referencedColumns().constBegin() ) )
518-
{
519-
QgsExpression exp( style.rule() );
520-
requestedAttrs += exp.referencedColumns();
521-
}
522-
}
523-
524-
QgsAttributeList attributes;
525-
Q_FOREACH ( const QString &attr, requestedAttrs )
526-
attributes << mReferencedLayer->fields().lookupField( attr );
527-
528504
mComboBox->setSourceLayer( mReferencedLayer );
529505
mComboBox->setDisplayExpression( mReferencedLayer->displayExpression() );
530506
mComboBox->setAllowNull( mAllowNull );

0 commit comments

Comments
 (0)