255 changes: 99 additions & 156 deletions src/providers/postgres/qgspgtablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,104 +42,109 @@ QgsPgTableModel::~QgsPgTableModel()

void QgsPgTableModel::addTableEntry( QgsPostgresLayerProperty layerProperty )
{
QgsDebugMsg( QString( "%1.%2.%3 type=%4 geomType=%5 srid=%6 pk=%7 sql=%8" )
.arg( layerProperty.schemaName )
.arg( layerProperty.tableName )
.arg( layerProperty.geometryColName )
.arg( layerProperty.type )
.arg( layerProperty.geometryColType )
.arg( layerProperty.srid )
.arg( layerProperty.pkCols.join( "," ) )
.arg( layerProperty.sql ) );
QgsDebugMsg( layerProperty.toString() );

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

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

QGis::WkbType wkbType = QgsPostgresConn::wkbTypeFromPostgis( layerProperty.type );
if ( wkbType == QGis::WKBUnknown && layerProperty.geometryColName.isEmpty() )
{
wkbType = QGis::WKBNoGeometry;
}

QList<QStandardItem*> childItemList;
QGis::WkbType wkbType = layerProperty.types[ i ];
int srid = layerProperty.srids[ i ];
if ( wkbType == QGis::WKBUnknown && layerProperty.geometryColName.isEmpty() )
{
wkbType = QGis::WKBNoGeometry;
}

QStandardItem *schemaNameItem = new QStandardItem( layerProperty.schemaName );
schemaNameItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
bool selectable = wkbType == QGis::WKBNoGeometry || ( wkbType != QGis::WKBUnknown && srid != 0 );

QStandardItem *typeItem = new QStandardItem( iconForWkbType( wkbType ),
wkbType == QGis::WKBUnknown
? tr( "Detecting..." )
: QgsPostgresConn::displayStringForWkbType( wkbType ) );
typeItem->setData( wkbType == QGis::WKBUnknown, Qt::UserRole + 1 );
typeItem->setData( wkbType, Qt::UserRole + 2 );
QStandardItem *schemaNameItem = new QStandardItem( layerProperty.schemaName );
QStandardItem *typeItem = new QStandardItem( iconForWkbType( wkbType ), wkbType == QGis::WKBUnknown ? tr( "Select..." ) : QgsPostgresConn::displayStringForWkbType( wkbType ) );
typeItem->setData( wkbType == QGis::WKBUnknown, Qt::UserRole + 1 );
typeItem->setData( wkbType, Qt::UserRole + 2 );
if ( wkbType == QGis::WKBUnknown )
typeItem->setFlags( typeItem->flags() | Qt::ItemIsEditable );

QStandardItem *geomTypeItem = new QStandardItem( QgsPostgresConn::displayStringForGeomType( layerProperty.geometryColType ) );
QStandardItem *geomTypeItem = new QStandardItem( QgsPostgresConn::displayStringForGeomType( layerProperty.geometryColType ) );

QStandardItem *tableItem = new QStandardItem( layerProperty.tableName );
QStandardItem *geomItem = new QStandardItem( layerProperty.geometryColName );
QStandardItem *sridItem = new QStandardItem( layerProperty.srid );
sridItem->setEditable( false );
QStandardItem *tableItem = new QStandardItem( layerProperty.tableName );
QStandardItem *geomItem = new QStandardItem( layerProperty.geometryColName );
QStandardItem *sridItem = new QStandardItem( wkbType != QGis::WKBNoGeometry ? QString::number( srid ) : "" );
sridItem->setEditable( wkbType != QGis::WKBNoGeometry && srid == 0 );
if ( sridItem->isEditable() )
{
sridItem->setText( tr( "Enter..." ) );
sridItem->setFlags( sridItem->flags() | Qt::ItemIsEditable );
}

QString pkCol = "";
if ( layerProperty.pkCols.size() > 0 )
{
pkCol = layerProperty.pkCols[0];
}
QString pkCol = "";
if ( layerProperty.pkCols.size() > 0 )
{
pkCol = layerProperty.pkCols[0];
}

QStandardItem *pkItem = new QStandardItem( pkCol );
if ( layerProperty.pkCols.size() > 1 )
pkItem->setFlags( pkItem->flags() | Qt::ItemIsEditable );
else
pkItem->setFlags( pkItem->flags() & ~Qt::ItemIsEditable );
QStandardItem *pkItem = new QStandardItem( pkCol );
if ( layerProperty.pkCols.size() > 1 )
pkItem->setFlags( pkItem->flags() | Qt::ItemIsEditable );
else
pkItem->setFlags( pkItem->flags() & ~Qt::ItemIsEditable );

pkItem->setData( layerProperty.pkCols, Qt::UserRole + 1 );
pkItem->setData( pkCol, Qt::UserRole + 2 );
pkItem->setData( layerProperty.pkCols, Qt::UserRole + 1 );
pkItem->setData( pkCol, Qt::UserRole + 2 );

QStandardItem *selItem = new QStandardItem( "" );
selItem->setFlags( selItem->flags() | 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 *selItem = new QStandardItem( "" );
selItem->setFlags( selItem->flags() | 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( layerProperty.sql );
QStandardItem* sqlItem = new QStandardItem( layerProperty.sql );

childItemList << schemaNameItem;
childItemList << tableItem;
childItemList << geomItem;
childItemList << geomTypeItem;
childItemList << typeItem;
childItemList << sridItem;
childItemList << pkItem;
childItemList << selItem;
childItemList << sqlItem;
QList<QStandardItem*> childItemList;

bool detailsFromThread = wkbType == QGis::WKBUnknown ||
( wkbType != QGis::WKBNoGeometry && layerProperty.srid.isEmpty() );
childItemList << schemaNameItem;
childItemList << tableItem;
childItemList << geomItem;
childItemList << geomTypeItem;
childItemList << typeItem;
childItemList << sridItem;
childItemList << pkItem;
childItemList << selItem;
childItemList << sqlItem;

if ( detailsFromThread )
{
foreach ( QStandardItem *item, childItemList )
{
item->setFlags( item->flags() & ~( Qt::ItemIsSelectable | Qt::ItemIsEnabled ) );
if ( selectable )
{
item->setFlags( item->flags() | Qt::ItemIsSelectable );
}
else
{
item->setFlags( item->flags() & ~Qt::ItemIsSelectable );
}
}

if ( !schemaItem )
{
QList<QStandardItem*> schemaItems = findItems( layerProperty.schemaName, Qt::MatchExactly, dbtmSchema );

// 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
schemaItem = new QStandardItem( layerProperty.schemaName );
schemaItem->setFlags( Qt::ItemIsEnabled );
invisibleRootItem()->setChild( invisibleRootItem()->rowCount(), schemaItem );
}
}
}

schemaItem->appendRow( childItemList );
schemaItem->appendRow( childItemList );

++mTableCount;
++mTableCount;
}
}

