supporting the SpatiaLite Data Provider

2009-04-24 Sandro Furieri <a.furieri@lqt.it>


git-svn-id: http://svn.osgeo.org/qgis/trunk@10414 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
esseffe 2009-03-24 20:52:12 +00:00
parent caa6177059
commit 38f81229f0
18 changed files with 3523 additions and 0 deletions

View File

@ -50,6 +50,12 @@ IF (WITH_POSTGRESQL)
SET (POSTGRESQL_PREFIX "" CACHE PATH "Path to POSTGRESQL base directory")
ENDIF (WITH_POSTGRESQL)
# try to configure and build SPATIALITE support
SET (WITH_SPATIALITE TRUE CACHE BOOL "Determines whether SPATIALITE support should be built")
IF (WITH_SPATIALITE)
SET (SPATIALITE_PREFIX "" CACHE PATH "Path to SPATIALITE base directory")
ENDIF (WITH_SPATIALITE)
# try to configure and build python bindings by default
SET (WITH_BINDINGS TRUE CACHE BOOL "Determines whether python bindings should be built")
IF (WITH_BINDINGS)
@ -118,6 +124,9 @@ FIND_PACKAGE(GSL) # Georeferencer
IF (WITH_GRASS)
FIND_PACKAGE(GRASS) # GRASS plugin
ENDIF (WITH_GRASS)
IF (WITH_SPATIALITE)
FIND_PACKAGE(SPATIALITE) # SPATIALITE provider
ENDIF (WITH_SPATIALITE)
IF (WITH_BINDINGS)
# python support:
@ -136,6 +145,10 @@ IF (POSTGRES_FOUND)
SET (HAVE_POSTGRESQL TRUE)
ENDIF (POSTGRES_FOUND)
IF (SPATIALITE_FOUND)
# following variable is used in qgsconfig.h
SET (HAVE_SPATIALITE TRUE)
ENDIF (SPATIALITE_FOUND)
#############################################################
# search for Qt4

View File

@ -0,0 +1,50 @@
# CMake module to search for SpatiaLite library
#
# If it's found it sets SPATIALITE_FOUND to TRUE
# and following variables are set:
# SPATIALITE_INCLUDE_DIR
# SPATIALITE_LIBRARY
# FIND_PATH and FIND_LIBRARY normally search standard locations
# before the specified paths. To search non-standard paths first,
# FIND_* is invoked first with specified paths and NO_DEFAULT_PATH
# and then again with no specified paths to search the default
# locations. When an earlier FIND_* succeeds, subsequent FIND_*s
# searching for the same item do nothing.
FIND_PATH(SPATIALITE_INCLUDE_DIR spatialite.h
"$ENV{LIB_DIR}/include"
"$ENV{LIB_DIR}/include/spatialite"
#mingw
c:/msys/local/include
NO_DEFAULT_PATH
)
FIND_PATH(SPATIALITE_INCLUDE_DIR spatialite.h)
FIND_LIBRARY(SPATIALITE_LIBRARY NAMES spatialite PATHS
"$ENV{LIB_DIR}/lib"
#mingw
c:/msys/local/lib
NO_DEFAULT_PATH
)
FIND_LIBRARY(SPATIALITE_LIBRARY NAMES spatialite)
IF (SPATIALITE_INCLUDE_DIR AND SPATIALITE_LIBRARY)
SET(SPATIALITE_FOUND TRUE)
ENDIF (SPATIALITE_INCLUDE_DIR AND SPATIALITE_LIBRARY)
IF (SPATIALITE_FOUND)
IF (NOT SPATIALITE_FIND_QUIETLY)
MESSAGE(STATUS "Found SpatiaLite: ${SPATIALITE_LIBRARY}")
ENDIF (NOT SPATIALITE_FIND_QUIETLY)
ELSE (SPATIALITE_FOUND)
IF (SPATIALITE_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find SpatiaLite")
ENDIF (SPATIALITE_FIND_REQUIRED)
ENDIF (SPATIALITE_FOUND)

View File

@ -25,6 +25,8 @@
#cmakedefine HAVE_POSTGRESQL
#cmakedefine HAVE_SPATIALITE
#cmakedefine HAVE_PYTHON
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -15,6 +15,8 @@ SET(QGIS_APP_SRCS
qgscustomprojectiondialog.cpp
qgsdbfilterproxymodel.cpp
qgsdbtablemodel.cpp
qgsspatialitefilterproxymodel.cpp
qgsspatialitetablemodel.cpp
qgsdelattrdialog.cpp
qgsgeomtypedialog.cpp
qgsgraduatedsymboldialog.cpp
@ -135,6 +137,7 @@ SET (QGIS_APP_MOC_HDRS
qgsuniquevaluedialog.h
qgsvectorlayerproperties.h
qgsdbtablemodel.h
qgsspatialitetablemodel.h
composer/qgscomposer.h
composer/qgscomposeritemwidget.h
@ -175,6 +178,15 @@ IF (POSTGRES_FOUND)
)
ENDIF (POSTGRES_FOUND)
IF (SPATIALITE_FOUND)
SET (QGIS_APP_SRCS ${QGIS_APP_SRCS}
qgsspatialitesourceselect.cpp
)
SET (QGIS_APP_MOC_HDRS ${QGIS_APP_MOC_HDRS}
qgsspatialitesourceselect.h
)
ENDIF (SPATIALITE_FOUND)
QT4_WRAP_CPP(QGIS_APP_MOC_SRCS ${QGIS_APP_MOC_HDRS})
@ -227,6 +239,10 @@ IF (POSTGRES_FOUND)
INCLUDE_DIRECTORIES(${POSTGRES_INCLUDE_DIR})
ENDIF (POSTGRES_FOUND)
IF (SPATIALITE_FOUND)
INCLUDE_DIRECTORIES(${SPATIALITE_INCLUDE_DIR})
ENDIF (SPATIALITE_FOUND)
#############
IF (WIN32)
@ -269,6 +285,10 @@ IF (POSTGRES_FOUND)
TARGET_LINK_LIBRARIES (qgis ${POSTGRES_LIBRARY})
ENDIF (POSTGRES_FOUND)
IF (SPATIALITE_FOUND)
TARGET_LINK_LIBRARIES (qgis ${SPATIALITE_LIBRARY})
ENDIF (SPATIALITE_FOUND)
IF (APPLE)
# For Mac OS X, the executable must be at the root of the bundle's executable folder
INSTALL(TARGETS qgis RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})

View File

@ -175,6 +175,9 @@
#ifdef HAVE_POSTGRESQL
#include "qgsdbsourceselect.h"
#endif
#ifdef HAVE_SPATIALITE
#include "qgsspatialitesourceselect.h"
#endif
#include "qgspythondialog.h"
#include "qgspythonutils.h"
@ -776,6 +779,18 @@ void QgisApp::createActions()
//#endif
connect( mActionAddPgLayer, SIGNAL( triggered() ), this, SLOT( addDatabaseLayer() ) );
mActionAddSpatiaLiteLayer = new QAction( getThemeIcon( "mActionAddSpatiaLiteLayer.png" ), tr( "Add SpatiaLite Layer..." ), this );
mActionAddSpatiaLiteLayer->setShortcut( tr( "L", "Add a SpatiaLite Layer" ) );
mActionAddSpatiaLiteLayer->setStatusTip( tr( "Add a SpatiaLite Layer" ) );
connect( mActionAddSpatiaLiteLayer, SIGNAL( triggered() ), this, SLOT( addSpatiaLiteLayer() ) );
//#ifdef HAVE_SPATIALITE
// QgsDebugMsg("HAVE_SPATIALITE is defined");
// assert(0);
//#else
// QgsDebugMsg("HAVE_SPATIALITE not defined");
// assert(0);
//#endif
mActionAddWmsLayer = new QAction( getThemeIcon( "mActionAddWmsLayer.png" ), tr( "Add WMS Layer..." ), this );
mActionAddWmsLayer->setShortcut( tr( "W", "Add a Web Mapping Server Layer" ) );
mActionAddWmsLayer->setStatusTip( tr( "Add a Web Mapping Server Layer" ) );
@ -1109,6 +1124,9 @@ void QgisApp::createMenus()
mLayerMenu->addAction( mActionAddRasterLayer );
#ifdef HAVE_POSTGRESQL
mLayerMenu->addAction( mActionAddPgLayer );
#endif
#ifdef HAVE_SPATIALITE
mLayerMenu->addAction( mActionAddSpatiaLiteLayer );
#endif
mLayerMenu->addAction( mActionAddWmsLayer );
mActionLayerSeparator1 = mLayerMenu->addSeparator();
@ -1207,6 +1225,9 @@ void QgisApp::createToolBars()
mFileToolBar->addAction( mActionAddRasterLayer );
#ifdef HAVE_POSTGRESQL
mFileToolBar->addAction( mActionAddPgLayer );
#endif
#ifdef HAVE_SPATIALITE
mFileToolBar->addAction( mActionAddSpatiaLiteLayer );
#endif
mFileToolBar->addAction( mActionAddWmsLayer );
mToolbarMenu->addAction( mFileToolBar->toggleViewAction() );
@ -1432,6 +1453,7 @@ void QgisApp::setTheme( QString theThemeName )
mActionAddOgrLayer->setIcon( getThemeIcon( "/mActionAddOgrLayer.png" ) );
mActionAddRasterLayer->setIcon( getThemeIcon( "/mActionAddRasterLayer.png" ) );
mActionAddPgLayer->setIcon( getThemeIcon( "/mActionAddLayer.png" ) );
mActionAddSpatiaLiteLayer->setIcon( getThemeIcon( "/mActionAddSpatiaLiteLayer.png" ) );
mActionRemoveLayer->setIcon( getThemeIcon( "/mActionRemoveLayer.png" ) );
mActionNewVectorLayer->setIcon( getThemeIcon( "/mActionNewVectorLayer.png" ) );
mActionAddAllToOverview->setIcon( getThemeIcon( "/mActionAddAllToOverview.png" ) );
@ -1794,6 +1816,13 @@ void QgisApp::about()
#else
versionString += tr( " This copy of QGIS has been built without PostgreSQL support." );
#endif
#ifdef HAVE_SPATIALITE
versionString += tr( "\nThis copy of QGIS has been built with SpatiaLite support." );
#else
versionString += tr( "\nThis copy of QGIS has been built without SpatiaLite support." );
#endif
versionString += tr( "\nThis binary was compiled against Qt %1,"
"and is currently running against Qt %2" )
@ -2384,6 +2413,87 @@ void QgisApp::addDatabaseLayer()
#endif
#ifndef HAVE_SPATIALITE
void QgisApp::addSpatiaLiteLayer() {}
#else
void QgisApp::addSpatiaLiteLayer()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
// show the SpatiaLite dialog
QgsSpatiaLiteSourceSelect *dbs = new QgsSpatiaLiteSourceSelect( this );
mMapCanvas->freeze();
if (dbs->exec())
{
// Let render() do its own cursor management
// QApplication::setOverrideCursor(Qt::WaitCursor);
// repaint the canvas if it was covered by the dialog
// add files to the map canvas
QStringList tables = dbs->selectedTables();
QApplication::setOverrideCursor(Qt::WaitCursor);
QString connectionInfo = dbs->connectionInfo();
// for each selected table, connect to the database and build a canvasitem for it
QStringList::Iterator it = tables.begin();
while (it != tables.end())
{
// normalizing the layer name
QString layername = *it;
layername = layername.mid(1);
int idx = layername.indexOf( "\" (" );
if (idx > 0)
layername.truncate(idx);
// create the layer
//qWarning("creating layer");
QgsVectorLayer *layer = new QgsVectorLayer( "dbname='" + connectionInfo + "' table=" + *it + ")", layername, "spatialite" );
if ( layer->isValid() )
{
// register this layer with the central layers registry
QgsMapLayerRegistry::instance()->addMapLayer( layer );
// notify the project we've made a change
QgsProject::instance()->dirty( true );
}
else
{
QgsDebugMsg( (*it) + " is an invalid layer - not loaded" );
QMessageBox::critical( this, tr( "Invalid Layer" ), tr( "%1 is an invalid layer and cannot be loaded." ).arg( *it ) );
delete layer;
}
//qWarning("incrementing iterator");
++it;
}
QApplication::restoreOverrideCursor();
statusBar()->showMessage( mMapCanvas->extent().toString( 2 ) );
}
delete dbs;
// update UI
qApp->processEvents();
// draw the map
mMapCanvas->freeze( false );
mMapCanvas->refresh();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
} // QgisApp::addSpatiaLiteLayer()
#endif
void QgisApp::addWmsLayer()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )

