Skip to content

Commit

Permalink
[composer] Cache features for attribute table, to reduce excessive cp…
Browse files Browse the repository at this point in the history
…u use and multiple queries to layer provider
  • Loading branch information
nyalldawson committed Apr 22, 2014
1 parent bf3566d commit a386e89
Show file tree
Hide file tree
Showing 8 changed files with 447 additions and 59 deletions.
106 changes: 101 additions & 5 deletions python/core/composer/qgscomposerattributetable.sip
Expand Up @@ -35,16 +35,74 @@ class QgsComposerAttributeTable : QgsComposerTable
bool writeXML( QDomElement& elem, QDomDocument & doc ) const;
bool readXML( const QDomElement& itemElem, const QDomDocument& doc );

void setVectorLayer( QgsVectorLayer* vl );
/**Sets the vector layer from which to display feature attributes
* @param layer Vector layer for attribute table
* @note added in 2.3
* @see vectorLayer
*/
void setVectorLayer( QgsVectorLayer* layer );

/*Returns the vector layer the attribute table is currently using
* @returns attribute table's current vector layer
* @note added in 2.3
* @see setVectorLayer
*/
QgsVectorLayer* vectorLayer() const;

/**Sets the composer map to use to limit the extent of features shown in the
* attribute table. This setting only has an effect if setDisplayOnlyVisibleFeatures is
* set to true. Changing the composer map forces the table to refetch features from its
* vector layer, and may result in the table changing size to accomodate the new displayed
* feature attributes.
* @param map QgsComposerMap which drives the extents of the table's features
* @note added in 2.3
* @see composerMap
* @see setDisplayOnlyVisibleFeatures
*/
void setComposerMap( const QgsComposerMap* map /TransferThis/ );

/*Returns the composer map whose extents are controlling the features shown in the
* table. The extents of the map are only used if displayOnlyVisibleFeatures() is true.
* @returns composer map controlling the attribute table
* @note added in 2.3
* @see setComposerMap
* @see displayOnlyVisibleFeatures
*/
const QgsComposerMap* composerMap() const;

void setMaximumNumberOfFeatures( int nr );
/**Sets the maximum number of features shown by the table. Changing this setting may result
* in the attribute table changing its size to accomodate the new number of rows, and requires
* the table to refetch features from its vector layer.
* @param features maximum number of features to show in the table
* @note added in 2.3
* @see maximumNumberOfFeatures
*/
void setMaximumNumberOfFeatures( int features );

/*Returns the maximum number of features to be shown by the table.
* @returns maximum number of features
* @note added in 2.3
* @see setMaximumNumberOfFeatures
*/
int maximumNumberOfFeatures() const;

/**Sets attribute table to only show features which are visible in a composer map item. Changing
* this setting forces the table to refetch features from its vector layer, and may result in
* the table changing size to accomodate the new displayed feature attributes.
* @param visibleOnly set to true to show only visible features
* @note added in 2.3
* @see displayOnlyVisibleFeatures
* @see setComposerMap
*/
void setDisplayOnlyVisibleFeatures( bool b );

/*Returns true if the table is set to show only features visible on a corresponding
* composer map item.
* @returns true if table only shows visible features
* @note added in 2.3
* @see composerMap
* @see setDisplayOnlyVisibleFeatures
*/
bool displayOnlyVisibleFeatures() const;

/*Returns true if a feature filter is active on the attribute table
Expand All @@ -54,7 +112,10 @@ class QgsComposerAttributeTable : QgsComposerTable
* @see featureFilter
*/
bool filterFeatures() const;
/**Sets whether the feature filter is active for the attribute table

/**Sets whether the feature filter is active for the attribute table. Changing
* this setting forces the table to refetch features from its vector layer, and may result in
* the table changing size to accomodate the new displayed feature attributes.
* @param filter Set to true to enable the feature filter
* @note added in 2.3
* @see filterFeatures
Expand All @@ -70,22 +131,57 @@ class QgsComposerAttributeTable : QgsComposerTable
* @see filterFeatures
*/
QString featureFilter() const;

/**Sets the expression used for filtering features in the table. The filter is only
* active if filterFeatures() is set to true.
* active if filterFeatures() is set to true. Changing this setting forces the table
* to refetch features from its vector layer, and may result in
* the table changing size to accomodate the new displayed feature attributes.
* @param expression filter to use for selecting which features to display in the table
* @note added in 2.3
* @see featureFilter
* @see setFilterFeatures
*/
void setFeatureFilter( const QString& expression );

