contacteditor.cpp 9.72 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
    This file is part of Akonadi Contact.

    Copyright (c) 2009 Tobias Koenig <tokoe@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "contacteditor.h"

24 25
#include "abstractcontacteditorwidget_p.h"
#include "autoqpointer_p.h"
26
#include "contactmetadataakonadi_p.h"
Laurent Montel's avatar
Laurent Montel committed
27
#include "attributes/contactmetadataattribute_p.h"
28
#include "editor/contacteditorwidget.h"
29

30 31 32 33 34 35 36 37
#include <collectiondialog.h>
#include <collectionfetchjob.h>
#include <itemcreatejob.h>
#include <itemfetchjob.h>
#include <itemfetchscope.h>
#include <itemmodifyjob.h>
#include <monitor.h>
#include <session.h>
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
38
#include <kcontacts/addressee.h>
Laurent Montel's avatar
Laurent Montel committed
39
#include <KLocalizedString>
40

Laurent Montel's avatar
Laurent Montel committed
41
#include <QPointer>
42 43
#include <QVBoxLayout>
#include <QMessageBox>
44 45 46

using namespace Akonadi;

47
class Q_DECL_HIDDEN ContactEditor::Private
48
{
Guy Maurel's avatar
Guy Maurel committed
49 50 51 52
public:
    Private(ContactEditor::Mode mode, ContactEditor::DisplayMode displayMode, AbstractContactEditorWidget *editorWidget, ContactEditor *parent)
        : mParent(parent)
        , mMode(mode)
Laurent Montel's avatar
Laurent Montel committed
53
        , mMonitor(nullptr)
Guy Maurel's avatar
Guy Maurel committed
54
        , mReadOnly(false)
55
    {
Guy Maurel's avatar
Guy Maurel committed
56 57 58
        if (editorWidget) {
            mEditorWidget = editorWidget;
        } else {
Laurent Montel's avatar
Laurent Montel committed
59
            mEditorWidget = new ContactEditorWidget(displayMode == FullMode ? ContactEditorWidget::FullMode : ContactEditorWidget::VCardMode, nullptr);
Guy Maurel's avatar
Guy Maurel committed
60
        }
61

Guy Maurel's avatar
Guy Maurel committed
62 63 64 65
        QVBoxLayout *layout = new QVBoxLayout(mParent);
        layout->setMargin(0);
        layout->setSpacing(0);
        layout->addWidget(mEditorWidget);
66 67 68 69
    }

    ~Private()
    {
Guy Maurel's avatar
Guy Maurel committed
70
        delete mMonitor;
71 72
    }

Guy Maurel's avatar
Guy Maurel committed
73 74 75 76
    void itemFetchDone(KJob *job);
    void parentCollectionFetchDone(KJob *job);
    void storeDone(KJob *job);
    void itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &);
77

78 79
    void loadContact(const KContacts::Addressee &addr, const ContactMetaDataAkonadi &metaData);
    void storeContact(KContacts::Addressee &addr, ContactMetaDataAkonadi &metaData);
80 81 82 83 84
    void setupMonitor();

    ContactEditor *mParent;
    ContactEditor::Mode mMode;
    Akonadi::Item mItem;
85
    Akonadi::ContactMetaDataAkonadi mContactMetaData;
86 87 88
    Akonadi::Monitor *mMonitor;
    Akonadi::Collection mDefaultCollection;
    AbstractContactEditorWidget *mEditorWidget;
89
    bool mReadOnly;
90 91
};

