Allow hiding empty layers in sublayers dialog (#49870)

* Sublayers dialog improvements

* added tests

* fix flake

* check against DisplayRole instead of EditRole
This commit is contained in:
Stefanos Natsis 2022-10-21 13:53:49 +03:00 committed by GitHub
parent 2648667b59
commit ba97282dd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 137 additions and 25 deletions

View File

@ -257,6 +257,24 @@ Returns ``True`` if system and internal tables will be shown in the model.
Sets whether system and internal tables will be shown in the model.
.. seealso:: :py:func:`includeSystemTables`
%End
bool includeEmptyLayers() const;
%Docstring
Returns ``True`` if empty tables will be shown in the model.
.. seealso:: :py:func:`setIncludeEmptyLayers`
.. versionadded:: 3.28
%End
void setIncludeEmptyLayers( bool include );
%Docstring
Sets whether empty tables will be shown in the model.
.. seealso:: :py:func:`includeEmptyLayers`
.. versionadded:: 3.28
%End
protected:

View File

@ -190,6 +190,7 @@ QgsProviderSublayersDialog::QgsProviderSublayersDialog( const QString &uri, cons
connect( mLayersTree->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsProviderSublayersDialog::treeSelectionChanged );
connect( mSearchLineEdit, &QgsFilterLineEdit::textChanged, mProxyModel, &QgsProviderSublayerProxyModel::setFilterString );
connect( mCheckShowSystem, &QCheckBox::toggled, mProxyModel, &QgsProviderSublayerProxyModel::setIncludeSystemTables );
connect( mCheckShowEmpty, &QCheckBox::toggled, mProxyModel, &QgsProviderSublayerProxyModel::setIncludeEmptyLayers );
connect( mLayersTree, &QTreeView::doubleClicked, this, [ = ]( const QModelIndex & index )
{
const QModelIndex left = mLayersTree->model()->index( index.row(), 0, index.parent() );

View File

@ -656,13 +656,18 @@ bool QgsProviderSublayerProxyModel::filterAcceptsRow( int source_row, const QMod
if ( !mIncludeSystemTables && static_cast< Qgis::SublayerFlags >( sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::Flags ) ).toInt() ) & Qgis::SublayerFlag::SystemTable )
return false;
if ( !mIncludeEmptyLayers && sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::FeatureCount ) ) == 0 )
return false;
if ( mFilterString.trimmed().isEmpty() )
return true;
if ( sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::Name ) ).toString().contains( mFilterString, Qt::CaseInsensitive ) )
return true;
if ( sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::Description ) ).toString().contains( mFilterString, Qt::CaseInsensitive ) )
// check against the Description column's display role as it might be different from QgsProviderSublayerModel::Role::Description
const QModelIndex descriptionColumnIndex = sourceModel()->index( source_row, 1, source_parent );
if ( sourceModel()->data( descriptionColumnIndex, static_cast< int >( Qt::DisplayRole ) ).toString().contains( mFilterString, Qt::CaseInsensitive ) )
return true;
const QVariant wkbTypeVariant = sourceModel()->data( sourceIndex, static_cast< int >( QgsProviderSublayerModel::Role::WkbType ) );
@ -703,6 +708,17 @@ void QgsProviderSublayerProxyModel::setIncludeSystemTables( bool include )
invalidateFilter();
}
bool QgsProviderSublayerProxyModel::includeEmptyLayers() const
{
return mIncludeEmptyLayers;
}
void QgsProviderSublayerProxyModel::setIncludeEmptyLayers( bool include )
{
mIncludeEmptyLayers = include;
invalidateFilter();
}
QString QgsProviderSublayerProxyModel::filterString() const
{
return mFilterString;

View File

@ -415,6 +415,22 @@ class CORE_EXPORT QgsProviderSublayerProxyModel: public QSortFilterProxyModel
*/
void setIncludeSystemTables( bool include );
/**
* Returns TRUE if empty tables will be shown in the model.
*
* \see setIncludeEmptyLayers()
* \since QGIS 3.28
*/
bool includeEmptyLayers() const;
/**
* Sets whether empty tables will be shown in the model.
*
* \see includeEmptyLayers()
* \since QGIS 3.28
*/
void setIncludeEmptyLayers( bool include );
protected:
bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const override;
bool lessThan( const QModelIndex &source_left, const QModelIndex &source_right ) const override;
@ -423,6 +439,7 @@ class CORE_EXPORT QgsProviderSublayerProxyModel: public QSortFilterProxyModel
QString mFilterString;
bool mIncludeSystemTables = false;
bool mIncludeEmptyLayers = true;
};

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>584</width>
<height>236</height>
<height>311</height>
</rect>
</property>
<property name="windowTitle">
@ -29,7 +29,7 @@
<property name="spacing">
<number>6</number>
</property>
<item row="7" column="0">
<item row="6" column="0">
<widget class="QDialogButtonBox" name="mButtonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -83,11 +83,40 @@
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="mCheckShowSystem">
<property name="text">
<string>Show system and internal tables</string>
<item row="5" column="0">
<widget class="QgsCollapsibleGroupBox" name="groupBox">
<property name="title">
<string>Options</string>
</property>
<property name="collapsed" stdset="0">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="mCbxAddToGroup">
<property name="text">
<string>Add layers to a group</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="mCheckShowSystem">
<property name="text">
<string>Show system and internal tables</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="mCheckShowEmpty">
<property name="text">
<string>Show empty vector layers</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
@ -120,17 +149,16 @@
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="mCbxAddToGroup">
<property name="text">
<string>Add layers to a group</string>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QgsCollapsibleGroupBox</class>
<extends>QGroupBox</extends>
<header>qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsFilterLineEdit</class>
<extends>QLineEdit</extends>
@ -142,8 +170,6 @@
<tabstop>mLayersTree</tabstop>
<tabstop>mBtnSelectAll</tabstop>
<tabstop>mBtnDeselectAll</tabstop>
<tabstop>mCbxAddToGroup</tabstop>
<tabstop>mCheckShowSystem</tabstop>
</tabstops>
<resources/>
<connections/>