void QgsPgTableModel::setSql( const QModelIndex &index, const QString &sql )
Expand Down Expand Up @@ -204,84 +209,6 @@ void QgsPgTableModel::setSql( const QModelIndex &index, const QString &sql )
}
}

void QgsPgTableModel::setGeometryTypesForTable( QgsPostgresLayerProperty layerProperty )
{
QStringList typeList = layerProperty.type.split( ",", QString::SkipEmptyParts );
QStringList sridList = layerProperty.srid.split( ",", QString::SkipEmptyParts );
Q_ASSERT( typeList.size() == sridList.size() );

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

if ( schemaItems.size() < 1 )
{
return;
}

schemaItem = schemaItems.at( 0 );

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

QList<QStandardItem *> row;

for ( int j = 0; j < dbtmColumns; j++ )
{
row << itemFromIndex( currentChildIndex.sibling( i, j ) );
}

if ( row[ dbtmTable ]->text() == layerProperty.tableName && row[ dbtmGeomCol ]->text() == layerProperty.geometryColName )
{
row[ dbtmSrid ]->setText( layerProperty.srid );

if ( typeList.isEmpty() )
{
row[ dbtmType ]->setText( tr( "Select..." ) );
row[ dbtmType ]->setFlags( row[ dbtmType ]->flags() | Qt::ItemIsEditable );

row[ dbtmSrid ]->setText( tr( "Enter..." ) );
row[ dbtmSrid ]->setFlags( row[ dbtmSrid ]->flags() | Qt::ItemIsEditable );

foreach ( QStandardItem *item, row )
{
item->setFlags( item->flags() | Qt::ItemIsEnabled );
}
}
else
{
// update existing row
QGis::WkbType wkbType = QgsPostgresConn::wkbTypeFromPostgis( typeList.at( 0 ) );

row[ dbtmType ]->setIcon( iconForWkbType( wkbType ) );
row[ dbtmType ]->setText( QgsPostgresConn::displayStringForWkbType( wkbType ) );
row[ dbtmType ]->setData( false, Qt::UserRole + 1 );
row[ dbtmType ]->setData( wkbType, Qt::UserRole + 2 );

row[ dbtmSrid ]->setText( sridList.at( 0 ) );

foreach ( QStandardItem *item, row )
{
item->setFlags( item->flags() | Qt::ItemIsSelectable | Qt::ItemIsEnabled );
}

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

QIcon QgsPgTableModel::iconForWkbType( QGis::WkbType type )
{
switch ( type )
Expand Down Expand Up @@ -321,7 +248,10 @@ bool QgsPgTableModel::setData( const QModelIndex &idx, const QVariant &value, in
bool ok = geomType != QGis::WKBUnknown;

if ( ok && geomType != QGis::WKBNoGeometry )
idx.sibling( idx.row(), dbtmSrid ).data().toInt( &ok );
{
int srid = idx.sibling( idx.row(), dbtmSrid ).data().toInt( &ok );
ok &= srid != 0;
}

QStringList pkCols = idx.sibling( idx.row(), dbtmPkCol ).data( Qt::UserRole + 1 ).toStringList();
if ( ok && pkCols.size() > 0 )
Expand All @@ -343,20 +273,29 @@ bool QgsPgTableModel::setData( const QModelIndex &idx, const QVariant &value, in
QString QgsPgTableModel::layerURI( const QModelIndex &index, QString connInfo, bool useEstimatedMetadata )
{
if ( !index.isValid() )
{
QgsDebugMsg( "invalid index" );
return QString::null;
}

QGis::WkbType wkbType = ( QGis::WkbType ) itemFromIndex( index.sibling( index.row(), dbtmType ) )->data( Qt::UserRole + 2 ).toInt();
if ( wkbType == QGis::WKBUnknown )
{
QgsDebugMsg( "unknown geometry type" );
// no geometry type selected
return QString::null;
}

QStandardItem *pkItem = itemFromIndex( index.sibling( index.row(), dbtmPkCol ) );
QString pkColumnName = pkItem->data( Qt::UserRole + 2 ).toString();

if ( pkItem->data( Qt::UserRole + 1 ).toStringList().size() > 0 &&
!pkItem->data( Qt::UserRole + 1 ).toStringList().contains( pkColumnName ) )
{
// no valid primary candidate selected
QgsDebugMsg( "no pk candidate selected" );
return QString::null;
}

QString schemaName = index.sibling( index.row(), dbtmSchema ).data( Qt::DisplayRole ).toString();
QString tableName = index.sibling( index.row(), dbtmTable ).data( Qt::DisplayRole ).toString();
Expand All @@ -371,7 +310,10 @@ QString QgsPgTableModel::layerURI( const QModelIndex &index, QString connInfo, b
bool ok;
srid.toInt( &ok );
if ( !ok )
{
QgsDebugMsg( "srid not numeric" );
return QString::null;
}
}

bool selectAtId = itemFromIndex( index.sibling( index.row(), dbtmSelectAtId ) )->checkState() == Qt::Checked;
Expand All @@ -384,5 +326,6 @@ QString QgsPgTableModel::layerURI( const QModelIndex &index, QString connInfo, b
uri.setSrid( srid );
uri.disableSelectAtId( !selectAtId );

QgsDebugMsg( QString( "returning uri %1" ).arg( uri.uri() ) );
return uri.uri();
}
8 changes: 3 additions & 5 deletions src/providers/postgres/qgspgtablemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSPGTABLEMODEL_H
#define QGSPGTABLEMODEL_H
#include <QStandardItemModel>

#include "qgis.h"
Expand All @@ -38,10 +39,6 @@ class QgsPgTableModel : public QStandardItemModel
/**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( QgsPostgresLayerProperty layerProperty );

/**Returns the number of tables in the model*/
int tableCount() const { return mTableCount; }

Expand Down Expand Up @@ -70,3 +67,4 @@ class QgsPgTableModel : public QStandardItemModel
int mTableCount;
};

#endif // QGSPGTABLEMODEL_H
113 changes: 51 additions & 62 deletions src/providers/postgres/qgspostgresconn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,11 +389,13 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
.arg( relkind ) );

layerProperty.pkCols.clear();
layerProperty.type = type;
layerProperty.schemaName = schemaName;
layerProperty.tableName = tableName;
layerProperty.geometryColName = column;
layerProperty.geometryColType = columnType;
layerProperty.types = QList<QGis::WkbType>() << ( QgsPostgresConn::wkbTypeFromPostgis( type ) );
layerProperty.srids = QList<int>() << srid.toInt();
layerProperty.sql = "";

if ( relkind == "v" )
{
Expand All @@ -405,9 +407,6 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
}
}

layerProperty.srid = srid;
layerProperty.sql = "";

mLayersSupported << layerProperty;
nColumns++;
}
Expand Down Expand Up @@ -493,7 +492,8 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP

QgsDebugMsg( QString( "%1.%2.%3: %4" ).arg( schemaName ).arg( tableName ).arg( column ).arg( relkind ) );

layerProperty.type = QString::null;
layerProperty.types.clear();
layerProperty.srids.clear();
layerProperty.schemaName = schemaName;
layerProperty.tableName = tableName;
layerProperty.geometryColName = column;
Expand Down Expand Up @@ -531,7 +531,6 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
}
}


if ( allowGeometrylessTables )
{
QString sql = "SELECT "
Expand Down Expand Up @@ -570,13 +569,13 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP

QgsDebugMsg( QString( "%1.%2: %3" ).arg( schema ).arg( table ).arg( relkind ) );

layerProperty.type = QString::null;
layerProperty.types = QList<QGis::WkbType>() << QGis::WKBUnknown;
layerProperty.srids = QList<int>() << 0;
layerProperty.schemaName = schema;
layerProperty.tableName = table;
layerProperty.geometryColName = QString::null;
layerProperty.geometryColType = sctNone;
layerProperty.pkCols = relkind == "v" ? pkCandidates( schema, table ) : QStringList();
layerProperty.srid = "";
layerProperty.sql = "";

mLayersSupported << layerProperty;
Expand Down Expand Up @@ -1095,66 +1094,56 @@ void QgsPostgresConn::retrieveLayerTypes( QgsPostgresLayerProperty &layerPropert
table = layerProperty.tableName;
}


// our estimatation ignores that a where clause might restrict the feature type or srid
if ( useEstimatedMetadata )
{
table = QString( "(SELECT %1 FROM %2 WHERE %1 IS NOT NULL%3 LIMIT %4) AS t" )
.arg( quotedIdentifier( layerProperty.geometryColName ) )
.arg( table )
.arg( layerProperty.sql.isEmpty() ? "" : QString( " AND (%1)" ).arg( layerProperty.sql ) )
.arg( sGeomTypeSelectLimit );
}
else if ( !layerProperty.sql.isEmpty() )
{
table += QString( " WHERE %1" ).arg( layerProperty.sql );
}

QString query = QString( "SELECT DISTINCT"
" CASE"
" WHEN %1 THEN 'POINT'"
" WHEN %2 THEN 'LINESTRING'"
" WHEN %3 THEN 'POLYGON'"
" END,"
" %4(%5%6)"
" FROM %7" )
.arg( postgisTypeFilter( layerProperty.geometryColName, QGis::WKBPoint, layerProperty.geometryColType == sctGeography ) )
.arg( postgisTypeFilter( layerProperty.geometryColName, QGis::WKBLineString, layerProperty.geometryColType == sctGeography ) )
.arg( postgisTypeFilter( layerProperty.geometryColName, QGis::WKBPolygon, layerProperty.geometryColType == sctGeography ) )
.arg( majorVersion() < 2 ? "srid" : "st_srid" )
.arg( quotedIdentifier( layerProperty.geometryColName ) )
.arg( layerProperty.geometryColType == sctGeography ? "::geometry" : "" )
.arg( table );

QgsDebugMsg( "Retrieving geometry types: " + query );

QgsPostgresResult gresult = PQexec( query );

QString type;
QString srid;
if ( gresult.PQresultStatus() == PGRES_TUPLES_OK )
if ( !layerProperty.geometryColName.isEmpty() )
{
QStringList types;
QStringList srids;
// our estimatation ignores that a where clause might restrict the feature type or srid
if ( useEstimatedMetadata )
{
table = QString( "(SELECT %1 FROM %2 WHERE %1 IS NOT NULL%3 LIMIT %4) AS t" )
.arg( quotedIdentifier( layerProperty.geometryColName ) )
.arg( table )
.arg( layerProperty.sql.isEmpty() ? "" : QString( " AND (%1)" ).arg( layerProperty.sql ) )
.arg( sGeomTypeSelectLimit );
}
else if ( !layerProperty.sql.isEmpty() )
{
table += QString( " WHERE %1" ).arg( layerProperty.sql );
}

for ( int i = 0; i < gresult.PQntuples(); i++ )
QString query = QString( "SELECT DISTINCT"
" CASE"
" WHEN %1 THEN 'POINT'"
" WHEN %2 THEN 'LINESTRING'"
" WHEN %3 THEN 'POLYGON'"
" END,"
" %4(%5%6)"
" FROM %7" )
.arg( postgisTypeFilter( layerProperty.geometryColName, QGis::WKBPoint, layerProperty.geometryColType == sctGeography ) )
.arg( postgisTypeFilter( layerProperty.geometryColName, QGis::WKBLineString, layerProperty.geometryColType == sctGeography ) )
.arg( postgisTypeFilter( layerProperty.geometryColName, QGis::WKBPolygon, layerProperty.geometryColType == sctGeography ) )
.arg( majorVersion() < 2 ? "srid" : "st_srid" )
.arg( quotedIdentifier( layerProperty.geometryColName ) )
.arg( layerProperty.geometryColType == sctGeography ? "::geometry" : "" )
.arg( table );

QgsDebugMsg( "Retrieving geometry types: " + query );

QgsPostgresResult gresult = PQexec( query );

if ( gresult.PQresultStatus() == PGRES_TUPLES_OK )
{
QString type = gresult.PQgetvalue( i, 0 );
QString srid = gresult.PQgetvalue( i, 1 );
if ( type.isEmpty() )
continue;
for ( int i = 0; i < gresult.PQntuples(); i++ )
{
QString type = gresult.PQgetvalue( i, 0 );
QString srid = gresult.PQgetvalue( i, 1 );
if ( type.isEmpty() )
continue;

types << type;
srids << srid;
layerProperty.types << QgsPostgresConn::wkbTypeFromPostgis( type );
layerProperty.srids << srid.toInt();
}
}

type = types.join( "," );
srid = srids.join( "," );
}

QgsDebugMsg( QString( "type:%1 srid:%2" ).arg( type ).arg( srid ) );
layerProperty.type = type;
layerProperty.srid = srid;
}

void QgsPostgresConn::postgisWkbType( QGis::WkbType wkbType, QString &geometryType, int &dim )
Expand Down
53 changes: 51 additions & 2 deletions src/providers/postgres/qgspostgresconn.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,63 @@ enum QgsPostgresGeometryColumnType
struct QgsPostgresLayerProperty
{
// Postgres/PostGIS layer properties
QString type;
QList<QGis::WkbType> types;
QString schemaName;
QString tableName;
QString geometryColName;
QgsPostgresGeometryColumnType geometryColType;
QStringList pkCols;
QString srid;
QList<int> srids;
QString sql;

int size() { Q_ASSERT( types.size() == srids.size() ); return types.size(); }

QgsPostgresLayerProperty at( int i )
{
QgsPostgresLayerProperty property;

Q_ASSERT( i >= 0 && i < size() );

property.types << types[ i ];
property.srids << srids[ i ];
property.schemaName = schemaName;
property.tableName = tableName;
property.geometryColName = geometryColName;
property.geometryColType = geometryColType;
property.pkCols = pkCols;
property.sql = sql;

return property;
}

#if QGISDEBUG
QString toString()
{
QString typeString;
foreach ( QGis::WkbType type, types )
{
if ( !typeString.isEmpty() )
typeString += "|";
typeString += QString::number( type );
}
QString sridString;
foreach ( int srid, srids )
{
if ( !sridString.isEmpty() )
sridString += "|";
sridString += QString::number( srid );
}

return QString( "%1.%2.%3 type=%4 srid=%5 pkCols=%6 sql=%7" )
.arg( schemaName )
.arg( tableName )
.arg( geometryColName )
.arg( typeString )
.arg( sridString )
.arg( pkCols.join( "|" ) )
.arg( sql );
}
#endif
};

class QgsPostgresResult
Expand Down
156 changes: 64 additions & 92 deletions src/providers/postgres/qgspostgresdataitems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,106 +73,66 @@ void QgsPGConnectionItem::refresh()
QVector<QgsDataItem*> QgsPGConnectionItem::createChildren()
{
QgsDebugMsg( "Entered" );
QVector<QgsDataItem*> children;
QgsDataSourceURI uri = QgsPostgresConn::connUri( mName );

mSchemaMap.clear();

mConn = QgsPostgresConn::connectDb( uri.connectionInfo(), true );
if ( !mConn )
return children;

QVector<QgsPostgresLayerProperty> layerProperties;
if ( !mConn->supportedLayers( layerProperties,
QgsPostgresConn::geometryColumnsOnly( mName ),
QgsPostgresConn::publicSchemaOnly( mName ),
QgsPostgresConn::allowGeometrylessTables( mName ) ) )
{
children.append( new QgsErrorItem( this, tr( "Failed to retrieve layers" ), mPath + "/error" ) );
return children;
}

if ( layerProperties.isEmpty() )
{
children.append( new QgsErrorItem( this, tr( "No layers found." ), mPath + "/error" ) );
return children;
}

stop();

bool dontResolveType = QgsPostgresConn::dontResolveType( mName );

foreach ( QgsPostgresLayerProperty layerProperty, layerProperties )
if ( !mColumnTypeThread )
{
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 ( QgsPostgresConn::wkbTypeFromPostgis( layerProperty.type ) == QGis::WKBUnknown )
{
if ( !dontResolveType )
{
QgsDebugMsg( QString( "Skip column %1.%2.%3 without type constraint" ).arg( layerProperty.schemaName ).arg( layerProperty.tableName ).arg( layerProperty.geometryColName ) );
continue;
}

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

connect( mColumnTypeThread, SIGNAL( setLayerType( QgsPostgresLayerProperty ) ),
this, SLOT( setLayerType( QgsPostgresLayerProperty ) ) );
connect( this, SIGNAL( addGeometryColumn( QgsPostgresLayerProperty ) ),
mColumnTypeThread, SLOT( addGeometryColumn( QgsPostgresLayerProperty ) ) );
}
}
mColumnTypeThread = new QgsGeomColumnTypeThread( mName, true /* useEstimatedMetadata */, QgsPostgresConn::allowGeometrylessTables( mName ) );

emit addGeometryColumn( layerProperty );
connect( mColumnTypeThread, SIGNAL( setLayerType( QgsPostgresLayerProperty ) ),
this, SLOT( setLayerType( QgsPostgresLayerProperty ) ) );
connect( mColumnTypeThread, SIGNAL( started() ), this, SLOT( threadStarted() ) );
connect( mColumnTypeThread, SIGNAL( finished() ), this, SLOT( threadFinished() ) );

continue;
if ( QgsPGRootItem::sMainWindow )
{
connect( mColumnTypeThread, SIGNAL( progress( int, int ) ),
QgsPGRootItem::sMainWindow, SLOT( showProgress( int, int ) ) );
connect( mColumnTypeThread, SIGNAL( progressMessage( QString ) ),
QgsPGRootItem::sMainWindow, SLOT( showStatusMessage( QString ) ) );
}

schemaItem->addLayer( layerProperty );
}

if ( mColumnTypeThread )
mColumnTypeThread->start();

return children;
return QVector<QgsDataItem*>();
}