Guy Maurel's avatar
Guy Maurel committed
92
void ContactEditor::Private::itemFetchDone(KJob *job)
93
{
Guy Maurel's avatar
Guy Maurel committed
94 95 96 97 98 99 100 101 102 103 104 105 106
    if (job->error() != KJob::NoError) {
        return;
    }

    Akonadi::ItemFetchJob *fetchJob = qobject_cast<Akonadi::ItemFetchJob *>(job);
    if (!fetchJob) {
        return;
    }

    if (fetchJob->items().isEmpty()) {
        return;
    }

Sergio Martins's avatar
Sergio Martins committed
107
    mItem = fetchJob->items().at(0);
Guy Maurel's avatar
Guy Maurel committed
108 109 110 111 112 113 114 115 116 117 118

    mReadOnly = false;
    if (mMode == ContactEditor::EditMode) {
        // if in edit mode we have to fetch the parent collection to find out
        // about the modify rights of the item

        Akonadi::CollectionFetchJob *collectionFetchJob = new Akonadi::CollectionFetchJob(mItem.parentCollection(),
                Akonadi::CollectionFetchJob::Base);
        mParent->connect(collectionFetchJob, SIGNAL(result(KJob*)),
                         SLOT(parentCollectionFetchDone(KJob*)));
    } else {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
119
        const KContacts::Addressee addr = mItem.payload<KContacts::Addressee>();
Guy Maurel's avatar
Guy Maurel committed
120 121 122 123
        mContactMetaData.load(mItem);
        loadContact(addr, mContactMetaData);
        mEditorWidget->setReadOnly(mReadOnly);
    }
124
}
125

Guy Maurel's avatar
Guy Maurel committed
126
void ContactEditor::Private::parentCollectionFetchDone(KJob *job)
127
{
Guy Maurel's avatar
Guy Maurel committed
128 129 130
    if (job->error()) {
        return;
    }
131

Guy Maurel's avatar
Guy Maurel committed
132 133 134 135
    Akonadi::CollectionFetchJob *fetchJob = qobject_cast<Akonadi::CollectionFetchJob *>(job);
    if (!fetchJob) {
        return;
    }
136

Sergio Martins's avatar
Sergio Martins committed
137
    const Akonadi::Collection parentCollection = fetchJob->collections().at(0);
Guy Maurel's avatar
Guy Maurel committed
138 139 140
    if (parentCollection.isValid()) {
        mReadOnly = !(parentCollection.rights() & Collection::CanChangeItem);
    }
141

Guy Maurel's avatar
Guy Maurel committed
142
    mEditorWidget->setReadOnly(mReadOnly);
143

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
144
    const KContacts::Addressee addr = mItem.payload<KContacts::Addressee>();
Guy Maurel's avatar
Guy Maurel committed
145 146
    mContactMetaData.load(mItem);
    loadContact(addr, mContactMetaData);
147 148
}

Guy Maurel's avatar
Guy Maurel committed
149
void ContactEditor::Private::storeDone(KJob *job)
150
{
Guy Maurel's avatar
Guy Maurel committed
151
    if (job->error() != KJob::NoError) {
Laurent Montel's avatar
Laurent Montel committed
152 153
        Q_EMIT mParent->error(job->errorString());
        Q_EMIT mParent->finished();
Guy Maurel's avatar
Guy Maurel committed
154 155 156 157
        return;
    }

    if (mMode == EditMode) {
Laurent Montel's avatar
Laurent Montel committed
158
        Q_EMIT mParent->contactStored(mItem);
Guy Maurel's avatar
Guy Maurel committed
159
    } else if (mMode == CreateMode) {
Laurent Montel's avatar
Laurent Montel committed
160
        Q_EMIT mParent->contactStored(static_cast<Akonadi::ItemCreateJob *>(job)->item());
Guy Maurel's avatar
Guy Maurel committed
161
    }
Laurent Montel's avatar
Laurent Montel committed
162
    Q_EMIT mParent->finished();
163 164
}

