src/eric7/SqlBrowser/SqlBrowserWidget.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
9 9
10 from PyQt6.QtCore import pyqtSignal, QVariant, Qt, pyqtSlot 10 from PyQt6.QtCore import pyqtSignal, QVariant, Qt, pyqtSlot
11 from PyQt6.QtGui import QStandardItemModel 11 from PyQt6.QtGui import QStandardItemModel
12 from PyQt6.QtWidgets import QWidget, QDialog, QAbstractItemView 12 from PyQt6.QtWidgets import QWidget, QDialog, QAbstractItemView
13 from PyQt6.QtSql import ( 13 from PyQt6.QtSql import (
14 QSqlDatabase, QSqlError, QSqlTableModel, QSqlQueryModel, QSqlQuery 14 QSqlDatabase,
15 QSqlError,
16 QSqlTableModel,
17 QSqlQueryModel,
18 QSqlQuery,
15 ) 19 )
16 20
17 from EricWidgets import EricMessageBox 21 from EricWidgets import EricMessageBox
18 22
19 from .Ui_SqlBrowserWidget import Ui_SqlBrowserWidget 23 from .Ui_SqlBrowserWidget import Ui_SqlBrowserWidget
20 24
21 25
22 class SqlBrowserWidget(QWidget, Ui_SqlBrowserWidget): 26 class SqlBrowserWidget(QWidget, Ui_SqlBrowserWidget):
23 """ 27 """
24 Class implementing the SQL Browser widget. 28 Class implementing the SQL Browser widget.
25 29
26 @signal statusMessage(str) emitted to show a status message 30 @signal statusMessage(str) emitted to show a status message
27 """ 31 """
32
28 statusMessage = pyqtSignal(str) 33 statusMessage = pyqtSignal(str)
29 34
30 cCount = 0 35 cCount = 0
31 36
32 def __init__(self, parent=None): 37 def __init__(self, parent=None):
33 """ 38 """
34 Constructor 39 Constructor
35 40
36 @param parent reference to the parent widget (QWidget) 41 @param parent reference to the parent widget (QWidget)
37 """ 42 """
38 super().__init__(parent) 43 super().__init__(parent)
39 self.setupUi(self) 44 self.setupUi(self)
40 45
41 self.table.addAction(self.insertRowAction) 46 self.table.addAction(self.insertRowAction)
42 self.table.addAction(self.deleteRowAction) 47 self.table.addAction(self.deleteRowAction)
43 48
44 if len(QSqlDatabase.drivers()) == 0: 49 if len(QSqlDatabase.drivers()) == 0:
45 EricMessageBox.information( 50 EricMessageBox.information(
46 self, 51 self,
47 self.tr("No database drivers found"), 52 self.tr("No database drivers found"),
48 self.tr( 53 self.tr(
49 """This tool requires at least one Qt database driver. """ 54 """This tool requires at least one Qt database driver. """
50 """Please check the Qt documentation how to build the """ 55 """Please check the Qt documentation how to build the """
51 """Qt SQL plugins.""")) 56 """Qt SQL plugins."""
52 57 ),
53 self.connections.tableActivated.connect( 58 )
54 self.on_connections_tableActivated) 59
55 self.connections.schemaRequested.connect( 60 self.connections.tableActivated.connect(self.on_connections_tableActivated)
56 self.on_connections_schemaRequested) 61 self.connections.schemaRequested.connect(self.on_connections_schemaRequested)
57 self.connections.cleared.connect(self.on_connections_cleared) 62 self.connections.cleared.connect(self.on_connections_cleared)
58 63
59 self.statusMessage.emit(self.tr("Ready")) 64 self.statusMessage.emit(self.tr("Ready"))
60 65
61 @pyqtSlot() 66 @pyqtSlot()
62 def on_clearButton_clicked(self): 67 def on_clearButton_clicked(self):
63 """ 68 """
64 Private slot to clear the SQL entry widget. 69 Private slot to clear the SQL entry widget.
65 """ 70 """
66 self.sqlEdit.clear() 71 self.sqlEdit.clear()
67 self.sqlEdit.setFocus() 72 self.sqlEdit.setFocus()
68 73
69 @pyqtSlot() 74 @pyqtSlot()
70 def on_executeButton_clicked(self): 75 def on_executeButton_clicked(self):
71 """ 76 """
72 Private slot to execute the entered SQL query. 77 Private slot to execute the entered SQL query.
73 """ 78 """
74 self.executeQuery() 79 self.executeQuery()
75 self.sqlEdit.setFocus() 80 self.sqlEdit.setFocus()
76 81
77 @pyqtSlot() 82 @pyqtSlot()
78 def on_insertRowAction_triggered(self): 83 def on_insertRowAction_triggered(self):
79 """ 84 """
80 Private slot handling the action to insert a new row. 85 Private slot handling the action to insert a new row.
81 """ 86 """
82 self.__insertRow() 87 self.__insertRow()
83 88
84 @pyqtSlot() 89 @pyqtSlot()
85 def on_deleteRowAction_triggered(self): 90 def on_deleteRowAction_triggered(self):
86 """ 91 """
87 Private slot handling the action to delete a row. 92 Private slot handling the action to delete a row.
88 """ 93 """
89 self.__deleteRow() 94 self.__deleteRow()
90 95
91 @pyqtSlot(str) 96 @pyqtSlot(str)
92 def on_connections_tableActivated(self, table): 97 def on_connections_tableActivated(self, table):
93 """ 98 """
94 Private slot to show the contents of a table. 99 Private slot to show the contents of a table.
95 100
96 @param table name of the table for which to show the contents (string) 101 @param table name of the table for which to show the contents (string)
97 """ 102 """
98 self.showTable(table) 103 self.showTable(table)
99 104
100 @pyqtSlot(str) 105 @pyqtSlot(str)
101 def on_connections_schemaRequested(self, table): 106 def on_connections_schemaRequested(self, table):
102 """ 107 """
103 Private slot to show the schema of a table. 108 Private slot to show the schema of a table.
104 109
105 @param table name of the table for which to show the schema (string) 110 @param table name of the table for which to show the schema (string)
106 """ 111 """
107 self.showSchema(table) 112 self.showSchema(table)
108 113
109 @pyqtSlot() 114 @pyqtSlot()
110 def on_connections_cleared(self): 115 def on_connections_cleared(self):
111 """ 116 """
112 Private slot to clear the table. 117 Private slot to clear the table.
113 """ 118 """
114 model = QStandardItemModel(self.table) 119 model = QStandardItemModel(self.table)
115 self.table.setModel(model) 120 self.table.setModel(model)
116 self.table.setEditTriggers( 121 self.table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
117 QAbstractItemView.EditTrigger.NoEditTriggers) 122
118 123 self.updateActions()
119 self.updateActions() 124
120
121 def addConnection(self, driver, dbName, user, password, host, port): 125 def addConnection(self, driver, dbName, user, password, host, port):
122 """ 126 """
123 Public method to add a database connection. 127 Public method to add a database connection.
124 128
125 @param driver name of the Qt database driver (string) 129 @param driver name of the Qt database driver (string)
126 @param dbName name of the database (string) 130 @param dbName name of the database (string)
127 @param user user name (string) 131 @param user user name (string)
128 @param password password (string) 132 @param password password (string)
129 @param host host name (string) 133 @param host host name (string)
130 @param port port number (integer) 134 @param port port number (integer)
131 @return SQL error object (QSqlError) 135 @return SQL error object (QSqlError)
132 """ 136 """
133 err = QSqlError() 137 err = QSqlError()
134 138
135 self.__class__.cCount += 1 139 self.__class__.cCount += 1
136 db = QSqlDatabase.addDatabase( 140 db = QSqlDatabase.addDatabase(
137 driver.upper(), "Browser{0:d}".format(self.__class__.cCount)) 141 driver.upper(), "Browser{0:d}".format(self.__class__.cCount)
142 )
138 db.setDatabaseName(dbName) 143 db.setDatabaseName(dbName)
139 db.setHostName(host) 144 db.setHostName(host)
140 db.setPort(port) 145 db.setPort(port)
141 if not db.open(user, password): 146 if not db.open(user, password):
142 err = db.lastError() 147 err = db.lastError()
143 db = QSqlDatabase() 148 db = QSqlDatabase()
144 QSqlDatabase.removeDatabase( 149 QSqlDatabase.removeDatabase("Browser{0:d}".format(self.__class__.cCount))
145 "Browser{0:d}".format(self.__class__.cCount)) 150
146
147 self.connections.refresh() 151 self.connections.refresh()
148 152
149 return err 153 return err
150 154
151 def addConnectionByDialog(self): 155 def addConnectionByDialog(self):
152 """ 156 """
153 Public slot to add a database connection via an input dialog. 157 Public slot to add a database connection via an input dialog.
154 """ 158 """
155 from .SqlConnectionDialog import SqlConnectionDialog 159 from .SqlConnectionDialog import SqlConnectionDialog
160
156 dlg = SqlConnectionDialog(self) 161 dlg = SqlConnectionDialog(self)
157 if dlg.exec() == QDialog.DialogCode.Accepted: 162 if dlg.exec() == QDialog.DialogCode.Accepted:
158 driver, dbName, user, password, host, port = dlg.getData() 163 driver, dbName, user, password, host, port = dlg.getData()
159 err = self.addConnection( 164 err = self.addConnection(driver, dbName, user, password, host, port)
160 driver, dbName, user, password, host, port) 165
161
162 if err.type() != QSqlError.ErrorType.NoError: 166 if err.type() != QSqlError.ErrorType.NoError:
163 EricMessageBox.warning( 167 EricMessageBox.warning(
164 self, 168 self,
165 self.tr("Unable to open database"), 169 self.tr("Unable to open database"),
166 self.tr( 170 self.tr("""An error occurred while opening the connection."""),
167 """An error occurred while opening the connection.""")) 171 )
168 172
169 def showTable(self, table): 173 def showTable(self, table):
170 """ 174 """
171 Public slot to show the contents of a table. 175 Public slot to show the contents of a table.
172 176
173 @param table name of the table to be shown (string) 177 @param table name of the table to be shown (string)
174 """ 178 """
175 model = QSqlTableModel(self.table, self.connections.currentDatabase()) 179 model = QSqlTableModel(self.table, self.connections.currentDatabase())
176 model.setEditStrategy(QSqlTableModel.EditStrategy.OnRowChange) 180 model.setEditStrategy(QSqlTableModel.EditStrategy.OnRowChange)
177 model.setTable(table) 181 model.setTable(table)
178 model.select() 182 model.select()
179 if model.lastError().type() != QSqlError.ErrorType.NoError: 183 if model.lastError().type() != QSqlError.ErrorType.NoError:
180 self.statusMessage.emit(model.lastError().text()) 184 self.statusMessage.emit(model.lastError().text())
181 self.table.setModel(model) 185 self.table.setModel(model)
182 self.table.setEditTriggers( 186 self.table.setEditTriggers(
183 QAbstractItemView.EditTrigger.DoubleClicked | 187 QAbstractItemView.EditTrigger.DoubleClicked
184 QAbstractItemView.EditTrigger.EditKeyPressed) 188 | QAbstractItemView.EditTrigger.EditKeyPressed
185 189 )
190
186 self.table.resizeColumnsToContents() 191 self.table.resizeColumnsToContents()
187 192
188 self.table.selectionModel().currentRowChanged.connect( 193 self.table.selectionModel().currentRowChanged.connect(self.updateActions)
189 self.updateActions) 194
190 195 self.updateActions()
191 self.updateActions() 196
192
193 def showSchema(self, table): 197 def showSchema(self, table):
194 """ 198 """
195 Public slot to show the schema of a table. 199 Public slot to show the schema of a table.
196 200
197 @param table name of the table to be shown (string) 201 @param table name of the table to be shown (string)
198 """ 202 """
199 rec = self.connections.currentDatabase().record(table) 203 rec = self.connections.currentDatabase().record(table)
200 model = QStandardItemModel(self.table) 204 model = QStandardItemModel(self.table)
201 205
202 model.insertRows(0, rec.count()) 206 model.insertRows(0, rec.count())
203 model.insertColumns(0, 7) 207 model.insertColumns(0, 7)
204 208
205 model.setHeaderData(0, Qt.Orientation.Horizontal, "Fieldname") 209 model.setHeaderData(0, Qt.Orientation.Horizontal, "Fieldname")
206 model.setHeaderData(1, Qt.Orientation.Horizontal, "Type") 210 model.setHeaderData(1, Qt.Orientation.Horizontal, "Type")
207 model.setHeaderData(2, Qt.Orientation.Horizontal, "Length") 211 model.setHeaderData(2, Qt.Orientation.Horizontal, "Length")
208 model.setHeaderData(3, Qt.Orientation.Horizontal, "Precision") 212 model.setHeaderData(3, Qt.Orientation.Horizontal, "Precision")
209 model.setHeaderData(4, Qt.Orientation.Horizontal, "Required") 213 model.setHeaderData(4, Qt.Orientation.Horizontal, "Required")
210 model.setHeaderData(5, Qt.Orientation.Horizontal, "Auto Value") 214 model.setHeaderData(5, Qt.Orientation.Horizontal, "Auto Value")
211 model.setHeaderData(6, Qt.Orientation.Horizontal, "Default Value") 215 model.setHeaderData(6, Qt.Orientation.Horizontal, "Default Value")
212 216
213 for i in range(rec.count()): 217 for i in range(rec.count()):
214 fld = rec.field(i) 218 fld = rec.field(i)
215 model.setData(model.index(i, 0), fld.name()) 219 model.setData(model.index(i, 0), fld.name())
216 if fld.typeID() == -1: 220 if fld.typeID() == -1:
217 model.setData(model.index(i, 1), 221 model.setData(model.index(i, 1), QVariant.typeToName(fld.type()))
218 QVariant.typeToName(fld.type()))
219 else: 222 else:
220 model.setData( 223 model.setData(
221 model.index(i, 1), "{0} ({1})".format( 224 model.index(i, 1),
222 QVariant.typeToName(fld.type()), fld.typeID())) 225 "{0} ({1})".format(QVariant.typeToName(fld.type()), fld.typeID()),
226 )
223 if fld.length() < 0: 227 if fld.length() < 0:
224 model.setData(model.index(i, 2), "?") 228 model.setData(model.index(i, 2), "?")
225 else: 229 else:
226 model.setData(model.index(i, 2), fld.length()) 230 model.setData(model.index(i, 2), fld.length())
227 if fld.precision() < 0: 231 if fld.precision() < 0:
232 model.setData(model.index(i, 4), "?") 236 model.setData(model.index(i, 4), "?")
233 else: 237 else:
234 model.setData(model.index(i, 4), bool(fld.requiredStatus())) 238 model.setData(model.index(i, 4), bool(fld.requiredStatus()))
235 model.setData(model.index(i, 5), fld.isAutoValue()) 239 model.setData(model.index(i, 5), fld.isAutoValue())
236 model.setData(model.index(i, 6), fld.defaultValue()) 240 model.setData(model.index(i, 6), fld.defaultValue())
237 241
238 self.table.setModel(model) 242 self.table.setModel(model)
239 self.table.setEditTriggers( 243 self.table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
240 QAbstractItemView.EditTrigger.NoEditTriggers) 244
241
242 self.table.resizeColumnsToContents() 245 self.table.resizeColumnsToContents()
243 246
244 self.updateActions() 247 self.updateActions()
245 248
246 def updateActions(self): 249 def updateActions(self):
247 """ 250 """
248 Public slot to update the actions. 251 Public slot to update the actions.
249 """ 252 """
250 enableIns = isinstance(self.table.model(), QSqlTableModel) 253 enableIns = isinstance(self.table.model(), QSqlTableModel)
251 enableDel = enableIns & self.table.currentIndex().isValid() 254 enableDel = enableIns & self.table.currentIndex().isValid()
252 255
253 self.insertRowAction.setEnabled(enableIns) 256 self.insertRowAction.setEnabled(enableIns)
254 self.deleteRowAction.setEnabled(enableDel) 257 self.deleteRowAction.setEnabled(enableDel)
255 258
256 def __insertRow(self): 259 def __insertRow(self):
257 """ 260 """
258 Private slot to insert a row into the database table. 261 Private slot to insert a row into the database table.
259 """ 262 """
260 model = self.table.model() 263 model = self.table.model()
261 if not isinstance(model, QSqlTableModel): 264 if not isinstance(model, QSqlTableModel):
262 return 265 return
263 266
264 insertIndex = self.table.currentIndex() 267 insertIndex = self.table.currentIndex()
265 row = 0 if insertIndex.row() == -1 else insertIndex.row() 268 row = 0 if insertIndex.row() == -1 else insertIndex.row()
266 model.insertRow(row) 269 model.insertRow(row)
267 insertIndex = model.index(row, 0) 270 insertIndex = model.index(row, 0)
268 self.table.setCurrentIndex(insertIndex) 271 self.table.setCurrentIndex(insertIndex)
269 self.table.edit(insertIndex) 272 self.table.edit(insertIndex)
270 273
271 def __deleteRow(self): 274 def __deleteRow(self):
272 """ 275 """
273 Private slot to delete a row from the database table. 276 Private slot to delete a row from the database table.
274 """ 277 """
275 model = self.table.model() 278 model = self.table.model()
276 if not isinstance(model, QSqlTableModel): 279 if not isinstance(model, QSqlTableModel):
277 return 280 return
278 281
279 model.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit) 282 model.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit)
280 283
281 currentSelection = self.table.selectionModel().selectedIndexes() 284 currentSelection = self.table.selectionModel().selectedIndexes()
282 for selectedIndex in currentSelection: 285 for selectedIndex in currentSelection:
283 if selectedIndex.column() != 0: 286 if selectedIndex.column() != 0:
284 continue 287 continue
285 model.removeRow(selectedIndex.row()) 288 model.removeRow(selectedIndex.row())
286 289
287 model.submitAll() 290 model.submitAll()
288 model.setEditStrategy(QSqlTableModel.EditStrategy.OnRowChange) 291 model.setEditStrategy(QSqlTableModel.EditStrategy.OnRowChange)
289 292
290 self.updateActions() 293 self.updateActions()
291 294
292 def executeQuery(self): 295 def executeQuery(self):
293 """ 296 """
294 Public slot to execute the entered query. 297 Public slot to execute the entered query.
295 """ 298 """
296 model = QSqlQueryModel(self.table) 299 model = QSqlQueryModel(self.table)
297 model.setQuery(QSqlQuery( 300 model.setQuery(
298 self.sqlEdit.toPlainText(), self.connections.currentDatabase())) 301 QSqlQuery(self.sqlEdit.toPlainText(), self.connections.currentDatabase())
302 )
299 self.table.setModel(model) 303 self.table.setModel(model)
300 304
301 if model.lastError().type() != QSqlError.ErrorType.NoError: 305 if model.lastError().type() != QSqlError.ErrorType.NoError:
302 self.statusMessage.emit(model.lastError().text()) 306 self.statusMessage.emit(model.lastError().text())
303 elif model.query().isSelect(): 307 elif model.query().isSelect():
304 self.statusMessage.emit(self.tr("Query OK.")) 308 self.statusMessage.emit(self.tr("Query OK."))
305 else: 309 else:
306 self.statusMessage.emit( 310 self.statusMessage.emit(
307 self.tr("Query OK, number of affected rows: {0}") 311 self.tr("Query OK, number of affected rows: {0}").format(
308 .format(model.query().numRowsAffected())) 312 model.query().numRowsAffected()
309 313 )
314 )
315
310 self.table.resizeColumnsToContents() 316 self.table.resizeColumnsToContents()
311 317
312 self.updateActions() 318 self.updateActions()

eric ide

mercurial