123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 |
- """
- /***************************************************************************
- 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 hashlib import md5
- import os
- from qgis.PyQt.QtCore import Qt, pyqtSignal, QDir, QCoreApplication
- from qgis.PyQt.QtWidgets import (QDialog,
- QWidget,
- QAction,
- QApplication,
- QInputDialog,
- QStyledItemDelegate,
- QTableWidgetItem,
- QFileDialog,
- QMessageBox
- )
- from qgis.PyQt.QtGui import (QKeySequence,
- QCursor,
- QClipboard,
- QIcon,
- QStandardItemModel,
- QStandardItem
- )
- from qgis.PyQt.Qsci import QsciAPIs, QsciScintilla
- from qgis.core import (
- QgsProject,
- QgsApplication,
- QgsTask,
- QgsSettings,
- QgsMapLayerType
- )
- from qgis.utils import OverrideCursor
- 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 # NOQA
- except:
- from .sqledit import SqlEdit
- from qgis import gui
- gui.QgsCodeEditorSQL = SqlEdit
- from .ui.ui_DlgSqlWindow import Ui_DbManagerDlgSqlWindow as Ui_Dialog
- import re
- def check_comments_in_sql(raw_sql_input):
- lines = []
- for line in raw_sql_input.splitlines():
- if not line.strip().startswith('--'):
- if '--' in line:
- comments = re.finditer(r'--', line)
- comment_positions = [
- match.start()
- for match in comments
- ]
- identifiers = re.finditer(r'"(?:[^"]|"")*"', line)
- quotes = re.finditer(r"'(?:[^']|'')*'", line)
- quote_positions = []
- for match in identifiers:
- quote_positions.append((match.start(), match.end()))
- for match in quotes:
- quote_positions.append((match.start(), match.end()))
- unquoted_comments = comment_positions.copy()
- for comment in comment_positions:
- for quote_position in quote_positions:
- if comment >= quote_position[0] and comment < quote_position[1]:
- unquoted_comments.remove(comment)
- if len(unquoted_comments) > 0:
- lines.append(line[:unquoted_comments[0]])
- else:
- lines.append(line)
- else:
- lines.append(line)
- sql = ' '.join(lines)
- return sql.strip()
- class DlgSqlWindow(QWidget, Ui_Dialog):
- nameChanged = pyqtSignal(str)
- QUERY_HISTORY_LIMIT = 20
- hasChanged = False
- def __init__(self, iface, db, parent=None):
- QWidget.__init__(self, parent)
- self.mainWindow = parent
- self.iface = iface
- self.db = db
- self.dbType = db.connection().typeNameString()
- self.connectionName = db.connection().connectionName()
- self.filter = ""
- self.modelAsync = None
- 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(
- self.tr("{0} - {1} [{2}]").format(self.windowTitle(), self.connectionName, self.dbType))
- self.defaultLayerName = self.tr('QueryLayer')
- if self.allowMultiColumnPk:
- self.uniqueColumnCheck.setText(self.tr("Column(s) with unique values"))
- else:
- self.uniqueColumnCheck.setText(self.tr("Column with unique values"))
- self.editSql.setFocus()
- self.editSql.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
- self.editSql.setLineNumbersVisible(True)
- self.initCompleter()
- self.editSql.textChanged.connect(lambda: self.setHasChanged(True))
- settings = QgsSettings()
- self.history = settings.value('DB_Manager/queryHistory/' + self.dbType, {self.connectionName: []})
- if self.connectionName not in self.history:
- self.history[self.connectionName] = []
- self.queryHistoryWidget.setVisible(False)
- self.queryHistoryTableWidget.verticalHeader().hide()
- self.queryHistoryTableWidget.doubleClicked.connect(self.insertQueryInEditor)
- self.populateQueryHistory()
- self.btnQueryHistory.toggled.connect(self.showHideQueryHistory)
- self.btnCancel.setEnabled(False)
- self.btnCancel.clicked.connect(self.executeSqlCanceled)
- self.btnCancel.setShortcut(QKeySequence.Cancel)
- self.progressBar.setEnabled(False)
- self.progressBar.setRange(0, 100)
- self.progressBar.setValue(0)
- self.progressBar.setFormat("")
- self.progressBar.setAlignment(Qt.AlignCenter)
- # 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.presetSaveAsFile.clicked.connect(self.saveAsFilePreset)
- self.presetLoadFile.clicked.connect(self.loadFilePreset)
- 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
- # hide the load query as layer if feature is not supported
- self._loadAsLayerAvailable = self.db.connector.hasCustomQuerySupport()
- self.loadAsLayerGroup.setVisible(self._loadAsLayerAvailable)
- if self._loadAsLayerAvailable:
- self.layerTypeWidget.hide() # show if load as raster is supported
- self.loadLayerBtn.clicked.connect(self.loadSqlLayer)
- self.getColumnsBtn.clicked.connect(self.fillColumnCombos)
- self.loadAsLayerGroup.toggled.connect(self.loadAsLayerToggled)
- self.loadAsLayerToggled(False)
- self._createViewAvailable = self.db.connector.hasCreateSpatialViewSupport()
- self.btnCreateView.setVisible(self._createViewAvailable)
- if self._createViewAvailable:
- self.btnCreateView.clicked.connect(self.createView)
- self.queryBuilderFirst = True
- self.queryBuilderBtn.setIcon(QIcon(":/db_manager/icons/sql.gif"))
- self.queryBuilderBtn.clicked.connect(self.displayQueryBuilder)
- self.presetName.textChanged.connect(self.nameChanged)
- def insertQueryInEditor(self, item):
- sql = item.data(Qt.DisplayRole)
- self.editSql.insertText(sql)
- def showHideQueryHistory(self, visible):
- self.queryHistoryWidget.setVisible(visible)
- def populateQueryHistory(self):
- self.queryHistoryTableWidget.clearContents()
- self.queryHistoryTableWidget.setRowCount(0)
- dictlist = self.history[self.connectionName]
- if not dictlist:
- return
- for i in range(len(dictlist)):
- self.queryHistoryTableWidget.insertRow(0)
- queryItem = QTableWidgetItem(dictlist[i]['query'])
- rowsItem = QTableWidgetItem(str(dictlist[i]['rows']))
- durationItem = QTableWidgetItem(str(dictlist[i]['secs']))
- self.queryHistoryTableWidget.setItem(0, 0, queryItem)
- self.queryHistoryTableWidget.setItem(0, 1, rowsItem)
- self.queryHistoryTableWidget.setItem(0, 2, durationItem)
- self.queryHistoryTableWidget.resizeColumnsToContents()
- self.queryHistoryTableWidget.resizeRowsToContents()
- def writeQueryHistory(self, sql, affectedRows, secs):
- if len(self.history[self.connectionName]) >= self.QUERY_HISTORY_LIMIT:
- self.history[self.connectionName].pop(0)
- settings = QgsSettings()
- self.history[self.connectionName].append({'query': sql,
- 'rows': affectedRows,
- 'secs': secs})
- settings.setValue('DB_Manager/queryHistory/' + self.dbType, self.history)
- self.populateQueryHistory()
- def getQueryHash(self, name):
- return 'q%s' % md5(name.encode('utf8')).hexdigest()
- 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 = str(self.presetName.text())
- QgsProject.instance().writeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/name', name)
- QgsProject.instance().writeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/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 saveAsFilePreset(self):
- settings = QgsSettings()
- lastDir = settings.value('DB_Manager/lastDirSQLFIle', "")
- query = self.editSql.text()
- if query == "":
- return
- filename, _ = QFileDialog.getSaveFileName(
- self,
- self.tr('Save SQL Query'),
- lastDir,
- self.tr("SQL File (*.sql *.SQL)"))
- if filename:
- if not filename.lower().endswith('.sql'):
- filename += ".sql"
- with open(filename, 'w') as f:
- f.write(query)
- lastDir = os.path.dirname(filename)
- settings.setValue('DB_Manager/lastDirSQLFile', lastDir)
- def loadFilePreset(self):
- settings = QgsSettings()
- lastDir = settings.value('DB_Manager/lastDirSQLFIle', "")
- filename, _ = QFileDialog.getOpenFileName(
- self,
- self.tr("Load SQL Query"),
- lastDir,
- self.tr("SQL File (*.sql *.SQL);;All Files (*)"))
- if filename:
- with open(filename) as f:
- self.editSql.clear()
- for line in f:
- self.editSql.insertText(line)
- lastDir = os.path.dirname(filename)
- settings.setValue('DB_Manager/lastDirSQLFile', lastDir)
- def deletePreset(self):
- name = self.presetCombo.currentText()
- QgsProject.instance().removeEntry('DBManager', 'savedQueries/' + self.getQueryHash(name))
- self.presetCombo.removeItem(self.presetCombo.findText(name))
- self.presetCombo.setCurrentIndex(-1)
- def loadPreset(self, name):
- query = QgsProject.instance().readEntry('DBManager', 'savedQueries/' + self.getQueryHash(name) + '/query')[0]
- self.editSql.setText(query)
- def loadAsLayerToggled(self, checked):
- self.loadAsLayerGroup.setChecked(checked)
- self.loadAsLayerWidget.setVisible(checked)
- if checked:
- self.fillColumnCombos()
- def clearSql(self):
- self.editSql.clear()
- self.editSql.setFocus()
- self.filter = ""
- self.setHasChanged(True)
- def updateUiWhileSqlExecution(self, status):
- if status:
- for i in range(0, self.mainWindow.tabs.count()):
- if i != self.mainWindow.tabs.currentIndex():
- self.mainWindow.tabs.setTabEnabled(i, False)
- self.mainWindow.menuBar.setEnabled(False)
- self.mainWindow.toolBar.setEnabled(False)
- self.mainWindow.tree.setEnabled(False)
- for w in self.findChildren(QWidget):
- w.setEnabled(False)
- self.btnCancel.setEnabled(True)
- self.progressBar.setEnabled(True)
- self.progressBar.setRange(0, 0)
- else:
- for i in range(0, self.mainWindow.tabs.count()):
- if i != self.mainWindow.tabs.currentIndex():
- self.mainWindow.tabs.setTabEnabled(i, True)
- self.mainWindow.refreshTabs()
- self.mainWindow.menuBar.setEnabled(True)
- self.mainWindow.toolBar.setEnabled(True)
- self.mainWindow.tree.setEnabled(True)
- for w in self.findChildren(QWidget):
- w.setEnabled(True)
- self.btnCancel.setEnabled(False)
- self.progressBar.setRange(0, 100)
- self.progressBar.setEnabled(False)
- def executeSqlCanceled(self):
- self.btnCancel.setEnabled(False)
- self.btnCancel.setText(QCoreApplication.translate("DlgSqlWindow", "Canceling…"))
- self.modelAsync.cancel()
- def executeSqlCompleted(self):
- self.updateUiWhileSqlExecution(False)
- with OverrideCursor(Qt.WaitCursor):
- if self.modelAsync.task.status() == QgsTask.Complete:
- model = self.modelAsync.model
- self.showError(None)
- self.viewResult.setModel(model)
- self.lblResult.setText(self.tr("{0} rows, {1:.3f} seconds").format(model.affectedRows(), model.secs()))
- cols = self.viewResult.model().columnNames()
- quotedCols = [
- self.db.connector.quoteId(col)
- for col in cols
- ]
- self.setColumnCombos(cols, quotedCols)
- self.writeQueryHistory(self.modelAsync.task.sql, model.affectedRows(), model.secs())
- self.update()
- elif not self.modelAsync.canceled:
- self.showError(self.modelAsync.error)
- self.uniqueModel.clear()
- self.geomCombo.clear()
- self.btnCancel.setText(self.tr("Cancel"))
- def executeSql(self):
- sql = self._getExecutableSqlQuery()
- if sql == "":
- return
- # delete the old model
- old_model = self.viewResult.model()
- self.viewResult.setModel(None)
- if old_model:
- old_model.deleteLater()
- try:
- self.modelAsync = self.db.sqlResultModelAsync(sql, self)
- self.modelAsync.done.connect(self.executeSqlCompleted)
- self.updateUiWhileSqlExecution(True)
- QgsApplication.taskManager().addTask(self.modelAsync.task)
- except Exception as e:
- self.showError(e)
- self.uniqueModel.clear()
- self.geomCombo.clear()
- return
- def showError(self, error):
- '''Shows the error or hides it if error is None'''
- if error:
- self.viewResult.setVisible(False)
- self.errorText.setVisible(True)
- self.errorText.setText(error.msg)
- self.errorText.setWrapMode(QsciScintilla.WrapWord)
- else:
- self.viewResult.setVisible(True)
- self.errorText.setVisible(False)
- def _getSqlLayer(self, _filter):
- hasUniqueField = self.uniqueColumnCheck.checkState() == Qt.Checked
- if hasUniqueField and self.allowMultiColumnPk:
- uniqueFieldName = ",".join(
- item.data()
- for item in self.uniqueModel.findItems("*", Qt.MatchWildcard)
- if item.checkState() == Qt.Checked
- )
- elif (
- hasUniqueField
- and not self.allowMultiColumnPk
- and self.uniqueCombo.currentIndex() >= 0
- ):
- uniqueFieldName = self.uniqueModel.item(self.uniqueCombo.currentIndex()).data()
- else:
- uniqueFieldName = None
- hasGeomCol = self.hasGeometryCol.checkState() == Qt.Checked
- if hasGeomCol:
- geomFieldName = self.geomCombo.currentText()
- else:
- geomFieldName = None
- query = self._getExecutableSqlQuery()
- if query == "":
- return None
- # remove a trailing ';' from query if present
- if query.strip().endswith(';'):
- query = query.strip()[:-1]
- layerType = QgsMapLayerType.VectorLayer if self.vectorRadio.isChecked() else QgsMapLayerType.RasterLayer
- # get a new layer name
- names = []
- for layer in list(QgsProject.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 = "%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:
- e = BaseError(self.tr("There was an error creating the SQL layer, please check the logs for further information."))
- DlgDbError.showError(e, self)
- return None
- def loadSqlLayer(self):
- with OverrideCursor(Qt.WaitCursor):
- layer = self._getSqlLayer(self.filter)
- if layer is None:
- return
- QgsProject.instance().addMapLayers([layer], True)
- def fillColumnCombos(self):
- query = self._getExecutableSqlQuery()
- if query == "":
- return
- with OverrideCursor(Qt.WaitCursor):
- # remove a trailing ';' from query if present
- if query.strip().endswith(';'):
- query = query.strip()[:-1]
- # get all the columns
- 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 = "SELECT * FROM (%s\n) AS %s LIMIT 0" % (str(query), connector.quoteId(alias))
- else:
- sql = "SELECT * FROM (%s\n) WHERE 1=0" % str(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:
- DlgDbError.showError(e, self)
- self.uniqueModel.clear()
- self.geomCombo.clear()
- return
- finally:
- if c:
- c.close()
- del c
- self.setColumnCombos(cols, quotedCols)
- def setColumnCombos(self, cols, quotedCols):
- # get sensible default columns. do this before sorting in case there's hints in the column order (e.g., 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)
- 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 value in dictionary.values():
- 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 createView(self):
- name, ok = QInputDialog.getText(None, self.tr("View Name"), self.tr("View name"))
- if ok:
- try:
- self.db.connector.createSpatialView(name, self._getExecutableSqlQuery())
- except BaseError as e:
- DlgDbError.showError(e, self)
- def _getSqlQuery(self):
- sql = self.editSql.selectedText()
- if len(sql) == 0:
- sql = self.editSql.text()
- return sql
- def _getExecutableSqlQuery(self):
- sql = self._getSqlQuery().strip()
- uncommented_sql = check_comments_in_sql(sql)
- uncommented_sql = uncommented_sql.rstrip(';')
- return uncommented_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.
- label = ", ".join(
- item.text()
- for item in self.uniqueModel.findItems("*", Qt.MatchWildcard)
- if item.checkState() == Qt.Checked
- )
- 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()
- def setHasChanged(self, hasChanged):
- self.hasChanged = hasChanged
- def close(self):
- if self.hasChanged:
- ret = QMessageBox.question(
- self, self.tr('Unsaved Changes?'),
- self.tr('There are unsaved changes. Do you want to keep them?'),
- QMessageBox.Save | QMessageBox.Cancel | QMessageBox.Discard, QMessageBox.Cancel)
- if ret == QMessageBox.Save:
- self.saveAsFilePreset()
- return True
- elif ret == QMessageBox.Discard:
- return True
- else:
- return False
- else:
- return True
|