[composer] Cache features for attribute table, to reduce excessive cpu use and multiple queries to layer provider

This commit is contained in:
Nyall Dawson 2014-04-23 06:28:56 +10:00
parent bf3566de88
commit a386e898f0
8 changed files with 447 additions and 59 deletions

View File

@ -35,16 +35,74 @@ class QgsComposerAttributeTable : QgsComposerTable
bool writeXML( QDomElement& elem, QDomDocument & doc ) const; bool writeXML( QDomElement& elem, QDomDocument & doc ) const;
bool readXML( const QDomElement& itemElem, const QDomDocument& doc ); 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; 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/ ); 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; 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; 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 ); 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; bool displayOnlyVisibleFeatures() const;
/*Returns true if a feature filter is active on the attribute table /*Returns true if a feature filter is active on the attribute table
@ -54,7 +112,10 @@ class QgsComposerAttributeTable : QgsComposerTable
* @see featureFilter * @see featureFilter
*/ */
bool filterFeatures() const; 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 * @param filter Set to true to enable the feature filter
* @note added in 2.3 * @note added in 2.3
* @see filterFeatures * @see filterFeatures
@ -70,8 +131,11 @@ class QgsComposerAttributeTable : QgsComposerTable
* @see filterFeatures * @see filterFeatures
*/ */
QString featureFilter() const; QString featureFilter() const;
/**Sets the expression used for filtering features in the table. The filter is only /**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 * @param expression filter to use for selecting which features to display in the table
* @note added in 2.3 * @note added in 2.3
* @see featureFilter * @see featureFilter
@ -79,13 +143,45 @@ class QgsComposerAttributeTable : QgsComposerTable
*/ */
void setFeatureFilter( const QString& expression ); 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; 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 ); 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; 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 ); 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 ); void setSceneRect( const QRectF& rectangle );
// @note not available in python bindings // @note not available in python bindings

View File

@ -35,10 +35,25 @@ class QgsComposerTable: QgsComposerItem
void setGridColor( const QColor& c ); void setGridColor( const QColor& c );
QColor gridColor() const; 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 /**Refreshes the attributes shown in the table by querying the vector layer for new data.
it needs to be done before the first render*/ * This also causes the column widths and size of the table to change to accomodate the
void adjustFrameToSize(); * 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: protected:
/**Retrieves feature attributes*/ /**Retrieves feature attributes*/

View File

@ -106,9 +106,14 @@ void QgsComposerTableWidget::on_mAttributesPushButton_clicked()
{ {
//change displayAttributes and aliases //change displayAttributes and aliases
mComposerTable->beginCommand( tr( "Table attribute settings" ) ); mComposerTable->beginCommand( tr( "Table attribute settings" ) );
mComposerTable->setDisplayAttributes( d.enabledAttributes() );
mComposerTable->setFieldAliasMap( d.aliasMap() ); //call these methods with update=false to prevent multiple refreshing of table attributes
mComposerTable->setSortAttributes( d.attributeSorting() ); 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->update();
mComposerTable->endCommand(); mComposerTable->endCommand();
} }

View File

@ -352,6 +352,7 @@ SET(QGIS_CORE_MOC_HDRS
composer/qgscomposerlabel.h composer/qgscomposerlabel.h
composer/qgscomposershape.h composer/qgscomposershape.h
composer/qgscomposerattributetable.h composer/qgscomposerattributetable.h
composer/qgscomposertable.h
composer/qgscomposerhtml.h composer/qgscomposerhtml.h
composer/qgscomposermultiframe.h composer/qgscomposermultiframe.h
composer/qgscomposereffect.h composer/qgscomposereffect.h

View File

@ -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(); return;
mVectorLayer = vl;
initializeAliasMap();
} }
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 ) void QgsComposerAttributeTable::setComposerMap( const QgsComposerMap* map )
{ {
if ( map == mComposerMap )
{
return;
}
if ( mComposerMap ) if ( mComposerMap )
{ {
QObject::disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( repaint() ) ); //disconnect from previous map
QObject::disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( refreshAttributes() ) );
} }
mComposerMap = map; mComposerMap = map;
if ( mComposerMap ) 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();
} }
} }
@ -259,9 +344,23 @@ void QgsComposerAttributeTable::setSceneRect( const QRectF& rectangle )
mMaximumNumberOfFeatures = 0; mMaximumNumberOfFeatures = 0;
} }
QgsComposerItem::setSceneRect( rectangle ); QgsComposerItem::setSceneRect( rectangle );
//refresh table attributes, since number of features has likely changed
refreshAttributes();
emit maximumNumberOfFeaturesChanged( mMaximumNumberOfFeatures ); 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 bool QgsComposerAttributeTable::writeXML( QDomElement& elem, QDomDocument & doc ) const
{ {
QDomElement composerTableElem = doc.createElement( "ComposerAttributeTable" ); QDomElement composerTableElem = doc.createElement( "ComposerAttributeTable" );
@ -349,6 +448,12 @@ bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDom
mComposerMap = 0; 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 //vector layer
QString layerId = itemElem.attribute( "vectorLayer", "not_existing" ); QString layerId = itemElem.attribute( "vectorLayer", "not_existing" );
if ( layerId == "not_existing" ) if ( layerId == "not_existing" )
@ -361,6 +466,11 @@ bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDom
if ( ml ) if ( ml )
{ {
mVectorLayer = dynamic_cast<QgsVectorLayer*>( 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() ) );
}
} }
} }
@ -417,6 +527,8 @@ bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDom
//must be done here because tableReadXML->setSceneRect changes mMaximumNumberOfFeatures //must be done here because tableReadXML->setSceneRect changes mMaximumNumberOfFeatures
mMaximumNumberOfFeatures = itemElem.attribute( "maxFeatures", "5" ).toInt(); mMaximumNumberOfFeatures = itemElem.attribute( "maxFeatures", "5" ).toInt();
refreshAttributes();
emit itemChanged(); emit itemChanged();
return success; return success;
} }

