Skip to content

Commit a386e89

Browse files
committedApr 22, 2014
[composer] Cache features for attribute table, to reduce excessive cpu use and multiple queries to layer provider
1 parent bf3566d commit a386e89

File tree

8 files changed

+447
-59
lines changed

8 files changed

+447
-59
lines changed
 

‎python/core/composer/qgscomposerattributetable.sip

Lines changed: 101 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,74 @@ class QgsComposerAttributeTable : QgsComposerTable
3535
bool writeXML( QDomElement& elem, QDomDocument & doc ) const;
3636
bool readXML( const QDomElement& itemElem, const QDomDocument& doc );
3737

38-
void setVectorLayer( QgsVectorLayer* vl );
38+
/**Sets the vector layer from which to display feature attributes
39+
* @param layer Vector layer for attribute table
40+
* @note added in 2.3
41+
* @see vectorLayer
42+
*/
43+
void setVectorLayer( QgsVectorLayer* layer );
44+
45+
/*Returns the vector layer the attribute table is currently using
46+
* @returns attribute table's current vector layer
47+
* @note added in 2.3
48+
* @see setVectorLayer
49+
*/
3950
QgsVectorLayer* vectorLayer() const;
4051

52+
/**Sets the composer map to use to limit the extent of features shown in the
53+
* attribute table. This setting only has an effect if setDisplayOnlyVisibleFeatures is
54+
* set to true. Changing the composer map forces the table to refetch features from its
55+
* vector layer, and may result in the table changing size to accomodate the new displayed
56+
* feature attributes.
57+
* @param map QgsComposerMap which drives the extents of the table's features
58+
* @note added in 2.3
59+
* @see composerMap
60+
* @see setDisplayOnlyVisibleFeatures
61+
*/
4162
void setComposerMap( const QgsComposerMap* map /TransferThis/ );
63+
64+
/*Returns the composer map whose extents are controlling the features shown in the
65+
* table. The extents of the map are only used if displayOnlyVisibleFeatures() is true.
66+
* @returns composer map controlling the attribute table
67+
* @note added in 2.3
68+
* @see setComposerMap
69+
* @see displayOnlyVisibleFeatures
70+
*/
4271
const QgsComposerMap* composerMap() const;
4372

44-
void setMaximumNumberOfFeatures( int nr );
73+
/**Sets the maximum number of features shown by the table. Changing this setting may result
74+
* in the attribute table changing its size to accomodate the new number of rows, and requires
75+
* the table to refetch features from its vector layer.
76+
* @param features maximum number of features to show in the table
77+
* @note added in 2.3
78+
* @see maximumNumberOfFeatures
79+
*/
80+
void setMaximumNumberOfFeatures( int features );
81+
82+
/*Returns the maximum number of features to be shown by the table.
83+
* @returns maximum number of features
84+
* @note added in 2.3
85+
* @see setMaximumNumberOfFeatures
86+
*/
4587
int maximumNumberOfFeatures() const;
4688

89+
/**Sets attribute table to only show features which are visible in a composer map item. Changing
90+
* this setting forces the table to refetch features from its vector layer, and may result in
91+
* the table changing size to accomodate the new displayed feature attributes.
92+
* @param visibleOnly set to true to show only visible features
93+
* @note added in 2.3
94+
* @see displayOnlyVisibleFeatures
95+
* @see setComposerMap
96+
*/
4797
void setDisplayOnlyVisibleFeatures( bool b );
98+
99+
/*Returns true if the table is set to show only features visible on a corresponding
100+
* composer map item.
101+
* @returns true if table only shows visible features
102+
* @note added in 2.3
103+
* @see composerMap
104+
* @see setDisplayOnlyVisibleFeatures
105+
*/
48106
bool displayOnlyVisibleFeatures() const;
49107

50108
/*Returns true if a feature filter is active on the attribute table
@@ -54,7 +112,10 @@ class QgsComposerAttributeTable : QgsComposerTable
54112
* @see featureFilter
55113
*/
56114
bool filterFeatures() const;
57-
/**Sets whether the feature filter is active for the attribute table
115+
116+
/**Sets whether the feature filter is active for the attribute table. Changing
117+
* this setting forces the table to refetch features from its vector layer, and may result in
118+
* the table changing size to accomodate the new displayed feature attributes.
58119
* @param filter Set to true to enable the feature filter
59120
* @note added in 2.3
60121
* @see filterFeatures
@@ -70,22 +131,57 @@ class QgsComposerAttributeTable : QgsComposerTable
70131
* @see filterFeatures
71132
*/
72133
QString featureFilter() const;
134+
73135
/**Sets the expression used for filtering features in the table. The filter is only
74-
* active if filterFeatures() is set to true.
136+
* active if filterFeatures() is set to true. Changing this setting forces the table
137+
* to refetch features from its vector layer, and may result in
138+
* the table changing size to accomodate the new displayed feature attributes.
75139
* @param expression filter to use for selecting which features to display in the table
76140
* @note added in 2.3
77141
* @see featureFilter
78142
* @see setFilterFeatures
79143
*/
80144
void setFeatureFilter( const QString& expression );
81145