void QgsPGConnectionItem::setLayerType( QgsPostgresLayerProperty layerProperty )
void QgsPGConnectionItem::threadStarted()
{
QgsPGSchemaItem *schemaItem = mSchemaMap.value( layerProperty.schemaName, 0 );
QgsDebugMsg( "Entering." );
qApp->setOverrideCursor( Qt::BusyCursor );
}

if ( !schemaItem )
{
QgsDebugMsg( QString( "schema item for %1 not found." ).arg( layerProperty.schemaName ) );
return;
}
void QgsPGConnectionItem::threadFinished()
{
QgsDebugMsg( "Entering." );
qApp->restoreOverrideCursor();
}

QStringList typeList = layerProperty.type.split( ",", QString::SkipEmptyParts );
QStringList sridList = layerProperty.srid.split( ",", QString::SkipEmptyParts );
Q_ASSERT( typeList.size() == sridList.size() );
void QgsPGConnectionItem::setLayerType( QgsPostgresLayerProperty layerProperties )
{
QgsDebugMsg( layerProperties.toString() );
QgsPGSchemaItem *schemaItem = mSchemaMap.value( layerProperties.schemaName, 0 );

for ( int i = 0 ; i < typeList.size(); i++ )
for ( int i = 0; i < layerProperties.size(); i++ )
{
QGis::WkbType wkbType = QgsPostgresConn::wkbTypeFromPostgis( typeList[i] );
if ( wkbType == QGis::WKBUnknown )
{
QgsDebugMsg( QString( "unsupported geometry type:%1" ).arg( typeList[i] ) );
QgsPostgresLayerProperty layerProperty = layerProperties.at( i );

if ( layerProperty.types[0] == QGis::WKBUnknown && !layerProperty.geometryColName.isEmpty() )
continue;

if ( !schemaItem )
{
schemaItem = new QgsPGSchemaItem( this, layerProperty.schemaName, mPath + "/" + layerProperty.schemaName );
addChildItem( schemaItem, true );
mSchemaMap[ layerProperty.schemaName ] = schemaItem;
}

layerProperty.type = typeList[i];
layerProperty.srid = sridList[i];
schemaItem->addLayer( layerProperty );
}
}
Expand All @@ -185,7 +145,7 @@ bool QgsPGConnectionItem::equal( const QgsDataItem *other )
}

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

