// 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 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
*/
