7 changes: 6 additions & 1 deletion python/plugins/db_manager/db_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,13 @@ def importActionSlot(self):
QMessageBox.information(self, "Sorry", "No database selected or you are not connected to it.")
return

outUri = db.uri()
schema = self.tree.currentSchema()
if schema:
outUri.setDataSource( schema.name, "", "", "" )

from .dlg_import_vector import DlgImportVector
dlg = DlgImportVector(None, db, db.uri(), self)
dlg = DlgImportVector(None, db, outUri, self)
dlg.exec_()

def exportActionSlot(self):
Expand Down
45 changes: 28 additions & 17 deletions python/plugins/db_manager/dlg_import_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,26 +44,27 @@ def __init__(self, inLayer, outDb, outUri, parent=None):
self.default_pk = "id"
self.default_geom = "geom"

# updates of UI
self.setupWorkingMode()
self.mode = self.ASK_FOR_INPUT_MODE if self.inLayer is None else self.HAS_INPUT_MODE

self.cboTable.setEditText(self.outUri.table())

self.populateLayers()
# updates of UI
self.setupWorkingMode( self.mode )

self.connect(self.cboSchema, SIGNAL("currentIndexChanged(int)"), self.populateTables)
self.populateSchemas()
self.populateTables()

self.populateLayers()
self.populateEncodings()


def setupWorkingMode(self):
""" display the widget to select a layer/file if there's no input layer """
self.mode = self.ASK_FOR_INPUT_MODE if self.inLayer is None else self.HAS_INPUT_MODE
self.wdgInput.setVisible( self.mode == self.ASK_FOR_INPUT_MODE )
def setupWorkingMode(self, mode):
""" hide the widget to select a layer/file if the input layer
is already set """
self.wdgInput.setVisible( mode == self.ASK_FOR_INPUT_MODE )
self.resize( 200, 200 )

self.cboTable.setEditText(self.outUri.table())

if not self.inLayer:
if mode == self.ASK_FOR_INPUT_MODE:
QObject.connect( self.btnChooseInputFile, SIGNAL("clicked()"), self.chooseInputFile )
#QObject.connect( self.cboInputLayer.lineEdit(), SIGNAL("editingFinished()"), self.updateInputLayer )
QObject.connect( self.cboInputLayer, SIGNAL("editTextChanged(const QString &)"), self.inputPathChanged )
Expand All @@ -88,10 +89,11 @@ def checkSupports(self):
""" update options available for the current input layer """
allowSpatial = self.db.connector.hasSpatialSupport()
hasGeomType = self.inLayer and self.inLayer.hasGeometryType()
isShapefile = self.inLayer and self.inLayer.providerType() == "ogr" and self.inLayer.storageType() == "ESRI Shapefile"
self.chkGeomColumn.setEnabled(allowSpatial and hasGeomType)
self.chkSourceSrid.setEnabled(allowSpatial and hasGeomType)
self.chkTargetSrid.setEnabled(allowSpatial and hasGeomType)
#self.chkSinglePart.setEnabled(allowSpatial and hasGeomType)
self.chkSinglePart.setEnabled(allowSpatial and hasGeomType and isShapefile)
self.chkSpatialIndex.setEnabled(allowSpatial and hasGeomType)


Expand All @@ -113,7 +115,7 @@ def deleteInputLayer(self):
return False

def chooseInputFile(self):
vectorFormats = qgis.core.QgsVectorFileWriter.fileFilterString()
vectorFormats = qgis.core.QgsProviderRegistry.instance().fileVectorFilters()
# get last used dir and format
settings = QSettings()
lastDir = settings.value("/db_manager/lastUsedDir", "").toString()
Expand Down Expand Up @@ -215,12 +217,19 @@ def populateEncodings(self):
self.cboEncoding.setCurrentIndex(2)

def accept(self):
if self.mode == self.ASK_FOR_INPUT_MODE:
# create the input layer (if not already done) and
# update available options w/o changing the tablename!
self.cboTable.blockSignals(True)
table = self.cboTable.currentText()
self.updateInputLayer()
self.cboTable.setEditText(table)
self.cboTable.blockSignals(False)

# sanity checks
if self.inLayer is None:
# create the input layer and update available options
if not self.updateInputLayer():
QMessageBox.information(self, "Import to database", "Input layer missing or not valid")
return
QMessageBox.information(self, "Import to database", "Input layer missing or not valid")
return

