diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index d6cd21faa586..5732df26f614 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -1,5 +1,5 @@ - -INSTALL(FILES srs.db qgis.db qgis_help.db symbology-ng-style.xml - DESTINATION ${QGIS_DATA_DIR}/resources) - -SUBDIRS(context_help) + +INSTALL(FILES srs.db qgis.db qgis_help.db symbology-ng-style.xml spatialite.db + DESTINATION ${QGIS_DATA_DIR}/resources) + +SUBDIRS(context_help) diff --git a/resources/context_help/QgsNewSpatialiteLayerDialog-en_US b/resources/context_help/QgsNewSpatialiteLayerDialog-en_US new file mode 100644 index 000000000000..f3ff4132f359 --- /dev/null +++ b/resources/context_help/QgsNewSpatialiteLayerDialog-en_US @@ -0,0 +1,20 @@ +

Create a New Spatialite Layer

+You can use this dialog to create a new Spatialite database and/or an empty Spatialite layer for editing. See below for an explanation of the dialog inputs. +

Database

+Choose the database from the drop-down list. This list is created from your saved Spatialite connections. If you don't have a saved connection or want to create a new database, click on the button () to the right of the drop-down. If you create a new database you will have to add it to your Spatialite connections in the Add Spatialite Table(s) dialog. +

Layer name

+Enter a name for the layer you want to create. The name should be one word. You can use underscores in the name if you like. +

Geometry column

+Enter a name for the geometry column or accept the default. +

Type

+Choose the type of layer you want to create. +

EPSG SRID

+Enter the EPSG number for the spatial reference id (SRID). By default the SRID for WGS 84 is filled in for you. Click on button to change the coordinate reference system of the layer if needed. The SRID must exist within the spatial_ref_sys in your Spatialite database. You can search for the SRID using partial matches on both name and SRID. +

New attribute

+Add the desired attributes by clicking on the button after you have specified a name and type for the attribute. Only real, integer, and string attributes are supported.
+Width and precision are irrelevant in a Spatialite database so you do not have to specify these. +

Attributes list

+In this section you can see the list of attributes. To delete one of them, click on it and choose button. + +

