doc/src/examples/drilldown.qdoc
branchRCL_3
changeset 8 3f74d0d4af4c
equal deleted inserted replaced
6:dee5afe5301f 8:3f74d0d4af4c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the documentation of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /*!
       
    43     \example sql/drilldown
       
    44     \title Drill Down Example
       
    45 
       
    46     The Drill Down example shows how to read data from a database as
       
    47     well as submit changes, using the QSqlRelationalTableModel and
       
    48     QDataWidgetMapper classes.
       
    49 
       
    50     \image drilldown-example.png Screenshot of the Drill Down Example
       
    51 
       
    52     When running the example application, a user can retrieve
       
    53     information about each of Nokia's Qt offices by clicking the
       
    54     corresponding image. The application pops up an information window
       
    55     displaying the data, and allows the users to alter the location
       
    56     description as well as the image. The main view will be updated
       
    57     when the users submit their changes.
       
    58 
       
    59     The example consists of three classes:
       
    60 
       
    61     \list
       
    62         \o \c ImageItem is a custom graphics item class used to
       
    63         display the office images.
       
    64 
       
    65         \o \c View is the main application widget allowing the user to
       
    66         browse through the various locations.
       
    67 
       
    68         \o \c InformationWindow displays the requested information,
       
    69         allowing the users to alter it and submit their changes to the
       
    70         database.
       
    71     \endlist
       
    72 
       
    73     We will first take a look at the \c InformationWindow class to see
       
    74     how you can read and modify data from a database. Then we will
       
    75     review the main application widget, i.e., the \c View class, and
       
    76     the associated \c ImageItem class.
       
    77 
       
    78     \section1 InformationWindow Class Definition
       
    79 
       
    80     The \c InformationWindow class is a custom widget inheriting
       
    81     QWidget:
       
    82 
       
    83     \snippet examples/sql/drilldown/informationwindow.h 0
       
    84 
       
    85     When we create an information window, we pass the associated
       
    86     location ID, a parent, and a pointer to the database, to the
       
    87     constructor. We will use the database pointer to populate our
       
    88     window with data, while passing the parent parameter on to the
       
    89     base class. The ID is stored for future reference.
       
    90 
       
    91     Once a window is created, we will use the public \c id() function
       
    92     to locate it whenever information for the given location is
       
    93     requested. We will also use the ID to update the main application
       
    94     widget when the users submit their changes to the database, i.e.,
       
    95     we will emit a signal carrying the ID and file name as parameters
       
    96     whenever the users changes the associated image.
       
    97 
       
    98     \snippet examples/sql/drilldown/informationwindow.h 1
       
    99 
       
   100     Since we allow the users to alter some of the location data, we
       
   101     must provide functionality for reverting and submitting their
       
   102     changes. The \c enableButtons() slot is provided for convenience
       
   103     to enable and disable the various buttons when required.
       
   104 
       
   105     \snippet examples/sql/drilldown/informationwindow.h 2
       
   106 
       
   107     The \c createButtons() function is also a convenience function,
       
   108     provided to simplify the constructor. As mentioned above we store
       
   109     the location ID for future reference. We also store the name of
       
   110     the currently displayed image file to be able to determine when to
       
   111     emit the \c imageChanged() signal.
       
   112 
       
   113     The information window uses the QLabel class to display the office
       
   114     location and the country. The associated image file is displayed
       
   115     using a QComboBox instance while the description is displayed using
       
   116     QTextEdit. In addition, the window has three buttons to control
       
   117     the data flow and whether the window is shown or not.
       
   118 
       
   119     Finally, we declare a \e mapper. The QDataWidgetMapper class
       
   120     provides mapping between a section of a data model to widgets. We
       
   121     will use the mapper to extract data from the given database,
       
   122     updating the database whenever the user modifies the data.
       
   123 
       
   124     \section1 InformationWindow Class Implementation
       
   125 
       
   126     The constructor takes three arguments: a location ID, a database
       
   127     pointer and a parent widget. The database pointer is actually a
       
   128     pointer to a QSqlRelationalTableModel object providing an editable
       
   129     data model (with foreign key support) for our database table.
       
   130 
       
   131     \snippet examples/sql/drilldown/informationwindow.cpp 0
       
   132     \snippet examples/sql/drilldown/informationwindow.cpp 1
       
   133 
       
   134     First we create the various widgets required to display the data
       
   135     contained in the database. Most of the widgets are created in a
       
   136     straight forward manner. But note the combobox displaying the
       
   137     name of the image file:
       
   138 
       
   139     \snippet examples/sql/drilldown/informationwindow.cpp 2
       
   140 
       
   141     In this example, the information about the offices are stored in a
       
   142     database table called "offices". When creating the model,
       
   143     we will use a foreign key to establish a relation between this
       
   144     table and a second data base table, "images", containing the names
       
   145     of the available image files. We will get back to how this is done
       
   146     when reviewing the \c View class. The rationale for creating such
       
   147     a relation though, is that we want to ensure that the user only
       
   148     can choose between predefined image files.
       
   149 
       
   150     The model corresponding to the "images" database table, is
       
   151     available through the QSqlRelationalTableModel's \l
       
   152     {QSqlRelationalTableModel::}{relationModel()} function, requiring
       
   153     the foreign key (in this case the "imagefile" column number) as
       
   154     argument. We use QComboBox's \l {QComboBox::}{setModel()} function
       
   155     to make the combobox use the "images" model. And, since this model
       
   156     has two columns ("locationid" and "file"), we also specify which
       
   157     column we want to be visible using the QComboBox::setModelColumn()
       
   158     function.
       
   159 
       
   160     \snippet examples/sql/drilldown/informationwindow.cpp 3
       
   161 
       
   162     Then we create the mapper. The QDataWidgetMapper class allows us
       
   163     to create data-aware widgets by mapping them to sections of an
       
   164     item model.
       
   165 
       
   166     The \l {QDataWidgetMapper::}{addMapping()} function adds a mapping
       
   167     between the given widget and the specified section of the
       
   168     model. If the mapper's orientation is horizontal (the default) the
       
   169     section is a column in the model, otherwise it is a row. We call
       
   170     the \l {QDataWidgetMapper::}{setCurrentIndex()} function to
       
   171     initialize the widgets with the data associated with the given
       
   172     location ID. Every time the current index changes, all the widgets
       
   173     are updated with the contents from the model.
       
   174 
       
   175     We also set the mapper's submit policy to
       
   176     QDataWidgetMapper::ManualSubmit. This means that no data is
       
   177     submitted to the database until the user expliclity requests a
       
   178     submit (the alternative is QDataWidgetMapper::AutoSubmit,
       
   179     automatically submitting changes when the corresponding widget
       
   180     looses focus). Finally, we specify the item delegate the mapper
       
   181     view should use for its items. The QSqlRelationalDelegate class
       
   182     represents a delegate that unlike the default delegate, enables
       
   183     combobox functionality for fields that are foreign keys into other
       
   184     tables (like "imagefile" in our "trolltechoffices" table).
       
   185 
       
   186     \snippet examples/sql/drilldown/informationwindow.cpp 4
       
   187 
       
   188     Finally, we connect the "something's changed" signals in the
       
   189     editors to our custom \c enableButtons() slot, enabling the users
       
   190     to either submit or revert their changes. We add all the widgets
       
   191     into a layout, store the location ID and the name of the displayed
       
   192     image file for future reference, and set the window title and
       
   193     initial size.
       
   194 
       
   195     Note that we also set the Qt::Window window flag to indicate that
       
   196     our widget is in fact a window, with a window system frame and a
       
   197     title bar.
       
   198 
       
   199     \snippet examples/sql/drilldown/informationwindow.cpp 5
       
   200 
       
   201     When a window is created, it is not deleted until the main
       
   202     application exits (i.e., if the user closes the information
       
   203     window, it is only hidden). For this reason we do not want to
       
   204     create more than one \c InformationWindow object for each
       
   205     location, and we provide the public \c id() function to be able to
       
   206     determine whether a window already exists for a given location
       
   207     when the user requests information about it.
       
   208 
       
   209     \snippet examples/sql/drilldown/informationwindow.cpp 6
       
   210 
       
   211     The \c revert() slot is triggered whenever the user hits the \gui
       
   212     Revert button.
       
   213 
       
   214     Since we set the QDataWidgetMapper::ManualSubmit submit policy,
       
   215     none of the user's changes are written back to the model unless
       
   216     the user expliclity choose to submit all of them. Nevertheless, we
       
   217     can use the QDataWidgetMapper's \l {QDataWidgetMapper::}{revert()}
       
   218     slot to reset the editor widgets, repopulating all widgets with
       
   219     the current data of the model.
       
   220 
       
   221     \snippet examples/sql/drilldown/informationwindow.cpp 7
       
   222 
       
   223     Likewise, the \c submit() slot is triggered whenever the users
       
   224     decide to submit their changes by pressing the \gui Submit button.
       
   225 
       
   226     We use QDataWidgetMapper's \l {QDataWidgetMapper::}{submit()} slot
       
   227     to submit all changes from the mapped widgets to the model,
       
   228     i.e. to the database. For every mapped section, the item delegate
       
   229     will then read the current value from the widget and set it in the
       
   230     model. Finally, the \e model's \l {QAbstractItemModel::}{submit()}
       
   231     function is invoked to let the model know that it should submit
       
   232     whatever it has cached to the permanent storage.
       
   233 
       
   234     Note that before any data is submitted, we check if the user has
       
   235     chosen another image file using the previously stored \c
       
   236     displayedImage variable as reference. If the current and stored
       
   237     file names differ, we store the new file name and emit the \c
       
   238     imageChanged() signal.
       
   239 
       
   240     \snippet examples/sql/drilldown/informationwindow.cpp 8
       
   241 
       
   242     The \c createButtons() function is provided for convenience, i.e.,
       
   243     to simplify the constructor.
       
   244 
       
   245     We make the \gui Close button the default button, i.e., the button
       
   246     that is pressed when the user presses \gui Enter, and connect its
       
   247     \l {QPushButton::}{clicked()} signal to the widget's \l
       
   248     {QWidget::}{close()} slot. As mentioned above closing the window
       
   249     only hides the widget; it is not deleted. We also connect the \gui
       
   250     Submit and \gui Revert buttons to the corresponding \c submit()
       
   251     and \c revert() slots.
       
   252 
       
   253     \snippet examples/sql/drilldown/informationwindow.cpp 9
       
   254 
       
   255     The QDialogButtonBox class is a widget that presents buttons in a
       
   256     layout that is appropriate to the current widget style. Dialogs
       
   257     like our information window, typically present buttons in a layout
       
   258     that conforms to the interface guidelines for that
       
   259     platform. Invariably, different platforms have different layouts
       
   260     for their dialogs. QDialogButtonBox allows us to add buttons,
       
   261     automatically using the appropriate layout for the user's desktop
       
   262     environment.
       
   263 
       
   264     Most buttons for a dialog follow certain roles. We give the \gui
       
   265     Submit and \gui Revert buttons the \l
       
   266     {QDialogButtonBox::ButtonRole}{reset} role, i.e., indicating that
       
   267     pressing the button resets the fields to the default values (in
       
   268     our case the information contained in the database). The \l
       
   269     {QDialogButtonBox::ButtonRole}{reject} role indicates that
       
   270     clicking the button causes the dialog to be rejected. On the other
       
   271     hand, since we only hide the information window, any changes that
       
   272     the user has made wil be preserved until the user expliclity
       
   273     revert or submit them.
       
   274 
       
   275     \snippet examples/sql/drilldown/informationwindow.cpp 10
       
   276 
       
   277     The \c enableButtons() slot is called to enable the buttons
       
   278     whenever the user changes the presented data. Likewise, when the
       
   279     data the user choose to submit the changes, the buttons are
       
   280     disabled to indicate that the current data is stored in the
       
   281     database.
       
   282 
       
   283     This completes the \c InformationWindow class. Let's take a look
       
   284     at how we have used it in our example application.
       
   285 
       
   286     \section1 View Class Definition
       
   287 
       
   288     The \c View class represents the main application window and
       
   289     inherits QGraphicsView:
       
   290 
       
   291     \snippet examples/sql/drilldown/view.h 0
       
   292     \codeline
       
   293     \snippet examples/sql/drilldown/view.h 1
       
   294 
       
   295     The QGraphicsView class is part of the \l {The Graphics View
       
   296     Framework} which we will use to display the images of Nokia's
       
   297     Qt offices. To be able to respond to user interaction;
       
   298     i.e., showing the
       
   299     appropriate information window whenever the user clicks one of the
       
   300     office images, we reimplement QGraphicsView's \l
       
   301     {QGraphicsView::}{mouseReleaseEvent()} function.
       
   302 
       
   303     Note that the constructor expects the names of two database
       
   304     tables: One containing the detailed information about the offices,
       
   305     and another containing the names of the available image files.  We
       
   306     also provide a private \c updateImage() slot to catch \c
       
   307     {InformationWindow}'s \c imageChanged() signal that is emitted
       
   308     whenever the user changes a location's image.
       
   309 
       
   310     \snippet examples/sql/drilldown/view.h 2
       
   311 
       
   312     The \c addItems() function is a convenience function provided to
       
   313     simplify the constructor. It is called only once, creating the
       
   314     various items and adding them to the view.
       
   315 
       
   316     The \c findWindow() function, on the other hand, is frequently
       
   317     used. It is called from the \c showInformation() function to
       
   318     detemine whether a window is already created for the given
       
   319     location (whenever we create an \c InformationWindow object, we
       
   320     store a reference to it in the \c informationWindows list). The
       
   321     latter function is in turn called from our custom \c
       
   322     mouseReleaseEvent() implementation.
       
   323 
       
   324     \snippet examples/sql/drilldown/view.h 3
       
   325 
       
   326     Finally we declare a QSqlRelationalTableModel pointer. As
       
   327     previously mentioned, the QSqlRelationalTableModel class provides
       
   328     an editable data model with foreign key support. There are a
       
   329     couple of things you should keep in mind when using the
       
   330     QSqlRelationalTableModel class: The table must have a primary key
       
   331     declared and this key cannot contain a relation to another table,
       
   332     i.e., it cannot be a foreign key. Note also that if a relational
       
   333     table contains keys that refer to non-existent rows in the
       
   334     referenced table, the rows containing the invalid keys will not be
       
   335     exposed through the model. It is the user's or the database's
       
   336     responsibility to maintain referential integrity.
       
   337 
       
   338     \section1 View Class Implementation
       
   339 
       
   340     Although the constructor requests the names of both the table
       
   341     containing office details as well as the table containing the
       
   342     names of the available image files, we only have to create a
       
   343     QSqlRelationalTableModel object for the office table:
       
   344 
       
   345     \snippet examples/sql/drilldown/view.cpp 0
       
   346 
       
   347     The reason is that once we have a model with the office details,
       
   348     we can create a relation to the available image files using
       
   349     QSqlRelationalTableModel's \l
       
   350     {QSqlRelationalTableModel::}{setRelation()} function. This
       
   351     function creates a foreign key for the given model column. The key
       
   352     is specified by the provided QSqlRelation object constructed by
       
   353     the name of the table the key refers to, the field the key is
       
   354     mapping to and the field that should be presented to the user.
       
   355 
       
   356     Note that setting the table only specifies which table the model
       
   357     operates on, i.e., we must explicitly call the model's \l
       
   358     {QSqlRelationalTableModel::}{select()} function to populate our
       
   359     model.
       
   360 
       
   361     \snippet examples/sql/drilldown/view.cpp 1
       
   362 
       
   363     Then we create the contents of our view, i.e., the scene and its
       
   364     items. The location labels are regular QGraphicsTextItem objects,
       
   365     and the "Qt" logo is represented by a QGraphicsPixmapItem
       
   366     object. The images, on the other hand, are instances of the \c
       
   367     ImageItem class (derived from QGraphicsPixmapItem). We will get
       
   368     back to this shortly when reviewing the \c addItems() function.
       
   369 
       
   370     Finally, we set the main application widget's size constraints and
       
   371     window title.
       
   372 
       
   373     \snippet examples/sql/drilldown/view.cpp 3
       
   374 
       
   375     The \c addItems() function is called only once, i.e., when
       
   376     creating the main application window. For each row in the database
       
   377     table, we first extract the corresponding record using the model's
       
   378     \l {QSqlRelationalTableModel::}{record()} function. The QSqlRecord
       
   379     class encapsulates both the functionality and characteristics of a
       
   380     database record, and supports adding and removing fields as well
       
   381     as setting and retrieving field values. The QSqlRecord::value()
       
   382     function returns the value of the field with the given name or
       
   383     index as a QVariant object.
       
   384 
       
   385     For each record, we create a label item as well as an image item,
       
   386     calculate their position and add them to the scene. The image
       
   387     items are represented by instances of the \c ImageItem class. The
       
   388     reason we must create a custom item class is that we want to catch
       
   389     the item's hover events, animating the item when the mouse cursor
       
   390     is hovering over the image (by default, no items accept hover
       
   391     events). Please see the \l{The Graphics View Framework}
       
   392     documentation and the \l{Graphics View Examples} for more details.
       
   393 
       
   394     \snippet examples/sql/drilldown/view.cpp 5
       
   395 
       
   396     We reimplement QGraphicsView's \l
       
   397     {QGraphicsView::}{mouseReleaseEvent()} event handler to respond to
       
   398     user interaction. If the user clicks any of the image items, this
       
   399     function calls the private \c showInformation() function to pop up
       
   400     the associated information window.
       
   401 
       
   402     \l {The Graphics View Framework} provides the qgraphicsitem_cast()
       
   403     function to determine whether the given QGraphicsItem instance is
       
   404     of a given type. Note that if the event is not related to any of
       
   405     our image items, we pass it on to the base class implementation.
       
   406 
       
   407     \snippet examples/sql/drilldown/view.cpp 6
       
   408 
       
   409     The \c showInformation() function is given an \c ImageItem object
       
   410     as argument, and starts off by extracting the item's location
       
   411     ID. Then it determines if there already is created an information
       
   412     window for this location. If it is, and the window is visible, it
       
   413     ensures that the window is raised to the top of the widget stack
       
   414     and activated. If the window exists but is hidden, calling its \l
       
   415     {QWidget::}{show()} slot gives the same result.
       
   416 
       
   417     If no window for the given location exists, we create one by
       
   418     passing the location ID, a pointer to the model, and our view as a
       
   419     parent, to the \c InformationWindow constructor. Note that we
       
   420     connect the information window's \c imageChanged() signal to \e
       
   421     this widget's \c updateImage() slot, before we give it a suitable
       
   422     position and add it to the list of existing windows.
       
   423 
       
   424     \snippet examples/sql/drilldown/view.cpp 7
       
   425 
       
   426     The \c updateImage() slot takes a location ID and the name of an
       
   427     image files as arguments. It filters out the image items, and
       
   428     updates the one that correspond to the given location ID, with the
       
   429     provided image file.
       
   430 
       
   431     \snippet examples/sql/drilldown/view.cpp 8
       
   432 
       
   433     The \c findWindow() function simply searches through the list of
       
   434     existing windows, returning a pointer to the window that matches
       
   435     the given location ID, or 0 if the window doesn't exists.
       
   436 
       
   437     Finally, let's take a quick look at our custom \c ImageItem class:
       
   438 
       
   439     \section1 ImageItem Class Definition
       
   440 
       
   441     The \c ImageItem class is provided to facilitate animation of the
       
   442     image items. It inherits QGraphicsPixmapItem and reimplements its
       
   443     hover event handlers:
       
   444 
       
   445     \snippet examples/sql/drilldown/imageitem.h 0
       
   446 
       
   447     In addition, we implement a public \c id() function to be able to
       
   448     identify the associated location and a public \c adjust() function
       
   449     that can be called to ensure that the image item is given the
       
   450     preferred size regardless of the original image file.
       
   451 
       
   452     The animation is implemented using the QTimeLine class together
       
   453     with the event handlers and the private \c setFrame() slot: The
       
   454     image item will expand when the mouse cursor hovers over it,
       
   455     returning back to its orignal size when the cursor leaves its
       
   456     borders.
       
   457 
       
   458     Finally, we store the location ID that this particular record is
       
   459     associated with as well as a z-value. In the \l {The Graphics View
       
   460     Framework}, an item's z-value determines its position in the item
       
   461     stack. An item of high Z-value will be drawn on top of an item
       
   462     with a lower z-value if they share the same parent item. We also
       
   463     provide an \c updateItemPosition() function to refresh the view
       
   464     when required.
       
   465 
       
   466     \section1 ImageItem Class Implementation
       
   467 
       
   468     The \c ImageItem class is really only a QGraphicsPixmapItem with
       
   469     some additional features, i.e., we can pass most of the
       
   470     constructor's arguments (the pixmap, parent and scene) on to the
       
   471     base class constructor:
       
   472 
       
   473     \snippet examples/sql/drilldown/imageitem.cpp 0
       
   474 
       
   475     Then we store the ID for future reference, and ensure that our
       
   476     item will accept hover events. Hover events are delivered when
       
   477     there is no current mouse grabber item. They are sent when the
       
   478     mouse cursor enters an item, when it moves around inside the item,
       
   479     and when the cursor leaves an item. As we mentioned earlier, none
       
   480     of the \l {The Graphics View Framework}'s items accept hover
       
   481     event's by default.
       
   482 
       
   483     The QTimeLine class provides a timeline for controlling
       
   484     animations. Its \l {QTimeLine::}{duration} property holds the
       
   485     total duration of the timeline in milliseconds. By default, the
       
   486     time line runs once from the beginning and towards the end. The
       
   487     QTimeLine::setFrameRange() function sets the timeline's frame
       
   488     counter; when the timeline is running, the \l
       
   489     {QTimeLine::}{frameChanged()} signal is emitted each time the
       
   490     frame changes. We set the duration and frame range for our
       
   491     animation, and connect the time line's \l
       
   492     {QTimeLine::}{frameChanged()} and \l {QTimeLine::}{finished()}
       
   493     signals to our private \c setFrame() and \c updateItemPosition()
       
   494     slots.
       
   495 
       
   496     Finally, we call \c adjust() to ensure that the item is given the
       
   497     preferred size.
       
   498 
       
   499     \snippet examples/sql/drilldown/imageitem.cpp 1
       
   500     \codeline
       
   501     \snippet examples/sql/drilldown/imageitem.cpp 2
       
   502 
       
   503     Whenever the mouse cursor enters or leave the image item, the
       
   504     corresponding event handlers are triggered: We first set the time
       
   505     line's direction, making the item expand or shrink,
       
   506     respectively. Then we alter the item's z-value if it is not already
       
   507     set to the expected value.
       
   508 
       
   509     In the case of hover \e enter events, we immediately update the
       
   510     item's position since we want the item to appear on top of all
       
   511     other items as soon as it starts expanding. In the case of hover
       
   512     \e leave events, on the other hand, we postpone the actual update
       
   513     to achieve the same result. But remember that when we constructed
       
   514     our item, we connected the time line's \l
       
   515     {QTimeLine::}{finished()} signal to the \c updateItemPosition()
       
   516     slot. In this way the item is given the correct position in the
       
   517     item stack once the animation is completed. Finally, if the time
       
   518     line is not already running, we start it.
       
   519 
       
   520     \snippet examples/sql/drilldown/imageitem.cpp 3
       
   521 
       
   522     When the time line is running, it triggers the \c setFrame() slot
       
   523     whenever the current frame changes due to the connection we
       
   524     created in the item constructor. It is this slot that controls the
       
   525     animation, expanding or shrinking the image item step by step.
       
   526 
       
   527     We first call the \c adjust() function to ensure that we start off
       
   528     with the item's original size. Then we scale the item with a
       
   529     factor depending on the animation's progress (using the \c frame
       
   530     parameter). Note that by default, the transformation will be
       
   531     relative to the item's top-left corner. Since we want the item to
       
   532     be transformed relative to its center, we must translate the
       
   533     coordinate system before we scale the item.
       
   534 
       
   535     In the end, only the following convenience functions remain:
       
   536 
       
   537     \snippet examples/sql/drilldown/imageitem.cpp 4
       
   538     \codeline
       
   539     \snippet examples/sql/drilldown/imageitem.cpp 5
       
   540     \codeline
       
   541     \snippet examples/sql/drilldown/imageitem.cpp 6
       
   542 
       
   543     The \c adjust() function defines and applies a transformation
       
   544     matrix, ensuring that our image item appears with the preferred
       
   545     size regardless of the size of the source image. The \c id()
       
   546     function is trivial, and is simply provided to be able to identify
       
   547     the item. In the \c updateItemPosition() slot we call the
       
   548     QGraphicsItem::setZValue() function, setting the elevation (i.e.,
       
   549     the position) of the item.
       
   550 */