File indexing completed on 2024-04-28 15:29:27

0001 /*
0002     SPDX-FileCopyrightText: 2012 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003     SPDX-FileCopyrightText: 2013 David Edmundson <david@davidedmundson.co.uk>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-or-later
0006 */
0007 
0008 #include "kpeople_debug.h"
0009 #include "match_p.h"
0010 #include "matchessolver_p.h"
0011 #include "personmanager_p.h"
0012 #include "personsmodel.h"
0013 
0014 #include <QString>
0015 
0016 using namespace KPeople;
0017 
0018 MatchesSolver::MatchesSolver(const QList<Match> &matches, PersonsModel *model, QObject *parent)
0019     : KJob(parent)
0020     , m_matches(matches)
0021     , m_model(model)
0022 {
0023 }
0024 
0025 void MatchesSolver::start()
0026 {
0027     QMetaObject::invokeMethod(this, "startMatching", Qt::QueuedConnection);
0028 }
0029 
0030 void MatchesSolver::startMatching()
0031 {
0032     // Will contain all the sets to be merged
0033     QHash<QString, QSet<QString>> jobsData;
0034     // has a relation of each person, to know where it is
0035     QHash<QString, QString> destinationResolver;
0036     for (const Match &m : std::as_const(m_matches)) {
0037         QString urlA = m.indexA.data(PersonsModel::PersonUriRole).toString();
0038         QString urlB = m.indexB.data(PersonsModel::PersonUriRole).toString();
0039         Q_ASSERT(urlA != urlB);
0040 
0041         const bool inA = destinationResolver.contains(urlA);
0042         const bool inB = destinationResolver.contains(urlB);
0043         if (inA && inB) {
0044             // Both are in already, so we have to merge both sets
0045             destinationResolver[urlB] = urlA;
0046             jobsData[urlA] = jobsData.take(urlB);
0047 
0048             // we've put all items pointed to by urlA, to the B set
0049             // now we re-assign anything pointing to B as pointing to A
0050             // because they are the same
0051             const auto keys = destinationResolver.keys(urlB);
0052             auto it = keys.constBegin();
0053             const auto end = keys.constEnd();
0054             for (; it != end; ++it) {
0055                 destinationResolver[*it] = urlA;
0056             }
0057         } else {
0058             // if A is in but not B, we want B wherever A is
0059             if (inA) {
0060                 qSwap(urlB, urlA);
0061             }
0062             // in case B is anywhere, add A to that set, otherwise just insert B
0063             const QString mergeUrl = destinationResolver.value(urlB, urlB);
0064 
0065             QSet<QString> &jobs = jobsData[mergeUrl];
0066             jobs.insert(urlB);
0067             jobs.insert(urlA);
0068 
0069             // remember where urlA and urlB are
0070             Q_ASSERT(urlA != mergeUrl);
0071             destinationResolver.insert(urlA, mergeUrl);
0072             if (urlB != mergeUrl) {
0073                 destinationResolver.insert(urlB, mergeUrl);
0074             }
0075         }
0076     }
0077 
0078     for (const QSet<QString> &uris : std::as_const(jobsData)) {
0079         if (PersonManager::instance()->mergeContacts(uris.values()).isEmpty()) {
0080             qCWarning(KPEOPLE_LOG) << "error: failing to merge contacts: " << uris;
0081         }
0082     }
0083     emitResult();
0084 }
0085 
0086 #include "moc_matchessolver_p.cpp"