View File

@ -53,16 +53,70 @@ class CORE_EXPORT QgsComposerAttributeTable: public QgsComposerTable
bool writeXML( QDomElement& elem, QDomDocument & doc ) const; bool writeXML( QDomElement& elem, QDomDocument & doc ) const;
bool readXML( const QDomElement& itemElem, const QDomDocument& doc ); 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 { return mVectorLayer; } QgsVectorLayer* vectorLayer() const { return mVectorLayer; }
/**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 ); void setComposerMap( const QgsComposerMap* map );
/*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 { return mComposerMap; } const QgsComposerMap* composerMap() const { return mComposerMap; }
void setMaximumNumberOfFeatures( int nr ) { mMaximumNumberOfFeatures = 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 { return mMaximumNumberOfFeatures; } int maximumNumberOfFeatures() const { return mMaximumNumberOfFeatures; }
void setDisplayOnlyVisibleFeatures( bool b ) { mShowOnlyVisibleFeatures = b; } /**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 visibleOnly );
/*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 { return mShowOnlyVisibleFeatures; } bool displayOnlyVisibleFeatures() const { return mShowOnlyVisibleFeatures; }
/*Returns true if a feature filter is active on the attribute table /*Returns true if a feature filter is active on the attribute table
@ -72,13 +126,15 @@ class CORE_EXPORT QgsComposerAttributeTable: public QgsComposerTable
* @see featureFilter * @see featureFilter
*/ */
bool filterFeatures() const { return mFilterFeatures; } bool filterFeatures() const { return mFilterFeatures; }
/**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 * @param filter Set to true to enable the feature filter
* @note added in 2.3 * @note added in 2.3
* @see filterFeatures * @see filterFeatures
* @see setFeatureFilter * @see setFeatureFilter
*/ */
void setFilterFeatures( bool filter ) { mFilterFeatures = filter; } void setFilterFeatures( bool filter );
/*Returns the current expression used to filter features for the table. The filter is only /*Returns the current expression used to filter features for the table. The filter is only
* active if filterFeatures() is true. * active if filterFeatures() is true.
@ -89,27 +145,77 @@ class CORE_EXPORT QgsComposerAttributeTable: public QgsComposerTable
*/ */
QString featureFilter() const { return mFeatureFilter; } QString featureFilter() const { return mFeatureFilter; }
/**Sets the expression used for filtering features in the table. The filter is only /**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 * @param expression filter to use for selecting which features to display in the table
* @note added in 2.3 * @note added in 2.3
* @see featureFilter * @see featureFilter
* @see setFilterFeatures * @see setFilterFeatures
*/ */
void setFeatureFilter( const QString& expression ) { mFeatureFilter = expression; } 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 { return mDisplayAttributes; } QSet<int> displayAttributes() const { return mDisplayAttributes; }
void setDisplayAttributes( const QSet<int>& attr ) { mDisplayAttributes = attr; } /**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, bool refresh = true );
/*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 { return mFieldAliasMap; } QMap<int, QString> fieldAliasMap() const { return mFieldAliasMap; }
void setFieldAliasMap( const QMap<int, QString>& map ) { mFieldAliasMap = map; }
/**Adapts mMaximumNumberOfFeatures depending on the rectangle height*/ /**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, bool refresh = true );
/**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 ); void setSceneRect( const QRectF& rectangle );
// @note not available in python bindings /**Sets the attributes to use to sort the table's features.
void setSortAttributes( const QList<QPair<int, bool> > att ) { mSortInformation = att; } * @param att QList integers/bool pairs, where the integer refers to the attribute index and
* the bool sets the sort order for the attribute. If true the attribute is sorted ascending,
* if false, the attribute is sorted in descending order. Note that features are sorted
* after the maximum number of displayed features have been fetched from the vector layer's
* provider.
* @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.l
* @see sortAttributes
* @note not available in python bindings
*/
void setSortAttributes( const QList<QPair<int, bool> > att, bool refresh = true );
// @note not available in python bindings /*Returns the attributes used to sort the table's features.
* @returns a QList of integer/bool pairs, where the integer refers to the attribute index and
* the bool to the sort order for the attribute. If true the attribute is sorted ascending,
* if false, the attribute is sorted in descending order.
* @see setSortAttributes
* @note not available in python bindings
*/
QList<QPair<int, bool> > sortAttributes() const { return mSortInformation; } QList<QPair<int, bool> > sortAttributes() const { return mSortInformation; }
protected: protected:
@ -147,7 +253,14 @@ class CORE_EXPORT QgsComposerAttributeTable: public QgsComposerTable
/**Inserts aliases from vector layer as starting configuration to the alias map*/ /**Inserts aliases from vector layer as starting configuration to the alias map*/
void initializeAliasMap(); void initializeAliasMap();
/**Returns the attribute name to display in the item (attribute name or an alias if present)*/
/**Returns the attribute name to display in the table's header row for a specified attribute.
* @param attributeIndex attribute index
* @param name default name to use for the attribute
* @returns the aliases for the attribute if set. If an alias is not set then the
* default name will be returned.
* @see setFieldAliasMap
*/
QString attributeDisplayName( int attributeIndex, const QString& name ) const; QString attributeDisplayName( int attributeIndex, const QString& name ) const;
private slots: private slots:

