Expose GeoPackage to the browser tree

This commit is contained in:
Alessandro Pasotti 2017-08-03 23:35:14 +02:00
parent 425aa30fe9
commit 61504e7073
16 changed files with 539 additions and 10 deletions

View File

@ -563,6 +563,7 @@
<file>themes/default/mActionMapSettings.svg</file>
<file>themes/default/mActionLockExtent.svg</file>
<file>icons/qgis_icon.svg</file>
<file>themes/default/mGeoPackage.png</file>
</qresource>
<qresource prefix="/images/tips">
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -361,6 +361,7 @@ class QgsLayerItem : QgsDataItem
Plugin
};
QgsLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri, LayerType layerType, const QString &providerKey );
@ -410,6 +411,13 @@ Returns provider key
:rtype: str
%End
static QString layerTypeAsString( const LayerType &layerType );
%Docstring
Returns the string representatio of the given ``layerType``
.. versionadded:: 3
:rtype: str
%End
protected:

View File

@ -4488,6 +4488,7 @@ void QgisApp::askUserForOGRSublayers( QgsVectorLayer *layer )
}
}
// Check if the current layer uri contains the
// We initialize a selection dialog and display it.
QgsSublayersDialog chooseSublayersDialog( QgsSublayersDialog::Ogr, QStringLiteral( "ogr" ), this );
@ -9807,7 +9808,7 @@ QgsVectorLayer *QgisApp::addVectorLayer( const QString &vectorLayerPath, const Q
// If the newly created layer has more than 1 layer of data available, we show the
// sublayers selection dialog so the user can select the sublayers to actually load.
if ( sublayers.count() > 1 )
if ( sublayers.count() > 1 && ! vectorLayerPath.contains( QStringLiteral( "layerid=" ) ) )
{
askUserForOGRSublayers( layer );

View File

@ -581,6 +581,12 @@ QgsMapLayer::LayerType QgsLayerItem::mapLayerType() const
return QgsMapLayer::VectorLayer;
}
QString QgsLayerItem::layerTypeAsString( const QgsLayerItem::LayerType &layerType )
{
static int enumIdx = staticMetaObject.indexOfEnumerator( "LayerType" );
return staticMetaObject.enumerator( enumIdx ).valueToKey( layerType );
}
bool QgsLayerItem::equal( const QgsDataItem *other )
{
//QgsDebugMsg ( mPath + " x " + other->mPath );

View File

@ -328,6 +328,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS( QgsDataItem::Capabilities )
class CORE_EXPORT QgsLayerItem : public QgsDataItem
{
Q_OBJECT
Q_ENUMS( LayerType )
public:
enum LayerType
{
@ -343,6 +344,8 @@ class CORE_EXPORT QgsLayerItem : public QgsDataItem
Plugin //!< Added in 2.10
};
Q_ENUMS( LayerType )
QgsLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri, LayerType layerType, const QString &providerKey );
// --- reimplemented from QgsDataItem ---
@ -379,6 +382,11 @@ class CORE_EXPORT QgsLayerItem : public QgsDataItem
*/
virtual QString comments() const { return QString(); }
/** Returns the string representatio of the given \a layerType
* \since QGIS 3
*/
static QString layerTypeAsString( const LayerType &layerType );
protected:
//! The provider key

View File

@ -6,6 +6,8 @@ SET (OGR_SRCS
qgsogrconnpool.cpp
qgsogrexpressioncompiler.cpp
qgsogrsourceselect.cpp
qgsgeopackagedataitems.cpp
qgsgeopackageconnection.cpp
)
SET(OGR_MOC_HDRS
@ -13,6 +15,8 @@ SET(OGR_MOC_HDRS
qgsogrdataitems.h
qgsogrconnpool.h
qgsogrsourceselect.h
qgsgeopackagedataitems.h
qgsgeopackageconnection.h
)
########################################################

View File

@ -0,0 +1,89 @@
/***************************************************************************
qgsgeopackageconnection.cpp - selector for geopackage
-------------------
begin : August 2017
copyright : (C) 2017 by Alessandro Pasotti
email : apasotti at boundlessgeo dot com
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include "qgis.h"
#include "qgsdatasourceuri.h"
#include "qgssettings.h"
#include "qgsgeopackageconnection.h"
#include "qgslogger.h"
#include <QInputDialog>
#include <QMessageBox>
const QString QgsGeoPackageConnection::SETTINGS_PREFIX = QStringLiteral( "providers/geopackage" );
QgsGeoPackageConnection::QgsGeoPackageConnection( const QString &connName )
: mConnName( connName )
{
QgsSettings settings;
QString key = QStringLiteral( "%1/%2/path" ).arg( connectionsPath( ), mConnName );
mPath = settings.value( key ).toString();
}
QgsGeoPackageConnection::~QgsGeoPackageConnection()
{
}
QgsDataSourceUri QgsGeoPackageConnection::uri()
{
QgsDataSourceUri uri;
uri.setEncodedUri( mPath );
return uri;
}
void QgsGeoPackageConnection::setPath( QString &path )
{
mPath = path;
}
void QgsGeoPackageConnection::save( )
{
QgsSettings settings;
settings.setValue( QStringLiteral( "%1/%2/path" ).arg( connectionsPath( ), mConnName ), mPath );
}
QString QgsGeoPackageConnection::connectionsPath()
{
return QStringLiteral( "%1/connections" ).arg( SETTINGS_PREFIX );
}
QStringList QgsGeoPackageConnection::connectionList()
{
QgsSettings settings;
settings.beginGroup( connectionsPath( ) );
return settings.childGroups();
}
QString QgsGeoPackageConnection::selectedConnection()
{
QgsSettings settings;
return settings.value( QStringLiteral( "%1/selected" ).arg( SETTINGS_PREFIX ) ).toString();
}
void QgsGeoPackageConnection::setSelectedConnection( const QString &name )
{
QgsSettings settings;
settings.setValue( QStringLiteral( "%1/selected" ).arg( SETTINGS_PREFIX ), name );
}
void QgsGeoPackageConnection::deleteConnection( const QString &name )
{
QgsSettings settings;
settings.remove( QStringLiteral( "%1/%2" ).arg( connectionsPath(), name ) );
}

View File

@ -0,0 +1,67 @@
/***************************************************************************
qgsgeopackageconnection.h - GeoPackage connection
-------------------
begin : August 2017
copyright : (C) 2017 by Alessandro Pasotti
email : apasotti at boundlessgeo dot com
***************************************************************************/
/***************************************************************************
* *
* 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 QGSGEOPACKAGECONNECTION_H
#define QGSGEOPACKAGECONNECTION_H
#include "qgsdatasourceuri.h"
#include <QStringList>
/*!
* \brief Connections management
*/
class QgsGeoPackageConnection : public QObject
{
Q_OBJECT
public:
//! Constructor
explicit QgsGeoPackageConnection( const QString &connName );
~QgsGeoPackageConnection();
static QStringList connectionList();
static void deleteConnection( const QString &name );
static QString selectedConnection();
static void setSelectedConnection( const QString &name );
public:
//! Return the uri
//! \see QgsDataSourceUri
QgsDataSourceUri uri();
//! Return the path
QString path( ) { return mPath; }
//! Returns the connection name
QString name() { return mConnName; }
//! Set the \a path fo the connection
void setPath( QString &path );
//! Store the connection data in the settings
void save();
const static QString SETTINGS_PREFIX;
private:
static QString connectionsPath( );
QString mConnName;
QString mPath;
};
#endif // QGSGEOPACKAGECONNECTION_H

View File

@ -0,0 +1,234 @@
/***************************************************************************
qgsgeopackagedataitems.h
---------------------
begin : August 2017
copyright : (C) 2017 by Alessandro Pasotti
email : apasotti at boundlessgeo dot com
***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include "qgsgeopackagedataitems.h"
#include "qgsgeopackageconnection.h"
#include "qgslogger.h"
#include "qgssettings.h"
#include "qgsvectorlayer.h"
#include <QAction>
#include <QMessageBox>
#include <QFileDialog>
#include <QInputDialog>
QgsDataItem *QgsGeoPackageDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
{
QgsDebugMsg( "path = " + path );
if ( path.isEmpty() )
{
return new QgsGeoPackageRootItem( parentItem, QStringLiteral( "GeoPackage" ), QStringLiteral( "gpkg:" ) );
}
return nullptr;
}
QgsGeoPackageRootItem::QgsGeoPackageRootItem( QgsDataItem *parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path )
{
mCapabilities |= Fast;
mIconName = QStringLiteral( "mGeoPackage.png" );
populate();
}
QgsGeoPackageRootItem::~QgsGeoPackageRootItem()
{
}
QVector<QgsDataItem *> QgsGeoPackageRootItem::createChildren()
{
QVector<QgsDataItem *> connections;
Q_FOREACH ( const QString &connName, QgsGeoPackageConnection::connectionList() )
{
QgsGeoPackageConnection connection( connName );
QgsDataItem *conn = new QgsGeoPackageConnectionItem( this, connection.name(), connection.uri().encodedUri() );
connections.append( conn );
}
return connections;
}
QList<QAction *> QgsGeoPackageRootItem::actions()
{
QList<QAction *> lst;
QAction *actionNew = new QAction( tr( "New Connection..." ), this );
connect( actionNew, &QAction::triggered, this, &QgsGeoPackageRootItem::newConnection );
lst.append( actionNew );
QAction *actionCreateDatabase = new QAction( tr( "Create Database..." ), this );
connect( actionCreateDatabase, &QAction::triggered, this, &QgsGeoPackageRootItem::createDatabase );
lst.append( actionCreateDatabase );
return lst;
}
QWidget *QgsGeoPackageRootItem::paramWidget()
{
return nullptr;
}
void QgsGeoPackageRootItem::connectionsChanged()
{
refresh();
}
void QgsGeoPackageRootItem::newConnection()
{
// TODO use QgsFileWidget
QString path = QFileDialog::getOpenFileName( nullptr, tr( "Open GeoPackage" ), "", tr( "GeoPackage Database (*.gpkg)" ) );
QFileInfo fileInfo( path );
QString folder = fileInfo.path();
QString connName = fileInfo.fileName();
if ( ! path.isEmpty() )
{
bool ok = true;
while ( ok && ! QgsGeoPackageConnection( connName ).path( ).isEmpty( ) )
{
connName = QInputDialog::getText( nullptr, tr( "Cannot add connection '%1'" ).arg( connName ),
tr( "A connection with the same name already exists,\nplease provide a new name:" ), QLineEdit::Normal,
QLatin1String( "" ), &ok );
}
if ( ok && ! connName.isEmpty() )
{
QgsGeoPackageConnection connection( connName );
connection.setPath( path );
connection.save();
refreshConnections();
}
}
}
void QgsGeoPackageRootItem::createDatabase()
{
// TODO
}
QgsGeoPackageConnectionItem::QgsGeoPackageConnectionItem( QgsDataItem *parent, QString name, QString path )
: QgsDataCollectionItem( parent, name, path )
, mPath( path )
{
mCapabilities |= Collapse;
}
QVector<QgsDataItem *> QgsGeoPackageConnectionItem::createChildren()
{
QVector<QgsDataItem *> children;
QgsVectorLayer layer( mPath, QStringLiteral( "ogr_tmp" ), QStringLiteral( "ogr" ) );
if ( ! layer.isValid( ) )
{
children.append( new QgsErrorItem( this, tr( "Layer is not a valid GeoPackage layer" ), mPath + "/error" ) );
}
else
{
Q_FOREACH ( const QString &descriptor, layer.dataProvider()->subLayers( ) )
{
QStringList pieces = descriptor.split( ':' );
QString layerId = pieces[0];
QString name = pieces[1];
QString featuresCount = pieces[2];
QString geometryType = pieces[3];
QgsGeoPackageLayerItem::LayerType layerType;
layerType = layerTypeFromDb( geometryType );
if ( layerType != QgsGeoPackageLayerItem::LayerType::NoType )
{
// URI: '/path/gdal_sample_v1.2_no_extensions.gpkg|layerid=7|geometrytype=Point'
QString uri = QStringLiteral( "%1|layerid=%2|geometrytype=%3" ).arg( mPath, layerId, QgsGeoPackageLayerItem::layerTypeAsString( layerTypeFromDb( geometryType ) ) );
QgsGeoPackageLayerItem *item = new QgsGeoPackageLayerItem( this, name, mPath, uri, layerType );
QgsDebugMsg( QStringLiteral( "Adding GPKG item %1 %2 %3" ).arg( name, uri, geometryType ) );
children.append( item );
}
else
{
children.append( new QgsErrorItem( this, tr( "Layer is not a supported GeoPackage layer geometry type: %1" ).arg( geometryType ), mPath + "/error" ) );
}
}
}
return children;
}
bool QgsGeoPackageConnectionItem::equal( const QgsDataItem *other )
{
if ( type() != other->type() )
{
return false;
}
const QgsGeoPackageConnectionItem *o = dynamic_cast<const QgsGeoPackageConnectionItem *>( other );
return o && mPath == o->mPath && mName == o->mName;
}
#ifdef HAVE_GUI
QList<QAction *> QgsGeoPackageConnectionItem::actions()
{
QList<QAction *> lst;
QAction *actionRemoveConnection = new QAction( tr( "Remove connection" ), this );
// TODO: implement layer deletion
// connect( actionDeleteLayer, &QAction::triggered, this, &QgsGeoPackageLayerItem::deleteLayer );
lst.append( actionRemoveConnection );
return lst;
}
#endif
QgsLayerItem::LayerType QgsGeoPackageConnectionItem::layerTypeFromDb( const QString &geometryType )
{
if ( QString::compare( geometryType, QStringLiteral( "Point" ), Qt::CaseInsensitive ) == 0 || QString::compare( geometryType, QStringLiteral( "MultiPoint" ), Qt::CaseInsensitive ) == 0 )
{
return QgsLayerItem::LayerType::Point;
}
else if ( QString::compare( geometryType, QStringLiteral( "Polygon" ), Qt::CaseInsensitive ) == 0 || QString::compare( geometryType, QStringLiteral( "MultiPolygon" ), Qt::CaseInsensitive ) == 0 )
{
return QgsLayerItem::LayerType::Polygon;
}
else if ( QString::compare( geometryType, QStringLiteral( "LineString" ), Qt::CaseInsensitive ) == 0 || QString::compare( geometryType, QStringLiteral( "MultiLineString" ), Qt::CaseInsensitive ) == 0 )
{
return QgsLayerItem::LayerType::Line;
}
// To be moved in a parent class that would also work for gdal and rasters
else if ( QString::compare( geometryType, QStringLiteral( "Raster" ), Qt::CaseInsensitive ) == 0 )
{
return QgsLayerItem::LayerType::Raster;
}
return QgsLayerItem::LayerType::NoType;
}
#ifdef HAVE_GUI
QList<QAction *> QgsGeoPackageLayerItem::actions()
{
QList<QAction *> lst;
QAction *actionDeleteLayer = new QAction( tr( "Delete Layer" ), this );
// TODO connect( actionDeleteLayer, &QAction::triggered, this, &QgsGeoPackageLayerItem::deleteLayer );
lst.append( actionDeleteLayer );
return lst;
}
#endif
QgsGeoPackageLayerItem::QgsGeoPackageLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, QgsLayerItem::LayerType layerType )
: QgsLayerItem( parent, name, path, uri, layerType, QStringLiteral( "ogr" ) )
{
setState( Populated ); // no children are expected
}

View File

@ -0,0 +1,106 @@
/***************************************************************************
qgsgeopackagedataitems.h
---------------------
begin : October 2011
copyright : (C) 2011 by Martin Dobias
email : wonder dot sk at gmail dot com
***************************************************************************
* *
* 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 QGSGEOPACKAGEDATAITEMS_H
#define QGSGEOPACKAGEDATAITEMS_H
#include "qgsdataitem.h"
#include "qgsdataitemprovider.h"
#include "qgsdataprovider.h"
class QgsGeoPackageLayerItem : public QgsLayerItem
{
Q_OBJECT
public:
QgsGeoPackageLayerItem( QgsDataItem *parent, QString name, QString path, QString uri, LayerType layerType );
#ifdef HAVE_GUI
QList<QAction *> actions() override;
#endif
public slots:
#ifdef HAVE_GUI
void deleteLayer();
#endif
};
class QgsGeoPackageConnectionItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsGeoPackageConnectionItem( QgsDataItem *parent, QString name, QString path );
QVector<QgsDataItem *> createChildren() override;
virtual bool equal( const QgsDataItem *other ) override;
#ifdef HAVE_GUI
virtual QList<QAction *> actions() override;
#endif
virtual bool acceptDrop() override { return true; }
//virtual bool handleDrop( const QMimeData *data, Qt::DropAction action ) override;
//! Return the layer type from \a geometryType
static QgsLayerItem::LayerType layerTypeFromDb( const QString &geometryType );
public slots:
#ifdef HAVE_GUI
void editConnection();
void deleteConnection();
#endif
protected:
QString mPath;
};
class QgsGeoPackageRootItem : public QgsDataCollectionItem
{
Q_OBJECT
public:
QgsGeoPackageRootItem( QgsDataItem *parent, QString name, QString path );
~QgsGeoPackageRootItem();
QVector<QgsDataItem *> createChildren() override;
#ifdef HAVE_GUI
virtual QList<QAction *> actions() override;
virtual QWidget *paramWidget() override;
#endif
public slots:
#ifdef HAVE_GUI
void newConnection();
void connectionsChanged();
#endif
void createDatabase();
};
//! Provider for geopackage root data item
class QgsGeoPackageDataItemProvider : public QgsDataItemProvider
{
public:
virtual QString name() override { return QStringLiteral( "GPKG" ); }
virtual int capabilities() override { return QgsDataProvider::Database; }
virtual QgsDataItem *createDataItem( const QString &path, QgsDataItem *parentItem ) override;
};
#endif // QGSGEOPACKAGEDATAITEMS_H

View File

@ -21,6 +21,7 @@
#include <QFileInfo>
#include <QTextStream>
#include <QAction>
#include <ogr_srs_api.h>
#include <cpl_error.h>

View File

@ -18,6 +18,7 @@
#include "qgsdataitem.h"
#include "qgsogrprovider.h"
#include "qgsdataitemprovider.h"
class QgsOgrLayerItem : public QgsLayerItem
{
@ -40,4 +41,5 @@ class QgsOgrDataCollectionItem : public QgsDataCollectionItem
QVector<QgsDataItem *> createChildren() override;
};
#endif // QGSOGRDATAITEMS_H

View File

@ -30,6 +30,9 @@ email : sherman at mrcc.com
#include "qgsgeometry.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsvectorlayerexporter.h"
#include "qgsdataitemprovider.h"
#include "qgsogrdataitems.h"
#include "qgsgeopackagedataitems.h"
#include "qgswkbtypes.h"
#include "qgis.h"
@ -2924,6 +2927,13 @@ QGISEXTERN bool createEmptyDataSource( const QString &uri,
return true;
}
QGISEXTERN QList<QgsDataItemProvider *> dataItemProviders()
{
return QList<QgsDataItemProvider *>()
<< new QgsGeoPackageDataItemProvider;
}
QgsCoordinateReferenceSystem QgsOgrProvider::crs() const
{
QgsDebugMsg( "Entering." );

View File

@ -27,14 +27,6 @@
#include "qgsnetworkaccessmanager.h"
#include "qgssettings.h"
#include <QInputDialog>
#include <QMessageBox>
#include <QPicture>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
QgsWMSConnection::QgsWMSConnection( const QString &connName )
: mConnName( connName )
{

View File

@ -449,7 +449,7 @@ QGISEXTERN QgsWMSSourceSelect *selectWidget( QWidget *parent, Qt::WindowFlags fl
QgsDataItem *QgsWmsDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
{
QgsDebugMsg( "thePath = " + path );
QgsDebugMsg( "path = " + path );
if ( path.isEmpty() )
{
return new QgsWMSRootItem( parentItem, QStringLiteral( "WMS" ), QStringLiteral( "wms:" ) );