if self.cboTable.currentText() == "":
QMessageBox.information(self, "Import to database", "Output table name is required")
Expand Down Expand Up @@ -269,6 +278,8 @@ def accept(self):
options['overwrite'] = True
elif self.radAppend.isChecked():
options['append'] = True
if self.chkSinglePart.isEnabled() and self.chkSinglePart.isChecked():
options['forceSinglePartGeometryType'] = True

outCrs = None
if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked():
Expand Down
9 changes: 0 additions & 9 deletions python/plugins/db_manager/ui/DlgImportVector.ui
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,6 @@
<zorder>label_2</zorder>
<zorder>cboSchema</zorder>
<zorder>label_3</zorder>
<zorder>widget_3</zorder>
<zorder>cboTable</zorder>
<zorder>label_2</zorder>
<zorder>cboSchema</zorder>
<zorder>label_3</zorder>
</widget>
</item>
<item>
Expand Down Expand Up @@ -302,9 +297,6 @@
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="chkSinglePart">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Create single-part geometries instead of multi-part</string>
</property>
Expand Down Expand Up @@ -334,7 +326,6 @@
<zorder>groupBox</zorder>
<zorder>groupBox_2</zorder>
<zorder>buttonBox</zorder>
<zorder>widget</zorder>
<zorder>groupBox_3</zorder>
<zorder>wdgInput</zorder>
</widget>
Expand Down
62 changes: 34 additions & 28 deletions src/core/qgsvectorlayerimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,15 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
outputCRS = &layer->crs();
}


bool overwrite = false;
bool forceSinglePartGeom = false;
if ( options )
{
overwrite = options->take( "overwrite" ).toBool();
forceSinglePartGeom = options->take( "forceSinglePartGeometryType" ).toBool();
}

QgsFieldMap fields = skipAttributeCreation ? QgsFieldMap() : layer->pendingFields();
QGis::WkbType wkbType = layer->wkbType();

Expand All @@ -216,38 +225,35 @@ QgsVectorLayerImport::importLayer( QgsVectorLayer* layer,
fldIt.value().setName( fldIt.value().name().toLower() );
}

// convert wkbtype to multipart (see #5547)
switch ( wkbType )
if ( !forceSinglePartGeom )
{
case QGis::WKBPoint:
wkbType = QGis::WKBMultiPoint;
break;
case QGis::WKBLineString:
wkbType = QGis::WKBMultiLineString;
break;
case QGis::WKBPolygon:
wkbType = QGis::WKBMultiPolygon;
break;
case QGis::WKBPoint25D:
wkbType = QGis::WKBMultiPoint25D;
break;
case QGis::WKBLineString25D:
wkbType = QGis::WKBMultiLineString25D;
break;
case QGis::WKBPolygon25D:
wkbType = QGis::WKBMultiPolygon25D;
break;
default:
break;
// convert wkbtype to multipart (see #5547)
switch ( wkbType )
{
case QGis::WKBPoint:
wkbType = QGis::WKBMultiPoint;
break;
case QGis::WKBLineString:
wkbType = QGis::WKBMultiLineString;
break;
case QGis::WKBPolygon:
wkbType = QGis::WKBMultiPolygon;
break;
case QGis::WKBPoint25D:
wkbType = QGis::WKBMultiPoint25D;
break;
case QGis::WKBLineString25D:
wkbType = QGis::WKBMultiLineString25D;
break;
case QGis::WKBPolygon25D:
wkbType = QGis::WKBMultiPolygon25D;
break;
default:
break;
}
}
}

bool overwrite = false;
if ( options )
{
overwrite = options->take( "overwrite" ).toBool();
}

QgsVectorLayerImport * writer =
new QgsVectorLayerImport( uri, providerKey, fields, wkbType, outputCRS, overwrite, options );

Expand Down
96 changes: 95 additions & 1 deletion src/providers/spatialite/qgsspatialiteprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ QgsSpatiaLiteProvider::createEmptyLayer(
QgsSpatiaLiteProvider::QgsSpatiaLiteProvider( QString const &uri )
: QgsVectorDataProvider( uri )
, geomType( QGis::WKBUnknown )
, mGotSpatialiteVersion( false )
, sqliteHandle( NULL )
, sqliteStatement( NULL )
, mSrid( -1 )
Expand Down Expand Up @@ -557,6 +558,10 @@ QgsSpatiaLiteProvider::QgsSpatiaLiteProvider( QString const &uri )
QgsDebugMsg( "Invalid SpatiaLite layer" );
return;
}

// retrieve version information
spatialiteVersion();