View File

@ -502,7 +502,16 @@ class TestQgsProviderSublayerModel(unittest.TestCase):
layer2.setFeatureCount(-1)
layer2.setWkbType(QgsWkbTypes.LineString)
model.setSublayerDetails([layer1, layer2])
layer3 = QgsProviderSublayerDetails()
layer3.setType(QgsMapLayerType.VectorLayer)
layer3.setName('yet another layer 3')
layer3.setDescription('an empty layer')
layer3.setProviderKey('ogr')
layer3.setUri('uri 3')
layer3.setFeatureCount(0)
layer3.setWkbType(QgsWkbTypes.Polygon)
model.setSublayerDetails([layer1, layer2, layer3])
item1 = QgsProviderSublayerModel.NonLayerItem()
item1.setUri('item uri 1')
@ -512,7 +521,7 @@ class TestQgsProviderSublayerModel(unittest.TestCase):
model.addNonLayerItem(item1)
self.assertEqual(proxy.rowCount(QModelIndex()), 3)
self.assertEqual(proxy.rowCount(QModelIndex()), 4)
self.assertEqual(proxy.data(proxy.index(0, 0), Qt.DisplayRole), 'item name 1')
self.assertEqual(proxy.data(proxy.index(0, 1), Qt.DisplayRole), 'item desc 1')
@ -539,6 +548,15 @@ class TestQgsProviderSublayerModel(unittest.TestCase):
self.assertEqual(proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.Description), 'description 1')
self.assertEqual(proxy.data(proxy.index(2, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), False)
self.assertEqual(proxy.data(proxy.index(3, 0), Qt.DisplayRole), 'yet another layer 3')
self.assertEqual(proxy.data(proxy.index(3, 1), Qt.DisplayRole), 'an empty layer - Polygon (0)')
self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.ProviderKey), 'ogr')
self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.LayerType), QgsMapLayerType.VectorLayer)
self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.Uri), 'uri 3')
self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.Name), 'yet another layer 3')
self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.Description), 'an empty layer')
self.assertEqual(proxy.data(proxy.index(3, 0), QgsProviderSublayerModel.Role.IsNonLayerItem), False)
proxy.setFilterString(' 1')
self.assertEqual(proxy.rowCount(QModelIndex()), 2)
self.assertEqual(proxy.data(proxy.index(0, 0), Qt.DisplayRole), 'item name 1')
@ -557,26 +575,42 @@ class TestQgsProviderSublayerModel(unittest.TestCase):
self.assertEqual(proxy.rowCount(QModelIndex()), 1)
self.assertEqual(proxy.data(proxy.index(0, 0), Qt.DisplayRole), 'another layer 2')
# should also allow filtering by the feature count as it appears in the description too but it's not in the description role
proxy.setFilterString('0')
self.assertEqual(proxy.rowCount(QModelIndex()), 1)
self.assertEqual(proxy.data(proxy.index(0, 0), Qt.DisplayRole), 'yet another layer 3')
proxy.setFilterString('')
self.assertEqual(proxy.rowCount(QModelIndex()), 3)
self.assertEqual(proxy.rowCount(QModelIndex()), 4)
self.assertEqual(proxy.data(proxy.index(0, 0), Qt.DisplayRole), 'item name 1')
self.assertEqual(proxy.data(proxy.index(1, 0), Qt.DisplayRole), 'another layer 2')
self.assertEqual(proxy.data(proxy.index(2, 0), Qt.DisplayRole), 'layer 1')
self.assertEqual(proxy.data(proxy.index(3, 0), Qt.DisplayRole), 'yet another layer 3')
# add a system table
layer3 = QgsProviderSublayerDetails()
layer3.setType(QgsMapLayerType.VectorLayer)
layer3.setName('system table')
layer3.setFlags(Qgis.SublayerFlags(Qgis.SublayerFlag.SystemTable))
layer_system = QgsProviderSublayerDetails()
layer_system.setType(QgsMapLayerType.VectorLayer)
layer_system.setName('system table')
layer_system.setFlags(Qgis.SublayerFlags(Qgis.SublayerFlag.SystemTable))
model.setSublayerDetails([layer1, layer2, layer3])
model.setSublayerDetails([layer1, layer2, layer3, layer_system])
# system tables should be hidden by default
self.assertEqual(proxy.rowCount(QModelIndex()), 3)
self.assertEqual(proxy.rowCount(QModelIndex()), 4)
self.assertEqual(proxy.data(proxy.index(0, 0), Qt.DisplayRole), 'item name 1')
self.assertEqual(proxy.data(proxy.index(1, 0), Qt.DisplayRole), 'another layer 2')
self.assertEqual(proxy.data(proxy.index(2, 0), Qt.DisplayRole), 'layer 1')
self.assertEqual(proxy.data(proxy.index(3, 0), Qt.DisplayRole), 'yet another layer 3')
proxy.setIncludeSystemTables(True)
self.assertEqual(proxy.rowCount(QModelIndex()), 5)
self.assertEqual(proxy.data(proxy.index(0, 0), Qt.DisplayRole), 'item name 1')
self.assertEqual(proxy.data(proxy.index(1, 0), Qt.DisplayRole), 'another layer 2')
self.assertEqual(proxy.data(proxy.index(2, 0), Qt.DisplayRole), 'layer 1')
self.assertEqual(proxy.data(proxy.index(3, 0), Qt.DisplayRole), 'system table')
self.assertEqual(proxy.data(proxy.index(4, 0), Qt.DisplayRole), 'yet another layer 3')
# hide empty vector layers
proxy.setIncludeEmptyLayers(False)
self.assertEqual(proxy.rowCount(QModelIndex()), 4)
self.assertEqual(proxy.data(proxy.index(0, 0), Qt.DisplayRole), 'item name 1')
self.assertEqual(proxy.data(proxy.index(1, 0), Qt.DisplayRole), 'another layer 2')