File indexing completed on 2024-11-24 04:50:41

0001 // SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
0002 // SPDX-License-Identifier: LGPL-2.0-or-later
0003 
0004 #include "contacteditorbackend.h"
0005 #include "addresseewrapper.h"
0006 #include "attributes/contactmetadataattribute_p.h"
0007 #include <Akonadi/CollectionDialog>
0008 #include <Akonadi/CollectionFetchJob>
0009 #include <Akonadi/ItemCreateJob>
0010 #include <Akonadi/ItemModifyJob>
0011 #include <Akonadi/Monitor>
0012 #include <Akonadi/Session>
0013 
0014 ContactEditorBackend::ContactEditorBackend(QObject *parent)
0015     : QObject(parent)
0016     , m_mode(ContactEditorBackend::CreateMode)
0017 {
0018 }
0019 
0020 ContactEditorBackend::~ContactEditorBackend() = default;
0021 
0022 void ContactEditorBackend::setDefaultAddressBook(const Akonadi::Collection &addressbook)
0023 {
0024     m_defaultAddressBook = addressbook;
0025 }
0026 
0027 void ContactEditorBackend::setCollectionId(const qint64 collectionId)
0028 {
0029     m_defaultAddressBook.setId(collectionId);
0030 }
0031 
0032 AddresseeWrapper *ContactEditorBackend::contact()
0033 {
0034     if (m_addressee) {
0035         return m_addressee;
0036     }
0037 
0038     m_addressee = new AddresseeWrapper(this);
0039     Q_EMIT contactChanged();
0040     return m_addressee;
0041 }
0042 
0043 ContactEditorBackend::Mode ContactEditorBackend::mode() const
0044 {
0045     return m_mode;
0046 }
0047 
0048 void ContactEditorBackend::setMode(ContactEditorBackend::Mode mode)
0049 {
0050     if (m_mode == mode) {
0051         return;
0052     }
0053     m_mode = mode;
0054     Q_EMIT modeChanged();
0055 }
0056 
0057 Akonadi::Item ContactEditorBackend::item() const
0058 {
0059     return m_item;
0060 }
0061 
0062 void ContactEditorBackend::setItem(const Akonadi::Item &item)
0063 {
0064     auto job = new Akonadi::ItemFetchJob(item);
0065     job->fetchScope().fetchFullPayload();
0066     job->fetchScope().fetchAttribute<ContactMetaDataAttribute>();
0067     job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
0068 
0069     connect(job, &Akonadi::ItemFetchJob::result, this, [this](KJob *job) {
0070         itemFetchDone(job);
0071     });
0072 
0073     setupMonitor();
0074     m_monitor->setItemMonitored(item);
0075 }
0076 
0077 void ContactEditorBackend::setupMonitor()
0078 {
0079     delete m_monitor;
0080     m_monitor = new Akonadi::Monitor;
0081     m_monitor->setObjectName(QLatin1StringView("ContactEditorMonitor"));
0082     m_monitor->ignoreSession(Akonadi::Session::defaultSession());
0083 
0084     connect(m_monitor, &Akonadi::Monitor::itemChanged, this, [this](const Akonadi::Item &item, const QSet<QByteArray> &) {
0085         m_item = item;
0086         Q_EMIT itemChangedExternally();
0087     });
0088 }
0089 
0090 void ContactEditorBackend::fetchItem()
0091 {
0092     auto job = new Akonadi::ItemFetchJob(m_item);
0093     job->fetchScope().fetchFullPayload();
0094     job->fetchScope().fetchAttribute<ContactMetaDataAttribute>();
0095     job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
0096 
0097     connect(job, &Akonadi::ItemFetchJob::result, this, [this](KJob *job) {
0098         itemFetchDone(job);
0099     });
0100 }
0101 
0102 void ContactEditorBackend::itemFetchDone(KJob *job)
0103 {
0104     if (job->error() != KJob::NoError) {
0105         Q_EMIT errorOccured(job->errorString());
0106         return;
0107     }
0108 
0109     auto fetchJob = qobject_cast<Akonadi::ItemFetchJob *>(job);
0110     if (!fetchJob) {
0111         return;
0112     }
0113 
0114     if (fetchJob->items().isEmpty()) {
0115         return;
0116     }
0117 
0118     m_item = fetchJob->items().at(0);
0119     Q_EMIT itemChanged();
0120 
0121     setReadOnly(false);
0122     if (m_mode == ContactEditorBackend::EditMode) {
0123         // if in edit mode we have to fetch the parent collection to find out
0124         // about the modify rights of the item
0125 
0126         auto collectionFetchJob = new Akonadi::CollectionFetchJob(m_item.parentCollection(), Akonadi::CollectionFetchJob::Base);
0127         this->connect(collectionFetchJob, &Akonadi::CollectionFetchJob::result, this, [this](KJob *job) {
0128             parentCollectionFetchDone(job);
0129         });
0130     } else {
0131         const auto addr = m_item.payload<KContacts::Addressee>();
0132         m_contactMetaData.load(m_item);
0133         contact()->setDisplayType((AddresseeWrapper::DisplayType)m_contactMetaData.displayNameMode());
0134         contact()->setAddressee(m_item.payload<KContacts::Addressee>());
0135     }
0136     Q_EMIT itemChanged();
0137     Q_EMIT contactChanged();
0138 }
0139 
0140 void ContactEditorBackend::parentCollectionFetchDone(KJob *job)
0141 {
0142     if (job->error()) {
0143         Q_EMIT errorOccured(job->errorString());
0144         return;
0145     }
0146 
0147     auto fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
0148     if (!fetchJob) {
0149         return;
0150     }
0151 
0152     const Akonadi::Collection parentCollection = fetchJob->collections().at(0);
0153     if (parentCollection.isValid()) {
0154         setReadOnly(!(parentCollection.rights() & Akonadi::Collection::CanChangeItem));
0155         m_defaultAddressBook = parentCollection;
0156         Q_EMIT collectionChanged();
0157     }
0158 
0159     m_contactMetaData.load(m_item);
0160     contact()->setDisplayType((AddresseeWrapper::DisplayType)m_contactMetaData.displayNameMode());
0161     contact()->setAddressee(m_item.payload<KContacts::Addressee>());
0162 }
0163 
0164 qint64 ContactEditorBackend::collectionId() const
0165 {
0166     return m_defaultAddressBook.id();
0167 }
0168 
0169 void ContactEditorBackend::saveContactInAddressBook()
0170 {
0171     if (m_mode == EditMode) {
0172         if (!m_item.isValid() || m_readOnly) {
0173             qDebug() << "item not valid anymore";
0174             return;
0175         }
0176 
0177         auto addressee = m_addressee->addressee();
0178 
0179         storeContact(addressee, m_contactMetaData);
0180 
0181         m_contactMetaData.store(m_item);
0182 
0183         m_item.setPayload<KContacts::Addressee>(addressee);
0184 
0185         auto job = new Akonadi::ItemModifyJob(m_item);
0186         connect(job, &Akonadi::ItemModifyJob::result, this, [this](KJob *job) {
0187             storeDone(job);
0188         });
0189     } else if (m_mode == CreateMode) {
0190         Q_ASSERT(m_defaultAddressBook.isValid());
0191 
0192         KContacts::Addressee addr(m_addressee->addressee());
0193         storeContact(addr, m_contactMetaData);
0194 
0195         Akonadi::Item item;
0196         item.setPayload<KContacts::Addressee>(addr);
0197         item.setMimeType(KContacts::Addressee::mimeType());
0198 
0199         m_contactMetaData.store(item);
0200 
0201         auto job = new Akonadi::ItemCreateJob(item, m_defaultAddressBook);
0202         connect(job, &Akonadi::ItemCreateJob::result, this, [this](KJob *job) {
0203             storeDone(job);
0204         });
0205     }
0206 }
0207 
0208 void ContactEditorBackend::storeDone(KJob *job)
0209 {
0210     if (job->error() != KJob::NoError) {
0211         Q_EMIT errorOccured(job->errorString());
0212         return;
0213     }
0214 
0215     if (m_mode == EditMode) {
0216         Q_EMIT contactStored(m_item);
0217     } else if (m_mode == CreateMode) {
0218         Q_EMIT contactStored(static_cast<Akonadi::ItemCreateJob *>(job)->item());
0219     }
0220     Q_EMIT finished();
0221 }
0222 
0223 void ContactEditorBackend::storeContact(KContacts::Addressee &contact, ContactMetaData &metaData) const
0224 {
0225     // TODO custom fields group description support
0226     // metaData.setCustomFieldDescriptions(d->mCustomFieldsWidget->localCustomFieldDescriptions());
0227     Q_UNUSED(contact)
0228 
0229     metaData.setDisplayNameMode(m_addressee->displayType());
0230 }
0231 
0232 bool ContactEditorBackend::isReadOnly() const
0233 {
0234     return m_readOnly;
0235 }
0236 void ContactEditorBackend::setReadOnly(bool isReadOnly)
0237 {
0238     if (m_readOnly == isReadOnly) {
0239         return;
0240     }
0241     m_readOnly = isReadOnly;
0242     Q_EMIT isReadOnlyChanged();
0243 }
0244 
0245 #include "moc_contacteditorbackend.cpp"