Commit b6b1b366 authored by David Jarvie's avatar David Jarvie
Browse files

Fix deletion of alarms copied to KOrganizer not working

parent 7c0e8d05
......@@ -151,6 +151,7 @@ set(kalarm_bin_SRCS ${kalarm_bin_SRCS}
akonadimodel.cpp
akonadiresourcecreator.cpp
collectionmodel.cpp
collectionsearch.cpp
itemlistmodel.cpp
calendarmigrator.cpp
eventid.cpp
......
KAlarm Change Log
=== Version 2.10.7 --- 6 March 2014 ===
=== Version 2.10.7 --- 19 March 2014 ===
- [Akonadi] Fix deletion of alarm copies from KOrganiser not working.
- Fix crash after session restoration has nothing to restore [KDE Bug 331719]
- Prevent data in birthday import dialogue being editable.
......
/*
* collectionsearch.cpp - Search Akonadi Collections
* Program: kalarm
* Copyright © 2014 by David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef USE_AKONADI
#include "collectionsearch.h"
#include <akonadi/agentinstance.h>
#include <akonadi/agentmanager.h>
#include <akonadi/collectionfetchjob.h>
#include <akonadi/collectionfetchscope.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/itemdeletejob.h>
#include <QStringList>
#include <QTimer>
using namespace Akonadi;
/******************************************************************************
* Constructor.
* Creates jobs to fetch all collections for resources containing the mime type.
* Its subsequent actions depend on the parameters:
* - If 'remove' is true, it will locate all Items with the specified 'remoteId'
* and delete them. The deleted() signal will be emitted.
* - Otherwise, if 'remoteId' is specified, it will emit the signal items() to
* notify all Items with that remote ID.
* - Otherwise, it will emit the signal collections() to notify all Collections.
*/
CollectionSearch::CollectionSearch(const QString& mimeType, const QString& remoteId, bool remove)
: mMimeType(mimeType),
mRemoteId(remoteId),
mDeleteCount(0),
mDelete(remove && !mRemoteId.isEmpty())
{
const AgentInstance::List agents = AgentManager::self()->instances();
foreach (const AgentInstance& agent, agents)
{
if (agent.type().mimeTypes().contains(mimeType))
{
{
CollectionFetchJob* job = new CollectionFetchJob(Collection::root(), CollectionFetchJob::FirstLevel);
job->fetchScope().setResource(agent.identifier());
mCollectionJobs << job;
connect(job, SIGNAL(result(KJob*)), SLOT(collectionFetchResult(KJob*)));
}
}
}
if (mCollectionJobs.isEmpty())
{
// There are no resources containing the mime type, so ensure that a
// signal is emitted after construction.
QTimer::singleShot(0, this, SLOT(finish()));
}
}
/******************************************************************************
* Called when a CollectionFetchJob has completed.
*/
void CollectionSearch::collectionFetchResult(KJob* j)
{
CollectionFetchJob* job = static_cast<CollectionFetchJob*>(j);
if (j->error())
kError() << "CollectionFetchJob" << job->fetchScope().resource() << "error: " << j->errorString();
else
{
const Collection::List collections = job->collections();
foreach (const Collection& c, collections)
{
if (c.contentMimeTypes().contains(mMimeType))
{
if (mRemoteId.isEmpty())
mCollections << c;
else
{
// Search for all Items with the specified remote ID
Item item;
item.setRemoteId(mRemoteId);
ItemFetchJob* ijob = new ItemFetchJob(item, this);
ijob->setCollection(c);
mItemFetchJobs[ijob] = c.id();
connect(ijob, SIGNAL(result(KJob*)), SLOT(itemFetchResult(KJob*)));
}
}
}
}
mCollectionJobs.removeAll(job);
if (mCollectionJobs.isEmpty())
{
// All collections have now been fetched
if (mRemoteId.isEmpty())
finish();
}
}
/******************************************************************************
* Called when an ItemFetchJob has completed.
*/
void CollectionSearch::itemFetchResult(KJob* j)
{
ItemFetchJob* job = static_cast<ItemFetchJob*>(j);
if (j->error())
kDebug() << "ItemFetchJob: collection" << mItemFetchJobs[job] << "remote ID" << mRemoteId << "error: " << j->errorString();
else
{
if (mDelete)
{
Item::List items = job->items();
foreach (const Item& item, items)
{
ItemDeleteJob* djob = new ItemDeleteJob(item, this);
mItemDeleteJobs[djob] = mItemFetchJobs[job];
connect(djob, SIGNAL(result(KJob*)), SLOT(itemDeleteResult(KJob*)));
}
}
else
mItems << job->items();
}
mItemFetchJobs.remove(job);
if (mItemFetchJobs.isEmpty() && mItemDeleteJobs.isEmpty() && mCollectionJobs.isEmpty())
finish(); // all Items have now been fetched or deleted, so notify the result
}
/******************************************************************************
* Called when an ItemDeleteJob has completed.
*/
void CollectionSearch::itemDeleteResult(KJob* j)
{
ItemDeleteJob* job = static_cast<ItemDeleteJob*>(j);
if (j->error())
kDebug() << "ItemDeleteJob: resource" << mItemDeleteJobs[job] << "remote ID" << mRemoteId << "error: " << j->errorString();
else
++mDeleteCount;
mItemDeleteJobs.remove(job);
if (mItemFetchJobs.isEmpty() && mItemDeleteJobs.isEmpty() && mCollectionJobs.isEmpty())
finish(); // all Items have now been deleted, so notify the result
}
/******************************************************************************
* Notify the result of the search/delete operation, and delete this instance.
*/
void CollectionSearch::finish()
{
if (mDelete)
emit deleted(mDeleteCount);
else if (mRemoteId.isEmpty())
emit collections(mCollections);
else
emit items(mItems);
deleteLater();
}
#endif
// vim: et sw=4:
/*
* collectionsearch.h - Search Akonadi Collections
* Program: kalarm
* Copyright © 2014 by David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef COLLECTIONSEARCH_H
#define COLLECTIONSEARCH_H
#ifdef USE_AKONADI
#include <akonadi/collection.h>
#include <akonadi/item.h>
#include <QObject>
#include <QMap>
#include <QList>
#include <QStringList>
class KJob;
namespace Akonadi
{
class CollectionFetchJob;
class ItemFetchJob;
class ItemDeleteJob;
}
/*=============================================================================
= Class: CollectionSearch
= Fetches a list of all Akonadi collections which handle a specified mime type,
= and then optionally fetches or deletes all Items from them with a given
= remote ID.
=
= Note that this class auto-deletes once it has emitted its completion signal.
= Instances must therefore be created on the heap by operator new(), not on the
= stack.
=============================================================================*/
class CollectionSearch : public QObject
{
Q_OBJECT
public:
explicit CollectionSearch(const QString& mimeType, const QString& remoteId = QString(), bool remove = false);
signals:
// Signal emitted if action is to fetch all collections for the mime type
void collections(const Akonadi::Collection::List&);
// Signal emitted if action is to fetch all items with the remote ID
void items(const Akonadi::Item::List&);
// Signal emitted if action is to delete all items with the remote ID
void deleted(int count);
private slots:
void collectionFetchResult(KJob*);
void itemFetchResult(KJob*);
void itemDeleteResult(KJob*);
void finish();
private:
QString mMimeType;
QString mRemoteId;
QList<Akonadi::CollectionFetchJob*> mCollectionJobs;
QMap<Akonadi::ItemFetchJob*, Akonadi::Collection::Id> mItemFetchJobs;
QMap<Akonadi::ItemDeleteJob*, Akonadi::Collection::Id> mItemDeleteJobs;
Akonadi::Collection::List mCollections;
Akonadi::Item::List mItems;
int mDeleteCount;
bool mDelete;
};
#endif
#endif // COLLECTIONSEARCH_H
// vim: et sw=4:
/*
* functions.cpp - miscellaneous functions
* Program: kalarm
* Copyright © 2001-2013 by David Jarvie <djarvie@kde.org>
* Copyright © 2001-2014 by David Jarvie <djarvie@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -24,6 +24,7 @@
#ifdef USE_AKONADI
#include "collectionmodel.h"
#include "collectionsearch.h"
#else
#include "alarmresources.h"
#include "eventlistmodel.h"
......@@ -105,8 +106,6 @@ using namespace Akonadi;
namespace
{
bool refreshAlarmsQueued = false;
QString korganizerName = QLatin1String("korganizer");
QString korgStartError;
QDBusInterface* korgInterface = 0;
const QLatin1String KMAIL_DBUS_SERVICE("org.kde.kmail");
......@@ -118,7 +117,10 @@ const QLatin1String KORG_DBUS_IFACE("org.kde.korganizer.Korganizer");
#define KORG_DBUS_PATH "/Korganizer"
#define KORG_DBUS_LOAD_PATH "/korganizer_PimApplication"
//const QLatin1String KORG_DBUS_WINDOW_PATH("/korganizer/MainWindow_1");
const QString KORGANIZER_UID = QString::fromLatin1("-korg");
#ifdef USE_AKONADI
const QLatin1String KORG_MIME_TYPE("application/x-vnd.akonadi.calendar.event");
#endif
const QLatin1String KORGANIZER_UID("-korg");
const QLatin1String ALARM_OPTS_FILE("alarmopts");
const char* DONT_SHOW_ERRORS_GROUP = "DontShowErrors";
......@@ -2352,10 +2354,14 @@ KAlarm::UpdateStatus sendToKOrganizer(const KAEvent& event)
*/
KAlarm::UpdateStatus deleteFromKOrganizer(const QString& eventID)
{
const QString newID = uidKOrganizer(eventID);
#ifdef USE_AKONADI
new CollectionSearch(KORG_MIME_TYPE, newID, true); // this auto-deletes when complete
// Ignore errors
#else
KAlarm::UpdateStatus st = runKOrganizer(); // start KOrganizer if it isn't already running, and create its D-Bus interface
if (st != KAlarm::UPDATE_OK)
return st;
QString newID = uidKOrganizer(eventID);
QList<QVariant> args;
args << newID << true;
QDBusReply<bool> reply = korgInterface->callWithArgumentList(QDBus::Block, QLatin1String("deleteIncidence"), args);
......@@ -2375,6 +2381,7 @@ KAlarm::UpdateStatus deleteFromKOrganizer(const QString& eventID)
return KAlarm::UPDATE_KORG_FUNCERR;
}
kDebug() << newID << ": success";
#endif
return KAlarm::UPDATE_OK;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment