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