Skip to content

Commit 724a5bd

Browse files
committed
Db_Manager now allows to select multiple columnns as the primary key for a query.
1 parent 20283a4 commit 724a5bd

File tree

2 files changed

+73
-15
lines changed

2 files changed

+73
-15
lines changed

python/plugins/db_manager/dlg_sql_window.py

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
from PyQt4.QtCore import Qt, QObject, QSettings, QByteArray, SIGNAL, pyqtSignal
2626
from PyQt4.QtGui import QDialog, QWidget, QAction, QKeySequence, \
27-
QDialogButtonBox, QApplication, QCursor, QMessageBox, QClipboard, QInputDialog, QIcon
27+
QDialogButtonBox, QApplication, QCursor, QMessageBox, QClipboard, QInputDialog, QIcon, QStyledItemDelegate, QStandardItemModel, QStandardItem
2828
from PyQt4.Qsci import QsciAPIs
2929

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

8181
self.updatePresetsCombobox()
8282

83+
self.uniqueCombo.setItemDelegate(QStyledItemDelegate())
84+
self.uniqueModel = QStandardItemModel(self.uniqueCombo)
85+
self.uniqueCombo.setModel(self.uniqueModel)
86+
self.uniqueCombo.setEditable(True)
87+
self.uniqueCombo.lineEdit().setReadOnly(True)
88+
self.uniqueModel.itemChanged.connect(self.uniqueChanged) # react to the (un)checking of an item
89+
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
90+
self.uniqueChanged
91+
8392
# hide the load query as layer if feature is not supported
8493
self._loadAsLayerAvailable = self.db.connector.hasCustomQuerySupport()
8594
self.loadAsLayerGroup.setVisible(self._loadAsLayerAvailable)
@@ -161,29 +170,38 @@ def executeSql(self):
161170
if old_model:
162171
old_model.deleteLater()
163172

173+
cols = []
174+
quotedCols = []
175+
164176
try:
165177
# set the new model
166178
model = self.db.sqlResultModel(sql, self)
167179
self.viewResult.setModel(model)
168180
self.lblResult.setText(self.tr("%d rows, %.1f seconds") % (model.affectedRows(), model.secs()))
181+
cols = self.viewResult.model().columnNames()
182+
for col in cols:
183+
quotedCols.append(self.db.connector.quoteId(col))
169184

170185
except BaseError as e:
171186
QApplication.restoreOverrideCursor()
172187
DlgDbError.showError(e, self)
173-
self.uniqueCombo.clear()
188+
self.uniqueModel.clear()
174189
self.geomCombo.clear()
175190
return
176191

177-
cols = self.viewResult.model().columnNames()
178-
self.setColumnCombos(cols)
192+
self.setColumnCombos(cols, quotedCols)
179193

180194
self.update()
181195
QApplication.restoreOverrideCursor()
182196

183197
def loadSqlLayer(self):
184198
hasUniqueField = self.uniqueColumnCheck.checkState() == Qt.Checked
185199
if hasUniqueField:
186-
uniqueFieldName = self.uniqueCombo.currentText()
200+
checkedCols = []
201+
for item in self.uniqueModel.findItems("*", Qt.MatchWildcard):
202+
if item.checkState() == Qt.Checked:
203+
checkedCols.append(item.data())
204+
uniqueFieldName = ",".join(checkedCols)
187205
else:
188206
uniqueFieldName = None
189207
hasGeomCol = self.hasGeometryCol.checkState() == Qt.Checked
@@ -250,18 +268,21 @@ def fillColumnCombos(self):
250268

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

256275
c = None
257276
try:
258277
c = connector._execute(None, sql)
259278
cols = connector._get_cursor_columns(c)
279+
for col in cols:
280+
quotedCols.append(connector.quoteId(col))
260281

261282
except BaseError as e:
262283
QApplication.restoreOverrideCursor()
263284
DlgDbError.showError(e, self)
264-
self.uniqueCombo.clear()
285+
self.uniqueModel.clear()
265286
self.geomCombo.clear()
266287
return
267288

@@ -270,11 +291,11 @@ def fillColumnCombos(self):
270291
c.close()
271292
del c
272293

273-
self.setColumnCombos(cols)
294+
self.setColumnCombos(cols, quotedCols)
274295

275296
QApplication.restoreOverrideCursor()
276297

277-
def setColumnCombos(self, cols):
298+
def setColumnCombos(self, cols, quotedCols):
278299
# 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)
279300
try:
280301
defaultGeomCol = next(col for col in cols if col in ['geom', 'geometry', 'the_geom', 'way'])
@@ -285,10 +306,22 @@ def setColumnCombos(self, cols):
285306
except:
286307
defaultUniqueCol = None
287308

288-
cols.sort()
289-
self.uniqueCombo.clear()
309+
colNames = zip(cols, quotedCols)
310+
colNames.sort()
311+
newItems = []
312+
for (col, quotedCol) in colNames:
313+
item = QStandardItem(col)
314+
item.setData(quotedCol)
315+
item.setEnabled(True)
316+
item.setCheckable(True)
317+
item.setSelectable(False)
318+
item.setCheckState(Qt.Unchecked)
319+
newItems.append(item)
320+
self.uniqueModel.clear()
321+
self.uniqueModel.appendColumn(newItems)
322+
self.uniqueChanged()
323+
290324
self.geomCombo.clear()
291-
self.uniqueCombo.addItems(cols)
292325
self.geomCombo.addItems(cols)
293326

294327
# set sensible default columns
@@ -297,7 +330,9 @@ def setColumnCombos(self, cols):
297330
except:
298331
pass
299332
try:
300-
self.uniqueCombo.setCurrentIndex(cols.index(defaultUniqueCol))
333+
items = self.uniqueModel.findItems(defaultUniqueCol)
334+
if items:
335+
items[0].setCheckState(Qt.Checked)
301336
except:
302337
pass
303338

@@ -356,3 +391,17 @@ def _getSqlQuery(self):
356391
if len(sql) == 0:
357392
sql = self.editSql.text()
358393
return sql
394+
395+
def uniqueChanged(self):
396+
# when an item is (un)checked, simply trigger an update of the combobox text
397+
self.uniqueTextChanged(None)
398+
399+
def uniqueTextChanged(self, text):
400+
# Whenever there is new text displayed in the combobox, check if it is the correct one and if not, display the correct one.
401+
checkedItems = []
402+
for item in self.uniqueModel.findItems("*", Qt.MatchWildcard):
403+
if item.checkState() == Qt.Checked:
404+
checkedItems.append(item.text())
405+
label = ", ".join(checkedItems)
406+
if text != label:
407+
self.uniqueCombo.setEditText(label)

python/plugins/db_manager/ui/DlgSqlWindow.ui

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
<item>
4444
<widget class="QCheckBox" name="uniqueColumnCheck">
4545
<property name="text">
46-
<string>Column with unique
47-
integer values</string>
46+
<string>Column(s) with
47+
unique values</string>
4848
</property>
4949
</widget>
5050
</item>
@@ -144,7 +144,16 @@ columns</string>
144144
<item>
145145
<widget class="QWidget" name="layerTypeWidget" native="true">
146146
<layout class="QHBoxLayout" name="horizontalLayout_3">
147-
<property name="margin">
147+
<property name="leftMargin">
148+
<number>0</number>
149+
</property>
150+
<property name="topMargin">
151+
<number>0</number>
152+
</property>
153+
<property name="rightMargin">
154+
<number>0</number>
155+
</property>
156+
<property name="bottomMargin">
148157
<number>0</number>
149158
</property>
150159
<item>

0 commit comments

Comments
 (0)