Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
++
++ /*!
++ \example cachedtable
++ \title Cached SQL Table
++ \ingroup sql_examples
++ \examplecategory {Data Processing & I/O}
++
++ \brief The Cached Table example shows how a table view can be used to access a database,
++ caching any changes to the data until the user explicitly submits them using a
++ push button.
++
++ \image cachedtable-example.png {The user updates a cell in the table, and selects the submit button to apply the change in the database}
++
++ The example consists of a single class, \c TableEditor, which is a
++ custom dialog widget that allows the user to modify data stored in
++ a database. We will first review the class definition and how to
++ use the class, then we will take a look at the implementation.
++
++ \section1 TableEditor Class Definition
++
++ The \c TableEditor class inherits QWidget making the table editor
++ widget a top-level dialog window.
++
++ \snippet cachedtable/tableeditor.h 0
++
++ The \c TableEditor constructor takes two arguments: The first is a
++ reference to the database table the \c TableEditor object will operate
++ on. The other is a pointer to the parent widget and is passed on to the
++ base class constructor.
++
++ Note the QSqlTableModel variable declaration: As we will see in
++ this example, the QSqlTableModel class can be used to provide data
++ to view classes such as QTableView. The QSqlTableModel class
++ provides an editable data model making it possible to read and
++ write database records from a single table. It is build on top of
++ the lower-level QSqlQuery class which provides means of executing
++ and manipulating SQL statements.
++
++ We are also going to show how a table view can be used to cache
++ any changes to the data until the user explicitly requests to
++ submit them. For that reason we need to declare a \c submit() slot
++ in addition to the model and the editor's buttons.
++
++ \table 100%
++ \header \li Connecting to a Database
++ \row
++ \li
++
++ Before we can use the \c TableEditor class, we must create a
++ connection to the database containing the table we want to edit:
++
++ \snippet cachedtable/main.cpp 0
++
++ The \c createConnection() function is a helper function provided
++ for convenience. It is defined in the \c connection.h file which
++ is located in the \c sql example directory (all the examples in
++ the \c sql directory use this function to connect to a database).
++
++ \snippet cachedtable/connection.h 0
++
++ The \c createConnection function opens a connection to an
++ in-memory SQLITE database and creates a test table. If you want
++ to use another database, simply modify this function's code.
++ \endtable
++
++ \section1 TableEditor Class Implementation
++
++ The class implementation consists of only two functions, the
++ constructor and the \c submit() slot. In the constructor we create
++ and customize the data model and the various window elements:
++
++ \snippet cachedtable/tableeditor.cpp 0
++
++ First we create the data model and set the SQL database table we
++ want the model to operate on. Note that the
++ QSqlTableModel::setTable() function does not select data from the
++ table; it only fetches its field information. For that reason we
++ call the QSqlTableModel::select() function later on, populating
++ the model with data from the table. The selection can be
++ customized by specifying filters and sort conditions (see the
++ QSqlTableModel class documentation for more details).
++
++ We also set the model's edit strategy. The edit strategy dictates
++ when the changes done by the user in the view, are actually
++ applied to the database. Since we want to cache the changes in the
++ table view (i.e. in the model) until the user explicitly submits
++ them, we choose the QSqlTableModel::OnManualSubmit strategy. The
++ alternatives are QSqlTableModel::OnFieldChange and
++ QSqlTableModel::OnRowChange.
++
++ Finally, we set up the labels displayed in the view header using
++ the \l {QSqlQueryModel::setHeaderData()}{setHeaderData()} function
++ that the model inherits from the QSqlQueryModel class.
++
++ \snippet cachedtable/tableeditor.cpp 1
++
++ Then we create a table view. The QTableView class provides a
++ default model/view implementation of a table view, i.e. it
++ implements a table view that displays items from a model. It also
++ allows the user to edit the items, storing the changes in the
++ model. To create a read only view, set the proper flag using the
++ \l {QAbstractItemView::editTriggers}{editTriggers} property the
++ view inherits from the QAbstractItemView class.
++
++ To make the view present our data, we pass our model to the view
++ using the \l {QAbstractItemView::setModel()}{setModel()} function.
++
++ \snippet cachedtable/tableeditor.cpp 2
++
++ The \c {TableEditor}'s buttons are regular QPushButton objects. We
++ add them to a button box to ensure that the buttons are presented
++ in a layout that is appropriate to the current widget style. The
++ rationale for this is that dialogs and message boxes typically
++ present buttons in a layout that conforms to the interface
++ guidelines for that platform. Invariably, different platforms have
++ different layouts for their dialogs. QDialogButtonBox allows a
++ developer to add buttons to it and will automatically use the
++ appropriate layout for the user's desktop environment.
++
++ Most buttons for a dialog follow certain roles. When adding a
++ button to a button box using the \l
++ {QDialogButtonBox}{addButton()} function, the button's role must
++ be specified using the QDialogButtonBox::ButtonRole
++ enum. Alternatively, QDialogButtonBox provides several standard
++ buttons (e.g. \uicontrol OK, \uicontrol Cancel, \uicontrol Save) that you can
++ use. They exist as flags so you can OR them together in the
++ constructor.
++
++ \snippet cachedtable/tableeditor.cpp 3
++
++ We connect the \uicontrol Quit button to the table editor's \l
++ {QWidget::close()}{close()} slot, and the \uicontrol Submit button to
++ our private \c submit() slot. The latter slot will take care of
++ the data transactions. Finally, we connect the \uicontrol Revert button
++ to our model's \l {QSqlTableModel::revertAll()}{revertAll()} slot,
++ reverting all pending changes (i.e., restoring the original data).
++
++ \snippet cachedtable/tableeditor.cpp 4
++
++ In the end we add the button box and the table view to a layout,
++ install the layout on the table editor widget, and set the
++ editor's window title.
++
++ \snippet cachedtable/tableeditor.cpp 5
++
++ The \c submit() slot is called whenever the users hit the \uicontrol
++ Submit button to save their changes.
++
++ First, we begin a transaction on the database using the
++ QSqlDatabase::transaction() function. A database transaction is a
++ unit of interaction with a database management system or similar
++ system that is treated in a coherent and reliable way independent
++ of other transactions. A pointer to the used database can be
++ obtained using the QSqlTableModel::database() function.
++
++ Then, we try to submit all the pending changes, i.e. the model's
++ modified items. If no error occurs, we commit the transaction to
++ the database using the QSqlDatabase::commit() function (note that
++ on some databases, this function will not work if there is an
++ active QSqlQuery on the database). Otherwise we perform a rollback
++ of the transaction using the QSqlDatabase::rollback() function and
++ post a warning to the user.
++
++ \table 100%
++ \row
++ \li
++ \b {See also:}
++
++ A complete list of Qt's SQL \l {Database Classes}, and the \l
++ {Model/View Programming} documentation.
++
++ \endtable
++ */