Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #3031 from rouault/gpkg_improvements
GeoPackage support related improvements
  • Loading branch information
nyalldawson committed May 2, 2016
2 parents 563d75c + 7703ad8 commit afdb6c7
Show file tree
Hide file tree
Showing 27 changed files with 2,262 additions and 69 deletions.
9 changes: 9 additions & 0 deletions cmake/FindGDAL.cmake
Expand Up @@ -64,6 +64,11 @@ ELSE(WIN32)
IF (GDAL_VERSION_MAJOR LESS 1 OR (GDAL_VERSION EQUAL 1 AND GDAL_VERSION_MINOR LESS 4))
MESSAGE (FATAL_ERROR "GDAL version is too old (${GDAL_VERSION}). Use 1.4.0 or higher.")
ENDIF (GDAL_VERSION_MAJOR LESS 1 OR (GDAL_VERSION EQUAL 1 AND GDAL_VERSION_MINOR LESS 4))

IF (GDAL_VERSION_MAJOR LESS 1 OR (GDAL_VERSION_MAJOR EQUAL 1 AND GDAL_VERSION_MINOR LESS 11))
MESSAGE (WARNING "GDAL version is too old (${GDAL_VERSION}) to support GeoPackage. 1.11.0 or higher is recommended.")
ENDIF (GDAL_VERSION_MAJOR LESS 1 OR (GDAL_VERSION_MAJOR EQUAL 1 AND GDAL_VERSION_MINOR LESS 11))

ENDIF (GDAL_LIBRARY)
SET (CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK_save} CACHE STRING "" FORCE)
ENDIF ()
Expand Down Expand Up @@ -105,6 +110,10 @@ ELSE(WIN32)
MESSAGE (FATAL_ERROR "GDAL version is too old (${GDAL_VERSION}). Use 1.4.0 or higher.")
ENDIF (GDAL_VERSION_MAJOR LESS 1 OR (GDAL_VERSION_MAJOR EQUAL 1 AND GDAL_VERSION_MINOR LESS 4))

IF (GDAL_VERSION_MAJOR LESS 1 OR (GDAL_VERSION_MAJOR EQUAL 1 AND GDAL_VERSION_MINOR LESS 11))
MESSAGE (WARNING "GDAL version is too old (${GDAL_VERSION}) to support GeoPackage. 1.11.0 or higher is recommended.")
ENDIF (GDAL_VERSION_MAJOR LESS 1 OR (GDAL_VERSION_MAJOR EQUAL 1 AND GDAL_VERSION_MINOR LESS 11))

# set INCLUDE_DIR to prefix+include
EXEC_PROGRAM(${GDAL_CONFIG}
ARGS --prefix
Expand Down
1 change: 1 addition & 0 deletions images/images.qrc
Expand Up @@ -259,6 +259,7 @@
<file>themes/default/mActionNewComposer.svg</file>
<file>themes/default/mActionNewFolder.png</file>
<file>themes/default/mActionNewSpatiaLiteLayer.svg</file>
<file>themes/default/mActionNewGeoPackageLayer.svg</file>
<file>themes/default/mActionNewVectorLayer.svg</file>
<file>themes/default/mActionNodeTool.png</file>
<file>themes/default/mActionOffsetCurve.png</file>
Expand Down
394 changes: 394 additions & 0 deletions images/themes/default/mActionNewGeoPackageLayer.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions python/gui/gui.sip
Expand Up @@ -121,6 +121,7 @@
%Include qgsnewmemorylayerdialog.sip
%Include qgsnewnamedialog.sip
%Include qgsnewvectorlayerdialog.sip
%Include qgsnewgeopackagelayerdialog.sip
%Include qgsnumericsortlistviewitem.sip
%Include qgsoptionsdialogbase.sip
%Include qgsorderbydialog.sip
Expand Down
14 changes: 14 additions & 0 deletions python/gui/qgsnewgeopackagelayerdialog.sip
@@ -0,0 +1,14 @@
/** Dialog to set up parameters to create a new GeoPackage layer, and on accept() to create it and add it to the layers */
class QgsNewGeoPackageLayerDialog : QDialog
{
%TypeHeaderCode
#include <qgsnewgeopackagelayerdialog.h>
%End

public:
/** Constructor */
QgsNewGeoPackageLayerDialog( QWidget *parent /TransferThis/ = 0, const Qt::WindowFlags& fl = QgisGui::ModalDialogFlags );

~QgsNewGeoPackageLayerDialog();

};
43 changes: 36 additions & 7 deletions src/app/qgisapp.cpp
Expand Up @@ -254,8 +254,13 @@
// GDAL/OGR includes
//
#include <ogr_api.h>
#include <gdal_version.h>
#include <proj_api.h>

#if defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0)
#define SUPPORT_GEOPACKAGE
#endif

//
// Other includes
//
Expand Down Expand Up @@ -334,6 +339,7 @@ extern "C"
#include <spatialite.h>
}
#include "qgsnewspatialitelayerdialog.h"
#include "qgsnewgeopackagelayerdialog.h"

