Skip to content
Permalink
Browse files

New data item for browser connection roots

in order to distinguish it from schema and layer collections.
  • Loading branch information
elpaso committed Jul 16, 2020
1 parent fe69426 commit 4473b2cc77a5840ca502e8756415a70dd718e845
Showing with 170 additions and 106 deletions.
  1. +30 −1 python/core/auto_generated/qgsdataitem.sip.in
  2. +71 −68 src/app/browser/qgsinbuiltdataitemproviders.cpp
  3. +1 −1 src/core/providers/ogr/qgsgeopackagedataitems.cpp
  4. +1 −1 src/core/providers/ogr/qgsgeopackagedataitems.h
  5. +1 −1 src/core/qgsbrowsermodel.cpp
  6. +7 −0 src/core/qgsdataitem.cpp
  7. +27 −1 src/core/qgsdataitem.h
  8. +1 −1 src/core/vectortile/qgsvectortiledataitems.cpp
  9. +1 −1 src/core/vectortile/qgsvectortiledataitems.h
  10. +1 −1 src/gui/qgsnewvectortabledialog.cpp
  11. +1 −1 src/providers/arcgisrest/qgsafsdataitems.cpp
  12. +1 −1 src/providers/arcgisrest/qgsafsdataitems.h
  13. +1 −1 src/providers/arcgisrest/qgsamsdataitems.cpp
  14. +1 −1 src/providers/arcgisrest/qgsamsdataitems.h
  15. +1 −1 src/providers/db2/qgsdb2dataitems.cpp
  16. +1 −1 src/providers/db2/qgsdb2dataitems.h
  17. +1 −1 src/providers/geonode/qgsgeonodedataitems.cpp
  18. +1 −1 src/providers/geonode/qgsgeonodedataitems.h
  19. +1 −1 src/providers/mssql/qgsmssqldataitems.cpp
  20. +1 −1 src/providers/mssql/qgsmssqldataitems.h
  21. +1 −1 src/providers/oracle/qgsoracledataitems.cpp
  22. +1 −1 src/providers/oracle/qgsoracledataitems.h
  23. +1 −1 src/providers/ows/qgsowsdataitems.cpp
  24. +1 −1 src/providers/ows/qgsowsdataitems.h
  25. +1 −1 src/providers/postgres/qgspostgresdataitems.cpp
  26. +1 −1 src/providers/postgres/qgspostgresdataitems.h
  27. +1 −2 src/providers/spatialite/qgsspatialitedataitemguiprovider.cpp
  28. +1 −1 src/providers/spatialite/qgsspatialitedataitems.cpp
  29. +1 −1 src/providers/spatialite/qgsspatialitedataitems.h
  30. +1 −1 src/providers/wcs/qgswcsdataitems.cpp
  31. +1 −1 src/providers/wcs/qgswcsdataitems.h
  32. +1 −1 src/providers/wfs/qgswfsdataitems.cpp
  33. +1 −1 src/providers/wfs/qgswfsdataitems.h
  34. +3 −3 src/providers/wms/qgswmsdataitems.cpp
  35. +3 −3 src/providers/wms/qgswmsdataitems.h
@@ -691,8 +691,37 @@ Returns the standard browser data collection icon.
.. seealso:: :py:func:`iconDir`
%End

protected:
};



class QgsConnectionsRootItem : QgsDataCollectionItem
{
%Docstring
A Collection that represents a root group of connections from a single data provider

.. versionadded:: 3.16
%End

%TypeHeaderCode
#include "qgsdataitem.h"
%End
public:

QgsConnectionsRootItem( QgsDataItem *parent /TransferThis/, const QString &name, const QString &path = QString(), const QString &providerKey = QString() );
%Docstring
Constructor for QgsConnectionsRootItem, with the specified ``parent`` item.

The ``name`` argument specifies the text to show in the model for the item. A translated string should
be used wherever appropriate.

The ``path`` argument gives the item path in the browser tree. The ``path`` string can take any form,
but QgsSchemaItem items pointing to different logical locations should always use a different item ``path``.

The optional ``providerKey`` string can be used to specify the key for the QgsDataItemProvider that created this item.
%End

~QgsConnectionsRootItem();
};


