Skip to content

Commit

Permalink
refactor postgres provider gui with enhanced filtering UX
Browse files Browse the repository at this point in the history
  • Loading branch information
3nids committed Nov 9, 2021
1 parent e8ae3b5 commit 7c6753c
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 152 deletions.
141 changes: 20 additions & 121 deletions src/providers/postgres/qgspgsourceselect.cpp
Expand Up @@ -19,6 +19,7 @@ email : sherman at mrcc.com
#include "qgspgsourceselect.h"

#include "qgslogger.h"
#include "qgsdbfilterproxymodel.h"
#include "qgsapplication.h"
#include "qgspostgresprovider.h"
#include "qgspgnewconnection.h"
Expand All @@ -32,6 +33,7 @@ email : sherman at mrcc.com
#include "qgsproject.h"
#include "qgsgui.h"
#include "qgsiconutils.h"
#include "qgspgtablemodel.h"

#include <QFileDialog>
#include <QInputDialog>
Expand Down Expand Up @@ -213,9 +215,8 @@ void QgsPgSourceSelectDelegate::setModelData( QWidget *editor, QAbstractItemMode
}

QgsPgSourceSelect::QgsPgSourceSelect( QWidget *parent, Qt::WindowFlags fl, QgsProviderRegistry::WidgetMode theWidgetMode )
: QgsAbstractDataSourceWidget( parent, fl, theWidgetMode )
: QgsDbSourceSelectBase( parent, fl, theWidgetMode )
{
setupUi( this );
QgsGui::instance()->enableAutoGeometryRestore( this );

connect( btnConnect, &QPushButton::clicked, this, &QgsPgSourceSelect::btnConnect_clicked );
Expand All @@ -225,10 +226,6 @@ QgsPgSourceSelect::QgsPgSourceSelect( QWidget *parent, Qt::WindowFlags fl, QgsPr
connect( btnDelete, &QPushButton::clicked, this, &QgsPgSourceSelect::btnDelete_clicked );
connect( btnSave, &QPushButton::clicked, this, &QgsPgSourceSelect::btnSave_clicked );
connect( btnLoad, &QPushButton::clicked, this, &QgsPgSourceSelect::btnLoad_clicked );
connect( mSearchGroupBox, &QGroupBox::toggled, this, &QgsPgSourceSelect::mSearchGroupBox_toggled );
connect( mSearchTableEdit, &QLineEdit::textChanged, this, &QgsPgSourceSelect::mSearchTableEdit_textChanged );
connect( mSearchColumnComboBox, &QComboBox::currentTextChanged, this, &QgsPgSourceSelect::mSearchColumnComboBox_currentIndexChanged );
connect( mSearchModeComboBox, &QComboBox::currentTextChanged, this, &QgsPgSourceSelect::mSearchModeComboBox_currentIndexChanged );
connect( cmbConnections, &QComboBox::currentTextChanged, this, &QgsPgSourceSelect::cmbConnections_currentIndexChanged );
connect( mTablesTreeView, &QTreeView::clicked, this, &QgsPgSourceSelect::mTablesTreeView_clicked );
connect( mTablesTreeView, &QTreeView::doubleClicked, this, &QgsPgSourceSelect::mTablesTreeView_doubleClicked );
Expand Down Expand Up @@ -256,30 +253,11 @@ QgsPgSourceSelect::QgsPgSourceSelect( QWidget *parent, Qt::WindowFlags fl, QgsPr

populateConnectionList();

mSearchModeComboBox->addItem( tr( "Wildcard" ) );
mSearchModeComboBox->addItem( tr( "RegExp" ) );

mSearchColumnComboBox->addItem( tr( "All" ) );
mSearchColumnComboBox->addItem( tr( "Schema" ) );
mSearchColumnComboBox->addItem( tr( "Table" ) );
mSearchColumnComboBox->addItem( tr( "Comment" ) );
mSearchColumnComboBox->addItem( tr( "Type" ) );
mSearchColumnComboBox->addItem( tr( "Geometry column" ) );
mSearchColumnComboBox->addItem( tr( "Feature id" ) );
mSearchColumnComboBox->addItem( tr( "SRID" ) );
mSearchColumnComboBox->addItem( tr( "Sql" ) );

mProxyModel.setParent( this );
mProxyModel.setFilterKeyColumn( -1 );
mProxyModel.setFilterCaseSensitivity( Qt::CaseInsensitive );
mProxyModel.setSourceModel( &mTableModel );

// Do not do dynamic sorting - otherwise whenever user selects geometry type / srid / pk columns,
// that item suddenly jumps to the end of the list (because the item gets changed) which is very annoying.
// The list gets sorted in finishList() method when the listing of tables and views has finished.
mProxyModel.setDynamicSortFilter( false );

mTablesTreeView->setModel( &mProxyModel );

mTableModel = new QgsPgTableModel( this );
setSourceModel( mTableModel );

mTablesTreeView->setModel( proxyModel() );
mTablesTreeView->setSortingEnabled( true );
mTablesTreeView->setUniformRowHeights( true );
mTablesTreeView->setEditTriggers( QAbstractItemView::CurrentChanged );
Expand All @@ -289,28 +267,15 @@ QgsPgSourceSelect::QgsPgSourceSelect( QWidget *parent, Qt::WindowFlags fl, QgsPr

mTablesTreeView->setSelectionMode( QAbstractItemView::ExtendedSelection );

//for Qt < 4.3.2, passing -1 to include all model columns
//in search does not seem to work
mSearchColumnComboBox->setCurrentIndex( 2 );

QgsSettings settings;
mHoldDialogOpen->setChecked( settings.value( QStringLiteral( "Windows/PgSourceSelect/HoldDialogOpen" ), false ).toBool() );

for ( int i = 0; i < mTableModel.columnCount(); i++ )
for ( int i = 0; i < mTableModel->columnCount(); i++ )
{
mTablesTreeView->setColumnWidth( i, settings.value( QStringLiteral( "Windows/PgSourceSelect/columnWidths/%1" ).arg( i ), mTablesTreeView->columnWidth( i ) ).toInt() );
}

//hide the search options by default
//they will be shown when the user ticks
//the search options group box
mSearchLabel->setVisible( false );
mSearchColumnComboBox->setVisible( false );
mSearchColumnsLabel->setVisible( false );
mSearchModeComboBox->setVisible( false );
mSearchModeLabel->setVisible( false );
mSearchTableEdit->setVisible( false );
}

//! Autoconnected SLOTS
// Slot for adding a new connection
void QgsPgSourceSelect::btnNew_clicked()
Expand Down Expand Up @@ -404,75 +369,9 @@ void QgsPgSourceSelect::mTablesTreeView_doubleClicked( const QModelIndex & )
addButtonClicked();
}

void QgsPgSourceSelect::mSearchGroupBox_toggled( bool checked )
{
if ( mSearchTableEdit->text().isEmpty() )
return;

mSearchTableEdit_textChanged( checked ? mSearchTableEdit->text() : QString() );
}

void QgsPgSourceSelect::mSearchTableEdit_textChanged( const QString &text )
{
if ( mSearchModeComboBox->currentText() == tr( "Wildcard" ) )
{
mProxyModel._setFilterWildcard( text );
}
else if ( mSearchModeComboBox->currentText() == tr( "RegExp" ) )
{
mProxyModel._setFilterRegExp( text );
}
}

void QgsPgSourceSelect::mSearchColumnComboBox_currentIndexChanged( const QString &text )
{
if ( text == tr( "All" ) )
{
mProxyModel.setFilterKeyColumn( -1 );
}
else if ( text == tr( "Schema" ) )
{
mProxyModel.setFilterKeyColumn( QgsPgTableModel::DbtmSchema );
}
else if ( text == tr( "Table" ) )
{
mProxyModel.setFilterKeyColumn( QgsPgTableModel::DbtmTable );
}
else if ( text == tr( "Comment" ) )
{
mProxyModel.setFilterKeyColumn( QgsPgTableModel::DbtmComment );
}
else if ( text == tr( "Type" ) )
{
mProxyModel.setFilterKeyColumn( QgsPgTableModel::DbtmType );
}
else if ( text == tr( "Geometry column" ) )
{
mProxyModel.setFilterKeyColumn( QgsPgTableModel::DbtmGeomCol );
}
else if ( text == tr( "Feature id" ) )
{
mProxyModel.setFilterKeyColumn( QgsPgTableModel::DbtmPkCol );
}
else if ( text == tr( "SRID" ) )
{
mProxyModel.setFilterKeyColumn( QgsPgTableModel::DbtmSrid );
}
else if ( text == tr( "Sql" ) )
{
mProxyModel.setFilterKeyColumn( QgsPgTableModel::DbtmSql );
}
}

void QgsPgSourceSelect::mSearchModeComboBox_currentIndexChanged( const QString &text )
{
Q_UNUSED( text )
mSearchTableEdit_textChanged( mSearchTableEdit->text() );
}

void QgsPgSourceSelect::setLayerType( const QgsPostgresLayerProperty &layerProperty )
{
mTableModel.addTableEntry( layerProperty );
mTableModel->addTableEntry( layerProperty );
}

QgsPgSourceSelect::~QgsPgSourceSelect()
Expand All @@ -487,7 +386,7 @@ QgsPgSourceSelect::~QgsPgSourceSelect()
QgsSettings settings;
settings.setValue( QStringLiteral( "Windows/PgSourceSelect/HoldDialogOpen" ), mHoldDialogOpen->isChecked() );

for ( int i = 0; i < mTableModel.columnCount(); i++ )
for ( int i = 0; i < mTableModel->columnCount(); i++ )
{
settings.setValue( QStringLiteral( "Windows/PgSourceSelect/columnWidths/%1" ).arg( i ), mTablesTreeView->columnWidth( i ) );
}
Expand Down Expand Up @@ -523,7 +422,7 @@ void QgsPgSourceSelect::addButtonClicked()
if ( idx.column() != QgsPgTableModel::DbtmTable )
continue;

QString uri = mTableModel.layerURI( mProxyModel.mapToSource( idx ), connectionInfo( false ), mUseEstimatedMetadata );
QString uri = mTableModel->layerURI( proxyModel()->mapToSource( idx ), connectionInfo( false ), mUseEstimatedMetadata );
if ( uri.isNull() )
continue;

Expand Down Expand Up @@ -578,9 +477,9 @@ void QgsPgSourceSelect::btnConnect_clicked()
return;
}

QModelIndex rootItemIndex = mTableModel.indexFromItem( mTableModel.invisibleRootItem() );
mTableModel.removeRows( 0, mTableModel.rowCount( rootItemIndex ), rootItemIndex );
mTableModel.setConnectionName( cmbConnections->currentText() );
QModelIndex rootItemIndex = mTableModel->indexFromItem( mTableModel->invisibleRootItem() );
mTableModel->removeRows( 0, mTableModel->rowCount( rootItemIndex ), rootItemIndex );
mTableModel->setConnectionName( cmbConnections->currentText() );

// populate the table list
QgsDataSourceUri uri = QgsPostgresConn::connUri( cmbConnections->currentText() );
Expand Down Expand Up @@ -664,10 +563,10 @@ void QgsPgSourceSelect::setSql( const QModelIndex &index )
return;
}

