eric6/SqlBrowser/SqlBrowserWidget.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7229
53054eb5b15a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/SqlBrowser/SqlBrowserWidget.py	Sun Apr 14 15:09:21 2019 +0200
@@ -0,0 +1,313 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2009 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the SQL Browser widget.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import pyqtSignal, QVariant, Qt, pyqtSlot
+from PyQt5.QtGui import QStandardItemModel
+from PyQt5.QtWidgets import QWidget, QDialog, QAbstractItemView
+from PyQt5.QtSql import QSqlDatabase, QSqlError, QSqlTableModel, \
+    QSqlQueryModel, QSqlQuery
+
+from E5Gui import E5MessageBox
+
+from .Ui_SqlBrowserWidget import Ui_SqlBrowserWidget
+
+
+class SqlBrowserWidget(QWidget, Ui_SqlBrowserWidget):
+    """
+    Class implementing the SQL Browser widget.
+    
+    @signal statusMessage(str) emitted to show a status message
+    """
+    statusMessage = pyqtSignal(str)
+    
+    cCount = 0
+    
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(SqlBrowserWidget, self).__init__(parent)
+        self.setupUi(self)
+        
+        self.table.addAction(self.insertRowAction)
+        self.table.addAction(self.deleteRowAction)
+        
+        if len(QSqlDatabase.drivers()) == 0:
+            E5MessageBox.information(
+                self,
+                self.tr("No database drivers found"),
+                self.tr(
+                    """This tool requires at least one Qt database driver. """
+                    """Please check the Qt documentation how to build the """
+                    """Qt SQL plugins."""))
+        
+        self.connections.tableActivated.connect(
+            self.on_connections_tableActivated)
+        self.connections.schemaRequested.connect(
+            self.on_connections_schemaRequested)
+        self.connections.cleared.connect(self.on_connections_cleared)
+        
+        self.statusMessage.emit(self.tr("Ready"))
+    
+    @pyqtSlot()
+    def on_clearButton_clicked(self):
+        """
+        Private slot to clear the SQL entry widget.
+        """
+        self.sqlEdit.clear()
+        self.sqlEdit.setFocus()
+    
+    @pyqtSlot()
+    def on_executeButton_clicked(self):
+        """
+        Private slot to execute the entered SQL query.
+        """
+        self.executeQuery()
+        self.sqlEdit.setFocus()
+    
+    @pyqtSlot()
+    def on_insertRowAction_triggered(self):
+        """
+        Private slot handling the action to insert a new row.
+        """
+        self.__insertRow()
+    
+    @pyqtSlot()
+    def on_deleteRowAction_triggered(self):
+        """
+        Private slot handling the action to delete a row.
+        """
+        self.__deleteRow()
+    
+    @pyqtSlot(str)
+    def on_connections_tableActivated(self, table):
+        """
+        Private slot to show the contents of a table.
+        
+        @param table name of the table for which to show the contents (string)
+        """
+        self.showTable(table)
+    
+    @pyqtSlot(str)
+    def on_connections_schemaRequested(self, table):
+        """
+        Private slot to show the schema of a table.
+        
+        @param table name of the table for which to show the schema (string)
+        """
+        self.showSchema(table)
+    
+    @pyqtSlot()
+    def on_connections_cleared(self):
+        """
+        Private slot to clear the table.
+        """
+        model = QStandardItemModel(self.table)
+        self.table.setModel(model)
+        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
+        
+        self.updateActions()
+    
+    def addConnection(self, driver, dbName, user, password, host, port):
+        """
+        Public method to add a database connection.
+        
+        @param driver name of the Qt database driver (string)
+        @param dbName name of the database (string)
+        @param user user name (string)
+        @param password password (string)
+        @param host host name (string)
+        @param port port number (integer)
+        @return SQL error object (QSqlError)
+        """
+        err = QSqlError()
+        
+        self.__class__.cCount += 1
+        db = QSqlDatabase.addDatabase(
+            driver.upper(), "Browser{0:d}".format(self.__class__.cCount))
+        db.setDatabaseName(dbName)
+        db.setHostName(host)
+        db.setPort(port)
+        if not db.open(user, password):
+            err = db.lastError()
+            db = QSqlDatabase()
+            QSqlDatabase.removeDatabase(
+                "Browser{0:d}".format(self.__class__.cCount))
+        
+        self.connections.refresh()
+        
+        return err
+    
+    def addConnectionByDialog(self):
+        """
+        Public slot to add a database connection via an input dialog.
+        """
+        from .SqlConnectionDialog import SqlConnectionDialog
+        dlg = SqlConnectionDialog(self)
+        if dlg.exec_() == QDialog.Accepted:
+            driver, dbName, user, password, host, port = dlg.getData()
+            err = self.addConnection(
+                driver, dbName, user, password, host, port)
+            
+            if err.type() != QSqlError.NoError:
+                E5MessageBox.warning(
+                    self,
+                    self.tr("Unable to open database"),
+                    self.tr(
+                        """An error occurred while opening the connection."""))
+    
+    def showTable(self, table):
+        """
+        Public slot to show the contents of a table.
+        
+        @param table name of the table to be shown (string)
+        """
+        model = QSqlTableModel(self.table, self.connections.currentDatabase())
+        model.setEditStrategy(QSqlTableModel.OnRowChange)
+        model.setTable(table)
+        model.select()
+        if model.lastError().type() != QSqlError.NoError:
+            self.statusMessage.emit(model.lastError().text())
+        self.table.setModel(model)
+        self.table.setEditTriggers(
+            QAbstractItemView.DoubleClicked | QAbstractItemView.EditKeyPressed)
+        
+        self.table.resizeColumnsToContents()
+        
+        self.table.selectionModel().currentRowChanged.connect(
+            self.updateActions)
+        
+        self.updateActions()
+    
+    def showSchema(self, table):
+        """
+        Public slot to show the schema of a table.
+        
+        @param table name of the table to be shown (string)
+        """
+        rec = self.connections.currentDatabase().record(table)
+        model = QStandardItemModel(self.table)
+        
+        model.insertRows(0, rec.count())
+        model.insertColumns(0, 7)
+        
+        model.setHeaderData(0, Qt.Horizontal, "Fieldname")
+        model.setHeaderData(1, Qt.Horizontal, "Type")
+        model.setHeaderData(2, Qt.Horizontal, "Length")
+        model.setHeaderData(3, Qt.Horizontal, "Precision")
+        model.setHeaderData(4, Qt.Horizontal, "Required")
+        model.setHeaderData(5, Qt.Horizontal, "Auto Value")
+        model.setHeaderData(6, Qt.Horizontal, "Default Value")
+        
+        for i in range(rec.count()):
+            fld = rec.field(i)
+            model.setData(model.index(i, 0), fld.name())
+            if fld.typeID() == -1:
+                model.setData(model.index(i, 1),
+                              QVariant.typeToName(fld.type()))
+            else:
+                model.setData(
+                    model.index(i, 1), "{0} ({1})".format(
+                        QVariant.typeToName(fld.type()), fld.typeID()))
+            if fld.length() < 0:
+                model.setData(model.index(i, 2), "?")
+            else:
+                model.setData(model.index(i, 2), fld.length())
+            if fld.precision() < 0:
+                model.setData(model.index(i, 3), "?")
+            else:
+                model.setData(model.index(i, 3), fld.precision())
+            if fld.requiredStatus() == -1:
+                model.setData(model.index(i, 4), "?")
+            else:
+                model.setData(model.index(i, 4), bool(fld.requiredStatus()))
+            model.setData(model.index(i, 5), fld.isAutoValue())
+            model.setData(model.index(i, 6), fld.defaultValue())
+        
+        self.table.setModel(model)
+        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
+        
+        self.table.resizeColumnsToContents()
+        
+        self.updateActions()
+    
+    def updateActions(self):
+        """
+        Public slot to update the actions.
+        """
+        enableIns = isinstance(self.table.model(), QSqlTableModel)
+        enableDel = enableIns & self.table.currentIndex().isValid()
+        
+        self.insertRowAction.setEnabled(enableIns)
+        self.deleteRowAction.setEnabled(enableDel)
+    
+    def __insertRow(self):
+        """
+        Private slot to insert a row into the database table.
+        """
+        model = self.table.model()
+        if not isinstance(model, QSqlTableModel):
+            return
+        
+        insertIndex = self.table.currentIndex()
+        if insertIndex.row() == -1:
+            row = 0
+        else:
+            row = insertIndex.row()
+        model.insertRow(row)
+        insertIndex = model.index(row, 0)
+        self.table.setCurrentIndex(insertIndex)
+        self.table.edit(insertIndex)
+    
+    def __deleteRow(self):
+        """
+        Private slot to delete a row from the database table.
+        """
+        model = self.table.model()
+        if not isinstance(model, QSqlTableModel):
+            return
+        
+        model.setEditStrategy(QSqlTableModel.OnManualSubmit)
+        
+        currentSelection = self.table.selectionModel().selectedIndexes()
+        for selectedIndex in currentSelection:
+            if selectedIndex.column() != 0:
+                continue
+            model.removeRow(selectedIndex.row())
+        
+        model.submitAll()
+        model.setEditStrategy(QSqlTableModel.OnRowChange)
+        
+        self.updateActions()
+    
+    def executeQuery(self):
+        """
+        Public slot to execute the entered query.
+        """
+        model = QSqlQueryModel(self.table)
+        model.setQuery(QSqlQuery(
+            self.sqlEdit.toPlainText(), self.connections.currentDatabase()))
+        self.table.setModel(model)
+        
+        if model.lastError().type() != QSqlError.NoError:
+            self.statusMessage.emit(model.lastError().text())
+        elif model.query().isSelect():
+            self.statusMessage.emit(self.tr("Query OK."))
+        else:
+            self.statusMessage.emit(
+                self.tr("Query OK, number of affected rows: {0}")
+                    .format(model.query().numRowsAffected()))
+        
+        self.table.resizeColumnsToContents()
+        
+        self.updateActions()

eric ide

mercurial