@@ -849,94 +849,97 @@ QString QgsDatabaseItemGuiProvider::name()
void QgsDatabaseItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu *menu, const QList<QgsDataItem *> &selectedItems, QgsDataItemGuiContext context )
{
Q_UNUSED( selectedItems )
// Add create new table for connections
if ( QgsDataCollectionItem * collectionItem { qobject_cast<QgsDataCollectionItem *>( item ) } )
// Add create new table for collection items but not not if it is a root item
if ( ! qobject_cast<QgsConnectionsRootItem *>( item ) )
{
QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( collectionItem->providerKey() ) };
if ( md )
if ( QgsDataCollectionItem * collectionItem { qobject_cast<QgsDataCollectionItem *>( item ) } )
{
const bool isSchema { qobject_cast<QgsDatabaseSchemaItem *>( item ) };
const QString connectionName { isSchema ? collectionItem->parent()->name() : collectionItem->name() };
std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn( static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionName ) ) );
if ( conn && conn->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::CreateVectorTable ) )
QgsProviderMetadata *md { QgsProviderRegistry::instance()->providerMetadata( collectionItem->providerKey() ) };
if ( md )
{
QAction *newTableAction = new QAction( QObject::tr( "New Table…" ), menu );
QObject::connect( newTableAction, &QAction::triggered, collectionItem, [ collectionItem, connectionName, md, isSchema, context]
const bool isSchema { qobject_cast<QgsDatabaseSchemaItem *>( item ) };
const QString connectionName { isSchema ? collectionItem->parent()->name() : collectionItem->name() };
std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn( static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionName ) ) );
if ( conn && conn->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::CreateVectorTable ) )
{
std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn2 { static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionName ) ) };
QgsNewVectorTableDialog dlg { conn2.get(), nullptr };
dlg.setCrs( QgsProject::instance()->defaultCrsForNewLayers() );
if ( isSchema )
{
dlg.setSchemaName( collectionItem->name() );
}
if ( dlg.exec() == QgsNewVectorTableDialog::DialogCode::Accepted )
QAction *newTableAction = new QAction( QObject::tr( "New Table…" ), menu );
QObject::connect( newTableAction, &QAction::triggered, collectionItem, [ collectionItem, connectionName, md, isSchema, context]
{
const QgsFields fields { dlg.fields() };
const QString tableName { dlg.tableName() };
const QString schemaName { dlg.schemaName() };
const QString geometryColumn { dlg.geometryColumnName() };
const QgsWkbTypes::Type geometryType { dlg.geometryType() };
const bool createSpatialIndex { dlg.createSpatialIndex() };
const QgsCoordinateReferenceSystem crs { dlg.crs( ) };
// This flag tells to the provider that field types do not need conversion
QMap<QString, QVariant> options { { QStringLiteral( "skipConvertFields" ), true } };

if ( ! geometryColumn.isEmpty() )
std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn2 { static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( connectionName ) ) };
QgsNewVectorTableDialog dlg { conn2.get(), nullptr };
dlg.setCrs( QgsProject::instance()->defaultCrsForNewLayers() );
if ( isSchema )
{
options[ QStringLiteral( "geometryColumn" ) ] = geometryColumn;
dlg.setSchemaName( collectionItem->name() );
}

QString title;
QString message;

try
if ( dlg.exec() == QgsNewVectorTableDialog::DialogCode::Accepted )
{
conn2->createVectorTable( schemaName, tableName, fields, geometryType, crs, true, &options );
if ( createSpatialIndex && conn2->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::CreateSpatialIndex ) )
const QgsFields fields { dlg.fields() };
const QString tableName { dlg.tableName() };
const QString schemaName { dlg.schemaName() };
const QString geometryColumn { dlg.geometryColumnName() };
const QgsWkbTypes::Type geometryType { dlg.geometryType() };
const bool createSpatialIndex { dlg.createSpatialIndex() };
const QgsCoordinateReferenceSystem crs { dlg.crs( ) };
// This flag tells to the provider that field types do not need conversion
QMap<QString, QVariant> options { { QStringLiteral( "skipConvertFields" ), true } };

if ( ! geometryColumn.isEmpty() )
{
conn2->createSpatialIndex( schemaName, tableName );
options[ QStringLiteral( "geometryColumn" ) ] = geometryColumn;
}
// Ok, here is the trick: we cannot refresh the connection item because the refresh is not
// recursive.
// So, we check if the item is a schema or not, if it's not it means we initiated the new table from
// the parent connection item, hence we search for the schema item and refresh it instead of refreshing
// the connection item (the parent) with no effects.
if ( ! isSchema && conn2->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::Schemas ) )

QString title;
QString message;

