1# -*- coding: utf-8 -*- 2 3""" 4/*************************************************************************** 5Name : DB Manager plugin for virtual layers 6Date : December 2015 7copyright : (C) 2015 by Hugo Mercier 8email : hugo dot mercier at oslandia dot com 9 10 ***************************************************************************/ 11 12/*************************************************************************** 13 * * 14 * This program is free software; you can redistribute it and/or modify * 15 * it under the terms of the GNU General Public License as published by * 16 * the Free Software Foundation; either version 2 of the License, or * 17 * (at your option) any later version. * 18 * * 19 ***************************************************************************/ 20""" 21 22# this will disable the dbplugin if the connector raise an ImportError 23from .connector import VLayerConnector 24 25from qgis.PyQt.QtCore import QCoreApplication 26from qgis.PyQt.QtGui import QIcon 27from qgis.core import QgsApplication, QgsVectorLayer, QgsProject, QgsVirtualLayerDefinition 28 29from ..plugin import DBPlugin, Database, Table, VectorTable, TableField 30 31 32def classFactory(): 33 return VLayerDBPlugin 34 35 36class VLayerDBPlugin(DBPlugin): 37 38 @classmethod 39 def icon(self): 40 return QgsApplication.getThemeIcon("/mIconVirtualLayer.svg") 41 42 def connectionIcon(self): 43 return QgsApplication.getThemeIcon("/providerQgis.svg") 44 45 @classmethod 46 def typeName(self): 47 return 'vlayers' 48 49 @classmethod 50 def typeNameString(self): 51 return QCoreApplication.translate('db_manager', 'Virtual Layers') 52 53 @classmethod 54 def providerName(self): 55 return 'virtual' 56 57 @classmethod 58 def connectionSettingsKey(self): 59 return 'vlayers' 60 61 @classmethod 62 def connections(self): 63 return [VLayerDBPlugin(QCoreApplication.translate('db_manager', 'Project layers'))] 64 65 def databasesFactory(self, connection, uri): 66 return FakeDatabase(connection, uri) 67 68 def database(self): 69 return self.db 70 71 # def info( self ): 72 73 def connect(self, parent=None): 74 self.connectToUri("qgis") 75 return True 76 77 78class FakeDatabase(Database): 79 80 def __init__(self, connection, uri): 81 Database.__init__(self, connection, uri) 82 83 def connectorsFactory(self, uri): 84 return VLayerConnector(uri) 85 86 def dataTablesFactory(self, row, db, schema=None): 87 return LTable(row, db, schema) 88 89 def vectorTablesFactory(self, row, db, schema=None): 90 return LVectorTable(row, db, schema) 91 92 def rasterTablesFactory(self, row, db, schema=None): 93 return None 94 95 def info(self): 96 from .info_model import LDatabaseInfo 97 return LDatabaseInfo(self) 98 99 def sqlResultModel(self, sql, parent): 100 from .data_model import LSqlResultModel 101 return LSqlResultModel(self, sql, parent) 102 103 def sqlResultModelAsync(self, sql, parent): 104 from .data_model import LSqlResultModelAsync 105 return LSqlResultModelAsync(self, sql, parent) 106 107 def toSqlLayer(self, sql, geomCol, uniqueCol, layerName="QueryLayer", layerType=None, avoidSelectById=False, _filter=""): 108 df = QgsVirtualLayerDefinition() 109 df.setQuery(sql) 110 if uniqueCol is not None: 111 uniqueCol = uniqueCol.strip('"').replace('""', '"') 112 df.setUid(uniqueCol) 113 if geomCol is not None: 114 df.setGeometryField(geomCol) 115 vl = QgsVectorLayer(df.toString(), layerName, "virtual") 116 if _filter: 117 vl.setSubsetString(_filter) 118 return vl 119 120 def registerDatabaseActions(self, mainWindow): 121 return 122 123 def runAction(self, action): 124 return 125 126 def uniqueIdFunction(self): 127 return None 128 129 def explicitSpatialIndex(self): 130 return True 131 132 def spatialIndexClause(self, src_table, src_column, dest_table, dest_column): 133 return '"%s"._search_frame_ = "%s"."%s"' % (src_table, dest_table, dest_column) 134 135 def supportsComment(self): 136 return False 137 138 139class LTable(Table): 140 141 def __init__(self, row, db, schema=None): 142 Table.__init__(self, db, None) 143 self.name, self.isView, self.isSysTable = row 144 145 def tableFieldsFactory(self, row, table): 146 return LTableField(row, table) 147 148 def tableDataModel(self, parent): 149 from .data_model import LTableDataModel 150 return LTableDataModel(self, parent) 151 152 def canBeAddedToCanvas(self): 153 return False 154 155 156class LVectorTable(LTable, VectorTable): 157 158 def __init__(self, row, db, schema=None): 159 LTable.__init__(self, row[:-5], db, schema) 160 VectorTable.__init__(self, db, schema) 161 # SpatiaLite does case-insensitive checks for table names, but the 162 # SL provider didn't do the same in QGIS < 1.9, so self.geomTableName 163 # stores the table name like stored in the geometry_columns table 164 self.geomTableName, self.geomColumn, self.geomType, self.geomDim, self.srid = row[ 165 -5:] 166 167 def uri(self): 168 uri = self.database().uri() 169 uri.setDataSource('', self.geomTableName, self.geomColumn) 170 return uri 171 172 def hasSpatialIndex(self, geom_column=None): 173 return True 174 175 def createSpatialIndex(self, geom_column=None): 176 return 177 178 def deleteSpatialIndex(self, geom_column=None): 179 return 180 181 def refreshTableEstimatedExtent(self): 182 self.extent = self.database().connector.getTableExtent( 183 ("id", self.geomTableName), None) 184 185 def runAction(self, action): 186 return 187 188 def toMapLayer(self, geometryType=None, crs=None): 189 return QgsProject.instance().mapLayer(self.geomTableName) 190 191 192class LTableField(TableField): 193 194 def __init__(self, row, table): 195 TableField.__init__(self, table) 196 self.num, self.name, self.dataType, self.notNull, self.default, self.primaryKey = row 197 self.hasDefault = self.default 198