/*Returns the attributes fields which are shown by the table.
* @returns a QSet of integers refering to the attributes in the vector layer
* @see setDisplayAttributes
*/
QSet<int> displayAttributes() const;

/**Sets the attributes to display in the table.
* @param attr QSet of integer values refering to the attributes from the vector layer to show
* @param refresh set to true to force the table to refetch features from its vector layer
* and immediately update the display of the table. This may result in the table changing size
* to accomodate the new displayed feature attributes.
* @see displayAttributes
*/
void setDisplayAttributes( const QSet<int>& attr );

/*Returns the attribute field aliases, which control how fields are named in the table's
* header row.
* @returns a QMap of integers to strings, where the string is the field's alias.
* @see setFieldAliasMap
*/
QMap<int, QString> fieldAliasMap() const;

/**Sets the attribute field aliases, which control how fields are named in the table's
* header row.
* @param map QMap of integers to strings, where the string is the alias to use for the
* corresponding field.
* @param refresh set to true to force the table to refetch features from its vector layer
* and immediately update the display of the table. This may result in the table changing size
* to accomodate the new displayed feature attributes and field aliases.
* @see fieldAliasMap
*/
void setFieldAliasMap( const QMap<int, QString>& map );

/**Adapts mMaximumNumberOfFeatures depending on the rectangle height*/
/**Adapts mMaximumNumberOfFeatures depending on the rectangle height. Calling this forces
* the table to refetch features from its vector layer and immediately updates the display
* of the table.
* @see maximumNumberOfFeatures
* @see setMaximumNumberOfFeatures
*/
void setSceneRect( const QRectF& rectangle );

// @note not available in python bindings
Expand Down
21 changes: 18 additions & 3 deletions python/core/composer/qgscomposertable.sip
Expand Up @@ -35,10 +35,25 @@ class QgsComposerTable: QgsComposerItem

void setGridColor( const QColor& c );
QColor gridColor() const;

public slots:

/**Adapts the size of the frame to match the content. This is normally done in the paint method, but sometimes
it needs to be done before the first render*/
void adjustFrameToSize();
/**Refreshes the attributes shown in the table by querying the vector layer for new data.
* This also causes the column widths and size of the table to change to accomodate the
* new data.
* @note added in 2.3
* @see adjustFrameToSize
*/
virtual void refreshAttributes();

/**Adapts the size of the frame to match the content. First, the optimal width of the columns
* is recalculated by checking the maximum width of attributes shown in the table. Then, the
* table is resized to fit its contents. This slot utilises the table's attribute cache so
* that a re-query of the vector layer is not required.
* @note added in 2.3
* @see refreshAttributes
*/
virtual void adjustFrameToSize();

protected:
/**Retrieves feature attributes*/
Expand Down
11 changes: 8 additions & 3 deletions src/app/composer/qgscomposertablewidget.cpp
Expand Up @@ -106,9 +106,14 @@ void QgsComposerTableWidget::on_mAttributesPushButton_clicked()
{
//change displayAttributes and aliases
mComposerTable->beginCommand( tr( "Table attribute settings" ) );
mComposerTable->setDisplayAttributes( d.enabledAttributes() );
mComposerTable->setFieldAliasMap( d.aliasMap() );
mComposerTable->setSortAttributes( d.attributeSorting() );

//call these methods with update=false to prevent multiple refreshing of table attributes
mComposerTable->setDisplayAttributes( d.enabledAttributes(), false );
mComposerTable->setFieldAliasMap( d.aliasMap(), false );
mComposerTable->setSortAttributes( d.attributeSorting(), false );
//finally, force a single refresh of the attributes
mComposerTable->refreshAttributes();

mComposerTable->update();
mComposerTable->endCommand();
}
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -352,6 +352,7 @@ SET(QGIS_CORE_MOC_HDRS
composer/qgscomposerlabel.h
composer/qgscomposershape.h
composer/qgscomposerattributetable.h
composer/qgscomposertable.h
composer/qgscomposerhtml.h
composer/qgscomposermultiframe.h
composer/qgscomposereffect.h
Expand Down
126 changes: 119 additions & 7 deletions src/core/composer/qgscomposerattributetable.cpp
Expand Up @@ -98,26 +98,111 @@ void QgsComposerAttributeTable::initializeAliasMap()
}
}