View File

@ -246,6 +246,7 @@ class QgisApp : public QMainWindow
QAction *actionAddOgrLayer() { return mActionAddOgrLayer; }
QAction *actionAddRasterLayer() { return mActionAddRasterLayer; }
QAction *actionAddPgLayer() { return mActionAddPgLayer; }
QAction *actionAddSpatiaLiteLayer() { return mActionAddSpatiaLiteLayer; };
QAction *actionAddWmsLayer() { return mActionAddWmsLayer; }
QAction *actionLayerSeparator1() { return mActionLayerSeparator1; }
QAction *actionOpenTable() { return mActionOpenTable; }
@ -369,6 +370,10 @@ class QgisApp : public QMainWindow
//#ifdef HAVE_POSTGRESQL
//! Add a databaselayer to the map
void addDatabaseLayer();
//#endif
//#ifdef HAVE_SPATIALITE
//! Add a SpatiaLite layer to the map
void addSpatiaLiteLayer();
//#endif
/** toggles whether the current selected layer is in overview or not */
void isInOverview();
@ -717,6 +722,7 @@ class QgisApp : public QMainWindow
QAction *mActionAddOgrLayer;
QAction *mActionAddRasterLayer;
QAction *mActionAddPgLayer;
QAction *mActionAddSpatiaLiteLayer;
QAction *mActionAddWmsLayer;
QAction *mActionLayerSeparator1;
QAction *mActionOpenTable;

View File

