10#include "personsmodel.h"
12#include "backends/abstractcontact.h"
13#include "backends/basepersonsdatasource.h"
14#include "imageprovideruri_p.h"
15#include "metacontact_p.h"
16#include "personmanager_p.h"
17#include "personpluginmanager.h"
19#include "kpeople_debug.h"
22#include <QStandardPaths>
27class PersonsModelPrivate :
public QObject
31 PersonsModelPrivate(PersonsModel *qq)
35 PersonsModel *
const q;
38 QHash<QString , QString > contactToPersons;
41 QHash<QString , QPersistentModelIndex > personIndex;
44 QList<MetaContact> metacontacts;
46 QList<AllContactsMonitorPtr> m_sourceMonitors;
48 int initialFetchesDoneCount = 0;
50 bool isInitialized =
false;
51 bool hasError =
false;
54 void addPerson(
const MetaContact &mc);
55 void removePerson(
const QString &
id);
56 void personChanged(
const QString &personUri);
57 QString personUriForContact(
const QString &contactUri)
const;
58 QVariant dataForContact(
const QString &personUri,
const AbstractContact::Ptr &contact,
int role)
const;
61 void onContactsFetched();
63 void onContactAdded(
const QString &contactUri,
const AbstractContact::Ptr &contact);
64 void onContactChanged(
const QString &contactUri,
const AbstractContact::Ptr &contact);
65 void onContactRemoved(
const QString &contactUri);
68 void onAddContactToPerson(
const QString &contactUri,
const QString &newPersonUri);
69 void onRemoveContactsFromPerson(
const QString &contactUri);
72 void onMonitorInitialFetchComplete(
bool success =
true);
76using namespace KPeople;
78PersonsModel::PersonsModel(
QObject *parent)
80 , d_ptr(new PersonsModelPrivate(this))
83 const auto listPlugins = PersonPluginManager::dataSourcePlugins();
84 for (BasePersonsDataSource *dataSource : listPlugins) {
85 const AllContactsMonitorPtr monitor = dataSource->allContactsMonitor();
86 if (monitor->isInitialFetchComplete()) {
91 d->m_sourceMonitors << monitor;
93 d->onContactsFetched();
95 connect(PersonManager::instance(), &PersonManager::contactAddedToPerson, d, &PersonsModelPrivate::onAddContactToPerson);
96 connect(PersonManager::instance(), &PersonManager::contactRemovedFromPerson, d, &PersonsModelPrivate::onRemoveContactsFromPerson);
101PersonsModel::~PersonsModel()
105QHash<int, QByteArray> PersonsModel::roleNames()
const
108 roles.
insert(PersonUriRole,
"personUri");
109 roles.
insert(PersonVCardRole,
"personVCard");
110 roles.
insert(ContactsVCardRole,
"contactsVCard");
116QVariant PersonsModel::data(
const QModelIndex &index,
int role)
const
118 Q_D(
const PersonsModel);
125 if (index.row() < 0 || index.row() >= rowCount(index.parent())) {
129 if (index.parent().isValid()) {
130 if (role == ContactsVCardRole) {
133 const MetaContact &mc = d->metacontacts.at(index.parent().row());
135 return d->dataForContact(mc.id(), mc.contacts().at(index.row()), role);
137 const MetaContact &mc = d->metacontacts.at(index.row());
138 return d->dataForContact(mc.id(), mc.personAddressee(), role);
142QVariant PersonsModelPrivate::dataForContact(
const QString &personUri,
const AbstractContact::Ptr &person,
int role)
const
145 case PersonsModel::FormattedNameRole:
147 case PersonsModel::PhotoRole: {
150 QImage avatar = pic.
value<QImage>();
155 QPixmap avatar = pic.
value<QPixmap>();
168 return QPixmap(QStringLiteral(
":/org.kde.kpeople/pixmaps/dummy_avatar.png"));
170 case PersonsModel::PersonUriRole:
172 case PersonsModel::PersonVCardRole:
174 case PersonsModel::ContactsVCardRole:
176 case PersonsModel::GroupsRole:
177 return person->customProperty(QStringLiteral(
"all-groups"));
181 return ::photoImageProviderUri(personUri);
186int PersonsModel::columnCount(
const QModelIndex &parent)
const
193int PersonsModel::rowCount(
const QModelIndex &parent)
const
195 Q_D(
const PersonsModel);
197 if (!parent.isValid()) {
198 return d->metacontacts.size();
201 if (parent.isValid() && !parent.parent().isValid()) {
202 return d->metacontacts.at(parent.row()).contacts().count();
210 Q_D(
const PersonsModel);
212 return d->isInitialized;
217 if (row < 0 || column < 0 || row >= rowCount(
parent)) {
231 return QModelIndex();
234 return index(childIndex.
internalId(), 0, QModelIndex());
237void PersonsModelPrivate::onMonitorInitialFetchComplete(
bool success)
239 initialFetchesDoneCount++;
243 Q_ASSERT(initialFetchesDoneCount <= m_sourceMonitors.count());
244 if (initialFetchesDoneCount == m_sourceMonitors.count()) {
245 isInitialized =
true;
246 Q_EMIT q->modelInitialized(!hasError);
250void PersonsModelPrivate::onContactsFetched()
252 QMap<QString, AbstractContact::Ptr> addresseeMap;
255 for (
const AllContactsMonitorPtr &contactWatcher : std::as_const(m_sourceMonitors)) {
256 addresseeMap.
insert(contactWatcher->contacts());
260 const QMultiHash<QString, QString> contactMapping = PersonManager::instance()->allPersons();
262 for (
const QString &key : contactMapping.
uniqueKeys()) {
263 QMap<QString, AbstractContact::Ptr> contacts;
264 for (
const QString &contact : contactMapping.
values(key)) {
265 contactToPersons[contact] = key;
266 AbstractContact::Ptr ptr = addresseeMap.
take(contact);
268 contacts[contact] = ptr;
272 addPerson(MetaContact(key, contacts));
277 QMap<QString, AbstractContact::Ptr>::const_iterator i;
279 addPerson(MetaContact(i.key(), i.value()));
282 for (
const AllContactsMonitorPtr &monitor : std::as_const(m_sourceMonitors)) {
289void PersonsModelPrivate::onContactAdded(
const QString &contactUri,
const AbstractContact::Ptr &contact)
291 const QString &personUri = personUriForContact(contactUri);
293 QHash<QString, QPersistentModelIndex>::const_iterator pidx = personIndex.constFind(personUri);
294 if (pidx != personIndex.constEnd()) {
295 int personRow = pidx->row();
296 MetaContact &mc = metacontacts[personRow];
299 if (mc.contactUris().contains(contactUri)) {
300 qCWarning(KPEOPLE_LOG) <<
"Source emitted contactAdded for a contact we already know about " << contactUri;
301 onContactChanged(contactUri, contact);
303 int newContactPos = mc.contacts().size();
304 q->beginInsertRows(q->index(personRow), newContactPos, newContactPos);
305 mc.insertContact(contactUri, contact);
307 personChanged(personUri);
310 QMap<QString, AbstractContact::Ptr>
map;
311 map[contactUri] = contact;
312 addPerson(MetaContact(personUri, map));
316void PersonsModelPrivate::onContactChanged(
const QString &contactUri,
const AbstractContact::Ptr &contact)
318 const QString &personUri = personUriForContact(contactUri);
319 int personRow = personIndex[personUri].row();
320 int contactRow = metacontacts[personRow].updateContact(contactUri, contact);
322 const QModelIndex contactIndex = q->index(contactRow, 0, q->index(personRow));
324 Q_EMIT q->dataChanged(contactIndex, contactIndex);
326 personChanged(personUri);
329void PersonsModelPrivate::onContactRemoved(
const QString &contactUri)
331 const QString &personUri = personUriForContact(contactUri);
333 int personRow = personIndex[personUri].row();
335 MetaContact &mc = metacontacts[personRow];
336 int contactPosition = mc.contactUris().indexOf(contactUri);
337 q->beginRemoveRows(q->index(personRow, 0), contactPosition, contactPosition);
338 mc.removeContact(contactUri);
343 removePerson(personUri);
345 personChanged(personUri);
349void PersonsModelPrivate::onAddContactToPerson(
const QString &contactUri,
const QString &newPersonUri)
351 const QString oldPersonUri = personUriForContact(contactUri);
353 contactToPersons.insert(contactUri, newPersonUri);
355 int oldPersonRow = personIndex[oldPersonUri].row();
357 if (oldPersonRow < 0) {
361 MetaContact &oldMc = metacontacts[oldPersonRow];
364 int contactPosition = oldMc.contactUris().indexOf(contactUri);
365 const AbstractContact::Ptr contact = oldMc.contacts().at(contactPosition);
367 q->beginRemoveRows(q->index(oldPersonRow), contactPosition, contactPosition);
368 oldMc.removeContact(contactUri);
371 if (!oldMc.isValid()) {
372 removePerson(oldPersonUri);
374 personChanged(oldPersonUri);
378 QHash<QString, QPersistentModelIndex>::const_iterator pidx = personIndex.constFind(newPersonUri);
379 if (pidx != personIndex.constEnd()) {
380 int newPersonRow = pidx->row();
381 MetaContact &newMc = metacontacts[newPersonRow];
382 int newContactPos = newMc.contacts().size();
383 q->beginInsertRows(q->index(newPersonRow), newContactPos, newContactPos);
384 newMc.insertContact(contactUri, contact);
386 personChanged(newPersonUri);
388 QMap<QString, AbstractContact::Ptr> contacts;
389 contacts[contactUri] = contact;
390 addPerson(MetaContact(newPersonUri, contacts));
394void PersonsModelPrivate::onRemoveContactsFromPerson(
const QString &contactUri)
396 const QString personUri = personUriForContact(contactUri);
397 int personRow = personIndex[personUri].row();
398 MetaContact &mc = metacontacts[personRow];
400 const AbstractContact::Ptr &contact = mc.contact(contactUri);
401 const int index = mc.contactUris().indexOf(contactUri);
403 q->beginRemoveRows(personIndex[personUri], index, index);
404 mc.removeContact(contactUri);
406 contactToPersons.remove(contactUri);
410 removePerson(personUri);
412 personChanged(personUri);
417 addPerson(MetaContact(contactUri, contact));
420void PersonsModelPrivate::addPerson(
const KPeople::MetaContact &mc)
422 const QString &
id = mc.id();
424 int row = metacontacts.size();
425 q->beginInsertRows(QModelIndex(), row, row);
426 metacontacts.append(mc);
427 personIndex[id] = q->index(row);
431void PersonsModelPrivate::removePerson(
const QString &
id)
433 QPersistentModelIndex index = personIndex.value(
id);
438 q->beginRemoveRows(QModelIndex(), index.
row(), index.
row());
439 personIndex.remove(
id);
440 metacontacts.removeAt(index.
row());
444void PersonsModelPrivate::personChanged(
const QString &personUri)
446 int row = personIndex[personUri].row();
448 const QModelIndex personIndex = q->index(row);
449 Q_EMIT q->dataChanged(personIndex, personIndex);
453QString PersonsModelPrivate::personUriForContact(
const QString &contactUri)
const
455 QHash<QString, QString>::const_iterator it = contactToPersons.constFind(contactUri);
456 if (it != contactToPersons.constEnd()) {
465 Q_D(
const PersonsModel);
466 return d->personIndex.value(personUri);
471 return index(row, 0).
data(role);
476 Q_D(
const PersonsModel);
477 if (index.parent().isValid()) {
478 const MetaContact &mc = d->metacontacts.at(index.parent().row());
480 return mc.contacts().at(index.row())->customProperty(key);
482 const MetaContact &mc = d->metacontacts.at(index.row());
483 return mc.personAddressee()->customProperty(key);
487#include "moc_personsmodel.cpp"
488#include "personsmodel.moc"
This class creates a model of all known contacts from all sources Contacts are represented as a tree ...
Q_SCRIPTABLE QVariant get(int row, int role)
Helper class to ease model access through QML.
QModelIndex indexForPersonUri(const QString &personUri) const
bool isInitialized
specifies whether the model has already been initialized
@ PhotoImageProviderUri
Provide a URL to use with QtQuick's Image.source, similar to the Photo Role.
@ PhoneNumberRole
groups QStringList
QVariant contactCustomProperty(const QModelIndex &index, const QString &key) const
Makes it possible to access custom properties that are not available to the model.
QModelIndex createIndex(int row, int column, const void *ptr) const const
virtual QHash< int, QByteArray > roleNames() const const
iterator insert(const Key &key, const T &value)
bool isNull() const const
const_iterator constBegin() const const
const_iterator constEnd() const const
iterator insert(const Key &key, const T &value)
bool isEmpty() const const
quintptr internalId() const const
bool isValid() const const
QList< Key > uniqueKeys() const const
QList< T > values() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
bool isValid() const const
bool isNull() const const
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isLocalFile() const const
QString toLocalFile() const const
bool canConvert() const const
QVariant fromValue(T &&value)