Skip to content

Commit 56a0af5

Browse files
committedJul 7, 2016
Sort attribute table by representation value where useful
Fix #15096 And aligns some edge-cases of sort behavior
1 parent 31fc2b0 commit 56a0af5

12 files changed

+136
-18
lines changed
 

‎python/gui/editorwidgets/core/qgseditorwidgetfactory.sip

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,21 @@ class QgsEditorWidgetFactory
123123
*/
124124
virtual QString representValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const;
125125

126+
/**
127+
* If the default sort order should be overwritten for this widget, you can transform the value in here.
128+
*
129+
* @param vl The vector layer.
130+
* @param fieldIdx The index of the field.
131+
* @param config The editor widget config.
132+
* @param cache The editor widget cache.
133+
* @param value The value to represent.
134+
*
135+
* @return By default the value is returned unmodified.
136+
*
137+
* @note Added in 2.16
138+
*/
139+
virtual QVariant sortValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const;
140+
126141
/**
127142
* Return the alignment for a particular field. By default this will consider the field type but can be overwritten if mapped
128143
* values are represented.

‎python/gui/editorwidgets/qgsrelationreferencewidget.sip

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,24 @@ class QgsRelationReferenceWidget : QWidget
6969

7070
//! return the related feature (from the referenced layer)
7171
//! if no feature is related, it returns an invalid feature
72-
QgsFeature referencedFeature();
72+
QgsFeature referencedFeature() const;
7373

7474
/** Sets the widget to display in an indeterminate "mixed value" state.
7575
* @note added in QGIS 2.16
7676
*/
7777
void showIndeterminateState();
78+
7879
/**
7980
* Determines if a button for adding new features should be shown.
81+
*
82+
* @note added in QGIS 2.16
8083
*/
8184
bool allowAddFeatures() const;
8285

8386
/**
8487
* Determines if a button for adding new features should be shown.
88+
*
89+
* @note added in QGIS 2.16
8590
*/
8691
void setAllowAddFeatures( bool allowAddFeatures );
8792

