2012-04-16 13:19:40 +02:00
# -*- coding: utf-8 -*-
"""
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Name : DB Manager
2013-06-09 18:28:52 +02:00
Description : Database manager plugin for QGIS
2012-04-16 13:19:40 +02:00
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 . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
"""
2016-09-21 18:24:26 +02:00
from builtins import str
2012-04-16 13:19:40 +02:00
# this will disable the dbplugin if the connector raise an ImportError
from . connector import SpatiaLiteDBConnector
2017-03-03 20:39:17 +01:00
from qgis . PyQt . QtCore import Qt , QFileInfo
2016-04-22 10:38:48 +02:00
from qgis . PyQt . QtGui import QIcon
from qgis . PyQt . QtWidgets import QApplication , QAction , QFileDialog
2018-02-05 22:11:34 -04:00
from qgis . core import Qgis , QgsDataSourceUri , QgsSettings
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
from qgis . gui import QgsMessageBar
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
from . . plugin import DBPlugin , Database , Table , VectorTable , RasterTable , TableField , TableIndex , TableTrigger , \
InvalidDataException
2016-03-21 04:51:10 +01:00
from . import resources_rc # NOQA
2016-03-15 23:41:19 +01:00
2012-04-16 13:19:40 +02:00
def classFactory ( ) :
2015-03-21 10:41:58 +10:00
return SpatiaLiteDBPlugin
2012-04-16 13:19:40 +02:00
class SpatiaLiteDBPlugin ( DBPlugin ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
@classmethod
def icon ( self ) :
return QIcon ( " :/db_manager/spatialite/icon " )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
@classmethod
def typeName ( self ) :
return ' spatialite '
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
@classmethod
def typeNameString ( self ) :
2016-10-18 14:28:30 +02:00
return ' SpatiaLite '
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
@classmethod
def providerName ( self ) :
return ' spatialite '
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
@classmethod
def connectionSettingsKey ( self ) :
return ' /SpatiaLite/connections '
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def databasesFactory ( self , connection , uri ) :
return SLDatabase ( connection , uri )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def connect ( self , parent = None ) :
conn_name = self . connectionName ( )
2017-03-03 20:39:17 +01:00
settings = QgsSettings ( )
2015-03-21 10:41:58 +10:00
settings . beginGroup ( u " / %s / %s " % ( self . connectionSettingsKey ( ) , conn_name ) )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
if not settings . contains ( " sqlitepath " ) : # non-existent entry?
2017-03-04 16:23:36 +01:00
raise InvalidDataException ( self . tr ( u ' There is no defined database connection " {0} " . ' ) . format ( conn_name ) )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
database = settings . value ( " sqlitepath " )
2012-04-16 13:19:40 +02:00
2016-08-04 09:10:08 +02:00
uri = QgsDataSourceUri ( )
2015-03-21 10:41:58 +10:00
uri . setDatabase ( database )
return self . connectToUri ( uri )
2012-04-16 13:19:40 +02:00
2015-09-03 01:22:54 +02:00
@classmethod
def addConnection ( self , conn_name , uri ) :
2017-03-03 20:39:17 +01:00
settings = QgsSettings ( )
2015-09-03 01:22:54 +02:00
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 :
2017-07-06 06:40:02 +02:00
filename , selected_filter = QFileDialog . getOpenFileName ( parent , " Choose SQLite/SpatiaLite file " )
2015-09-03 01:22:54 +02:00
if not filename :
return
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
2015-09-04 00:31:14 +02:00
conn_name = QFileInfo ( filename ) . fileName ( )
2016-08-04 09:10:08 +02:00
uri = QgsDataSourceUri ( )
2015-09-04 00:31:14 +02:00
uri . setDatabase ( filename )
2015-09-03 01:22:54 +02:00
self . addConnection ( conn_name , uri )
2016-09-01 20:51:26 +02:00
index . internalPointer ( ) . itemChanged ( )
2015-09-03 01:22:54 +02:00
2012-04-16 13:19:40 +02:00
class SLDatabase ( Database ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , connection , uri ) :
Database . __init__ ( self , connection , uri )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def connectorsFactory ( self , uri ) :
return SpatiaLiteDBConnector ( uri )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def dataTablesFactory ( self , row , db , schema = None ) :
return SLTable ( row , db , schema )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def vectorTablesFactory ( self , row , db , schema = None ) :
return SLVectorTable ( row , db , schema )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def rasterTablesFactory ( self , row , db , schema = None ) :
return SLRasterTable ( row , db , schema )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def info ( self ) :
from . info_model import SLDatabaseInfo
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
return SLDatabaseInfo ( self )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def sqlResultModel ( self , sql , parent ) :
from . data_model import SLSqlResultModel
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
return SLSqlResultModel ( self , sql , parent )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def registerDatabaseActions ( self , mainWindow ) :
action = QAction ( self . tr ( " Run &Vacuum " ) , self )
mainWindow . registerAction ( action , self . tr ( " &Database " ) , self . runVacuumActionSlot )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
Database . registerDatabaseActions ( self , mainWindow )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
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. " ) ,
2018-02-05 22:11:34 -04:00
Qgis . Info , parent . iface . messageTimeout ( ) )
2015-03-21 10:41:58 +10:00
return
finally :
QApplication . setOverrideCursor ( Qt . WaitCursor )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
self . runVacuum ( )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def runVacuum ( self ) :
2016-04-14 09:02:04 +02:00
self . database ( ) . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
self . database ( ) . connector . runVacuum ( )
self . database ( ) . refresh ( )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def runAction ( self , action ) :
2016-09-21 18:24:26 +02:00
action = str ( action )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
if action . startswith ( " vacuum/ " ) :
if action == " vacuum/run " :
self . runVacuum ( )
return True
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
return Database . runAction ( self , action )
2012-04-16 13:19:40 +02:00
2015-03-27 14:32:41 +01:00
def uniqueIdFunction ( self ) :
return None
2012-04-16 13:19:40 +02:00
2015-08-22 14:29:41 +02:00
def explicitSpatialIndex ( self ) :
2015-03-30 15:31:19 +02:00
return True
2015-08-22 14:29:41 +02:00
def spatialIndexClause ( self , src_table , src_column , dest_table , dest_column ) :
2015-09-03 01:22:54 +02:00
return u """ " %s " .ROWID IN ( \n SELECT ROWID FROM SpatialIndex WHERE f_table_name= ' %s ' AND search_frame= " %s " . " %s " ) """ % ( src_table , src_table , dest_table , dest_column )
2015-08-22 14:29:41 +02:00
2015-03-30 15:31:19 +02:00
2015-03-21 10:41:58 +10:00
class SLTable ( Table ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , row , db , schema = None ) :
Table . __init__ ( self , db , None )
self . name , self . isView , self . isSysTable = row
2012-04-16 13:19:40 +02:00
2015-09-03 01:22:54 +02:00
def ogrUri ( self ) :
ogrUri = u " %s |layername= %s " % ( self . uri ( ) . database ( ) , self . name )
return ogrUri
def mimeUri ( self ) :
2016-02-23 16:51:57 +08:00
return Table . mimeUri ( self )
2015-09-03 01:22:54 +02:00
def toMapLayer ( self ) :
from qgis . core import QgsVectorLayer
2016-10-18 14:28:30 +02:00
provider = self . database ( ) . dbplugin ( ) . providerName ( )
uri = self . uri ( ) . uri ( )
2015-09-03 01:22:54 +02:00
return QgsVectorLayer ( uri , self . name , provider )
2015-03-21 10:41:58 +10:00
def tableFieldsFactory ( self , row , table ) :
return SLTableField ( row , table )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def tableIndexesFactory ( self , row , table ) :
return SLTableIndex ( row , table )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def tableTriggersFactory ( self , row , table ) :
return SLTableTrigger ( row , table )
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def tableDataModel ( self , parent ) :
from . data_model import SLTableDataModel
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
return SLTableDataModel ( self , parent )
fix python pep8 warnings and fix some revealed errors
pep8 --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701 \
--exclude="ui_*.py,debian/*,python/ext-libs/*" \
.
2015-02-01 14:15:42 +01:00
2015-03-21 10:41:58 +10:00
class SLVectorTable ( SLTable , VectorTable ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
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
2016-07-21 22:01:38 +10:00
# SL provider didn't do the same in Qgis < 1.9, so self.geomTableName
2015-03-21 10:41:58 +10:00
# 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 ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
ret = VectorTable . createSpatialIndex ( self , geom_column )
if ret is not False :
self . database ( ) . refresh ( )
return ret
def deleteSpatialIndex ( self , geom_column = None ) :
2016-03-21 04:51:10 +01:00
self . aboutToChange . emit ( )
2015-03-21 10:41:58 +10:00
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 )
2012-04-16 13:19:40 +02:00
class SLRasterTable ( SLTable , RasterTable ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
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 '
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
# def info(self):
#from .info_model import SLRasterTableInfo
#return SLRasterTableInfo(self)
2012-04-16 13:19:40 +02:00
2015-09-03 01:22:54 +02:00
def rasterliteGdalUri ( self ) :
gdalUri = u ' RASTERLITE: %s ,table= %s ' % ( self . uri ( ) . database ( ) , self . prefixName )
2015-03-21 10:41:58 +10:00
return gdalUri
2012-04-16 13:19:40 +02:00
2015-03-21 10:41:58 +10:00
def mimeUri ( self ) :
2015-09-21 23:07:04 +02:00
# QGIS has no provider to load rasters, let's use GDAL
uri = u " raster:gdal: %s : %s " % ( self . name , self . uri ( ) . database ( ) )
2015-03-21 10:41:58 +10:00
return uri
2012-12-10 00:12:07 +01:00
2015-03-21 10:41:58 +10:00
def toMapLayer ( self ) :
2015-04-04 23:38:14 +02:00
from qgis . core import QgsRasterLayer , QgsContrastEnhancement
2015-03-21 10:41:58 +10:00
2016-10-18 14:28:30 +02:00
# QGIS has no provider to load Rasterlite rasters, let's use GDAL
uri = self . rasterliteGdalUri ( )
2015-09-03 01:22:54 +02:00
rl = QgsRasterLayer ( uri , self . name )
2015-03-21 10:41:58 +10:00
if rl . isValid ( ) :
2015-04-04 23:38:14 +02:00
rl . setContrastEnhancement ( QgsContrastEnhancement . StretchToMinimumMaximum )
2015-03-21 10:41:58 +10:00
return rl
2012-04-16 13:19:40 +02:00
class SLTableField ( TableField ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
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
2012-04-16 13:19:40 +02:00
class SLTableIndex ( TableIndex ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , row , table ) :
TableIndex . __init__ ( self , table )
self . num , self . name , self . isUnique , self . columns = row
2012-04-16 13:19:40 +02:00
class SLTableTrigger ( TableTrigger ) :
2015-08-22 14:29:41 +02:00
2015-03-21 10:41:58 +10:00
def __init__ ( self , row , table ) :
TableTrigger . __init__ ( self , table )
self . name , self . function = row