1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
|
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\example itemviews/customsortfiltermodel
\title Custom Sort/Filter Model Example
The Custom Sort/Filter Model example illustrates how to subclass
QSortFilterProxyModel to perform advanced sorting and filtering.
\image customsortfiltermodel-example.png Screenshot of the Custom Sort/Filter Model Example
The QSortFilterProxyModel class provides support for sorting and
filtering data passed between another model and a view.
The model transforms the structure of a source model by mapping
the model indexes it supplies to new indexes, corresponding to
different locations, for views to use. This approach allows a
given source model to be restructured as far as views are
concerned, without requiring any transformations on the underlying
data and without duplicating the data in memory.
The Custom Sort/Filter Model example consists of two classes:
\list
\o The \c MySortFilterProxyModel class provides a custom proxy
model.
\o The \c Window class provides the main application window,
using the custom proxy model to sort and filter a standard
item model.
\endlist
We will first take a look at the \c MySortFilterProxyModel class
to see how the custom proxy model is implemented, then we will
take a look at the \c Window class to see how the model is
used. Finally we will take a quick look at the \c main() function.
\section1 MySortFilterProxyModel Class Definition
The \c MySortFilterProxyModel class inherits the
QSortFilterProxyModel class.
Since QAbstractProxyModel and its subclasses are derived from
QAbstractItemModel, much of the same advice about subclassing
normal models also applies to proxy models.
On the other hand, it is worth noting that many of
QSortFilterProxyModel's default implementations of functions are
written so that they call the equivalent functions in the relevant
source model. This simple proxying mechanism may need to be
overridden for source models with more complex behavior; in this
example we derive from the QSortFilterProxyModel class to ensure
that our filter can recognize a valid range of dates, and to
control the sorting behavior.
\snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.h 0
We want to be able to filter our data by specifying a given period
of time. For that reason, we implement the custom \c
setFilterMinimumDate() and \c setFilterMaximumDate() functions as
well as the corresponding \c filterMinimumDate() and \c
filterMaximumDate() functions. We reimplement
QSortFilterProxyModel's \l
{QSortFilterProxyModel::filterAcceptsRow()}{filterAcceptsRow()}
function to only accept rows with valid dates, and
QSortFilterProxyModel::lessThan() to be able to sort the senders
by their email adresses. Finally, we implement a \c dateInRange()
convenience function that we will use to determine if a date is
valid.
\section1 MySortFilterProxyModel Class Implementation
The \c MySortFilterProxyModel constructor is trivial, passing the
parent parameter on to the base class constructor:
\snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 0
The most interesting parts of the \c MySortFilterProxyModel
implementation are the reimplementations of
QSortFilterProxyModel's \l
{QSortFilterProxyModel::filterAcceptsRow()}{filterAcceptsRow()}
and \l {QSortFilterProxyModel::lessThan()}{lessThan()}
functions. Let's first take a look at our customized \c lessThan()
function.
\snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 4
We want to sort the senders by their email adresses. The \l
{QSortFilterProxyModel::}{lessThan()} function is used as the <
operator when sorting. The default implementation handles a
collection of types including QDateTime and String, but in order
to be able to sort the senders by their email adresses we must
first identify the adress within the given string:
\snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 6
We use QRegExp to define a pattern for the adresses we are looking
for. The QRegExp::indexIn() function attempts to find a match in
the given string and returns the position of the first match, or
-1 if there was no match. If the given string contains the
pattern, we use QRegExp's \l {QRegExp::cap()}{cap()} function to
retrieve the actual adress. The \l {QRegExp::cap()}{cap()}
function returns the text captured by the \e nth
subexpression. The entire match has index 0 and the parenthesized
subexpressions have indexes starting from 1 (excluding
non-capturing parentheses).
\snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 3
The \l
{QSortFilterProxyModel::filterAcceptsRow()}{filterAcceptsRow()}
function, on the other hand, is expected to return true if the
given row should be included in the model. In our example, a row
is accepted if either the subject or the sender contains the given
regular expression, and the date is valid.
\snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 7
We use our custom \c dateInRange() function to determine if a date
is valid.
To be able to filter our data by specifying a given period of
time, we also implement functions for getting and setting the
minimum and maximum dates:
\snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 1
\codeline
\snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 2
The get functions, \c filterMinimumDate() and \c
filterMaximumDate(), are trivial and implemented as inline
function in the header file.
This completes our custom proxy model. Let's see how we can use it
in an application.
\section1 Window Class Definition
The \c CustomFilter class inherits QWidget, and provides this
example's main application window:
\snippet examples/itemviews/customsortfiltermodel/window.h 0
We implement two private slots, \c textFilterChanged() and \c
dateFilterChanged(), to respond to the user changing the filter
pattern, case sensitivity or any of the dates. In addition, we
implement a public \c setSourceModel() convenience function to set
up the model/ view relation.
\section1 Window Class Implementation
In this example, we have chosen to create and set the source model
in the \c main () function (which we will come back to later). So
when constructing the main application window, we assume that a
source model already exists and start by creating an instance of
our custom proxy model:
\snippet examples/itemviews/customsortfiltermodel/window.cpp 0
We set the \l
{QSortFilterProxyModel::dynamicSortFilter}{dynamicSortFilter}
property that holds whether the proxy model is dynamically sorted
and filtered. By setting this property to true, we ensure that the
model is sorted and filtered whenever the contents of the source
model change.
The main application window shows views of both the source model
and the proxy model. The source view is quite simple:
\snippet examples/itemviews/customsortfiltermodel/window.cpp 1
The QTreeView class provides a default model/view implementation
of a tree view; our view implements a tree representation of items
in the application's source model.
\snippet examples/itemviews/customsortfiltermodel/window.cpp 2
The QTreeView class provides a default model/view implementation
of a tree view; our view implements a tree representation of items
in the application's source model. We add our view widget to a
layout that we install on a corresponding group box.
The proxy model view, on the other hand, contains several widgets
controlling the various aspects of transforming the source model's
data structure:
\snippet examples/itemviews/customsortfiltermodel/window.cpp 3
\snippet examples/itemviews/customsortfiltermodel/window.cpp 4
Note that whenever the user changes one of the filtering options,
we must explicitly reapply the filter. This is done by connecting
the various editors to functions that update the proxy model.
\snippet examples/itemviews/customsortfiltermodel/window.cpp 5
The sorting will be handled by the view. All we have to do is to
enable sorting for our proxy view by setting the
QTreeView::sortingEnabled property (which is false by
default). Then we add all the filtering widgets and the proxy view
to a layout that we install on a corresponding group box.
\snippet examples/itemviews/customsortfiltermodel/window.cpp 6
Finally, after putting our two group boxes into another layout
that we install on our main application widget, we customize the
application window.
As mentioned above, we create the source model in the \c main ()
function, calling the \c Window::setSourceModel() function to make
the application use it:
\snippet examples/itemviews/customsortfiltermodel/window.cpp 7
The QSortFilterProxyModel::setSourceModel() function makes the
proxy model process the data in the given model, in this case out
mail model. The \l {QAbstractItemView::}{setModel()} that the
view widget inherits from the QAbstractItemModel class, sets the
model for the view to present. Note that the latter function will
also create and set a new selection model.
\snippet examples/itemviews/customsortfiltermodel/window.cpp 8
The \c textFilterChanged() function is called whenever the user
changes the filter pattern or the case sensitivity.
We first retrieve the preferred syntax (the QRegExp::PatternSyntax
enum is used to interpret the meaning of the given pattern), then
we determine the preferred case sensitivity. Based on these
preferences and the current filter pattern, we set the proxy
model's \l {QSortFilterProxyModel::}{filterRegExp} property. The
\l {QSortFilterProxyModel::}{filterRegExp} property holds the
regular expression used to filter the contents of the source
model. Note that calling QSortFilterProxyModel's \l
{QSortFilterProxyModel::}{setFilterRegExp()} function also updates
the model.
\snippet examples/itemviews/customsortfiltermodel/window.cpp 9
The \c dateFilterChanged() function is called whenever the user
modifies the range of valid dates. We retrieve the new dates from
the user interface, and call the corresponding functions (provided
by our custom proxy model) to set the proxy model's minimum and
maximum dates. As we explained above, calling these functions also
updates the model.
\section1 The Main() Function
In this example, we have separated the application from the source
model by creating the model in the \c main () function. First we
create the application, then we create the source model:
\snippet examples/itemviews/customsortfiltermodel/main.cpp 0
The \c createMailModel() function is a convenience function
provided to simplify the constructor. All it does is to create and
return a model describing a collection of emails. The model is an
instance of the QStandardItemModel class, i.e., a generic model
for storing custom data typically used as a repository for
standard Qt data types. Each mail description is added to the
model using \c addMail(), another convenience function. See \l
{itemviews/customsortfiltermodel/main.cpp}{main.cpp} for details.
*/
|