123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- """
- /***************************************************************************
- Name : DB Manager
- Description : Database manager plugin for QGIS
- Date : May 23, 2011
- copyright : (C) 2011 by Giuseppe Sucameli
- email : brush.tyler@gmail.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. *
- * *
- ***************************************************************************/
- """
- # this will disable the dbplugin if the connector raise an ImportError
- from .connector import SpatiaLiteDBConnector
- from qgis.PyQt.QtCore import Qt, QFileInfo, QCoreApplication
- from qgis.PyQt.QtGui import QIcon
- from qgis.PyQt.QtWidgets import QApplication, QAction, QFileDialog
- from qgis.core import Qgis, QgsApplication, QgsDataSourceUri, QgsSettings
- from qgis.gui import QgsMessageBar
- from ..plugin import DBPlugin, Database, Table, VectorTable, RasterTable, TableField, TableIndex, TableTrigger, \
- InvalidDataException
- def classFactory():
- return SpatiaLiteDBPlugin
- class SpatiaLiteDBPlugin(DBPlugin):
- @classmethod
- def icon(self):
- return QgsApplication.getThemeIcon("/mIconSpatialite.svg")
- @classmethod
- def typeName(self):
- return 'spatialite'
- @classmethod
- def typeNameString(self):
- return QCoreApplication.translate('db_manager', 'SpatiaLite')
- @classmethod
- def providerName(self):
- return 'spatialite'
- @classmethod
- def connectionSettingsKey(self):
- return '/SpatiaLite/connections'
- def databasesFactory(self, connection, uri):
- return SLDatabase(connection, uri)
- def connect(self, parent=None):
- conn_name = self.connectionName()
- settings = QgsSettings()
- settings.beginGroup("/%s/%s" % (self.connectionSettingsKey(), conn_name))
- if not settings.contains("sqlitepath"): # non-existent entry?
- raise InvalidDataException(self.tr('There is no defined database connection "{0}".').format(conn_name))
- database = settings.value("sqlitepath")
- uri = QgsDataSourceUri()
- uri.setDatabase(database)
- return self.connectToUri(uri)
- @classmethod
- def addConnection(self, conn_name, uri):
- settings = QgsSettings()
- settings.beginGroup("/%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, selected_filter = QFileDialog.getOpenFileName(parent, "Choose SQLite/SpatiaLite file")
- if not filename:
- return
- finally:
- QApplication.setOverrideCursor(Qt.WaitCursor)
- conn_name = QFileInfo(filename).fileName()
- uri = QgsDataSourceUri()
- uri.setDatabase(filename)
- self.addConnection(conn_name, uri)
- index.internalPointer().itemChanged()
- class SLDatabase(Database):
- def __init__(self, connection, uri):
- Database.__init__(self, connection, uri)
- def connectorsFactory(self, uri):
- return SpatiaLiteDBConnector(uri)
- def dataTablesFactory(self, row, db, schema=None):
- return SLTable(row, db, schema)
- def vectorTablesFactory(self, row, db, schema=None):
- return SLVectorTable(row, db, schema)
- def rasterTablesFactory(self, row, db, schema=None):
- return SLRasterTable(row, db, schema)
- def info(self):
- from .info_model import SLDatabaseInfo
- return SLDatabaseInfo(self)
- def sqlResultModel(self, sql, parent):
- from .data_model import SLSqlResultModel
- return SLSqlResultModel(self, sql, parent)
- def sqlResultModelAsync(self, sql, parent):
- from .data_model import SLSqlResultModelAsync
- return SLSqlResultModelAsync(self, sql, parent)
- def registerDatabaseActions(self, mainWindow):
- action = QAction(self.tr("Run &Vacuum"), self)
- mainWindow.registerAction(action, self.tr("&Database"), self.runVacuumActionSlot)
- Database.registerDatabaseActions(self, mainWindow)
- def runVacuumActionSlot(self, item, action, parent):
- QApplication.restoreOverrideCursor()
- try:
- if not isinstance(item, (DBPlugin, Table)) or item.database() is None:
- parent.infoBar.pushMessage(self.tr("No database selected or you are not connected to it."),
- Qgis.Info, parent.iface.messageTimeout())
- return
- finally:
- QApplication.setOverrideCursor(Qt.WaitCursor)
- self.runVacuum()
- def runVacuum(self):
- self.database().aboutToChange.emit()
- self.database().connector.runVacuum()
- self.database().refresh()
- def runAction(self, action):
- action = str(action)
- if action.startswith("vacuum/"):
- if action == "vacuum/run":
- self.runVacuum()
- return True
- return Database.runAction(self, action)
- def uniqueIdFunction(self):
- return None
- def explicitSpatialIndex(self):
- 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)
- def supportsComment(self):
- return False
- class SLTable(Table):
- def __init__(self, row, db, schema=None):
- Table.__init__(self, db, None)
- self.name, self.isView, self.isSysTable = row
- def ogrUri(self):
- ogrUri = "%s|layername=%s" % (self.uri().database(), self.name)
- return ogrUri
- def mimeUri(self):
- return Table.mimeUri(self)
- def toMapLayer(self, geometryType=None, crs=None):
- from qgis.core import QgsVectorLayer
- provider = self.database().dbplugin().providerName()
- uri = self.uri().uri()
- return QgsVectorLayer(uri, self.name, provider)
- def tableFieldsFactory(self, row, table):
- return SLTableField(row, table)
- def tableIndexesFactory(self, row, table):
- return SLTableIndex(row, table)
- def tableTriggersFactory(self, row, table):
- return SLTableTrigger(row, table)
- def tableDataModel(self, parent):
- from .data_model import SLTableDataModel
- return SLTableDataModel(self, parent)
- class SLVectorTable(SLTable, VectorTable):
- def __init__(self, row, db, schema=None):
- SLTable.__init__(self, row[:-5], db, schema)
- VectorTable.__init__(self, db, schema)
- # SpatiaLite does case-insensitive checks for table names, but the
- # SL provider didn't do the same in QGIS < 1.9, so self.geomTableName
- # stores the table name like stored in the geometry_columns table
- self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = row[-5:]
- def uri(self):
- uri = self.database().uri()
- uri.setDataSource('', self.geomTableName, self.geomColumn)
- return uri
- def hasSpatialIndex(self, geom_column=None):
- geom_column = geom_column if geom_column is not None else self.geomColumn
- return self.database().connector.hasSpatialIndex((self.schemaName(), self.name), geom_column)
- def createSpatialIndex(self, geom_column=None):
- self.aboutToChange.emit()
- ret = VectorTable.createSpatialIndex(self, geom_column)
- if ret is not False:
- self.database().refresh()
- return ret
- def deleteSpatialIndex(self, geom_column=None):
- self.aboutToChange.emit()
- ret = VectorTable.deleteSpatialIndex(self, geom_column)
- if ret is not False:
- self.database().refresh()
- return ret
- def refreshTableEstimatedExtent(self):
- return
- def runAction(self, action):
- if SLTable.runAction(self, action):
- return True
- return VectorTable.runAction(self, action)
- class SLRasterTable(SLTable, RasterTable):
- def __init__(self, row, db, schema=None):
- SLTable.__init__(self, row[:-3], db, schema)
- RasterTable.__init__(self, db, schema)
- self.prefixName, self.geomColumn, self.srid = row[-3:]
- self.geomType = 'RASTER'
- # def info(self):
- # from .info_model import SLRasterTableInfo
- # return SLRasterTableInfo(self)
- def rasterliteGdalUri(self):
- gdalUri = 'RASTERLITE:%s,table=%s' % (self.uri().database(), self.prefixName)
- return gdalUri
- def mimeUri(self):
- # QGIS has no provider to load rasters, let's use GDAL
- uri = "raster:gdal:%s:%s" % (self.name, self.uri().database())
- return uri
- def toMapLayer(self, geometryType=None, crs=None):
- from qgis.core import QgsRasterLayer, QgsContrastEnhancement
- # 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
- class SLTableField(TableField):
- def __init__(self, row, table):
- TableField.__init__(self, table)
- self.num, self.name, self.dataType, self.notNull, self.default, self.primaryKey = row
- self.hasDefault = self.default
- class SLTableIndex(TableIndex):
- def __init__(self, row, table):
- TableIndex.__init__(self, table)
- self.num, self.name, self.isUnique, self.columns = row
- class SLTableTrigger(TableTrigger):
- def __init__(self, row, table):
- TableTrigger.__init__(self, table)
- self.name, self.function = row
|