Skip to content

Commit

Permalink
Add API to show empty entries in QgsDatabaseTableComboBox
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Mar 14, 2020
1 parent 513966c commit 30fbf24
Show file tree
Hide file tree
Showing 8 changed files with 363 additions and 9 deletions.
15 changes: 15 additions & 0 deletions python/core/auto_generated/qgsdatabasetablemodel.sip.in
Expand Up @@ -36,6 +36,7 @@ called.
RoleCustomInfo,
RoleWkbType,
RoleCrs,
RoleEmpty,
};

explicit QgsDatabaseTableModel( const QString &provider, const QString &connection, const QString &schema = QString(), QObject *parent /TransferThis/ = 0 );
Expand Down Expand Up @@ -70,6 +71,20 @@ Ownership of ``connection`` is transferred to the model.
virtual QModelIndex index( int row, int column, const QModelIndex &parent ) const;


void setAllowEmptyTable( bool allowEmpty );
%Docstring
Sets whether an optional empty table ("not set") option is present in the model.

.. seealso:: :py:func:`allowEmptyTable`
%End

bool allowEmptyTable() const;
%Docstring
Returns ``True`` if the model allows the empty table ("not set") choice.

.. seealso:: :py:func:`setAllowEmptyTable`
%End

public slots:

void refresh();
Expand Down
15 changes: 15 additions & 0 deletions python/gui/auto_generated/qgsdatabasetablecombobox.sip.in
Expand Up @@ -10,6 +10,7 @@




class QgsDatabaseTableComboBox : QWidget
{
%Docstring
Expand Down Expand Up @@ -47,6 +48,20 @@ Constructor for QgsDatabaseTableComboBox, for the specified ``connection``.
The optional ``schema`` argument can be used to restrict the listed tables to a specific schema.

Ownership of ``connection`` is transferred to the combobox.
%End

void setAllowEmptyTable( bool allowEmpty );
%Docstring
Sets whether an optional empty table ("not set") option is present in the combobox.

.. seealso:: :py:func:`allowEmptyTable`
%End

bool allowEmptyTable() const;
%Docstring
Returns ``True`` if the combobox allows the empty table ("not set") choice.

.. seealso:: :py:func:`setAllowEmptyTable`
%End

QString currentTable() const;
Expand Down
41 changes: 36 additions & 5 deletions src/core/qgsdatabasetablemodel.cpp
Expand Up @@ -57,7 +57,7 @@ int QgsDatabaseTableModel::rowCount( const QModelIndex &parent ) const
if ( parent.isValid() )
return 0;

return mTables.count();
return mTables.count() + ( mAllowEmpty ? 1 : 0 );
}

int QgsDatabaseTableModel::columnCount( const QModelIndex &parent ) const
Expand All @@ -72,14 +72,26 @@ QVariant QgsDatabaseTableModel::data( const QModelIndex &index, int role ) const
if ( !index.isValid() )
return QVariant();

if ( index.row() >= mTables.count() )
if ( index.row() == 0 && mAllowEmpty )
{
if ( role == RoleEmpty )
return true;

return QVariant();
}

const QgsAbstractDatabaseProviderConnection::TableProperty &table = mTables[ index.row() ];
if ( index.row() - ( mAllowEmpty ? 1 : 0 ) >= mTables.count() )
return QVariant();