QList<QAction*> QgsPGConnectionItem::actions()
Expand All @@ -200,6 +160,10 @@ QList<QAction*> QgsPGConnectionItem::actions()
connect( actionDelete, SIGNAL( triggered() ), this, SLOT( deleteConnection() ) );
lst.append( actionDelete );

QAction* actionRefresh = new QAction( tr( "Refresh" ), this );
connect( actionRefresh, SIGNAL( triggered() ), this, SLOT( refreshConnection() ) );
lst.append( actionRefresh );

return lst;
}

Expand All @@ -220,6 +184,12 @@ void QgsPGConnectionItem::deleteConnection()
mParent->refresh();
}

void QgsPGConnectionItem::refreshConnection()
{
// the parent should be updated
refresh();
}

bool QgsPGConnectionItem::handleDrop( const QMimeData * data, Qt::DropAction )
{
if ( !QgsMimeDataUtils::isUriList( data ) )
Expand Down Expand Up @@ -301,6 +271,7 @@ QgsPGLayerItem::QgsPGLayerItem( QgsDataItem* parent, QString name, QString path,
{
mUri = createUri();
mPopulated = true;
Q_ASSERT( mLayerProperty.size() == 1 );
}

QgsPGLayerItem::~QgsPGLayerItem()
Expand Down Expand Up @@ -344,12 +315,10 @@ QString QgsPGLayerItem::createUri()
return QString::null;
}

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

QgsDataSourceURI uri( connItem->connection()->connInfo() );
QgsDataSourceURI uri( QgsPostgresConn::connUri( connItem->name() ).connectionInfo() );
uri.setDataSource( mLayerProperty.schemaName, mLayerProperty.tableName, mLayerProperty.geometryColName, mLayerProperty.sql, pkColName );
uri.setSrid( mLayerProperty.srid );
uri.setWkbType( QgsPostgresConn::wkbTypeFromPostgis( mLayerProperty.type ) );
uri.setSrid( QString::number( mLayerProperty.srids[0] ) );
uri.setWkbType( mLayerProperty.types[0] );
QgsDebugMsg( QString( "layer uri: %1" ).arg( uri.uri() ) );
return uri.uri();
}
Expand All @@ -373,8 +342,8 @@ QgsPGSchemaItem::~QgsPGSchemaItem()

