39 changes: 39 additions & 0 deletions src/providers/postgres/qgsdbfilterproxymodel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/***************************************************************************
qgsdbfilterproxymodel.h - description
-----------------------
begin : Dec 2007
copyright : (C) 2007 by Marco Hugentobler
email : marco dot hugentobler at karto dot baug dot ethz dot ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSDBFILTERPROXYMODEL_H
#define QGSDBFILTERPROXYMODEL_H

#include <QSortFilterProxyModel>

/**A class that implements a custom filter and can be used
as a proxy for QgsDbTableModel*/
class CORE_EXPORT QgsDbFilterProxyModel: public QSortFilterProxyModel
{
public:
QgsDbFilterProxyModel( QObject* parent = 0 );
~QgsDbFilterProxyModel();
/**Calls QSortFilterProxyModel::setFilterWildcard and triggers update*/
void _setFilterWildcard( const QString& pattern );
/**Calls QSortFilterProxyModel::setFilterRegExp and triggers update*/
void _setFilterRegExp( const QString& pattern );

protected:
virtual bool filterAcceptsRow( int row, const QModelIndex & source_parent ) const;
};

#endif
60 changes: 7 additions & 53 deletions src/providers/postgres/qgspgnewconnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,7 @@
#include "qgspgnewconnection.h"
#include "qgscontexthelp.h"
#include "qgsdatasourceuri.h"
#include "qgslogger.h"
#include "qgscredentialdialog.h"

extern "C"
{
#include <libpq-fe.h>
}
#include "qgspostgresconn.h"

QgsPgNewConnection::QgsPgNewConnection( QWidget *parent, const QString& connName, Qt::WFlags fl )
: QDialog( parent, fl ), mOriginalConnName( connName )
Expand Down Expand Up @@ -175,63 +169,23 @@ void QgsPgNewConnection::testConnection()
( QgsDataSourceURI::SSLmode ) cbxSSLmode->itemData( cbxSSLmode->currentIndex() ).toInt() );
}
QString conninfo = uri.connectionInfo();
QgsDebugMsg( "PQconnectdb(\"" + conninfo + "\");" );

PGconn *pd = PQconnectdb( conninfo.toLocal8Bit() ); // use what is set based on locale; after connecting, use Utf8
// check the connection status
if ( PQstatus( pd ) != CONNECTION_OK )
{
QString username = txtUsername->text();
QString password = txtPassword->text();

uri.setUsername( "" );
uri.setPassword( "" );

while ( PQstatus( pd ) != CONNECTION_OK )
{
bool ok = QgsCredentials::instance()->get( conninfo, username, password, QString::fromUtf8( PQerrorMessage( pd ) ) );
if ( !ok )
break;

::PQfinish( pd );

QgsDataSourceURI uri( conninfo );

if ( !username.isEmpty() )
uri.setUsername( username );
QgsPostgresConn *conn = QgsPostgresConn::connectDb( conninfo, true );

if ( !password.isEmpty() )
uri.setPassword( password );

QgsDebugMsg( "PQconnectdb(\"" + uri.connectionInfo() + "\");" );
pd = PQconnectdb( uri.connectionInfo().toLocal8Bit() );
}

if ( PQstatus( pd ) == CONNECTION_OK )
{
if ( chkStoreUsername->isChecked() )
txtUsername->setText( username );
if ( chkStorePassword->isChecked() )
txtPassword->setText( password );

QgsCredentials::instance()->put( conninfo, username, password );
}
}

if ( PQstatus( pd ) == CONNECTION_OK )
if ( conn )
{
// Database successfully opened; we can now issue SQL commands.
QMessageBox::information( this,
tr( "Test connection" ),
tr( "Connection to %1 was successful" ).arg( txtDatabase->text() ) );

// free pg connection resources
conn->disconnect();
}
else
{
QMessageBox::information( this,
tr( "Test connection" ),
tr( "Connection failed - Check settings and try again.\n\nExtended error information:\n%1" )
.arg( QString::fromUtf8( PQerrorMessage( pd ) ) ) );
tr( "Connection failed - Check settings and try again.\n\n" ) );
}
// free pg connection resources
PQfinish( pd );
}
352 changes: 155 additions & 197 deletions src/providers/postgres/qgspgsourceselect.cpp

Large diffs are not rendered by default.

113 changes: 16 additions & 97 deletions src/providers/postgres/qgspgsourceselect.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,13 @@
***************************************************************************/
#ifndef QGSPGSOURCESELECT_H
#define QGSPGSOURCESELECT_H

#include "ui_qgsdbsourceselectbase.h"
#include "qgisgui.h"
#include "qgsdbfilterproxymodel.h"
#include "qgsdbtablemodel.h"
#include "qgspgtablemodel.h"
#include "qgscontexthelp.h"

extern "C"
{
#include <libpq-fe.h>
}

#include <QThread>
#include <QMap>
#include <QPair>
#include <QIcon>
Expand All @@ -37,58 +32,19 @@ class QPushButton;
class QStringList;
class QgsGeomColumnTypeThread;
class QgisApp;
class QgsPgSourceSelect;

class QgsPgSourceSelectDelegate : public QItemDelegate
{
Q_OBJECT;

public:
QgsPgSourceSelectDelegate( QObject *parent = NULL ) : QItemDelegate( parent )
{
}

/** Used to create an editor for when the user tries to
* change the contents of a cell */
QWidget *createEditor(
QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index ) const
{
Q_UNUSED( option );
if ( index.column() == QgsDbTableModel::dbtmSql )
{
QLineEdit *le = new QLineEdit( parent );
le->setText( index.data( Qt::DisplayRole ).toString() );
return le;
}


if ( index.column() == QgsDbTableModel::dbtmPkCol )
{
QStringList values = index.data( Qt::UserRole + 1 ).toStringList();

if ( values.size() > 0 )
{
QComboBox *cb = new QComboBox( parent );
cb->addItems( values );
cb->setCurrentIndex( cb->findText( index.data( Qt::DisplayRole ).toString() ) );
return cb;
}
}

return NULL;
}

void setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
{
QComboBox *cb = qobject_cast<QComboBox *>( editor );
if ( cb )
model->setData( index, cb->currentText() );

QLineEdit *le = qobject_cast<QLineEdit *>( editor );
if ( le )
model->setData( index, le->text() );
}
QgsPgSourceSelectDelegate( QObject *parent = NULL )
: QItemDelegate( parent )
{}

QWidget *createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const;
void setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const;
};


