Skip to content

Commit b42bddd

Browse files
committedMar 10, 2020
New database table widget new signals & tests
1 parent d1404ac commit b42bddd

File tree

4 files changed

+170
-67
lines changed

4 files changed

+170
-67
lines changed
 

‎python/gui/auto_generated/qgsnewdatabasetablenamewidget.sip.in

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ The table name is validated for uniqueness and the selected
2020
data item provider, schema and table names can be retrieved with
2121
getters.
2222

23+
.. warning::
24+
25+
The data provider that originated the data item provider
26+
must support the connections API
27+
2328
.. versionadded:: 3.14
2429
%End
2530

@@ -35,8 +40,9 @@ getters.
3540
Constructs a new QgsNewDatabaseTableNameWidget
3641

3742
:param browserModel: an existing browser model (typically from app), if NULL an instance will be created
38-
:param providersFilter: optional white list of item provider names (not data providers!) that should be
39-
shown in the widget, if not specified all providers data items with database capabilities will be shown
43+
:param providersFilter: optional white list of data provider keys that should be
44+
shown in the widget, if not specified all providers data items with database
45+
capabilities will be shown
4046
:param parent: optional parent for this widget
4147
%End
4248

@@ -50,9 +56,9 @@ Returns the currently selected schema for the new table
5056
Returns the current name of the new table
5157
%End
5258

53-
QString dataItemProviderName();
59+
QString dataProviderKey();
5460
%Docstring
55-
Returns the currently selected data item provider name (which is NOT the data provider key!) for the new table
61+
Returns the currently selected data item provider key
5662
%End
5763

5864
bool isValid() const;
@@ -88,6 +94,14 @@ This signal is emitted when the user enters a table name
8894
:param tableName: the name of the new table
8995
%End
9096

97+
void providerKeyChanged( const QString &providerKey );
98+
%Docstring
99+
This signal is emitted when the selects a data provider or a schema name
100+
that has a different data provider than the previously selected one.
101+
102+
:param providerKey: the data provider key of the selected schema
103+
%End
104+
91105

92106
};
93107

‎src/gui/qgsnewdatabasetablenamewidget.cpp

Lines changed: 89 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "qgsapplication.h"
2121
#include "qgsdataitemproviderregistry.h"
2222
#include "qgsdataitemprovider.h"
23+
#include "qgsproviderregistry.h"
24+
#include "qgsprovidermetadata.h"
2325