‎src/gui/attributetable/qgsattributetablemodel.cpp

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ QgsAttributeTableModel::QgsAttributeTableModel( QgsVectorLayerCache *layerCache,
4040
, mLayerCache( layerCache )
4141
, mFieldCount( 0 )
4242
, mSortCacheExpression( "" )
43+
, mSortFieldIndex( -1 )
4344
, mExtraColumns( 0 )
4445
{
4546
mExpressionContext << QgsExpressionContextUtils::globalScope()
@@ -206,8 +207,19 @@ void QgsAttributeTableModel::featureAdded( QgsFeatureId fid )
206207

207208
if ( featOk && mFeatureRequest.acceptFeature( mFeat ) )
208209
{
209-
mExpressionContext.setFeature( mFeat );
210-
mSortCache[fid] = mSortCacheExpression.evaluate();
210+
if ( mSortFieldIndex == -1 )
211+
{
212+
mExpressionContext.setFeature( mFeat );
213+
mSortCache[mFeat.id()] = mSortCacheExpression.evaluate( &mExpressionContext );
214+
}
215+
else
216+
{
217+
QgsEditorWidgetFactory* widgetFactory = mWidgetFactories.at( mSortFieldIndex );
218+
const QVariant& widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
219+
const QgsEditorWidgetConfig& widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
220+
QVariant sortValue = widgetFactory->representValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, mFeat.attribute( mSortFieldIndex ) );
221+
mSortCache.insert( mFeat.id(), sortValue );
222+
}
211223

212224
int n = mRowIdMap.size();
213225
beginInsertRows( QModelIndex(), n, n );
@@ -257,10 +269,20 @@ void QgsAttributeTableModel::attributeValueChanged( QgsFeatureId fid, int idx, c
257269

258270
if ( mSortCacheAttributes.contains( idx ) )
259271
{
260-
// if the expression used multiple fields, this will not work but this way we don't have
261-
// to run the expensive query in the 80% cases where we just have a simple column for sorting
262-
// or it's the first used column, this works just fine
263-
mSortCache[fid] = value;
272+
if ( mSortFieldIndex == -1 )
273+
{
274+
loadFeatureAtId( fid );
275+
mExpressionContext.setFeature( mFeat );
276+
mSortCache[fid] = mSortCacheExpression.evaluate( &mExpressionContext );
277+
}
278+
else
279+
{
280+
QgsEditorWidgetFactory* widgetFactory = mWidgetFactories.at( mSortFieldIndex );
281+
const QVariant& widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
282+
const QgsEditorWidgetConfig& widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
283+
QVariant sortValue = widgetFactory->representValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, value );
284+
mSortCache.insert( fid, sortValue );
285+
}
264286
}
265287
// No filter request: skip all possibly heavy checks
266288
if ( mFeatureRequest.filterType() == QgsFeatureRequest::FilterNone )
@@ -341,6 +363,9 @@ void QgsAttributeTableModel::loadAttributes()
341363
mFieldCount = attributes.size();
342364
mAttributes = attributes;
343365

366+
if ( mSortFieldIndex >= mAttributes.count() )
367+
mSortFieldIndex = -1;
368+
344369
if ( ins )
345370
{
346371
endInsertColumns();
@@ -373,8 +398,7 @@ void QgsAttributeTableModel::loadLayer()
373398
QTime t;
374399
t.start();
375400

376-
QgsFeature feat;
377-
while ( features.nextFeature( feat ) )
401+
while ( features.nextFeature( mFeat ) )
378402
{
379403
++i;
380404

@@ -387,8 +411,7 @@ void QgsAttributeTableModel::loadLayer()
387411

388412
t.restart();
389413
}
390-
mFeat = feat;
391-
featureAdded( feat.id() );
414+
featureAdded( mFeat.id() );
392415
}
393416

394417
emit finished();
@@ -758,14 +781,35 @@ void QgsAttributeTableModel::prefetchSortData( const QString& expressionString )
758781
{
759782
mSortCache.clear();
760783
mSortCacheAttributes.clear();
761-
784+
mSortFieldIndex = -1;
762785
mSortCacheExpression = QgsExpression( expressionString );
763786

764-
mSortCacheExpression.prepare( &mExpressionContext );
787+
QgsEditorWidgetFactory* widgetFactory = nullptr;
788+
QVariant widgetCache;
789+
QgsEditorWidgetConfig widgetConfig;
765790

766-
Q_FOREACH ( const QString& col, mSortCacheExpression.referencedColumns() )
791+
if ( mSortCacheExpression.isField() )
767792
{
768-
mSortCacheAttributes.append( mLayerCache->layer()->fieldNameIndex( col ) );
793+
QString fieldName = dynamic_cast<const QgsExpression::NodeColumnRef*>( mSortCacheExpression.rootNode() )->name();
794+
mSortFieldIndex = mLayerCache->layer()->fieldNameIndex( fieldName );
795+
}
796+
797+
if ( mSortFieldIndex == -1 )
798+
{
799+
mSortCacheExpression.prepare( &mExpressionContext );
800+
801+
Q_FOREACH ( const QString& col, mSortCacheExpression.referencedColumns() )
802+
{
803+
mSortCacheAttributes.append( mLayerCache->layer()->fieldNameIndex( col ) );
804+
}
805+
}
806+
else
807+
{
808+
mSortCacheAttributes.append( mSortFieldIndex );
809+
810+
widgetFactory = mWidgetFactories.at( mSortFieldIndex );
811+
widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
812+
widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
769813
}
770814

771815
QgsFeatureRequest request = QgsFeatureRequest( mFeatureRequest )
@@ -776,8 +820,16 @@ void QgsAttributeTableModel::prefetchSortData( const QString& expressionString )
776820
QgsFeature f;
777821
while ( it.nextFeature( f ) )
778822
{
779-
mExpressionContext.setFeature( f );
780-
mSortCache.insert( f.id(), mSortCacheExpression.evaluate( &mExpressionContext ) );
823+
if ( mSortFieldIndex == -1 )
824+
{
825+
mExpressionContext.setFeature( f );
826+
mSortCache.insert( f.id(), mSortCacheExpression.evaluate( &mExpressionContext ) );
827+
}
828+
else
829+
{
830+
QVariant sortValue = widgetFactory->representValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, f.attribute( mSortFieldIndex ) );
831+
mSortCache.insert( f.id(), sortValue );
832+
}
781833
}
782834
}
783835

‎src/gui/attributetable/qgsattributetablemodel.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
218218
/**
219219
* Get the the feature request
220220
*/
221+
// TODO QGIS 3: return copy instead of reference
221222
const QgsFeatureRequest& request() const;
222223

223224
/**
@@ -350,6 +351,8 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
350351
/** The currently cached column */
351352
QgsExpression mSortCacheExpression;
352353
QgsAttributeList mSortCacheAttributes;
354+
/** If it is set, a simple field is used for sorting, if it's -1 it's the mSortCacheExpression*/
355+
int mSortFieldIndex;
353356
/** Allows caching of one value per column (used for sorting) */
354357
QHash<QgsFeatureId, QVariant> mSortCache;
355358

‎src/gui/editorwidgets/core/qgseditorwidgetfactory.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ QString QgsEditorWidgetFactory::representValue( QgsVectorLayer* vl, int fieldIdx
7575
return value == defVal ? defVal : vl->fields().at( fieldIdx ).displayString( value );
7676
}
7777

78+
QVariant QgsEditorWidgetFactory::sortValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const
79+
{
80+
Q_UNUSED( vl )
81+
Q_UNUSED( fieldIdx )
82+
Q_UNUSED( config )
83+
Q_UNUSED( cache )
84+
return value;
85+
}
86+
7887
Qt::AlignmentFlag QgsEditorWidgetFactory::alignmentFlag( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config ) const
7988
{
8089
Q_UNUSED( config );

‎src/gui/editorwidgets/core/qgseditorwidgetfactory.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,21 @@ class GUI_EXPORT QgsEditorWidgetFactory
138138
*/
139139
virtual QString representValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const;
140140

141+
/**
142+
* If the default sort order should be overwritten for this widget, you can transform the value in here.
143+
*
144+
* @param vl The vector layer.
145+
* @param fieldIdx The index of the field.
146+
* @param config The editor widget config.
147+
* @param cache The editor widget cache.
148+
* @param value The value to represent.
149+
*
150+
* @return By default the value is returned unmodified.
151+
*
152+
* @note Added in 2.16
153+
*/
154+
virtual QVariant sortValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const;
155+
141156
/**
142157
* Return the alignment for a particular field. By default this will consider the field type but can be overwritten if mapped
143158
* values are represented.

‎src/gui/editorwidgets/qgsrelationreferencefactory.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,8 @@ QString QgsRelationReferenceFactory::representValue( QgsVectorLayer* vl, int fie
171171
}
172172
return title;
173173
}
174+
175+
QVariant QgsRelationReferenceFactory::sortValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const
176+
{
177+
return representValue( vl, fieldIdx, config, cache, value );
178+
}

‎src/gui/editorwidgets/qgsrelationreferencefactory.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ class GUI_EXPORT QgsRelationReferenceFactory : public QgsEditorWidgetFactory
8282
*/
8383
virtual void writeConfig( const QgsEditorWidgetConfig& config, QDomElement& configElement, QDomDocument& doc, const QgsVectorLayer* layer, int fieldIdx ) override;
8484

85-
QString representValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const override;
85+
virtual QString representValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const override;
86+
87+
virtual QVariant sortValue( QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config, const QVariant &cache, const QVariant &value ) const override;
8688

8789
virtual QMap<const char*, int> supportedWidgetTypes() override;
8890

‎src/gui/editorwidgets/qgsvaluemapwidgetfactory.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ QString QgsValueMapWidgetFactory::representValue( QgsVectorLayer* vl, int fieldI
8989
return config.key( value, QVariant( QString( "(%1)" ).arg( value.toString() ) ).toString() );
9090
}
9191

92+
QVariant QgsValueMapWidgetFactory::sortValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const
93+
{
94+
return representValue( vl, fieldIdx, config, cache, value );
95+
}
96+
9297
Qt::AlignmentFlag QgsValueMapWidgetFactory::alignmentFlag( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config ) const
9398
{
9499
Q_UNUSED( vl );

‎src/gui/editorwidgets/qgsvaluemapwidgetfactory.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class GUI_EXPORT QgsValueMapWidgetFactory : public QgsEditorWidgetFactory
3636
QgsEditorWidgetConfig readConfig( const QDomElement& configElement, QgsVectorLayer* layer, int fieldIdx ) override;
3737
void writeConfig( const QgsEditorWidgetConfig& config, QDomElement& configElement, QDomDocument& doc, const QgsVectorLayer* layer, int fieldIdx ) override;
3838
QString representValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const override;
39+
QVariant sortValue( QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config, const QVariant &cache, const QVariant &value ) const override;
3940
Qt::AlignmentFlag alignmentFlag( QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config ) const override;
4041
virtual QMap<const char*, int> supportedWidgetTypes() override;
4142
};

‎src/gui/editorwidgets/qgsvaluerelationwidgetfactory.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ QString QgsValueRelationWidgetFactory::representValue( QgsVectorLayer* vl, int f
130130
return QString( "(%1)" ).arg( value.toString() );
131131
}
132132

133+
QVariant QgsValueRelationWidgetFactory::sortValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const
134+
{
135+
return representValue( vl, fieldIdx, config, cache, value );
136+
}
137+
133138
Qt::AlignmentFlag QgsValueRelationWidgetFactory::alignmentFlag( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config ) const
134139
{
135140
Q_UNUSED( vl );

‎src/gui/editorwidgets/qgsvaluerelationwidgetfactory.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class GUI_EXPORT QgsValueRelationWidgetFactory : public QgsEditorWidgetFactory
3939
QgsEditorWidgetConfig readConfig( const QDomElement& configElement, QgsVectorLayer* layer, int fieldIdx ) override;
4040
void writeConfig( const QgsEditorWidgetConfig& config, QDomElement& configElement, QDomDocument& doc, const QgsVectorLayer* layer, int fieldIdx ) override;
4141
QString representValue( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, const QVariant& cache, const QVariant& value ) const override;
42+
QVariant sortValue( QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config, const QVariant &cache, const QVariant &value ) const override;
4243
Qt::AlignmentFlag alignmentFlag( QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config ) const override;
4344
QVariant createCache( QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config ) override;
4445
};

0 commit comments

Comments
 (0)
Please sign in to comment.