@ -0,0 +1,52 @@
/***************************************************************************
qgsspatialitefilterproxymodel.cpp - description
-------------------------
begin : Dec 2008
copyright : (C) 2008 by Sandro Furieri
email : a.furieri@lqt.it
***************************************************************************/
/***************************************************************************
* *
* 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 "qgsspatialitefilterproxymodel.h"
QgsSpatiaLiteFilterProxyModel::QgsSpatiaLiteFilterProxyModel(QObject * parent):QSortFilterProxyModel(parent)
{
}
QgsSpatiaLiteFilterProxyModel::~QgsSpatiaLiteFilterProxyModel()
{
}
bool QgsSpatiaLiteFilterProxyModel::filterAcceptsRow(int row, const QModelIndex & source_parent) const
{
//if parent is valid, we have a toplevel item that should be always shown
if (!source_parent.isValid())
{
return true;
}
//else we have a row that describes a table and that
//should be tested using the given wildcard/regexp
return QSortFilterProxyModel::filterAcceptsRow(row, source_parent);
}
void QgsSpatiaLiteFilterProxyModel::_setFilterWildcard(const QString & pattern)
{
QSortFilterProxyModel::setFilterWildcard(pattern);
emit layoutChanged();
}
void QgsSpatiaLiteFilterProxyModel::_setFilterRegExp(const QString & pattern)
{
QSortFilterProxyModel::setFilterRegExp(pattern);
emit layoutChanged();
}

View File

@ -0,0 +1,39 @@
/***************************************************************************
qgsspatialitefilterproxymodel.h - description
-----------------------
begin : Dec 2008
copyright : (C) 2008 by Sandro Furieri
email : a.furieri@lqt.it
***************************************************************************/
/***************************************************************************
* *
* 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 QGSSPATIALITEFILTERPROXYMODEL_H
#define QGSSPATIALITEFILTERPROXYMODEL_H
#include <QSortFilterProxyModel>
/**A class that implements a custom filter and can be used
as a proxy for QgsSpatiaLiteTableModel*/
class QgsSpatiaLiteFilterProxyModel:public QSortFilterProxyModel
{
public:
QgsSpatiaLiteFilterProxyModel(QObject * parent = 0);
~QgsSpatiaLiteFilterProxyModel();
/**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

View File

@ -0,0 +1,622 @@
/***************************************************************************
qgsspatialitesourceselect.cpp
Dialog to select SpatiaLite layer(s) and add it to the map canvas
-------------------
begin : Dec 2008
copyright : (C) 2008 bySandro Furieri
email : a.furieri@lqt.it
***************************************************************************/
/***************************************************************************
* *
* 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 "qgsspatialitesourceselect.h"
#include "qgisapp.h"
#include "qgslogger.h"
#include "qgsapplication.h"
#include "qgscontexthelp.h"
#include <QInputDialog>
#include <QMessageBox>
#include <QSettings>
#include <QTextStream>
#include <QTableWidgetItem>
#include <QHeaderView>
#include <QStringList>
#include <cassert>
#include <iostream>
QgsSpatiaLiteSourceSelect::QgsSpatiaLiteSourceSelect(QgisApp * app, Qt::WFlags fl):
QDialog(app, fl), qgisApp(app)
{
setupUi(this);
btnAdd->setEnabled(false);
populateConnectionList();
mSearchModeComboBox->addItem(tr("Wildcard"));
mSearchModeComboBox->addItem(tr("RegExp"));
mSearchColumnComboBox->addItem(tr("All"));
mSearchColumnComboBox->addItem(tr("Table"));
mSearchColumnComboBox->addItem(tr("Type"));
mSearchColumnComboBox->addItem(tr("Geometry column"));
mProxyModel.setParent(this);
mProxyModel.setFilterKeyColumn(-1);
mProxyModel.setFilterCaseSensitivity(Qt::CaseInsensitive);
mProxyModel.setDynamicSortFilter(true);
mProxyModel.setSourceModel(&mTableModel);
mTablesTreeView->setModel(&mProxyModel);
mTablesTreeView->setSortingEnabled(true);
mSearchGroupBox->hide();
//for Qt < 4.3.2, passing -1 to include all model columns
//in search does not seem to work
mSearchColumnComboBox->setCurrentIndex(1);
}
/** Autoconnected SLOTS **/
// Slot for adding a new connection
void QgsSpatiaLiteSourceSelect::on_btnNew_clicked()
{
addNewConnection();
}
// Slot for deleting an existing connection
void QgsSpatiaLiteSourceSelect::on_btnDelete_clicked()
{
deleteConnection();
}
// Slot for performing action when the Add button is clicked
void QgsSpatiaLiteSourceSelect::on_btnAdd_clicked()
{
addTables();
}
// Slot for showing help
void QgsSpatiaLiteSourceSelect::on_btnHelp_clicked()
{
showHelp();
}
/** End Autoconnected SLOTS **/
// Remember which database is selected
void QgsSpatiaLiteSourceSelect::on_cmbConnections_activated(int)
{
dbChanged();
}
void QgsSpatiaLiteSourceSelect::on_mSearchOptionsButton_clicked()
{
if (mSearchGroupBox->isVisible())
{
mSearchGroupBox->hide();
} else
{
mSearchGroupBox->show();
}
}
void QgsSpatiaLiteSourceSelect::on_mSearchTableEdit_textChanged(const QString & text)
{
if (mSearchModeComboBox->currentText() == tr("Wildcard"))
{
mProxyModel._setFilterWildcard(text);
} else if (mSearchModeComboBox->currentText() == tr("RegExp"))
{
mProxyModel._setFilterRegExp(text);
}
}
void QgsSpatiaLiteSourceSelect::on_mSearchColumnComboBox_currentIndexChanged(const QString & text)
{
if (text == tr("All"))
{
mProxyModel.setFilterKeyColumn(-1);
} else if (text == tr("Table"))
{
mProxyModel.setFilterKeyColumn(0);
} else if (text == tr("Type"))
{
mProxyModel.setFilterKeyColumn(1);
} else if (text == tr("Geometry column"))
{
mProxyModel.setFilterKeyColumn(2);
}
}
void QgsSpatiaLiteSourceSelect::on_mSearchModeComboBox_currentIndexChanged(const QString & text)
{
on_mSearchTableEdit_textChanged(mSearchTableEdit->text());
}
void QgsSpatiaLiteSourceSelect::setLayerType(QString table, QString column, QString type)
{
mTableModel.setGeometryTypesForTable(table, column, type);
mTablesTreeView->sortByColumn(0, Qt::AscendingOrder);
}
sqlite3 *QgsSpatiaLiteSourceSelect::openSpatiaLiteDb(const char *path)
{
sqlite3 *handle = NULL;
bool gcSpatiaLite = false;
bool rsSpatiaLite = false;
bool tableName = false;
bool geomColumn = false;
bool coordDims = false;
bool gcSrid = false;
bool type = false;
bool spatialIndex = false;
bool srsSrid = false;
bool authName = false;
bool authSrid = false;
bool refSysName = false;
bool proj4text = false;
int ret;
const char *name;
int i;
char **results;
int rows;
int columns;
char *errMsg = NULL;
QString errCause;
// trying to open the SQLite DB
mSqlitePath = path;
ret = sqlite3_open_v2(path, &handle, SQLITE_OPEN_READWRITE, NULL);
if (ret)
{
// failure
errCause = sqlite3_errmsg(handle);
QMessageBox::critical(this, tr("SpatiaLite DB Open Error"),
tr("Failure while connecting to: %1\n\n%2").arg(mSqlitePath).arg(errCause));
mSqlitePath = "";
return NULL;
}
// checking if table GEOMETRY_COLUMNS exists and has the expected layout
ret = sqlite3_get_table(handle, "PRAGMA table_info(geometry_columns)", &results, &rows, &columns, &errMsg);
if (ret != SQLITE_OK)
goto error;
if (rows < 1)
;
else
{
for (i = 1; i <= rows; i++)
{
name = results[(i * columns) + 1];
if (strcasecmp(name, "f_table_name") == 0)
tableName = true;
if (strcasecmp(name, "f_geometry_column") == 0)
geomColumn = true;
if (strcasecmp(name, "coord_dimension") == 0)
coordDims = true;
if (strcasecmp(name, "srid") == 0)
gcSrid = true;
if (strcasecmp(name, "type") == 0)
type = true;
if (strcasecmp(name, "spatial_index_enabled") == 0)
spatialIndex = true;
}
}
sqlite3_free_table(results);
if (tableName == true && geomColumn == true && type == true && coordDims == true && gcSrid == true && spatialIndex == true)
gcSpatiaLite = true;
// checking if table SPATIAL_REF_SYS exists and has the expected layout
ret = sqlite3_get_table(handle, "PRAGMA table_info(spatial_ref_sys)", &results, &rows, &columns, &errMsg);
if (ret != SQLITE_OK)
goto error;
if (rows < 1)
;
else
{
for (i = 1; i <= rows; i++)
{
name = results[(i * columns) + 1];
if (strcasecmp(name, "srid") == 0)
srsSrid = true;
if (strcasecmp(name, "auth_name") == 0)
authName = true;
if (strcasecmp(name, "auth_srid") == 0)
authSrid = true;
if (strcasecmp(name, "ref_sys_name") == 0)
refSysName = true;
if (strcasecmp(name, "proj4text") == 0)
proj4text = true;
}
}
sqlite3_free_table(results);
if (srsSrid == true && authName == true && authSrid == true && refSysName == true && proj4text == true)
rsSpatiaLite = true;
// OK, this one seems to be a valid SpatiaLite DB
if (gcSpatiaLite == true && rsSpatiaLite == true)
return handle;
// this one cannot be a valid SpatiaLite DB - no Spatial MetaData where found
closeSpatiaLiteDb(handle);
errCause = tr("seems to be a valid SQLite DB, but not a SpatiaLite's one ...");
QMessageBox::critical(this, tr("SpatiaLite DB Open Error"),
tr("Failure while connecting to: %1\n\n%2").arg(mSqlitePath).arg(errCause));
mSqlitePath = "";
return NULL;
error:
// unexpected IO error
closeSpatiaLiteDb(handle);
errCause = tr("unknown error cause");
if (errMsg != NULL)
{
errCause = errMsg;
sqlite3_free(errMsg);
}
QMessageBox::critical(this, tr("SpatiaLite DB Open Error"),
tr("Failure while connecting to: %1\n\n%2").arg(mSqlitePath).arg(errCause));
mSqlitePath = "";
return NULL;
}
void QgsSpatiaLiteSourceSelect::closeSpatiaLiteDb(sqlite3 * handle)
{
if (handle)
sqlite3_close(handle);
}
void QgsSpatiaLiteSourceSelect::populateConnectionList()
{
QSettings settings;
settings.beginGroup("/SpatiaLite/connections");
QStringList keys = settings.childGroups();
QStringList::Iterator it = keys.begin();
cmbConnections->clear();
while (it != keys.end())
{
// retrieving the SQLite DB name and full path
QString text = *it + tr(" @ ");
text += settings.value(*it + tr("/sqlitepath"), "###unknown###").toString();
cmbConnections->addItem(text);
++it;
}
settings.endGroup();
setConnectionListPosition();
}
void QgsSpatiaLiteSourceSelect::addNewConnection()
{
// Retrieve last used project dir from persistent settings
sqlite3 *handle;
char *path = NULL;
int sz;
QSettings settings;
QString fullPath;
QString lastUsedDir = settings.value("/UI/lastSpatiaLiteDir", ".").toString();
QFileDialog *openFileDialog = new QFileDialog(this,
tr("Choose a SpatiaLite/SQLite DB to open"),
lastUsedDir, QObject::tr("SQLite DB (*.sqlite);;All files (*.*)"));
openFileDialog->setFileMode(QFileDialog::ExistingFile);
if (openFileDialog->exec() == QDialog::Accepted)
{
fullPath = openFileDialog->selectedFiles().first();
QFileInfo myFI(fullPath);
QString myPath = myFI.path();
QString myName = myFI.fileName();
// transforming full path as char *
QByteArray utf8 = fullPath.toUtf8();
sz = utf8.size();
path = new char[sz + 1];
memcpy(path, utf8.data(), sz);
path[sz] = '\0';
handle = openSpatiaLiteDb(path);
if (handle)
{
// OK, this one is a valid SpatiaLite DB
closeSpatiaLiteDb(handle);
// Persist last used SpatiaLite dir
settings.setValue("/UI/lastSpatiaLiteDir", myPath);
// inserting this SQLite DB path
QString baseKey = "/SpatiaLite/connections/";
settings.setValue(baseKey + "selected", myName);
baseKey += myName;
settings.setValue(baseKey + "/sqlitepath", fullPath);
}
} else
{
// if they didn't select anything, just return
delete openFileDialog;
return;
}
delete openFileDialog;
if (path != NULL)
delete path;
populateConnectionList();
}
void QgsSpatiaLiteSourceSelect::deleteConnection()
{
QSettings settings;
QString subKey = cmbConnections->currentText();
int idx = subKey.indexOf(" @ ");
if (idx > 0)
subKey.truncate(idx);
QString key = "/SpatiaLite/connections/" + subKey;
QString msg = tr("Are you sure you want to remove the ") + subKey + tr(" connection and all associated settings?");
QMessageBox::StandardButton result =
QMessageBox::information(this, tr("Confirm Delete"), msg, QMessageBox::Ok | QMessageBox::Cancel);
if (result == QMessageBox::Ok)
{
settings.remove(key + "/sqlitepath");
settings.remove(key);
//if(!success){
// QMessageBox::information(this,"Unable to Remove","Unable to remove the connection " + cmbConnections->currentText());
//}
cmbConnections->removeItem(cmbConnections->currentIndex()); // populateConnectionList();
setConnectionListPosition();
}
}
void QgsSpatiaLiteSourceSelect::addTables()
{
m_selectedTables.clear();
typedef QMap < int, QVector < QString > >schemaInfo;
QMap < QString, schemaInfo > dbInfo;
QItemSelection selection = mTablesTreeView->selectionModel()->selection();
QModelIndexList selectedIndices = selection.indexes();
QStandardItem *currentItem = 0;
QModelIndexList::const_iterator selected_it = selectedIndices.constBegin();
for (; selected_it != selectedIndices.constEnd(); ++selected_it)
{
if (!selected_it->parent().isValid())
{
//top level items only contain the schema names
continue;
}
currentItem = mTableModel.itemFromIndex(mProxyModel.mapToSource(*selected_it));
if (!currentItem)
{
continue;
}
QString currentSchemaName = currentItem->parent()->text();
int currentRow = currentItem->row();
int currentColumn = currentItem->column();
if (dbInfo[currentSchemaName][currentRow].size() == 0)
{
dbInfo[currentSchemaName][currentRow].resize(5);
}
dbInfo[currentSchemaName][currentRow][currentColumn] = currentItem->text();
}
//now traverse all the schemas and table infos
QString tableName, geomColumnName;
QString query;
QMap < QString, schemaInfo >::const_iterator schema_it = dbInfo.constBegin();
for (; schema_it != dbInfo.constEnd(); ++schema_it)
{
schemaInfo scheme = schema_it.value();
schemaInfo::const_iterator entry_it = scheme.constBegin();
for (; entry_it != scheme.constEnd(); ++entry_it)
{
tableName = entry_it->at(0);
geomColumnName = entry_it->at(2);
query = "\"" + tableName + "\" (" + geomColumnName;
m_selectedTables.push_back(query);
}
}
if (m_selectedTables.empty())
{
QMessageBox::information(this, tr("Select Table"), tr("You must select a table in order to add a Layer."));
} else
{
accept();
}
}
void QgsSpatiaLiteSourceSelect::on_btnConnect_clicked()
{
sqlite3 *handle;
char *path = NULL;
int sz;
QSettings settings;
QString subKey = cmbConnections->currentText();
int idx = subKey.indexOf(" @ ");
if (idx > 0)
subKey.truncate(idx);
QString key = "/SpatiaLite/connections/" + subKey;
QString fullPath = settings.value(key + "/sqlitepath").toString();
// transforming full path as char *
QByteArray utf8 = fullPath.toUtf8();
sz = utf8.size();
path = new char[sz + 1];
memcpy(path, utf8.data(), sz);
path[sz] = '\0';
// trying to connect to SpatiaLite DB
handle = openSpatiaLiteDb(path);
if (handle == NULL)
{
// unexpected error; invalid SpatiaLite DB
delete path;
return;
}
delete path;
QModelIndex rootItemIndex = mTableModel.indexFromItem(mTableModel.invisibleRootItem());
mTableModel.removeRows(0, mTableModel.rowCount(rootItemIndex), rootItemIndex);
// populate the table list
// get the list of suitable tables and columns and populate the UI
geomCol details;
if (getTableInfo(handle) == true)
;
else
{
qDebug("Unable to get list of spatially enabled tables from the database");
qDebug(sqlite3_errmsg(handle));
}
closeSpatiaLiteDb(handle);
// BEGIN CHANGES ECOS
if (cmbConnections->count() > 0)
btnAdd->setEnabled(true);
// END CHANGES ECOS
mTablesTreeView->sortByColumn(0, Qt::AscendingOrder);
mTablesTreeView->header()->resizeSection(1, 140);
mTablesTreeView->resizeColumnToContents(0);
//expand all the toplevel items
int numTopLevelItems = mTableModel.invisibleRootItem()->rowCount();
for (int i = 0; i < numTopLevelItems; ++i)
{
mTablesTreeView->expand(mProxyModel.mapFromSource(mTableModel.indexFromItem(mTableModel.invisibleRootItem()->child(i))));
}
}
QStringList QgsSpatiaLiteSourceSelect::selectedTables()
{
return m_selectedTables;
}
QString QgsSpatiaLiteSourceSelect::connectionInfo()
{
return mSqlitePath;
}
bool QgsSpatiaLiteSourceSelect::getTableInfo(sqlite3 * handle)
{
int ret;
int i;
char **results;
int rows;
int columns;
char *errMsg = NULL;
bool ok = false;
QApplication::setOverrideCursor(Qt::WaitCursor);
// setting the SQLite DB name
QFileInfo myFI(mSqlitePath);
QString myName = myFI.fileName();
mTableModel.setSqliteDb(myName);
// the following query return the tables containing a Geometry column
ret = sqlite3_get_table(handle,
"SELECT f_table_name, f_geometry_column, type FROM geometry_columns", &results, &rows, &columns, &errMsg);
if (ret != SQLITE_OK)
goto error;
if (rows < 1)
;
else
{
for (i = 1; i <= rows; i++)
{
QString tableName = results[(i * columns) + 0];
QString column = results[(i * columns) + 1];
QString type = results[(i * columns) + 2];
mTableModel.addTableEntry(type, tableName, column);
}
ok = true;
}
sqlite3_free_table(results);
QApplication::restoreOverrideCursor();
return ok;
error:
// unexpected IO error
QString errCause = tr("unknown error cause");
if (errMsg != NULL)
{
errCause = errMsg;
sqlite3_free(errMsg);
}
QMessageBox::critical(this, tr("SpatiaLite getTableInfo Error"),
tr("Failure exploring tables from: %1\n\n%2").arg(mSqlitePath).arg(errCause));
}
void QgsSpatiaLiteSourceSelect::showHelp()
{
QgsContextHelp::run(context_id);
}
QString QgsSpatiaLiteSourceSelect::fullDescription(QString table, QString column, QString type)
{
QString full_desc = "";
full_desc += table + "\" (" + column + ") " + type;
return full_desc;
}
void QgsSpatiaLiteSourceSelect::dbChanged()
{
// Remember which database was selected.
QSettings settings;
settings.setValue("/SpatiaLite/connections/selected", cmbConnections->currentText());
}
void QgsSpatiaLiteSourceSelect::setConnectionListPosition()
{
QSettings settings;
// If possible, set the item currently displayed database
QString toSelect = settings.value("/SpatiaLite/connections/selected").toString();
// Does toSelect exist in cmbConnections?
bool set = false;
for (int i = 0; i < cmbConnections->count(); ++i)
if (cmbConnections->itemText(i) == toSelect)
{
cmbConnections->setCurrentIndex(i);
set = true;
break;
}
// If we couldn't find the stored item, but there are some,
// default to the last item (this makes some sense when deleting
// items as it allows the user to repeatidly click on delete to
// remove a whole lot of items).
if (!set && cmbConnections->count() > 0)
{
// If toSelect is null, then the selected connection wasn't found
// by QSettings, which probably means that this is the first time
// the user has used qgis with database connections, so default to
// the first in the list of connetions. Otherwise default to the last.
if (toSelect.isNull())
cmbConnections->setCurrentIndex(0);
else
cmbConnections->setCurrentIndex(cmbConnections->count() - 1);
}
}
void QgsSpatiaLiteSourceSelect::setSearchExpression(const QString & regexp)
{
}

View File

@ -0,0 +1,137 @@
/***************************************************************************
qgspatialitesourceselect.h - description
-------------------
begin : Dec 2008
copyright : (C) 2008 by Sandro Furieri
email : a.furieri@lqt.it
***************************************************************************/
/***************************************************************************
* *
* 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 QGSSPATIALITESOURCESELECT_H
#define QGSSPATIALITESOURCESELECT_H
#include "ui_qgsspatialitesourceselectbase.h"
#include "qgisgui.h"
#include "qgsspatialitefilterproxymodel.h"
#include "qgsspatialitetablemodel.h"
extern "C"
{
#include <spatialite/sqlite3.h>
}
#include <QThread>
#include <vector>
#include <list>
#include <utility>
#include <QMap>
#include <QPair>
#include <QIcon>
#include <QFileDialog>
class QStringList;
class QTableWidgetItem;
class QgisApp;
/*! \class QgsSpatiaLiteSourceSelect
* \brief Dialog to create connections and add tables from SpatiaLite.
*
* This dialog allows the user to define and save connection information
* for SpatiaLite/SQLite databases. The user can then connect and add
* tables from the database to the map canvas.
*/
class QgsSpatiaLiteSourceSelect:public QDialog, private Ui::QgsSpatiaLiteSourceSelectBase
{
Q_OBJECT public:
//! Constructor
QgsSpatiaLiteSourceSelect(QgisApp * app, Qt::WFlags fl = QgisGui::ModalDialogFlags);
//! Destructor
~QgsSpatiaLiteSourceSelect()
{
;
}
//! Opens the create connection dialog to build a new connection
void addNewConnection();
//! Deletes the selected connection
void deleteConnection();
//! Populate the connection list combo box
void populateConnectionList();
//! Determines the tables the user selected and closes the dialog
void addTables();
//! String list containing the selected tables
QStringList selectedTables();
//! Connection info (DB-path)
QString connectionInfo();
// Store the selected database
void dbChanged();
public slots:
/*! Connects to the database using the stored connection parameters.
* Once connected, available layers are displayed.
*/
void on_btnConnect_clicked();
void on_btnAdd_clicked();
void on_btnNew_clicked();
void on_btnDelete_clicked();
void on_mSearchOptionsButton_clicked();
void on_mSearchTableEdit_textChanged(const QString & text);
void on_mSearchColumnComboBox_currentIndexChanged(const QString & text);
void on_mSearchModeComboBox_currentIndexChanged(const QString & text);
void on_btnHelp_clicked();
void on_cmbConnections_activated(int);
void setLayerType(QString table, QString column, QString type);
//!Sets a new regular expression to the model
void setSearchExpression(const QString & regexp);
private:
enum columns
{
dbssType = 0,
dbssDetail,
dbssSql,
dbssColumns,
};
typedef std::pair < QString, QString > geomPair;
typedef std::list < geomPair > geomCol;
/**Inserts information about the spatial tables into mTableModel*/
bool getTableInfo(sqlite3 * handle);
// SpatiaLite DB open / close
sqlite3 *openSpatiaLiteDb(const char *path);
void closeSpatiaLiteDb(sqlite3 * handle);
// Set the position of the database connection list to the last
// used one.
void setConnectionListPosition();
// Show the context help for the dialog
void showHelp();
// Combine the table and column data into a single string
// useful for display to the user
QString fullDescription(QString table, QString column, QString type);
// The column labels
QStringList mColumnLabels;
QString mSqlitePath;
QStringList m_selectedTables;
// Storage for the range of layer type icons
QMap < QString, QPair < QString, QIcon > >mLayerIcons;
//! Pointer to the qgis application mainwindow
QgisApp *qgisApp;
static const int context_id = 250632828;
//! Model that acts as datasource for mTableTreeWidget
QgsSpatiaLiteTableModel mTableModel;
QgsSpatiaLiteFilterProxyModel mProxyModel;
};
#endif // QGSSPATIALITESOURCESELECT_H

View File

@ -0,0 +1,204 @@
/***************************************************************************
qgsspatialitetablemodel.cpp - description
-------------------
begin : Dec 2008
copyright : (C) 2008 by Sandro Furieri
email : a.furieri@lqt.it
***************************************************************************/
/***************************************************************************
* *
* 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 "qgsspatialitetablemodel.h"
#include "qgsapplication.h"
#include "qgisapp.h"
QgsSpatiaLiteTableModel::QgsSpatiaLiteTableModel():QStandardItemModel(), mTableCount(0)
{
QStringList headerLabels;
headerLabels << tr("Table");
headerLabels << tr("Type");
headerLabels << tr("Geometry column");
setHorizontalHeaderLabels(headerLabels);
}
QgsSpatiaLiteTableModel::~QgsSpatiaLiteTableModel()
{
}
void QgsSpatiaLiteTableModel::addTableEntry(QString type, QString tableName, QString geometryColName)
{
//is there already a root item ?
QStandardItem *dbItem;
QList < QStandardItem * >dbItems = findItems(mSqliteDb, Qt::MatchExactly, 0);
//there is already an item
if (dbItems.size() > 0)
{
dbItem = dbItems.at(0);
} else //create a new toplevel item
{
dbItem = new QStandardItem(mSqliteDb);
dbItem->setFlags(Qt::ItemIsEnabled);
invisibleRootItem()->setChild(invisibleRootItem()->rowCount(), dbItem);
}
//path to icon for specified type
QString typeName;
QGis::WkbType wkbType = qgisTypeFromDbType(type);
QIcon iconFile = iconForType(wkbType);
QList < QStandardItem * >childItemList;
QStandardItem *typeItem = new QStandardItem(QIcon(iconFile), type);
typeItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
QStandardItem *tableItem = new QStandardItem(tableName);
tableItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
QStandardItem *geomItem = new QStandardItem(geometryColName);
geomItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
childItemList.push_back(tableItem);
childItemList.push_back(typeItem);
childItemList.push_back(geomItem);
dbItem->appendRow(childItemList);
++mTableCount;
}
void QgsSpatiaLiteTableModel::setGeometryTypesForTable(const QString & table, const QString & attribute, const QString & type)
{
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(",");
//find schema item and table item
QStandardItem *dbItem;
QList < QStandardItem * >dbItems = findItems(mSqliteDb, Qt::MatchExactly, 0);
if (dbItems.size() < 1)
{
return;
}
dbItem = dbItems.at(0);
int numChildren = dbItem->rowCount();
QModelIndex currentChildIndex;
QModelIndex currentTableIndex;
QModelIndex currentTypeIndex;
QModelIndex currentGeomColumnIndex;
for (int i = 0; i < numChildren; ++i)
{
currentChildIndex = indexFromItem(dbItem->child(i, 0));
if (!currentChildIndex.isValid())
{
continue;
}
currentTableIndex = currentChildIndex.sibling(i, 1);
currentTypeIndex = currentChildIndex.sibling(i, 2);
currentGeomColumnIndex = currentChildIndex.sibling(i, 3);
QString geomColText = itemFromIndex(currentGeomColumnIndex)->text();
if (!currentTypeIndex.isValid() || !currentTableIndex.isValid() || !currentGeomColumnIndex.isValid())
{
continue;
}
if (itemFromIndex(currentTableIndex)->text() == table &&
(geomColText == attribute || geomColText.startsWith(attribute + " AS ")))
{
if (typeIsEmpty)
{
removeRow(i, indexFromItem(dbItem));
return;
}
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 "))
{
itemFromIndex(currentGeomColumnIndex)->setText(geomColText + " AS " + typeList.at(0));
}
for (int j = 1; j < typeList.size(); ++j)
{
//todo: add correct type
addTableEntry(typeList.at(j), table, geomColText + " AS " + typeList.at(j));
}
}
}
}
QIcon QgsSpatiaLiteTableModel::iconForType(QGis::WkbType type) const
{
if (type == QGis::WKBPoint || type == QGis::WKBPoint25D || type == QGis::WKBMultiPoint || type == QGis::WKBMultiPoint25D)
{
return QgisApp::getThemeIcon("/mIconPointLayer.png");
} else if (type == QGis::WKBLineString || type == QGis::WKBLineString25D || type == QGis::WKBMultiLineString
|| type == QGis::WKBMultiLineString25D)
{
return QgisApp::getThemeIcon("/mIconLineLayer.png");
} else if (type == QGis::WKBPolygon || type == QGis::WKBPolygon25D || type == QGis::WKBMultiPolygon
|| type == QGis::WKBMultiPolygon25D)
{
return QgisApp::getThemeIcon("/mIconPolygonLayer.png");
} else
return QIcon();
}
QString QgsSpatiaLiteTableModel::displayStringForType(QGis::WkbType type) const
{
if (type == QGis::WKBPoint || type == QGis::WKBPoint25D)
{
return tr("Point");
} else if (type == QGis::WKBMultiPoint || type == QGis::WKBMultiPoint25D)
{
return tr("Multipoint");
} else if (type == QGis::WKBLineString || type == QGis::WKBLineString25D)
{
return tr("Line");
} else if (type == QGis::WKBMultiLineString || type == QGis::WKBMultiLineString25D)
{
return tr("Multiline");
} else if (type == QGis::WKBPolygon || type == QGis::WKBPolygon25D)
{
return tr("Polygon");
} else if (type == QGis::WKBMultiPolygon || type == QGis::WKBMultiPolygon25D)
{
return tr("Multipolygon");
}
return "Unknown";
}
QGis::WkbType QgsSpatiaLiteTableModel::qgisTypeFromDbType(const QString & dbType) const
{
if (dbType == "POINT")
{
return QGis::WKBPoint;
} else if (dbType == "MULTIPOINT")
{
return QGis::WKBMultiPoint;
} else if (dbType == "LINESTRING")
{
return QGis::WKBLineString;
} else if (dbType == "MULTILINESTRING")
{
return QGis::WKBMultiLineString;
} else if (dbType == "POLYGON")
{
return QGis::WKBPolygon;
} else if (dbType == "MULTIPOLYGON")
{
return QGis::WKBMultiPolygon;
}
return QGis::WKBUnknown;
}

View File

@ -0,0 +1,56 @@
/***************************************************************************
qgsspatialitetablemodel.h - description
-------------------
begin : Dec 2008
copyright : (C) 2008 by Sandro Furieri
email : a.furieri@lqt.it
***************************************************************************/
/***************************************************************************
* *
* 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 <QStandardItemModel>
class QIcon;
#include "qgis.h"
/**A model that holds the tables of a database in a hierarchy where the
SQLite DB is the root elements that contain the individual tables as children.
The tables have the following columns: Type, Tablename, Geometry Column*/
class QgsSpatiaLiteTableModel:public QStandardItemModel
{
Q_OBJECT public:
QgsSpatiaLiteTableModel();
~QgsSpatiaLiteTableModel();
/**Adds entry for one database table to the model*/
void addTableEntry(QString type, QString tableName, QString geometryColName);
/**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 & table, const QString & attribute, const QString & type);
/**Returns the number of tables in the model*/
int tableCount() const
{
return mTableCount;
}
/** Sets the SQLite DB full path*/
void setSqliteDb(const QString & dbName)
{
mSqliteDb = dbName;
}
private:
/**Number of tables in the model*/
int mTableCount;
QString mSqliteDb;
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;
};

View File

@ -5,6 +5,10 @@ IF (POSTGRES_FOUND)
SUBDIRS (postgres)
ENDIF (POSTGRES_FOUND)
IF (SPATIALITE_FOUND)
SUBDIRS (spatialite)
ENDIF (SPATIALITE_FOUND)
IF (EXPAT_FOUND)
SUBDIRS (gpx wfs)
ENDIF (EXPAT_FOUND)

View File

@ -0,0 +1,36 @@
########################################################
# Files
SET(SPATIALITE_SRCS qgsspatialiteprovider.cpp)
SET(SPATIALITE_MOC_HDRS qgsspatialiteprovider.h)
########################################################
# Build
QT4_WRAP_CPP(SPATIALITE_MOC_SRCS ${SPATIALITE_MOC_HDRS})
INCLUDE_DIRECTORIES(
../../core
${SPATIALITE_INCLUDE_DIR}
${SPATIALITE_INCLUDE_DIR}
)
ADD_LIBRARY (spatialiteprovider MODULE ${SPATIALITE_SRCS} ${SPATIALITE_MOC_SRCS})
TARGET_LINK_LIBRARIES(spatialiteprovider
${QT_QTCORE_LIBRARY}
${QT_QTXML_LIBRARY}
${SPATIALITE_LIBRARY}
qgis_core
)
########################################################
# Install
INSTALL(TARGETS spatialiteprovider
RUNTIME DESTINATION ${QGIS_PLUGIN_DIR}
LIBRARY DESTINATION ${QGIS_PLUGIN_DIR})

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,364 @@
/***************************************************************************
qgsspatialiteprovider.h Data provider for SpatiaLite DBMS
begin : Dec 2008
copyright : (C) 2008 Sandro Furieri
email : a.furieri@lqt.it
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
extern "C"
{
#include <spatialite/sqlite3.h>
#include <spatialite/gaiageo.h>
#include <spatialite.h>
}
#include "qgsvectordataprovider.h"
#include "qgsrectangle.h"
#include <list>
#include <queue>
#include <fstream>
#include <set>
class QgsFeature;
class QgsField;
#include "qgsdatasourceuri.h"
/**
\class QgsSpatiaLiteProvider
\brief Data provider for SQLite/SpatiaLite layers.
This provider implements the
interface defined in the QgsDataProvider class to provide access to spatial
data residing in a SQLite/SpatiaLite enabled database.
*/
class QgsSpatiaLiteProvider:public QgsVectorDataProvider
{
Q_OBJECT public:
/**
* Constructor of the vector provider
* @param uri uniform resource locator (URI) for a dataset
*/
QgsSpatiaLiteProvider(QString const &uri = "");
//! Destructor
virtual ~ QgsSpatiaLiteProvider();
/**
* Returns the permanent storage type for this layer as a friendly name.
*/
virtual QString storageType() const;
/*! Get the QgsCoordinateReferenceSystem for this layer
* @note Must be reimplemented by each provider.
* If the provider isn't capable of returning
* its projection an empty srs will be return, ti will return 0
*/
virtual QgsCoordinateReferenceSystem crs();
/** Select features based on a bounding rectangle. Features can be retrieved with calls to nextFeature.
* @param fetchAttributes list of attributes which should be fetched
* @param rect spatial filter
* @param fetchGeometry true if the feature geometry should be fetched
* @param useIntersect true if an accurate intersection test should be used,
* false if a test based on bounding box is sufficient
*/
virtual bool featureAtId(int featureId,
QgsFeature & feature, bool fetchGeometry = true, QgsAttributeList fetchAttributes = QgsAttributeList());
/** Select features based on a bounding rectangle. Features can be retrieved with calls to nextFeature.
* @param fetchAttributes list of attributes which should be fetched
* @param rect spatial filter
* @param fetchGeometry true if the feature geometry should be fetched
* @param useIntersect true if an accurate intersection test should be used,
* false if a test based on bounding box is sufficient
*/
virtual void select(QgsAttributeList fetchAttributes = QgsAttributeList(),
QgsRectangle rect = QgsRectangle(), bool fetchGeometry = true, bool useIntersect = false);
/**
* Get the next feature resulting from a select operation.
* @param feature feature which will receive data from the provider
* @return true when there was a feature to fetch, false when end was hit
*/
virtual bool nextFeature(QgsFeature & feature);
/** Get the feature type. This corresponds to
* WKBPoint,
* WKBLineString,
* WKBPolygon,
* WKBMultiPoint,
* WKBMultiLineString or
* WKBMultiPolygon
* as defined in qgis.h
*/
QGis::WkbType geometryType() const;
/** return the number of layers for the current data source
@note
Should this be subLayerCount() instead?
*/
size_t layerCount() const;
/**
* Get the number of features in the layer
*/
long featureCount() const;
/**
* Get the number of fields in the layer
*/
uint fieldCount() const;
/** Return the extent for this data layer
*/
virtual QgsRectangle extent();
/** * Get the name of the primary key for the layer
*/
QString getPrimaryKey();
/**
* Get the field information for the layer
* @return vector of QgsField objects
*/
const QgsFieldMap & fields() const;
/** Reset the layer - for a PostgreSQL layer, this means clearing the PQresult
* pointer, setting it to 0 and reloading the field list
*/
void rewind();
/** Returns the minimum value of an attribute
* @param index the index of the attribute */
QVariant minimumValue(int index);
/** Returns the maximum value of an attribute
* @param index the index of the attribute */
QVariant maximumValue(int index);
/** Return the unique values of an attribute
* @param index the index of the attribute
* @param values reference to the list of unique values */
virtual void uniqueValues(int index, QList < QVariant > &uniqueValues);
/**Returns true if layer is valid
*/
bool isValid();
/**Adds a list of features
@return true in case of success and false in case of failure*/
bool addFeatures(QgsFeatureList & flist);
/**Deletes a list of features
@param id list of feature ids
@return true in case of success and false in case of failure*/
bool deleteFeatures(const QgsFeatureIds & id);
/**Adds new attributes
@param name map with attribute name as key and type as value
@return true in case of success and false in case of failure*/
bool addAttributes(const QgsNewAttributesMap & name);
/**Changes attribute values of existing features
@param attr_map a map containing the new attributes. The integer is the feature id,
the first QString is the attribute name and the second one is the new attribute value
@return true in case of success and false in case of failure*/
bool changeAttributeValues(const QgsChangedAttributesMap & attr_map);
/**
Changes geometries of existing features
@param geometry_map A std::map containing the feature IDs to change the geometries of.
the second map parameter being the new geometries themselves
@return true in case of success and false in case of failure
*/
bool changeGeometryValues(QgsGeometryMap & geometry_map);
/**Returns a bitmask containing the supported capabilities*/
int capabilities() const;
/** The SpatiaLite provider does its own transforms so we return
* true for the following three functions to indicate that transforms
* should not be handled by the QgsCoordinateTransform object. See the
* documentation on QgsVectorDataProvider for details on these functions.
*/
// XXX For now we have disabled native transforms in the SpatiaLite
// (following the PostgreSQL provider example)
bool supportsNativeTransform()
{
return false;
}
/** return a provider name
Essentially just returns the provider key. Should be used to build file
dialogs so that providers can be shown with their supported types. Thus
if more than one provider supports a given format, the user is able to
select a specific provider to open that file.
@note
Instead of being pure virtual, might be better to generalize this
behavior and presume that none of the sub-classes are going to do
anything strange with regards to their name or description?
*/
QString name() const;
/** return description
Return a terse string describing what the provider is.
@note
Instead of being pure virtual, might be better to generalize this
behavior and presume that none of the sub-classes are going to do
anything strange with regards to their name or description?
*/
QString description() const;
signals:
/**
* This is emitted whenever the worker thread has fully calculated the
* PostGIS extents for this layer, and its event has been received by this
* provider.
*/
void fullExtentCalculated();
/**
* This is emitted when this provider is satisfied that all objects
* have had a chance to adjust themselves after they'd been notified that
* the full extent is available.
*
* \note It currently isn't being emitted because we don't have an easy way
* for the overview canvas to only be repainted. In the meantime
* we are satisfied for the overview to reflect the new extent
* when the user adjusts the extent of the main map canvas.
*/
void repaintRequested();
private:
/** loads fields from input file to member attributeFields */
void loadFields();
QgsFieldMap attributeFields;
/**
* Flag indicating if the layer data source is a valid SpatiaLite layer
*/
bool valid;
/**
* DB full path
*/
QString mSqlitePath;
/**
* Name of the table with no schema
*/
QString mTableName;
/**
* Name of the primary key column in the table
*/
QString primaryKey;
/**
* Name of the geometry column in the table
*/
QString geometryColumn;
/**
* Geometry type
*/
QGis::WkbType geomType;
/**
* SQLite handle
*/
sqlite3 *sqliteHandle;
/**
* SQLite statement handle
*/
sqlite3_stmt *sqliteStatement;
/**
* Spatial reference id of the layer
*/
int mSrid;
/**
* proj4text
*/
QString mProj4text;
/**
* Rectangle that contains the extent (bounding box) of the layer
*/
QgsRectangle layerExtent;
/**
* Number of features in the layer
*/
long numberFeatures;
/**
* this Geometry is supported by an R*Tree spatial index
*/
bool spatialIndexRTree;
/**
* this Geometry is supported by an MBR cache spatial index
*/
bool spatialIndexMbrCache;
int enabledCapabilities;
const QgsField & field(int index) const;
/**
* internal utility functions used to handle common SQLite tasks
*/
//void sqliteOpen();
void closeDb();
QString quotedValue(QString value) const;
bool getGeometryDetails();
bool getTableSummary();
public:
class SqliteHandles
{
//
// a class allowing to reuse the same sqlite handle for more layers
//
public:
SqliteHandles(sqlite3 * handle):
ref(1), sqlite_handle(handle)
{
}
sqlite3 *handle()
{
return sqlite_handle;
}
//
// libsqlite3 wrapper
//
void sqliteClose();
static SqliteHandles *openDb(const QString & dbPath);
static void closeDb(SqliteHandles * &handle);
static void closeDb(QMap < QString, SqliteHandles * >&handlesRO, SqliteHandles * &handle);
private:
int ref;
sqlite3 *sqlite_handle;
static QMap < QString, SqliteHandles * >handles;
};
/**
* sqlite3 handles pointer
*/
SqliteHandles *handle;
};

View File

@ -0,0 +1,244 @@
<ui version="4.0" >
<class>QgsSpatiaLiteSourceSelectBase</class>
<widget class="QDialog" name="QgsSpatiaLiteSourceSelectBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>472</width>
<height>687</height>
</rect>
</property>
<property name="windowTitle" >
<string>Add SpatiaLite Table(s)</string>
</property>
<property name="windowIcon" >
<iconset/>
</property>
<property name="sizeGripEnabled" >
<bool>true</bool>
</property>
<property name="modal" >
<bool>true</bool>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="2" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>271</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" colspan="2" >
<widget class="QTreeView" name="mTablesTreeView" >
<property name="selectionMode" >
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2" >
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>SpatiaLite DBs</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>11</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="1" column="2" >
<widget class="QPushButton" name="btnDelete" >
<property name="text" >
<string>Delete</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QPushButton" name="btnNew" >
<property name="text" >
<string>New</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QPushButton" name="btnConnect" >
<property name="text" >
<string>Connect</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3" >
<widget class="QComboBox" name="cmbConnections" />
</item>
</layout>
</widget>
</item>
<item row="4" column="0" colspan="2" >
<layout class="QHBoxLayout" >
<property name="margin" >
<number>11</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QPushButton" name="btnHelp" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="text" >
<string>Help</string>
</property>
<property name="shortcut" >
<string>F1</string>
</property>
<property name="autoDefault" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>141</width>
<height>21</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnAdd" >
<property name="text" >
<string>Add</string>
</property>
<property name="shortcut" >
<string/>
</property>
<property name="autoDefault" >
<bool>true</bool>
</property>
<property name="default" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnCancel" >
<property name="text" >
<string>Close</string>
</property>
<property name="shortcut" >
<string/>
</property>
<property name="autoDefault" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2" >
<widget class="QGroupBox" name="mSearchGroupBox" >
<property name="title" >
<string/>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="0" >
<widget class="QLabel" name="mSearchLabel" >
<property name="text" >
<string>Search:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2" >
<widget class="QLabel" name="mSearchModeLabel" >
<property name="text" >
<string>Search mode:</string>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QComboBox" name="mSearchModeComboBox" />
</item>
<item row="1" column="0" colspan="2" >
<widget class="QLabel" name="mSearchColumnsLabel" >
<property name="text" >
<string>Search in columns:</string>
</property>
</widget>
</item>
<item row="1" column="2" >
<widget class="QComboBox" name="mSearchColumnComboBox" />
</item>
<item row="0" column="1" colspan="2" >
<widget class="QLineEdit" name="mSearchTableEdit" />
</item>
</layout>
</widget>
</item>
<item row="2" column="1" >
<widget class="QPushButton" name="mSearchOptionsButton" >
<property name="text" >
<string>Search options...</string>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11" />
<tabstops>
<tabstop>cmbConnections</tabstop>
<tabstop>btnConnect</tabstop>
<tabstop>btnNew</tabstop>
<tabstop>btnDelete</tabstop>
<tabstop>btnHelp</tabstop>
<tabstop>btnAdd</tabstop>
<tabstop>btnCancel</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>btnCancel</sender>
<signal>clicked()</signal>
<receiver>QgsSpatiaLiteSourceSelectBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>404</x>
<y>446</y>
</hint>
<hint type="destinationlabel" >
<x>229</x>
<y>236</y>
</hint>
</hints>
</connection>
</connections>
</ui>