From 03916d549a27eb7b6f182082fc9920e1ce5320ac Mon Sep 17 00:00:00 2001 From: Giuseppe Sucameli Date: Thu, 3 Sep 2015 01:22:54 +0200 Subject: [PATCH] [DBManager] add SL/Geopackage connection by drag&drop (follow b11f67b4f5), improve GPKG support: - recognize tables with geometry, - load GPGK layers to canvas from context menu, - disable table editing --- python/plugins/db_manager/db_model.py | 59 ++++++--- .../plugins/db_manager/db_plugins/plugin.py | 47 +++++-- .../db_manager/db_plugins/postgis/plugin.py | 5 +- .../db_plugins/spatialite/connector.py | 120 ++++++++++++++---- .../db_plugins/spatialite/info_model.py | 24 ++++ .../db_plugins/spatialite/plugin.py | 75 +++++++++-- python/plugins/db_manager/db_tree.py | 50 +++----- 7 files changed, 286 insertions(+), 94 deletions(-) diff --git a/python/plugins/db_manager/db_model.py b/python/plugins/db_manager/db_model.py index 5536c6581f2..16768360f6d 100644 --- a/python/plugins/db_manager/db_model.py +++ b/python/plugins/db_manager/db_model.py @@ -284,6 +284,8 @@ class DBModel(QAbstractItemModel): if self.isImportVectorAvail: self.connect(self, SIGNAL("importVector"), self.importVector) + self.hasSpatialiteSupport = "spatialite" in supportedDbTypes() + self.rootItem = TreeItem(None, None) for dbtype in supportedDbTypes(): dbpluginclass = createDbPlugin(dbtype) @@ -373,13 +375,18 @@ class DBModel(QAbstractItemModel): if isinstance(item, TableItem): flags |= Qt.ItemIsDragEnabled - if self.isImportVectorAvail: # allow to import a vector layer + # vectors/tables can be dropped on connected databases to be imported + if self.isImportVectorAvail: if isinstance(item, ConnectionItem) and item.populated: flags |= Qt.ItemIsDropEnabled - if isinstance(item, SchemaItem) or isinstance(item, TableItem): + if isinstance(item, (SchemaItem, TableItem)): flags |= Qt.ItemIsDropEnabled + # SL/Geopackage db files can be dropped everywhere in the tree + if self.hasSpatialiteSupport: + flags |= Qt.ItemIsDropEnabled + return flags def headerData(self, section, orientation, role): @@ -508,8 +515,10 @@ class DBModel(QAbstractItemModel): if action == Qt.IgnoreAction: return True - if not self.isImportVectorAvail: - return False + # vectors/tables to be imported must be dropped on connected db, schema or table + canImportLayer = self.isImportVectorAvail and parent.isValid() and \ + ( isinstance(parent.internalPointer(), (SchemaItem, TableItem)) or \ + ( isinstance(parent.internalPointer(), ConnectionItem) and parent.internalPointer().populated ) ) added = 0 @@ -518,22 +527,42 @@ class DBModel(QAbstractItemModel): filename = u.toLocalFile() if filename == "": continue - if qgis.core.QgsRasterLayer.isValidRasterFileName(filename): - layerType = 'raster' - providerKey = 'gdal' - else: - layerType = 'vector' - providerKey = 'ogr' - layerName = QFileInfo(filename).completeBaseName() + if self.hasSpatialiteSupport: + from .db_plugins.spatialite.connector import SpatiaLiteDBConnector - if self.importLayer(layerType, providerKey, layerName, filename, parent): - added += 1 + if SpatiaLiteDBConnector.isValidDatabase(filename): + # retrieve the SL plugin tree item using its path + index = self._rPath2Index(["spatialite"]) + if not index.isValid(): + continue + item = index.internalPointer() + + conn_name = QFileInfo(filename).fileName() + uri = qgis.core.QgsDataSourceURI() + uri.setDatabase(filename) + item.getItemData().addConnection(conn_name, uri) + item.emit(SIGNAL('itemChanged'), item) + added += 1 + continue + + if canImportLayer: + if qgis.core.QgsRasterLayer.isValidRasterFileName(filename): + layerType = 'raster' + providerKey = 'gdal' + else: + layerType = 'vector' + providerKey = 'ogr' + + layerName = QFileInfo(filename).completeBaseName() + if self.importLayer(layerType, providerKey, layerName, filename, parent): + added += 1 if data.hasFormat(self.QGIS_URI_MIME): for uri in qgis.core.QgsMimeDataUtils.decodeUriList(data): - if self.importLayer(uri.layerType, uri.providerKey, uri.name, uri.uri, parent): - added += 1 + if canImportLayer: + if self.importLayer(uri.layerType, uri.providerKey, uri.name, uri.uri, parent): + added += 1 return added > 0 diff --git a/python/plugins/db_manager/db_plugins/plugin.py b/python/plugins/db_manager/db_plugins/plugin.py index 84e777e438f..cb7c1813a0d 100644 --- a/python/plugins/db_manager/db_plugins/plugin.py +++ b/python/plugins/db_manager/db_plugins/plugin.py @@ -97,6 +97,9 @@ class DBPlugin(QObject): return DatabaseInfo(None) + def connect(self, parent=None): + raise NotImplemented + def connectToUri(self, uri): self.db = self.databasesFactory(self, uri) if self.db: @@ -111,6 +114,17 @@ class DBPlugin(QObject): return self.connectToUri(uri) return self.connect(self.parent()) + def remove(self): + settings = QSettings() + settings.beginGroup(u"/%s/%s" % (self.connectionSettingsKey(), self.connectionName())) + settings.remove("") + self.emit(SIGNAL('deleted')) + return True + + @classmethod + def addConnection(self, conn_name, uri): + raise NotImplemented + @classmethod def icon(self): return None @@ -135,11 +149,6 @@ class DBPlugin(QObject): # return the key used to store the connections in settings pass - @classmethod - def connectionSettingsFileKey(self): - # return the filekey for the settings - pass - @classmethod def connections(self): # get the list of connections @@ -154,6 +163,24 @@ class DBPlugin(QObject): def databasesFactory(self, connection, uri): return None + @classmethod + def addConnectionActionSlot(self, item, action, parent): + raise NotImplemented + + def removeActionSlot(self, item, action, parent): + QApplication.restoreOverrideCursor() + try: + res = QMessageBox.question(parent, QApplication.translate("DBManagerPlugin", "hey!"), + QApplication.translate("DBManagerPlugin", + "Really remove connection to %s?") % item.connectionName(), + QMessageBox.Yes | QMessageBox.No) + if res != QMessageBox.Yes: + return + finally: + QApplication.setOverrideCursor(Qt.WaitCursor) + + item.remove() + class DbItemObject(QObject): @@ -207,6 +234,13 @@ class Database(DbItemObject): def publicUri(self): return self.connector.publicUri() + def delete(self): + self.aboutToChange() + ret = self.connection().remove() + if ret is not False: + self.emit(SIGNAL('deleted')) + return ret + def info(self): from .info_model import DatabaseInfo @@ -636,9 +670,6 @@ class Table(DbItemObject): def mimeUri(self): layerType = "raster" if self.type == Table.RasterType else "vector" - if self.database().dbplugin().typeName() == "spatialite" and self.database().connector.isgpkg(): - url = unicode(self.database().connector._connectionInfo() + "|layername=" + self.name) - return u"%s:%s:%s:%s" % (layerType, "ogr", self.name, url) return u"%s:%s:%s:%s" % (layerType, self.database().dbplugin().providerName(), self.name, self.uri().uri()) def toMapLayer(self): diff --git a/python/plugins/db_manager/db_plugins/postgis/plugin.py b/python/plugins/db_manager/db_plugins/postgis/plugin.py index 3f5086605f1..bbdedee6b74 100644 --- a/python/plugins/db_manager/db_plugins/postgis/plugin.py +++ b/python/plugins/db_manager/db_plugins/postgis/plugin.py @@ -64,10 +64,6 @@ class PostGisDBPlugin(DBPlugin): def connectionSettingsKey(self): return '/PostgreSQL/connections' - @classmethod - def connectionSettingsFileKey(self): - return "database" - def databasesFactory(self, connection, uri): return PGDatabase(connection, uri) @@ -284,6 +280,7 @@ class PGRasterTable(PGTable, RasterTable): return gdalUri def mimeUri(self): + # QGIS has no provider for PGRasters, let's use GDAL uri = u"raster:gdal:%s:%s" % (self.name, re.sub(":", "\:", self.gdalUri())) return uri diff --git a/python/plugins/db_manager/db_plugins/spatialite/connector.py b/python/plugins/db_manager/db_plugins/spatialite/connector.py index a8f474cfdee..f3cd8e76dbd 100644 --- a/python/plugins/db_manager/db_plugins/spatialite/connector.py +++ b/python/plugins/db_manager/db_plugins/spatialite/connector.py @@ -50,12 +50,22 @@ class SpatiaLiteDBConnector(DBConnector): self._checkSpatial() self._checkRaster() - self._checkGeometryColumnsTable() - self._checkRastersTable() + self._checkGeopackage() def _connectionInfo(self): return unicode(self.dbname) + @classmethod + def isValidDatabase(self, path): + if not QFile.exists(path): + return False + try: + conn = sqlite.connect(path) + except self.connection_error_types() as e: + return False + conn.close() + return True + def _checkSpatial(self): """ check if it's a valid spatialite db """ self.has_spatial = self._checkGeometryColumnsTable() @@ -63,9 +73,14 @@ class SpatiaLiteDBConnector(DBConnector): def _checkRaster(self): """ check if it's a rasterite db """ - self.has_raster = self._checkRastersTable() + self.has_raster = self._checkRasterTables() return self.has_raster + def _checkGeopackage(self): + """ check if it's a geopackage db """ + self.is_gpkg = self._checkGeopackageTables() + return self.is_gpkg + def _checkGeometryColumnsTable(self): try: c = self._get_cursor() @@ -80,13 +95,40 @@ class SpatiaLiteDBConnector(DBConnector): self.has_geometry_columns_access = self.has_geometry_columns return self.has_geometry_columns - def _checkRastersTable(self): + def _checkRasterTables(self): c = self._get_cursor() sql = u"SELECT count(*) = 3 FROM sqlite_master WHERE name IN ('layer_params', 'layer_statistics', 'raster_pyramids')" self._execute(c, sql) ret = c.fetchone() return ret and ret[0] + def _checkGeopackageTables(self): + try: + sql = u"SELECT HasGeoPackage()" + result = self._execute(None, sql).fetchone()[0] == 1 + except ConnectionError: + result = False + + if result: + try: + sql = u"SELECT CheckGeoPackageMetaData()" + result = self._execute(None, sql).fetchone()[0] == 1 + except ConnectionError: + result = False + else: + # Spatialite < 4.2 has no GeoPackage support, check for filename and GPKG layout + ver = map(int, self.getInfo()[0].split('.')[0:2]) + if ver[0] < 4 or (ver[0] == 4 and ver[1] < 2): + hasGpkgFileExt = self.dbname[-5:] == ".gpkg" or self.dbname[-11:] == ".geopackage" + + sql = u"SELECT count(*) = 3 FROM sqlite_master WHERE name IN ('gpkg_geometry_columns', 'gpkg_spatial_ref_sys', 'gpkg_contents')" + ret = self._execute(None, sql).fetchone() + hasGpkgLayout = ret and ret[0] + + result = hasGpkgFileExt and hasGpkgLayout + + return result + def getInfo(self): c = self._get_cursor() self._execute(c, u"SELECT sqlite_version()") @@ -98,7 +140,7 @@ class SpatiaLiteDBConnector(DBConnector): - geos version - proj version """ - if not self.has_spatial: + if not self.has_spatial and not self.is_gpkg: return c = self._get_cursor() @@ -126,14 +168,8 @@ class SpatiaLiteDBConnector(DBConnector): def hasCreateSpatialViewSupport(self): return True - def isgpkg(self): - info = map(int, self.getInfo()[0].split('.')[0:2]) - if info[0] < 4 or (info[0] == 4 and info[1] < 2): - result = self.uri().database()[-5:] == ".gpkg" - else: - sql = u"SELECT HasGeoPackage()" - result = self._execute(None, sql).fetchone()[0] == 1 - return result + def isGpkg(self): + return self.is_gpkg def fieldTypes(self): return [ @@ -225,13 +261,9 @@ class SpatiaLiteDBConnector(DBConnector): srid """ - if not self.has_geometry_columns: - return [] - - c = self._get_cursor() - - if self.has_spatialite4: - cols = """CASE geometry_type % 10 + if self.has_geometry_columns: + if self.has_spatialite4: + cols = """CASE geometry_type % 10 WHEN 1 THEN 'POINT' WHEN 2 THEN 'LINESTRING' WHEN 3 THEN 'POLYGON' @@ -247,15 +279,27 @@ class SpatiaLiteDBConnector(DBConnector): WHEN 3 THEN 'XYZM' ELSE NULL END AS coord_dimension""" - else: - cols = "g.type,g.coord_dimension" + else: + cols = "g.type,g.coord_dimension" - # get geometry info from geometry_columns if exists - sql = u"""SELECT m.name, m.type = 'view', g.f_table_name, g.f_geometry_column, %s, g.srid + # get geometry info from geometry_columns if exists + sql = u"""SELECT m.name, m.type = 'view', g.f_table_name, g.f_geometry_column, %s, g.srid FROM sqlite_master AS m JOIN geometry_columns AS g ON upper(m.name) = upper(g.f_table_name) WHERE m.type in ('table', 'view') ORDER BY m.name, g.f_geometry_column""" % cols + elif self.is_gpkg: + # get info from gpkg_geometry_columns table + dim = " 'XY' || CASE z WHEN 1 THEN 'Z' END || CASE m WHEN 1 THEN 'M' END AS coord_dimension " + sql = u"""SELECT m.name, m.type = 'view', g.table_name, g.column_name, g.geometry_type_name AS gtype, %s, g.srs_id + FROM sqlite_master AS m JOIN gpkg_geometry_columns AS g ON upper(m.name) = upper(g.table_name) + WHERE m.type in ('table', 'view') + ORDER BY m.name, g.column_name""" % dim + + else: + return [] + + c = self._get_cursor() self._execute(c, sql) items = [] @@ -277,6 +321,8 @@ class SpatiaLiteDBConnector(DBConnector): srid """ + if self.is_gpkg: + return [] # Not implemented if not self.has_geometry_columns: return [] if not self.has_raster: @@ -375,7 +421,10 @@ class SpatiaLiteDBConnector(DBConnector): return ret[0] if ret is not None else None def getSpatialRefInfo(self, srid): - sql = u"SELECT ref_sys_name FROM spatial_ref_sys WHERE srid = %s" % self.quoteString(srid) + if self.is_gpkg: + sql = u"SELECT srs_name FROM gpkg_spatial_ref_sys WHERE srs_id = %s" % self.quoteString(srid) + else: + sql = u"SELECT ref_sys_name FROM spatial_ref_sys WHERE srid = %s" % self.quoteString(srid) c = self._execute(None, sql) ret = c.fetchone() return ret[0] if ret is not None else None @@ -428,6 +477,8 @@ class SpatiaLiteDBConnector(DBConnector): """ delete table from the database """ if self.isRasterTable(table): return False + if self.is_gpkg: + return False # Not implemented c = self._get_cursor() sql = u"DROP TABLE %s" % self.quoteId(table) @@ -441,6 +492,8 @@ class SpatiaLiteDBConnector(DBConnector): """ delete all rows from table """ if self.isRasterTable(table): return False + if self.is_gpkg: + return False # Not implemented sql = u"DELETE FROM %s" % self.quoteId(table) self._execute_and_commit(sql) @@ -453,6 +506,8 @@ class SpatiaLiteDBConnector(DBConnector): if self.isRasterTable(table): return False + if self.is_gpkg: + return False # Not implemented c = self._get_cursor() @@ -492,6 +547,9 @@ class SpatiaLiteDBConnector(DBConnector): return self.renameTable(view, new_name) def createSpatialView(self, view, query): + if self.is_gpkg: + return False # Not implemented + self.createView(view, query) # get type info about the view sql = u"PRAGMA table_info(%s)" % self.quoteString(view) @@ -570,6 +628,9 @@ class SpatiaLiteDBConnector(DBConnector): return False # column editing not supported def isGeometryColumn(self, table, column): + if self.is_gpkg: + return False # Not implemented + c = self._get_cursor() schema, tablename = self.getSchemaTableName(table) sql = u"SELECT count(*) > 0 FROM geometry_columns WHERE upper(f_table_name) = upper(%s) AND upper(f_geometry_column) = upper(%s)" % ( @@ -578,6 +639,9 @@ class SpatiaLiteDBConnector(DBConnector): return c.fetchone()[0] == 't' def addGeometryColumn(self, table, geom_column='geometry', geom_type='POINT', srid=-1, dim=2): + if self.is_gpkg: + return False # Not implemented + schema, tablename = self.getSchemaTableName(table) sql = u"SELECT AddGeometryColumn(%s, %s, %d, %s, %s)" % ( self.quoteString(tablename), self.quoteString(geom_column), srid, self.quoteString(geom_type), dim) @@ -614,6 +678,8 @@ class SpatiaLiteDBConnector(DBConnector): def createSpatialIndex(self, table, geom_column='geometry'): if self.isRasterTable(table): return False + if self.is_gpkg: + return False # Not implemented schema, tablename = self.getSchemaTableName(table) sql = u"SELECT CreateSpatialIndex(%s, %s)" % (self.quoteString(tablename), self.quoteString(geom_column)) @@ -622,6 +688,8 @@ class SpatiaLiteDBConnector(DBConnector): def deleteSpatialIndex(self, table, geom_column='geometry'): if self.isRasterTable(table): return False + if self.is_gpkg: + return False # Not implemented schema, tablename = self.getSchemaTableName(table) try: @@ -635,6 +703,8 @@ class SpatiaLiteDBConnector(DBConnector): self.deleteTable(idx_table_name) def hasSpatialIndex(self, table, geom_column='geometry'): + if self.is_gpkg: + return False # Not implemented if not self.has_geometry_columns or self.isRasterTable(table): return False c = self._get_cursor() diff --git a/python/plugins/db_manager/db_plugins/spatialite/info_model.py b/python/plugins/db_manager/db_plugins/spatialite/info_model.py index 715d959b785..43325d0bae6 100644 --- a/python/plugins/db_manager/db_plugins/spatialite/info_model.py +++ b/python/plugins/db_manager/db_plugins/spatialite/info_model.py @@ -44,5 +44,29 @@ class SLDatabaseInfo(DatabaseInfo): ] return HtmlTable(tbl) + def spatialInfo(self): + ret = [] + + info = self.db.connector.getSpatialInfo() + if info is None: + return + + tbl = [ + (QApplication.translate("DBManagerPlugin", "Library:"), info[0]), + ("GEOS:", info[1]), + ("Proj:", info[2]) + ] + ret.append(HtmlTable(tbl)) + + if self.db.connector.is_gpkg: + pass + + elif not self.db.connector.has_geometry_columns: + ret.append(HtmlParagraph( + QApplication.translate("DBManagerPlugin", " geometry_columns table doesn't exist!\n" + "This table is essential for many GIS applications for enumeration of tables."))) + + return ret + def privilegesDetails(self): return None diff --git a/python/plugins/db_manager/db_plugins/spatialite/plugin.py b/python/plugins/db_manager/db_plugins/spatialite/plugin.py index 3a73b2cee9d..68055c55cdb 100644 --- a/python/plugins/db_manager/db_plugins/spatialite/plugin.py +++ b/python/plugins/db_manager/db_plugins/spatialite/plugin.py @@ -62,10 +62,6 @@ class SpatiaLiteDBPlugin(DBPlugin): def connectionSettingsKey(self): return '/SpatiaLite/connections' - @classmethod - def connectionSettingsFileKey(self): - return "sqlitepath" - def databasesFactory(self, connection, uri): return SLDatabase(connection, uri) @@ -85,6 +81,31 @@ class SpatiaLiteDBPlugin(DBPlugin): uri.setDatabase(database) return self.connectToUri(uri) + @classmethod + def addConnection(self, conn_name, uri): + settings = QSettings() + settings.beginGroup(u"/%s/%s" % (self.connectionSettingsKey(), conn_name)) + settings.setValue("sqlitepath", uri.database()) + return True + + + @classmethod + def addConnectionActionSlot(self, item, action, parent, index): + QApplication.restoreOverrideCursor() + try: + filename = QFileDialog.getOpenFileName(self, "Choose Sqlite/Spatialite/Geopackage file") + if not filename: + return + finally: + QApplication.setOverrideCursor(Qt.WaitCursor) + + conn_name = QFileInfo(filepath).fileName() + uri = qgis.core.QgsDataSourceURI() + uri.setDatabase(filepath) + self.addConnection(conn_name, uri) + index.internalPointer().emit(SIGNAL('itemChanged')) + + class SLDatabase(Database): @@ -153,7 +174,7 @@ class SLDatabase(Database): return True def spatialIndexClause(self, src_table, src_column, dest_table, dest_column): - return """"%s".ROWID IN (\nSELECT ROWID FROM SpatialIndex WHERE f_table_name='%s' AND search_frame="%s"."%s") """ % (src_table, src_table, dest_table, dest_column) + return u""" "%s".ROWID IN (\nSELECT ROWID FROM SpatialIndex WHERE f_table_name='%s' AND search_frame="%s"."%s") """ % (src_table, src_table, dest_table, dest_column) class SLTable(Table): @@ -162,6 +183,29 @@ class SLTable(Table): Table.__init__(self, db, None) self.name, self.isView, self.isSysTable = row + def ogrUri(self): + ogrUri = u"%s|layername=%s" % (self.uri().database(), self.name) + return ogrUri + + def mimeUri(self): + if self.database().connector.isGpkg(): + # QGIS has no provider to load Geopackage vectors, let's use OGR + return u"vector:ogr:%s:%s" % (self.name, self.ogrUri()) + return VectorTable.mimeUri(self) + + def toMapLayer(self): + from qgis.core import QgsVectorLayer + + if self.database().connector.isGpkg(): + # QGIS has no provider to load Geopackage vectors, let's use OGR + provider = "ogr" + uri = self.ogrUri() + else: + provider = self.database().dbplugin().providerName() + uri = self.uri().uri() + + return QgsVectorLayer(uri, self.name, provider) + def tableFieldsFactory(self, row, table): return SLTableField(row, table) @@ -231,19 +275,30 @@ class SLRasterTable(SLTable, RasterTable): #from .info_model import SLRasterTableInfo #return SLRasterTableInfo(self) - def gdalUri(self): - uri = self.database().uri() - gdalUri = u'RASTERLITE:%s,table=%s' % (uri.database(), self.prefixName) + def rasterliteGdalUri(self): + gdalUri = u'RASTERLITE:%s,table=%s' % (self.uri().database(), self.prefixName) return gdalUri def mimeUri(self): - uri = u"raster:gdal:%s:%s" % (self.name, self.gdalUri()) + if self.database().connector.isGpkg(): + # QGIS has no provider to load Geopackage rasters, let's use GDAL + uri = u"raster:gdal:%s:%s" % (self.name, self.uri().database()) + else: + # QGIS has no provider to load Rasterlite rasters, let's use GDAL + uri = u"raster:gdal:%s:%s" % (self.name, self.rasterliteGdalUri()) return uri def toMapLayer(self): from qgis.core import QgsRasterLayer, QgsContrastEnhancement - rl = QgsRasterLayer(self.gdalUri(), self.name) + if self.database().connector.isGpkg(): + # QGIS has no provider to load Geopackage rasters, let's use GDAL + uri = self.ogrUri() + else: + # QGIS has no provider to load Rasterlite rasters, let's use GDAL + uri = self.rasterliteGdalUri() + + rl = QgsRasterLayer(uri, self.name) if rl.isValid(): rl.setContrastEnhancement(QgsContrastEnhancement.StretchToMinimumMaximum) return rl diff --git a/python/plugins/db_manager/db_tree.py b/python/plugins/db_manager/db_tree.py index f3144fdcc65..311d8978208 100644 --- a/python/plugins/db_manager/db_tree.py +++ b/python/plugins/db_manager/db_tree.py @@ -26,7 +26,7 @@ from PyQt4.QtGui import QWidget, QTreeView, QMenu, QLabel, QFileDialog from qgis.core import QgsMapLayerRegistry, QgsMessageLog from qgis.gui import QgsMessageBar, QgsMessageBarItem -from .db_model import DBModel +from .db_model import DBModel, PluginItem from .db_plugins.plugin import DBPlugin, Schema, Table @@ -94,12 +94,12 @@ class DBTree(QTreeView): return item return None - def openConnection(self): - index = self.selectedIndexes()[0] - if index: - if index.data() != "PostGIS": - filename = QFileDialog.getOpenFileName(self, "Open File") - self.model().addConnection(filename, index) + def newConnection(self): + index = self.currentIndex() + if not index.isValid() or not isinstance(index.internalPointer(), PluginItem): + return + item = self.currentItem() + self.mainWindow.invokeCallback(item.addConnectionActionSlot, index) def itemChanged(self, index): self.setCurrentIndex(index) @@ -131,12 +131,13 @@ class DBTree(QTreeView): menu.addSeparator() menu.addAction(self.tr("Add to canvas"), self.addLayer) - elif isinstance(item, DBPlugin) and item.database() is not None: - menu.addAction(self.tr("Re-connect"), self.reconnect) - menu.addAction(self.tr("Delete"), self.delActionSlot) + elif isinstance(item, DBPlugin): + if item.database() is not None: + menu.addAction(self.tr("Re-connect"), self.reconnect) + menu.addAction(self.tr("Remove"), self.delete) - elif not index.parent().data(): - menu.addAction(self.tr("New Connection..."), self.openConnection) + elif not index.parent().isValid() and item.typeName() == "spatialite": + menu.addAction(self.tr("New Connection..."), self.newConnection) if not menu.isEmpty(): menu.exec_(ev.globalPos()) @@ -144,32 +145,16 @@ class DBTree(QTreeView): menu.deleteLater() def rename(self): - index = self.currentIndex() - item = self.model().getItem(index) + item = self.currentItem() if isinstance(item, (Table, Schema)): - self.edit(index) - - def delActionSlot(self): - db = self.currentDatabase() - path = db.uri().database() - connkey = db.connection().connectionSettingsKey() - self.deletedb(path, connkey) - - index = self.currentIndex().parent() - self.setCurrentIndex(index) - self.mainWindow.refreshActionSlot() - - def deletedb(self, path, conn): - paths = path.split("/") - path = paths[-1] - s = QSettings() - s.beginGroup("/%s/%s" % (conn, path)) - s.remove("") + self.edit(self.currentIndex()) def delete(self): item = self.currentItem() if isinstance(item, (Table, Schema)): self.mainWindow.invokeCallback(item.database().deleteActionSlot) + elif isinstance(item, DBPlugin): + self.mainWindow.invokeCallback(item.removeActionSlot) def addLayer(self): table = self.currentTable() @@ -193,3 +178,4 @@ class DBTree(QTreeView): db = self.currentDatabase() if db is not None: self.mainWindow.invokeCallback(db.reconnectActionSlot) +