#include "qgspythonutils.h"

Expand Down Expand Up @@ -1431,6 +1437,7 @@ void QgisApp::createActions()

connect( mActionNewVectorLayer, SIGNAL( triggered() ), this, SLOT( newVectorLayer() ) );
connect( mActionNewSpatiaLiteLayer, SIGNAL( triggered() ), this, SLOT( newSpatialiteLayer() ) );
connect( mActionNewGeoPackageLayer, SIGNAL( triggered() ), this, SLOT( newGeoPackageLayer() ) );
connect( mActionNewMemoryLayer, SIGNAL( triggered() ), this, SLOT( newMemoryLayer() ) );
connect( mActionShowRasterCalculator, SIGNAL( triggered() ), this, SLOT( showRasterCalculator() ) );
connect( mActionShowAlignRasterTool, SIGNAL( triggered() ), this, SLOT( showAlignRasterTool() ) );
Expand Down Expand Up @@ -1725,6 +1732,11 @@ void QgisApp::createMenus()
* For Mac, About and Exit are also automatically moved by Qt to the Application menu.
*/

// Layer menu
#ifndef SUPPORT_GEOPACKAGE
mNewLayerMenu->removeAction( mActionNewGeoPackageLayer );
#endif

// Panel and Toolbar Submenus
mPanelMenu = new QMenu( tr( "Panels" ), this );
mPanelMenu->setObjectName( "mPanelMenu" );
Expand Down Expand Up @@ -1980,6 +1992,9 @@ void QgisApp::createToolBars()
bt->setPopupMode( QToolButton::MenuButtonPopup );
bt->addAction( mActionNewVectorLayer );
bt->addAction( mActionNewSpatiaLiteLayer );
#ifdef SUPPORT_GEOPACKAGE
bt->addAction( mActionNewGeoPackageLayer );
#endif
bt->addAction( mActionNewMemoryLayer );

QAction* defNewLayerAction = mActionNewVectorLayer;
Expand All @@ -1994,6 +2009,11 @@ void QgisApp::createToolBars()
case 2:
defNewLayerAction = mActionNewMemoryLayer;
break;
#ifdef SUPPORT_GEOPACKAGE
case 3:
defNewLayerAction = mActionNewGeoPackageLayer;
break;
#endif
}
bt->setDefaultAction( defNewLayerAction );
QAction* newLayerAction = mLayerToolBar->addWidget( bt );
Expand Down Expand Up @@ -3668,10 +3688,10 @@ void QgisApp::loadOGRSublayers( const QString& layertype, const QString& uri, co
}

QString layerName = elements.value( 0 );
QString layerType = elements.value( 1 );
if ( layerType == "any" )
QString layerGeometryType = elements.value( 1 );
if ( layerGeometryType == "any" )
{
layerType = "";
layerGeometryType = "";
elements.removeAt( 1 );
}

Expand All @@ -3684,16 +3704,17 @@ void QgisApp::loadOGRSublayers( const QString& layertype, const QString& uri, co
composedURI = uri + "|layerindex=" + layerName;
}

if ( !layerType.isEmpty() )
if ( !layerGeometryType.isEmpty() )
{
composedURI += "|geometrytype=" + layerType;
composedURI += "|geometrytype=" + layerGeometryType;
}

// addVectorLayer( composedURI, list.at( i ), "ogr" );

QgsDebugMsg( "Creating new vector layer using " + composedURI );
QString name = list.at( i );
name.replace( ':', ' ' );
QString name = layerName;
if ( !layerGeometryType.isEmpty() )
name += " " + layerGeometryType;
QgsVectorLayer *layer = new QgsVectorLayer( composedURI, fileName + " " + name, "ogr", false );
if ( layer && layer->isValid() )
{
Expand Down Expand Up @@ -4366,6 +4387,12 @@ void QgisApp::newSpatialiteLayer()
spatialiteDialog.exec();
}

