[feature][ui] Add a Show in Attribute Table action to the right click menu of legend class symbols (#49984)

This commit is contained in:
Mathieu Pellerin 2022-08-29 17:18:06 +07:00 committed by GitHub
parent ec51684f06
commit b7e31d4508
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 95 additions and 8 deletions

View File

@ -220,6 +220,12 @@ need to be filtered again (like on filter or on main model data change).
.. versionadded:: 3.10.3
%End
QString filterExpression() const;
%Docstring
Returns the stored filter expression string.
.. versionadded:: 3.28.0
%End
signals:
void sortColumnChanged( int column, Qt::SortOrder order );

View File

@ -7747,7 +7747,7 @@ void QgisApp::fieldCalculator()
}
}
void QgisApp::attributeTable( QgsAttributeTableFilterModel::FilterMode filter )
void QgisApp::attributeTable( QgsAttributeTableFilterModel::FilterMode filter, const QString &filterExpression )
{
QgsVectorLayer *myLayer = qobject_cast<QgsVectorLayer *>( activeLayer() );
if ( !myLayer || !myLayer->dataProvider() )
@ -7755,7 +7755,7 @@ void QgisApp::attributeTable( QgsAttributeTableFilterModel::FilterMode filter )
return;
}
QgsAttributeTableDialog *mDialog = new QgsAttributeTableDialog( myLayer, filter );
QgsAttributeTableDialog *mDialog = new QgsAttributeTableDialog( myLayer, filter, nullptr, Qt::Window, nullptr, filterExpression );
mDialog->show();
// the dialog will be deleted by itself on close
}

View File

@ -934,7 +934,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void layerProperties();
//! show the attribute table for the currently selected layer
void attributeTable( QgsAttributeTableFilterModel::FilterMode filter = QgsAttributeTableFilterModel::ShowAll );
void attributeTable( QgsAttributeTableFilterModel::FilterMode filter = QgsAttributeTableFilterModel::ShowAll, const QString &filterExpression = QString() );
void fieldCalculator();

View File

@ -802,7 +802,6 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
{
QAction *selectMatching = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mIconSelected.svg" ) ), tr( "Select Features" ), menu );
menu->addAction( selectMatching );
menu->addSeparator();
connect( selectMatching, &QAction::triggered, this, [layerId, ruleKey ]
{
if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProject::instance()->mapLayer( layerId ) ) )
@ -836,6 +835,29 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
}
}
} );
QAction *showMatchingInAttributeTable = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/attributes.svg" ) ), tr( "Show in Attribute Table" ), menu );
menu->addAction( showMatchingInAttributeTable );
connect( showMatchingInAttributeTable, &QAction::triggered, this, [layerId, ruleKey ]
{
if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProject::instance()->mapLayer( layerId ) ) )
{
bool ok = false;
QString filterExp = layer->renderer() ? layer->renderer()->legendKeyToExpression( ruleKey, layer, ok ) : QString();
if ( ok )
{
const QString canvasFilter = QgsMapCanvasUtils::filterForLayer( QgisApp::instance()->mapCanvas(), layer );
if ( canvasFilter == QLatin1String( "FALSE" ) )
return;
else if ( !canvasFilter.isEmpty() )
filterExp = QStringLiteral( "(%1) AND (%2)" ).arg( filterExp, canvasFilter );
QgisApp::instance()->attributeTable( QgsAttributeTableFilterModel::ShowFilteredList, filterExp );
}
}
} );
menu->addSeparator();
}
if ( layer && layer->type() == QgsMapLayerType::VectorLayer && symbolNode->symbol() )

View File