2426
QgsNewDatabaseTableNameWidget::QgsNewDatabaseTableNameWidget(
2527
QgsBrowserGuiModel *browserModel,
@@ -28,7 +30,6 @@ QgsNewDatabaseTableNameWidget::QgsNewDatabaseTableNameWidget(
2830
: QWidget( parent )
2931
{
3032

31-
3233
// Initalize the browser
3334
if ( ! browserModel )
3435
{
@@ -43,6 +44,8 @@ QgsNewDatabaseTableNameWidget::QgsNewDatabaseTableNameWidget(
4344

4445
setupUi( this );
4546

47+
mValidationResults->setStyleSheet( QStringLiteral( "* { font-weight: bold; color: red; }" ) );
48+
4649
QStringList hiddenProviders
4750
{
4851
QStringLiteral( "special:Favorites" ),
@@ -55,15 +58,26 @@ QgsNewDatabaseTableNameWidget::QgsNewDatabaseTableNameWidget(
5558
const auto providerList { QgsApplication::dataItemProviderRegistry()->providers() };
5659
for ( const auto &provider : providerList )
5760
{
61+
if ( provider->dataProviderKey().isEmpty() )
62+
{
63+
hiddenProviders.push_back( provider->name() );
64+
continue;
65+
}
66+
QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( provider->dataProviderKey() ) };
67+
if ( ! md )
68+
{
69+
hiddenProviders.push_back( provider->name() );
70+
continue;
71+
}
5872
if ( provider->capabilities() & QgsDataProvider::DataCapability::Database )
5973
{
60-
if ( ! providersFilter.isEmpty() && ! providersFilter.contains( provider->name() ) )
74+
if ( ! providersFilter.isEmpty() && ! providersFilter.contains( provider->dataProviderKey() ) )
6175
{
6276
hiddenProviders.push_back( provider->name() );
6377
}
6478
else
6579
{
66-
mShownProviders.insert( provider->name() );
80+
mShownProviders.insert( provider->dataProviderKey() );
6781
}
6882
}
6983
else
@@ -98,26 +112,41 @@ QgsNewDatabaseTableNameWidget::QgsNewDatabaseTableNameWidget(
98112
const QgsDataCollectionItem *collectionItem = qobject_cast<const QgsDataCollectionItem *>( dataItem );
99113
if ( collectionItem )
100114
{
101-
if ( mShownProviders.contains( collectionItem->name() ) )
115+
const QString providerKey { QgsApplication::dataItemProviderRegistry()->dataProviderKey( dataItem->providerKey() ) };
116+
if ( mShownProviders.contains( providerKey ) )
102117
{
103-
if ( mDataProviderName != collectionItem->name() )
118+
bool validationRequired { false };
119+
const QString oldSchema { mSchemaName };
120+
121+
if ( mDataProviderKey != providerKey )
104122
{
105123
mSchemaName.clear();
106-
mDataProviderName = collectionItem->name();
124+
emit providerKeyChanged( providerKey );
125+
mDataProviderKey = providerKey;
126+
validate();
127+
}
128+
129+
if ( collectionItem->layerCollection( ) )
130+
{
131+
mSchemaName = collectionItem->name(); // it may be cleared
132+
if ( oldSchema != collectionItem->name() )
133+
{
134+
emit schemaNameChanged( mSchemaName );
135+
validationRequired = true;
136+
}
137+
}
138+
139+
if ( validationRequired )
140+
{
141+
validate();
107142
}
108143
}
109-
else
110-
{
111-
mSchemaName = collectionItem->name();
112-
emit schemaNameChanged( mSchemaName );
113-
}
114-
validate();
115144
}
116145
}
117146
}
118147
} );
119148

120-
mValidationResults->hide();
149+
validate();
121150

122151
}
123152

@@ -131,16 +160,17 @@ QString QgsNewDatabaseTableNameWidget::table()
131160
return mTableName;
132161
}
133162

134-
QString QgsNewDatabaseTableNameWidget::dataItemProviderName()
163+
QString QgsNewDatabaseTableNameWidget::dataProviderKey()
135164
{
136-
return mDataProviderName;
165+
return mDataProviderKey;
137166
}
138167

139168
void QgsNewDatabaseTableNameWidget::validate()
140169
{
170+
const bool wasValid { mIsValid };
141171
// Check table uniqueness
142-
mIsValid = ! mDataProviderName.isEmpty() &&
143-
mShownProviders.contains( mDataProviderName ) &&
172+
mIsValid = ! mDataProviderKey.isEmpty() &&
173+
mShownProviders.contains( mDataProviderKey ) &&
144174
! mSchemaName.isEmpty() &&
145175
! mTableName.isEmpty() &&
146176
! tableNames( ).contains( mTableName );
@@ -149,27 +179,39 @@ void QgsNewDatabaseTableNameWidget::validate()
149179

150180
if ( ! mIsValid )
151181
{
152-
153-
if ( mTableName.isEmpty() )
182+
if ( mTableName.isEmpty() && mSchemaName.isEmpty() )
154183
{
155-
mValidationError = tr( "Enter a unique name for the new table" );
184+
mValidationError = tr( "Select a database schema and enter a unique name for the new table" );
185+
}
186+
else if ( ! mTableName.isEmpty() &&
187+
! mSchemaName.isEmpty() &&
188+
tableNames( ).contains( mTableName ) )
189+
{
190+
mValidationError = tr( "A table named '%1' already exists" ).arg( mTableName );
156191
}
157192
else if ( mSchemaName.isEmpty() )
158193
{
159194
mValidationError = tr( "Select a database schema" );
160195
}
196+
else if ( mTableName.isEmpty() )
197+
{
198+
mValidationError = tr( "Enter a unique name for the new table" );
199+
}
161200
else if ( tableNames( ).contains( mTableName ) )
162201
{
163202
mValidationError = tr( "A table named '%1' already exists" ).arg( mTableName );
164203
}
165204
else
166205
{
167-
mValidationError = tr( "Select a schema and enter a unique name for the new table" );
206+
mValidationError = tr( "Select a database schema and enter a unique name for the new table" );
168207
}
169208
}
170209
mValidationResults->setText( mValidationError );
171210
mValidationResults->setVisible( ! mIsValid );
172-
emit validationChanged( mIsValid );
211+
if ( wasValid != mIsValid )
212+
{
213+
emit validationChanged( mIsValid );
214+
}
173215
}
174216

175217
QStringList QgsNewDatabaseTableNameWidget::tableNames()
@@ -178,16 +220,34 @@ QStringList QgsNewDatabaseTableNameWidget::tableNames()
178220
QModelIndex index { mBrowserTreeView->currentIndex() };
179221
if ( index.isValid() )
180222
{
181-
for ( int row = 0; row < mBrowserProxyModel.rowCount( ); ++row )
223+
QgsDataItem *dataItem { mBrowserProxyModel.dataItem( index ) };
224+
if ( dataItem )
182225
{
183-
// Column 1 contains the
184-
index = mBrowserProxyModel.index( row, 1, index );
185-
if ( index.isValid() )
226+
const QString dataProviderKey { QgsApplication::dataItemProviderRegistry()->dataProviderKey( dataItem->providerKey() ) };
227+
if ( ! dataProviderKey.isEmpty() )
186228
{
187-
const QgsDataItem *dataItem { mBrowserProxyModel.dataItem( index ) };
188-
if ( dataItem )
229+
QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( dataProviderKey ) };
230+
if ( md )
189231
{
190-
tableNames.push_back( dataItem->name() );
232+
QgsDataItem *parentDataItem { dataItem->parent() };
233+
if ( parentDataItem )
234+
{
235+
QgsAbstractProviderConnection *conn { md->findConnection( parentDataItem->name() ) };
236+
const QString cacheKey { conn->uri() + dataItem->name() };
237+
if ( mTableNamesCache.contains( cacheKey ) )
238+
{
239+
tableNames = mTableNamesCache.value( cacheKey );
240+
}
241+
else if ( conn && static_cast<QgsAbstractDatabaseProviderConnection *>( conn ) )
242+
{
243+
const auto tables { static_cast<QgsAbstractDatabaseProviderConnection *>( conn )->tables( dataItem->name() ) };
244+
for ( const auto &tp : tables )
245+
{
246+
tableNames.push_back( tp.tableName() );
247+
}
248+
mTableNamesCache[ cacheKey ] = tableNames;
249+
}
250+
}
191251
}
192252
}
193253
}

‎src/gui/qgsnewdatabasetablenamewidget.h

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
* data item provider, schema and table names can be retrieved with
3535
* getters.
3636
*
37+
* \warning The data provider that originated the data item provider
38+
* must support the connections API
39+
*
3740
* \since QGIS 3.14
3841
*/
3942
class GUI_EXPORT QgsNewDatabaseTableNameWidget : public QWidget, private Ui::QgsNewDatabaseTableNameWidget
@@ -46,8 +49,9 @@ class GUI_EXPORT QgsNewDatabaseTableNameWidget : public QWidget, private Ui::Qgs
4649
* Constructs a new QgsNewDatabaseTableNameWidget
4750
*
4851
* \param browserModel an existing browser model (typically from app), if NULL an instance will be created
49-
* \param providersFilter optional white list of item provider names (not data providers!) that should be
50-
* shown in the widget, if not specified all providers data items with database capabilities will be shown
52+
* \param providersFilter optional white list of data provider keys that should be
53+
* shown in the widget, if not specified all providers data items with database
54+
* capabilities will be shown
5155
* \param parent optional parent for this widget
5256
*/
5357
explicit QgsNewDatabaseTableNameWidget( QgsBrowserGuiModel *browserModel = nullptr,
@@ -65,9 +69,9 @@ class GUI_EXPORT QgsNewDatabaseTableNameWidget : public QWidget, private Ui::Qgs
6569
QString table();
6670

6771
/**
68-
* Returns the currently selected data item provider name (which is NOT the data provider key!) for the new table
72+
* Returns the currently selected data item provider key
6973
*/
70-
QString dataItemProviderName();
74+
QString dataProviderKey();
7175

7276
/**
7377
* Returns TRUE if the widget contains a valid new table name
@@ -102,19 +106,31 @@ class GUI_EXPORT QgsNewDatabaseTableNameWidget : public QWidget, private Ui::Qgs
102106
*/
103107
void tableNameChanged( const QString &tableName );
104108

109+
/**
110+
* This signal is emitted when the selects a data provider or a schema name
111+
* that has a different data provider than the previously selected one.
112+
*
113+
* \param providerKey the data provider key of the selected schema
114+
*/
115+
void providerKeyChanged( const QString &providerKey );
116+
105117

106118
private:
107119

108120
QgsBrowserProxyModel mBrowserProxyModel;
109121
QgsBrowserGuiModel *mBrowserModel = nullptr;
110122
void validate();
111123
QStringList tableNames();
112-
QString mDataProviderName;
124+
QString mDataProviderKey;
113125
QString mTableName;
114126
QString mSchemaName;
127+
//! List of data provider keys of shown providers
115128
QSet<QString> mShownProviders;
116129
bool mIsValid = false;
117130
QString mValidationError;
131+
//! Table names cache
132+
QMap<QString, QStringList> mTableNamesCache;
133+
118134

119135
// For testing:
120136
friend class TestQgsNewDatabaseTableNameWidget;

‎tests/src/gui/testqgsnewdatabasetablewidget.cpp

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ class TestQgsNewDatabaseTableNameWidget: public QObject
3030
public:
3131
TestQgsNewDatabaseTableNameWidget() = default;
3232

33-
void testWidget();
34-
3533
private slots:
3634
void initTestCase(); // will be called before the first testfunction is executed.
3735
void cleanupTestCase(); // will be called after the last testfunction was executed.
@@ -74,14 +72,14 @@ void TestQgsNewDatabaseTableNameWidget::testWidgetFilters()
7472
QCOMPARE( w->mBrowserProxyModel.rowCount(), 0 );
7573
std::unique_ptr<QgsNewDatabaseTableNameWidget> w2 { qgis::make_unique<QgsNewDatabaseTableNameWidget>( nullptr ) };
7674
QVERIFY( w2->mBrowserProxyModel.rowCount() > 0 );
77-
std::unique_ptr<QgsNewDatabaseTableNameWidget> w3 { qgis::make_unique<QgsNewDatabaseTableNameWidget>( nullptr, QStringList{ "PostGIS" } ) };
75+
std::unique_ptr<QgsNewDatabaseTableNameWidget> w3 { qgis::make_unique<QgsNewDatabaseTableNameWidget>( nullptr, QStringList{ "postgres" } ) };
7876
QVERIFY( w3->mBrowserProxyModel.rowCount() > 0 );
7977
}
8078

8179

8280
void TestQgsNewDatabaseTableNameWidget::testWidgetSignals()
8381
{
84-
std::unique_ptr<QgsNewDatabaseTableNameWidget> w { qgis::make_unique<QgsNewDatabaseTableNameWidget>( nullptr, QStringList{ "PostGIS" } ) };
82+
std::unique_ptr<QgsNewDatabaseTableNameWidget> w { qgis::make_unique<QgsNewDatabaseTableNameWidget>( nullptr, QStringList{ "postgres" } ) };
8583

8684
auto index = w->mBrowserModel->findPath( QStringLiteral( "pg:/PG_1" ) );
8785
QVERIFY( index.isValid() );
@@ -93,6 +91,7 @@ void TestQgsNewDatabaseTableNameWidget::testWidgetSignals()
9391
QSignalSpy validationSpy( w.get(), SIGNAL( validationChanged( bool ) ) );
9492
QSignalSpy schemaSpy( w.get(), SIGNAL( schemaNameChanged( QString ) ) );
9593
QSignalSpy tableSpy( w.get(), SIGNAL( tableNameChanged( QString ) ) );
94+
QSignalSpy providerSpy( w.get(), SIGNAL( providerKeyChanged( QString ) ) );
9695

9796
index = w->mBrowserProxyModel.mapToSource( w->mBrowserProxyModel.index( 0, 0 ) );
9897
QVERIFY( index.isValid() );
@@ -103,10 +102,12 @@ void TestQgsNewDatabaseTableNameWidget::testWidgetSignals()
103102

104103
QVERIFY( ! w->isValid() );
105104

106-
QCOMPARE( validationSpy.count(), 1 );
107-
auto arguments = validationSpy.takeLast();
108-
QCOMPARE( arguments.at( 0 ).toBool(), false );
105+
QCOMPARE( providerSpy.count(), 1 );
106+
QCOMPARE( tableSpy.count(), 0 );
109107
QCOMPARE( schemaSpy.count(), 0 );
108+
QCOMPARE( validationSpy.count(), 0 );
109+
auto arguments = providerSpy.takeLast();
110+
QCOMPARE( arguments.at( 0 ).toString(), QString( "postgres" ) );
110111

111112
// Find qgis_test schema item
112113
index = w->mBrowserModel->findPath( QStringLiteral( "pg:/PG_1/qgis_test" ), Qt::MatchFlag::MatchStartsWith );
@@ -115,9 +116,10 @@ void TestQgsNewDatabaseTableNameWidget::testWidgetSignals()
115116
rect = w->mBrowserTreeView->visualRect( w->mBrowserProxyModel.mapFromSource( index ) );
116117
QVERIFY( rect.isValid() );
117118
QTest::mouseClick( w->mBrowserTreeView->viewport(), Qt::LeftButton, 0, rect.center() );
118-
QCOMPARE( validationSpy.count(), 1 );
119-
arguments = validationSpy.takeLast();
120-
QCOMPARE( arguments.at( 0 ).toBool(), false );
119+
120+
QVERIFY( ! w->isValid() );
121+
122+
QCOMPARE( validationSpy.count(), 0 );
121123
QCOMPARE( schemaSpy.count(), 1 );
122124
arguments = schemaSpy.takeLast();
123125
QCOMPARE( arguments.at( 0 ).toString(), QString( "qgis_test" ) );
@@ -126,38 +128,49 @@ void TestQgsNewDatabaseTableNameWidget::testWidgetSignals()
126128
QCOMPARE( tableSpy.count(), 1 );
127129
arguments = tableSpy.takeLast();
128130
QCOMPARE( arguments.at( 0 ).toString(), QString( "someNewTableData" ) );
129-
131+
QCOMPARE( validationSpy.count(), 1 );
132+
arguments = validationSpy.takeLast();
133+
QCOMPARE( arguments.at( 0 ).toBool(), true );
130134
QVERIFY( w->isValid() );
131135

132-
// Test unique
136+
// Test getters
137+
QCOMPARE( w->table(), QString( "someNewTableData" ) );
138+
QCOMPARE( w->schema(), QString( "qgis_test" ) );
139+
QCOMPARE( w->dataProviderKey(), QString( "postgres" ) );
140+
141+
// Test unique and make it invalid again so we get a status change
133142
w->mNewTableName->setText( QStringLiteral( "someData" ) );
143+
QVERIFY( ! w->isValid() );
134144
QCOMPARE( tableSpy.count(), 1 );
135145
arguments = tableSpy.takeLast();
136146
QCOMPARE( arguments.at( 0 ).toString(), QString( "someData" ) );
147+
QCOMPARE( validationSpy.count(), 1 );
148+
arguments = validationSpy.takeLast();
149+
QCOMPARE( arguments.at( 0 ).toBool(), false );
137150

138-
QVERIFY( ! w->isValid() );
151+
// Now select another schema
152+
index = w->mBrowserModel->findPath( QStringLiteral( "pg:/PG_1/public" ), Qt::MatchFlag::MatchStartsWith );
153+
QVERIFY( index.isValid() );
154+
w->mBrowserTreeView->scrollTo( w->mBrowserProxyModel.mapFromSource( index ) );
155+
rect = w->mBrowserTreeView->visualRect( w->mBrowserProxyModel.mapFromSource( index ) );
156+
QVERIFY( rect.isValid() );
157+
QTest::mouseClick( w->mBrowserTreeView->viewport(), Qt::LeftButton, 0, rect.center() );
158+
QCOMPARE( w->schema(), QString( "public" ) );
159+
QVERIFY( w->isValid() );
160+
QCOMPARE( validationSpy.count(), 1 );
161+
arguments = validationSpy.takeLast();
162+
QCOMPARE( arguments.at( 0 ).toBool(), true );
163+
QCOMPARE( schemaSpy.count(), 1 );
164+
arguments = schemaSpy.takeLast();
165+
QCOMPARE( arguments.at( 0 ).toString(), QString( "public" ) );
139166

140167
// Test getters
141168
QCOMPARE( w->table(), QString( "someData" ) );
142-
QCOMPARE( w->schema(), QString( "qgis_test" ) );
143-
QCOMPARE( w->dataItemProviderName(), QString( "postgres" ) );
169+
QCOMPARE( w->schema(), QString( "public" ) );
170+
QCOMPARE( w->dataProviderKey(), QString( "postgres" ) );
144171

145172
}
146173

147-
148-
void TestQgsNewDatabaseTableNameWidget::testWidget()
149-
{
150-
QDialog d;
151-
QVBoxLayout layout;
152-
d.setLayout( &layout );
153-
std::unique_ptr<QgsNewDatabaseTableNameWidget> w { qgis::make_unique<QgsNewDatabaseTableNameWidget>( nullptr, QStringList{ "PostGIS" } ) };
154-
d.layout()->addWidget( w.get() );
155-
156-
d.exec();
157-
158-
}
159-
160-
161174
QGSTEST_MAIN( TestQgsNewDatabaseTableNameWidget )
162175
#include "testqgsnewdatabasetablewidget.moc"
163176

0 commit comments

Comments
 (0)
Please sign in to comment.