void QgsComposerAttributeTable::setVectorLayer( QgsVectorLayer* vl )
void QgsComposerAttributeTable::setVectorLayer( QgsVectorLayer* layer )
{
if ( vl != mVectorLayer )
if ( layer == mVectorLayer )
{
mDisplayAttributes.clear();
mVectorLayer = vl;
initializeAliasMap();
return;
}

mDisplayAttributes.clear();

if ( mVectorLayer )
{
//disconnect from previous layer
QObject::disconnect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
}

mVectorLayer = layer;
initializeAliasMap();
refreshAttributes();

//listen for modifications to layer and refresh table when they occur
QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
}

void QgsComposerAttributeTable::setComposerMap( const QgsComposerMap* map )
{
if ( map == mComposerMap )
{
return;
}

if ( mComposerMap )
{
QObject::disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
//disconnect from previous map
QObject::disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( refreshAttributes() ) );
}
mComposerMap = map;
if ( mComposerMap )
{
QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
//listen out for extent changes in linked map
QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( refreshAttributes() ) );
}
refreshAttributes();
}

void QgsComposerAttributeTable::setMaximumNumberOfFeatures( int features )
{
if ( features == mMaximumNumberOfFeatures )
{
return;
}

mMaximumNumberOfFeatures = features;
refreshAttributes();
}

void QgsComposerAttributeTable::setDisplayOnlyVisibleFeatures( bool visibleOnly )
{
if ( visibleOnly == mShowOnlyVisibleFeatures )
{
return;
}

mShowOnlyVisibleFeatures = visibleOnly;
refreshAttributes();
}

void QgsComposerAttributeTable::setFilterFeatures( bool filter )
{
if ( filter == mFilterFeatures )
{
return;
}

mFilterFeatures = filter;
refreshAttributes();
}

void QgsComposerAttributeTable::setFeatureFilter( const QString& expression )
{
if ( expression == mFeatureFilter )
{
return;
}

mFeatureFilter = expression;
refreshAttributes();
}

void QgsComposerAttributeTable::setDisplayAttributes( const QSet<int>& attr, bool refresh )
{
mDisplayAttributes = attr;

if ( refresh )
{
refreshAttributes();
}
}

void QgsComposerAttributeTable::setFieldAliasMap( const QMap<int, QString>& map, bool refresh )
{
mFieldAliasMap = map;

if ( refresh )
{
refreshAttributes();
}
}

Expand Down Expand Up @@ -259,9 +344,23 @@ void QgsComposerAttributeTable::setSceneRect( const QRectF& rectangle )
mMaximumNumberOfFeatures = 0;
}
QgsComposerItem::setSceneRect( rectangle );

//refresh table attributes, since number of features has likely changed
refreshAttributes();

emit maximumNumberOfFeaturesChanged( mMaximumNumberOfFeatures );
}

void QgsComposerAttributeTable::setSortAttributes( const QList<QPair<int, bool> > att, bool refresh )
{
mSortInformation = att;

if ( refresh )
{
refreshAttributes();
}
}

bool QgsComposerAttributeTable::writeXML( QDomElement& elem, QDomDocument & doc ) const
{
QDomElement composerTableElem = doc.createElement( "ComposerAttributeTable" );
Expand Down Expand Up @@ -349,6 +448,12 @@ bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDom
mComposerMap = 0;
}

if ( mComposerMap )
{
//if we have found a valid map item, listen out to extent changes on it and refresh the table
QObject::connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( refreshAttributes() ) );
}

//vector layer
QString layerId = itemElem.attribute( "vectorLayer", "not_existing" );
if ( layerId == "not_existing" )
Expand All @@ -361,6 +466,11 @@ bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDom
if ( ml )
{
mVectorLayer = dynamic_cast<QgsVectorLayer*>( ml );
if ( mVectorLayer )
{
//if we have found a valid vector layer, listen for modifications on it and refresh the table
QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
}
}
}

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

refreshAttributes();

emit itemChanged();
return success;
}

0 comments on commit a386e89

Please sign in to comment.