void QgsPGSchemaItem::addLayer( QgsPostgresLayerProperty layerProperty )
{
QGis::WkbType wkbType = QgsPostgresConn::wkbTypeFromPostgis( layerProperty.type );
QString tip = tr( "%1 as %2 in %3" ).arg( layerProperty.geometryColName ).arg( QgsPostgresConn::displayStringForWkbType( wkbType ) ).arg( layerProperty.srid );
QGis::WkbType wkbType = layerProperty.types[0];
QString tip = tr( "%1 as %2 in %3" ).arg( layerProperty.geometryColName ).arg( QgsPostgresConn::displayStringForWkbType( wkbType ) ).arg( layerProperty.srids[0] );

QgsLayerItem::LayerType layerType;
switch ( wkbType )
Expand All @@ -398,15 +367,11 @@ void QgsPGSchemaItem::addLayer( QgsPostgresLayerProperty layerProperty )
layerType = QgsLayerItem::Polygon;
break;
default:
if ( layerProperty.type.isEmpty() && layerProperty.geometryColName.isEmpty() )
{
layerType = QgsLayerItem::TableLayer;
tip = tr( "as geometryless table" );
}
else
{
if ( !layerProperty.geometryColName.isEmpty() )
return;
}

layerType = QgsLayerItem::TableLayer;
tip = tr( "as geometryless table" );
}