View File

@ -42,6 +42,23 @@ QgsComposerTable::~QgsComposerTable()
} }
void QgsComposerTable::refreshAttributes()
{
mMaxColumnWidthMap.clear();
mAttributeMaps.clear();
//getFeatureAttributes
if ( !getFeatureAttributes( mAttributeMaps ) )
{
return;
}
//since attributes have changed, we also need to recalculate the column widths
//and size of table
adjustFrameToSize();
}
void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget ) void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
{ {
Q_UNUSED( itemStyle ); Q_UNUSED( itemStyle );
@ -51,19 +68,14 @@ void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem*
return; return;
} }
//getFeatureAttributes if ( mComposition->plotStyle() == QgsComposition::Print ||
QList<QgsAttributeMap> attributeMaps; mComposition->plotStyle() == QgsComposition::Postscript )
if ( !getFeatureAttributes( attributeMaps ) )
{ {
return; //exporting composition, so force an attribute refresh
//we do this in case vector layer has changed via an external source (eg, another database user)
refreshAttributes();
} }
QMap<int, double> maxColumnWidthMap;
//check how much space each column needs
calculateMaxColumnWidths( maxColumnWidthMap, attributeMaps );
//adapt item frame to max width / height
adaptItemFrame( maxColumnWidthMap, attributeMaps );
drawBackground( painter ); drawBackground( painter );
painter->setPen( Qt::SolidLine ); painter->setPen( Qt::SolidLine );
@ -86,8 +98,8 @@ void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem*
currentY += mGridStrokeWidth; currentY += mGridStrokeWidth;
//draw the attribute values //draw the attribute values
QList<QgsAttributeMap>::const_iterator attIt = attributeMaps.begin(); QList<QgsAttributeMap>::const_iterator attIt = mAttributeMaps.begin();
for ( ; attIt != attributeMaps.end(); ++attIt ) for ( ; attIt != mAttributeMaps.end(); ++attIt )
{ {
currentY += fontAscentMillimeters( mContentFont ); currentY += fontAscentMillimeters( mContentFont );
currentY += mLineTextDistance; currentY += mLineTextDistance;
@ -99,7 +111,7 @@ void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem*
currentY += mGridStrokeWidth; currentY += mGridStrokeWidth;
} }
currentX += maxColumnWidthMap[columnIt.key()]; currentX += mMaxColumnWidthMap[columnIt.key()];
currentX += mLineTextDistance; currentX += mLineTextDistance;
currentX += mGridStrokeWidth; currentX += mGridStrokeWidth;
} }
@ -112,8 +124,8 @@ void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem*
gridPen.setColor( mGridColor ); gridPen.setColor( mGridColor );
gridPen.setJoinStyle( Qt::MiterJoin ); gridPen.setJoinStyle( Qt::MiterJoin );
painter->setPen( gridPen ); painter->setPen( gridPen );
drawHorizontalGridLines( painter, attributeMaps.size() ); drawHorizontalGridLines( painter, mAttributeMaps.size() );
drawVerticalGridLines( painter, maxColumnWidthMap ); drawVerticalGridLines( painter, mMaxColumnWidthMap );
} }
//draw frame and selection boxes if necessary //draw frame and selection boxes if necessary
@ -124,17 +136,31 @@ void QgsComposerTable::paint( QPainter* painter, const QStyleOptionGraphicsItem*
} }
} }
void QgsComposerTable::setHeaderFont( const QFont& f )
{
mHeaderFont = f;
//since font attributes have changed, we need to recalculate the table size
adjustFrameToSize();
}
void QgsComposerTable::setContentFont( const QFont& f )
{
mContentFont = f;
//since font attributes have changed, we need to recalculate the table size
adjustFrameToSize();
}
void QgsComposerTable::adjustFrameToSize() void QgsComposerTable::adjustFrameToSize()
{ {
QList<QgsAttributeMap> attributes; //check how much space each column needs
if ( !getFeatureAttributes( attributes ) ) if ( !calculateMaxColumnWidths( mMaxColumnWidthMap, mAttributeMaps ) )
{
return; return;
}
//adapt item frame to max width / height
adaptItemFrame( mMaxColumnWidthMap, mAttributeMaps );
QMap<int, double> maxWidthMap; repaint();
if ( !calculateMaxColumnWidths( maxWidthMap, attributes ) )
return;
adaptItemFrame( maxWidthMap, attributes );
} }
bool QgsComposerTable::tableWriteXML( QDomElement& elem, QDomDocument & doc ) const bool QgsComposerTable::tableWriteXML( QDomElement& elem, QDomDocument & doc ) const