//fill type names into sets
mNativeTypes
<< QgsVectorDataProvider::NativeType( tr( "Binary object (BLOB)" ), "BLOB", QVariant::ByteArray )
Expand Down Expand Up @@ -618,6 +623,48 @@ void QgsSpatiaLiteProvider::loadFieldsAbstractInterface( gaiaVectorLayerPtr lyr
}
#endif

QString QgsSpatiaLiteProvider::spatialiteVersion()
{
if ( mGotSpatialiteVersion )
return mSpatialiteVersionInfo;

int ret;
char **results;
int rows;
int columns;
char *errMsg = NULL;
QString sql;

sql = "SELECT spatialite_version()";
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8(), &results, &rows, &columns, &errMsg );
if ( ret != SQLITE_OK || rows != 1 )
{
QgsMessageLog::logMessage( tr( "Retrieval of spatialite version failed" ), tr( "SpatiaLite" ) );
return QString::null;
}

mSpatialiteVersionInfo = QString::fromUtf8( results[( 1 * columns ) + 0] );
sqlite3_free_table( results );

QgsDebugMsg( "SpatiaLite version info: " + mSpatialiteVersionInfo );

QStringList spatialiteParts = mSpatialiteVersionInfo.split( " ", QString::SkipEmptyParts );

// Get major and minor version
QStringList spatialiteVersionParts = spatialiteParts[0].split( ".", QString::SkipEmptyParts );
if ( spatialiteVersionParts.size() < 2 )
{
QgsMessageLog::logMessage( tr( "Could not parse spatialite version string '%1'" ).arg( mSpatialiteVersionInfo ), tr( "SpatiaLite" ) );
return QString::null;
}

mSpatialiteVersionMajor = spatialiteVersionParts[0].toInt();
mSpatialiteVersionMinor = spatialiteVersionParts[1].toInt();

mGotSpatialiteVersion = true;
return mSpatialiteVersionInfo;
}

void QgsSpatiaLiteProvider::loadFields()
{
int ret;
Expand Down Expand Up @@ -3720,6 +3767,53 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
return;
}

QString QgsSpatiaLiteProvider::geomParam() const
{
QString geometry;

bool forceMulti = false;

switch ( geometryType() )
{
case QGis::WKBPoint:
case QGis::WKBLineString:
case QGis::WKBPolygon:
case QGis::WKBPoint25D:
case QGis::WKBLineString25D:
case QGis::WKBPolygon25D:
case QGis::WKBUnknown:
case QGis::WKBNoGeometry:
forceMulti = false;
break;

case QGis::WKBMultiPoint:
case QGis::WKBMultiLineString:
case QGis::WKBMultiPolygon:
case QGis::WKBMultiPoint25D:
case QGis::WKBMultiLineString25D:
case QGis::WKBMultiPolygon25D:
forceMulti = true;
break;
}

// ST_Multi function is available from QGIS >= 2.4
bool hasMultiFunction = mSpatialiteVersionMajor > 2 ||
( mSpatialiteVersionMajor == 2 && mSpatialiteVersionMinor >= 4 );

if ( forceMulti && hasMultiFunction )
{
geometry += "ST_Multi(";
}

geometry += QString( "GeomFromWKB(?, %2)" ).arg( mSrid );

if ( forceMulti && hasMultiFunction )
{
geometry += ")";
}

return geometry;
}

bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList & flist )
{
Expand Down Expand Up @@ -3750,7 +3844,7 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList & flist )
if ( !mGeometryColumn.isNull() )
{
sql += separator + quotedIdentifier( mGeometryColumn );
values += separator + QString( "GeomFromWKB(?, %2)" ).arg( mSrid );
values += separator + geomParam();
separator = ",";
}

Expand Down
17 changes: 17 additions & 0 deletions src/providers/spatialite/qgsspatialiteprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
/** convert a QgsField to work with SL */
static bool convertField( QgsField &field );

QString geomParam() const;

//! get SpatiaLite version string
QString spatialiteVersion();

QgsFieldMap attributeFields;
/**
* Flag indicating if the layer data source is a valid SpatiaLite layer
Expand Down Expand Up @@ -396,6 +401,18 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
/** geometry column index used when fetching geometry */
int mGeomColIdx;

//! SpatiaLite version string
QString mSpatialiteVersionInfo;

//! Are mSpatialiteVersionMajor, mSpatialiteVersionMinor valid?
bool mGotSpatialiteVersion;

//! SpatiaLite major version
int mSpatialiteVersionMajor;

//! SpatiaLite minor version
int mSpatialiteVersionMinor;

/**
* internal utility functions used to handle common SQLite tasks
*/
Expand Down