Expand All @@ -108,7 +64,6 @@ class QgsPgSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
//! static function to delete a connection
static void deleteConnection( QString key );


//! Constructor
QgsPgSourceSelect( QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags, bool managerMode = false, bool embeddedMode = false );
//! Destructor
Expand All @@ -121,8 +76,7 @@ class QgsPgSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
QString connectionInfo();

signals:
void addDatabaseLayers( QStringList const & layerPathList,
QString const & providerKey );
void addDatabaseLayers( QStringList const & layerPathList, QString const & providerKey );
void connectionsChanged();

public slots:
Expand Down Expand Up @@ -151,14 +105,16 @@ class QgsPgSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
void setSql( const QModelIndex& index );
//! Store the selected database
void on_cmbConnections_activated( int );
void setLayerType( QString schema, QString table, QString column, QString type );
void setLayerType( QgsPostgresLayerProperty layerProperty );
void on_mTablesTreeView_clicked( const QModelIndex &index );
void on_mTablesTreeView_doubleClicked( const QModelIndex &index );
//!Sets a new regular expression to the model
void setSearchExpression( const QString& regexp );

void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }

void columnThreadFinished();

private:
typedef QPair<QString, QString> geomPair;
typedef QList<geomPair> geomCol;
Expand All @@ -170,7 +126,7 @@ class QgsPgSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
bool mEmbeddedMode;

// queue another query for the thread
void addSearchGeometryColumn( const QString &schema, const QString &table, const QString &column );
void addSearchGeometryColumn( QgsPostgresLayerProperty layerProperty );

// Set the position of the database connection list to the last
// used one.
Expand All @@ -189,50 +145,13 @@ class QgsPgSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
QMap<QString, QPair<QString, QIcon> > mLayerIcons;

//! Model that acts as datasource for mTableTreeWidget
QgsDbTableModel mTableModel;
QgsPgTableModel mTableModel;
QgsDbFilterProxyModel mProxyModel;

QString layerURI( const QModelIndex &index );
QPushButton *mBuildQueryButton;
QPushButton *mAddButton;
};


// Perhaps this class should be in its own file??
//
// A class that determines the geometry type of a given database
// schema.table.column, with the option of doing so in a separate
// thread.

class QgsGeomColumnTypeThread : public QThread
{
Q_OBJECT
public:

void setConnInfo( QString s, bool useEstimatedMetadata );
void addGeometryColumn( QString schema, QString table, QString column );

// These functions get the layer types and pass that information out
// by emitting the setLayerType() signal. The getLayerTypes()
// function does the actual work, but use the run() function if you
// want the work to be done as a separate thread from the calling
// process.
virtual void run() { getLayerTypes(); }
void getLayerTypes();

signals:
void setLayerType( QString schema, QString table, QString column,
QString type );

public slots:
void stop();


private:
QString mConnInfo;
bool mUseEstimatedMetadata;
bool mStopped;
std::vector<QString> schemas, tables, columns;
void updateSelectableState( const QModelIndex &index );
};

#endif // QGSPGSOURCESELECT_H
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***************************************************************************
qgsdbtablemodel.cpp - description
qgspgtablemodel.cpp - description
-------------------
begin : Dec 2007
copyright : (C) 2007 by Marco Hugentobler
Expand All @@ -15,90 +15,119 @@
* *
***************************************************************************/

#include "qgsdbtablemodel.h"
#include "qgspgtablemodel.h"
#include "qgsdataitem.h"
#include "qgslogger.h"

QgsDbTableModel::QgsDbTableModel(): QStandardItemModel(), mTableCount( 0 )
QgsPgTableModel::QgsPgTableModel()
: QStandardItemModel()
, mTableCount( 0 )
{
QStringList headerLabels;
headerLabels << tr( "Schema" );
headerLabels << tr( "Table" );
headerLabels << tr( "Type" );
headerLabels << tr( "Geometry column" );
headerLabels << tr( "SRID" );
headerLabels << tr( "Primary key column" );
headerLabels << tr( "Select at id" );
headerLabels << tr( "Sql" );
setHorizontalHeaderLabels( headerLabels );
}

QgsDbTableModel::~QgsDbTableModel()
QgsPgTableModel::~QgsPgTableModel()
{

}

void QgsDbTableModel::addTableEntry( QString type, QString schemaName, QString tableName, QString geometryColName, const QStringList &pkCols, QString sql )
void QgsPgTableModel::addTableEntry( QgsPostgresLayerProperty layerProperty )
{
//is there already a root item with the given scheme Name?
QgsDebugMsg( QString( "%1.%2.%3 type=%4 srid=%5 pk=%6 sql=%7" )
.arg( layerProperty.schemaName )
.arg( layerProperty.tableName )
.arg( layerProperty.geometryColName )
.arg( layerProperty.type )
.arg( layerProperty.srid )
.arg( layerProperty.pkCols.join( "," ) )
.arg( layerProperty.sql ) );

// is there already a root item with the given scheme Name?
QStandardItem *schemaItem;
QList<QStandardItem*> schemaItems = findItems( schemaName, Qt::MatchExactly, dbtmSchema );
QList<QStandardItem*> schemaItems = findItems( layerProperty.schemaName, Qt::MatchExactly, dbtmSchema );

//there is already an item for this schema
// there is already an item for this schema
if ( schemaItems.size() > 0 )
{
schemaItem = schemaItems.at( dbtmSchema );
}
else //create a new toplevel item for this schema
else
{
schemaItem = new QStandardItem( schemaName );
// create a new toplevel item for this schema
schemaItem = new QStandardItem( layerProperty.schemaName );
schemaItem->setFlags( Qt::ItemIsEnabled );
invisibleRootItem()->setChild( invisibleRootItem()->rowCount(), schemaItem );
}

//path to icon for specified type
QString typeName;

QGis::WkbType wkbType = qgisTypeFromDbType( type );
QIcon iconFile = iconForType( wkbType );
QGis::WkbType wkbType = qgisTypeFromDbType( layerProperty.type );
if ( wkbType == QGis::WKBUnknown && layerProperty.geometryColName.isEmpty() )
{
wkbType = QGis::WKBNoGeometry;
}

QList<QStandardItem*> childItemList;

QStandardItem* schemaNameItem = new QStandardItem( schemaName );
QStandardItem *schemaNameItem = new QStandardItem( layerProperty.schemaName );
schemaNameItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );

QStandardItem* typeItem = new QStandardItem( QIcon( iconFile ), type );
typeItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
QStandardItem *typeItem = new QStandardItem( iconForType( wkbType ), wkbType == QGis::WKBUnknown ? tr( "Waiting..." ) : displayStringForType( wkbType ) );
typeItem->setData( wkbType == QGis::WKBUnknown, Qt::UserRole + 1 );
typeItem->setData( wkbType, Qt::UserRole + 2 );
typeItem->setFlags(( wkbType != QGis::WKBUnknown ? Qt::ItemIsEnabled : Qt::NoItemFlags ) | Qt::ItemIsSelectable | Qt::ItemIsEditable );

QStandardItem* tableItem = new QStandardItem( tableName );
QStandardItem *tableItem = new QStandardItem( layerProperty.tableName );
tableItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );

QStandardItem* geomItem = new QStandardItem( geometryColName );
QStandardItem *geomItem = new QStandardItem( layerProperty.geometryColName );
geomItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );

QStandardItem* pkItem = new QStandardItem( "" );
pkItem->setData( pkCols );
QStandardItem *sridItem = new QStandardItem( QString::number( layerProperty.srid ) );
sridItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );

QString pkText, pkCol = "";
switch ( layerProperty.pkCols.size() )
{
case 0: pkText = ""; break;
case 1: pkText = layerProperty.pkCols[0]; pkCol = pkText; break;
default: pkText = tr( "Select..." ); break;
}

QStandardItem *pkItem = new QStandardItem( pkText );
pkItem->setData( layerProperty.pkCols, Qt::UserRole + 1 );
pkItem->setData( pkCol, Qt::UserRole + 2 );
pkItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable );

QStandardItem* selItem = new QStandardItem( "" );
QStandardItem *selItem = new QStandardItem( "" );
selItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable );
selItem->setCheckState( Qt::Checked );
selItem->setToolTip( tr( "Disable 'Fast Access to Features at ID' capability to force keeping the attribute table in memory (e.g. in case of expensive views)." ) );

QStandardItem* sqlItem = new QStandardItem( sql );
QStandardItem* sqlItem = new QStandardItem( layerProperty.sql );
sqlItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable );

childItemList.push_back( schemaNameItem );
childItemList.push_back( tableItem );
childItemList.push_back( typeItem );
childItemList.push_back( geomItem );
childItemList.push_back( pkItem );
childItemList.push_back( selItem );
childItemList.push_back( sqlItem );
childItemList << schemaNameItem;
childItemList << tableItem;
childItemList << typeItem;
childItemList << geomItem;
childItemList << sridItem;
childItemList << pkItem;
childItemList << selItem;
childItemList << sqlItem;

schemaItem->appendRow( childItemList );

++mTableCount;
}