Guy Maurel's avatar
Guy Maurel committed
165
void ContactEditor::Private::itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &)
166
{
167
    Q_UNUSED(item);
Guy Maurel's avatar
Guy Maurel committed
168
    QPointer<QMessageBox> dlg = new QMessageBox(mParent);   //krazy:exclude=qclasses
169

Guy Maurel's avatar
Guy Maurel committed
170 171 172
    dlg->setInformativeText(i18n("The contact has been changed by someone else.\nWhat should be done?"));
    dlg->addButton(i18n("Take over changes"), QMessageBox::AcceptRole);
    dlg->addButton(i18n("Ignore and Overwrite changes"), QMessageBox::RejectRole);
173

Guy Maurel's avatar
Guy Maurel committed
174 175 176 177 178
    if (dlg->exec() == QMessageBox::AcceptRole) {
        Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(mItem);
        job->fetchScope().fetchFullPayload();
        job->fetchScope().fetchAttribute<ContactMetaDataAttribute>();
        job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
179

Guy Maurel's avatar
Guy Maurel committed
180 181
        mParent->connect(job, SIGNAL(result(KJob*)), mParent, SLOT(itemFetchDone(KJob*)));
    }
Tobias Koenig's avatar
Tobias Koenig committed
182

Guy Maurel's avatar
Guy Maurel committed
183
    delete dlg;
184 185
}

186
void ContactEditor::Private::loadContact(const KContacts::Addressee &addr, const ContactMetaDataAkonadi &metaData)
187
{
Guy Maurel's avatar
Guy Maurel committed
188
    mEditorWidget->loadContact(addr, metaData);
189 190
}

191
void ContactEditor::Private::storeContact(KContacts::Addressee &addr, ContactMetaDataAkonadi &metaData)
192
{
Guy Maurel's avatar
Guy Maurel committed
193
    mEditorWidget->storeContact(addr, metaData);
194 195 196 197
}

void ContactEditor::Private::setupMonitor()
{
Guy Maurel's avatar
Guy Maurel committed
198 199 200
    delete mMonitor;
    mMonitor = new Akonadi::Monitor;
    mMonitor->ignoreSession(Akonadi::Session::defaultSession());
201

202
    connect(mMonitor, SIGNAL(itemChanged(Akonadi::Item,QSet<QByteArray>)), mParent, SLOT(itemChanged(Akonadi::Item,QSet<QByteArray>)));
203 204
}

Guy Maurel's avatar
Guy Maurel committed
205 206
ContactEditor::ContactEditor(Mode mode, QWidget *parent)
    : QWidget(parent)
Laurent Montel's avatar
Laurent Montel committed
207
    , d(new Private(mode, FullMode, nullptr, this))
208
{
209
}
210

Guy Maurel's avatar
Guy Maurel committed
211 212 213
ContactEditor::ContactEditor(Mode mode, AbstractContactEditorWidget *editorWidget, QWidget *parent)
    : QWidget(parent)
    , d(new Private(mode, FullMode, editorWidget, this))
214
{
215 216
}

Guy Maurel's avatar
Guy Maurel committed
217 218
ContactEditor::ContactEditor(Mode mode, DisplayMode displayMode, QWidget *parent)
    : QWidget(parent)
Laurent Montel's avatar
Laurent Montel committed
219
    , d(new Private(mode, displayMode, nullptr, this))
220 221 222
{
}

223 224
ContactEditor::~ContactEditor()
{
Guy Maurel's avatar
Guy Maurel committed
225
    delete d;
226 227
}

Guy Maurel's avatar
Guy Maurel committed
228
void ContactEditor::loadContact(const Akonadi::Item &item)
229
{
Guy Maurel's avatar
Guy Maurel committed
230 231 232
    if (d->mMode == CreateMode) {
        Q_ASSERT_X(false, "ContactEditor::loadContact", "You are calling loadContact in CreateMode!");
    }
233

Guy Maurel's avatar
Guy Maurel committed
234 235 236 237
    Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(item);
    job->fetchScope().fetchFullPayload();
    job->fetchScope().fetchAttribute<ContactMetaDataAttribute>();
    job->fetchScope().setAncestorRetrieval(Akonadi::ItemFetchScope::Parent);
238

Guy Maurel's avatar
Guy Maurel committed
239
    connect(job, SIGNAL(result(KJob*)), SLOT(itemFetchDone(KJob*)));
240

Guy Maurel's avatar
Guy Maurel committed
241 242
    d->setupMonitor();
    d->mMonitor->setItemMonitored(item);
243 244
}

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
245
KContacts::Addressee ContactEditor::contact()
246
{
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
247
    KContacts::Addressee addr;
Guy Maurel's avatar
Guy Maurel committed
248 249
    d->storeContact(addr, d->mContactMetaData);
    return addr;
250 251
}