QgsPGLayerItem *layerItem = new QgsPGLayerItem( this, layerProperty.tableName, mPath + "/" + layerProperty.tableName, layerType, layerProperty );
Expand Down Expand Up @@ -467,3 +432,10 @@ void QgsPGRootItem::newConnection()
refresh();
}
}

QMainWindow *QgsPGRootItem::sMainWindow = 0;

QGISEXTERN void registerGui( QMainWindow *mainWindow )
{
QgsPGRootItem::sMainWindow = mainWindow;
}
10 changes: 8 additions & 2 deletions src/providers/postgres/qgspostgresdataitems.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#ifndef QGSPOSTGRESDATAITEMS_H
#define QGSPOSTGRESDATAITEMS_H

#include <QMainWindow>

#include "qgsdataitem.h"

#include "qgspostgresconn.h"
Expand All @@ -40,6 +42,8 @@ class QgsPGRootItem : public QgsDataCollectionItem

virtual QList<QAction*> actions();

static QMainWindow *sMainWindow;

public slots:
void connectionsChanged();
void newConnection();
Expand All @@ -59,8 +63,6 @@ class QgsPGConnectionItem : public QgsDataCollectionItem
virtual bool acceptDrop() { return true; }
virtual bool handleDrop( const QMimeData * data, Qt::DropAction action );