@ -108,7 +108,7 @@ void QgsAttributeTableDialog::updateMultiEditButtonState()
}
}
QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttributeTableFilterModel::FilterMode initialMode, QWidget *parent, Qt::WindowFlags flags, bool *initiallyDocked )
QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttributeTableFilterModel::FilterMode initialMode, QWidget *parent, Qt::WindowFlags flags, bool *initiallyDocked, const QString &filterExpression )
: QDialog( parent, flags )
, mLayer( layer )
{
@ -221,6 +221,10 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttr
{
r.setFilterFids( layer->editBuffer() ? layer->editBuffer()->allAddedOrEditedFeatures() : QgsFeatureIds() );
}
else if ( !filterExpression.isEmpty() )
{
r.setFilterExpression( filterExpression );
}
if ( !needsGeom )
r.setFlags( QgsFeatureRequest::NoGeometry );
@ -385,6 +389,10 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttr
mFeatureFilterWidget->filterEdited();
break;
case QgsAttributeTableFilterModel::ShowFilteredList:
mFeatureFilterWidget->setFilterExpression( filterExpression );
break;
case QgsAttributeTableFilterModel::ShowAll:
default:
mFeatureFilterWidget->filterShowAll();

View File

@ -53,8 +53,12 @@ class APP_EXPORT QgsAttributeTableDialog : public QDialog, private Ui::QgsAttrib
* \param parent parent object
* \param flags window flags
*/
QgsAttributeTableDialog( QgsVectorLayer *layer, QgsAttributeTableFilterModel::FilterMode initialMode = QgsAttributeTableFilterModel::ShowAll, QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::Window,
bool *initiallyDocked = nullptr );
QgsAttributeTableDialog( QgsVectorLayer *layer,
QgsAttributeTableFilterModel::FilterMode initialMode = QgsAttributeTableFilterModel::ShowAll,
QWidget *parent = nullptr,
Qt::WindowFlags flags = Qt::Window,
bool *initiallyDocked = nullptr,
const QString &filterExpression = QString() );
~QgsAttributeTableDialog() override;
QgsExpressionContext createExpressionContext() const override;

View File

@ -251,6 +251,13 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
*/
void setFilterExpression( const QgsExpression &expression, const QgsExpressionContext &context );
/**
* Returns the stored filter expression string.
*
* \since QGIS 3.28.0
*/
QString filterExpression() const { return mFilterExpression; };
signals:
/**

View File

@ -361,9 +361,14 @@ void QgsDualView::setFilterMode( QgsAttributeTableFilterModel::FilterMode filter
case QgsAttributeTableFilterModel::ShowAll:
case QgsAttributeTableFilterModel::ShowFilteredList:
{
const QString filterExpression = filterMode == QgsAttributeTableFilterModel::ShowFilteredList ? mFilterModel->filterExpression() : QString();
if ( !filterExpression.isEmpty() )
r.setFilterExpression( mFilterModel->filterExpression() );
connect( mFilterModel, &QgsAttributeTableFilterModel::featuresFiltered, this, &QgsDualView::filterChanged );
connect( mFilterModel, &QgsAttributeTableFilterModel::filterError, this, &QgsDualView::filterError );
break;
}
case QgsAttributeTableFilterModel::ShowSelected:
connect( masterModel()->layer(), &QgsVectorLayer::selectionChanged, this, &QgsDualView::updateSelectedFeatures );

View File

@ -462,7 +462,6 @@ void QgsFeatureFilterWidget::setFilterExpression( const QString &filterString, Q
}
mMainView->filterFeatures( filterExpression, context );
mMainView->setFilterMode( QgsAttributeTableFilterModel::ShowFilteredList );
}

View File

@ -61,6 +61,7 @@ class TestQgsAttributeTable : public QObject
void testSortByDisplayExpression();
void testOrderColumn();
void testFilteredFeatures();
void testOpenWithFilterExpression();
void testVisibleTemporal();
void testCopySelectedRows();
void testSortNumbers();
@ -757,5 +758,40 @@ void TestQgsAttributeTable::testCopySelectedRows()
QCOMPARE( clipboard->crs().authid(), "EPSG:3111" );
}
void TestQgsAttributeTable::testOpenWithFilterExpression()
{
// test attribute table opening in show feature visible mode
std::unique_ptr< QgsVectorLayer> tempLayer( new QgsVectorLayer( QStringLiteral( "LineString?crs=epsg:4326&field=pk:int&field=col1:date" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
QVERIFY( tempLayer->isValid() );
QgsPolylineXY line;
line << QgsPointXY( 0, 0 ) << QgsPointXY( 1, 1 );
QgsGeometry geometry = QgsGeometry::fromPolylineXY( line ) ;
QgsFeature f1( tempLayer->dataProvider()->fields(), 1 );
f1.setGeometry( geometry );
f1.setAttributes( QgsAttributes() << 1 << QDate( 2020, 1, 1 ) );
QgsFeature f2( tempLayer->dataProvider()->fields(), 2 );
f2.setGeometry( geometry );
f2.setAttributes( QgsAttributes() << 2 << QDate( 2020, 3, 1 ) );
QgsFeature f3( tempLayer->dataProvider()->fields(), 3 );
line.clear();
line << QgsPointXY( -3, -3 ) << QgsPointXY( -2, -2 );
geometry = QgsGeometry::fromPolylineXY( line );
f3.setGeometry( geometry );
f3.setAttributes( QgsAttributes() << 3 << QDate( 2020, 1, 1 ) );
QVERIFY( tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 ) );
const QString filterExpression = QStringLiteral( "col1 < to_date('2020-02-03')" );
std::unique_ptr< QgsAttributeTableDialog > dlg( new QgsAttributeTableDialog( tempLayer.get(),
QgsAttributeTableFilterModel::ShowFilteredList,
nullptr,
Qt::Window,
nullptr,
filterExpression ) );
// feature id 2 is filtered out due not matching the provided filter expression
QCOMPARE( dlg->mMainView->filteredFeatures(), QgsFeatureIds() << 1 << 3 );
}
QGSTEST_MAIN( TestQgsAttributeTable )
#include "testqgsattributetable.moc"