void QgisApp::newGeoPackageLayer()
{
QgsNewGeoPackageLayerDialog dialog( this );
dialog.exec();
}

void QgisApp::showRasterCalculator()
{
QgsRasterCalcDialog d( this );
Expand Down Expand Up @@ -11227,6 +11254,8 @@ void QgisApp::toolButtonActionTriggered( QAction *action )
settings.setValue( "/UI/defaultNewLayer", 1 );
else if ( action == mActionNewMemoryLayer )
settings.setValue( "/UI/defaultNewLayer", 2 );
else if ( action == mActionNewGeoPackageLayer )
settings.setValue( "/UI/defaultNewLayer", 3 );
bt->setDefaultAction( action );
}

Expand Down
2 changes: 2 additions & 0 deletions src/app/qgisapp.h
Expand Up @@ -948,6 +948,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void newMemoryLayer();
//! Create a new empty spatialite layer
void newSpatialiteLayer();
//! Create a new empty GeoPackage layer
void newGeoPackageLayer();
//! Print the current map view frame
void newPrintComposer();
void showComposerManager();
Expand Down
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -188,6 +188,7 @@ SET(QGIS_CORE_SRCS
qgssnappingutils.cpp
qgsspatialindex.cpp
qgssqlexpressioncompiler.cpp
qgssqliteexpressioncompiler.cpp
qgsstatisticalsummary.cpp
qgsstringutils.cpp
qgstextlabelfeature.cpp
Expand Down
9 changes: 7 additions & 2 deletions src/core/qgsogrutils.cpp
Expand Up @@ -72,7 +72,7 @@ QgsFields QgsOgrUtils::readOgrFields( OGRFeatureH ogrFet, QTextCodec* encoding )
continue;
}