void QgsDbTableModel::setSql( const QModelIndex &index, const QString &sql )
void QgsPgTableModel::setSql( const QModelIndex &index, const QString &sql )
{
if ( !index.isValid() || !index.parent().isValid() )
{
Expand Down Expand Up @@ -126,26 +155,22 @@ void QgsDbTableModel::setSql( const QModelIndex &index, const QString &sql )
}

QStandardItem* schemaItem = schemaItems.at( dbtmSchema );
int numChildren = schemaItem->rowCount();

QModelIndex currentChildIndex;
QModelIndex currentTableIndex;
QModelIndex currentGeomIndex;

for ( int i = 0; i < numChildren; ++i )
int n = schemaItem->rowCount();
for ( int i = 0; i < n; i++ )
{
currentChildIndex = indexFromItem( schemaItem->child( i, dbtmSchema ) );
QModelIndex currentChildIndex = indexFromItem( schemaItem->child( i, dbtmSchema ) );
if ( !currentChildIndex.isValid() )
{
continue;
}
currentTableIndex = currentChildIndex.sibling( i, dbtmTable );
QModelIndex currentTableIndex = currentChildIndex.sibling( i, dbtmTable );
if ( !currentTableIndex.isValid() )
{
continue;
}

currentGeomIndex = currentChildIndex.sibling( i, dbtmGeomCol );
QModelIndex currentGeomIndex = currentChildIndex.sibling( i, dbtmGeomCol );
if ( !currentGeomIndex.isValid() )
{
continue;
Expand All @@ -164,75 +189,82 @@ void QgsDbTableModel::setSql( const QModelIndex &index, const QString &sql )
}
}

void QgsDbTableModel::setGeometryTypesForTable( const QString& schema, const QString& table, const QString& attribute, const QString& type )
void QgsPgTableModel::setGeometryTypesForTable( QgsPostgresLayerProperty layerProperty )
{
bool typeIsEmpty = type.isEmpty(); //true means the table has no valid geometry entry and the item for this table should be removed
QStringList typeList = type.split( "," );
QStringList typeList = layerProperty.type.split( ",", QString::SkipEmptyParts );

//find schema item and table item
QStandardItem* schemaItem;
QList<QStandardItem*> schemaItems = findItems( schema, Qt::MatchExactly, dbtmSchema );
QList<QStandardItem*> schemaItems = findItems( layerProperty.schemaName, Qt::MatchExactly, dbtmSchema );

if ( schemaItems.size() < 1 )
{
return;
}
schemaItem = schemaItems.at( 0 );
int numChildren = schemaItem->rowCount();

QModelIndex currentChildIndex;
QModelIndex currentTableIndex;
QModelIndex currentTypeIndex;
QModelIndex currentGeomColumnIndex;
QModelIndex currentPkColumnIndex;
schemaItem = schemaItems.at( 0 );

for ( int i = 0; i < numChildren; ++i )
int n = schemaItem->rowCount();
for ( int i = 0; i < n; i++ )
{
currentChildIndex = indexFromItem( schemaItem->child( i, dbtmSchema ) );
QModelIndex currentChildIndex = indexFromItem( schemaItem->child( i, dbtmSchema ) );
if ( !currentChildIndex.isValid() )
{
continue;
}
currentTableIndex = currentChildIndex.sibling( i, dbtmTable );
currentTypeIndex = currentChildIndex.sibling( i, dbtmType );
currentGeomColumnIndex = currentChildIndex.sibling( i, dbtmGeomCol );
currentPkColumnIndex = currentChildIndex.sibling( i, dbtmPkCol );
QString geomColText = itemFromIndex( currentGeomColumnIndex )->text();
QStringList pkCols = itemFromIndex( currentPkColumnIndex )->data().toStringList();

if ( !currentTypeIndex.isValid() || !currentTableIndex.isValid() || !currentGeomColumnIndex.isValid() )
QModelIndex currentTypeIndex = currentChildIndex.sibling( i, dbtmType );
QModelIndex currentTableIndex = currentChildIndex.sibling( i, dbtmTable );
QModelIndex currentGeomColumnIndex = currentChildIndex.sibling( i, dbtmGeomCol );
QModelIndex currentPkColumnIndex = currentChildIndex.sibling( i, dbtmPkCol );
QModelIndex currentSridIndex = currentChildIndex.sibling( i, dbtmSrid );

if ( !currentTypeIndex.isValid()
|| !currentTableIndex.isValid()
|| !currentGeomColumnIndex.isValid()
|| !currentPkColumnIndex.isValid()
|| !currentSridIndex.isValid()
)
{
continue;
}

if ( itemFromIndex( currentTableIndex )->text() == table &&
( geomColText == attribute || geomColText.startsWith( attribute + " AS " ) ) )
QString tableText = itemFromIndex( currentTableIndex )->text();
QString geomColText = itemFromIndex( currentGeomColumnIndex )->text();
QStandardItem *typeItem = itemFromIndex( currentTypeIndex );
QStandardItem *sridItem = itemFromIndex( currentSridIndex );

if ( tableText == layerProperty.tableName && geomColText == layerProperty.geometryColName )
{
if ( typeIsEmpty )
{
removeRow( i, indexFromItem( schemaItem ) );
return;
}
sridItem->setText( QString::number( layerProperty.srid ) );

QGis::WkbType wkbType = qgisTypeFromDbType( typeList.at( 0 ) );
QIcon myIcon = iconForType( wkbType );
itemFromIndex( currentTypeIndex )->setText( typeList.at( 0 ) ); //todo: add other rows
itemFromIndex( currentTypeIndex )->setIcon( myIcon );
if ( !geomColText.contains( " AS " ) )
if ( typeList.isEmpty() )
{
itemFromIndex( currentGeomColumnIndex )->setText( geomColText + " AS " + typeList.at( 0 ) );
typeItem->setText( tr( "Select..." ) );
}

for ( int j = 1; j < typeList.size(); ++j )
else
{
//todo: add correct type
addTableEntry( typeList.at( j ), schema, table, geomColText + " AS " + typeList.at( j ), pkCols, "" );
// update existing row
QGis::WkbType wkbType = qgisTypeFromDbType( typeList.at( 0 ) );

typeItem->setIcon( iconForType( wkbType ) );
typeItem->setText( displayStringForType( wkbType ) );
typeItem->setData( false, Qt::UserRole + 1 );
typeItem->setData( wkbType, Qt::UserRole + 2 );

for ( int j = 1; j < typeList.size(); j++ )
{
layerProperty.type = typeList[j];
addTableEntry( layerProperty );
}
}

typeItem->setFlags( typeItem->flags() | Qt::ItemIsEnabled );
}
}
}

QIcon QgsDbTableModel::iconForType( QGis::WkbType type ) const
QIcon QgsPgTableModel::iconForType( QGis::WkbType type )
{
if ( type == QGis::WKBPoint || type == QGis::WKBPoint25D || type == QGis::WKBMultiPoint || type == QGis::WKBMultiPoint25D )
{
Expand All @@ -246,10 +278,17 @@ QIcon QgsDbTableModel::iconForType( QGis::WkbType type ) const
{
return QIcon( QgsDataItem::getThemePixmap( "/mIconPolygonLayer.png" ) );
}
else return QIcon();
else if ( type == QGis::WKBNoGeometry )
{
return QIcon( QgsDataItem::getThemePixmap( "/mIconTableLayer.png" ) );
}
else
{
return QIcon( QgsDataItem::getThemePixmap( "/mIconLayer.png" ) );
}
}

QString QgsDbTableModel::displayStringForType( QGis::WkbType type ) const
QString QgsPgTableModel::displayStringForType( QGis::WkbType type )
{
if ( type == QGis::WKBPoint || type == QGis::WKBPoint25D )
{
Expand All @@ -275,11 +314,20 @@ QString QgsDbTableModel::displayStringForType( QGis::WkbType type ) const
{
return tr( "Multipolygon" );
}
return "Unknown";
else if ( type == QGis::WKBNoGeometry )
{
return tr( "No Geometry" );
}
else
{
return tr( "Unknown" );
}
}

QGis::WkbType QgsDbTableModel::qgisTypeFromDbType( const QString& dbType ) const
QGis::WkbType QgsPgTableModel::qgisTypeFromDbType( QString dbType )
{
dbType = dbType.toUpper();

if ( dbType == "POINT" )
{
return QGis::WKBPoint;
Expand All @@ -304,5 +352,8 @@ QGis::WkbType QgsDbTableModel::qgisTypeFromDbType( const QString& dbType ) const
{
return QGis::WKBMultiPolygon;
}
return QGis::WKBUnknown;
else
{
return QGis::WKBUnknown;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***************************************************************************
qgsdbtablemodel.h - description
qgspgtablemodel.h - description
-------------------
begin : Dec 2007
copyright : (C) 2007 by Marco Hugentobler
Expand All @@ -16,28 +16,31 @@
***************************************************************************/

#include <QStandardItemModel>
class QIcon;

#include "qgis.h"
#include "qgspostgresconn.h"

class QIcon;

/**A model that holds the tables of a database in a hierarchy where the
schemas are the root elements that contain the individual tables as children.
The tables have the following columns: Type, Schema, Tablename, Geometry Column, Sql*/
class CORE_EXPORT QgsDbTableModel : public QStandardItemModel
class QgsPgTableModel : public QStandardItemModel
{
Q_OBJECT
public:
QgsDbTableModel();
~QgsDbTableModel();
QgsPgTableModel();
~QgsPgTableModel();

/**Adds entry for one database table to the model*/
void addTableEntry( QString type, QString schemaName, QString tableName, QString geometryColName, const QStringList &pkCols, QString Sql );
void addTableEntry( QgsPostgresLayerProperty property );

/**Sets an sql statement that belongs to a cell specified by a model index*/
void setSql( const QModelIndex& index, const QString& sql );

/**Sets one or more geometry types to a row. In case of several types, additional rows are inserted.
This is for tables where the type is dectected later by thread*/
void setGeometryTypesForTable( const QString& schema, const QString& table, const QString& attribute, const QString& type );
void setGeometryTypesForTable( QgsPostgresLayerProperty layerProperty );

/**Returns the number of tables in the model*/
int tableCount() const { return mTableCount; }
Expand All @@ -48,20 +51,19 @@ class CORE_EXPORT QgsDbTableModel : public QStandardItemModel
dbtmTable,
dbtmType,
dbtmGeomCol,
dbtmSrid,
dbtmPkCol,
dbtmSelectAtId,
dbtmSql,
dbtmColumns
};

static QIcon iconForType( QGis::WkbType type );
static QString displayStringForType( QGis::WkbType type );
static QGis::WkbType qgisTypeFromDbType( QString dbType );

private:
/**Number of tables in the model*/
int mTableCount;

QIcon iconForType( QGis::WkbType type ) const;
QString displayStringForType( QGis::WkbType type ) const;

/**Returns qgis wkbtype from database typename*/
QGis::WkbType qgisTypeFromDbType( const QString& dbType ) const;
};

1,228 changes: 1,228 additions & 0 deletions src/providers/postgres/qgspostgresconn.cpp

Large diffs are not rendered by default.

236 changes: 236 additions & 0 deletions src/providers/postgres/qgspostgresconn.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/***************************************************************************
qgspostgresconn.h - connection class to PostgreSQL/PostGIS
-------------------
begin : 2011/01/28
copyright : (C) 2011 by Juergen E. Fischer
email : jef at norbit dot de
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSPOSTGRESCONN_H
#define QGSPOSTGRESCONN_H

#include <QString>
#include <QStringList>
#include <QVector>
#include <QMap>
#include <QMutex>

#include "qgis.h"
#include "qgsdatasourceuri.h"

extern "C"
{
#include <libpq-fe.h>
}

class QgsField;

/** Layer Property structure */
// TODO: Fill to Postgres/PostGIS specifications
struct QgsPostgresLayerProperty
{
// Postgres/PostGIS layer properties
QString type;
QString schemaName;
QString tableName;
QString geometryColName;
QStringList pkCols;
int srid;
QString sql;
};

class QgsPostgresResult
{
public:
QgsPostgresResult( PGresult *theRes = 0 ) : mRes( theRes ) {}
~QgsPostgresResult();

QgsPostgresResult &operator=( PGresult *theRes );
QgsPostgresResult &operator=( const QgsPostgresResult &src );

ExecStatusType PQresultStatus();
QString PQresultErrorMessage();

int PQntuples();
QString PQgetvalue( int row, int col );
bool PQgetisnull( int row, int col );

int PQnfields();
QString PQfname( int col );
int PQftable( int col );
int PQftype( int col );
int PQftablecol( int col );

PGresult *result() const { return mRes; }

private:
PGresult *mRes;
};

class QgsPostgresConn : public QObject
{
Q_OBJECT;
public:
static QgsPostgresConn *connectDb( QString connInfo, bool readOnly );
void disconnect();

//! get postgis version string
QString postgisVersion();

//! get status of GEOS capability
bool hasGEOS();

//! get status of topology capability
bool hasTopology();

//! get status of GIST capability
bool hasGIST();

//! get status of PROJ4 capability
bool hasPROJ();

//! encode wkb in hex
bool useWkbHex() { return mUseWkbHex; }

//! major PostgreSQL version
int majorVersion() { return mPostgisVersionMajor; }

//! PostgreSQL version
int pgVersion() { return mPostgresqlVersion; }

//! run a query and free result buffer
bool PQexecNR( QString query, bool retry = true );

//! cursor handling
bool openCursor( QString cursorName, QString declare );
bool closeCursor( QString cursorName );

#if 0
PGconn *pgConnection() { return mConn; }
#endif

//
// libpq wrapper
//

// run a query and check for errors
PGresult *PQexec( QString query );
void PQfinish();
QString PQerrorMessage();
int PQsendQuery( QString query );
int PQstatus();
PGresult *PQgetResult();
PGresult *PQprepare( QString stmtName, QString query, int nParams, const Oid *paramTypes );
PGresult *PQexecPrepared( QString stmtName, const QStringList &params );

/** Double quote a PostgreSQL identifier for placement in a SQL string.
*/
static QString quotedIdentifier( QString ident );

/** Quote a value for placement in a SQL string.
*/
static QString quotedValue( QVariant value );

//! Get the list of supported layers
bool supportedLayers( QVector<QgsPostgresLayerProperty> &layers,
bool searchGeometryColumnsOnly = true,
bool searchPublicOnly = true,
bool allowGeometrylessTables = false );

void retrieveLayerTypes( QgsPostgresLayerProperty &layerProperty, bool useEstimatedMetadata );

/** Gets information about the spatial tables */
bool getTableInfo( bool searchGeometryColumnsOnly, bool searchPublicOnly, bool allowGeometrylessTables );

/** get primary key candidates (all int4 columns) */
QStringList pkCandidates( QString schemaName, QString viewName );

qint64 getBinaryInt( QgsPostgresResult &queryResult, int row, int col );

QString fieldExpression( const QgsField &fld );

QString connInfo() const { return mConnInfo; }

static const int sGeomTypeSelectLimit;

static QString postgisGeometryTypeName( QGis::WkbType wkbType );
static int postgisGeometryTypeDim( QGis::WkbType wkbType );
static void postgisGeometryType( QGis::WkbType wkbType, QString &geometryType, int &dim );
static QGis::WkbType wkbTypeFromPostgis( QString type );

static QStringList connectionList();
static QString selectedConnection();
static void setSelectedConnection( QString theConnName );
static QgsDataSourceURI connUri( QString theConnName );

private:
QgsPostgresConn( QString conninfo, bool readOnly );
~QgsPostgresConn();

int mRef;
int mOpenCursors;
PGconn *mConn;
QString mConnInfo;

//! GEOS capability
bool mGeosAvailable;

//! Topology capability
bool mTopologyAvailable;

//! PostGIS version string
QString mPostgisVersionInfo;

//! Are mPostgisVersionMajor, mPostgisVersionMinor, mGeosAvailable, mGistAvailable, mProjAvailable, mTopologyAvailable valid?
bool mGotPostgisVersion;

//! PostgreSQL version
int mPostgresqlVersion;

//! PostGIS major version
int mPostgisVersionMajor;

//! PostGIS minor version
int mPostgisVersionMinor;

//! GIST capability
bool mGistAvailable;

//! PROJ4 capability
bool mProjAvailable;

//! encode wkb in hex
bool mUseWkbHex;

bool mReadOnly;

static QMap<QString, QgsPostgresConn *> sConnectionsRW;
static QMap<QString, QgsPostgresConn *> sConnectionsRO;

//! List of the supported layers
QVector<QgsPostgresLayerProperty> mLayersSupported;

/**
* Flag indicating whether data from binary cursors must undergo an
* endian conversion prior to use
@note
XXX Umm, it'd be helpful to know what we're swapping from and to.
XXX Presumably this means swapping from big-endian (network) byte order
XXX to little-endian; but the inverse transaction is possible, too, and
XXX that's not reflected in this variable
*/
bool mSwapEndian;
void deduceEndian();
};

#endif
132 changes: 0 additions & 132 deletions src/providers/postgres/qgspostgresconnection.cpp

This file was deleted.

51 changes: 0 additions & 51 deletions src/providers/postgres/qgspostgresconnection.h

This file was deleted.

204 changes: 118 additions & 86 deletions src/providers/postgres/qgspostgresdataitems.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#include "qgspostgresdataitems.h"

#include "qgslogger.h"

#include "qgspostgresconnection.h"
#include "qgspgsourceselect.h"
#include "qgspgnewconnection.h"
#include "qgscolumntypethread.h"
#include "qgslogger.h"
#include "qgsdatasourceuri.h"

// ---------------------------------------------------------------------------
QgsPGConnectionItem::QgsPGConnectionItem( QgsDataItem* parent, QString name, QString path )
Expand All @@ -21,37 +21,76 @@ QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
{
QgsDebugMsg( "Entered" );
QVector<QgsDataItem*> children;
QgsPostgresConnection connection( mName );
QgsPostgresProvider *pgProvider = connection.provider( );
if ( !pgProvider )
return children;
QgsDataSourceURI uri = QgsPostgresConn::connUri( mName );

QString mConnInfo = connection.connectionInfo();
QgsDebugMsg( "mConnInfo = " + mConnInfo );
mConn = QgsPostgresConn::connectDb( uri.connectionInfo(), true );
if ( !mConn )
return children;

QVector<QgsPostgresLayerProperty> layerProperties;
if ( !pgProvider->supportedLayers( layerProperties, true, false, false ) )
if ( !mConn->supportedLayers( layerProperties, true, false, false ) )
{
children.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) );
return children;
}

// fill the schemas map
mSchemasMap.clear();
QgsGeomColumnTypeThread *columnTypeThread = 0;

foreach( QgsPostgresLayerProperty layerProperty, layerProperties )
{
mSchemasMap[ layerProperty.schemaName ].push_back( layerProperty );
QgsPGSchemaItem *schemaItem = mSchemaMap.value( layerProperty.schemaName, 0 );
if ( !schemaItem )
{
schemaItem = new QgsPGSchemaItem( this, layerProperty.schemaName, mPath + "/" + layerProperty.schemaName );
children.append( schemaItem );
mSchemaMap[ layerProperty.schemaName ] = schemaItem;
}

if ( layerProperty.type == "GEOMETRY" )
{
if ( !columnTypeThread )
{
QgsPostgresConn *conn = QgsPostgresConn::connectDb( uri.connectionInfo(), true /* readonly */ );
if ( conn )
{
columnTypeThread = new QgsGeomColumnTypeThread( conn, true /* use estimated metadata */ );

connect( columnTypeThread, SIGNAL( setLayerType( QgsPostgresLayerProperty ) ),
this, SLOT( setLayerType( QgsPostgresLayerProperty ) ) );
columnTypeThread->start();
}
}
columnTypeThread->addGeometryColumn( layerProperty );
continue;
}

schemaItem->addLayer( layerProperty );
}

QMap<QString, QVector<QgsPostgresLayerProperty> >::const_iterator it = mSchemasMap.constBegin();
for ( ; it != mSchemasMap.constEnd(); it++ )
return children;
}

void QgsPGConnectionItem::setLayerType( QgsPostgresLayerProperty layerProperty )
{
QgsPGSchemaItem *schemaItem = mSchemaMap.value( layerProperty.schemaName, 0 );

if ( !schemaItem )
{
QgsDebugMsg( "schema: " + it.key() );
QgsPGSchemaItem * schema = new QgsPGSchemaItem( this, it.key(), mPath + "/" + it.key(), mConnInfo );
QgsDebugMsg( QString( "schema item for %1 not found." ).arg( layerProperty.schemaName ) );
return;
}

foreach( QString type, layerProperty.type.split( ",", QString::SkipEmptyParts ) )
{
QGis::WkbType wkbType = QgsPgTableModel::qgisTypeFromDbType( type );
if ( wkbType == QGis::WKBUnknown )
{
QgsDebugMsg( QString( "unsupported geometry type:%1" ).arg( type ) );
continue;
}

children.append( schema );
schemaItem->addLayer( layerProperty );
}
return children;
}

bool QgsPGConnectionItem::equal( const QgsDataItem *other )
Expand All @@ -60,8 +99,9 @@ bool QgsPGConnectionItem::equal( const QgsDataItem *other )
{
return false;
}
const QgsPGConnectionItem *o = dynamic_cast<const QgsPGConnectionItem *>( other );
return ( mPath == o->mPath && mName == o->mName && mConnInfo == o->mConnInfo );

const QgsPGConnectionItem *o = qobject_cast<const QgsPGConnectionItem *>( other );
return ( mPath == o->mPath && mName == o->mName && o->connection() == connection() );
}

QList<QAction*> QgsPGConnectionItem::actions()
Expand Down Expand Up @@ -98,10 +138,9 @@ void QgsPGConnectionItem::deleteConnection()


// ---------------------------------------------------------------------------
QgsPGLayerItem::QgsPGLayerItem( QgsDataItem* parent, QString name, QString path, QString connInfo, QgsLayerItem::LayerType layerType, QgsPostgresLayerProperty layerProperty )
: QgsLayerItem( parent, name, path, QString(), layerType, "postgres" ),
mConnInfo( connInfo ),
mLayerProperty( layerProperty )
QgsPGLayerItem::QgsPGLayerItem( QgsDataItem* parent, QString name, QString path, QgsLayerItem::LayerType layerType, QgsPostgresLayerProperty layerProperty )
: QgsLayerItem( parent, name, path, QString(), layerType, "postgres" )
, mLayerProperty( layerProperty )
{
mUri = createUri();
mPopulated = true;
Expand All @@ -114,61 +153,73 @@ QgsPGLayerItem::~QgsPGLayerItem()
QString QgsPGLayerItem::createUri()
{
QString pkColName = mLayerProperty.pkCols.size() > 0 ? mLayerProperty.pkCols.at( 0 ) : QString::null;
QgsDataSourceURI uri( mConnInfo );
QgsPGConnectionItem *connItem = qobject_cast<QgsPGConnectionItem *>( parent() ? parent()->parent() : 0 );

if ( !connItem )
{
QgsDebugMsg( "connection item not found." );
return QString::null;
}

QgsDebugMsg( QString( "connInfo: %1" ).arg( connItem->connection()->connInfo() ) );

QgsDataSourceURI uri( connItem->connection()->connInfo() );
uri.setDataSource( mLayerProperty.schemaName, mLayerProperty.tableName, mLayerProperty.geometryColName, mLayerProperty.sql, pkColName );
uri.setSrid( QString::number( mLayerProperty.srid ) );
uri.setGeometryType( QgsPgTableModel::qgisTypeFromDbType( mLayerProperty.type ) );
QgsDebugMsg( QString( "layer uri: %1" ).arg( uri.uri() ) );
return uri.uri();
}

// ---------------------------------------------------------------------------
QgsPGSchemaItem::QgsPGSchemaItem( QgsDataItem* parent, QString name, QString path, QString connInfo )
QgsPGSchemaItem::QgsPGSchemaItem( QgsDataItem* parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path )
{
mIcon = QIcon( getThemePixmap( "mIconDbSchema.png" ) );
mConnInfo = connInfo;
}

QVector<QgsDataItem*> QgsPGSchemaItem::createChildren()
{
QgsPGConnectionItem* connItem = dynamic_cast<QgsPGConnectionItem*>( mParent );
Q_ASSERT( connItem );
QVector<QgsPostgresLayerProperty> layers = connItem->mSchemasMap.value( mName );
QgsDebugMsg( "Entering." );
return QVector<QgsDataItem*>();
}

QVector<QgsDataItem*> children;
// Populate everything, it costs nothing, all info about layers is collected
foreach( QgsPostgresLayerProperty layerProperty, layers )
{
QgsDebugMsg( "table: " + layerProperty.schemaName + "." + layerProperty.tableName );
QgsPGSchemaItem::~QgsPGSchemaItem()
{
}

QgsLayerItem::LayerType layerType = QgsLayerItem::NoType;
if ( layerProperty.type.contains( "POINT" ) )
{
layerType = QgsLayerItem::Point;
}
else if ( layerProperty.type.contains( "LINE" ) )
{
layerType = QgsLayerItem::Line;
}
else if ( layerProperty.type.contains( "POLYGON" ) )
{
layerType = QgsLayerItem::Polygon;
}
else if ( layerProperty.type == QString::null )
{
if ( layerProperty.geometryColName == QString::null )
{
layerType = QgsLayerItem::TableLayer;
}
}
void QgsPGSchemaItem::addLayer( QgsPostgresLayerProperty layerProperty )
{
QGis::WkbType wkbType = QgsPgTableModel::qgisTypeFromDbType( layerProperty.type );
QString name = layerProperty.tableName + "." + layerProperty.geometryColName;

QgsPGLayerItem * layer = new QgsPGLayerItem( this, layerProperty.tableName, mPath + "/" + layerProperty.tableName, mConnInfo, layerType, layerProperty );
children.append( layer );
QgsLayerItem::LayerType layerType;
if ( layerProperty.type.contains( "POINT" ) )
{
layerType = QgsLayerItem::Point;
}
else if ( layerProperty.type.contains( "LINE" ) )
{
layerType = QgsLayerItem::Line;
}
else if ( layerProperty.type.contains( "POLYGON" ) )
{
layerType = QgsLayerItem::Polygon;
}
else if ( layerProperty.type.isEmpty() && layerProperty.geometryColName.isEmpty() )
{
layerType = QgsLayerItem::TableLayer;
name = layerProperty.tableName;
}
else
{
return;
}

return children;
}
name += " (" + QgsPgTableModel::displayStringForType( wkbType ) + ")";

QgsPGSchemaItem::~QgsPGSchemaItem()
{
QgsPGLayerItem *layerItem = new QgsPGLayerItem( this, name, mPath + "/" + name, layerType, layerProperty );
addChild( layerItem );
}

// ---------------------------------------------------------------------------
Expand All @@ -183,13 +234,12 @@ QgsPGRootItem::~QgsPGRootItem()
{
}

QVector<QgsDataItem*>QgsPGRootItem::createChildren()
QVector<QgsDataItem*> QgsPGRootItem::createChildren()
{
QVector<QgsDataItem*> connections;
foreach( QString connName, QgsPostgresConnection::connectionList() )
foreach( QString connName, QgsPostgresConn::connectionList() )
{
QgsDataItem * conn = new QgsPGConnectionItem( this, connName, mPath + "/" + connName );
connections.push_back( conn );
connections << new QgsPGConnectionItem( this, connName, mPath + "/" + connName );
}
return connections;
}
Expand All @@ -205,12 +255,13 @@ QList<QAction*> QgsPGRootItem::actions()
return lst;
}

QWidget * QgsPGRootItem::paramWidget()
QWidget *QgsPGRootItem::paramWidget()
{
QgsPgSourceSelect *select = new QgsPgSourceSelect( 0, 0, true, true );
connect( select, SIGNAL( connectionsChanged() ), this, SLOT( connectionsChanged() ) );
return select;
}

void QgsPGRootItem::connectionsChanged()
{
refresh();
Expand All @@ -224,22 +275,3 @@ void QgsPGRootItem::newConnection()
refresh();
}
}

// ---------------------------------------------------------------------------

QGISEXTERN QgsPgSourceSelect * selectWidget( QWidget * parent, Qt::WFlags fl )
{
// TODO: this should be somewhere else
return new QgsPgSourceSelect( parent, fl );
}

QGISEXTERN int dataCapabilities()
{
return QgsDataProvider::Database;
}

QGISEXTERN QgsDataItem * dataItem( QString thePath, QgsDataItem* parentItem )
{
Q_UNUSED( thePath );
return new QgsPGRootItem( parentItem, "PostGIS", "pg:" );
}
73 changes: 39 additions & 34 deletions src/providers/postgres/qgspostgresdataitems.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,31 @@

#include "qgsdataitem.h"

#include "qgspostgresprovider.h"
#include "qgspostgresconn.h"
#include "qgspgsourceselect.h"

class QgsPGRootItem;
class QgsPGConnectionItem;
class QgsPGSchemaItem;
class QgsPGLayerItem;

class QgsPGRootItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsPGRootItem( QgsDataItem* parent, QString name, QString path );
~QgsPGRootItem();

QVector<QgsDataItem*> createChildren();

virtual QWidget * paramWidget();

virtual QList<QAction*> actions();

public slots:
void connectionsChanged();
void newConnection();
};

class QgsPGConnectionItem : public QgsDataCollectionItem
{
Expand All @@ -14,64 +38,45 @@ class QgsPGConnectionItem : public QgsDataCollectionItem

QVector<QgsDataItem*> createChildren();
virtual bool equal( const QgsDataItem *other );

virtual QList<QAction*> actions();

QString mConnInfo;
QMap<QString, QVector<QgsPostgresLayerProperty> > mSchemasMap;
QgsPostgresConn *connection() const { return mConn; }

public slots:
void editConnection();
void deleteConnection();
};

// WMS Layers may be nested, so that they may be both QgsDataCollectionItem and QgsLayerItem
// We have to use QgsDataCollectionItem and support layer methods if necessary
class QgsPGLayerItem : public QgsLayerItem
{
Q_OBJECT
public:
QgsPGLayerItem( QgsDataItem* parent, QString name, QString path,
QString connInfo, QgsLayerItem::LayerType layerType, QgsPostgresLayerProperty layerProperties );
~QgsPGLayerItem();

QString createUri();
void setLayerType( QgsPostgresLayerProperty layerProperty );

QString mConnInfo;
QgsPostgresLayerProperty mLayerProperty;
private:
QgsPostgresConn *mConn;
QMap<QString, QgsPGSchemaItem * > mSchemaMap;
};

class QgsPGSchemaItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsPGSchemaItem( QgsDataItem* parent, QString name, QString path,
QString connInfo );
QgsPGSchemaItem( QgsDataItem* parent, QString name, QString path );
~QgsPGSchemaItem();

QVector<QgsDataItem*> createChildren();

protected:
QString mConnInfo;
void addLayer( QgsPostgresLayerProperty layerProperty );
};

class QgsPGRootItem : public QgsDataCollectionItem
class QgsPGLayerItem : public QgsLayerItem
{
Q_OBJECT
public:
QgsPGRootItem( QgsDataItem* parent, QString name, QString path );
~QgsPGRootItem();

QVector<QgsDataItem*> createChildren();

virtual QWidget * paramWidget();
public:
QgsPGLayerItem( QgsDataItem* parent, QString name, QString path, QgsLayerItem::LayerType layerType, QgsPostgresLayerProperty layerProperties );
~QgsPGLayerItem();

virtual QList<QAction*> actions();
QString createUri();

public slots:
void connectionsChanged();
void newConnection();
private:
QgsPostgresLayerProperty mLayerProperty;
};


#endif // QGSPOSTGRESDATAITEMS_H
4,040 changes: 1,342 additions & 2,698 deletions src/providers/postgres/qgspostgresprovider.cpp

Large diffs are not rendered by default.

401 changes: 62 additions & 339 deletions src/providers/postgres/qgspostgresprovider.h

Large diffs are not rendered by default.

File renamed without changes.