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