QString name = encoding->toUnicode( OGR_Fld_GetNameRef( fldDef ) );
QString name = encoding ? encoding->toUnicode( OGR_Fld_GetNameRef( fldDef ) ) : QString::fromUtf8( OGR_Fld_GetNameRef( fldDef ) );
QVariant::Type varType;
switch ( OGR_Fld_GetType( fldDef ) )
{
Expand Down Expand Up @@ -137,8 +137,13 @@ QVariant QgsOgrUtils::getOgrFeatureAttribute( OGRFeatureH ogrFet, const QgsField
switch ( fields.at( attIndex ).type() )
{
case QVariant::String:
value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
{
if ( encoding )
value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
else
value = QVariant( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
break;
}
case QVariant::Int:
value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) );
break;
Expand Down
@@ -1,5 +1,5 @@
/***************************************************************************
qgsspatialiteexpressioncompiler.cpp
qgssqliteexpressioncompiler.cpp
-----------------------------------
begin : November 2015
copyright : (C) 2015 Nyall Dawson
Expand All @@ -13,16 +13,17 @@
* *
***************************************************************************/

#include "qgsspatialiteexpressioncompiler.h"
///@cond PRIVATE

#include "qgssqliteexpressioncompiler.h"
#include "qgssqlexpressioncompiler.h"
#include "qgsspatialiteprovider.h"

QgsSpatiaLiteExpressionCompiler::QgsSpatiaLiteExpressionCompiler( QgsSpatiaLiteFeatureSource* source )
: QgsSqlExpressionCompiler( source->mFields, QgsSqlExpressionCompiler::LikeIsCaseInsensitive )
QgsSQLiteExpressionCompiler::QgsSQLiteExpressionCompiler( const QgsFields& fields )
: QgsSqlExpressionCompiler( fields, QgsSqlExpressionCompiler::LikeIsCaseInsensitive )
{
}

QgsSqlExpressionCompiler::Result QgsSpatiaLiteExpressionCompiler::compileNode( const QgsExpression::Node* node, QString& result )
QgsSqlExpressionCompiler::Result QgsSQLiteExpressionCompiler::compileNode( const QgsExpression::Node* node, QString& result )
{
switch ( node->nodeType() )
{
Expand All @@ -47,12 +48,14 @@ QgsSqlExpressionCompiler::Result QgsSpatiaLiteExpressionCompiler::compileNode( c
return QgsSqlExpressionCompiler::compileNode( node, result );
}

QString QgsSpatiaLiteExpressionCompiler::quotedIdentifier( const QString& identifier )
QString QgsSQLiteExpressionCompiler::quotedIdentifier( const QString& identifier )
{
return QgsSpatiaLiteProvider::quotedIdentifier( identifier );
QString id( identifier );
id.replace( '\"', "\"\"" );
return id.prepend( '\"' ).append( '\"' );
}

QString QgsSpatiaLiteExpressionCompiler::quotedValue( const QVariant& value, bool& ok )
QString QgsSQLiteExpressionCompiler::quotedValue( const QVariant& value, bool& ok )
{
ok = true;

Expand All @@ -73,10 +76,12 @@ QString QgsSpatiaLiteExpressionCompiler::quotedValue( const QVariant& value, boo
default:
case QVariant::String:
QString v = value.toString();
v.replace( '\'', "''" );
if ( v.contains( '\\' ) )
return v.replace( '\\', "\\\\" ).prepend( "E'" ).append( '\'' );
else
return v.prepend( '\'' ).append( '\'' );
// https://www.sqlite.org/lang_expr.html :
// """A string constant is formed by enclosing the string in single quotes (').
// A single quote within the string can be encoded by putting two single quotes
// in a row - as in Pascal. C-style escapes using the backslash character are not supported because they are not standard SQL. """
return v.replace( '\'', "''" ).prepend( '\'' ).append( '\'' );
}
}

///@endcond
@@ -1,5 +1,5 @@
/***************************************************************************
qgsspatialiteexpressioncompiler.h
qgssqliteexpressioncompiler.h
---------------------------------
begin : November 2015
copyright : (C) 2015 Nyall Dawson
Expand All @@ -13,18 +13,32 @@
* *
***************************************************************************/

#ifndef QGSSPATIALITEEXPRESSIONCOMPILER_H
#define QGSSPATIALITEEXPRESSIONCOMPILER_H
#ifndef QGSSQLITEEXPRESSIONCOMPILER_H
#define QGSSQLITEEXPRESSIONCOMPILER_H

///@cond PRIVATE

#include "qgssqlexpressioncompiler.h"
#include "qgsexpression.h"
#include "qgsspatialitefeatureiterator.h"

class QgsSpatiaLiteExpressionCompiler : public QgsSqlExpressionCompiler
/** \ingroup core
* \class QgsSQLiteExpressionCompiler
* \brief Expression compiler for translation to SQlite SQL WHERE clauses.
*
* This class is designed to be used by spatialite and OGR providers.
* \note Added in version 2.16
* \note Not part of stable API, may change in future versions of QGIS
* \note Not available in Python bindings
*/

class CORE_EXPORT QgsSQLiteExpressionCompiler : public QgsSqlExpressionCompiler
{
public:

explicit QgsSpatiaLiteExpressionCompiler( QgsSpatiaLiteFeatureSource* source );
/** Constructor for expression compiler.
* @param fields fields from provider
*/
explicit QgsSQLiteExpressionCompiler( const QgsFields& fields );

protected:

Expand All @@ -34,4 +48,6 @@ class QgsSpatiaLiteExpressionCompiler : public QgsSqlExpressionCompiler

};

#endif // QGSSPATIALITEEXPRESSIONCOMPILER_H
///@endcond

#endif // QGSSQLITEEXPRESSIONCOMPILER_H
42 changes: 42 additions & 0 deletions src/core/qgsvectorfilewriter.cpp
Expand Up @@ -982,6 +982,48 @@ QMap<QString, QgsVectorFileWriter::MetaData> QgsVectorFileWriter::initMetaData()
)
);

// GeoPackage
datasetOptions.clear();
layerOptions.clear();

layerOptions.insert( "IDENTIFIER", new StringOption(
QObject::tr( "Human-readable identifier (e.g. short name) for the layer content" ),
"" // Default value
) );

layerOptions.insert( "DESCRIPTION", new StringOption(
QObject::tr( "Human-readable description for the layer content" ),
"" // Default value
) );

layerOptions.insert( "FID", new StringOption(
QObject::tr( "Name for the feature identifier column" ),
"fid" // Default value
) );

layerOptions.insert( "GEOMETRY_NAME", new StringOption(
QObject::tr( "Name for the geometry column" ),
"geometry" // Default value
) );

#if defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,0,0)
layerOptions.insert( "SPATIAL_INDEX", new BoolOption(
QObject::tr( "If a spatial index must be created." ),
true // Default value
) );
#endif

driverMetadata.insert( "GPKG",
MetaData(
"GeoPackage",
QObject::tr( "GeoPackage" ),
"*.gpkg",
"gpkg",
datasetOptions,
layerOptions
)
);

// Generic Mapping Tools [GMT]
datasetOptions.clear();
layerOptions.clear();
Expand Down

0 comments on commit afdb6c7

Please sign in to comment.