34 changes: 33 additions & 1 deletion python/core/composer/qgscomposerattributetable.sip
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class QgsComposerAttributeTable : QgsComposerTable
bool readXML( const QDomElement& itemElem, const QDomDocument& doc );

void setVectorLayer( QgsVectorLayer* vl );
const QgsVectorLayer* vectorLayer() const;
QgsVectorLayer* vectorLayer() const;

void setComposerMap( const QgsComposerMap* map /TransferThis/ );
const QgsComposerMap* composerMap() const;
Expand All @@ -46,6 +46,38 @@ class QgsComposerAttributeTable : QgsComposerTable

void setDisplayOnlyVisibleFeatures( bool b );
bool displayOnlyVisibleFeatures() const;

/*Returns true if a feature filter is active on the attribute table
* @returns bool state of the feature filter
* @note added in 2.3
* @see setFilterFeatures
* @see featureFilter
*/
bool filterFeatures() const;
/**Sets whether the feature filter is active for the attribute table
* @param filter Set to true to enable the feature filter
* @note added in 2.3
* @see filterFeatures
* @see setFeatureFilter
*/
void setFilterFeatures( bool filter );

/*Returns the current expression used to filter features for the table. The filter is only
* active if filterFeatures() is true.
* @returns feature filter expression
* @note added in 2.3
* @see setFeatureFilter
* @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.
* @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 );

QSet<int> displayAttributes() const;
void setDisplayAttributes( const QSet<int>& attr );
Expand Down
136 changes: 85 additions & 51 deletions src/app/composer/qgscomposertablewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "qgscomposermap.h"
#include "qgsmaplayerregistry.h"
#include "qgsvectorlayer.h"
#include "qgsexpressionbuilderdialog.h"
#include <QColorDialog>
#include <QFontDialog>

Expand All @@ -33,19 +34,8 @@ QgsComposerTableWidget::QgsComposerTableWidget( QgsComposerAttributeTable* table
mainLayout->addWidget( itemPropertiesWidget );

blockAllSignals( true );

//insert vector layers into combo
QMap<QString, QgsMapLayer*> layerMap = QgsMapLayerRegistry::instance()->mapLayers();
QMap<QString, QgsMapLayer*>::const_iterator mapIt = layerMap.constBegin();

for ( ; mapIt != layerMap.constEnd(); ++mapIt )
{
QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( mapIt.value() );
if ( vl )
{
mLayerComboBox->addItem( vl->name(), mapIt.key() );
}
}
mLayerComboBox->setFilters( QgsMapLayerProxyModel::HasGeometry );
connect( mLayerComboBox, SIGNAL( layerChanged( QgsMapLayer* ) ), this, SLOT( changeLayer( QgsMapLayer* ) ) );

refreshMapComboBox();

Expand Down Expand Up @@ -104,35 +94,6 @@ void QgsComposerTableWidget::refreshMapComboBox()
}
}

void QgsComposerTableWidget::on_mLayerComboBox_currentIndexChanged( int index )
{
if ( !mComposerTable )
{
return;
}

//set new layer to table item
QVariant itemData = mLayerComboBox->itemData( index );
if ( itemData.type() == QVariant::Invalid )
{
return;
}

QString layerId = itemData.toString();
QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
if ( ml )
{
QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( ml );
if ( vl )
{
mComposerTable->beginCommand( tr( "Table layer changed" ) );
mComposerTable->setVectorLayer( vl );
mComposerTable->update();
mComposerTable->endCommand();
}
}
}

void QgsComposerTableWidget::on_mAttributesPushButton_clicked()
{
if ( !mComposerTable )
Expand Down Expand Up @@ -302,15 +263,7 @@ void QgsComposerTableWidget::updateGuiElements()
blockAllSignals( true );

//layer combo box
const QgsVectorLayer* vl = mComposerTable->vectorLayer();
if ( vl )
{
int layerIndex = mLayerComboBox->findText( vl->name() );
if ( layerIndex != -1 )
{
mLayerComboBox->setCurrentIndex( layerIndex );
}
}
mLayerComboBox->setLayer( mComposerTable->vectorLayer() );

//map combo box
const QgsComposerMap* cm = mComposerTable->composerMap();
Expand Down Expand Up @@ -345,6 +298,11 @@ void QgsComposerTableWidget::updateGuiElements()
{
mShowOnlyVisibleFeaturesCheckBox->setCheckState( Qt::Unchecked );
}

mFeatureFilterEdit->setText( mComposerTable->featureFilter() );
mFeatureFilterCheckBox->setCheckState( mComposerTable->filterFeatures() ? Qt::Checked : Qt::Unchecked );
mFeatureFilterEdit->setEnabled( mComposerTable->filterFeatures() );
mFeatureFilterButton->setEnabled( mComposerTable->filterFeatures() );
blockAllSignals( false );
}

Expand All @@ -358,6 +316,8 @@ void QgsComposerTableWidget::blockAllSignals( bool b )
mGridStrokeWidthSpinBox->blockSignals( b );
mShowGridGroupCheckBox->blockSignals( b );
mShowOnlyVisibleFeaturesCheckBox->blockSignals( b );
mFeatureFilterEdit->blockSignals( b );
mFeatureFilterCheckBox->blockSignals( b );
}

void QgsComposerTableWidget::setMaximumNumberOfFeatures( int n )
Expand All @@ -381,4 +341,78 @@ void QgsComposerTableWidget::on_mShowOnlyVisibleFeaturesCheckBox_stateChanged( i
mComposerTable->endCommand();
}

void QgsComposerTableWidget::on_mFeatureFilterCheckBox_stateChanged( int state )
{
if ( !mComposerTable )
{
return;
}

if ( state == Qt::Checked )
{
mFeatureFilterEdit->setEnabled( true );
mFeatureFilterButton->setEnabled( true );
}
else
{
mFeatureFilterEdit->setEnabled( false );
mFeatureFilterButton->setEnabled( false );
}
mComposerTable->beginCommand( tr( "Table feature filter toggled" ) );
mComposerTable->setFilterFeatures( state == Qt::Checked );
mComposerTable->update();
mComposerTable->endCommand();
}

void QgsComposerTableWidget::on_mFeatureFilterEdit_editingFinished()
{
if ( !mComposerTable )
{
return;
}

mComposerTable->beginCommand( tr( "Table feature filter modified" ) );
mComposerTable->setFeatureFilter( mFeatureFilterEdit->text() );
mComposerTable->update();
mComposerTable->endCommand();
}

void QgsComposerTableWidget::on_mFeatureFilterButton_clicked()
{
if ( !mComposerTable )
{
return;
}

QgsExpressionBuilderDialog exprDlg( mComposerTable->vectorLayer(), mFeatureFilterEdit->text(), this );
exprDlg.setWindowTitle( tr( "Expression based filter" ) );
if ( exprDlg.exec() == QDialog::Accepted )
{
QString expression = exprDlg.expressionText();
if ( !expression.isEmpty() )
{
mFeatureFilterEdit->setText( expression );
mComposerTable->beginCommand( tr( "Table feature filter modified" ) );
mComposerTable->setFeatureFilter( mFeatureFilterEdit->text() );
mComposerTable->update();
mComposerTable->endCommand();
}
}
}

void QgsComposerTableWidget::changeLayer( QgsMapLayer *layer )
{
if ( !mComposerTable )
{
return;
}

QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( layer );
if ( vl )
{
mComposerTable->beginCommand( tr( "Table layer changed" ) );
mComposerTable->setVectorLayer( vl );
mComposerTable->update();
mComposerTable->endCommand();
}
}
6 changes: 5 additions & 1 deletion src/app/composer/qgscomposertablewidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class QgsComposerTableWidget: public QWidget, private Ui::QgsComposerTableWidget
void refreshMapComboBox();

private slots:
void on_mLayerComboBox_currentIndexChanged( int index );
void on_mAttributesPushButton_clicked();
void on_mComposerMapComboBox_activated( int index );
void on_mMaximumColumnsSpinBox_valueChanged( int i );
Expand All @@ -51,12 +50,17 @@ class QgsComposerTableWidget: public QWidget, private Ui::QgsComposerTableWidget
void on_mContentFontPushButton_clicked();
void on_mShowGridGroupCheckBox_toggled( bool state );
void on_mShowOnlyVisibleFeaturesCheckBox_stateChanged( int state );
void on_mFeatureFilterCheckBox_stateChanged( int state );
void on_mFeatureFilterEdit_editingFinished();
void on_mFeatureFilterButton_clicked();
void changeLayer( QgsMapLayer* layer );

/**Inserts a new maximum number of features into the spin box (without the spinbox emitting a signal)*/
void setMaximumNumberOfFeatures( int n );