QgsPostgresConn *connection() const { return mConn; }

void refresh();

signals:
Expand All @@ -69,9 +71,13 @@ class QgsPGConnectionItem : public QgsDataCollectionItem
public slots:
void editConnection();
void deleteConnection();
void refreshConnection();

void setLayerType( QgsPostgresLayerProperty layerProperty );

void threadStarted();
void threadFinished();

private:
void stop();
QgsPostgresConn *mConn;
Expand Down
19 changes: 8 additions & 11 deletions src/providers/postgres/qgspostgresprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2666,12 +2666,9 @@ bool QgsPostgresProvider::getGeometryDetails()

mConnectionRO->retrieveLayerTypes( layerProperty, mUseEstimatedMetadata );

QStringList typeList = layerProperty.type.split( ",", QString::SkipEmptyParts );
QStringList sridList = layerProperty.srid.split( ",", QString::SkipEmptyParts );
Q_ASSERT( typeList.size() == sridList.size() );
mSpatialColType = layerProperty.geometryColType;

if ( typeList.size() == 0 )
if ( layerProperty.size() == 0 )
{
// no data - so take what's requested
if ( mRequestedGeomType == QGis::WKBUnknown || mRequestedSrid.isEmpty() )
Expand All @@ -2685,23 +2682,23 @@ bool QgsPostgresProvider::getGeometryDetails()
else
{
int i;
for ( i = 0; i < typeList.size(); i++ )
for ( i = 0; i < layerProperty.size(); i++ )
{
QGis::WkbType wkbType = QgsPostgresConn::wkbTypeFromPostgis( typeList.at( i ) );
QGis::WkbType wkbType = layerProperty.types[ i ];

if (( wkbType != QGis::WKBUnknown && ( mRequestedGeomType == QGis::WKBUnknown || mRequestedGeomType == wkbType ) ) &&
( mRequestedSrid.isEmpty() || sridList.at( i ) == mRequestedSrid ) )
( mRequestedSrid.isEmpty() || layerProperty.srids[ i ] == mRequestedSrid.toInt() ) )
break;
}

// requested type && srid is available
if ( i < typeList.size() )
if ( i < layerProperty.size() )
{
if ( typeList.size() == 1 )
if ( layerProperty.size() == 1 )
{
// only what we requested is available
detectedType = typeList.at( 0 );
detectedSrid = sridList.at( 0 );
detectedType = layerProperty.types[ 0 ];
detectedSrid = layerProperty.srids[ 0 ];
}
else
{
Expand Down