File indexing completed on 2023-11-26 08:16:44
0001 /* 0002 * Provide some filters on the account model 0003 * 0004 * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk> 0005 * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com> 0006 * Copyright (C) 2012 Daniele E. Domenichelli <daniele.domenichelli@gmail.com> 0007 * Copyright (C) 2012 Dominik Cermak <d.cermak@arcor.de> 0008 * 0009 * This library is free software; you can redistribute it and/or 0010 * modify it under the terms of the GNU Lesser General Public 0011 * License as published by the Free Software Foundation; either 0012 * version 2.1 of the License, or (at your option) any later version. 0013 * 0014 * This library is distributed in the hope that it will be useful, 0015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 * Lesser General Public License for more details. 0018 * 0019 * You should have received a copy of the GNU Lesser General Public 0020 * License along with this library; if not, write to the Free Software 0021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 0022 */ 0023 0024 #include "contacts-filter-model.h" 0025 0026 #include "types.h" 0027 0028 #include <presence.h> 0029 0030 #include "debug.h" 0031 0032 0033 class KTp::ContactsFilterModel::Private 0034 { 0035 public: 0036 Private(ContactsFilterModel *parent) 0037 : q(parent), 0038 presenceTypeFilterFlags(DoNotFilterByPresence), 0039 capabilityFilterFlags(DoNotFilterByCapability), 0040 subscriptionStateFilterFlags(DoNotFilterBySubscription), 0041 globalFilterMatchFlags(Qt::MatchContains), 0042 displayNameFilterMatchFlags(Qt::MatchContains), 0043 nicknameFilterMatchFlags(Qt::MatchContains), 0044 aliasFilterMatchFlags(Qt::MatchContains), 0045 groupsFilterMatchFlags(Qt::MatchContains), 0046 idFilterMatchFlags(Qt::MatchContains) 0047 { 0048 } 0049 0050 ContactsFilterModel *q; 0051 0052 PresenceTypeFilterFlags presenceTypeFilterFlags; 0053 CapabilityFilterFlags capabilityFilterFlags; 0054 SubscriptionStateFilterFlags subscriptionStateFilterFlags; 0055 0056 QString globalFilterString; 0057 Qt::MatchFlags globalFilterMatchFlags; 0058 0059 QString displayNameFilterString; 0060 QString nicknameFilterString; 0061 QString aliasFilterString; 0062 QString groupsFilterString; 0063 QString idFilterString; 0064 QStringList tubesFilterStrings; 0065 Qt::MatchFlags displayNameFilterMatchFlags; 0066 Qt::MatchFlags nicknameFilterMatchFlags; 0067 Qt::MatchFlags aliasFilterMatchFlags; 0068 Qt::MatchFlags groupsFilterMatchFlags; 0069 Qt::MatchFlags idFilterMatchFlags; 0070 Tp::AccountPtr accountFilter; 0071 0072 bool filterAcceptsAccount(const QModelIndex &index) const; 0073 bool filterAcceptsContact(const QModelIndex &index) const; 0074 bool filterAcceptsGroup(const QModelIndex &index); 0075 0076 void sourceModelParentIndexChanged(const QModelIndex &sourceIndex); 0077 void sourceModelIndexChanged(const QModelIndex &sourceIndex); 0078 }; 0079 0080 using namespace KTp; 0081 0082 bool ContactsFilterModel::Private::filterAcceptsAccount(const QModelIndex &index) const 0083 { 0084 // Check capability 0085 if (capabilityFilterFlags != DoNotFilterByCapability) { 0086 if ((capabilityFilterFlags & FilterByTextChatCapability) 0087 && !index.data(KTp::ContactCanTextChatRole).toBool()) { 0088 return false; 0089 } 0090 if ((capabilityFilterFlags & FilterByAudioCallCapability) 0091 && !index.data(KTp::ContactCanAudioCallRole).toBool()) { 0092 return false; 0093 } 0094 if ((capabilityFilterFlags & FilterByVideoCallCapability) 0095 && !index.data(KTp::ContactCanVideoCallRole).toBool()) { 0096 return false; 0097 } 0098 if ((capabilityFilterFlags & FilterByFileTransferCapability) 0099 && !index.data(KTp::ContactCanFileTransferRole).toBool()) { 0100 return false; 0101 } 0102 if (capabilityFilterFlags & FilterByTubes) { 0103 Q_FOREACH(const QString &tube, index.data(KTp::ContactTubesRole).toStringList()) { 0104 if (tubesFilterStrings.contains(tube)) { 0105 return true; 0106 } 0107 } 0108 return false; 0109 } 0110 } 0111 0112 return true; 0113 } 0114 0115 bool ContactsFilterModel::Private::filterAcceptsContact(const QModelIndex &index) const 0116 { 0117 // Presence type, capability and subscription state are always checked 0118 // Then if global filter is set we can return true if a result is found for 0119 // any of the strings, otherwise we check all of them 0120 0121 Q_ASSERT(index.isValid()); 0122 if (!index.isValid()) { 0123 return false; 0124 } 0125 0126 //always return all subcontacts of a metacontact 0127 if (index.parent().isValid() && index.parent().data(KTp::RowTypeRole).toUInt() == KTp::PersonRowType) { 0128 return true; 0129 } 0130 0131 // Check presence type 0132 if (presenceTypeFilterFlags != DoNotFilterByPresence) { 0133 switch (static_cast<Tp::ConnectionPresenceType>(index.data(KTp::ContactPresenceTypeRole).toUInt())) { 0134 case Tp::ConnectionPresenceTypeUnset: 0135 if (presenceTypeFilterFlags & HidePresenceTypeUnset) { 0136 return false; 0137 } 0138 break; 0139 case Tp::ConnectionPresenceTypeOffline: 0140 if (presenceTypeFilterFlags & HidePresenceTypeOffline) { 0141 return false; 0142 } 0143 break; 0144 case Tp::ConnectionPresenceTypeAvailable: 0145 if (presenceTypeFilterFlags & HidePresenceTypeAvailable) { 0146 return false; 0147 } 0148 break; 0149 case Tp::ConnectionPresenceTypeAway: 0150 if (presenceTypeFilterFlags & HidePresenceTypeAway) { 0151 return false; 0152 } 0153 break; 0154 case Tp::ConnectionPresenceTypeExtendedAway: 0155 if (presenceTypeFilterFlags & HidePresenceTypeExtendedAway) { 0156 return false; 0157 } 0158 break; 0159 case Tp::ConnectionPresenceTypeHidden: 0160 if (presenceTypeFilterFlags & HidePresenceTypeHidden) { 0161 return false; 0162 } 0163 break; 0164 case Tp::ConnectionPresenceTypeBusy: 0165 if (presenceTypeFilterFlags & HidePresenceTypeBusy) { 0166 return false; 0167 } 0168 break; 0169 case Tp::ConnectionPresenceTypeUnknown: 0170 if (presenceTypeFilterFlags & HidePresenceTypeUnknown) { 0171 return false; 0172 } 0173 break; 0174 case Tp::ConnectionPresenceTypeError: 0175 if (presenceTypeFilterFlags & HidePresenceTypeError) { 0176 return false; 0177 } 0178 break; 0179 default: 0180 //This should never happen 0181 Q_ASSERT(false); 0182 return false; 0183 } 0184 } 0185 0186 0187 // Check capability 0188 if (capabilityFilterFlags != DoNotFilterByCapability) { 0189 if ((capabilityFilterFlags & FilterByTextChatCapability) 0190 && !index.data(KTp::ContactCanTextChatRole).toBool()) { 0191 return false; 0192 } 0193 if ((capabilityFilterFlags & FilterByAudioCallCapability) 0194 && !index.data(KTp::ContactCanAudioCallRole).toBool()) { 0195 return false; 0196 } 0197 if ((capabilityFilterFlags & FilterByVideoCallCapability) 0198 && !index.data(KTp::ContactCanVideoCallRole).toBool()) { 0199 return false; 0200 } 0201 if ((capabilityFilterFlags & FilterByFileTransferCapability) 0202 && !index.data(KTp::ContactCanFileTransferRole).toBool()) { 0203 return false; 0204 } 0205 if (capabilityFilterFlags & FilterByTubes) { 0206 if (!tubesFilterStrings.isEmpty()) { 0207 bool tubeFound = false; 0208 Q_FOREACH(const QString &tube, index.data(KTp::ContactTubesRole).toStringList()) { 0209 if (tubesFilterStrings.contains(tube)) { 0210 tubeFound = true; 0211 } 0212 } 0213 if (!tubeFound) { 0214 return false; 0215 } 0216 } 0217 } 0218 } 0219 0220 0221 // Check subscription state 0222 if (subscriptionStateFilterFlags != DoNotFilterBySubscription) { 0223 switch (index.data(KTp::ContactSubscriptionStateRole).toUInt()) { 0224 case Tp::Contact::PresenceStateNo: 0225 if (subscriptionStateFilterFlags & HideSubscriptionStateNo) { 0226 return false; 0227 } 0228 break; 0229 case Tp::Contact::PresenceStateAsk: 0230 if (subscriptionStateFilterFlags & HideSubscriptionStateAsk) { 0231 return false; 0232 } 0233 break; 0234 case Tp::Contact::PresenceStateYes: 0235 if (subscriptionStateFilterFlags & HideSubscriptionStateYes) { 0236 return false; 0237 } 0238 break; 0239 default: 0240 //This should never happen 0241 Q_ASSERT(false); 0242 return false; 0243 } 0244 0245 switch (index.data(KTp::ContactPublishStateRole).toUInt()) { 0246 case Tp::Contact::PresenceStateNo: 0247 if (subscriptionStateFilterFlags & HidePublishStateNo) { 0248 return false; 0249 } 0250 break; 0251 case Tp::Contact::PresenceStateAsk: 0252 if (subscriptionStateFilterFlags & HidePublishStateAsk) { 0253 return false; 0254 } 0255 break; 0256 case Tp::Contact::PresenceStateYes: 0257 if (subscriptionStateFilterFlags & HidePublishStateYes) { 0258 return false; 0259 } 0260 break; 0261 default: 0262 //This should never happen 0263 Q_ASSERT(false); 0264 return false; 0265 } 0266 0267 if (index.data(KTp::ContactIsBlockedRole).toBool()) { 0268 if (subscriptionStateFilterFlags & HideBlocked) { 0269 return false; 0270 } 0271 } else { 0272 if (subscriptionStateFilterFlags & HideNonBlocked) { 0273 return false; 0274 } 0275 } 0276 } 0277 0278 if (!globalFilterString.isEmpty()) { 0279 // Check global filter (search on all the roles) 0280 0281 // Check display name 0282 if (!q->match(index, Qt::DisplayRole, globalFilterString, 1, globalFilterMatchFlags).isEmpty()) { 0283 return true; 0284 } 0285 0286 // check groups 0287 // TODO Check if exact match on a single group works 0288 if (!q->match(index, KTp::ContactGroupsRole, globalFilterString, 1, globalFilterMatchFlags).isEmpty()) { 0289 return true; 0290 } 0291 0292 // Check id 0293 if (!q->match(index, KTp::IdRole, globalFilterString, 1, globalFilterMatchFlags).isEmpty()) { 0294 return true; 0295 } 0296 0297 return false; 0298 } else { 0299 // Check on single filters 0300 // Check display name 0301 if (!displayNameFilterString.isEmpty()) { 0302 if (q->match(index, Qt::DisplayRole, displayNameFilterString, 1, displayNameFilterMatchFlags).isEmpty()) { 0303 return false; 0304 } 0305 } 0306 // check groups 0307 // TODO Check if exact match on a single group works 0308 if (!groupsFilterString.isEmpty()) { 0309 if (q->match(index, KTp::ContactGroupsRole, groupsFilterString, 1, groupsFilterMatchFlags).isEmpty()) { 0310 return false; 0311 } 0312 } 0313 0314 // Check id 0315 if (!idFilterString.isEmpty()) { 0316 if (q->match(index, KTp::IdRole, idFilterString, 1, idFilterMatchFlags).isEmpty()) { 0317 return false; 0318 } 0319 } 0320 } 0321 0322 //check account 0323 if (accountFilter) { 0324 if(index.data(KTp::AccountRole).value<Tp::AccountPtr>()->uniqueIdentifier() != accountFilter->uniqueIdentifier()) { 0325 return false; 0326 } 0327 } 0328 0329 return true; 0330 } 0331 0332 bool ContactsFilterModel::Private::filterAcceptsGroup(const QModelIndex &/*index*/) 0333 { 0334 return true; 0335 } 0336 0337 void ContactsFilterModel::Private::sourceModelParentIndexChanged(const QModelIndex &sourceIndex) 0338 { 0339 //if parent is a group heading 0340 if (sourceIndex.isValid() && 0341 (sourceIndex.data(KTp::RowTypeRole).toInt() == KTp::GroupRowType || 0342 sourceIndex.data(KTp::RowTypeRole).toInt() == KTp::AccountRowType)) { 0343 0344 0345 q->dataChanged(q->mapFromSource(sourceIndex), q->mapFromSource(sourceIndex)); 0346 } 0347 } 0348 0349 void ContactsFilterModel::Private::sourceModelIndexChanged(const QModelIndex &sourceIndex) 0350 { 0351 sourceModelParentIndexChanged(sourceIndex.parent()); 0352 } 0353 0354 0355 ContactsFilterModel::ContactsFilterModel(QObject *parent) 0356 : QSortFilterProxyModel(parent), 0357 d(new Private(this)) 0358 { 0359 sort(0); //sort always 0360 setDynamicSortFilter(true); 0361 } 0362 0363 ContactsFilterModel::~ContactsFilterModel() 0364 { 0365 delete d; 0366 } 0367 0368 QVariant ContactsFilterModel::data(const QModelIndex &index, int role) const 0369 { 0370 if (!index.isValid()) { 0371 return QVariant(); 0372 } 0373 0374 QModelIndex sourceIndex = mapToSource(index); 0375 if (!sourceIndex.isValid()) { 0376 return QVariant(); 0377 } 0378 0379 if (role == KTp::HeaderOnlineUsersRole) { 0380 return rowCount(index); 0381 } else if (role == KTp::HeaderTotalUsersRole) { 0382 return sourceModel()->rowCount(sourceIndex); 0383 } 0384 0385 // In all other cases just delegate it to the source model 0386 return sourceModel()->data(sourceIndex, role); 0387 } 0388 0389 void ContactsFilterModel::setSourceModel(QAbstractItemModel *sourceModel) 0390 { 0391 // Disconnect the previous source model 0392 if (this->sourceModel()) { 0393 disconnect(this->sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), 0394 this, SLOT(sourceModelIndexChanged(QModelIndex))); 0395 disconnect(this->sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), 0396 this, SLOT(sourceModelParentIndexChanged(QModelIndex))); 0397 disconnect(this->sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), 0398 this, SLOT(sourceModelParentIndexChanged(QModelIndex))); 0399 disconnect(this->sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), 0400 this, SLOT(sourceModelParentIndexChanged(QModelIndex))); 0401 } 0402 0403 if (sourceModel) { 0404 QSortFilterProxyModel::setSourceModel(sourceModel); 0405 0406 // Connect the new source model 0407 connect(this->sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), 0408 this, SLOT(sourceModelIndexChanged(QModelIndex))); 0409 connect(this->sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), 0410 this, SLOT(sourceModelParentIndexChanged(QModelIndex))); 0411 connect(this->sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), 0412 this, SLOT(sourceModelParentIndexChanged(QModelIndex))); 0413 connect(this->sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), 0414 this, SLOT(sourceModelParentIndexChanged(QModelIndex))); 0415 } 0416 } 0417 0418 void ContactsFilterModel::invalidateFilter() 0419 { 0420 QSortFilterProxyModel::invalidateFilter(); 0421 } 0422 0423 ContactsFilterModel::PresenceTypeFilterFlags ContactsFilterModel::presenceTypeFilterFlags() const 0424 { 0425 return d->presenceTypeFilterFlags; 0426 } 0427 0428 void ContactsFilterModel::clearPresenceTypeFilterFlags() 0429 { 0430 setPresenceTypeFilterFlags(DoNotFilterByPresence); 0431 } 0432 0433 void ContactsFilterModel::setPresenceTypeFilterFlags(ContactsFilterModel::PresenceTypeFilterFlags presenceTypeFilterFlags) 0434 { 0435 if (d->presenceTypeFilterFlags != presenceTypeFilterFlags) { 0436 d->presenceTypeFilterFlags = presenceTypeFilterFlags; 0437 invalidateFilter(); 0438 Q_EMIT presenceTypeFilterFlagsChanged(presenceTypeFilterFlags); 0439 } 0440 } 0441 0442 ContactsFilterModel::CapabilityFilterFlags ContactsFilterModel::capabilityFilterFlags() const 0443 { 0444 return d->capabilityFilterFlags; 0445 } 0446 0447 void ContactsFilterModel::clearCapabilityFilterFlags() 0448 { 0449 setCapabilityFilterFlags(DoNotFilterByCapability); 0450 } 0451 0452 void ContactsFilterModel::setCapabilityFilterFlags(ContactsFilterModel::CapabilityFilterFlags capabilityFilterFlags) 0453 { 0454 if (d->capabilityFilterFlags != capabilityFilterFlags) { 0455 d->capabilityFilterFlags = capabilityFilterFlags; 0456 invalidateFilter(); 0457 Q_EMIT capabilityFilterFlagsChanged(capabilityFilterFlags); 0458 } 0459 } 0460 0461 ContactsFilterModel::SubscriptionStateFilterFlags ContactsFilterModel::subscriptionStateFilterFlags() const 0462 { 0463 return d->subscriptionStateFilterFlags; 0464 } 0465 0466 void ContactsFilterModel::clearSubscriptionStateFilterFlags() 0467 { 0468 setSubscriptionStateFilterFlags(DoNotFilterBySubscription); 0469 } 0470 0471 void ContactsFilterModel::setSubscriptionStateFilterFlags(ContactsFilterModel::SubscriptionStateFilterFlags subscriptionStateFilterFlags) 0472 { 0473 if (d->subscriptionStateFilterFlags != subscriptionStateFilterFlags) { 0474 d->subscriptionStateFilterFlags = subscriptionStateFilterFlags; 0475 invalidateFilter(); 0476 Q_EMIT subscriptionStateFilterFlagsChanged(subscriptionStateFilterFlags); 0477 } 0478 } 0479 0480 QString ContactsFilterModel::globalFilterString() const 0481 { 0482 return d->globalFilterString; 0483 } 0484 0485 void ContactsFilterModel::clearGlobalFilterString() 0486 { 0487 setGlobalFilterString(QString()); 0488 } 0489 0490 void ContactsFilterModel::setGlobalFilterString(const QString &globalFilterString) 0491 { 0492 if (d->globalFilterString != globalFilterString) { 0493 d->globalFilterString = globalFilterString; 0494 invalidateFilter(); 0495 Q_EMIT globalFilterStringChanged(globalFilterString); 0496 } 0497 } 0498 0499 Qt::MatchFlags ContactsFilterModel::globalFilterMatchFlags() const 0500 { 0501 return d->globalFilterMatchFlags; 0502 } 0503 0504 void ContactsFilterModel::resetGlobalFilterMatchFlags() 0505 { 0506 setGlobalFilterMatchFlags(Qt::MatchStartsWith | Qt::MatchWrap); 0507 } 0508 0509 void ContactsFilterModel::setGlobalFilterMatchFlags(Qt::MatchFlags globalFilterMatchFlags) 0510 { 0511 if (d->globalFilterMatchFlags != globalFilterMatchFlags) { 0512 d->globalFilterMatchFlags = globalFilterMatchFlags; 0513 invalidateFilter(); 0514 Q_EMIT globalFilterMatchFlagsChanged(globalFilterMatchFlags); 0515 } 0516 } 0517 0518 QString ContactsFilterModel::displayNameFilterString() const 0519 { 0520 return d->displayNameFilterString; 0521 } 0522 0523 void ContactsFilterModel::clearDisplayNameFilterString() 0524 { 0525 setDisplayNameFilterString(QString()); 0526 } 0527 0528 void ContactsFilterModel::setDisplayNameFilterString(const QString &displayNameFilterString) 0529 { 0530 if (d->displayNameFilterString != displayNameFilterString) { 0531 d->displayNameFilterString = displayNameFilterString; 0532 invalidateFilter(); 0533 Q_EMIT displayNameFilterStringChanged(displayNameFilterString); 0534 } 0535 } 0536 0537 Qt::MatchFlags ContactsFilterModel::displayNameFilterMatchFlags() const 0538 { 0539 return d->displayNameFilterMatchFlags; 0540 } 0541 0542 void ContactsFilterModel::resetDisplayNameFilterMatchFlags() 0543 { 0544 setDisplayNameFilterMatchFlags(Qt::MatchStartsWith | Qt::MatchWrap); 0545 } 0546 0547 void ContactsFilterModel::setDisplayNameFilterMatchFlags(Qt::MatchFlags displayNameFilterMatchFlags) 0548 { 0549 if (d->displayNameFilterMatchFlags != displayNameFilterMatchFlags) { 0550 d->displayNameFilterMatchFlags = displayNameFilterMatchFlags; 0551 invalidateFilter(); 0552 Q_EMIT displayNameFilterMatchFlagsChanged(displayNameFilterMatchFlags); 0553 } 0554 } 0555 0556 QString ContactsFilterModel::nicknameFilterString() const 0557 { 0558 return d->nicknameFilterString; 0559 } 0560 0561 void ContactsFilterModel::clearNicknameFilterString() 0562 { 0563 setNicknameFilterString(QString()); 0564 } 0565 0566 void ContactsFilterModel::setNicknameFilterString(const QString &nicknameFilterString) 0567 { 0568 if (d->nicknameFilterString != nicknameFilterString) { 0569 d->nicknameFilterString = nicknameFilterString; 0570 invalidateFilter(); 0571 Q_EMIT nicknameFilterStringChanged(nicknameFilterString); 0572 } 0573 } 0574 0575 Qt::MatchFlags ContactsFilterModel::nicknameFilterMatchFlags() const 0576 { 0577 return d->nicknameFilterMatchFlags; 0578 } 0579 0580 void ContactsFilterModel::resetNicknameFilterMatchFlags() 0581 { 0582 setNicknameFilterMatchFlags(Qt::MatchStartsWith | Qt::MatchWrap); 0583 } 0584 0585 void ContactsFilterModel::setNicknameFilterMatchFlags(Qt::MatchFlags nicknameFilterMatchFlags) 0586 { 0587 if (d->nicknameFilterMatchFlags != nicknameFilterMatchFlags) { 0588 d->nicknameFilterMatchFlags = nicknameFilterMatchFlags; 0589 invalidateFilter(); 0590 Q_EMIT nicknameFilterMatchFlagsChanged(nicknameFilterMatchFlags); 0591 } 0592 } 0593 0594 QString ContactsFilterModel::aliasFilterString() const 0595 { 0596 return d->aliasFilterString; 0597 } 0598 0599 void ContactsFilterModel::clearAliasFilterString() 0600 { 0601 setAliasFilterString(QString()); 0602 } 0603 0604 void ContactsFilterModel::setAliasFilterString(const QString &aliasFilterString) 0605 { 0606 if (d->aliasFilterString != aliasFilterString) { 0607 d->aliasFilterString = aliasFilterString; 0608 invalidateFilter(); 0609 Q_EMIT aliasFilterStringChanged(aliasFilterString); 0610 } 0611 } 0612 0613 Qt::MatchFlags ContactsFilterModel::aliasFilterMatchFlags() const 0614 { 0615 return d->aliasFilterMatchFlags; 0616 } 0617 0618 void ContactsFilterModel::resetAliasFilterMatchFlags() 0619 { 0620 setAliasFilterMatchFlags(Qt::MatchStartsWith | Qt::MatchWrap); 0621 } 0622 0623 void ContactsFilterModel::setAliasFilterMatchFlags(Qt::MatchFlags aliasFilterMatchFlags) 0624 { 0625 if (d->aliasFilterMatchFlags != aliasFilterMatchFlags) { 0626 d->aliasFilterMatchFlags = aliasFilterMatchFlags; 0627 invalidateFilter(); 0628 Q_EMIT aliasFilterMatchFlagsChanged(aliasFilterMatchFlags); 0629 } 0630 } 0631 0632 QString ContactsFilterModel::groupsFilterString() const 0633 { 0634 return d->groupsFilterString; 0635 } 0636 0637 void ContactsFilterModel::clearGroupsFilterString() 0638 { 0639 setGroupsFilterString(QString()); 0640 } 0641 0642 void ContactsFilterModel::setGroupsFilterString(const QString &groupsFilterString) 0643 { 0644 if (d->groupsFilterString != groupsFilterString) { 0645 d->groupsFilterString = groupsFilterString; 0646 invalidateFilter(); 0647 Q_EMIT groupsFilterStringChanged(groupsFilterString); 0648 } 0649 } 0650 0651 Qt::MatchFlags ContactsFilterModel::groupsFilterMatchFlags() const 0652 { 0653 return d->groupsFilterMatchFlags; 0654 } 0655 0656 void ContactsFilterModel::resetGroupsFilterMatchFlags() 0657 { 0658 setGroupsFilterMatchFlags(Qt::MatchStartsWith | Qt::MatchWrap); 0659 } 0660 0661 void ContactsFilterModel::setGroupsFilterMatchFlags(Qt::MatchFlags groupsFilterMatchFlags) 0662 { 0663 if (d->groupsFilterMatchFlags != groupsFilterMatchFlags) { 0664 d->groupsFilterMatchFlags = groupsFilterMatchFlags; 0665 invalidateFilter(); 0666 Q_EMIT groupsFilterMatchFlagsChanged(groupsFilterMatchFlags); 0667 } 0668 } 0669 0670 QString ContactsFilterModel::idFilterString() const 0671 { 0672 return d->idFilterString; 0673 } 0674 0675 void ContactsFilterModel::clearIdFilterString() 0676 { 0677 setIdFilterString(QString()); 0678 } 0679 0680 void ContactsFilterModel::setIdFilterString(const QString &idFilterString) 0681 { 0682 if (d->idFilterString != idFilterString) { 0683 d->idFilterString = idFilterString; 0684 invalidateFilter(); 0685 Q_EMIT idFilterStringChanged(idFilterString); 0686 } 0687 } 0688 0689 Qt::MatchFlags ContactsFilterModel::idFilterMatchFlags() const 0690 { 0691 return d->idFilterMatchFlags; 0692 } 0693 0694 0695 Tp::AccountPtr ContactsFilterModel::accountFilter() const 0696 { 0697 return d->accountFilter; 0698 } 0699 0700 void ContactsFilterModel::setAccountFilter(const Tp::AccountPtr &accountFilter) 0701 { 0702 if (d->accountFilter != accountFilter) { 0703 d->accountFilter = accountFilter; 0704 invalidateFilter(); 0705 Q_EMIT accountFilterChanged(accountFilter); 0706 } 0707 } 0708 0709 void ContactsFilterModel::clearAccountFilter() 0710 { 0711 setAccountFilter(Tp::AccountPtr()); 0712 } 0713 0714 void ContactsFilterModel::resetIdFilterMatchFlags() 0715 { 0716 setIdFilterMatchFlags(Qt::MatchStartsWith | Qt::MatchWrap); 0717 } 0718 0719 void ContactsFilterModel::setIdFilterMatchFlags(Qt::MatchFlags idFilterMatchFlags) 0720 { 0721 if (d->idFilterMatchFlags != idFilterMatchFlags) { 0722 d->idFilterMatchFlags = idFilterMatchFlags; 0723 invalidateFilter(); 0724 Q_EMIT idFilterMatchFlagsChanged(idFilterMatchFlags); 0725 } 0726 } 0727 0728 QStringList ContactsFilterModel::tubesFilterStrings() const 0729 { 0730 return d->tubesFilterStrings; 0731 } 0732 0733 void ContactsFilterModel::clearTubesFilterStrings() 0734 { 0735 setTubesFilterStrings(QStringList()); 0736 } 0737 0738 void ContactsFilterModel::setTubesFilterStrings(const QStringList &tubesFilterStrings) 0739 { 0740 if (d->tubesFilterStrings != tubesFilterStrings) { 0741 d->tubesFilterStrings = tubesFilterStrings; 0742 invalidateFilter(); 0743 Q_EMIT tubesFilterStringsChanged(tubesFilterStrings); 0744 } 0745 } 0746 0747 bool ContactsFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const 0748 { 0749 QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); 0750 0751 bool rc; 0752 int type = index.data(KTp::RowTypeRole).toInt(); 0753 if (type == KTp::ContactRowType || type == KTp::PersonRowType) { 0754 rc = d->filterAcceptsContact(index); 0755 } 0756 else if (type == KTp::AccountRowType) { 0757 rc = d->filterAcceptsAccount(index); 0758 } 0759 else if (type == KTp::GroupRowType) { 0760 rc = d->filterAcceptsGroup(index); 0761 } 0762 else { 0763 qCDebug(KTP_MODELS) << "Unknown type found in Account Filter"; 0764 rc = true; 0765 } 0766 0767 return rc; 0768 } 0769 0770 bool ContactsFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const 0771 { 0772 0773 QString leftDisplayedName = sourceModel()->data(left).toString(); 0774 QString rightDisplayedName = sourceModel()->data(right).toString(); 0775 0776 switch (sortRole()) { 0777 case KTp::ContactPresenceTypeRole: 0778 { 0779 Tp::ConnectionPresenceType leftPresence = (Tp::ConnectionPresenceType)left.data(KTp::ContactPresenceTypeRole).toUInt(); 0780 Tp::ConnectionPresenceType rightPresence = (Tp::ConnectionPresenceType)right.data(KTp::ContactPresenceTypeRole).toUInt(); 0781 0782 if (leftPresence == rightPresence) { 0783 //presences are the same, compare client types 0784 0785 bool leftPhone = left.data(KTp::ContactClientTypesRole).toStringList().contains(QLatin1String("phone")); 0786 bool rightPhone = right.data(KTp::ContactClientTypesRole).toStringList().contains(QLatin1String("phone")); 0787 0788 if (leftPhone && ! rightPhone) { 0789 return false; 0790 } 0791 else if (rightPhone && !leftPhone) { 0792 return true; 0793 } 0794 0795 return QString::localeAwareCompare(leftDisplayedName, rightDisplayedName) < 0; 0796 } else { 0797 if (leftPresence == Tp::ConnectionPresenceTypeAvailable) { 0798 return true; 0799 } 0800 if (leftPresence == Tp::ConnectionPresenceTypeUnset || 0801 leftPresence == Tp::ConnectionPresenceTypeOffline || 0802 leftPresence == Tp::ConnectionPresenceTypeUnknown || 0803 leftPresence == Tp::ConnectionPresenceTypeError) { 0804 return false; 0805 } 0806 0807 return KTp::Presence::sortPriority(leftPresence) < KTp::Presence::sortPriority(rightPresence); 0808 } 0809 } 0810 case Qt::DisplayRole: 0811 default: 0812 return QString::localeAwareCompare(leftDisplayedName, rightDisplayedName) < 0; 0813 } 0814 } 0815 0816 0817 QModelIndexList ContactsFilterModel::match(const QModelIndex &start, int role, 0818 const QVariant &value, int hits, 0819 Qt::MatchFlags flags) const 0820 { 0821 if (!start.isValid()) { 0822 return QModelIndexList(); 0823 } 0824 0825 QModelIndexList result; 0826 uint matchType = flags & 0x0F; 0827 Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; 0828 bool recurse = flags & Qt::MatchRecursive; 0829 bool allHits = (hits == -1); 0830 QString text; // only convert to a string if it is needed 0831 QVariant v = start.data(role); 0832 // QVariant based matching 0833 if (matchType == Qt::MatchExactly) { 0834 if (value == v) 0835 result.append(start); 0836 } else { // QString based matching 0837 if (text.isEmpty()) // lazy conversion 0838 text = value.toString(); 0839 QString t; 0840 0841 // If we're being case-insensitve then we should also be "foreign character insensitive" 0842 if (cs == Qt::CaseInsensitive) { 0843 const QString normalized = v.toString().normalized(QString::NormalizationForm_D); 0844 Q_FOREACH (const QChar &c, normalized) { 0845 if (c.category() != QChar::Mark_NonSpacing 0846 && c.category() != QChar::Mark_SpacingCombining 0847 && c.category() != QChar::Mark_Enclosing) { 0848 t.append(c); 0849 } 0850 } 0851 } else { 0852 t = v.toString(); 0853 } 0854 0855 switch (matchType) { 0856 case Qt::MatchRegExp: 0857 if (QRegExp(text, cs).exactMatch(t)) 0858 result.append(start); 0859 break; 0860 case Qt::MatchWildcard: 0861 if (QRegExp(text, cs, QRegExp::Wildcard).exactMatch(t)) 0862 result.append(start); 0863 break; 0864 case Qt::MatchStartsWith: 0865 if (t.startsWith(text, cs)) 0866 result.append(start); 0867 break; 0868 case Qt::MatchEndsWith: 0869 if (t.endsWith(text, cs)) 0870 result.append(start); 0871 break; 0872 case Qt::MatchFixedString: 0873 if (t.compare(text, cs) == 0) 0874 result.append(start); 0875 break; 0876 case Qt::MatchContains: 0877 default: 0878 if (t.contains(text, cs)) 0879 result.append(start); 0880 } 0881 } 0882 if (recurse && hasChildren(start)) { // search the hierarchy 0883 result += match(index(0, start.column(), start), role, 0884 (text.isEmpty() ? value : text), 0885 (allHits ? -1 : hits - result.count()), flags); 0886 } 0887 return result; 0888 } 0889 0890 void ContactsFilterModel::setSortRoleString(const QString &role) 0891 { 0892 setSortRole(roleNames().key(role.toUtf8())); 0893 } 0894 0895 QString ContactsFilterModel::sortRoleString() const 0896 { 0897 // Q_ASSERT(roleNames().contains(sortRole())); 0898 // return QString::fromUtf8(roleNames().value(sortRole())); 0899 return QString(); 0900 } 0901 0902 #include "moc_contacts-filter-model.cpp"