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

0001 // SPDX-FileCopyrightText: 2007-2009 Tobias Koenig <tokoe@kde.org>
0002 // SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
0003 // SPDX-License-Identifier: LGPL-2.0-or-later
0004 
0005 #include "contactgroupeditor.h"
0006 #include <qobjectdefs.h>
0007 
0008 #include "contactgroupmodel.h"
0009 
0010 #include <Akonadi/CollectionDialog>
0011 #include <Akonadi/CollectionFetchJob>
0012 #include <Akonadi/ItemCreateJob>
0013 #include <Akonadi/ItemFetchJob>
0014 #include <Akonadi/ItemFetchScope>
0015 #include <Akonadi/ItemModifyJob>
0016 #include <Akonadi/Monitor>
0017 #include <Akonadi/Session>
0018 #include <KColorScheme>
0019 #include <KContacts/ContactGroup>
0020 #include <KLocalizedString>
0021 
0022 using namespace Akonadi;
0023 
0024 class ContactGroupEditorPrivate
0025 {
0026 public:
0027     ContactGroupEditorPrivate(ContactGroupEditor *parent);
0028     ~ContactGroupEditorPrivate();
0029 
0030     void itemFetchDone(KJob *job);
0031     void parentCollectionFetchDone(KJob *job);
0032     void storeDone(KJob *job);
0033     void itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &notUsed);
0034     void memberChanged();
0035 
0036     void loadContactGroup(const KContacts::ContactGroup &group);
0037     [[nodiscard]] bool storeContactGroup(KContacts::ContactGroup &group);
0038     void setupMonitor();
0039 
0040     ContactGroupEditor::Mode mMode = ContactGroupEditor::Mode::CreateMode;
0041     Item mItem;
0042     Collection mCollection;
0043     Collection mDefaultCollection;
0044     ContactGroupEditor *mParent = nullptr;
0045     ContactGroupModel *mGroupModel = nullptr;
0046     Monitor *mMonitor = nullptr;
0047     QString mName;
0048     bool mReadOnly = false;
0049 };
0050 
0051 ContactGroupEditorPrivate::ContactGroupEditorPrivate(ContactGroupEditor *parent)
0052     : mParent(parent)
0053 {
0054 }
0055 
0056 ContactGroupEditorPrivate::~ContactGroupEditorPrivate()
0057 {
0058     delete mMonitor;
0059 }
0060 
0061 void ContactGroupEditorPrivate::itemFetchDone(KJob *job)
0062 {
0063     if (job->error()) {
0064         return;
0065     }
0066 
0067     auto fetchJob = qobject_cast<ItemFetchJob *>(job);
0068     if (!fetchJob) {
0069         return;
0070     }
0071 
0072     if (fetchJob->items().isEmpty()) {
0073         return;
0074     }
0075 
0076     mItem = fetchJob->items().at(0);
0077 
0078     mParent->setReadOnly(false);
0079     if (mMode == ContactGroupEditor::EditMode) {
0080         // if in edit mode we have to fetch the parent collection to find out
0081         // about the modify rights of the item
0082 
0083         auto collectionFetchJob = new Akonadi::CollectionFetchJob(mItem.parentCollection(), Akonadi::CollectionFetchJob::Base);
0084         mParent->connect(collectionFetchJob, &CollectionFetchJob::result, mParent, [this](KJob *job) {
0085             parentCollectionFetchDone(job);
0086         });
0087     } else {
0088         const auto group = mItem.payload<KContacts::ContactGroup>();
0089         loadContactGroup(group);
0090     }
0091 }
0092 
0093 void ContactGroupEditorPrivate::parentCollectionFetchDone(KJob *job)
0094 {
0095     if (job->error()) {
0096         return;
0097     }
0098 
0099     auto fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
0100     if (!fetchJob) {
0101         return;
0102     }
0103 
0104     const Akonadi::Collection parentCollection = fetchJob->collections().at(0);
0105     if (parentCollection.isValid()) {
0106         mReadOnly = !(parentCollection.rights() & Collection::CanChangeItem);
0107     }
0108     mCollection = parentCollection;
0109     Q_EMIT mParent->collectionChanged();
0110 
0111     const auto group = mItem.payload<KContacts::ContactGroup>();
0112     loadContactGroup(group);
0113 
0114     mParent->setReadOnly(mReadOnly);
0115 }
0116 
0117 void ContactGroupEditorPrivate::storeDone(KJob *job)
0118 {
0119     if (job->error()) {
0120         Q_EMIT mParent->errorOccured(job->errorString());
0121         return;
0122     }
0123 
0124     if (mMode == ContactGroupEditor::EditMode) {
0125         Q_EMIT mParent->contactGroupStored(mItem);
0126     } else if (mMode == ContactGroupEditor::CreateMode) {
0127         Q_EMIT mParent->contactGroupStored(static_cast<ItemCreateJob *>(job)->item());
0128     }
0129     Q_EMIT mParent->finished();
0130 }
0131 
0132 void ContactGroupEditor::fetchItem()
0133 {
0134     auto job = new ItemFetchJob(d->mItem);
0135     job->fetchScope().fetchFullPayload();
0136     job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
0137 
0138     connect(job, &ItemFetchJob::result, this, [this](KJob *job) {
0139         d->itemFetchDone(job);
0140     });
0141 }
0142 
0143 void ContactGroupEditorPrivate::loadContactGroup(const KContacts::ContactGroup &group)
0144 {
0145     mName = group.name();
0146     Q_EMIT mParent->nameChanged();
0147 
0148     mGroupModel->loadContactGroup(group);
0149 }
0150 
0151 bool ContactGroupEditorPrivate::storeContactGroup(KContacts::ContactGroup &group)
0152 {
0153     group.setName(mName);
0154 
0155     if (!mGroupModel->storeContactGroup(group)) {
0156         Q_EMIT mParent->errorOccured(mGroupModel->lastErrorMessage());
0157         return false;
0158     }
0159 
0160     return true;
0161 }
0162 
0163 void ContactGroupEditorPrivate::setupMonitor()
0164 {
0165     delete mMonitor;
0166     mMonitor = new Monitor;
0167     mMonitor->setObjectName(QLatin1StringView("ContactGroupEditorMonitor"));
0168     mMonitor->ignoreSession(Session::defaultSession());
0169 
0170     QObject::connect(mMonitor, &Monitor::itemChanged, mParent, [this](const Akonadi::Item &, const QSet<QByteArray> &) {
0171         Q_EMIT mParent->itemChanged();
0172     });
0173 }
0174 
0175 ContactGroupEditor::ContactGroupEditor(QObject *parent)
0176     : QObject(parent)
0177     , d(new ContactGroupEditorPrivate(this))
0178 {
0179     d->mMode = ContactGroupEditor::CreateMode;
0180     d->mGroupModel = new ContactGroupModel(true, this);
0181     KContacts::ContactGroup dummyGroup;
0182     d->mGroupModel->loadContactGroup(dummyGroup);
0183 }
0184 
0185 ContactGroupEditor::~ContactGroupEditor() = default;
0186 
0187 void ContactGroupEditor::loadContactGroup(const Akonadi::Item &item)
0188 {
0189     if (d->mMode == CreateMode) {
0190         Q_ASSERT_X(false, "ContactGroupEditor::loadContactGroup", "You are calling loadContactGroup in CreateMode!");
0191     }
0192 
0193     auto job = new ItemFetchJob(item);
0194     job->fetchScope().fetchFullPayload();
0195     job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
0196 
0197     connect(job, &ItemModifyJob::result, this, [this](KJob *job) {
0198         d->itemFetchDone(job);
0199     });
0200 
0201     d->setupMonitor();
0202     d->mMonitor->setItemMonitored(item);
0203 }
0204 
0205 bool ContactGroupEditor::saveContactGroup()
0206 {
0207     if (d->mMode == EditMode) {
0208         if (!d->mItem.isValid()) {
0209             return false;
0210         }
0211 
0212         if (d->mReadOnly) {
0213             return true;
0214         }
0215 
0216         auto group = d->mItem.payload<KContacts::ContactGroup>();
0217 
0218         if (!d->storeContactGroup(group)) {
0219             return false;
0220         }
0221 
0222         d->mItem.setPayload<KContacts::ContactGroup>(group);
0223 
0224         auto job = new ItemModifyJob(d->mItem);
0225         connect(job, &ItemModifyJob::result, this, [this](KJob *job) {
0226             d->storeDone(job);
0227         });
0228     } else if (d->mMode == CreateMode) {
0229         if (!d->mDefaultCollection.isValid()) {
0230             const QStringList mimeTypeFilter(KContacts::ContactGroup::mimeType());
0231             Q_EMIT errorOccured(i18n("No address book selected"));
0232             return false;
0233 
0234             // TODO check if this can happen
0235             // QPointer<CollectionDialog> dlg = new CollectionDialog(this);
0236             // dlg->setMimeTypeFilter(mimeTypeFilter);
0237             // dlg->setAccessRightsFilter(Collection::CanCreateItem);
0238             // dlg->setWindowTitle(i18nc("@title:window", "Select Address Book"));
0239             // dlg->setDescription(i18n("Select the address book the new contact group shall be saved in:"));
0240 
0241             // if (dlg->exec() == QDialog::Accepted) {
0242             //     setDefaultAddressBook(dlg->selectedCollection());
0243             //     delete dlg;
0244             // } else {
0245             //     delete dlg;
0246             //     return false;
0247             // }
0248         }
0249 
0250         KContacts::ContactGroup group;
0251         if (!d->storeContactGroup(group)) {
0252             return false;
0253         }
0254 
0255         Item item;
0256         item.setPayload<KContacts::ContactGroup>(group);
0257         item.setMimeType(KContacts::ContactGroup::mimeType());
0258 
0259         auto job = new ItemCreateJob(item, d->mDefaultCollection);
0260         connect(job, &ItemCreateJob::result, this, [this](KJob *job) {
0261             d->storeDone(job);
0262         });
0263     }
0264 
0265     return true;
0266 }
0267 
0268 void ContactGroupEditor::setDefaultAddressBook(const Akonadi::Collection &collection)
0269 {
0270     d->mDefaultCollection = collection;
0271 }
0272 
0273 QString ContactGroupEditor::name() const
0274 {
0275     return d->mName;
0276 }
0277 
0278 void ContactGroupEditor::setName(const QString &name)
0279 {
0280     if (d->mName == name) {
0281         return;
0282     }
0283 
0284     d->mName = name;
0285     Q_EMIT nameChanged();
0286 }
0287 
0288 qint64 ContactGroupEditor::collectionId() const
0289 {
0290     return d->mCollection.isValid() ? d->mCollection.id() : d->mDefaultCollection.id();
0291 }
0292 
0293 ContactGroupEditor::Mode ContactGroupEditor::mode() const
0294 {
0295     return d->mMode;
0296 }
0297 
0298 void ContactGroupEditor::setMode(Mode mode)
0299 {
0300     if (d->mMode == mode) {
0301         return;
0302     }
0303     d->mMode = mode;
0304     Q_EMIT modeChanged();
0305 }
0306 
0307 bool ContactGroupEditor::isReadOnly() const
0308 {
0309     return d->mReadOnly;
0310 }
0311 
0312 void ContactGroupEditor::setReadOnly(bool isReadOnly)
0313 {
0314     if (d->mReadOnly == isReadOnly) {
0315         return;
0316     }
0317     d->mReadOnly = isReadOnly;
0318     Q_EMIT isReadOnlyChanged();
0319 }
0320 
0321 QAbstractItemModel *ContactGroupEditor::groupModel() const
0322 {
0323     return d->mGroupModel;
0324 }
0325 
0326 #include "moc_contactgroupeditor.cpp"