try
{
const auto constChildren { collectionItem->children() };
for ( const auto &c : constChildren )
conn2->createVectorTable( schemaName, tableName, fields, geometryType, crs, true, &options );
if ( createSpatialIndex && conn2->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::CreateSpatialIndex ) )
{
conn2->createSpatialIndex( schemaName, tableName );
}
// Ok, here is the trick: we cannot refresh the connection item because the refresh is not
// recursive.
// So, we check if the item is a schema or not, if it's not it means we initiated the new table from
// the parent connection item, hence we search for the schema item and refresh it instead of refreshing
// the connection item (the parent) with no effects.
if ( ! isSchema && conn2->capabilities().testFlag( QgsAbstractDatabaseProviderConnection::Capability::Schemas ) )
{
if ( c->name() == schemaName )
const auto constChildren { collectionItem->children() };
for ( const auto &c : constChildren )
{
c->refresh();
if ( c->name() == schemaName )
{
c->refresh();
}
}
}
else
{
collectionItem->refresh( );
}
title = QObject::tr( "New Table Created" );
message = QObject::tr( "Table '%1' was created successfully." ).arg( tableName );
}
else
catch ( QgsProviderConnectionException &ex )
{
collectionItem->refresh( );
title = QObject::tr( "New Table Creation Error" );
message = QObject::tr( "Error creating new table '%1': %2" ).arg( tableName, ex.what() );
}
title = QObject::tr( "New Table Created" );
message = QObject::tr( "Table '%1' was created successfully." ).arg( tableName );
}
catch ( QgsProviderConnectionException &ex )
{
title = QObject::tr( "New Table Creation Error" );
message = QObject::tr( "Error creating new table '%1': %2" ).arg( tableName, ex.what() );
}

if ( context.messageBar() )
{
context.messageBar()->pushSuccess( title, message );
}
else
{
QMessageBox::information( nullptr, title, message );
if ( context.messageBar() )
{
context.messageBar()->pushSuccess( title, message );
}
else
{
QMessageBox::information( nullptr, title, message );
}
}
}
} );
menu->addAction( newTableAction );
} );
menu->addAction( newTableAction );
}
}
}
}
@@ -67,7 +67,7 @@ QgsDataItem *QgsGeoPackageDataItemProvider::createDataItem( const QString &path,
}

QgsGeoPackageRootItem::QgsGeoPackageRootItem( QgsDataItem *parent, const QString &name, const QString &path )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "GPKG" ) )
: QgsConnectionsRootItem( parent, name, path, QStringLiteral( "ogr" ) )
{
mCapabilities |= Fast;
mIconName = QStringLiteral( "mGeoPackage.svg" );
@@ -144,7 +144,7 @@ class CORE_EXPORT QgsGeoPackageConnectionItem final: public QgsGeoPackageCollect
};


class CORE_EXPORT QgsGeoPackageRootItem final: public QgsDataCollectionItem
class CORE_EXPORT QgsGeoPackageRootItem final: public QgsConnectionsRootItem
{
Q_OBJECT

@@ -777,7 +777,7 @@ QgsDataItem *QgsBrowserModel::addProviderRootItem( QgsDataItemProvider *pr )
if ( item )
{
// make sure the top level key is set always
item->setProviderKey( pr->name() );
item->setProviderKey( pr->dataProviderKey() );
// Forward the signal from the root items to the model (and then to the app)
connect( item, &QgsDataItem::connectionsChanged, this, &QgsBrowserModel::onConnectionsChanged );
QgsDebugMsgLevel( "Add new top level item : " + item->name(), 4 );
@@ -1758,6 +1758,13 @@ QIcon QgsDatabaseSchemaItem::iconDataCollection()
return QgsApplication::getThemeIcon( QStringLiteral( "/mIconDbSchema.svg" ) );
}


QgsConnectionsRootItem::QgsConnectionsRootItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey )
: QgsDataCollectionItem( parent, name, path, providerKey )
{
}


///@cond PRIVATE

QgsProjectHomeItem::QgsProjectHomeItem( QgsDataItem *parent, const QString &name, const QString &dirPath, const QString &path )
@@ -699,8 +699,34 @@ class CORE_EXPORT QgsDatabaseSchemaItem : public QgsDataCollectionItem
*/
static QIcon iconDataCollection();

protected:
};



/**
* \ingroup core
* A Collection that represents a root group of connections from a single data provider
* \since QGIS 3.16
*/
class CORE_EXPORT QgsConnectionsRootItem : public QgsDataCollectionItem
{
Q_OBJECT
public:

/**
* Constructor for QgsConnectionsRootItem, with the specified \a parent item.
*
* The \a name argument specifies the text to show in the model for the item. A translated string should
* be used wherever appropriate.
*
* The \a path argument gives the item path in the browser tree. The \a path string can take any form,
* but QgsSchemaItem items pointing to different logical locations should always use a different item \a path.
*
* The optional \a providerKey string can be used to specify the key for the QgsDataItemProvider that created this item.
*/
QgsConnectionsRootItem( QgsDataItem *parent SIP_TRANSFERTHIS, const QString &name, const QString &path = QString(), const QString &providerKey = QString() );

~QgsConnectionsRootItem() override = default;
};


@@ -20,7 +20,7 @@
///@cond PRIVATE