QModelIndex idx = mProxyModel.mapToSource( index );
QString tableName = mTableModel.itemFromIndex( idx.sibling( idx.row(), QgsPgTableModel::DbtmTable ) )->text();
QModelIndex idx = proxyModel()->mapToSource( index );
QString tableName = mTableModel->itemFromIndex( idx.sibling( idx.row(), QgsPgTableModel::DbtmTable ) )->text();

QString uri = mTableModel.layerURI( idx, connectionInfo( false ), mUseEstimatedMetadata );
QString uri = mTableModel->layerURI( idx, connectionInfo( false ), mUseEstimatedMetadata );
if ( uri.isNull() )
{
QgsDebugMsg( QStringLiteral( "no uri" ) );
Expand All @@ -686,7 +585,7 @@ void QgsPgSourceSelect::setSql( const QModelIndex &index )
QgsQueryBuilder *gb = new QgsQueryBuilder( vlayer, this );
if ( gb->exec() )
{
mTableModel.setSql( mProxyModel.mapToSource( index ), gb->sql() );
mTableModel->setSql( proxyModel()->mapToSource( index ), gb->sql() );
}

delete gb;
Expand Down
16 changes: 5 additions & 11 deletions src/providers/postgres/qgspgsourceselect.h
Expand Up @@ -17,14 +17,12 @@
#ifndef QGSPGSOURCESELECT_H
#define QGSPGSOURCESELECT_H

#include "ui_qgsdbsourceselectbase.h"
#include "qgsguiutils.h"
#include "qgsdatasourceuri.h"
#include "qgsdbfilterproxymodel.h"
#include "qgspgtablemodel.h"
#include "qgshelp.h"
#include "qgsproviderregistry.h"
#include "qgsabstractdatasourcewidget.h"
#include "qgsdbsourceselectbase.h"
#include "qgspostgresconn.h"

#include <QMap>
#include <QPair>
Expand All @@ -36,6 +34,7 @@ class QgsGeomColumnTypeThread;
class QgisApp;
class QgsPgSourceSelect;
class QgsProxyProgressTask;
class QgsPgTableModel;

class QgsPgSourceSelectDelegate : public QItemDelegate
{
Expand All @@ -60,7 +59,7 @@ class QgsPgSourceSelectDelegate : public QItemDelegate
* for PostGIS enabled PostgreSQL databases. The user can then connect and add
* tables from the database to the map canvas.
*/
class QgsPgSourceSelect : public QgsAbstractDataSourceWidget, private Ui::QgsDbSourceSelectBase
class QgsPgSourceSelect : public QgsDbSourceSelectBase
{
Q_OBJECT

Expand Down Expand Up @@ -105,10 +104,6 @@ class QgsPgSourceSelect : public QgsAbstractDataSourceWidget, private Ui::QgsDbS
void btnSave_clicked();
//! Loads the selected connections from file
void btnLoad_clicked();
void mSearchGroupBox_toggled( bool );
void mSearchTableEdit_textChanged( const QString &text );
void mSearchColumnComboBox_currentIndexChanged( const QString &text );
void mSearchModeComboBox_currentIndexChanged( const QString &text );
void cmbConnections_currentIndexChanged( const QString &text );
void setSql( const QModelIndex &index );
//! Store the selected database
Expand Down Expand Up @@ -149,8 +144,7 @@ class QgsPgSourceSelect : public QgsAbstractDataSourceWidget, private Ui::QgsDbS
QMap<QString, QPair<QString, QIcon> > mLayerIcons;

//! Model that acts as datasource for mTableTreeWidget
QgsPgTableModel mTableModel;
QgsDatabaseFilterProxyModel mProxyModel;
QgsPgTableModel *mTableModel = nullptr;

QPushButton *mBuildQueryButton = nullptr;

Expand Down
63 changes: 48 additions & 15 deletions src/providers/postgres/qgspgtablemodel.cpp
Expand Up @@ -24,25 +24,57 @@
#include <QRegularExpression>
#include <climits>

QgsPgTableModel::QgsPgTableModel()
QgsPgTableModel::QgsPgTableModel( QObject *parent )
: QgsAbstractDbTableModel( parent )
{
QStringList headerLabels;
headerLabels << tr( "Schema" );
headerLabels << tr( "Table" );
headerLabels << tr( "Comment" );
headerLabels << tr( "Column" );
headerLabels << tr( "Data Type" );
headerLabels << tr( "Spatial Type" );
headerLabels << tr( "SRID" );
headerLabels << tr( "Feature id" );
headerLabels << tr( "Select at id" );
headerLabels << tr( "Check PK unicity" );
headerLabels << tr( "Sql" );
setHorizontalHeaderLabels( headerLabels );
mColumns << tr( "Schema" )
<< tr( "Table" )
<< tr( "Comment" )
<< tr( "Column" )
<< tr( "Data Type" )
<< tr( "Spatial Type" )
<< tr( "SRID" )
<< tr( "Feature id" )
<< tr( "Select at id" )
<< tr( "Check PK unicity" )
<< tr( "Sql" );
setHorizontalHeaderLabels( mColumns );
setHeaderData( Columns::DbtmSelectAtId, Qt::Orientation::Horizontal, tr( "Disable 'Fast Access to Features at ID' capability to force keeping the attribute table in memory (e.g. in case of expensive views)." ), Qt::ToolTipRole );
setHeaderData( Columns::DbtmCheckPkUnicity, Qt::Orientation::Horizontal, tr( "Enable check for primary key unicity when loading views and materialized views. This option can make loading of large datasets significantly slower." ), Qt::ToolTipRole );
}

QStringList QgsPgTableModel::columns() const
{
return mColumns;
}

int QgsPgTableModel::defaultSearchColumn() const
{
return static_cast<int>( DbtmTable );
}

bool QgsPgTableModel::searchableColumn( int column ) const
{
Columns col = static_cast<Columns>( column );
switch ( col )
{
case DbtmSchema:
case DbtmTable:
case DbtmComment:
case DbtmGeomCol:
case DbtmType:
case DbtmSrid:
case DbtmSql:
return true;

case DbtmGeomType:
case DbtmPkCol:
case DbtmSelectAtId:
case DbtmCheckPkUnicity:
return false;
}
}

void QgsPgTableModel::addTableEntry( const QgsPostgresLayerProperty &layerProperty )
{
QgsDebugMsgLevel( layerProperty.toString(), 3 );
Expand Down Expand Up @@ -342,7 +374,7 @@ bool QgsPgTableModel::setData( const QModelIndex &idx, const QVariant &value, in
tip = tr( "Select columns in the '%1' column that uniquely identify features of this layer" ).arg( tr( "Feature id" ) );
}

for ( int i = 0; i < DbtmColumns; i++ )
for ( int i = 0; i < columnCount(); i++ )
{
QStandardItem *item = itemFromIndex( idx.sibling( idx.row(), i ) );
if ( tip.isEmpty() )
Expand Down Expand Up @@ -466,3 +498,4 @@ QString QgsPgTableModel::layerURI( const QModelIndex &index, const QString &conn
QgsDebugMsg( QStringLiteral( "returning uri %1" ).arg( uri.uri( false ) ) );
return uri.uri( false );
}

0 comments on commit 7c6753c

Please sign in to comment.