/**Sets the GUI elements to the values of mComposerTable*/
void updateGuiElements();

};

#endif // QGSCOMPOSERTABLEWIDGET_H
29 changes: 29 additions & 0 deletions src/core/composer/qgscomposerattributetable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ QgsComposerAttributeTable::QgsComposerAttributeTable( QgsComposition* compositio
, mComposerMap( 0 )
, mMaximumNumberOfFeatures( 5 )
, mShowOnlyVisibleFeatures( true )
, mFilterFeatures( false )
, mFeatureFilter( "" )
{
//set first vector layer from layer registry as default one
QMap<QString, QgsMapLayer*> layerMap = QgsMapLayerRegistry::instance()->mapLayers();
Expand Down Expand Up @@ -128,6 +130,18 @@ bool QgsComposerAttributeTable::getFeatureAttributes( QList<QgsAttributeMap> &at

attributeMaps.clear();

//prepare filter expression
std::auto_ptr<QgsExpression> filterExpression;
bool activeFilter = false;
if ( mFilterFeatures && !mFeatureFilter.isEmpty() )
{
filterExpression = std::auto_ptr<QgsExpression>( new QgsExpression( mFeatureFilter ) );
if ( !filterExpression->hasParserError() )
{
activeFilter = true;
}
}

QgsRectangle selectionRect;
if ( mComposerMap && mShowOnlyVisibleFeatures )
{
Expand Down Expand Up @@ -163,6 +177,17 @@ bool QgsComposerAttributeTable::getFeatureAttributes( QList<QgsAttributeMap> &at

while ( fit.nextFeature( f ) && counter < mMaximumNumberOfFeatures )
{
//check feature against filter
if ( activeFilter )
{
QVariant result = filterExpression->evaluate( &f, mVectorLayer->pendingFields() );
// skip this feature if the filter evaluation if false
if ( !result.toBool() )
{
continue;
}
}

attributeMaps.push_back( QgsAttributeMap() );

for ( int i = 0; i < f.attributes().size(); i++ )
Expand Down Expand Up @@ -242,6 +267,8 @@ bool QgsComposerAttributeTable::writeXML( QDomElement& elem, QDomDocument & doc
QDomElement composerTableElem = doc.createElement( "ComposerAttributeTable" );
composerTableElem.setAttribute( "showOnlyVisibleFeatures", mShowOnlyVisibleFeatures );
composerTableElem.setAttribute( "maxFeatures", mMaximumNumberOfFeatures );
composerTableElem.setAttribute( "filterFeatures", mFilterFeatures ? "true" : "false" );
composerTableElem.setAttribute( "featureFilter", mFeatureFilter );

if ( mComposerMap )
{
Expand Down Expand Up @@ -303,6 +330,8 @@ bool QgsComposerAttributeTable::readXML( const QDomElement& itemElem, const QDom
}

mShowOnlyVisibleFeatures = itemElem.attribute( "showOnlyVisibleFeatures", "1" ).toInt();
mFilterFeatures = itemElem.attribute( "filterFeatures", "false" ) == "true" ? true : false;
mFeatureFilter = itemElem.attribute( "featureFilter", "" );

//composer map
int composerMapId = itemElem.attribute( "composerMap", "-1" ).toInt();
Expand Down
39 changes: 38 additions & 1 deletion src/core/composer/qgscomposerattributetable.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class CORE_EXPORT QgsComposerAttributeTable: public QgsComposerTable
bool readXML( const QDomElement& itemElem, const QDomDocument& doc );

void setVectorLayer( QgsVectorLayer* vl );
const QgsVectorLayer* vectorLayer() const { return mVectorLayer; }
QgsVectorLayer* vectorLayer() const { return mVectorLayer; }

void setComposerMap( const QgsComposerMap* map );
const QgsComposerMap* composerMap() const { return mComposerMap; }
Expand All @@ -65,6 +65,38 @@ class CORE_EXPORT QgsComposerAttributeTable: public QgsComposerTable
void setDisplayOnlyVisibleFeatures( bool b ) { mShowOnlyVisibleFeatures = b; }
bool displayOnlyVisibleFeatures() const { return mShowOnlyVisibleFeatures; }

/*Returns true if a feature filter is active on the attribute table
* @returns bool state of the feature filter
* @note added in 2.3
* @see setFilterFeatures
* @see featureFilter
*/
bool filterFeatures() const { return mFilterFeatures; }
/**Sets whether the feature filter is active for the attribute table
* @param filter Set to true to enable the feature filter
* @note added in 2.3
* @see filterFeatures
* @see setFeatureFilter
*/
void setFilterFeatures( bool filter ) { mFilterFeatures = filter; }

/*Returns the current expression used to filter features for the table. The filter is only
* active if filterFeatures() is true.
* @returns feature filter expression
* @note added in 2.3
* @see setFeatureFilter
* @see filterFeatures
*/
QString featureFilter() const { return mFeatureFilter; }
/**Sets the expression used for filtering features in the table. The filter is only
* active if filterFeatures() is set to true.
* @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 ) { mFeatureFilter = expression; }

QSet<int> displayAttributes() const { return mDisplayAttributes; }
void setDisplayAttributes( const QSet<int>& attr ) { mDisplayAttributes = attr; }

Expand Down Expand Up @@ -100,6 +132,11 @@ class CORE_EXPORT QgsComposerAttributeTable: public QgsComposerTable
/**Shows only the features that are visible in the associated composer map (true by default)*/
bool mShowOnlyVisibleFeatures;

// feature filtering
bool mFilterFeatures;
// feature expression filter
QString mFeatureFilter;

/**List of attribute indices to display (or all attributes if list is empty)*/
QSet<int> mDisplayAttributes;
/**Map of attribute name aliases. The aliases might be different to those of QgsVectorLayer (but those from the vector layer are the default)*/
Expand Down
Loading