aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside2/doc
diff options
context:
space:
mode:
authorMariana Meireles <mariana.meireles-gontijo@qt.io>2019-11-22 17:26:12 +0100
committerCristián Maureira-Fredes <cristian.maureira-fredes@qt.io>2020-01-27 23:41:38 +0100
commit1273f72b013a875c5cf51d3da4fc9b081eee28c1 (patch)
treec066816f37a88d5e30cd471a2bfaa39a0176450e /sources/pyside2/doc
parent450086611ae9640a375b696f251c337e160cbfbf (diff)
docs: QML and SQL integration tutorial
Change-Id: I6ba4ae9fe6a9bfe669b76a23f27556b1f3c59eb4 Reviewed-by: Venugopal Shivashankar <Venugopal.Shivashankar@qt.io>
Diffstat (limited to 'sources/pyside2/doc')
-rw-r--r--sources/pyside2/doc/tutorials/index.rst17
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/chat.qml127
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/example_list_view.pngbin0 -> 6954 bytes
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/main.py85
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst223
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/sqlDialog.py146
6 files changed, 598 insertions, 0 deletions
diff --git a/sources/pyside2/doc/tutorials/index.rst b/sources/pyside2/doc/tutorials/index.rst
index 7486554f9..73e6b6b26 100644
--- a/sources/pyside2/doc/tutorials/index.rst
+++ b/sources/pyside2/doc/tutorials/index.rst
@@ -7,6 +7,8 @@ documents were ported from C++ to Python and cover a range of topics,
from basic use of widgets to step-by-step tutorials that show how an
application is put together.
+Basic tutorials
+---------------
.. toctree::
:maxdepth: 2
@@ -16,8 +18,23 @@ application is put together.
basictutorial/clickablebutton.rst
basictutorial/dialog.rst
basictutorial/uifiles.rst
+
+Real use-cases applications
+---------------------------
+
+.. toctree::
+ :maxdepth: 2
+
datavisualize/index.rst
expenses/expenses.rst
qmlapp/qmlapplication.rst
qmlintegration/qmlintegration.rst
+ qmlsqlintegration/qmlsqlintegration.rst
+
+C++ and Python
+--------------
+
+.. toctree::
+ :maxdepth: 2
+
portingguide/index.rst
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/chat.qml b/sources/pyside2/doc/tutorials/qmlsqlintegration/chat.qml
new file mode 100644
index 000000000..487f5b36c
--- /dev/null
+++ b/sources/pyside2/doc/tutorials/qmlsqlintegration/chat.qml
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+
+ApplicationWindow {
+ id: window
+ title: qsTr("Chat")
+ width: 640
+ height: 960
+ visible: true
+ ColumnLayout {
+ anchors.fill: parent
+
+ ListView {
+ id: listView
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: pane.leftPadding + messageField.leftPadding
+ displayMarginBeginning: 40
+ displayMarginEnd: 40
+ verticalLayoutDirection: ListView.BottomToTop
+ spacing: 12
+ model: chat_model
+ delegate: Column {
+ readonly property bool sentByMe: model.recipient !== "Me"
+ anchors.right: sentByMe ? parent.right : undefined
+ spacing: 6
+
+ Row {
+ id: messageRow
+ spacing: 6
+ anchors.right: sentByMe ? parent.right : undefined
+
+ Rectangle {
+ width: Math.min(messageText.implicitWidth + 24, listView.width - messageRow.spacing)
+ height: messageText.implicitHeight + 24
+ radius: 15
+ color: sentByMe ? "lightgrey" : "#ff627c"
+
+ Label {
+ id: messageText
+ text: model.message
+ color: sentByMe ? "black" : "white"
+ anchors.fill: parent
+ anchors.margins: 12
+ wrapMode: Label.Wrap
+ }
+ }
+ }
+
+ Label {
+ id: timestampText
+ text: Qt.formatDateTime(model.timestamp, "d MMM hh:mm")
+ color: "lightgrey"
+ anchors.right: sentByMe ? parent.right : undefined
+ }
+ }
+
+ ScrollBar.vertical: ScrollBar {}
+ }
+
+ Pane {
+ id: pane
+ Layout.fillWidth: true
+
+ RowLayout {
+ width: parent.width
+
+ TextArea {
+ id: messageField
+ Layout.fillWidth: true
+ placeholderText: qsTr("Compose message")
+ wrapMode: TextArea.Wrap
+ }
+
+ Button {
+ id: sendButton
+ text: qsTr("Send")
+ enabled: messageField.length > 0
+ onClicked: {
+ chat_model.send_message("machine", messageField.text, "Me");
+ messageField.text = "";
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/example_list_view.png b/sources/pyside2/doc/tutorials/qmlsqlintegration/example_list_view.png
new file mode 100644
index 000000000..a0c189665
--- /dev/null
+++ b/sources/pyside2/doc/tutorials/qmlsqlintegration/example_list_view.png
Binary files differ
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/main.py b/sources/pyside2/doc/tutorials/qmlsqlintegration/main.py
new file mode 100644
index 000000000..c710e019a
--- /dev/null
+++ b/sources/pyside2/doc/tutorials/qmlsqlintegration/main.py
@@ -0,0 +1,85 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python project.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import logging
+
+from PySide2.QtCore import QDir, QFile, QUrl
+from PySide2.QtGui import QGuiApplication
+from PySide2.QtQml import QQmlApplicationEngine
+from PySide2.QtSql import QSqlDatabase
+
+from sqlDialog import SqlConversationModel
+
+logging.basicConfig(filename="chat.log", level=logging.DEBUG)
+logger = logging.getLogger("logger")
+
+
+def connectToDatabase():
+ database = QSqlDatabase.database()
+ if not database.isValid():
+ database = QSqlDatabase.addDatabase("QSQLITE")
+ if not database.isValid():
+ logger.error("Cannot add database")
+
+ write_dir = QDir()
+ if not write_dir.mkpath("."):
+ logger.error("Failed to create writable directory")
+
+ # Ensure that we have a writable location on all devices.
+ filename = "{}/chat-database.sqlite3".format(write_dir.absolutePath())
+
+ # When using the SQLite driver, open() will create the SQLite
+ # database if it doesn't exist.
+ database.setDatabaseName(filename)
+ if not database.open():
+ logger.error("Cannot open database")
+ QFile.remove(filename)
+
+
+if __name__ == "__main__":
+ app = QGuiApplication()
+ connectToDatabase()
+ sql_conversation_model = SqlConversationModel()
+
+ engine = QQmlApplicationEngine()
+ # Export pertinent objects to QML
+ engine.rootContext().setContextProperty("chat_model", sql_conversation_model)
+ engine.load(QUrl("chat.qml"))
+
+ app.exec_()
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst b/sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst
new file mode 100644
index 000000000..c26d154ac
--- /dev/null
+++ b/sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst
@@ -0,0 +1,223 @@
+QML, SQL and PySide Integration Tutorial
+########################################
+
+This tutorial is very similar to the `Qt Chat Tutorial`_ one but it focuses on explaining how to
+integrate a SQL database into a PySide2 application using QML for its UI.
+
+.. _`Qt Chat Tutorial`: https://doc.qt.io/qt-5/qtquickcontrols-chattutorial-example.html
+
+sqlDialog.py
+------------
+
+We import the pertinent libraries to our program, define a global variable that hold the
+name of our table, and define the global function ``createTable()`` that creates a new table if it
+doesn't already exist.
+The database contains a single line to mock the beginning of a conversation.
+
+ .. literalinclude:: sqlDialog.py
+ :linenos:
+ :lines: 40-77
+
+The ``SqlConversationModel`` class offers the read-only data model required for the non-editable
+contacts list. It derives from the :ref:`QSqlQueryModel` class, which is the logical choice for
+this use case.
+Then, we proceed to create the table, set its name to the one defined previously with the
+:meth:`~.QSqlTableModel.setTable` method.
+We add the necessary attributes to the table, to have a program that reflects the idea
+of a chat application.
+
+ .. literalinclude:: sqlDialog.py
+ :linenos:
+ :lines: 80-91
+
+In ``setRecipient()``, you set a filter over the returned results from the database, and
+emit a signal every time the recipient of the message changes.
+
+ .. literalinclude:: sqlDialog.py
+ :linenos:
+ :lines: 93-103
+
+The ``data()`` function falls back to ``QSqlTableModel``'s implementation if the role is not a
+custom user role.
+If you get a user role, we can subtract :meth:`~.QtCore.Qt.UserRole` from it to get the index of
+that field, and then use that index to find the value to be returned.
+
+ .. literalinclude:: sqlDialog.py
+ :linenos:
+ :lines: 105-112
+
+
+In ``roleNames()``, we return a Python dictionary with our custom role and role names as key-values
+pairs, so we can use these roles in QML.
+Alternatively, it can be useful to declare an Enum to hold all of the role values.
+Note that ``names`` has to be a hash to be used as a dictionary key,
+and that's why we're using the ``hash`` function.
+
+ .. literalinclude:: sqlDialog.py
+ :linenos:
+ :lines: 114-128
+
+The ``send_message()`` function uses the given recipient and message to insert a new record into
+the database.
+Using :meth:`~.QSqlTableModel.OnManualSubmit` requires you to also call ``submitAll()``,
+since all the changes will be cached in the model until you do so.
+
+ .. literalinclude:: sqlDialog.py
+ :linenos:
+ :lines: 130-146
+
+chat.qml
+--------
+
+Let's look at the ``chat.qml`` file.
+
+ .. literalinclude:: chat.qml
+ :linenos:
+ :lines: 40-42
+
+First, import the Qt Quick module.
+This gives us access to graphical primitives such as Item, Rectangle, Text, and so on.
+For a full list of types, see the `Qt Quick QML Types`_ documentation.
+We then add QtQuick.Layouts import, which we'll cover shortly.
+
+Next, import the Qt Quick Controls module.
+Among other things, this provides access to ``ApplicationWindow``, which replaces the existing
+root type, Window:
+
+Let's step through the ``chat.qml`` file.
+
+ .. literalinclude:: chat.qml
+ :linenos:
+ :lines: 44-49
+
+``ApplicationWindow`` is a Window with some added convenience for creating a header and a footer.
+It also provides the foundation for popups and supports some basic styling, such as the background
+color.
+
+There are three properties that are almost always set when using ApplicationWindow: ``width``,
+``height``, and ``visible``.
+Once we've set these, we have a properly sized, empty window ready to be filled with content.
+
+There are two ways of laying out items in QML: `Item Positioners`_ and `Qt Quick Layouts`_.
+* Item positioners (`Row`_, `Column`_, and so on) are useful for situations where the size of items
+ is known or fixed, and all that is required is to neatly position them in a certain formation.
+* The layouts in Qt Quick Layouts can both position and resize items, making them well suited for
+ resizable user interfaces.
+ Below, we use `ColumnLayout`_ to vertically lay out a `ListView`_ and a `Pane`_.
+
+ .. literalinclude:: chat.qml
+ :linenos:
+ :lines: 50-53
+
+Pane is basically a rectangle whose color comes from the application's style.
+It's similar to `Frame`_, but it has no stroke around its border.
+
+Items that are direct children of a layout have various `attached properties`_ available to them.
+We use `Layout.fillWidth`_ and `Layout.fillHeight`_ on the `ListView`_ to ensure that it takes as
+much space within the `ColumnLayout`_ as it can, and the same is done for the Pane.
+As `ColumnLayout`_ is a vertical layout, there aren't any items to the left or right of each child,
+so this results in each item consuming the entire width of the layout.
+
+On the other hand, the `Layout.fillHeight`_ statement in the `ListView`_ enables it to occupy the
+remaining space that is left after accommodating the Pane.
+
+.. _Item Positioners: https://doc.qt.io/qt-5/qtquick-positioning-layouts.html
+.. _Qt Quick Layouts: https://doc.qt.io/qt-5/qtquicklayouts-index.html
+.. _Row: https://doc.qt.io/qt-5/qml-qtquick-row.html
+.. _Column: https://doc.qt.io/qt-5/qml-qtquick-column.html
+.. _ColumnLayout: https://doc.qt.io/qt-5/qml-qtquick-layouts-columnlayout.html
+.. _ListView: https://doc.qt.io/qt-5/qml-qtquick-listview.html
+.. _Pane: https://doc.qt.io/qt-5/qml-qtquick-controls2-pane.html
+.. _Frame: https://doc.qt.io/qt-5/qml-qtquick-controls2-frame.html
+.. _attached properties: https://doc.qt.io/qt-5/qml-qtquick-layouts-layout.html
+.. _Layout.fillWidth: https://doc.qt.io/qt-5/qml-qtquick-layouts-layout.html#fillWidth-attached-prop
+.. _Layout.fillHeight: https://doc.qt.io/qt-5/qml-qtquick-layouts-layout.html#fillHeight-attached-prop
+.. _ListView: https://doc.qt.io/qt-5/qml-qtquick-listview.html
+.. _Qt Quick QML Types: https://doc.qt.io/qt-5/qtquick-qmlmodule.html
+
+Let's look at the ``Listview`` in detail:
+
+ .. literalinclude:: chat.qml
+ :linenos:
+ :lines: 53-99
+
+After filling the ``width`` and ``height`` of its parent, we also set some margins on the view.
+
+
+Next, we set `displayMarginBeginning`_ and `displayMarginEnd`_.
+These properties ensure that the delegates outside the view don't disappear when you
+scroll at the edges of the view.
+To get a better understanding, consider commenting out the properties and then rerun your code.
+Now watch what happens when you scroll the view.
+
+We then flip the vertical direction of the view, so that first items are at the bottom.
+
+Additionally, messages sent by the contact should be distinguished from those sent by a contact.
+For now, when a message is sent by you, we set a ``sentByMe`` property, to alternate between
+different contacts.
+Using this property, we distinguish between different contacts in two ways:
+
+* Messages sent by the contact are aligned to the right side of the screen by setting
+ ``anchors.right`` to ``parent.right``.
+* We change the color of the rectangle depending on the contact.
+ Since we don't want to display dark text on a dark background, and vice versa, we also set the
+ text color depending on who the contact is.
+
+At the bottom of the screen, we place a `TextArea`_ item to allow multi-line text input, and a
+button to send the message.
+We use Pane to cover the area under these two items:
+
+ .. literalinclude:: chat.qml
+ :linenos:
+ :lines: 101-125
+
+The `TextArea`_ should fill the available width of the screen.
+We assign some placeholder text to provide a visual cue to the contact as to where they should begin
+typing.
+The text within the input area is wrapped to ensure that it does not go outside of the screen.
+
+Lastly, we have a button that allows us to call the ``send_message`` method we defined on
+``sqlDialog.py``, since we're just having a mock up example here and there is only one possible
+recipient and one possible sender for this conversation we're just using strings here.
+
+.. _displayMarginBeginning: https://doc.qt.io/qt-5/qml-qtquick-listview.html#displayMarginBeginning-prop
+.. _displayMarginEnd: https://doc.qt.io/qt-5/qml-qtquick-listview.html#displayMarginEnd-prop
+.. _TextArea: https://doc.qt.io/qt-5/qml-qtquick-controls2-textarea.html
+
+
+main.py
+-------
+
+We use ``logging`` instead of Python's ``print()``, because it provides a better way to control the
+messages levels that our application will generate (errors, warnings, and information messages).
+
+ .. literalinclude:: main.py
+ :linenos:
+ :lines: 40-50
+
+``connectToDatabase()`` creates a connection with the SQLite database, creating the actual file
+if it doesn't already exist.
+
+ .. literalinclude:: main.py
+ :linenos:
+ :lines: 53-72
+
+
+
+A few interesting things happen in the ``main`` function:
+* Declaring a :ref:`QGuiApplication`.
+ You should use a :ref:`QGuiApplication` instead of :ref:`QApplication` because we're not
+ using the **QtWidgets** module.
+* Connecting to the database,
+* Declaring a :ref:`QQmlApplicationEngine`.
+ This allows you to access the QML context property to connect Python
+ and QML from the conversation model we built on ``sqlDialog.py``.
+* Loading the ``.qml`` file that defines the UI.
+
+Finally, the Qt application runs, and your program starts.
+
+ .. literalinclude:: main.py
+ :linenos:
+ :lines: 75-85
+
+.. image:: example_list_view.png
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/sqlDialog.py b/sources/pyside2/doc/tutorials/qmlsqlintegration/sqlDialog.py
new file mode 100644
index 000000000..6a9ff8234
--- /dev/null
+++ b/sources/pyside2/doc/tutorials/qmlsqlintegration/sqlDialog.py
@@ -0,0 +1,146 @@
+#############################################################################
+##
+## Copyright (C) 2019 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt for Python project.
+##
+## $QT_BEGIN_LICENSE:LGPL$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 3 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL3 included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 3 requirements
+## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 2.0 or (at your option) the GNU General
+## Public license version 3 or any later version approved by the KDE Free
+## Qt Foundation. The licenses are as published by the Free Software
+## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-2.0.html and
+## https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import datetime
+import logging
+
+from PySide2.QtCore import Qt, Slot
+from PySide2.QtSql import QSqlDatabase, QSqlQuery, QSqlRecord, QSqlTableModel
+
+table_name = "Conversations"
+
+
+def createTable():
+ if table_name in QSqlDatabase.database().tables():
+ return
+
+ query = QSqlQuery()
+ if not query.exec_(
+ """
+ CREATE TABLE IF NOT EXISTS 'Conversations' (
+ 'author' TEXT NOT NULL,
+ 'recipient' TEXT NOT NULL,
+ 'timestamp' TEXT NOT NULL,
+ 'message' TEXT NOT NULL,
+ FOREIGN KEY('author') REFERENCES Contacts ( name ),
+ FOREIGN KEY('recipient') REFERENCES Contacts ( name )
+ )
+ """
+ ):
+ logging.error("Failed to query database")
+
+ # This adds the first message from the Bot
+ # and further development is required to make it interactive.
+ query.exec_(
+ """
+ INSERT INTO Conversations VALUES(
+ 'machine', 'Me', '2019-01-07T14:36:06', 'Hello!'
+ )
+ """
+ )
+ logging.info(query)
+
+
+class SqlConversationModel(QSqlTableModel):
+ def __init__(self, parent=None):
+ super(SqlConversationModel, self).__init__(parent)
+
+ createTable()
+ self.setTable(table_name)
+ self.setSort(2, Qt.DescendingOrder)
+ self.setEditStrategy(QSqlTableModel.OnManualSubmit)
+ self.recipient = ""
+
+ self.select()
+ logging.debug("Table was loaded successfully.")
+
+ def setRecipient(self, recipient):
+ if recipient == self.recipient:
+ pass
+
+ self.recipient = recipient
+
+ filter_str = (
+ "(recipient = '{}' AND author = 'Me') OR " "(recipient = 'Me' AND author='{}')"
+ ).format(self.recipient)
+ self.setFilter(filter_str)
+ self.select()
+
+ def data(self, index, role):
+ if role < Qt.UserRole:
+ return QSqlTableModel.data(self, index, role)
+
+ sql_record = QSqlRecord()
+ sql_record = self.record(index.row())
+
+ return sql_record.value(role - Qt.UserRole)
+
+ def roleNames(self):
+ """Converts dict to hash because that's the result expected
+ by QSqlTableModel"""
+ names = {}
+ author = "author".encode()
+ recipient = "recipient".encode()
+ timestamp = "timestamp".encode()
+ message = "message".encode()
+
+ names[hash(Qt.UserRole)] = author
+ names[hash(Qt.UserRole + 1)] = recipient
+ names[hash(Qt.UserRole + 2)] = timestamp
+ names[hash(Qt.UserRole + 3)] = message
+
+ return names
+
+ def send_message(self, recipient, message, author):
+ timestamp = datetime.datetime.now()
+
+ new_record = self.record()
+ new_record.setValue("author", author)
+ new_record.setValue("recipient", recipient)
+ new_record.setValue("timestamp", str(timestamp))
+ new_record.setValue("message", message)
+
+ logging.debug('Message: "{}" \n Received by: "{}"'.format(message, recipient))
+
+ if not self.insertRecord(self.rowCount(), new_record):
+ logging.error("Failed to send message: {}".format(self.lastError().text()))
+ return
+
+ self.submitAll()
+ self.select()