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.
24 //krazy:excludeall=kdebug because we use the korgac(check) debug area in here
26 #include "koalarmclient.h"
27 #if !defined(KORGAC_AKONADI_AGENT)
28 #include "alarmdialog.h"
29 #include "alarmdockwindow.h"
31 #include <KNotification>
33 #include "korgacadaptor.h"
35 #include <calendarsupport/utils.h>
37 #include <Akonadi/ChangeRecorder>
38 #include <Akonadi/Collection>
39 #include <Akonadi/DBusConnectionPool>
40 #include <Akonadi/EntityTreeModel>
41 #include <Akonadi/Item>
42 #include <Akonadi/ItemFetchScope>
43 #include <Akonadi/Session>
45 #include <KCalCore/Calendar>
47 #include <KApplication>
48 #include <KCheckableProxyModel>
50 #include <KConfigGroup>
52 #include <KStandardDirs>
55 #include <QtMaemo5/QMaemo5InformationBox>
58 using namespace KCalCore
;
60 KOAlarmClient::KOAlarmClient( QObject
*parent
)
61 : QObject( parent
), mDocker( 0 ), mDialog( 0 )
63 new KOrgacAdaptor( this );
64 Akonadi::DBusConnectionPool::threadConnection().registerObject( QLatin1String("/ac"), this );
67 #if !defined(KORGAC_AKONADI_AGENT)
68 if ( dockerEnabled() ) {
69 mDocker
= new AlarmDockWindow
;
70 connect( this, SIGNAL(reminderCount(int)), mDocker
, SLOT(slotUpdate(int)) );
71 connect( mDocker
, SIGNAL(quitSignal()), SLOT(slotQuit()) );
74 QStringList mimeTypes
;
75 mimeTypes
<< Event::eventMimeType() << Todo::todoMimeType();
76 mCalendar
= Akonadi::ETMCalendar::Ptr( new Akonadi::ETMCalendar( mimeTypes
) );
77 mCalendar
->setObjectName( QLatin1String("KOrgac's calendar") );
78 mETM
= mCalendar
->entityTreeModel();
80 connect( &mCheckTimer
, SIGNAL(timeout()), SLOT(checkAlarms()) );
81 connect( mETM
, SIGNAL(collectionPopulated(Akonadi::Collection::Id
)),
82 SLOT(deferredInit()) );
83 connect( mETM
, SIGNAL(collectionTreeFetched(Akonadi::Collection::List
)),
84 SLOT(deferredInit()) );
86 KConfigGroup
alarmGroup( KGlobal::config(), "Alarms" );
87 const int interval
= alarmGroup
.readEntry( "Interval", 60 );
88 kDebug() << "KOAlarmClient check interval:" << interval
<< "seconds.";
89 mLastChecked
= alarmGroup
.readEntry( "CalendarsLastChecked", QDateTime() );
92 mCheckTimer
.start( 1000 * interval
); // interval in seconds
95 KOAlarmClient::~KOAlarmClient()
97 #if !defined(KORGAC_AKONADI_AGENT)
103 void checkAllItems( KCheckableProxyModel
*model
, const QModelIndex
&parent
= QModelIndex() )
105 const int rowCount
= model
->rowCount( parent
);
106 for ( int row
= 0; row
< rowCount
; row
++ ) {
107 QModelIndex index
= model
->index( row
, 0, parent
);
108 model
->setData( index
, Qt::Checked
, Qt::CheckStateRole
);
110 if ( model
->rowCount( index
) > 0 ) {
111 checkAllItems( model
, index
);
116 void KOAlarmClient::deferredInit()
118 if ( !collectionsAvailable() ) {
122 kDebug(5891) << "Performing delayed initialization.";
124 // load reminders that were active when quitting
125 KConfigGroup
genGroup( KGlobal::config(), "General" );
126 const int numReminders
= genGroup
.readEntry( "Reminders", 0 );
128 for ( int i
=1; i
<=numReminders
; ++i
) {
129 const QString
group( QString::fromLatin1( "Incidence-%1" ).arg( i
) );
130 const KConfigGroup
incGroup( KGlobal::config(), group
);
132 const KUrl url
= incGroup
.readEntry( "AkonadiUrl" );
133 Akonadi::Item::Id akonadiItemId
= -1;
134 if ( !url
.isValid() ) {
135 // logic to migrate old KOrganizer incidence uid's to a Akonadi item.
136 const QString uid
= incGroup
.readEntry( "UID" );
137 if ( !uid
.isEmpty() ) {
138 akonadiItemId
= mCalendar
->item( uid
).id();
141 akonadiItemId
= Akonadi::Item::fromUrl( url
).id();
144 if ( akonadiItemId
>= 0 ) {
145 const QDateTime dt
= incGroup
.readEntry( "RemindAt", QDateTime() );
146 Akonadi::Item i
= mCalendar
->item( Akonadi::Item::fromUrl( url
).id() );
147 if ( CalendarSupport::hasIncidence( i
) && !CalendarSupport::incidence( i
)->alarms().isEmpty() ) {
148 createReminder( mCalendar
, i
, dt
, QString() );
153 KCheckableProxyModel
*checkableModel
= mCalendar
->checkableProxyModel();
154 checkAllItems( checkableModel
);
156 // Now that everything is set up, a first check for reminders can be performed.
160 bool KOAlarmClient::dockerEnabled()
162 KConfig
korgConfig( KStandardDirs::locate( "config", QLatin1String("korganizerrc") ) );
163 KConfigGroup
generalGroup( &korgConfig
, "System Tray" );
164 return generalGroup
.readEntry( "ShowReminderDaemon", true );
167 bool KOAlarmClient::collectionsAvailable() const
169 // The list of collections must be available.
170 if ( !mETM
->isCollectionTreeFetched() ) {
174 // All collections must be populated.
175 const int rowCount
= mETM
->rowCount();
176 for ( int row
= 0; row
< rowCount
; ++row
) {
177 static const int column
= 0;
178 const QModelIndex index
= mETM
->index( row
, column
);
180 mETM
->data( index
, Akonadi::EntityTreeModel::IsPopulatedRole
).toBool();
189 void KOAlarmClient::checkAlarms()
191 KConfigGroup
cfg( KGlobal::config(), "General" );
193 if ( !cfg
.readEntry( "Enabled", true ) ) {
197 // We do not want to miss any reminders, so don't perform check unless
198 // the collections are available and populated.
199 if ( !collectionsAvailable() ) {
200 kDebug(5891) << "Collections are not available; aborting check.";
204 QDateTime from
= mLastChecked
.addSecs( 1 );
205 mLastChecked
= QDateTime::currentDateTime();
207 kDebug(5891) << "Check:" << from
.toString() << " -" << mLastChecked
.toString();
209 const Alarm::List alarms
= mCalendar
->alarms( KDateTime( from
, KDateTime::LocalZone
),
210 KDateTime( mLastChecked
, KDateTime::LocalZone
),
211 true /* exclude blocked alarms */);
213 foreach ( const Alarm::Ptr
&alarm
, alarms
) {
214 const QString uid
= alarm
->customProperty( "ETMCalendar", "parentUid" );
215 const Akonadi::Item::Id id
= mCalendar
->item( uid
).id();
216 const Akonadi::Item item
= mCalendar
->item( id
);
218 createReminder( mCalendar
, item
, from
, alarm
->text() );
222 void KOAlarmClient::createReminder( const Akonadi::ETMCalendar::Ptr
&calendar
,
223 const Akonadi::Item
&aitem
,
224 const QDateTime
&remindAtDate
,
225 const QString
&displayText
)
227 if ( !CalendarSupport::hasIncidence( aitem
) ) {
231 #if !defined(Q_WS_MAEMO_5) && !defined(KORGAC_AKONADI_AGENT)
233 mDialog
= new AlarmDialog( calendar
);
234 connect( this, SIGNAL(saveAllSignal()), mDialog
, SLOT(slotSave()) );
236 connect( mDialog
, SIGNAL(reminderCount(int)),
237 mDocker
, SLOT(slotUpdate(int)) );
238 connect( mDocker
, SIGNAL(suspendAllSignal()),
239 mDialog
, SLOT(suspendAll()) );
240 connect( mDocker
, SIGNAL(dismissAllSignal()),
241 mDialog
, SLOT(dismissAll()) );
245 mDialog
->addIncidence( aitem
, remindAtDate
, displayText
);
248 const Incidence::Ptr incidence
= CalendarSupport::incidence( aitem
);
249 Q_UNUSED( calendar
);
250 Q_UNUSED( remindAtDate
);
251 Q_UNUSED( displayText
);
253 #if defined(Q_WS_MAEMO_5)
254 QMaemo5InformationBox::information( 0, incidence
->summary(), QMaemo5InformationBox::NoTimeout
);
256 KNotification
*notify
= new KNotification( "reminder", 0, KNotification::Persistent
);
257 notify
->setText( incidence
->summary() );
265 void KOAlarmClient::slotQuit()
267 emit
saveAllSignal();
272 void KOAlarmClient::saveLastCheckTime()
274 KConfigGroup
cg( KGlobal::config(), "Alarms" );
275 cg
.writeEntry( "CalendarsLastChecked", mLastChecked
);
276 KGlobal::config()->sync();
279 void KOAlarmClient::quit()
282 #if !defined(KORGAC_AKONADI_AGENT)
287 bool KOAlarmClient::commitData( QSessionManager
& )
289 emit
saveAllSignal();
294 void KOAlarmClient::forceAlarmCheck()
300 void KOAlarmClient::dumpDebug()
302 KConfigGroup
cfg( KGlobal::config(), "Alarms" );
303 const QDateTime lastChecked
= cfg
.readEntry( "CalendarsLastChecked", QDateTime() );
304 kDebug() << "Last Check:" << lastChecked
;
307 QStringList
KOAlarmClient::dumpAlarms()
309 const KDateTime start
= KDateTime( QDateTime::currentDateTime().date(),
310 QTime( 0, 0 ), KDateTime::LocalZone
);
311 const KDateTime end
= start
.addDays( 1 ).addSecs( -1 );
314 // Don't translate, this is for debugging purposes.
315 lst
<< QLatin1String( "AlarmDeamon::dumpAlarms() from " ) + start
.toString() + QLatin1String(" to ") +
318 Alarm::List alarms
= mCalendar
->alarms( start
, end
);
319 foreach( Alarm::Ptr a
, alarms
) {
320 const Incidence::Ptr parentIncidence
= mCalendar
->incidence( a
->parentUid() );
321 lst
<< QLatin1String( " " ) + parentIncidence
->summary() + QLatin1String(" (") + a
->time().toString() + QLatin1Char(')');
327 void KOAlarmClient::debugShowDialog()
329 // showAlarmDialog();
332 void KOAlarmClient::hide()
334 #if !defined(KORGAC_AKONADI_AGENT)
340 void KOAlarmClient::show()
342 #if !defined(KORGAC_AKONADI_AGENT)
344 if ( dockerEnabled() ) {
345 mDocker
= new AlarmDockWindow
;
346 connect( this, SIGNAL(reminderCount(int)), mDocker
, SLOT(slotUpdate(int)) );
347 connect( mDocker
, SIGNAL(quitSignal()), SLOT(slotQuit()) );
351 connect( mDialog
, SIGNAL(reminderCount(int)),
352 mDocker
, SLOT(slotUpdate(int)) );
353 connect( mDocker
, SIGNAL(suspendAllSignal()),
354 mDialog
, SLOT(suspendAll()) );
355 connect( mDocker
, SIGNAL(dismissAllSignal()),
356 mDialog
, SLOT(dismissAll()) );