252 253
void ContactEditor::saveContactInAddressBook()
{
Guy Maurel's avatar
Guy Maurel committed
254 255
    if (d->mMode == EditMode) {
        if (!d->mItem.isValid() || d->mReadOnly) {
Laurent Montel's avatar
Laurent Montel committed
256
            Q_EMIT finished();
Guy Maurel's avatar
Guy Maurel committed
257 258
            return;
        }
259

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
260
        KContacts::Addressee addr = d->mItem.payload<KContacts::Addressee>();
261

Guy Maurel's avatar
Guy Maurel committed
262
        d->storeContact(addr, d->mContactMetaData);
263

Guy Maurel's avatar
Guy Maurel committed
264
        d->mContactMetaData.store(d->mItem);
265

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
266
        d->mItem.setPayload<KContacts::Addressee>(addr);
267

Guy Maurel's avatar
Guy Maurel committed
268 269 270 271
        Akonadi::ItemModifyJob *job = new Akonadi::ItemModifyJob(d->mItem);
        connect(job, SIGNAL(result(KJob*)), SLOT(storeDone(KJob*)));
    } else if (d->mMode == CreateMode) {
        if (!d->mDefaultCollection.isValid()) {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
272
            const QStringList mimeTypeFilter(KContacts::Addressee::mimeType());
273

Guy Maurel's avatar
Guy Maurel committed
274 275 276
            AutoQPointer<CollectionDialog> dlg = new CollectionDialog(this);
            dlg->setMimeTypeFilter(mimeTypeFilter);
            dlg->setAccessRightsFilter(Collection::CanCreateItem);
Laurent Montel's avatar
Laurent Montel committed
277
            dlg->setWindowTitle(i18n("Select Address Book"));
Guy Maurel's avatar
Guy Maurel committed
278
            dlg->setDescription(i18n("Select the address book the new contact shall be saved in:"));
Laurent Montel's avatar
Laurent Montel committed
279
            if (dlg->exec() == QDialog::Accepted) {
Guy Maurel's avatar
Guy Maurel committed
280 281 282 283
                setDefaultAddressBook(dlg->selectedCollection());
            } else {
                return;
            }
284 285
        }

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
286
        KContacts::Addressee addr;
Guy Maurel's avatar
Guy Maurel committed
287
        d->storeContact(addr, d->mContactMetaData);
288

Guy Maurel's avatar
Guy Maurel committed
289
        Akonadi::Item item;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
290 291
        item.setPayload<KContacts::Addressee>(addr);
        item.setMimeType(KContacts::Addressee::mimeType());
292

Guy Maurel's avatar
Guy Maurel committed
293
        d->mContactMetaData.store(item);
294

Guy Maurel's avatar
Guy Maurel committed
295 296
        Akonadi::ItemCreateJob *job = new Akonadi::ItemCreateJob(item, d->mDefaultCollection);
        connect(job, SIGNAL(result(KJob*)), SLOT(storeDone(KJob*)));
297 298 299
    }
}

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
300
void ContactEditor::setContactTemplate(const KContacts::Addressee &contact)
301
{
Guy Maurel's avatar
Guy Maurel committed
302
    d->loadContact(contact, d->mContactMetaData);
303 304
}

Guy Maurel's avatar
Guy Maurel committed
305
void ContactEditor::setDefaultAddressBook(const Akonadi::Collection &collection)
306
{
Guy Maurel's avatar
Guy Maurel committed
307
    d->mDefaultCollection = collection;
308 309
}

310
#include "moc_contacteditor.cpp"