QgsVectorTileRootItem::QgsVectorTileRootItem( QgsDataItem *parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "vectortile" ) )
: QgsConnectionsRootItem( parent, name, path, QStringLiteral( "vectortile" ) )
{
mCapabilities |= Fast;
mIconName = QStringLiteral( "mIconVectorTileLayer.svg" );
@@ -22,7 +22,7 @@
#define SIP_NO_FILE

//! Root item for XYZ tile layers
class CORE_EXPORT QgsVectorTileRootItem : public QgsDataCollectionItem
class CORE_EXPORT QgsVectorTileRootItem : public QgsConnectionsRootItem
{
Q_OBJECT
public:
@@ -365,7 +365,7 @@ void QgsNewVectorTableDialog::validate()
// No geometry and no fields? No party!
if ( ! isSpatial && mFieldModel->fields().count() == 0 )
{
mValidationErrors.push_back( tr( "The table has no geometry column and no fields: cannot create an empty table!" ) );
mValidationErrors.push_back( tr( "The table has no geometry column and no fields!" ) );
}

const bool isValid { mValidationErrors.isEmpty() };
@@ -29,7 +29,7 @@


QgsAfsRootItem::QgsAfsRootItem( QgsDataItem *parent, const QString &name, const QString &path )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "AFS" ) )
: QgsConnectionsRootItem( parent, name, path, QStringLiteral( "AFS" ) )
{
mCapabilities |= Fast;
mIconName = QStringLiteral( "mIconAfs.svg" );
@@ -21,7 +21,7 @@
#include "qgsdataitemprovider.h"


class QgsAfsRootItem : public QgsDataCollectionItem
class QgsAfsRootItem : public QgsConnectionsRootItem
{
Q_OBJECT
public:
@@ -27,7 +27,7 @@
#include <QImageReader>

QgsAmsRootItem::QgsAmsRootItem( QgsDataItem *parent, const QString &name, const QString &path )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "AMS" ) )
: QgsConnectionsRootItem( parent, name, path, QStringLiteral( "AMS" ) )
{
mCapabilities |= Fast;
mIconName = QStringLiteral( "mIconAms.svg" );
@@ -23,7 +23,7 @@
#include "qgsdataitemprovider.h"


class QgsAmsRootItem : public QgsDataCollectionItem
class QgsAmsRootItem : public QgsConnectionsRootItem
{
Q_OBJECT
public:
@@ -334,7 +334,7 @@ bool QgsDb2ConnectionItem::handleDrop( const QMimeData *data, const QString &toS
}

QgsDb2RootItem::QgsDb2RootItem( QgsDataItem *parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "DB2" ) )
: QgsConnectionsRootItem( parent, name, path, QStringLiteral( "DB2" ) )
{
mIconName = QStringLiteral( "mIconDb2.svg" );
populate();
@@ -30,7 +30,7 @@ class QgsDb2LayerItem;
* \class QgsDb2RootItem
* \brief Browser Panel DB2 root object.
*/
class QgsDb2RootItem : public QgsDataCollectionItem
class QgsDb2RootItem : public QgsConnectionsRootItem
{
Q_OBJECT

@@ -186,7 +186,7 @@ void QgsGeoNodeServiceItem::replacePath( QgsDataItem *item, const QString &befor
}

QgsGeoNodeRootItem::QgsGeoNodeRootItem( QgsDataItem *parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "GeoNode" ) )
: QgsConnectionsRootItem( parent, name, path, QStringLiteral( "GeoNode" ) )
{
mCapabilities |= Fast;
{
@@ -56,7 +56,7 @@ class QgsGeoNodeServiceItem : public QgsDataCollectionItem
bool layerCollection() const override;
};

class QgsGeoNodeRootItem : public QgsDataCollectionItem
class QgsGeoNodeRootItem : public QgsConnectionsRootItem
{
Q_OBJECT
public:
@@ -610,7 +610,7 @@ QVector<QgsDataItem *> QgsMssqlLayerItem::createChildren()

// ---------------------------------------------------------------------------
QgsMssqlRootItem::QgsMssqlRootItem( QgsDataItem *parent, const QString &name, const QString &path )
: QgsDataCollectionItem( parent, name, path, QStringLiteral( "MSSQL" ) )
: QgsConnectionsRootItem( parent, name, path, QStringLiteral( "MSSQL" ) )
{
mIconName = QStringLiteral( "mIconMssql.svg" );
populate();
@@ -31,7 +31,7 @@ class QgsMssqlConnectionItem;
class QgsMssqlSchemaItem;
class QgsMssqlLayerItem;

class QgsMssqlRootItem : public QgsDataCollectionItem
class QgsMssqlRootItem : public QgsConnectionsRootItem
{
Q_OBJECT
public:

0 comments on commit 4473b2c

Please sign in to comment.
You can’t perform that action at this time.