+To create the layer, click on . The layer will be created and you will be returned to the dialog. From here you can click or change the parameters to create additional layers. diff --git a/resources/spatialite.db b/resources/spatialite.db new file mode 100644 index 000000000000..50b2d39c4eae Binary files /dev/null and b/resources/spatialite.db differ diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 86384b2770c9..4d4026ce689b 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -24,6 +24,7 @@ SET(QGIS_APP_SRCS qgsdelattrdialog.cpp qgsdisplayangle.cpp qgsfieldcalculator.cpp + qgsnewspatialitelayerdialog.cpp qgsnewvectorlayerdialog.cpp qgsgraduatedsymboldialog.cpp qgshelpviewer.cpp @@ -58,6 +59,7 @@ SET(QGIS_APP_SRCS qgsnewhttpconnection.cpp qgsnumericsortlistviewitem.cpp qgsoptions.cpp + qgsspatialitesridsdialog.cpp qgspastetransformations.cpp qgspointrotationitem.cpp qgspluginitem.cpp @@ -143,6 +145,7 @@ SET (QGIS_APP_MOC_HDRS qgsfieldcalculator.h qgsformannotationdialog.h qgsmaptoolmeasureangle.h + qgsnewspatialitelayerdialog.h qgsnewvectorlayerdialog.h qgsgraduatedsymboldialog.h qgshelpviewer.h @@ -178,6 +181,7 @@ SET (QGIS_APP_MOC_HDRS qgswmssourceselect.h qgssinglesymboldialog.h qgssnappingdialog.h + qgsspatialitesridsdialog.h qgsuniquevaluedialog.h qgsvectorlayerproperties.h qgsdbtablemodel.h @@ -330,6 +334,7 @@ IF (WITH_INTERNAL_SPATIALITE) INCLUDE_DIRECTORIES(../core/spatialite/headers/spatialite) ELSE (WITH_INTERNAL_SPATIALITE) INCLUDE_DIRECTORIES(${SQLITE3_INCLUDE_DIR}) + ADD_DEFINITIONS(-DEXTERNAL_SPATIALITE) ENDIF (WITH_INTERNAL_SPATIALITE) IF (POSTGRES_FOUND) diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 98defda23570..9493e58df659 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -214,6 +214,7 @@ #endif #ifdef HAVE_SPATIALITE #include "qgsspatialitesourceselect.h" +#include "qgsnewspatialitelayerdialog.h" #endif #include "qgspythonutils.h" @@ -936,11 +937,18 @@ void QgisApp::createActions() // Layer Menu Items - mActionNewVectorLayer = new QAction( getThemeIcon( "mActionNewVectorLayer.png" ), tr( "New Vector Layer..." ), this ); - shortcuts->registerAction( mActionNewVectorLayer, tr( "Ctrl+Shift+N", "Create a New Vector Layer" ) ); - mActionNewVectorLayer->setStatusTip( tr( "Create a New Vector Layer" ) ); + mActionNewVectorLayer = new QAction( getThemeIcon( "mActionNewVectorLayer.png" ), tr( "New Vector Layer (shapefile)..." ), this ); + shortcuts->registerAction( mActionNewVectorLayer, tr( "Ctrl+Shift+N", "Create a New Vector Layer (shapefile)" ) ); + mActionNewVectorLayer->setStatusTip( tr( "Create a New Vector Layer (shapefile)" ) ); connect( mActionNewVectorLayer, SIGNAL( triggered() ), this, SLOT( newVectorLayer() ) ); +#ifdef HAVE_SPATIALITE + mActionNewSpatialiteLayer = new QAction( getThemeIcon( "mActionNewVectorLayer.png" ), tr( "New Spatialite Layer ..." ), this ); + shortcuts->registerAction( mActionNewSpatialiteLayer, tr( "Ctrl+Shift+S", "Create a New Spatialite Layer " ) ); + mActionNewSpatialiteLayer->setStatusTip( tr( "Create a New Spatialite Layer " ) ); + connect( mActionNewSpatialiteLayer, SIGNAL( triggered() ), this, SLOT( newSpatialiteLayer() ) ); +#endif + mActionAddOgrLayer = new QAction( getThemeIcon( "mActionAddOgrLayer.png" ), tr( "Add Vector Layer..." ), this ); shortcuts->registerAction( mActionAddOgrLayer, tr( "Ctrl+Shift+V", "Add a Vector Layer" ) ); mActionAddOgrLayer->setStatusTip( tr( "Add a Vector Layer" ) ); @@ -1411,7 +1419,14 @@ void QgisApp::createMenus() mLayerMenu = menuBar()->addMenu( tr( "&Layer" ) ); +#ifdef HAVE_SPATIALITE + QMenu *newLayerMenu = mLayerMenu->addMenu( tr( "New ") ); + newLayerMenu->addAction( mActionNewVectorLayer ); + newLayerMenu->addAction( mActionNewSpatialiteLayer ); +#else mLayerMenu->addAction( mActionNewVectorLayer ); +#endif + mLayerMenu->addAction( mActionAddOgrLayer ); mLayerMenu->addAction( mActionAddRasterLayer ); #ifdef HAVE_POSTGRESQL @@ -3082,6 +3097,213 @@ void QgisApp::newVectorLayer() addVectorLayers( fileNames, enc, "file" ); } +void QgisApp::newSpatialiteLayer() +{ + if ( mMapCanvas && mMapCanvas->isDrawing() ) + { + return; + } + + QgsNewSpatialiteLayerDialog spatialiteDialog( this ); + if ( spatialiteDialog.exec() == QDialog::Rejected ) + { + return; + } + + QString geometrytype = spatialiteDialog.selectedType(); + //QString fileformat = geomDialog.selectedFileFormat(); + QString crsId = spatialiteDialog.selectedCrsId(); + QString databaseName = spatialiteDialog.databaseName(); + QString newLayerName = spatialiteDialog.layerName(); + //QgsDebugMsg( QString( "New file format will be: %1" ).arg( fileformat ) ); + + // Get the list containing the name/type pairs for each attribute + QList * items = spatialiteDialog.attributes( ); + + // Build up the sql statement for creating the table + // + QString sql = QString("create table %1 (id integer primary key autoincrement").arg(newLayerName); + // iterate through the field names and add them to the create statement + // (use indexed access since this is just as fast as iterators + for ( int i = 0; i < items->size(); ++i ) + { + QStringList field = items->at(i); + sql += QString(", %1 %2").arg(field.at(0)).arg(field.at(1)); + } + // complete the create table statement + sql += ")"; + std::cout << "Creating table in database " << databaseName.toUtf8().data() << std::endl; + std::cout << sql.toUtf8().data() << std::endl; // OK + + QString sqlAddGeom = QString("select AddGeometryColumn('%1', 'geom', %2, '%3', 2)").arg(newLayerName).arg(crsId).arg(geometrytype); + std::cout << sqlAddGeom.toUtf8().data() << std::endl; // OK + QString sqlCreateIndex = QString("select CreateSpatialIndex('%1', 'geom')").arg(newLayerName); + std::cout << sqlCreateIndex.toUtf8().data() << std::endl; // OK + + sqlite3 *db; + int rc = sqlite3_open( databaseName.toUtf8(), &db ); + if ( rc != SQLITE_OK ) + { + QMessageBox::warning( this, "Spatialite Database", tr( "Unable to open the database: %1").arg(databaseName ) ); + } + else + { + char * errmsg; + rc = sqlite3_exec( db, sql.toUtf8(), NULL, NULL, &errmsg); + if ( rc != SQLITE_OK ) + { + QMessageBox::warning( this, tr( "Error deleting bookmark" ), + tr( "Failed to create the Spatialite table %1. The database returned:\n%2" ).arg( newLayerName ).arg( errmsg ) ); + sqlite3_free( errmsg ); + } + else + { + // create the geometry column and the spatial index + rc = sqlite3_exec( db, sqlAddGeom.toUtf8(), NULL, NULL, &errmsg); + if ( rc != SQLITE_OK ) + { + QMessageBox::warning( this, tr( "Error Creating Geometry Column" ), + tr( "Failed to create the geometry column. The database returned:\n%1" ).arg( errmsg ) ); + sqlite3_free( errmsg ); + } + else + { + // create the spatial index + rc = sqlite3_exec( db, sqlCreateIndex.toUtf8(), NULL, NULL, &errmsg); + if ( rc != SQLITE_OK ) + { + QMessageBox::warning( this, tr( "Error Creating Spatial Index" ), + tr( "Failed to create the spatial index. The database returned:\n%1" ).arg( errmsg ) ); + sqlite3_free( errmsg ); + } + } + } + + + } + + + /* + bool haveLastUsedFilter = false; // by default, there is no last + // used filter + QString enc; + QString fileName; + + QSettings settings; // where we keep last used filter in + // persistent state + + haveLastUsedFilter = settings.contains( "/UI/lastVectorFileFilter" ); + QString lastUsedFilter = settings.value( "/UI/lastVectorFileFilter", + QVariant( QString::null ) ).toString(); + + QString lastUsedDir = settings.value( "/UI/lastVectorFileFilterDir", + "." ).toString(); + + QgsDebugMsg( "Saving vector file dialog without filters: " ); + + QgsEncodingFileDialog* openFileDialog = new QgsEncodingFileDialog( this, + tr( "Save As" ), lastUsedDir, "", QString( "" ) ); + + // allow for selection of more than one file + openFileDialog->setFileMode( QFileDialog::AnyFile ); + openFileDialog->setAcceptMode( QFileDialog::AcceptSave ); + openFileDialog->setConfirmOverwrite( true ); + + if ( haveLastUsedFilter ) // set the filter to the last one used + { + openFileDialog->selectFilter( lastUsedFilter ); + } + + int res; + while (( res = openFileDialog->exec() ) == QDialog::Accepted ) + { + fileName = openFileDialog->selectedFiles().first(); + + if ( fileformat == "ESRI Shapefile" ) + { + if ( !isValidShapeFileName( fileName ) ) + { + fileName += ".shp"; + } + + if ( !isValidShapeFileName( fileName ) ) + { + QMessageBox::information( this, + tr( "New Shapefile" ), + tr( "Shapefiles must end on .shp" ) ); + continue; + } + } + + break; + } + + if ( res == QDialog::Rejected ) + { + delete openFileDialog; + return; + } + + enc = openFileDialog->encoding(); + + // If the file exists, delete it otherwise we'll end up loading that + // file, which can cause problems (e.g., if the file contains + // linestrings, but we're wanting to create points, we'll end up + // with a linestring file). + if ( fileformat == "ESRI Shapefile" ) + { + QgsVectorFileWriter::deleteShapeFile( fileName ); + } + else + { + QFile::remove( fileName ); + } + + settings.setValue( "/UI/lastVectorFileFilter", openFileDialog->selectedFilter() ); + + settings.setValue( "/UI/lastVectorFileFilterDir", openFileDialog->directory().absolutePath() ); + + delete openFileDialog; + + //try to create the new layer with OGRProvider instead of QgsVectorFileWriter + QgsProviderRegistry * pReg = QgsProviderRegistry::instance(); + QString ogrlib = pReg->library( "ogr" ); + // load the data provider + QLibrary* myLib = new QLibrary( ogrlib ); + bool loaded = myLib->load(); + if ( loaded ) + { + QgsDebugMsg( "ogr provider loaded" ); + + typedef bool ( *createEmptyDataSourceProc )( const QString&, const QString&, const QString&, QGis::WkbType, + const std::list >&, const QgsCoordinateReferenceSystem * ); + createEmptyDataSourceProc createEmptyDataSource = ( createEmptyDataSourceProc ) cast_to_fptr( myLib->resolve( "createEmptyDataSource" ) ); + if ( createEmptyDataSource ) + { + if ( geometrytype != QGis::WKBUnknown ) + { + QgsCoordinateReferenceSystem srs( crsId, QgsCoordinateReferenceSystem::InternalCrsId ); + createEmptyDataSource( fileName, fileformat, enc, geometrytype, attributes, &srs ); + } + else + { + QgsDebugMsg( "geometry type not recognised" ); + return; + } + } + else + { + QgsDebugMsg( "Resolving newEmptyDataSource(...) failed" ); + } + } + + //then add the layer to the view + QStringList fileNames; + fileNames.append( fileName ); + //todo: the last parameter will change accordingly to layer type + addVectorLayers( fileNames, enc, "file" ); + */ +} void QgisApp::fileOpen() { if ( mMapCanvas && mMapCanvas->isDrawing() ) diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index 5bff76bf4051..44cce9b5c27c 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -265,6 +265,7 @@ class QgisApp : public QMainWindow QAction *actionViewSeparator3() { return mActionViewSeparator3; } QAction *actionNewVectorLayer() { return mActionNewVectorLayer; } + QAction *actionNewSpatialLiteLayer() { return mActionNewSpatialiteLayer; } QAction *actionAddOgrLayer() { return mActionAddOgrLayer; } QAction *actionAddRasterLayer() { return mActionAddRasterLayer; } QAction *actionAddPgLayer() { return mActionAddPgLayer; } @@ -488,6 +489,8 @@ class QgisApp : public QMainWindow void fileNew( bool thePromptToSaveFlag ); //! Create a new empty vector layer void newVectorLayer(); + //! Create a new empty spatialite layer + void newSpatialiteLayer(); //! Print the current map view frame void newPrintComposer(); void showComposerManager(); @@ -859,6 +862,7 @@ class QgisApp : public QMainWindow QAction *mActionAnnotation; QAction *mActionNewVectorLayer; + QAction *mActionNewSpatialiteLayer; QAction *mActionAddOgrLayer; QAction *mActionAddRasterLayer; QAction *mActionAddPgLayer; diff --git a/src/app/qgsnewspatialitelayerdialog.cpp b/src/app/qgsnewspatialitelayerdialog.cpp new file mode 100644 index 000000000000..b0ee8885a74a --- /dev/null +++ b/src/app/qgsnewspatialitelayerdialog.cpp @@ -0,0 +1,320 @@ +/*************************************************************************** + qgsnewspatialitelayerdialog.cpp + Creates a new Spatialite layer. This dialog borrows heavily from + qgsnewvectorlayerdialog.cpp + ------------------- + begin : 2010-03-18 + copyright : (C) 2010 by Gary Sherman + email : gsherman@mrcc.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. * + * * + ***************************************************************************/ +/* $Id$ */ + +/* +extern "C" +{ +#include +#include +#include +} +*/ +#include "qgsnewspatialitelayerdialog.h" +#include "qgsspatialitesridsdialog.h" +#include "qgsapplication.h" +#include "qgisapp.h" // <- for theme icons +#include "qgslogger.h" +//#include +#include +#include +#include +#include +#include + + + +QgsNewSpatialiteLayerDialog::QgsNewSpatialiteLayerDialog( QWidget *parent, Qt::WFlags fl ) + : QDialog( parent, fl ) +{ + setupUi( this ); + mAddAttributeButton->setIcon( QgisApp::getThemeIcon( "/mActionNewAttribute.png" ) ); + mRemoveAttributeButton->setIcon( QgisApp::getThemeIcon( "/mActionDeleteAttribute.png" ) ); + mTypeBox->addItem( tr( "Text data" ), "text" ); + mTypeBox->addItem( tr( "Whole number" ), "integer" ); + mTypeBox->addItem( tr( "Decimal number" ), "real" ); + + mPointRadioButton->setChecked( true ); + // Populate the database list from the stored connections + QSettings settings; + settings.beginGroup( "/SpatiaLite/connections" ); + QStringList keys = settings.childGroups(); + QStringList::Iterator it = keys.begin(); + mDatabaseComboBox->clear(); + while ( it != keys.end() ) + { + // retrieving the SQLite DB name and full path + //QString text = *it + tr( "@" ); + QString text = settings.value( *it + "/sqlitepath", "###unknown###" ).toString(); + mDatabaseComboBox->addItem( text ); + ++it; + } + settings.endGroup(); + mApplyButton = buttonBox->button( QDialogButtonBox::Apply ); + mApplyButton->setEnabled( false ); + mApplyButton->setDefault( true ); + connect( buttonBox->button( QDialogButtonBox::Apply ), SIGNAL( clicked() ), this, SLOT( apply() ) ); + + // Set the SRID box to a default of WGS84 + leSRID->setText( "4326" ); + + // flag to indicate if we need to create a new db before adding a layer + needNewDb = false; +} + +QgsNewSpatialiteLayerDialog::~QgsNewSpatialiteLayerDialog() +{ +} + +void QgsNewSpatialiteLayerDialog::createNewDb() +{ +// QMessageBox::information( 0, tr( "Spatialite Layer" ), tr( "Create new db clicked" ) ); + QString fileName = QFileDialog::getSaveFileName(this, tr("New Spatialite Database File"), + ".", + tr("Spatialite (*.sqlite *.db )")); + + if ( !fileName.isEmpty() ) + { + mDatabaseComboBox->insertItem( 0, fileName ); + mDatabaseComboBox->setCurrentIndex(0); + needNewDb = true; + } +} +void QgsNewSpatialiteLayerDialog::on_mTypeBox_currentIndexChanged( int index ) +{ + // This isn't used since widths are irrelevant in sqlite3 + switch ( index ) + { + case 0: // Text data + case 1: // Whole number + case 2: // Decimal number + default: + break; + } +} + +QString QgsNewSpatialiteLayerDialog::selectedType() const +{ + if ( mPointRadioButton->isChecked() ) + { + return "POINT"; + } + else if ( mLineRadioButton->isChecked() ) + { + return "LINESTRING"; + } + else if ( mPolygonRadioButton->isChecked() ) + { + return "POLYGON"; + } + else if ( mMultipointRadioButton->isChecked() ) + { + return "MULTIPOINT"; + } + else if ( mMultilineRadioButton->isChecked() ) + { + return "MULTILINESTRING"; + } + else if ( mMultipolygonRadioButton->isChecked() ) + { + return "MULTIPOLYGON"; + } +} + +QString QgsNewSpatialiteLayerDialog::selectedCrsId() const +{ + return leSRID->text(); +} + +void QgsNewSpatialiteLayerDialog::apply() +{ + // Check to see if the db exists and if not create it + createDb(); + + // Init spatialite + spatialite_init( 0 ); + QString newLayerName = leLayerName->text(); + int rc = sqlite3_open_v2( mDatabaseComboBox->currentText().toUtf8(), &db, SQLITE_OPEN_READWRITE, NULL ); + if ( rc != SQLITE_OK ) + { + QMessageBox::warning( this, "Spatialite Database", tr( "Unable to open the database")); + } + else + { + char * errmsg; + QString sql = QString("CREATE TABLE %1 (id integer primary key autoincrement, name text)").arg( newLayerName ); + rc = sqlite3_exec( db, sql.toUtf8(), NULL, NULL, &errmsg); + if ( rc != SQLITE_OK ) + { + QMessageBox::warning( this, tr( "Error Creating Table" ), + tr( "Failed to create the Spatialite table. The database returned:\n%1" ).arg( errmsg ) ); + sqlite3_free( errmsg ); + } + else + { + // get the geometry type + QString geomType = selectedType(); + // create the geometry column and the spatial index + sql = QString("select AddGeometryColumn('%1', 'geom', %2, '%3', 2)").arg( newLayerName ).arg( leSRID->text() ).arg( geomType ); + rc = sqlite3_exec( db, sql.toUtf8(), NULL, NULL, &errmsg); + if ( rc != SQLITE_OK ) + { + QMessageBox::warning( this, tr( "Error Creating Geometry Column" ), + tr( "Failed to create the geometry column. The database returned:\n%1" ).arg( errmsg ) ); + sqlite3_free( errmsg ); + } + else + { + // create the spatial index + sql = QString("select CreateSpatialIndex('%1', 'geom')").arg( newLayerName ); + rc = sqlite3_exec( db, sql.toUtf8(), NULL, NULL, &errmsg); + if ( rc != SQLITE_OK ) + { + QMessageBox::warning( this, tr( "Error Creating Spatial Index" ), + tr( "Failed to create the spatial index. The database returned:\n%1" ).arg( errmsg ) ); + sqlite3_free( errmsg ); + } + else + { + QMessageBox::information( 0, tr( "Spatialite Layer" ), tr( "Layer created" ) ); + } + } + } + } +} +void QgsNewSpatialiteLayerDialog::on_leLayerName_textChanged( QString text ) +{ + if ( leLayerName->text().length() > 0 && mAttributeView->topLevelItemCount() > 0) + { + mApplyButton->setEnabled( true ); + } +} + +void QgsNewSpatialiteLayerDialog::on_mAddAttributeButton_clicked() +{ + if ( mNameEdit->text().length() > 0 ) + { + QString myName = mNameEdit->text(); + //use userrole to avoid translated type string + QString myType = mTypeBox->itemData( mTypeBox->currentIndex(), Qt::UserRole ).toString(); + mAttributeView->addTopLevelItem( new QTreeWidgetItem( QStringList() << myName << myType ) ); + if ( mAttributeView->topLevelItemCount() > 0 && leLayerName->text().length() > 0 ) + { + mApplyButton->setEnabled( true ); + } + mNameEdit->clear(); + } +} + +void QgsNewSpatialiteLayerDialog::on_mRemoveAttributeButton_clicked() +{ + delete mAttributeView->currentItem(); + if ( mAttributeView->topLevelItemCount() == 0 ) + { + mApplyButton->setEnabled( false ); + } +} + +void QgsNewSpatialiteLayerDialog::on_pbnFindSRID_clicked() +{ + /* hold on to this for a bit + int rc = sqlite3_open( mDatabaseComboBox->currentText().toUtf8().data(), &db ); + if ( rc != SQLITE_OK ) + { + QMessageBox::warning( this, "Spatialite Database", tr( "Unable to open the database: %1").arg(mDatabaseComboBox->currentText() ) ); + } + */ + // set the SRID from a list returned from the selected Spatialite database + QgsSpatialiteSridsDialog *sridDlg = new QgsSpatialiteSridsDialog(this); + if ( sridDlg->load( mDatabaseComboBox->currentText() ) ) + { + if ( sridDlg->exec() ) + { + // set the srid field to the selection + sridDlg->selectedSrid(); + leSRID->setText( sridDlg->selectedSrid() ); + sridDlg->accept(); + } + } +} + +// Create a QList of QStringList objects that define the layer attributes. +// Each QStringList contains the field name and its type. +QList * QgsNewSpatialiteLayerDialog::attributes() const +{ + QTreeWidgetItemIterator it( mAttributeView ); + QList *list = new QList; + while ( *it ) + { + QTreeWidgetItem *item = *it; + QStringList items; + items << item->text( 0 ); + items << item->text( 1 ); + list->append(items); + + //QString type = QString( "%1;%2;%3" ).arg( item->text( 1 ) ).arg( item->text( 2 ) ).arg( item->text( 3 ) ); + //at.push_back( std::make_pair( item->text( 0 ), type ) ); + //QgsDebugMsg( QString( "appending %1//%2" ).arg( item->text( 0 ) ).arg( type ) ); + ++it; + } + return list; +} + +QString QgsNewSpatialiteLayerDialog::databaseName() const +{ + return mDatabaseComboBox->currentText(); +} + +QString QgsNewSpatialiteLayerDialog::layerName() const +{ + return leLayerName->text(); +} +bool QgsNewSpatialiteLayerDialog::createDb() +{ + QFile newDb( mDatabaseComboBox->currentText() ); + if ( !newDb.exists() ) + { + qWarning( "creating a new db" ); + // copy the spatilite template to the user specified path + QString spatialiteTemplate = QgsApplication::qgisSpatialiteDbTemplatePath(); + QFile spatialiteTemplateDb( spatialiteTemplate ); + + QFileInfo fullPath = QFileInfo( mDatabaseComboBox->currentText() ); + QDir path = fullPath.dir(); + qWarning("making this dir: %s", path.absolutePath().toUtf8().data()); + + + // Must be sure there is destination directory ~/.qgis + QDir().mkpath( path.absolutePath( ) ); + + qWarning("Copying %s ", spatialiteTemplate.toUtf8().data()); + qWarning("to %s", newDb.fileName().toUtf8().data()); + + //now copy the template db file into the chosen location + bool isDbFileCopied = spatialiteTemplateDb.copy( newDb.fileName() ); + + if ( !isDbFileCopied ) + { + // QMessageBox::warning( this, "Spatialite Database", tr( "Unable to copy the template database to your new location" )); + return false; + } + } + return true; +} + diff --git a/src/app/qgsnewspatialitelayerdialog.h b/src/app/qgsnewspatialitelayerdialog.h new file mode 100644 index 000000000000..0211b2081af4 --- /dev/null +++ b/src/app/qgsnewspatialitelayerdialog.h @@ -0,0 +1,70 @@ +/*************************************************************************** + QgsNewSpatialiteLayerDialog.h - description + ------------------- + begin : 2010-03-19 + copyright : (C) 2010 by Gary Sherman + email : gsherman@mrcc.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. * + * * + ***************************************************************************/ +/* $Id$ */ +#ifndef qgsnewspatialitelayerdialog_H +#define qgsnewspatialitelayerdialog_H +#include +extern "C" +{ +#include +} +//#include +#include "ui_qgsnewspatialitelayerdialogbase.h" +#include "qgisgui.h" +#include "qgscontexthelp.h" + +#include "qgis.h" + +class QgsNewSpatialiteLayerDialog: public QDialog, private Ui::QgsNewSpatialiteLayerDialogBase +{ + Q_OBJECT + + public: + QgsNewSpatialiteLayerDialog( QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags ); + ~QgsNewSpatialiteLayerDialog(); + /**Returns the selected geometry type*/ + QString selectedType() const; + /**Appends the chosen attribute names and types to at*/ + //void attributes( std::list >& at ) const; + QList * attributes() const; + /**Returns the database name */ + QString databaseName() const; + /**Returns the layer name to be created */ + QString layerName() const; + /**Returns the selected crs id*/ + QString selectedCrsId() const; + /** Create a new database */ + bool createDb(); + + protected slots: + void on_mAddAttributeButton_clicked(); + void on_mRemoveAttributeButton_clicked(); + void on_mTypeBox_currentIndexChanged( int index ); + void on_pbnFindSRID_clicked(); + void on_leLayerName_textChanged( QString text ); + void createNewDb(); + void apply(); + void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); } + + private: + QPushButton *mApplyButton; + int mCrsId; + sqlite3 *db; + bool needNewDb; +}; + +#endif //qgsnewvectorlayerdialog_H diff --git a/src/app/qgsspatialitesridsdialog.cpp b/src/app/qgsspatialitesridsdialog.cpp new file mode 100644 index 000000000000..85063def8f6e --- /dev/null +++ b/src/app/qgsspatialitesridsdialog.cpp @@ -0,0 +1,119 @@ +#include +#include "qgsspatialitesridsdialog.h" +QgsSpatialiteSridsDialog::QgsSpatialiteSridsDialog( QWidget *parent, Qt::WFlags fl ) + : QDialog( parent, fl ) +{ + setupUi( this ); + db = 0; + pbnFilter->setDefault( true ); + leSearch->setFocus(); +} + +QgsSpatialiteSridsDialog::~QgsSpatialiteSridsDialog() +{ + sqlite3_close( db ); +} +QString QgsSpatialiteSridsDialog::selectedSrid() +{ + return twSrids->currentItem()->text(0); +} +bool QgsSpatialiteSridsDialog::load(QString dbName) +{ + mDbName = dbName; + bool status = true; + if ( !db ) + { + int rc = sqlite3_open_v2( dbName.toUtf8(), &db, SQLITE_OPEN_READONLY, NULL ); + if ( rc != SQLITE_OK ) + { + QMessageBox::warning( this, "Spatialite Database", tr( "Unable to open the database")); + return false; + } + } + // load up the srid table + // prepare the sql statement + const char *pzTail; + sqlite3_stmt *ppStmt; + QString sql = "select auth_srid, auth_name, ref_sys_name from spatial_ref_sys order by srid asc"; + + int rc = sqlite3_prepare( db, sql.toUtf8(), sql.toUtf8().length(), &ppStmt, &pzTail ); + // XXX Need to free memory from the error msg if one is set + if ( rc == SQLITE_OK ) + { + // get the first row of the result set + while ( sqlite3_step( ppStmt ) == SQLITE_ROW ) + { + QTreeWidgetItem *item = new QTreeWidgetItem( twSrids ); + // srid + item->setText (0, QString::fromUtf8(( const char * )sqlite3_column_text( ppStmt, 0 ) ) ); + item->setText (1, QString::fromUtf8(( const char * )sqlite3_column_text( ppStmt, 1 ) ) ); + // name + item->setText( 2, QString::fromUtf8(( const char * )sqlite3_column_text( ppStmt, 2 ) ) ); + // proj4 text + item->setText( 3, QString::fromUtf8(( const char * )sqlite3_column_text( ppStmt, 3 ) ) ); + + } + twSrids->sortByColumn( 0, Qt::AscendingOrder ); + } + else + { + // XXX query failed -- warn the user some how + QMessageBox::warning(0, "Error", QString( "Failed to load SRIDS: %1" ).arg( sqlite3_errmsg( db ) ) ); + status = false; + } + // close the statement + sqlite3_finalize( ppStmt ); + return status; +} +void QgsSpatialiteSridsDialog::on_pbnFilter_clicked() +{ + if ( leSearch->text().length() == 0 ) + { + load( mDbName ); + } + else + { + const char *pzTail; + sqlite3_stmt *ppStmt; + QString search; + if ( radioButtonSrid->isChecked() ) + { + search = "srid"; + } + else + { + search = "ref_sys_name"; + } + QString sql = QString("select auth_srid, auth_name, ref_sys_name from spatial_ref_sys where %1 like '%").arg(search) + leSearch->text() + QString("%' order by srid asc"); + //QMessageBox::information(0, "Sql", sql); + + int rc = sqlite3_prepare( db, sql.toUtf8(), sql.toUtf8().length(), &ppStmt, &pzTail ); + // XXX Need to free memory from the error msg if one is set + if ( rc == SQLITE_OK ) + { + // clear the display + twSrids->clear(); + // get the first row of the result set + while ( sqlite3_step( ppStmt ) == SQLITE_ROW ) + { + QTreeWidgetItem *item = new QTreeWidgetItem( twSrids ); + // srid + item->setText (0, QString::fromUtf8(( const char * )sqlite3_column_text( ppStmt, 0 ) ) ); + item->setText (1, QString::fromUtf8(( const char * )sqlite3_column_text( ppStmt, 1 ) ) ); + // name + item->setText( 2, QString::fromUtf8(( const char * )sqlite3_column_text( ppStmt, 2 ) ) ); + // proj4 text + item->setText( 3, QString::fromUtf8(( const char * )sqlite3_column_text( ppStmt, 3 ) ) ); + + } + twSrids->sortByColumn( 0, Qt::AscendingOrder ); + } + else + { + // XXX query failed -- warn the user some how + QMessageBox::warning(0, "Error", QString( "Failed to load SRIDS: %1" ).arg( sqlite3_errmsg( db ) ) ); + } + // close the statement + sqlite3_finalize( ppStmt ); + } +} diff --git a/src/app/qgsspatialitesridsdialog.h b/src/app/qgsspatialitesridsdialog.h new file mode 100644 index 000000000000..5d457e720169 --- /dev/null +++ b/src/app/qgsspatialitesridsdialog.h @@ -0,0 +1,42 @@ +/*************************************************************************** + QgsSpatialiteSridsDialog.h - Dialog for selecting an + SRID from a Spatialite spatial_ref_sys table + ------------------- + begin : 2010-04-03 + copyright : (C) 2010 by Gary Sherman + email : gsherman@geoapt.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. * + * * + ***************************************************************************/ +/* $Id$ */ +#ifndef QgsSpatialiteSridsDialog_H +#define QgsSpatialiteSridsDialog_H +#include "ui_qgsspatialitesridsdialogbase.h" +#include "qgisgui.h" +#include "qgscontexthelp.h" + +#include "qgis.h" +#include + +class QgsSpatialiteSridsDialog: public QDialog, private Ui::QgsSpatialiteSridsDialogBase +{ + Q_OBJECT +public: + QgsSpatialiteSridsDialog( QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags); + ~QgsSpatialiteSridsDialog(); + bool load(QString dbName); + QString selectedSrid(); +public slots: + void on_pbnFilter_clicked(); +private: + sqlite3 *db; + QString mDbName; +}; +#endif //QgsSpatialiteSridsDialog_H diff --git a/src/core/qgsapplication.cpp b/src/core/qgsapplication.cpp index cdcef08f0da7..3d9149ef66a6 100644 --- a/src/core/qgsapplication.cpp +++ b/src/core/qgsapplication.cpp @@ -269,6 +269,14 @@ const QString QgsApplication::qgisMasterDbFilePath() return mPkgDataPath + QString( "/resources/qgis.db" ); } +/*! + Returns the path to the spatialite template db file. +*/ +const QString QgsApplication::qgisSpatialiteDbTemplatePath() +{ + return mPkgDataPath + QString( "/resources/spatialite.db" ); +} + /*! Returns the path to the settings directory in user's home dir */ diff --git a/src/core/qgsapplication.h b/src/core/qgsapplication.h index b537dc285db6..4eec4cc872e7 100644 --- a/src/core/qgsapplication.h +++ b/src/core/qgsapplication.h @@ -89,6 +89,9 @@ class CORE_EXPORT QgsApplication: public QApplication //! Returns the path to the master qgis.db file. static const QString qgisMasterDbFilePath(); + //! Returns the path to the spatialite template db file. + static const QString qgisSpatialiteDbTemplatePath(); + //! Returns the path to the settings directory in user's home dir static const QString qgisSettingsDirPath(); diff --git a/src/ui/qgsnewspatialitelayerdialogbase.ui b/src/ui/qgsnewspatialitelayerdialogbase.ui new file mode 100644 index 000000000000..451b4919f8e6 --- /dev/null +++ b/src/ui/qgsnewspatialitelayerdialogbase.ui @@ -0,0 +1,478 @@ + + + QgsNewSpatialiteLayerDialogBase + + + + 0 + 0 + 411 + 593 + + + + + 0 + 0 + + + + + 351 + 0 + + + + + 16777215 + 16777215 + + + + New Spatialite Layer + + + true + + + + + + + + true + + + Database + + + mDatabaseComboBox + + + + + + + true + + + + 0 + 0 + + + + + + + + Create a new Spatialite database + + + ... + + + + + + + + + + + Layer name + + + + + + + + 0 + 0 + + + + Name for the new layer + + + + + + + + + + + Geometry column + + + + + + + + 0 + 0 + + + + Name for the new layer + + + geometry + + + + + + + + + + 0 + 0 + + + + Type + + + + + + Point + + + + + + + Line + + + + + + + Polygon + + + + + + + MultiPoint + + + + + + + Multiline + + + + + + + Multipolygon + + + + + + + + + + + + EPSG SRID + + + leSRID + + + + + + + Spatial Reference Id + + + true + + + + + + + + 0 + 0 + + + + Specify the coordinate reference system of the layer's geometry. + + + Specify the coordinate reference system of the layer's geometry. + + + Find SRID + + + + + + + + + New attribute + + + + + + + 0 + 0 + + + + Name + + + mNameEdit + + + + + + + An attribute name + + + + + + + + 0 + 0 + + + + Type + + + mTypeBox + + + + + + + + 0 + 0 + + + + + + + + + + + Attributes list + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Add attribute to list + + + Qt::LeftToRight + + + Add to attributes list + + + + ../../images/themes/default/mActionNewAttribute.png../../images/themes/default/mActionNewAttribute.png + + + Qt::ToolButtonTextBesideIcon + + + + + + + + 0 + 0 + + + + true + + + false + + + 2 + + + + Name + + + + + Type + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Delete selected attribute + + + Remove selected attribute + + + + ../../images/themes/default/mActionDeleteAttribute.png../../images/themes/default/mActionDeleteAttribute.png + + + Qt::ToolButtonTextBesideIcon + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Apply|QDialogButtonBox::Close|QDialogButtonBox::Help + + + + + + + + mDatabaseComboBox + mPointRadioButton + mLineRadioButton + mPolygonRadioButton + mNameEdit + mTypeBox + mAttributeView + mRemoveAttributeButton + buttonBox + + + + + buttonBox + accepted() + QgsNewSpatialiteLayerDialogBase + accept() + + + 355 + 568 + + + 387 + 304 + + + + + buttonBox + rejected() + QgsNewSpatialiteLayerDialogBase + reject() + + + 281 + 568 + + + 242 + 308 + + + + + toolButtonNewDatabase + clicked() + QgsNewSpatialiteLayerDialogBase + createNewDb() + + + 403 + 28 + + + 52 + 39 + + + + + + createNewDb() + + diff --git a/src/ui/qgsspatialitesridsdialogbase.ui b/src/ui/qgsspatialitesridsdialogbase.ui new file mode 100644 index 000000000000..0d94238937fa --- /dev/null +++ b/src/ui/qgsspatialitesridsdialogbase.ui @@ -0,0 +1,150 @@ + + + QgsSpatialiteSridsDialogBase + + + + 0 + 0 + 601 + 332 + + + + Select a Spatialite Spatial Reference System + + + + + + false + + + true + + + 3 + + + + SRID + + + + + Authority + + + + + Reference Name + + + + + + + + + + Search + + + + + + + + + + Filter + + + + + + + + + + 160 + 26 + + + + true + + + + + + SRID + + + false + + + + + + + Name + + + true + + + + + + + + + + QDialogButtonBox::Close|QDialogButtonBox::Ok + + + + + + + + twSrids + buttonBox + + + + + buttonBox + rejected() + QgsSpatialiteSridsDialogBase + reject() + + + 217 + 327 + + + 274 + 256 + + + + + buttonBox + clicked(QAbstractButton*) + QgsSpatialiteSridsDialogBase + accept() + + + 378 + 308 + + + 452 + 295 + + + + +