146+
/*Returns the attributes fields which are shown by the table.
147+
* @returns a QSet of integers refering to the attributes in the vector layer
148+
* @see setDisplayAttributes
149+
*/
82150
QSet<int> displayAttributes() const;
151+
152+
/**Sets the attributes to display in the table.
153+
* @param attr QSet of integer values refering to the attributes from the vector layer to show
154+
* @param refresh set to true to force the table to refetch features from its vector layer
155+
* and immediately update the display of the table. This may result in the table changing size
156+
* to accomodate the new displayed feature attributes.
157+
* @see displayAttributes
158+
*/
83159
void setDisplayAttributes( const QSet<int>& attr );
84160

161+
/*Returns the attribute field aliases, which control how fields are named in the table's
162+
* header row.
163+
* @returns a QMap of integers to strings, where the string is the field's alias.
164+
* @see setFieldAliasMap
165+
*/
85166
QMap<int, QString> fieldAliasMap() const;
167+
168+
/**Sets the attribute field aliases, which control how fields are named in the table's
169+
* header row.
170+
* @param map QMap of integers to strings, where the string is the alias to use for the
171+
* corresponding field.
172+
* @param refresh set to true to force the table to refetch features from its vector layer
173+
* and immediately update the display of the table. This may result in the table changing size
174+
* to accomodate the new displayed feature attributes and field aliases.
175+
* @see fieldAliasMap
176+
*/
86177
void setFieldAliasMap( const QMap<int, QString>& map );
87178

88-
/**Adapts mMaximumNumberOfFeatures depending on the rectangle height*/
179+
/**Adapts mMaximumNumberOfFeatures depending on the rectangle height. Calling this forces
180+
* the table to refetch features from its vector layer and immediately updates the display
181+
* of the table.
182+
* @see maximumNumberOfFeatures
183+
* @see setMaximumNumberOfFeatures
184+
*/
89185
void setSceneRect( const QRectF& rectangle );
90186

91187
// @note not available in python bindings

‎python/core/composer/qgscomposertable.sip

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,25 @@ class QgsComposerTable: QgsComposerItem
3535

3636
void setGridColor( const QColor& c );
3737
QColor gridColor() const;
38+
39+
public slots:
3840

39-
/**Adapts the size of the frame to match the content. This is normally done in the paint method, but sometimes
40-
it needs to be done before the first render*/
41-
void adjustFrameToSize();
41+
/**Refreshes the attributes shown in the table by querying the vector layer for new data.
42+
* This also causes the column widths and size of the table to change to accomodate the
43+
* new data.
44+
* @note added in 2.3
45+
* @see adjustFrameToSize
46+
*/
47+
virtual void refreshAttributes();
48+
49+
/**Adapts the size of the frame to match the content. First, the optimal width of the columns
50+
* is recalculated by checking the maximum width of attributes shown in the table. Then, the
51+
* table is resized to fit its contents. This slot utilises the table's attribute cache so
52+
* that a re-query of the vector layer is not required.
53+
* @note added in 2.3
54+
* @see refreshAttributes
55+
*/
56+
virtual void adjustFrameToSize();
4257

4358
protected:
4459
/**Retrieves feature attributes*/

‎src/app/composer/qgscomposertablewidget.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,14 @@ void QgsComposerTableWidget::on_mAttributesPushButton_clicked()
106106
{
107107
//change displayAttributes and aliases
108108
mComposerTable->beginCommand( tr( "Table attribute settings" ) );
109-
mComposerTable->setDisplayAttributes( d.enabledAttributes() );
110-
mComposerTable->setFieldAliasMap( d.aliasMap() );
111-
mComposerTable->setSortAttributes( d.attributeSorting() );
109+
110+
//call these methods with update=false to prevent multiple refreshing of table attributes
111+
mComposerTable->setDisplayAttributes( d.enabledAttributes(), false );
112+
mComposerTable->setFieldAliasMap( d.aliasMap(), false );
113+
mComposerTable->setSortAttributes( d.attributeSorting(), false );
114+
//finally, force a single refresh of the attributes
115+
mComposerTable->refreshAttributes();
116+
112117
mComposerTable->update();
113118
mComposerTable->endCommand();
114119
}

‎src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ SET(QGIS_CORE_MOC_HDRS
352352
composer/qgscomposerlabel.h
353353
composer/qgscomposershape.h
354354
composer/qgscomposerattributetable.h
355+
composer/qgscomposertable.h
355356
composer/qgscomposerhtml.h
356357
composer/qgscomposermultiframe.h
357358
composer/qgscomposereffect.h

‎src/core/composer/qgscomposerattributetable.cpp

Lines changed: 119 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,26 +98,111 @@ void QgsComposerAttributeTable::initializeAliasMap()
9898
}
9999
}
100100