const QgsAbstractDatabaseProviderConnection::TableProperty &table = mTables[ index.row() - ( mAllowEmpty ? 1 : 0 ) ];
switch ( role )
{
case RoleEmpty:
return false;

case Qt::DisplayRole:
case Qt::ToolTipRole:
case Qt::EditRole:
{
return mSchema.isEmpty() && !table.schema().isEmpty() ? QStringLiteral( "%1.%2" ).arg( table.schema(), table.tableName() ) : table.tableName();
}
Expand Down Expand Up @@ -158,6 +170,25 @@ QModelIndex QgsDatabaseTableModel::index( int row, int column, const QModelIndex
return QModelIndex();
}

void QgsDatabaseTableModel::setAllowEmptyTable( bool allowEmpty )
{
if ( allowEmpty == mAllowEmpty )
return;

if ( allowEmpty )
{
beginInsertRows( QModelIndex(), 0, 0 );
mAllowEmpty = true;
endInsertRows();
}
else
{
beginRemoveRows( QModelIndex(), 0, 0 );
mAllowEmpty = false;
endRemoveRows();
}
}

void QgsDatabaseTableModel::refresh()
{
const QList< QgsAbstractDatabaseProviderConnection::TableProperty > newTables = mConnection->tables( mSchema );
Expand All @@ -168,7 +199,7 @@ void QgsDatabaseTableModel::refresh()
if ( !newTables.contains( oldTable ) )
{
int r = mTables.indexOf( oldTable );
beginRemoveRows( QModelIndex(), r, r );
beginRemoveRows( QModelIndex(), r + ( mAllowEmpty ? 1 : 0 ), r + ( mAllowEmpty ? 1 : 0 ) );
mTables.removeAt( r );
endRemoveRows();
}
Expand All @@ -178,7 +209,7 @@ void QgsDatabaseTableModel::refresh()
{
if ( !mTables.contains( newTable ) )
{
beginInsertRows( QModelIndex(), mTables.count(), mTables.count() );
beginInsertRows( QModelIndex(), mTables.count() + ( mAllowEmpty ? 1 : 0 ), mTables.count() + ( mAllowEmpty ? 1 : 0 ) );
mTables.append( newTable );
endInsertRows();
}
Expand Down
14 changes: 14 additions & 0 deletions src/core/qgsdatabasetablemodel.h
Expand Up @@ -52,6 +52,7 @@ class CORE_EXPORT QgsDatabaseTableModel : public QAbstractItemModel
RoleCustomInfo, //!< Custom info variant map role
RoleWkbType, //!< WKB type for primary (first) geometry column in table
RoleCrs, //!< CRS for primary (first) geometry column in table
RoleEmpty, //!< Entry is an empty entry
};

/**
Expand Down Expand Up @@ -80,6 +81,18 @@ class CORE_EXPORT QgsDatabaseTableModel : public QAbstractItemModel
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
QModelIndex index( int row, int column, const QModelIndex &parent ) const override;

/**
* Sets whether an optional empty table ("not set") option is present in the model.
* \see allowEmptyTable()
*/
void setAllowEmptyTable( bool allowEmpty );

/**
* Returns TRUE if the model allows the empty table ("not set") choice.
* \see setAllowEmptyTable()
*/
bool allowEmptyTable() const { return mAllowEmpty; }

public slots:

/**
Expand All @@ -92,6 +105,7 @@ class CORE_EXPORT QgsDatabaseTableModel : public QAbstractItemModel
std::unique_ptr< QgsAbstractDatabaseProviderConnection > mConnection;
QString mSchema;
QList<QgsAbstractDatabaseProviderConnection::TableProperty> mTables;
bool mAllowEmpty = false;
};

#endif // QGSDATABASETABLEMODEL_H
44 changes: 41 additions & 3 deletions src/gui/qgsdatabasetablecombobox.cpp
Expand Up @@ -38,11 +38,21 @@ QgsDatabaseTableComboBox::QgsDatabaseTableComboBox( QgsAbstractDatabaseProviderC
init();
}

void QgsDatabaseTableComboBox::setAllowEmptyTable( bool allowEmpty )
{
mModel->setAllowEmptyTable( allowEmpty );
}

bool QgsDatabaseTableComboBox::allowEmptyTable() const
{
return mModel->allowEmptyTable();
}

void QgsDatabaseTableComboBox::init()
{
mComboBox = new QComboBox();

mSortModel = new QSortFilterProxyModel( this );
mSortModel = new QgsDatabaseTableComboBoxSortModel( this );
mSortModel->setSourceModel( mModel );
mSortModel->setSortRole( Qt::DisplayRole );
mSortModel->setSortLocaleAware( true );
Expand Down Expand Up @@ -77,7 +87,11 @@ void QgsDatabaseTableComboBox::setTable( const QString &table, const QString &sc

if ( table.isEmpty() )
{
mComboBox->setCurrentIndex( -1 );
if ( mModel->allowEmptyTable() )
mComboBox->setCurrentIndex( 0 );
else
mComboBox->setCurrentIndex( -1 );

emit tableChanged( QString() );
return;
}
Expand Down Expand Up @@ -108,6 +122,7 @@ void QgsDatabaseTableComboBox::setConnectionName( const QString &connection, con
const QString oldSchema = currentSchema();
QgsDatabaseTableModel *oldModel = mModel;
mModel = new QgsDatabaseTableModel( mProvider, mConnection, mSchema, this );
mModel->setAllowEmptyTable( oldModel->allowEmptyTable() );
mSortModel->setSourceModel( mModel );
oldModel->deleteLater();
if ( currentTable() != oldTable || currentSchema() != oldSchema )
Expand Down Expand Up @@ -163,7 +178,7 @@ void QgsDatabaseTableComboBox::indexChanged( int i )

void QgsDatabaseTableComboBox::rowsChanged()
{
if ( mComboBox->count() == 1 )
if ( mComboBox->count() == 1 || ( mModel->allowEmptyTable() && mComboBox->count() == 2 && mComboBox->currentIndex() == 1 ) )
{
//currently selected connection item has changed
emit tableChanged( currentTable(), currentSchema() );
Expand All @@ -173,3 +188,26 @@ void QgsDatabaseTableComboBox::rowsChanged()
emit tableChanged( QString() );
}
}

///@cond PRIVATE
QgsDatabaseTableComboBoxSortModel::QgsDatabaseTableComboBoxSortModel( QObject *parent )
: QSortFilterProxyModel( parent )
{

}

bool QgsDatabaseTableComboBoxSortModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
{
// empty row is always first
if ( sourceModel()->data( left, QgsDatabaseTableModel::RoleEmpty ).toBool() )
return true;
else if ( sourceModel()->data( right, QgsDatabaseTableModel::RoleEmpty ).toBool() )
return false;

// default mode is alphabetical order
QString leftStr = sourceModel()->data( left ).toString();
QString rightStr = sourceModel()->data( right ).toString();
return QString::localeAwareCompare( leftStr, rightStr ) < 0;
}

///@endcond
27 changes: 26 additions & 1 deletion src/gui/qgsdatabasetablecombobox.h
Expand Up @@ -20,11 +20,24 @@

#include "qgis_gui.h"
#include "qgis_sip.h"
#include <QSortFilterProxyModel>

class QgsDatabaseTableModel;
class QSortFilterProxyModel;
class QgsAbstractDatabaseProviderConnection;

///@cond PRIVATE
#ifndef SIP_RUN
class GUI_EXPORT QgsDatabaseTableComboBoxSortModel: public QSortFilterProxyModel
{
public:
explicit QgsDatabaseTableComboBoxSortModel( QObject *parent = nullptr );
protected:
bool lessThan( const QModelIndex &source_left, const QModelIndex &source_right ) const override;

};
#endif
///@endcond

/**
* \ingroup gui
* \brief The QgsDatabaseTableComboBox class is a combo box which displays the list of tables for a specific database connection.
Expand Down Expand Up @@ -59,6 +72,18 @@ class GUI_EXPORT QgsDatabaseTableComboBox : public QWidget
*/
explicit QgsDatabaseTableComboBox( QgsAbstractDatabaseProviderConnection *connection SIP_TRANSFER, const QString &schema = QString(), QWidget *parent SIP_TRANSFERTHIS = nullptr );

/**
* Sets whether an optional empty table ("not set") option is present in the combobox.
* \see allowEmptyTable()
*/
void setAllowEmptyTable( bool allowEmpty );

/**
* Returns TRUE if the combobox allows the empty table ("not set") choice.
* \see setAllowEmptyTable()
*/
bool allowEmptyTable() const;

/**
* Returns the name of the current table selected in the combo box.
*/
Expand Down

0 comments on commit 30fbf24

Please sign in to comment.