mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
[DB Manager] Add the ability to update SQL Layer
This commit is contained in:
parent
cd33ccf7f6
commit
c1cdfe860d
@ -199,6 +199,15 @@ class DBManager(QMainWindow):
|
|||||||
self.tabs.setCurrentIndex(index)
|
self.tabs.setCurrentIndex(index)
|
||||||
query.nameChanged.connect(functools.partial(self.update_query_tab_name, index, dbname))
|
query.nameChanged.connect(functools.partial(self.update_query_tab_name, index, dbname))
|
||||||
|
|
||||||
|
def runSqlLayerWindow(self, layer):
|
||||||
|
from dlg_sql_layer_window import DlgSqlLayerWindow
|
||||||
|
query = DlgSqlLayerWindow(self.iface, layer, self)
|
||||||
|
lname = layer.name()
|
||||||
|
tabname = self.tr("Layer") + u" (%s)" % lname
|
||||||
|
index = self.tabs.addTab(query, tabname)
|
||||||
|
#self.tabs.setTabIcon(index, db.connection().icon())
|
||||||
|
self.tabs.setCurrentIndex(index)
|
||||||
|
|
||||||
def update_query_tab_name(self, index, dbname, queryname):
|
def update_query_tab_name(self, index, dbname, queryname):
|
||||||
if not queryname:
|
if not queryname:
|
||||||
queryname = self.tr("Query")
|
queryname = self.tr("Query")
|
||||||
|
@ -24,6 +24,9 @@ from qgis.PyQt.QtCore import Qt
|
|||||||
from qgis.PyQt.QtWidgets import QAction, QApplication
|
from qgis.PyQt.QtWidgets import QAction, QApplication
|
||||||
from qgis.PyQt.QtGui import QIcon
|
from qgis.PyQt.QtGui import QIcon
|
||||||
|
|
||||||
|
from qgis.core import QgsMapLayerRegistry, QgsMapLayer, QgsDataSourceURI
|
||||||
|
import re
|
||||||
|
|
||||||
from . import resources_rc # NOQA
|
from . import resources_rc # NOQA
|
||||||
|
|
||||||
|
|
||||||
@ -48,6 +51,15 @@ class DBManagerPlugin:
|
|||||||
else:
|
else:
|
||||||
self.iface.addPluginToMenu(QApplication.translate("DBManagerPlugin", "DB Manager"), self.action)
|
self.iface.addPluginToMenu(QApplication.translate("DBManagerPlugin", "DB Manager"), self.action)
|
||||||
|
|
||||||
|
self.layerAction = QAction(QIcon(":/db_manager/icon"), QApplication.translate("DBManagerPlugin", "Update Sql Layer"),
|
||||||
|
self.iface.mainWindow())
|
||||||
|
self.layerAction.setObjectName("dbManagerUpdateSqlLayer")
|
||||||
|
QObject.connect(self.layerAction, SIGNAL("triggered()"), self.onUpdateSqlLayer)
|
||||||
|
self.iface.legendInterface().addLegendLayerAction(self.layerAction, "", "dbManagerUpdateSqlLayer", QgsMapLayer.VectorLayer, False)
|
||||||
|
for l in QgsMapLayerRegistry.instance().mapLayers().values():
|
||||||
|
self.onLayerWasAdded(l)
|
||||||
|
QgsMapLayerRegistry.instance().layerWasAdded.connect(self.onLayerWasAdded)
|
||||||
|
|
||||||
def unload(self):
|
def unload(self):
|
||||||
# Remove the plugin menu item and icon
|
# Remove the plugin menu item and icon
|
||||||
if hasattr(self.iface, 'removePluginDatabaseMenu'):
|
if hasattr(self.iface, 'removePluginDatabaseMenu'):
|
||||||
@ -59,9 +71,36 @@ class DBManagerPlugin:
|
|||||||
else:
|
else:
|
||||||
self.iface.removeToolBarIcon(self.action)
|
self.iface.removeToolBarIcon(self.action)
|
||||||
|
|
||||||
|
self.iface.legendInterface().removeLegendLayerAction(self.layerAction)
|
||||||
|
QgsMapLayerRegistry.instance().layerWasAdded.disconnect(self.onLayerWasAdded)
|
||||||
|
|
||||||
if self.dlg is not None:
|
if self.dlg is not None:
|
||||||
self.dlg.close()
|
self.dlg.close()
|
||||||
|
|
||||||
|
def onLayerWasAdded(self, aMapLayer):
|
||||||
|
if aMapLayer.dataProvider().name() in ['postgres', 'spatialite', 'oracle']:
|
||||||
|
uri = QgsDataSourceURI(aMapLayer.source())
|
||||||
|
if re.search('^\(SELECT .+ FROM .+\)$', uri.table(), re.S):
|
||||||
|
self.iface.legendInterface().addLegendLayerActionForLayer(self.layerAction, aMapLayer)
|
||||||
|
# virtual has QUrl source
|
||||||
|
# url = QUrl(QUrl.fromPercentEncoding(l.source()))
|
||||||
|
# url.queryItemValue('query')
|
||||||
|
# url.queryItemValue('uid')
|
||||||
|
# url.queryItemValue('geometry')
|
||||||
|
|
||||||
|
def onUpdateSqlLayer(self):
|
||||||
|
l = self.iface.legendInterface().currentLayer()
|
||||||
|
if l.dataProvider().name() in ['postgres', 'spatialite', 'oracle']:
|
||||||
|
uri = QgsDataSourceURI(l.source())
|
||||||
|
if re.search('^\(SELECT .+ FROM .+\)$', uri.table(), re.S):
|
||||||
|
self.run()
|
||||||
|
self.dlg.runSqlLayerWindow(l)
|
||||||
|
# virtual has QUrl source
|
||||||
|
# url = QUrl(QUrl.fromPercentEncoding(l.source()))
|
||||||
|
# url.queryItemValue('query')
|
||||||
|
# url.queryItemValue('uid')
|
||||||
|
# url.queryItemValue('geometry')
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# keep opened only one instance
|
# keep opened only one instance
|
||||||
if self.dlg is None:
|
if self.dlg is None:
|
||||||
|
530
python/plugins/db_manager/dlg_sql_layer_window.py
Normal file
530
python/plugins/db_manager/dlg_sql_layer_window.py
Normal file
@ -0,0 +1,530 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
/***************************************************************************
|
||||||
|
Name : DB Manager
|
||||||
|
Description : Database manager plugin for QGIS
|
||||||
|
Date : May 23, 2011
|
||||||
|
copyright : (C) 2011 by Giuseppe Sucameli
|
||||||
|
email : brush.tyler@gmail.com
|
||||||
|
|
||||||
|
The content of this file is based on
|
||||||
|
- PG_Manager by Martin Dobias (GPLv2 license)
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* 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. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PyQt4.QtCore import Qt, QObject, QSettings, QByteArray, SIGNAL, pyqtSignal
|
||||||
|
from PyQt4.QtGui import QDialog, QWidget, QAction, QKeySequence, \
|
||||||
|
QDialogButtonBox, QApplication, QCursor, QMessageBox, QClipboard, QInputDialog, QIcon, QStyledItemDelegate, QStandardItemModel, QStandardItem
|
||||||
|
from PyQt4.Qsci import QsciAPIs
|
||||||
|
from PyQt4.QtXml import QDomDocument
|
||||||
|
|
||||||
|
from qgis.core import QgsProject, QgsDataSourceURI
|
||||||
|
|
||||||
|
from .db_plugins import createDbPlugin
|
||||||
|
from .db_plugins.plugin import BaseError
|
||||||
|
from .db_plugins.postgis.plugin import PGDatabase
|
||||||
|
from .dlg_db_error import DlgDbError
|
||||||
|
from .dlg_query_builder import QueryBuilderDlg
|
||||||
|
|
||||||
|
try:
|
||||||
|
from qgis.gui import QgsCodeEditorSQL
|
||||||
|
except:
|
||||||
|
from .sqledit import SqlEdit
|
||||||
|
from qgis import gui
|
||||||
|
|
||||||
|
gui.QgsCodeEditorSQL = SqlEdit
|
||||||
|
|
||||||
|
from .ui.ui_DlgSqlLayerWindow import Ui_DbManagerDlgSqlLayerWindow as Ui_Dialog
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
class DlgSqlLayerWindow(QWidget, Ui_Dialog):
|
||||||
|
nameChanged = pyqtSignal(str)
|
||||||
|
|
||||||
|
def __init__(self, iface, layer, parent=None):
|
||||||
|
QWidget.__init__(self, parent)
|
||||||
|
self.iface = iface
|
||||||
|
self.layer = layer
|
||||||
|
|
||||||
|
uri = QgsDataSourceURI(layer.source())
|
||||||
|
dbplugin = None
|
||||||
|
db = None
|
||||||
|
if layer.dataProvider().name() == 'postgres':
|
||||||
|
dbplugin = createDbPlugin('postgis', 'postgres')
|
||||||
|
elif layer.dataProvider().name() == 'spatialite':
|
||||||
|
dbplugin = createDbPlugin('spatialite', 'spatialite')
|
||||||
|
elif layer.dataProvider().name() == 'oracle':
|
||||||
|
dbplugin = createDbPlugin('oracle', 'oracle')
|
||||||
|
elif layer.dataProvider().name() == 'virtual':
|
||||||
|
dbplugin = createDbPlugin('vlayers', 'virtual')
|
||||||
|
if dbplugin:
|
||||||
|
dbplugin.connectToUri(uri)
|
||||||
|
db = dbplugin.db
|
||||||
|
|
||||||
|
self.dbplugin = dbplugin
|
||||||
|
self.db = db
|
||||||
|
self.filter = ""
|
||||||
|
self.allowMultiColumnPk = isinstance(db, PGDatabase) # at the moment only PostgreSQL allows a primary key to span multiple columns, spatialite doesn't
|
||||||
|
self.aliasSubQuery = isinstance(db, PGDatabase) # only PostgreSQL requires subqueries to be aliases
|
||||||
|
self.setupUi(self)
|
||||||
|
self.setWindowTitle(
|
||||||
|
u"%s - %s [%s]" % (self.windowTitle(), db.connection().connectionName(), db.connection().typeNameString()))
|
||||||
|
|
||||||
|
self.defaultLayerName = 'QueryLayer'
|
||||||
|
|
||||||
|
if self.allowMultiColumnPk:
|
||||||
|
self.uniqueColumnCheck.setText(self.trUtf8("Column(s) with unique values"))
|
||||||
|
else:
|
||||||
|
self.uniqueColumnCheck.setText(self.trUtf8("Column with unique values"))
|
||||||
|
|
||||||
|
self.editSql.setFocus()
|
||||||
|
self.editSql.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||||
|
self.editSql.setMarginVisible(True)
|
||||||
|
self.initCompleter()
|
||||||
|
|
||||||
|
# allow copying results
|
||||||
|
copyAction = QAction("copy", self)
|
||||||
|
self.viewResult.addAction(copyAction)
|
||||||
|
copyAction.setShortcuts(QKeySequence.Copy)
|
||||||
|
|
||||||
|
copyAction.triggered.connect(self.copySelectedResults)
|
||||||
|
|
||||||
|
self.btnExecute.clicked.connect(self.executeSql)
|
||||||
|
self.btnSetFilter.clicked.connect(self.setFilter)
|
||||||
|
self.btnClear.clicked.connect(self.clearSql)
|
||||||
|
|
||||||
|
self.presetStore.clicked.connect(self.storePreset)
|
||||||
|
self.presetDelete.clicked.connect(self.deletePreset)
|
||||||
|
self.presetCombo.activated[str].connect(self.loadPreset)
|
||||||
|
self.presetCombo.activated[str].connect(self.presetName.setText)
|
||||||
|
|
||||||
|
self.updatePresetsCombobox()
|
||||||
|
|
||||||
|
self.geomCombo.setEditable(True)
|
||||||
|
self.geomCombo.lineEdit().setReadOnly(True)
|
||||||
|
|
||||||
|
self.uniqueCombo.setEditable(True)
|
||||||
|
self.uniqueCombo.lineEdit().setReadOnly(True)
|
||||||
|
self.uniqueModel = QStandardItemModel(self.uniqueCombo)
|
||||||
|
self.uniqueCombo.setModel(self.uniqueModel)
|
||||||
|
if self.allowMultiColumnPk:
|
||||||
|
self.uniqueCombo.setItemDelegate(QStyledItemDelegate())
|
||||||
|
self.uniqueModel.itemChanged.connect(self.uniqueChanged) # react to the (un)checking of an item
|
||||||
|
self.uniqueCombo.lineEdit().textChanged.connect(self.uniqueTextChanged) # there are other events that change the displayed text and some of them can not be caught directly
|
||||||
|
|
||||||
|
self.layerTypeWidget.hide() # show if load as raster is supported
|
||||||
|
#self.loadLayerBtn.clicked.connect(self.loadSqlLayer)
|
||||||
|
self.updateLayerBtn.clicked.connect(self.updateSqlLayer)
|
||||||
|
self.getColumnsBtn.clicked.connect(self.fillColumnCombos)
|
||||||
|
|
||||||
|
self.queryBuilderFirst = True
|
||||||
|
self.queryBuilderBtn.setIcon(QIcon(":/db_manager/icons/sql.gif"))
|
||||||
|
self.queryBuilderBtn.clicked.connect(self.displayQueryBuilder)
|
||||||
|
|
||||||
|
self.presetName.textChanged.connect(self.nameChanged)
|
||||||
|
|
||||||
|
# Update from layer
|
||||||
|
# Fisrtly the SQL from QgsDataSourceURI table
|
||||||
|
sql = uri.table()
|
||||||
|
if uri.keyColumn() == '_uid_':
|
||||||
|
match = re.search('^\(SELECT .+ AS _uid_,\* FROM \((.*)\) AS _subq_.+_\s*\)$', sql, re.S)
|
||||||
|
if match:
|
||||||
|
sql = match.group(1)
|
||||||
|
else:
|
||||||
|
match = re.search('^\((SELECT .+ FROM .+)\)$', sql, re.S)
|
||||||
|
if match:
|
||||||
|
sql = match.group(1)
|
||||||
|
self.editSql.setText(sql)
|
||||||
|
self.executeSql()
|
||||||
|
|
||||||
|
# Then the columns
|
||||||
|
self.geomCombo.setCurrentIndex(self.geomCombo.findText(uri.geometryColumn(), Qt.MatchExactly))
|
||||||
|
if uri.keyColumn() != '_uid_':
|
||||||
|
self.uniqueColumnCheck.setCheckState(Qt.Checked)
|
||||||
|
if self.allowMultiColumnPk:
|
||||||
|
itemsData = uri.keyColumn().split(',')
|
||||||
|
for item in self.uniqueModel.findItems("*", Qt.MatchWildcard):
|
||||||
|
if item.data() in itemsData:
|
||||||
|
item.setCheckState(Qt.Checked)
|
||||||
|
else:
|
||||||
|
keyColumn = uri.keyColumn()
|
||||||
|
for item in self.uniqueModel.findItems("*", Qt.MatchWildcard):
|
||||||
|
if item.data() == keyColumn:
|
||||||
|
self.uniqueCombo.setCurrentIndex(self.uniqueModel.indexFromItem(item).row())
|
||||||
|
|
||||||
|
# Finally layer name, filter and selectAtId
|
||||||
|
self.layerNameEdit.setText(layer.name())
|
||||||
|
self.filter = uri.sql()
|
||||||
|
if uri.selectAtIdDisabled():
|
||||||
|
self.avoidSelectById.setCheckState(Qt.Checked)
|
||||||
|
|
||||||
|
def updatePresetsCombobox(self):
|
||||||
|
self.presetCombo.clear()
|
||||||
|
|
||||||
|
names = []
|
||||||
|
entries = QgsProject.instance().subkeyList('DBManager', 'savedQueries')
|
||||||
|
for entry in entries:
|
||||||
|
name = QgsProject.instance().readEntry('DBManager', 'savedQueries/' + entry + '/name')[0]
|
||||||
|
names.append(name)
|
||||||
|
|
||||||
|
for name in sorted(names):
|
||||||
|
self.presetCombo.addItem(name)
|
||||||
|
self.presetCombo.setCurrentIndex(-1)
|
||||||
|
|
||||||
|
def storePreset(self):
|
||||||
|
query = self._getSqlQuery()
|
||||||
|
if query == "":
|
||||||
|
return
|
||||||
|
name = self.presetName.text()
|
||||||
|
QgsProject.instance().writeEntry('DBManager', 'savedQueries/q' + unicode(name.__hash__()) + '/name', name)
|
||||||
|
QgsProject.instance().writeEntry('DBManager', 'savedQueries/q' + unicode(name.__hash__()) + '/query', query)
|
||||||
|
index = self.presetCombo.findText(name)
|
||||||
|
if index == -1:
|
||||||
|
self.presetCombo.addItem(name)
|
||||||
|
self.presetCombo.setCurrentIndex(self.presetCombo.count() - 1)
|
||||||
|
else:
|
||||||
|
self.presetCombo.setCurrentIndex(index)
|
||||||
|
|
||||||
|
def deletePreset(self):
|
||||||
|
name = self.presetCombo.currentText()
|
||||||
|
QgsProject.instance().removeEntry('DBManager', 'savedQueries/q' + unicode(name.__hash__()))
|
||||||
|
self.presetCombo.removeItem(self.presetCombo.findText(name))
|
||||||
|
self.presetCombo.setCurrentIndex(-1)
|
||||||
|
|
||||||
|
def loadPreset(self, name):
|
||||||
|
query = QgsProject.instance().readEntry('DBManager', 'savedQueries/q' + unicode(name.__hash__()) + '/query')[0]
|
||||||
|
name = QgsProject.instance().readEntry('DBManager', 'savedQueries/q' + unicode(name.__hash__()) + '/name')[0]
|
||||||
|
self.editSql.setText(query)
|
||||||
|
|
||||||
|
def clearSql(self):
|
||||||
|
self.editSql.clear()
|
||||||
|
self.editSql.setFocus()
|
||||||
|
self.filter = ""
|
||||||
|
|
||||||
|
def executeSql(self):
|
||||||
|
|
||||||
|
sql = self._getSqlQuery()
|
||||||
|
if sql == "":
|
||||||
|
return
|
||||||
|
|
||||||
|
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||||
|
|
||||||
|
# delete the old model
|
||||||
|
old_model = self.viewResult.model()
|
||||||
|
self.viewResult.setModel(None)
|
||||||
|
if old_model:
|
||||||
|
old_model.deleteLater()
|
||||||
|
|
||||||
|
cols = []
|
||||||
|
quotedCols = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
# set the new model
|
||||||
|
model = self.db.sqlResultModel(sql, self)
|
||||||
|
self.viewResult.setModel(model)
|
||||||
|
self.lblResult.setText(self.tr("%d rows, %.1f seconds") % (model.affectedRows(), model.secs()))
|
||||||
|
cols = self.viewResult.model().columnNames()
|
||||||
|
for col in cols:
|
||||||
|
quotedCols.append(self.db.connector.quoteId(col))
|
||||||
|
|
||||||
|
except BaseError as e:
|
||||||
|
QApplication.restoreOverrideCursor()
|
||||||
|
DlgDbError.showError(e, self)
|
||||||
|
self.uniqueModel.clear()
|
||||||
|
self.geomCombo.clear()
|
||||||
|
return
|
||||||
|
|
||||||
|
self.setColumnCombos(cols, quotedCols)
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
QApplication.restoreOverrideCursor()
|
||||||
|
|
||||||
|
def _getSqlLayer(self, _filter):
|
||||||
|
hasUniqueField = self.uniqueColumnCheck.checkState() == Qt.Checked
|
||||||
|
if hasUniqueField:
|
||||||
|
if self.allowMultiColumnPk:
|
||||||
|
checkedCols = []
|
||||||
|
for item in self.uniqueModel.findItems("*", Qt.MatchWildcard):
|
||||||
|
if item.checkState() == Qt.Checked:
|
||||||
|
checkedCols.append(item.data())
|
||||||
|
uniqueFieldName = ",".join(checkedCols)
|
||||||
|
elif self.uniqueCombo.currentIndex() >= 0:
|
||||||
|
uniqueFieldName = self.uniqueModel.item(self.uniqueCombo.currentIndex()).data()
|
||||||
|
else:
|
||||||
|
uniqueFieldName = None
|
||||||
|
else:
|
||||||
|
uniqueFieldName = None
|
||||||
|
hasGeomCol = self.hasGeometryCol.checkState() == Qt.Checked
|
||||||
|
if hasGeomCol:
|
||||||
|
geomFieldName = self.geomCombo.currentText()
|
||||||
|
else:
|
||||||
|
geomFieldName = None
|
||||||
|
|
||||||
|
query = self._getSqlQuery()
|
||||||
|
if query == "":
|
||||||
|
return None
|
||||||
|
|
||||||
|
# remove a trailing ';' from query if present
|
||||||
|
if query.strip().endswith(';'):
|
||||||
|
query = query.strip()[:-1]
|
||||||
|
|
||||||
|
from qgis.core import QgsMapLayer, QgsMapLayerRegistry
|
||||||
|
|
||||||
|
layerType = QgsMapLayer.VectorLayer if self.vectorRadio.isChecked() else QgsMapLayer.RasterLayer
|
||||||
|
|
||||||
|
# get a new layer name
|
||||||
|
names = []
|
||||||
|
for layer in QgsMapLayerRegistry.instance().mapLayers().values():
|
||||||
|
names.append(layer.name())
|
||||||
|
|
||||||
|
layerName = self.layerNameEdit.text()
|
||||||
|
if layerName == "":
|
||||||
|
layerName = self.defaultLayerName
|
||||||
|
newLayerName = layerName
|
||||||
|
index = 1
|
||||||
|
while newLayerName in names:
|
||||||
|
index += 1
|
||||||
|
newLayerName = u"%s_%d" % (layerName, index)
|
||||||
|
|
||||||
|
# create the layer
|
||||||
|
layer = self.db.toSqlLayer(query, geomFieldName, uniqueFieldName, newLayerName, layerType,
|
||||||
|
self.avoidSelectById.isChecked(), _filter)
|
||||||
|
if layer.isValid():
|
||||||
|
return layer
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def loadSqlLayer(self):
|
||||||
|
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||||
|
try:
|
||||||
|
layer = self._getSqlLayer(self.filter)
|
||||||
|
if layer == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
from qgis.core import QgsMapLayerRegistry
|
||||||
|
QgsMapLayerRegistry.instance().addMapLayers([layer], True)
|
||||||
|
finally:
|
||||||
|
QApplication.restoreOverrideCursor()
|
||||||
|
|
||||||
|
def updateSqlLayer(self):
|
||||||
|
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||||
|
try:
|
||||||
|
layer = self._getSqlLayer(self.filter)
|
||||||
|
if layer == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
#self.layer.dataProvider().setDataSourceUri(layer.dataProvider().dataSourceUri())
|
||||||
|
#self.layer.dataProvider().reloadData()
|
||||||
|
XMLDocument = QDomDocument("style")
|
||||||
|
XMLMapLayers = XMLDocument.createElement("maplayers")
|
||||||
|
XMLMapLayer = XMLDocument.createElement("maplayer")
|
||||||
|
self.layer.writeLayerXML(XMLMapLayer, XMLDocument)
|
||||||
|
XMLMapLayer.firstChildElement("datasource").firstChild().setNodeValue(layer.source())
|
||||||
|
XMLMapLayers.appendChild(XMLMapLayer)
|
||||||
|
XMLDocument.appendChild(XMLMapLayers)
|
||||||
|
self.layer.readLayerXML(XMLMapLayer)
|
||||||
|
self.layer.reload()
|
||||||
|
self.iface.actionDraw().trigger()
|
||||||
|
self.iface.mapCanvas().refresh()
|
||||||
|
self.iface.legendInterface().refreshLayerSymbology(layer)
|
||||||
|
finally:
|
||||||
|
QApplication.restoreOverrideCursor()
|
||||||
|
|
||||||
|
def fillColumnCombos(self):
|
||||||
|
query = self._getSqlQuery()
|
||||||
|
if query == "":
|
||||||
|
return
|
||||||
|
|
||||||
|
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
|
||||||
|
|
||||||
|
# remove a trailing ';' from query if present
|
||||||
|
if query.strip().endswith(';'):
|
||||||
|
query = query.strip()[:-1]
|
||||||
|
|
||||||
|
# get all the columns
|
||||||
|
cols = []
|
||||||
|
quotedCols = []
|
||||||
|
connector = self.db.connector
|
||||||
|
if self.aliasSubQuery:
|
||||||
|
# get a new alias
|
||||||
|
aliasIndex = 0
|
||||||
|
while True:
|
||||||
|
alias = "_subQuery__%d" % aliasIndex
|
||||||
|
escaped = re.compile('\\b("?)' + re.escape(alias) + '\\1\\b')
|
||||||
|
if not escaped.search(query):
|
||||||
|
break
|
||||||
|
aliasIndex += 1
|
||||||
|
|
||||||
|
sql = u"SELECT * FROM (%s\n) AS %s LIMIT 0" % (unicode(query), connector.quoteId(alias))
|
||||||
|
else:
|
||||||
|
sql = u"SELECT * FROM (%s\n) WHERE 1=0" % unicode(query)
|
||||||
|
|
||||||
|
c = None
|
||||||
|
try:
|
||||||
|
c = connector._execute(None, sql)
|
||||||
|
cols = connector._get_cursor_columns(c)
|
||||||
|
for col in cols:
|
||||||
|
quotedCols.append(connector.quoteId(col))
|
||||||
|
|
||||||
|
except BaseError as e:
|
||||||
|
QApplication.restoreOverrideCursor()
|
||||||
|
DlgDbError.showError(e, self)
|
||||||
|
self.uniqueModel.clear()
|
||||||
|
self.geomCombo.clear()
|
||||||
|
return
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if c:
|
||||||
|
c.close()
|
||||||
|
del c
|
||||||
|
|
||||||
|
self.setColumnCombos(cols, quotedCols)
|
||||||
|
|
||||||
|
QApplication.restoreOverrideCursor()
|
||||||
|
|
||||||
|
def setColumnCombos(self, cols, quotedCols):
|
||||||
|
# get sensible default columns. do this before sorting in case there's hints in the column order (eg, id is more likely to be first)
|
||||||
|
try:
|
||||||
|
defaultGeomCol = next(col for col in cols if col in ['geom', 'geometry', 'the_geom', 'way'])
|
||||||
|
except:
|
||||||
|
defaultGeomCol = None
|
||||||
|
try:
|
||||||
|
defaultUniqueCol = [col for col in cols if 'id' in col][0]
|
||||||
|
except:
|
||||||
|
defaultUniqueCol = None
|
||||||
|
|
||||||
|
colNames = sorted(zip(cols, quotedCols))
|
||||||
|
newItems = []
|
||||||
|
uniqueIsFilled = False
|
||||||
|
for (col, quotedCol) in colNames:
|
||||||
|
item = QStandardItem(col)
|
||||||
|
item.setData(quotedCol)
|
||||||
|
item.setEnabled(True)
|
||||||
|
item.setCheckable(self.allowMultiColumnPk)
|
||||||
|
item.setSelectable(not self.allowMultiColumnPk)
|
||||||
|
if self.allowMultiColumnPk:
|
||||||
|
matchingItems = self.uniqueModel.findItems(col)
|
||||||
|
if matchingItems:
|
||||||
|
item.setCheckState(matchingItems[0].checkState())
|
||||||
|
uniqueIsFilled = uniqueIsFilled or matchingItems[0].checkState() == Qt.Checked
|
||||||
|
else:
|
||||||
|
item.setCheckState(Qt.Unchecked)
|
||||||
|
newItems.append(item)
|
||||||
|
if self.allowMultiColumnPk:
|
||||||
|
self.uniqueModel.clear()
|
||||||
|
self.uniqueModel.appendColumn(newItems)
|
||||||
|
self.uniqueChanged()
|
||||||
|
else:
|
||||||
|
previousUniqueColumn = self.uniqueCombo.currentText()
|
||||||
|
self.uniqueModel.clear()
|
||||||
|
self.uniqueModel.appendColumn(newItems)
|
||||||
|
if self.uniqueModel.findItems(previousUniqueColumn):
|
||||||
|
self.uniqueCombo.setEditText(previousUniqueColumn)
|
||||||
|
uniqueIsFilled = True
|
||||||
|
|
||||||
|
oldGeometryColumn = self.geomCombo.currentText()
|
||||||
|
self.geomCombo.clear()
|
||||||
|
self.geomCombo.addItems(cols)
|
||||||
|
self.geomCombo.setCurrentIndex(self.geomCombo.findText(oldGeometryColumn, Qt.MatchExactly))
|
||||||
|
|
||||||
|
# set sensible default columns if the columns are not already set
|
||||||
|
try:
|
||||||
|
if self.geomCombo.currentIndex() == -1:
|
||||||
|
self.geomCombo.setCurrentIndex(cols.index(defaultGeomCol))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
items = self.uniqueModel.findItems(defaultUniqueCol)
|
||||||
|
if items and not uniqueIsFilled:
|
||||||
|
if self.allowMultiColumnPk:
|
||||||
|
items[0].setCheckState(Qt.Checked)
|
||||||
|
else:
|
||||||
|
self.uniqueCombo.setEditText(defaultUniqueCol)
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def copySelectedResults(self):
|
||||||
|
if len(self.viewResult.selectedIndexes()) <= 0:
|
||||||
|
return
|
||||||
|
model = self.viewResult.model()
|
||||||
|
|
||||||
|
# convert to string using tab as separator
|
||||||
|
text = model.headerToString("\t")
|
||||||
|
for idx in self.viewResult.selectionModel().selectedRows():
|
||||||
|
text += "\n" + model.rowToString(idx.row(), "\t")
|
||||||
|
|
||||||
|
QApplication.clipboard().setText(text, QClipboard.Selection)
|
||||||
|
QApplication.clipboard().setText(text, QClipboard.Clipboard)
|
||||||
|
|
||||||
|
def initCompleter(self):
|
||||||
|
dictionary = None
|
||||||
|
if self.db:
|
||||||
|
dictionary = self.db.connector.getSqlDictionary()
|
||||||
|
if not dictionary:
|
||||||
|
# use the generic sql dictionary
|
||||||
|
from .sql_dictionary import getSqlDictionary
|
||||||
|
|
||||||
|
dictionary = getSqlDictionary()
|
||||||
|
|
||||||
|
wordlist = []
|
||||||
|
for name, value in dictionary.iteritems():
|
||||||
|
wordlist += value # concat lists
|
||||||
|
wordlist = list(set(wordlist)) # remove duplicates
|
||||||
|
|
||||||
|
api = QsciAPIs(self.editSql.lexer())
|
||||||
|
for word in wordlist:
|
||||||
|
api.add(word)
|
||||||
|
|
||||||
|
api.prepare()
|
||||||
|
self.editSql.lexer().setAPIs(api)
|
||||||
|
|
||||||
|
def displayQueryBuilder(self):
|
||||||
|
dlg = QueryBuilderDlg(self.iface, self.db, self, reset=self.queryBuilderFirst)
|
||||||
|
self.queryBuilderFirst = False
|
||||||
|
r = dlg.exec_()
|
||||||
|
if r == QDialog.Accepted:
|
||||||
|
self.editSql.setText(dlg.query)
|
||||||
|
|
||||||
|
def _getSqlQuery(self):
|
||||||
|
sql = self.editSql.selectedText()
|
||||||
|
if len(sql) == 0:
|
||||||
|
sql = self.editSql.text()
|
||||||
|
return sql
|
||||||
|
|
||||||
|
def uniqueChanged(self):
|
||||||
|
# when an item is (un)checked, simply trigger an update of the combobox text
|
||||||
|
self.uniqueTextChanged(None)
|
||||||
|
|
||||||
|
def uniqueTextChanged(self, text):
|
||||||
|
# Whenever there is new text displayed in the combobox, check if it is the correct one and if not, display the correct one.
|
||||||
|
checkedItems = []
|
||||||
|
for item in self.uniqueModel.findItems("*", Qt.MatchWildcard):
|
||||||
|
if item.checkState() == Qt.Checked:
|
||||||
|
checkedItems.append(item.text())
|
||||||
|
label = ", ".join(checkedItems)
|
||||||
|
if text != label:
|
||||||
|
self.uniqueCombo.setEditText(label)
|
||||||
|
|
||||||
|
def setFilter(self):
|
||||||
|
from qgis.gui import QgsQueryBuilder
|
||||||
|
layer = self._getSqlLayer("")
|
||||||
|
if not layer:
|
||||||
|
return
|
||||||
|
|
||||||
|
dlg = QgsQueryBuilder(layer)
|
||||||
|
dlg.setSql(self.filter)
|
||||||
|
if dlg.exec_():
|
||||||
|
self.filter = dlg.sql()
|
||||||
|
layer.deleteLater()
|
407
python/plugins/db_manager/ui/DlgSqlLayerWindow.ui
Normal file
407
python/plugins/db_manager/ui/DlgSqlLayerWindow.ui
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DbManagerDlgSqlLayerWindow</class>
|
||||||
|
<widget class="QDialog" name="DbManagerDlgSqlLayerWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>662</width>
|
||||||
|
<height>525</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>SQL window</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="3" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="avoidSelectById">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Avoid selecting feature by id. Sometimes - especially when running expensive queries/views - fetching the data sequentially instead of fetching features by id can be much quicker.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Avoid selecting by feature id</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="updateLayerBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Update</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="layoutWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="queryBuilderBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Saved query:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="presetCombo"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="presetName">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="presetStore">
|
||||||
|
<property name="text">
|
||||||
|
<string>Store</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="presetDelete">
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QgsCodeEditorSQL" name="editSql"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnExecute">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Execute (F5)</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>F5</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="lblResult">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnClear">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Clear</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="layoutWidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="viewResult">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>3</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollMode">
|
||||||
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="uniqueColumnCheck">
|
||||||
|
<property name="text">
|
||||||
|
<string>Column(s) with
|
||||||
|
unique values</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="uniqueCombo">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="insertPolicy">
|
||||||
|
<enum>QComboBox::NoInsert</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="hasGeometryCol">
|
||||||
|
<property name="text">
|
||||||
|
<string>Geometry column</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="geomCombo">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="editable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="insertPolicy">
|
||||||
|
<enum>QComboBox::NoInsert</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_5">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="getColumnsBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Retrieve
|
||||||
|
columns</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Layer name (prefix)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="layerNameEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="layerTypeWidget" native="true">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Type</string>
|
||||||
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>40</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="vectorRadio">
|
||||||
|
<property name="text">
|
||||||
|
<string>Vector</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="rasterRadio">
|
||||||
|
<property name="text">
|
||||||
|
<string>Raster</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_6">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnSetFilter">
|
||||||
|
<property name="text">
|
||||||
|
<string>Set filter</string>
|
||||||
|
</property>
|
||||||
|
<property name="autoDefault">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>QgsCodeEditorSQL</class>
|
||||||
|
<extends>QTextEdit</extends>
|
||||||
|
<header>qgis.gui</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>btnExecute</tabstop>
|
||||||
|
<tabstop>btnClear</tabstop>
|
||||||
|
<tabstop>viewResult</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>hasGeometryCol</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>geomCombo</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>379</x>
|
||||||
|
<y>385</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>525</x>
|
||||||
|
<y>385</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>uniqueColumnCheck</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>uniqueCombo</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>109</x>
|
||||||
|
<y>385</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>274</x>
|
||||||
|
<y>385</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
Loading…
x
Reference in New Issue
Block a user