101-
void QgsComposerAttributeTable::setVectorLayer( QgsVectorLayer* vl )
101+
void QgsComposerAttributeTable::setVectorLayer( QgsVectorLayer* layer )
102102
{
103-
if ( vl != mVectorLayer )
103+
if ( layer == mVectorLayer )
104104
{
105-
mDisplayAttributes.clear();
106-
mVectorLayer = vl;
107-
initializeAliasMap();
105+
return;
108106
}
107+
108+
mDisplayAttributes.clear();
109+
110+
if ( mVectorLayer )
111+
{
112+
//disconnect from previous layer
113+
QObject::disconnect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
114+
}
115+
116+
mVectorLayer = layer;
117+
initializeAliasMap();
118+
refreshAttributes();
119+
120+
//listen for modifications to layer and refresh table when they occur
121+
QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
109122
}
110123

111124
void QgsComposerAttributeTable::setComposerMap( const QgsComposerMap* map )
112125
{
126+
if ( map == mComposerMap )
127+
{
128+
return;
129+
}
130+
113131
if ( mComposerMap )
114132
{
115-
QObject::disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
133+
//disconnect from previous map
134+
QObject::disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( refreshAttributes() ) );
116135
}
117136
mComposerMap = map;
118137
if ( mComposerMap )
119138
{
120-
QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
139+
//listen out for extent changes in linked map
140+
QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( refreshAttributes() ) );
141+
}
142+
refreshAttributes();
143+
}
144+
145+
void QgsComposerAttributeTable::setMaximumNumberOfFeatures( int features )
146+
{
147+
if ( features == mMaximumNumberOfFeatures )
148+
{
149+
return;
150+
}
151+
152+
mMaximumNumberOfFeatures = features;
153+
refreshAttributes();
154+
}
155+
156+
void QgsComposerAttributeTable::setDisplayOnlyVisibleFeatures( bool visibleOnly )
157+
{
158+
if ( visibleOnly == mShowOnlyVisibleFeatures )
159+
{
160+
return;
161+
}
162+
163+
mShowOnlyVisibleFeatures = visibleOnly;
164+
refreshAttributes();
165+
}
166+
167+
void QgsComposerAttributeTable::setFilterFeatures( bool filter )
168+
{
169+
if ( filter == mFilterFeatures )
170+
{
171+
return;
172+
}
173+
174+
mFilterFeatures = filter;
175+
refreshAttributes();
176+
}
177+
178+
void QgsComposerAttributeTable::setFeatureFilter( const QString& expression )
179+
{
180+
if ( expression == mFeatureFilter )
181+
{
182+
return;
183+
}
184+
185+
mFeatureFilter = expression;
186+
refreshAttributes();
187+
}
188+
189+
void QgsComposerAttributeTable::setDisplayAttributes( const QSet<int>& attr, bool refresh )
190+
{
191+
mDisplayAttributes = attr;
192+
193+
if ( refresh )
194+
{
195+
refreshAttributes();
196+
}
197+
}
198+
199+
void QgsComposerAttributeTable::setFieldAliasMap( const QMap<int, QString>& map, bool refresh )
200+
{
201+
mFieldAliasMap = map;
202+
203+
if ( refresh )
204+
{
205+
refreshAttributes();
121206
}
122207
}
123208

@@ -259,9 +344,23 @@ void QgsComposerAttributeTable::setSceneRect( const QRectF& rectangle )
259344
mMaximumNumberOfFeatures = 0;
260345
}
261346
QgsComposerItem::setSceneRect( rectangle );
347+
348+
//refresh table attributes, since number of features has likely changed
349+
refreshAttributes();
350+
262351
emit maximumNumberOfFeaturesChanged( mMaximumNumberOfFeatures );
263352
}
264353

354+
void QgsComposerAttributeTable::setSortAttributes( const QList<QPair<int, bool> > att, bool refresh )
355+
{
356+
mSortInformation = att;
357+
358+
if ( refresh )
359+
{
360+
refreshAttributes();
361+
}
362+
}
363+
265364
bool QgsComposerAttributeTable::writeXML( QDomElement& elem, QDomDocument & doc ) const
266365
{
267366
QDomElement composerTableElem = doc.createElement( "ComposerAttributeTable" );
@@ -349,6 +448,12 @@ bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDom
349448
mComposerMap = 0;
350449
}
351450

451+
if ( mComposerMap )
452+
{
453+
//if we have found a valid map item, listen out to extent changes on it and refresh the table
454+
QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( refreshAttributes() ) );
455+
}
456+
352457
//vector layer
353458
QString layerId = itemElem.attribute( "vectorLayer", "not_existing" );
354459
if ( layerId == "not_existing" )
@@ -361,6 +466,11 @@ bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDom
361466
if ( ml )
362467
{
363468
mVectorLayer = dynamic_cast<QgsVectorLayer*>( ml );
469+
if ( mVectorLayer )
470+
{
471+
//if we have found a valid vector layer, listen for modifications on it and refresh the table
472+
QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
473+
}
364474
}
365475
}
366476

@@ -417,6 +527,8 @@ bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDom
417527
//must be done here because tableReadXML->setSceneRect changes mMaximumNumberOfFeatures
418528
mMaximumNumberOfFeatures = itemElem.attribute( "maxFeatures", "5" ).toInt();
419529

530+
refreshAttributes();
531+
420532
emit itemChanged();
421533
return success;
422534
}

0 commit comments

Comments
 (0)
Please sign in to comment.