View File

@ -28,6 +28,8 @@
/**A class to display feature attributes in the print composer*/ /**A class to display feature attributes in the print composer*/
class CORE_EXPORT QgsComposerTable: public QgsComposerItem class CORE_EXPORT QgsComposerTable: public QgsComposerItem
{ {
Q_OBJECT
public: public:
QgsComposerTable( QgsComposition* composition ); QgsComposerTable( QgsComposition* composition );
virtual ~QgsComposerTable(); virtual ~QgsComposerTable();
@ -44,10 +46,10 @@ class CORE_EXPORT QgsComposerTable: public QgsComposerItem
void setLineTextDistance( double d ) { mLineTextDistance = d; } void setLineTextDistance( double d ) { mLineTextDistance = d; }
double lineTextDistance() const { return mLineTextDistance; } double lineTextDistance() const { return mLineTextDistance; }
void setHeaderFont( const QFont& f ) { mHeaderFont = f;} void setHeaderFont( const QFont& f );
QFont headerFont() const { return mHeaderFont; } QFont headerFont() const { return mHeaderFont; }
void setContentFont( const QFont& f ) { mContentFont = f; } void setContentFont( const QFont& f );
QFont contentFont() const { return mContentFont; } QFont contentFont() const { return mContentFont; }
void setShowGrid( bool show ) { mShowGrid = show;} void setShowGrid( bool show ) { mShowGrid = show;}
@ -59,9 +61,24 @@ class CORE_EXPORT QgsComposerTable: public QgsComposerItem
void setGridColor( const QColor& c ) { mGridColor = c; } void setGridColor( const QColor& c ) { mGridColor = c; }
QColor gridColor() const { return mGridColor; } QColor gridColor() const { return mGridColor; }
/**Adapts the size of the frame to match the content. This is normally done in the paint method, but sometimes public slots:
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: protected:
/**Distance between table lines and text*/ /**Distance between table lines and text*/
@ -74,6 +91,9 @@ class CORE_EXPORT QgsComposerTable: public QgsComposerItem
double mGridStrokeWidth; double mGridStrokeWidth;
QColor mGridColor; QColor mGridColor;
QList<QgsAttributeMap> mAttributeMaps;
QMap<int, double> mMaxColumnWidthMap;
/**Retrieves feature attributes*/ /**Retrieves feature attributes*/
//! @note not available in python bindings //! @note not available in python bindings
virtual bool getFeatureAttributes( QList<QgsAttributeMap>& attributeMaps ) { Q_UNUSED( attributeMaps ); return false; } virtual bool getFeatureAttributes( QList<QgsAttributeMap>& attributeMaps ) { Q_UNUSED( attributeMaps ); return false; }