source: trunk/doc/src/examples/addressbook.qdoc@ 1168

Last change on this file since 1168 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 17.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the documentation of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:FDL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in a
14** written agreement between you and Nokia.
15**
16** GNU Free Documentation License
17** Alternatively, this file may be used under the terms of the GNU Free
18** Documentation License version 1.3 as published by the Free Software
19** Foundation and appearing in the file included in the packaging of this
20** file.
21**
22** If you have questions regarding the use of this file, please contact
23** Nokia at [email protected].
24** $QT_END_LICENSE$
25**
26****************************************************************************/
27
28/*!
29 \example itemviews/addressbook
30 \title Address Book Example
31
32 The address book example shows how to use proxy models to display
33 different views onto data from a single model.
34
35 \image addressbook-example.png Screenshot of the Address Book example
36
37 This example provides an address book that allows contacts to be
38 grouped alphabetically into 9 groups: ABC, DEF, GHI, ... , VW,
39 ..., XYZ. This is achieved by using multiple views on the same
40 model, each of which is filtered using an instance of the
41 QSortFilterProxyModel class.
42
43
44 \section1 Overview
45
46 The address book contains 5 classes: \c MainWindow,
47 \c AddressWidget, \c TableModel, \c NewAddressTab and
48 \c AddDialog. The \c MainWindow class uses \c AddressWidget as
49 its central widget and provides \gui File and \gui Tools menus.
50
51 \image addressbook-classes.png Diagram for Address Book Example
52
53 The \c AddressWidget class is a QTabWidget subclass that is used
54 to manipulate the 10 tabs displayed in the example: the 9
55 alphabet group tabs and an instance of \c NewAddressTab.
56 The \c NewAddressTab class is a subclass of QWidget that
57 is only used whenever the address book is empty, prompting the
58 user to add some contacts. \c AddressWidget also interacts with
59 an instance of \c TableModel to add, edit and remove entries to
60 the address book.
61
62 \c TableModel is a subclass of QAbstractTableModel that provides
63 the standard model/view API to access data. It also holds a
64 QList of \l{QPair}s corresponding to the contacts added.
65 However, this data is not all visible in a single tab. Instead,
66 QTableView is used to provide 9 different views of the same
67 data, according to the alphabet groups.
68
69 QSortFilterProxyModel is the class responsible for filtering
70 the contacts for each group of contacts. Each proxy model uses
71 a QRegExp to filter out contacts that do not belong in the
72 corresponding alphabetical group. The \c AddDialog class is
73 used to obtain information from the user for the address book.
74 This QDialog subclass is instantiated by \c NewAddressTab to
75 add contacts, and by \c AddressWidget to add and edit contacts.
76
77 We begin by looking at the \c TableModel implementation.
78
79
80 \section1 TableModel Class Definition
81
82 The \c TableModel class provides standard API to access data in
83 its QList of \l{QPair}s by subclassing QAbstractTableModel. The
84 basic functions that must be implemented in order to do so are:
85 \c rowCount(), \c columnCount(), \c data(), \c headerData().
86 For TableModel to be editable, it has to provide implementations
87 \c insertRows(), \c removeRows(), \c setData() and \c flags()
88 functions.
89
90 \snippet itemviews/addressbook/tablemodel.h 0
91
92 Two constructors are used, a default constructor which uses
93 \c TableModel's own \c {QList<QPair<QString, QString>>} and one
94 that takes \c {QList<QPair<QString, QString>} as an argument,
95 for convenience.
96
97
98 \section1 TableModel Class Implementation
99
100 We implement the two constructors as defined in the header file.
101 The second constructor initializes the list of pairs in the
102 model, with the parameter value.
103
104 \snippet itemviews/addressbook/tablemodel.cpp 0
105
106 The \c rowCount() and \c columnCount() functions return the
107 dimensions of the model. Whereas, \c rowCount()'s value will vary
108 depending on the number of contacts added to the address book,
109 \c columnCount()'s value is always 2 because we only need space
110 for the \bold Name and \bold Address columns.
111
112 \note The \c Q_UNUSED() macro prevents the compiler from
113 generating warnings regarding unused parameters.
114
115 \snippet itemviews/addressbook/tablemodel.cpp 1
116
117 The \c data() function returns either a \bold Name or
118 \bold {Address}, based on the contents of the model index
119 supplied. The row number stored in the model index is used to
120 reference an item in the list of pairs. Selection is handled
121 by the QItemSelectionModel, which will be explained with
122 \c AddressWidget.
123
124 \snippet itemviews/addressbook/tablemodel.cpp 2
125
126 The \c headerData() function displays the table's header,
127 \bold Name and \bold Address. If you require numbered entries
128 for your address book, you can use a vertical header which we
129 have hidden in this example (see the \c AddressWidget
130 implementation).
131
132 \snippet itemviews/addressbook/tablemodel.cpp 3
133
134 The \c insertRows() function is called before new data is added,
135 otherwise the data will not be displayed. The
136 \c beginInsertRows() and \c endInsertRows() functions are called
137 to ensure all connected views are aware of the changes.
138
139 \snippet itemviews/addressbook/tablemodel.cpp 4
140
141 The \c removeRows() function is called to remove data. Again,
142 \l{QAbstractItemModel::}{beginRemoveRows()} and
143 \l{QAbstractItemModel::}{endRemoveRows()} are called to ensure
144 all connected views are aware of the changes.
145
146 \snippet itemviews/addressbook/tablemodel.cpp 5
147
148 The \c setData() function is the function that inserts data into
149 the table, item by item and not row by row. This means that to
150 fill a row in the address book, \c setData() must be called
151 twice, as each row has 2 columns. It is important to emit the
152 \l{QAbstractItemModel::}{dataChanged()} signal as it tells all
153 connected views to update their displays.
154
155 \snippet itemviews/addressbook/tablemodel.cpp 6
156
157 The \c flags() function returns the item flags for the given
158 index.
159
160 \snippet itemviews/addressbook/tablemodel.cpp 7
161
162 We set the Qt::ItemIsEditable flag because we want to allow the
163 \c TableModel to be edited. Although for this example we don't
164 use the editing features of the QTableView object, we enable
165 them here so that we can reuse the model in other programs.
166
167 The last function in \c {TableModel}, \c getList() returns the
168 QList<QPair<QString, QString>> object that holds all the
169 contacts in the address book. We use this function later to
170 obtain the list of contacts to check for existing entries, write
171 the contacts to a file and read them back. Further explanation is
172 given with \c AddressWidget.
173
174 \snippet itemviews/addressbook/tablemodel.cpp 8
175
176
177 \section1 AddressWidget Class Definition
178
179 The \c AddressWidget class is technically the main class
180 involved in this example as it provides functions to add, edit
181 and remove contacts, to save the contacts to a file and to load
182 them from a file.
183
184 \snippet itemviews/addressbook/addresswidget.h 0
185
186 \c AddressWidget extends QTabWidget in order to hold 10 tabs
187 (\c NewAddressTab and the 9 alphabet group tabs) and also
188 manipulates \c table, the \c TableModel object, \c proxyModel,
189 the QSortFilterProxyModel object that we use to filter the
190 entries, and \c tableView, the QTableView object.
191
192
193 \section1 AddressWidget Class Implementation
194
195 The \c AddressWidget constructor accepts a parent widget and
196 instantiates \c NewAddressTab, \c TableModel and
197 QSortFilterProxyModel. The \c NewAddressTab object, which is
198 used to indicate that the address book is empty, is added
199 and the rest of the 9 tabs are set up with \c setupTabs().
200
201 \snippet itemviews/addressbook/addresswidget.cpp 0
202
203 The \c setupTabs() function is used to set up the 9 alphabet
204 group tabs, table views and proxy models in
205 \c AddressWidget. Each proxy model in turn is set to filter
206 contact names according to the relevant alphabet group using a
207 \l{Qt::CaseInsensitive}{case-insensitive} QRegExp object. The
208 table views are also sorted in ascending order using the
209 corresponding proxy model's \l{QSortFilterProxyModel::}{sort()}
210 function.
211
212 Each table view's \l{QTableView::}{selectionMode} is set to
213 QAbstractItemView::SingleSelection and
214 \l{QTableView::}{selectionBehavior} is set to
215 QAbstractItemView::SelectRows, allowing the user to select
216 all the items in one row at the same time. Each QTableView object
217 is automatically given a QItemSelectionModel that keeps track
218 of the selected indexes.
219
220 \snippet itemviews/addressbook/addresswidget.cpp 1
221
222 The QItemSelectionModel class provides a
223 \l{QItemSelectionModel::selectionChanged()}{selectionChanged}
224 signal that is connected to \c{AddressWidget}'s
225 \c selectionChanged() signal. This signal to signal connection
226 is necessary to enable the \gui{Edit Entry...} and
227 \gui{Remove Entry} actions in \c MainWindow's Tools menu. This
228 connection is further explained in \c MainWindow's
229 implementation.
230
231 Each table view in the address book is added as a tab to the
232 QTabWidget with the relevant label, obtained from the QStringList
233 of groups.
234
235 \image addressbook-signals.png Signals and Slots Connections
236
237 We provide 2 \c addEntry() functions: 1 which is intended to be
238 used to accept user input, and the other which performs the actual
239 task of adding new entries to the address book. We divide the
240 responsibility of adding entries into two parts to allow
241 \c newAddressTab to insert data without having to popup a dialog.
242
243 The first \c addEntry() function is a slot connected to the
244 \c MainWindow's \gui{Add Entry...} action. This function creates an
245 \c AddDialog object and then calls the second \c addEntry()
246 function to actually add the contact to \c table.
247
248 \snippet itemviews/addressbook/addresswidget.cpp 2
249
250 Basic validation is done in the second \c addEntry() function to
251 prevent duplicate entries in the address book. As mentioned with
252 \c TableModel, this is part of the reason why we require the
253 getter method \c getList().
254
255 \snippet itemviews/addressbook/addresswidget.cpp 3
256
257 If the model does not already contain an entry with the same name,
258 we call \c setData() to insert the name and address into the
259 first and second columns. Otherwise, we display a QMessageBox
260 to inform the user.
261
262 \note The \c newAddressTab is removed once a contact is added
263 as the address book is no longer empty.
264
265 Editing an entry is a way to update the contact's address only,
266 as the example does not allow the user to change the name of an
267 existing contact.
268
269 Firstly, we obtain the active tab's QTableView object using
270 QTabWidget::currentWidget(). Then we extract the
271 \c selectionModel from the \c tableView to obtain the selected
272 indexes.
273
274 \snippet itemviews/addressbook/addresswidget.cpp 4a
275
276 Next we extract data from the row the user intends to
277 edit. This data is displayed in an instance of \c AddDialog
278 with a different window title. The \c table is only
279 updated if changes have been made to data in \c aDialog.
280
281 \snippet itemviews/addressbook/addresswidget.cpp 4b
282
283 \image addressbook-editdialog.png Screenshot of Dialog to Edit a Contact
284
285 Entries are removed using the \c removeEntry() function.
286 The selected row is removed by accessing it through the
287 QItemSelectionModel object, \c selectionModel. The
288 \c newAddressTab is re-added to the \c AddressWidget only if
289 the user removes all the contacts in the address book.
290
291 \snippet itemviews/addressbook/addresswidget.cpp 5
292
293 The \c writeToFile() function is used to save a file containing
294 all the contacts in the address book. The file is saved in a
295 custom \c{.dat} format. The contents of the QList of \l{QPair}s
296 are written to \c file using QDataStream. If the file cannot be
297 opened, a QMessageBox is displayed with the related error message.
298
299 \snippet itemviews/addressbook/addresswidget.cpp 6
300
301 The \c readFromFile() function loads a file containing all the
302 contacts in the address book, previously saved using
303 \c writeToFile(). QDataStream is used to read the contents of a
304 \c{.dat} file into a list of pairs and each of these is added
305 using \c addEntry().
306
307 \snippet itemviews/addressbook/addresswidget.cpp 7
308
309
310 \section1 NewAddressTab Class Definition
311
312 The \c NewAddressTab class provides an informative tab telling
313 the user that the address book is empty. It appears and
314 disappears according to the contents of the address book, as
315 mentioned in \c{AddressWidget}'s implementation.
316
317 \image addressbook-newaddresstab.png Screenshot of NewAddressTab
318
319 The \c NewAddressTab class extends QWidget and contains a QLabel
320 and QPushButton.
321
322 \snippet itemviews/addressbook/newaddresstab.h 0
323
324
325 \section1 NewAddressTab Class Implementation
326
327 The constructor instantiates the \c addButton,
328 \c descriptionLabel and connects the \c{addButton}'s signal to
329 the \c{addEntry()} slot.
330
331 \snippet itemviews/addressbook/newaddresstab.cpp 0
332
333 The \c addEntry() function is similar to \c AddressWidget's
334 \c addEntry() in the sense that both functions instantiate an
335 \c AddDialog object. Data from the dialog is extracted and sent
336 to \c AddressWidget's \c addEntry() slot by emitting the
337 \c sendDetails() signal.
338
339 \snippet itemviews/addressbook/newaddresstab.cpp 1
340
341 \image signals-n-slots-aw-nat.png
342
343
344 \section1 AddDialog Class Definition
345
346 The \c AddDialog class extends QDialog and provides the user
347 with a QLineEdit and a QTextEdit to input data into the
348 address book.
349
350 \snippet itemviews/addressbook/adddialog.h 0
351
352 \image addressbook-adddialog.png
353
354
355 \section1 AddDialog Class Implementation
356
357 The \c AddDialog's constructor sets up the user interface,
358 creating the necessary widgets and placing them into layouts.
359
360 \snippet itemviews/addressbook/adddialog.cpp 0
361
362 To give the dialog the desired behavior, we connect the \gui OK
363 and \gui Cancel buttons to the dialog's \l{QDialog::}{accept()} and
364 \l{QDialog::}{reject()} slots. Since the dialog only acts as a
365 container for name and address information, we do not need to
366 implement any other functions for it.
367
368
369 \section1 MainWindow Class Definition
370
371 The \c MainWindow class extends QMainWindow and implements the
372 menus and actions necessary to manipulate the address book.
373
374 \table
375 \row \o \inlineimage addressbook-filemenu.png
376 \o \inlineimage addressbook-toolsmenu.png
377 \endtable
378
379 \snippet itemviews/addressbook/mainwindow.h 0
380
381 The \c MainWindow class uses an \c AddressWidget as its central
382 widget and provides the File menu with \gui Open, \gui Close and
383 \gui Exit actions, as well as the \gui Tools menu with
384 \gui{Add Entry...}, \gui{Edit Entry...} and \gui{Remove Entry}
385 actions.
386
387
388 \section1 MainWindow Class Implementation
389
390 The constructor for \c MainWindow instantiates AddressWidget,
391 sets it as its central widget and calls the \c createMenus()
392 function.
393
394 \snippet itemviews/addressbook/mainwindow.cpp 0
395
396 The \c createMenus() function sets up the \gui File and
397 \gui Tools menus, connecting the actions to their respective slots.
398 Both the \gui{Edit Entry...} and \gui{Remove Entry} actions are
399 disabled by default as such actions cannot be carried out on an empty
400 address book. They are only enabled when one or more contacts
401 are added.
402
403 \snippet itemviews/addressbook/mainwindow.cpp 1a
404 \dots
405 \codeline
406 \snippet itemviews/addressbook/mainwindow.cpp 1b
407
408 Apart from connecting all the actions' signals to their
409 respective slots, we also connect \c AddressWidget's
410 \c selectionChanged() signal to its \c updateActions() slot.
411
412 The \c openFile() function allows the user to choose a file with
413 the \l{QFileDialog::getOpenFileName()}{open file dialog}. The chosen
414 file has to be a custom \c{.dat} file that contains address book
415 contacts. This function is a slot connected to \c openAct in the
416 \gui File menu.
417
418 \snippet itemviews/addressbook/mainwindow.cpp 2
419
420 The \c saveFile() function allows the user to save a file with
421 the \l{QFileDialog::getSaveFileName()}{save file dialog}. This function
422 is a slot connected to \c saveAct in the \gui File menu.
423
424 \snippet itemviews/addressbook/mainwindow.cpp 3
425
426 The \c updateActions() function enables and disables
427 \gui{Edit Entry...} and \gui{Remove Entry} depending on the contents of
428 the address book. If the address book is empty, these actions
429 are disabled; otherwise, they are enabled. This function is a slot
430 is connected to the \c AddressWidget's \c selectionChanged()
431 signal.
432
433 \snippet itemviews/addressbook/mainwindow.cpp 4
434
435
436 \section1 main() Function
437
438 The main function for the address book instantiates QApplication
439 and opens a \c MainWindow before running the event loop.
440
441 \snippet itemviews/addressbook/main.cpp 0
442*/
Note: See TracBrowser for help on using the repository browser.