SVN_SILENT made messages (after extraction)
[kdepim.git] / korgac / koalarmclient.cpp
blob111adc7cd548502545672808e15d436e7f6ab556
1 /*
2 This file is part of the KDE reminder agent.
4 Copyright (c) 2002,2003 Cornelius Schumacher <schumacher@kde.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 As a special exception, permission is given to link this program
21 with any edition of Qt, and distribute the resulting executable,
22 without including the source code for Qt in the source distribution.
25 #include "koalarmclient.h"
26 #include "alarmdialog.h"
27 #include "alarmdockwindow.h"
28 #include "korgacadaptor.h"
30 #include <CalendarSupport/Utils>
31 #include <AkonadiCore/ChangeRecorder>
32 #include <AkonadiCore/Collection>
33 #include <kdbusconnectionpool.h>
34 #include <AkonadiCore/EntityTreeModel>
35 #include <AkonadiCore/Item>
36 #include <AkonadiCore/ItemFetchScope>
37 #include <AkonadiCore/Session>
39 #include <KCalCore/Calendar>
41 #include <KCheckableProxyModel>
42 #include <KConfig>
43 #include <KConfigGroup>
44 #include <QApplication>
46 #include "koalarmclient_debug.h"
48 using namespace KCalCore;
50 KOAlarmClient::KOAlarmClient(QObject *parent)
51 : QObject(parent), mDocker(0), mDialog(0)
53 new KOrgacAdaptor(this);
54 KDBusConnectionPool::threadConnection().registerObject(QStringLiteral("/ac"), this);
55 qCDebug(KOALARMCLIENT_LOG);
57 if (dockerEnabled()) {
58 mDocker = new AlarmDockWindow;
59 connect(this, &KOAlarmClient::reminderCount, mDocker, &AlarmDockWindow::slotUpdate);
60 connect(mDocker, &AlarmDockWindow::quitSignal, this, &KOAlarmClient::slotQuit);
62 QStringList mimeTypes;
63 mimeTypes << Event::eventMimeType() << Todo::todoMimeType();
64 mCalendar = Akonadi::ETMCalendar::Ptr(new Akonadi::ETMCalendar(mimeTypes));
65 mCalendar->setObjectName(QStringLiteral("KOrgac's calendar"));
66 mETM = mCalendar->entityTreeModel();
68 connect(&mCheckTimer, &QTimer::timeout, this, &KOAlarmClient::checkAlarms);
69 connect(mETM, &Akonadi::EntityTreeModel::collectionPopulated, this, &KOAlarmClient::deferredInit);
70 connect(mETM, &Akonadi::EntityTreeModel::collectionTreeFetched, this, &KOAlarmClient::deferredInit);
72 KConfigGroup alarmGroup(KSharedConfig::openConfig(), "Alarms");
73 const int interval = alarmGroup.readEntry("Interval", 60);
74 qCDebug(KOALARMCLIENT_LOG) << "KOAlarmClient check interval:" << interval << "seconds.";
75 mLastChecked = alarmGroup.readEntry("CalendarsLastChecked", QDateTime());
77 checkAlarms();
78 mCheckTimer.start(1000 * interval); // interval in seconds
79 connect(qApp, &QApplication::commitDataRequest, this, &KOAlarmClient::slotCommitData);
82 KOAlarmClient::~KOAlarmClient()
84 delete mDocker;
85 delete mDialog;
88 void checkAllItems(KCheckableProxyModel *model, const QModelIndex &parent = QModelIndex())
90 const int rowCount = model->rowCount(parent);
91 for (int row = 0; row < rowCount; ++row) {
92 QModelIndex index = model->index(row, 0, parent);
93 model->setData(index, Qt::Checked, Qt::CheckStateRole);
95 if (model->rowCount(index) > 0) {
96 checkAllItems(model, index);
101 void KOAlarmClient::deferredInit()
103 if (!collectionsAvailable()) {
104 return;
107 qCDebug(KOALARMCLIENT_LOG) << "Performing delayed initialization.";
109 // load reminders that were active when quitting
110 KConfigGroup genGroup(KSharedConfig::openConfig(), "General");
111 const int numReminders = genGroup.readEntry("Reminders", 0);
113 for (int i = 1; i <= numReminders; ++i) {
114 const QString group(QStringLiteral("Incidence-%1").arg(i));
115 const KConfigGroup incGroup(KSharedConfig::openConfig(), group);
117 const QUrl url = incGroup.readEntry("AkonadiUrl");
118 Akonadi::Item::Id akonadiItemId = -1;
119 if (!url.isValid()) {
120 // logic to migrate old KOrganizer incidence uid's to a Akonadi item.
121 const QString uid = incGroup.readEntry("UID");
122 if (!uid.isEmpty()) {
123 akonadiItemId = mCalendar->item(uid).id();
125 } else {
126 akonadiItemId = Akonadi::Item::fromUrl(url).id();
129 if (akonadiItemId >= 0) {
130 const QDateTime dt = incGroup.readEntry("RemindAt", QDateTime());
131 Akonadi::Item i = mCalendar->item(Akonadi::Item::fromUrl(url).id());
132 if (CalendarSupport::hasIncidence(i) && !CalendarSupport::incidence(i)->alarms().isEmpty()) {
133 createReminder(mCalendar, i, dt, QString());
138 KCheckableProxyModel *checkableModel = mCalendar->checkableProxyModel();
139 checkAllItems(checkableModel);
141 // Now that everything is set up, a first check for reminders can be performed.
142 checkAlarms();
145 bool KOAlarmClient::dockerEnabled()
147 KConfig korgConfig(QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("korganizerrc")));
148 KConfigGroup generalGroup(&korgConfig, "System Tray");
149 return generalGroup.readEntry("ShowReminderDaemon", true);
152 bool KOAlarmClient::collectionsAvailable() const
154 // The list of collections must be available.
155 if (!mETM->isCollectionTreeFetched()) {
156 return false;
159 // All collections must be populated.
160 const int rowCount = mETM->rowCount();
161 for (int row = 0; row < rowCount; ++row) {
162 static const int column = 0;
163 const QModelIndex index = mETM->index(row, column);
164 bool haveData =
165 mETM->data(index, Akonadi::EntityTreeModel::IsPopulatedRole).toBool();
166 if (!haveData) {
167 return false;
171 return true;
174 void KOAlarmClient::checkAlarms()
176 KConfigGroup cfg(KSharedConfig::openConfig(), "General");
178 if (!cfg.readEntry("Enabled", true)) {
179 return;
182 // We do not want to miss any reminders, so don't perform check unless
183 // the collections are available and populated.
184 if (!collectionsAvailable()) {
185 qCDebug(KOALARMCLIENT_LOG) << "Collections are not available; aborting check.";
186 return;
189 QDateTime from = mLastChecked.addSecs(1);
190 mLastChecked = QDateTime::currentDateTime();
192 qCDebug(KOALARMCLIENT_LOG) << "Check:" << from.toString() << " -" << mLastChecked.toString();
194 const Alarm::List alarms = mCalendar->alarms(KDateTime(from, KDateTime::LocalZone),
195 KDateTime(mLastChecked, KDateTime::LocalZone),
196 true /* exclude blocked alarms */);
198 foreach (const Alarm::Ptr &alarm, alarms) {
199 const QString uid = alarm->customProperty("ETMCalendar", "parentUid");
200 const Akonadi::Item::Id id = mCalendar->item(uid).id();
201 const Akonadi::Item item = mCalendar->item(id);
203 createReminder(mCalendar, item, from, alarm->text());
207 void KOAlarmClient::createReminder(const Akonadi::ETMCalendar::Ptr &calendar,
208 const Akonadi::Item &aitem,
209 const QDateTime &remindAtDate,
210 const QString &displayText)
212 if (!CalendarSupport::hasIncidence(aitem)) {
213 return;
216 if (!mDialog) {
217 mDialog = new AlarmDialog(calendar);
218 connect(this, &KOAlarmClient::saveAllSignal, mDialog, &AlarmDialog::slotSave);
219 if (mDocker) {
220 connect(mDialog, &AlarmDialog::reminderCount, mDocker, &AlarmDockWindow::slotUpdate);
221 connect(mDocker, &AlarmDockWindow::suspendAllSignal, mDialog, &AlarmDialog::suspendAll);
222 connect(mDocker, &AlarmDockWindow::dismissAllSignal, mDialog, &AlarmDialog::dismissAll);
226 mDialog->addIncidence(aitem, remindAtDate, displayText);
227 mDialog->wakeUp();
228 saveLastCheckTime();
231 void KOAlarmClient::slotQuit()
233 Q_EMIT saveAllSignal();
234 saveLastCheckTime();
235 quit();
238 void KOAlarmClient::saveLastCheckTime()
240 KConfigGroup cg(KSharedConfig::openConfig(), "Alarms");
241 cg.writeEntry("CalendarsLastChecked", mLastChecked);
242 KSharedConfig::openConfig()->sync();
245 void KOAlarmClient::quit()
247 qCDebug(KOALARMCLIENT_LOG);
248 qApp->quit();
251 void KOAlarmClient::slotCommitData(QSessionManager &)
253 Q_EMIT saveAllSignal();
254 saveLastCheckTime();
257 void KOAlarmClient::forceAlarmCheck()
259 checkAlarms();
260 saveLastCheckTime();
263 QString KOAlarmClient::dumpDebug()
265 KConfigGroup cfg(KSharedConfig::openConfig(), "Alarms");
266 const QDateTime lastChecked = cfg.readEntry("CalendarsLastChecked", QDateTime());
267 const QString str = QStringLiteral("Last Check: %1").arg(lastChecked.toString());
268 return str;
271 QStringList KOAlarmClient::dumpAlarms()
273 const KDateTime start = KDateTime(QDateTime::currentDateTime().date(),
274 QTime(0, 0), KDateTime::LocalZone);
275 const KDateTime end = start.addDays(1).addSecs(-1);
277 QStringList lst;
278 const Alarm::List alarms = mCalendar->alarms(start, end);
279 lst.reserve(1 + (alarms.isEmpty() ? 1 : alarms.count()));
280 // Don't translate, this is for debugging purposes.
281 lst << QStringLiteral("AlarmDeamon::dumpAlarms() from ") + start.toString() + QLatin1String(" to ") +
282 end.toString();
284 if (alarms.isEmpty()) {
285 lst << QStringLiteral("No alarm found.");
286 } else {
288 foreach (const Alarm::Ptr &a, alarms) {
289 const Incidence::Ptr parentIncidence = mCalendar->incidence(a->parentUid());
290 lst << QStringLiteral(" ") + parentIncidence->summary() + QLatin1String(" (") + a->time().toString() + QLatin1Char(')');
294 return lst;
297 void KOAlarmClient::hide()
299 delete mDocker;
300 mDocker = 0;
303 void KOAlarmClient::show()
305 if (!mDocker) {
306 if (dockerEnabled()) {
307 mDocker = new AlarmDockWindow;
308 connect(this, &KOAlarmClient::reminderCount, mDocker, &AlarmDockWindow::slotUpdate);
309 connect(mDocker, &AlarmDockWindow::quitSignal, this, &KOAlarmClient::slotQuit);
312 if (mDialog) {
313 connect(mDialog, &AlarmDialog::reminderCount, mDocker, &AlarmDockWindow::slotUpdate);
314 connect(mDocker, &AlarmDockWindow::suspendAllSignal, mDialog, &AlarmDialog::suspendAll);
315 connect(mDocker, &AlarmDockWindow::dismissAllSignal, mDialog, &AlarmDialog::dismissAll);