Commit d0a65cd1 authored by David Jarvie's avatar David Jarvie

Allow a resource ID to be specified with event ID in commands

To enable a unique specifier of an alarm, allow the Akonadi
resource ID to be prefixed to the event ID in command line and
D-Bus comand arguments.
parent 10697d77
......@@ -139,6 +139,7 @@ set(kalarm_bin_SRCS ${kalarm_bin_SRCS}
collectionmodel.cpp
itemlistmodel.cpp
calendarmigrator.cpp
eventid.cpp
)
else(KALARM_USE_AKONADI)
set(kalarm_bin_SRCS ${kalarm_bin_SRCS}
......
......@@ -1798,15 +1798,34 @@ Event* AlarmCalendar::createKCalEvent(const KAEvent* ev, const QString& baseID)
/******************************************************************************
* Return the event with the specified ID.
* If 'checkDuplicates' is true, and the collection ID is invalid, if there is
* a unique event with the given ID, it will be returned.
*/
#ifdef USE_AKONADI
KAEvent* AlarmCalendar::event(const EventId& uniqueID)
KAEvent* AlarmCalendar::event(const EventId& uniqueID, bool checkDuplicates)
#else
KAEvent* AlarmCalendar::event(const QString& uniqueID)
#endif
{
if (!isValid())
return 0;
#ifdef USE_AKONADI
const QString eventId = uniqueID.eventId();
if (uniqueID.collectionId() == -1 && checkDuplicates)
{
// The collection isn't known, but use the event ID if it is
// unique among all collections.
KAEvent::List list = events(eventId);
if (list.count() > 1)
{
kWarning() << "Multiple events found with ID" << eventId;
return 0;
}
if (list.isEmpty())
return 0;
return list[0];
}
#endif
KAEventMap::ConstIterator it = mEventMap.constFind(uniqueID);
if (it == mEventMap.constEnd())
return 0;
......
......@@ -80,7 +80,7 @@ class AlarmCalendar : public QObject
KAEvent::List atLoginAlarms() const;
#ifdef USE_AKONADI
KCalCore::Event::Ptr kcalEvent(const QString& uniqueID); // if Akonadi, display calendar only
KAEvent* event(const EventId& uniqueId);
KAEvent* event(const EventId& uniqueId, bool checkDuplicates = false);
#else
KCal::Event* createKCalEvent(const KAEvent* e) const
{ return createKCalEvent(e, QString()); }
......
......@@ -1230,6 +1230,20 @@ Collection::List CollectionControlModel::enabledCollections(CalEvent::Type type,
return result;
}
/******************************************************************************
* Return the collection ID for a given resource ID.
*/
Collection CollectionControlModel::collectionForResource(const QString& resourceId)
{
Collection::List cols = instance()->collections();
for (int i = 0, count = cols.count(); i < count; ++i)
{
if (cols[i].resource() == resourceId)
return cols[i];
}
return Collection();
}
/******************************************************************************
* Return the data for a given role, for a specified item.
*/
......
......@@ -258,6 +258,11 @@ class CollectionControlModel : public Akonadi::FavoriteCollectionsModel
*/
static Akonadi::Collection::List enabledCollections(CalEvent::Type, bool writable);
/** Return the collection ID for a given resource ID.
* \return collection ID, or -1 if the resource is not in KAlarm's list.
*/
static Akonadi::Collection collectionForResource(const QString& resourceId);
virtual QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const;
/** Return a bulleted list of alarm types for inclusion in an i18n message. */
......
......@@ -70,17 +70,17 @@ CommandOptions::CommandOptions()
if (mArgs->count())
setErrorParameter("--list");
}
if (checkCommand("triggerEvent", TRIGGER_EVENT))
{
mEventId = mArgs->getOption(mCommandName);
}
if (checkCommand("cancelEvent", CANCEL_EVENT))
{
mEventId = mArgs->getOption(mCommandName);
}
if (checkCommand("edit", EDIT))
if (checkCommand("triggerEvent", TRIGGER_EVENT)
|| checkCommand("cancelEvent", CANCEL_EVENT)
|| checkCommand("edit", EDIT))
{
#ifdef USE_AKONADI
// Fetch the event ID. This can optionally include a prefix of the
// resource ID followed by a colon delimiter.
mEventId = EventId(mArgs->getOption(mCommandName));
#else
mEventId = mArgs->getOption(mCommandName);
#endif
}
if (checkCommand("edit-new-preset", EDIT_NEW_PRESET))
{
......
......@@ -22,6 +22,9 @@
#define COMMANDOPTIONS_H
#include "editdlg.h"
#ifdef USE_AKONADI
#include "eventid.h"
#endif
#include <kalarmcal/kaevent.h>
#include <kalarmcal/karecurrence.h>
......@@ -52,7 +55,12 @@ class CommandOptions
};
CommandOptions();
Command command() const { return mCommand; }
QString commandName() const { return QString::fromLatin1(mCommandName); }
#ifdef USE_AKONADI
EventId eventId() const { return mEventId; }
#else
QString eventId() const { return mEventId; }
#endif
QString templateName() const { return mTemplateName; }
EditAlarmDlg::Type editType() const { return mEditType; }
KAEvent::SubAction editAction() const { return mEditAction; }
......@@ -96,7 +104,11 @@ class CommandOptions
QString mError; // error message
Command mCommand; // the selected command
QByteArray mCommandName; // option string for the selected command
#ifdef USE_AKONADI
EventId mEventId; // TRIGGER_EVENT, CANCEL_EVENT, EDIT: event ID
#else
QString mEventId; // TRIGGER_EVENT, CANCEL_EVENT, EDIT: event ID
#endif
QString mTemplateName; // EDIT_NEW_PRESET: template name
EditAlarmDlg::Type mEditType; // NEW, EDIT_NEW_*: alarm edit type
KAEvent::SubAction mEditAction; // NEW: alarm edit sub-type
......
......@@ -64,12 +64,20 @@ DBusHandler::DBusHandler()
bool DBusHandler::cancelEvent(const QString& eventId)
{
#ifdef USE_AKONADI
return theApp()->dbusDeleteEvent(EventId(eventId));
#else
return theApp()->dbusDeleteEvent(eventId);
#endif
}
bool DBusHandler::triggerEvent(const QString& eventId)
{
#ifdef USE_AKONADI
return theApp()->dbusTriggerEvent(EventId(eventId));
#else
return theApp()->dbusTriggerEvent(eventId);
#endif
}
QString DBusHandler::list()
......@@ -248,7 +256,11 @@ bool DBusHandler::scheduleAudio(const QString& audioUrl, int volumePercent, cons
bool DBusHandler::edit(const QString& eventID)
{
#ifdef USE_AKONADI
return KAlarm::editAlarmById(EventId(eventID));
#else
return KAlarm::editAlarmById(eventID);
#endif
}
bool DBusHandler::editNew(int type)
......
/*
* eventid.cpp - KAlarm unique event identifier for Akonadi
* Program: kalarm
* Copyright © 2012 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 "eventid.h"
#include "collectionmodel.h"
#include <kdebug.h>
#include <QString>
#include <QRegExp>
/** Set by event ID and optional resource ID, in the format "[rid:]eid". */
EventId::EventId(const QString& resourceEventId)
{
bool resourceOk = false;
QRegExp rx("^\\w+:");
if (rx.indexIn(resourceEventId) == 0)
{
// A resource ID has been supplied, so use it
int n = rx.matchedLength();
Akonadi::Collection c = CollectionControlModel::collectionForResource(resourceEventId.left(n - 1));
{
first = c.id();
second = resourceEventId.mid(n);
resourceOk = true;
}
}
if (!resourceOk)
{
// Only an event ID has been supplied (or the syntax was invalid)
first = -1;
second = resourceEventId;
}
}
#endif
// vim: et sw=4:
......@@ -42,6 +42,8 @@ struct EventId : public QPair<Akonadi::Collection::Id, QString>
: QPair<Akonadi::Collection::Id, QString>(c, e) {}
explicit EventId(const KAEvent& event)
: QPair<Akonadi::Collection::Id, QString>(event.collectionId(), event.id()) {}
/** Set by event ID and optional resource ID, in the format "[rid:]eid". */
explicit EventId(const QString& resourceEventId);
void clear() { first = -1; second.clear(); }
/** Return whether the instance contains any data. */
bool isEmpty() const { return second.isEmpty(); }
......
......@@ -1556,28 +1556,31 @@ void editAlarm(KAEvent* event, QWidget* parent)
* An error occurs if the alarm is not found, if there is more than one alarm
* with the same ID, or if it is read-only or expired.
*/
#ifdef USE_AKONADI
bool editAlarmById(const EventId& id, QWidget* parent)
#else
bool editAlarmById(const QString& eventID, QWidget* parent)
#endif
{
#ifdef USE_AKONADI
KAEvent::List events = AlarmCalendar::resources()->events(eventID);
if (events.count() > 1)
const QString eventID(id.eventId());
KAEvent* event = AlarmCalendar::resources()->event(id, true);
if (!event)
{
kWarning() << eventID << ": multiple events found";
if (id.collectionId() != -1)
kWarning() << "Event ID not found, or duplicated:" << eventID;
else
kWarning() << "Event ID not found:" << eventID;
return false;
}
if (events.isEmpty())
if (AlarmCalendar::resources()->eventReadOnly(event->itemId()))
#else
KAEvent* event = AlarmCalendar::resources()->event(eventID);
if (!event)
#endif
{
kError() << eventID << ": event ID not found";
return false;
}
#ifdef USE_AKONADI
KAEvent* event = events[0];
if (AlarmCalendar::resources()->eventReadOnly(event->itemId()))
#else
if (AlarmCalendar::resources()->eventReadOnly(eventID))
#endif
{
......
......@@ -111,11 +111,12 @@ bool editNewAlarm(const QString& templateName, QWidget* parent =
void editNewAlarm(EditAlarmDlg::Type, QWidget* parent = 0);
void editNewAlarm(KAEvent::SubAction, QWidget* parent = 0, const AlarmText* = 0);
void editNewAlarm(const KAEvent* preset, QWidget* parent = 0);
bool editAlarmById(const QString& eventID, QWidget* parent = 0);
void editAlarm(KAEvent*, QWidget* parent = 0);
#ifdef USE_AKONADI
bool editAlarmById(const EventId& eventID, QWidget* parent = 0);
void updateEditedAlarm(EditAlarmDlg*, KAEvent&, Akonadi::Collection&);
#else
bool editAlarmById(const QString& eventID, QWidget* parent = 0);
void updateEditedAlarm(EditAlarmDlg*, KAEvent&, AlarmResource*);
#endif
void viewAlarm(const KAEvent*, QWidget* parent = 0);
......
......@@ -335,8 +335,19 @@ int KAlarmApp::newInstance()
{
startProcessQueue(); // start processing the execution queue
dontRedisplay = true;
#ifdef USE_AKONADI
if (!handleEvent(options.eventId(), function, true))
#else
if (!handleEvent(options.eventId(), function))
#endif
{
#ifdef USE_AKONADI
CommandOptions::printError(i18nc("@info:shell", "<icode>%1</icode>: Event <resource>%2</resource> not found, or not unique", "--" + options.commandName(), options.eventId().eventId()));
#else
CommandOptions::printError(i18nc("@info:shell", "<icode>%1</icode>: Event <resource>%2</resource> not found", "--" + options.commandName(), options.eventId()));
#endif
exitCode = 1;
}
}
break;
}
......@@ -360,7 +371,11 @@ int KAlarmApp::newInstance()
exitCode = 1;
else if (!KAlarm::editAlarmById(options.eventId()))
{
CommandOptions::printError(i18nc("@info:shell", "<icode>%1</icode>: Event <resource>%2</resource> not found, or not editable", QString::fromLatin1("--edit"), options.eventId()));
#ifdef USE_AKONADI
CommandOptions::printError(i18nc("@info:shell", "<icode>%1</icode>: Event <resource>%2</resource> not found, or not editable", "--" + options.commandName(), options.eventId().eventId()));
#else
CommandOptions::printError(i18nc("@info:shell", "<icode>%1</icode>: Event <resource>%2</resource> not found, or not editable", "--" + options.commandName(), options.eventId()));
#endif
exitCode = 1;
}
break;
......@@ -535,7 +550,7 @@ void KAlarmApp::checkKtimezoned()
done = true;
#if KDE_IS_VERSION(4,5,70)
if (!KSystemTimeZones::isTimeZoneDaemonAvailable())
{
{
kDebug() << "ktimezoned not running: using UTC only";
KAMessageBox::information(MainWindow::mainMainWindow(),
i18nc("@info", "Time zones are not accessible:<nl/>KAlarm will use the UTC time zone.<nl/><nl/>(The KDE time zone service is not available:<nl/>check that <application>ktimezoned</application> is installed.)"),
......@@ -726,7 +741,7 @@ void KAlarmApp::checkNextDueAlarm()
if (interval <= 0)
{
// Queue the alarm
queueAlarmId(nextEvent->id());
queueAlarmId(*nextEvent);
kDebug() << nextEvent->id() << ": due now";
QTimer::singleShot(0, this, SLOT(processQueue()));
}
......@@ -759,8 +774,13 @@ void KAlarmApp::checkNextDueAlarm()
* Also called when the execution queue has finished processing to check for the
* next alarm.
*/
void KAlarmApp::queueAlarmId(const QString& id)
void KAlarmApp::queueAlarmId(const KAEvent& event)
{
#ifdef USE_AKONADI
EventId id(event);
#else
const QString id(event.id());
#endif
for (int i = 0, end = mActionQueue.count(); i < end; ++i)
{
if (mActionQueue[i].function == EVENT_HANDLE && mActionQueue[i].eventId == id)
......@@ -815,7 +835,7 @@ void KAlarmApp::processQueue()
if (!cancelReminderAndDeferral(event))
{
if (mAlarmsEnabled)
queueAlarmId(event.id());
queueAlarmId(event);
}
}
mLoginAlarmsDone = true;
......@@ -880,7 +900,7 @@ void KAlarmApp::atLoginEventAdded(const KAEvent& event)
{
if (mAlarmsEnabled)
{
mActionQueue.enqueue(ActionQEntry(EVENT_HANDLE, ev.id()));
mActionQueue.enqueue(ActionQEntry(EVENT_HANDLE, EventId(ev)));
if (mInitialised)
QTimer::singleShot(0, this, SLOT(processQueue()));
}
......@@ -1153,7 +1173,6 @@ QStringList KAlarmApp::scheduledAlarmList()
#else
KAEvent::List events = KAlarm::getSortedActiveEvents();
#endif
kDebug()<<"List count="<<events.count();
QStringList alarms;
for (int i = 0, count = events.count(); i < count; ++i)
{
......@@ -1278,7 +1297,11 @@ bool KAlarmApp::scheduleEvent(KAEvent::SubAction action, const QString& text, co
* Optionally display the event. Delete the event from the calendar file and
* from every main window instance.
*/
#ifdef USE_AKONADI
bool KAlarmApp::dbusHandleEvent(const EventId& eventID, EventFunc function)
#else
bool KAlarmApp::dbusHandleEvent(const QString& eventID, EventFunc function)
#endif
{
kDebug() << eventID;
mActionQueue.append(ActionQEntry(function, eventID));
......@@ -1306,29 +1329,33 @@ QString KAlarmApp::dbusList()
* Reply = false if event ID not found, or if more than one event with the same
* ID is found.
*/
#ifdef USE_AKONADI
bool KAlarmApp::handleEvent(const EventId& id, EventFunc function, bool checkDuplicates)
#else
bool KAlarmApp::handleEvent(const QString& eventID, EventFunc function)
#endif
{
// Delete any expired wake-on-suspend config data
KAlarm::checkRtcWakeConfig();
#ifdef USE_AKONADI
KAEvent::List events = AlarmCalendar::resources()->events(eventID);
if (events.count() > 1)
const QString eventID(id.eventId());
KAEvent* event = AlarmCalendar::resources()->event(id, checkDuplicates);
if (!event)
{
kWarning() << "Multiple events found with ID" << eventID;
if (id.collectionId() != -1)
kWarning() << "Event ID not found, or duplicated:" << eventID;
else
kWarning() << "Event ID not found:" << eventID;
return false;
}
if (events.isEmpty())
#else
KAEvent* event = AlarmCalendar::resources()->event(eventID);
if (!event)
#endif
{
kWarning() << "Event ID not found:" << eventID;
return false;
}
#ifdef USE_AKONADI
KAEvent* event = events[0];
#endif
switch (function)
{
......@@ -1570,7 +1597,7 @@ int KAlarmApp::rescheduleAlarm(KAEvent& event, const KAAlarm& alarm, bool update
event.startChanges();
if (alarm.repeatAtLogin())
{
// Leave an alarm which repeats at every login until its main alarm triggers
// Leave an alarm which repeats at every login until its main alarm triggers
if (!event.reminderActive() && event.reminderMinutes() < 0)
{
// Executing an at-login alarm: first schedule the reminder
......@@ -1610,7 +1637,7 @@ int KAlarmApp::rescheduleAlarm(KAEvent& event, const KAAlarm& alarm, bool update
// Note that at-login reminders are scheduled in execAlarm().
event.activateReminderAfter(last);
updateCalAndDisplay = true;
}
}
if (cancelAlarm(event, alarm.type(), updateCalAndDisplay))
return -1;
break;
......@@ -1660,7 +1687,7 @@ int KAlarmApp::rescheduleAlarm(KAEvent& event, const KAAlarm& alarm, bool update
// Set the reminder which is now due after the last main alarm trigger.
// Note that at-login reminders are scheduled in execAlarm().
event.activateReminderAfter(last);
}
}
}
event.endChanges();
if (update)
......
......@@ -23,6 +23,9 @@
/** @file kalarmapp.h - the KAlarm application object */
#ifdef USE_AKONADI
#include "eventid.h"
#endif
#include "kamail.h"
#include "preferences.h"
......@@ -79,7 +82,6 @@ class KAlarmApp : public KUniqueApplication
ShellProcess* execCommandAlarm(const KAEvent&, const KAAlarm&, const QObject* receiver = 0, const char* slot = 0);
void alarmCompleted(const KAEvent&);
void rescheduleAlarm(KAEvent& e, const KAAlarm& a) { rescheduleAlarm(e, a, true); }
bool deleteEvent(const QString& eventID) { return handleEvent(eventID, EVENT_CANCEL); }
void purgeAll() { purge(0); }
void commandMessage(ShellProcess*, QWidget* parent);
void notifyAudioPlaying(bool playing);
......@@ -97,8 +99,13 @@ class KAlarmApp : public KUniqueApplication
#endif
const QString& mailSubject = QString(),
const QStringList& mailAttachments = QStringList());
#ifdef USE_AKONADI
bool dbusTriggerEvent(const EventId& eventID) { return dbusHandleEvent(eventID, EVENT_TRIGGER); }
bool dbusDeleteEvent(const EventId& eventID) { return dbusHandleEvent(eventID, EVENT_CANCEL); }
#else
bool dbusTriggerEvent(const QString& eventID) { return dbusHandleEvent(eventID, EVENT_TRIGGER); }
bool dbusDeleteEvent(const QString& eventID) { return dbusHandleEvent(eventID, EVENT_CANCEL); }
#endif
QString dbusList();
public slots:
......@@ -172,11 +179,19 @@ class KAlarmApp : public KUniqueApplication
};
struct ActionQEntry
{
#ifdef USE_AKONADI
ActionQEntry(EventFunc f, const EventId& id) : function(f), eventId(id) { }
#else
ActionQEntry(EventFunc f, const QString& id) : function(f), eventId(id) { }
#endif
ActionQEntry(const KAEvent& e, EventFunc f = EVENT_HANDLE) : function(f), event(e) { }
ActionQEntry() { }
EventFunc function;
#ifdef USE_AKONADI
EventId eventId;
#else
QString eventId;
#endif
KAEvent event;
};
......@@ -184,9 +199,14 @@ class KAlarmApp : public KUniqueApplication
bool quitIf(int exitCode, bool force = false);
bool checkSystemTray();
void startProcessQueue();
void queueAlarmId(const QString& id);
void queueAlarmId(const KAEvent&);
#ifdef USE_AKONADI
bool dbusHandleEvent(const EventId&, EventFunc);
bool handleEvent(const EventId&, EventFunc, bool checkDuplicates = false);
#else
bool dbusHandleEvent(const QString& eventID, EventFunc);
bool handleEvent(const QString& eventID, EventFunc);
#endif
int rescheduleAlarm(KAEvent&, const KAAlarm&, bool updateCalAndDisplay,
const KDateTime& nextDt = KDateTime());
bool cancelAlarm(KAEvent&, KAAlarm::Type, bool updateCalAndDisplay);
......
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