Skip to content

Commit

Permalink
Db_Manager now allows to select multiple columnns as the primary key …
Browse files Browse the repository at this point in the history
…for a query.
  • Loading branch information
SebDieBln committed Oct 17, 2015
1 parent 20283a4 commit 724a5bd
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 15 deletions.
73 changes: 61 additions & 12 deletions python/plugins/db_manager/dlg_sql_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

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
QDialogButtonBox, QApplication, QCursor, QMessageBox, QClipboard, QInputDialog, QIcon, QStyledItemDelegate, QStandardItemModel, QStandardItem
from PyQt4.Qsci import QsciAPIs

from qgis.core import QgsProject
Expand Down Expand Up @@ -80,6 +80,15 @@ def __init__(self, iface, db, parent=None):

self.updatePresetsCombobox()

self.uniqueCombo.setItemDelegate(QStyledItemDelegate())
self.uniqueModel = QStandardItemModel(self.uniqueCombo)
self.uniqueCombo.setModel(self.uniqueModel)
self.uniqueCombo.setEditable(True)
self.uniqueCombo.lineEdit().setReadOnly(True)
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.uniqueChanged

# hide the load query as layer if feature is not supported
self._loadAsLayerAvailable = self.db.connector.hasCustomQuerySupport()
self.loadAsLayerGroup.setVisible(self._loadAsLayerAvailable)
Expand Down Expand Up @@ -161,29 +170,38 @@ def executeSql(self):
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.uniqueCombo.clear()
self.uniqueModel.clear()
self.geomCombo.clear()
return

cols = self.viewResult.model().columnNames()
self.setColumnCombos(cols)
self.setColumnCombos(cols, quotedCols)

self.update()
QApplication.restoreOverrideCursor()

def loadSqlLayer(self):
hasUniqueField = self.uniqueColumnCheck.checkState() == Qt.Checked
if hasUniqueField:
uniqueFieldName = self.uniqueCombo.currentText()
checkedCols = []
for item in self.uniqueModel.findItems("*", Qt.MatchWildcard):
if item.checkState() == Qt.Checked:
checkedCols.append(item.data())
uniqueFieldName = ",".join(checkedCols)
else:
uniqueFieldName = None
hasGeomCol = self.hasGeometryCol.checkState() == Qt.Checked
Expand Down Expand Up @@ -250,18 +268,21 @@ def fillColumnCombos(self):

# get all the columns
cols = []
quotedCols = []
connector = self.db.connector
sql = u"SELECT * FROM (%s\n) AS %s LIMIT 0" % (unicode(query), connector.quoteId(alias))

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.uniqueCombo.clear()
self.uniqueModel.clear()
self.geomCombo.clear()
return

Expand All @@ -270,11 +291,11 @@ def fillColumnCombos(self):
c.close()
del c

self.setColumnCombos(cols)
self.setColumnCombos(cols, quotedCols)

QApplication.restoreOverrideCursor()

def setColumnCombos(self, cols):
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'])
Expand All @@ -285,10 +306,22 @@ def setColumnCombos(self, cols):
except:
defaultUniqueCol = None

cols.sort()
self.uniqueCombo.clear()
colNames = zip(cols, quotedCols)
colNames.sort()
newItems = []
for (col, quotedCol) in colNames:
item = QStandardItem(col)
item.setData(quotedCol)
item.setEnabled(True)
item.setCheckable(True)
item.setSelectable(False)
item.setCheckState(Qt.Unchecked)
newItems.append(item)
self.uniqueModel.clear()
self.uniqueModel.appendColumn(newItems)
self.uniqueChanged()

self.geomCombo.clear()
self.uniqueCombo.addItems(cols)
self.geomCombo.addItems(cols)

# set sensible default columns
Expand All @@ -297,7 +330,9 @@ def setColumnCombos(self, cols):
except:
pass
try:
self.uniqueCombo.setCurrentIndex(cols.index(defaultUniqueCol))
items = self.uniqueModel.findItems(defaultUniqueCol)
if items:
items[0].setCheckState(Qt.Checked)
except:
pass

Expand Down Expand Up @@ -356,3 +391,17 @@ def _getSqlQuery(self):
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)
15 changes: 12 additions & 3 deletions python/plugins/db_manager/ui/DlgSqlWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@
<item>
<widget class="QCheckBox" name="uniqueColumnCheck">
<property name="text">
<string>Column with unique
integer values</string>
<string>Column(s) with
unique values</string>
</property>
</widget>
</item>
Expand Down Expand Up @@ -144,7 +144,16 @@ columns</string>
<item>
<widget class="QWidget" name="layerTypeWidget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
Expand Down

0 comments on commit 724a5bd

Please sign in to comment.