Akonadi Contacts

contactsfilterproxymodel.cpp
1 /*
2  This file is part of Akonadi Contact.
3 
4  Copyright (c) 2009 Tobias Koenig <[email protected]>
5 
6  This library is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Library General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or (at your
9  option) any later version.
10 
11  This library is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14  License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301, USA.
20 */
21 
22 #include "contactsfilterproxymodel.h"
23 
24 #include "contactstreemodel.h"
25 
26 #include <entitytreemodel.h>
27 #include <kcontacts/addressee.h>
28 #include <kcontacts/contactgroup.h>
29 
30 using namespace Akonadi;
31 
32 static bool contactMatchesFilter(const KContacts::Addressee &contact, const QString &filterString, ContactsFilterProxyModel::MatchFilterContactFlag flag);
33 static bool contactGroupMatchesFilter(const KContacts::ContactGroup &group, const QString &filterString);
34 
35 
36 class Q_DECL_HIDDEN ContactsFilterProxyModel::Private
37 {
38 public:
39  Private()
40  : flags({})
41  , matchFilterFlag(ContactsFilterProxyModel::MatchFilterContactFlag::All)
42  , mExcludeVirtualCollections(false)
43  {
44  }
45 
46  QString mFilter;
48  ContactsFilterProxyModel::MatchFilterContactFlag matchFilterFlag;
49  bool mExcludeVirtualCollections;
50 };
51 
53  : QSortFilterProxyModel(parent)
54  , d(new Private)
55 {
56  // contact names should be sorted correctly
57  setSortLocaleAware(true);
59 }
60 
62 {
63  delete d;
64 }
65 
67 {
68  d->mFilter = filter;
70 }
71 
73 {
74  const QModelIndex index = sourceModel()->index(row, 0, parent);
75  if (d->mExcludeVirtualCollections) {
77  if (collection.isValid() && collection.isVirtual()) {
78  return false;
79  }
80  }
81 
82  if ((d->mFilter.isEmpty()) && (!(d->flags & ContactsFilterProxyModel::HasEmail))) {
83  return true;
84  }
85 
86  const Akonadi::Item item = index.data(Akonadi::EntityTreeModel::ItemRole).value<Akonadi::Item>();
87 
88  if (item.hasPayload<KContacts::Addressee>()) {
89  const KContacts::Addressee contact = item.payload<KContacts::Addressee>();
90  if (d->flags & ContactsFilterProxyModel::HasEmail) {
91  if (contact.emails().isEmpty()) {
92  return false;
93  }
94  }
95  if (!d->mFilter.isEmpty()) {
96  return contactMatchesFilter(contact, d->mFilter, d->matchFilterFlag);
97  }
98  } else {
99  if (!d->mFilter.isEmpty()) {
100  if (item.hasPayload<KContacts::ContactGroup>()) {
101  const KContacts::ContactGroup group = item.payload<KContacts::ContactGroup>();
102  return contactGroupMatchesFilter(group, d->mFilter);
103  }
104  }
105  }
106 
107  return true;
108 }
109 
110 bool ContactsFilterProxyModel::lessThan(const QModelIndex &leftIndex, const QModelIndex &rightIndex) const
111 {
112  const QDate leftDate = leftIndex.data(ContactsTreeModel::DateRole).toDate();
113  const QDate rightDate = rightIndex.data(ContactsTreeModel::DateRole).toDate();
114  if (leftDate.isValid() && rightDate.isValid()) {
115  if (leftDate.month() < rightDate.month()) {
116  return true;
117  } else if (leftDate.month() == rightDate.month()) {
118  if (leftDate.day() < rightDate.day()) {
119  return true;
120  }
121  } else {
122  return false;
123  }
124  }
125 
126  return QSortFilterProxyModel::lessThan(leftIndex, rightIndex);
127 }
128 
129 void ContactsFilterProxyModel::setMatchFilterContactFlag(ContactsFilterProxyModel::MatchFilterContactFlag flag)
130 {
131  d->matchFilterFlag = flag;
132 }
133 
135 {
136  d->flags = flags;
137 }
138 
140 {
141  if (exclude != d->mExcludeVirtualCollections) {
142  d->mExcludeVirtualCollections = exclude;
144  }
145 }
146 
147 Qt::ItemFlags ContactsFilterProxyModel::flags(const QModelIndex &index) const
148 {
149  if (!index.isValid()) {
150  // Don't crash
151  return Qt::NoItemFlags;
152  }
154  if (collection.isValid()) {
156  }
157  return QSortFilterProxyModel::flags(index);
158 }
159 
160 static bool addressMatchesFilter(const KContacts::Address &address, const QString &filterString)
161 {
162  if (address.street().contains(filterString, Qt::CaseInsensitive)) {
163  return true;
164  }
165 
166  if (address.locality().contains(filterString, Qt::CaseInsensitive)) {
167  return true;
168  }
169 
170  if (address.region().contains(filterString, Qt::CaseInsensitive)) {
171  return true;
172  }
173 
174  if (address.postalCode().contains(filterString, Qt::CaseInsensitive)) {
175  return true;
176  }
177 
178  if (address.country().contains(filterString, Qt::CaseInsensitive)) {
179  return true;
180  }
181 
182  if (address.label().contains(filterString, Qt::CaseInsensitive)) {
183  return true;
184  }
185 
186  if (address.postOfficeBox().contains(filterString, Qt::CaseInsensitive)) {
187  return true;
188  }
189 
190  return false;
191 }
192 
193 static bool contactMatchesFilter(const KContacts::Addressee &contact, const QString &filterString, ContactsFilterProxyModel::MatchFilterContactFlag flag)
194 {
195  if (contact.assembledName().contains(filterString, Qt::CaseInsensitive)) {
196  return true;
197  }
198 
199  if (contact.formattedName().contains(filterString, Qt::CaseInsensitive)) {
200  return true;
201  }
202 
203  if (contact.nickName().contains(filterString, Qt::CaseInsensitive)) {
204  return true;
205  }
206 
207 
208  int count = 0;
209  if (flag == ContactsFilterProxyModel::MatchFilterContactFlag::All) {
210  if (contact.birthday().toString().contains(filterString, Qt::CaseInsensitive)) {
211  return true;
212  }
213  const KContacts::Address::List addresses = contact.addresses();
214  count = addresses.count();
215  for (int i = 0; i < count; ++i) {
216  if (addressMatchesFilter(addresses.at(i), filterString)) {
217  return true;
218  }
219  }
220 
221  const KContacts::PhoneNumber::List phoneNumbers = contact.phoneNumbers();
222  count = phoneNumbers.count();
223  for (int i = 0; i < count; ++i) {
224  if (phoneNumbers.at(i).number().contains(filterString, Qt::CaseInsensitive)) {
225  return true;
226  }
227  }
228  }
229 
230  const QStringList emails = contact.emails();
231  count = emails.count();
232  for (int i = 0; i < count; ++i) {
233  if (emails.at(i).contains(filterString, Qt::CaseInsensitive)) {
234  return true;
235  }
236  }
237 
238 
239  if (flag == ContactsFilterProxyModel::MatchFilterContactFlag::All) {
240  const QStringList categories = contact.categories();
241  count = categories.count();
242  for (int i = 0; i < count; ++i) {
243  if (categories.at(i).contains(filterString, Qt::CaseInsensitive)) {
244  return true;
245  }
246  }
247  if (contact.mailer().contains(filterString, Qt::CaseInsensitive)) {
248  return true;
249  }
250 
251  if (contact.title().contains(filterString, Qt::CaseInsensitive)) {
252  return true;
253  }
254 
255  if (contact.role().contains(filterString, Qt::CaseInsensitive)) {
256  return true;
257  }
258 
259  if (contact.organization().contains(filterString, Qt::CaseInsensitive)) {
260  return true;
261  }
262 
263  if (contact.department().contains(filterString, Qt::CaseInsensitive)) {
264  return true;
265  }
266 
267  if (contact.note().contains(filterString, Qt::CaseInsensitive)) {
268  return true;
269  }
270 
271  if (contact.url().url().url().contains(filterString, Qt::CaseInsensitive)) {
272  return true;
273  }
274 
275  const QStringList customs = contact.customs();
276  count = customs.count();
277  for (int i = 0; i < count; ++i) {
278  if (customs.at(i).contains(filterString, Qt::CaseInsensitive)) {
279  return true;
280  }
281  }
282  }
283 
284  return false;
285 }
286 
287 bool contactGroupMatchesFilter(const KContacts::ContactGroup &group, const QString &filterString)
288 {
289  if (group.name().contains(filterString, Qt::CaseInsensitive)) {
290  return true;
291  }
292 
293  const int count = group.dataCount();
294  for (int i = 0; i < count; ++i) {
295  if (group.data(i).name().contains(filterString, Qt::CaseInsensitive)) {
296  return true;
297  }
298  if (group.data(i).email().contains(filterString, Qt::CaseInsensitive)) {
299  return true;
300  }
301  }
302 
303  return false;
304 }
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
QString street() const
virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const const
void setFilterString(const QString &filter)
Sets the filter that is used to filter for matching contacts and contact groups.
~ContactsFilterProxyModel() override
Destroys the contacts filter proxy model.
QString toString(Qt::DateFormat format) const const
A proxy model for ContactsTreeModel models.
QString region() const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const =0
bool isValid() const
QStringList categories() const
virtual Qt::ItemFlags flags(const QModelIndex &index) const const override
void setFilterFlags(ContactsFilterProxyModel::FilterFlags flags)
Sets the filter flags.
QStringList emails() const
QString organization() const
QString role() const
QString country() const
const T & at(int i) const const
QString nickName() const
T value() const const
QString assembledName() const
int day() const const
void setMatchFilterContactFlag(ContactsFilterProxyModel::MatchFilterContactFlag flag)
setMatchFilterContactFlag
ContactsFilterProxyModel(QObject *parent=nullptr)
Creates a new contacts filter proxy model.
QString mailer() const
The QDate object for the current index.
ResourceLocatorUrl url() const
QString title() const
bool isValid() const const
QString name() const
int count(const T &value) const const
QString postOfficeBox() const
QString label() const
CaseInsensitive
bool isEmpty() const const
bool isValid() const const
QString postalCode() const
void setDynamicSortFilter(bool enable)
QString locality() const
void setExcludeVirtualCollections(bool exclude)
Sets whether we want virtual collections to be filtered or not.
QDateTime birthday() const
QString formattedName() const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QDate toDate() const const
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const const
const T & at(int i) const const
PhoneNumber::List phoneNumbers() const
QAbstractItemModel * sourceModel() const const
QString department() const
QVariant data(int role) const const
void setSortLocaleAware(bool on)
QStringList customs() const
int count(const T &value) const const
Address::List addresses() const
Data & data(int index)
QObject * parent() const const
int month() const const
QString note() const
bool isVirtual() const
typedef ItemFlags
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Tue Jul 7 2020 23:06:20 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.