2 This file is part of the KDE reminder agent.
4 Copyright (c) 2000,2003 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (c) 2008-2009 Allen Winter <winter@kde.org>
6 Copyright (c) 2009-2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 As a special exception, permission is given to link this program
23 with any edition of Qt, and distribute the resulting executable,
24 without including the source code for Qt in the source distribution.
27 #include "alarmdialog.h"
28 #include "korganizer_interface.h"
29 #include "mailclient.h"
31 #include <calendarsupport/next/incidenceviewer.h>
32 #include <calendarsupport/kcalprefs.h>
33 #include <calendarsupport/identitymanager.h>
34 #include <calendarsupport/utils.h>
36 #include <incidenceeditor-ng/incidencedialog.h>
37 #include <incidenceeditor-ng/incidencedialogfactory.h>
39 #include <KCalCore/Event>
40 #include <KCalCore/Todo>
41 #include <KCalUtils/IncidenceFormatter>
43 #include <KPIMIdentities/Identity>
44 #include <KPIMIdentities/IdentityManager>
46 #include <Akonadi/Item>
48 #include <Mailtransport/TransportManager>
54 #include <KMessageBox>
55 #include <KNotification>
56 #include <KSharedConfig>
57 #include <KSystemTimeZone>
58 #include <KToolInvocation>
59 #include <KWindowSystem>
61 #include <phonon/mediaobject.h>
65 #include <QTreeWidget>
66 #include <QVBoxLayout>
68 using namespace KPIMIdentities
;
69 using namespace KCalCore
;
70 using namespace KCalUtils
;
72 static int defSuspendVal
= 5;
73 static int defSuspendUnit
= 0; // 0=>minutes, 1=>hours, 2=>days, 3=>weeks
75 class ReminderTree
: public QTreeWidget
78 ReminderTree( QWidget
*parent
) : QTreeWidget( parent
)
83 void mouseReleaseEvent( QMouseEvent
*event
);
86 void ReminderTree::mouseReleaseEvent( QMouseEvent
*event
)
88 QTreeWidgetItem
*item
= itemAt( event
->pos() );
90 if ( event
->button() == Qt::LeftButton
) {
91 emit
itemActivated( item
, 0 );
92 } else if ( event
->button() == Qt::RightButton
) {
93 emit
customContextMenuRequested( event
->pos() );
98 class ReminderTreeItem
: public QTreeWidgetItem
101 ReminderTreeItem( const Akonadi::Item
&incidence
, QTreeWidget
*parent
)
102 : QTreeWidgetItem( parent
), mIncidence( incidence
), mNotified( false )
105 bool operator<( const QTreeWidgetItem
& other
) const;
107 QString mDisplayText
;
109 const Akonadi::Item mIncidence
;
112 KDateTime mHappening
;
122 bool ReminderTreeItem::operator<( const QTreeWidgetItem
&other
) const
124 switch( treeWidget()->sortColumn() ) {
125 case 1: // happening datetime
127 const ReminderTreeItem
*item
= static_cast<const ReminderTreeItem
*>( &other
);
128 return item
->mHappening
.secsTo( mHappening
);
130 case 2: // trigger datetime
132 const ReminderTreeItem
*item
= static_cast<const ReminderTreeItem
*>( &other
);
133 return item
->mTrigger
.secsTo( mTrigger
);
136 return QTreeWidgetItem::operator < ( other
);
140 typedef QList
<ReminderTreeItem
*> ReminderList
;
142 AlarmDialog::AlarmDialog( const Akonadi::ETMCalendar::Ptr
&calendar
, QWidget
*parent
)
143 : KDialog( parent
, Qt::WindowStaysOnTopHint
),
144 mCalendar( calendar
), mSuspendTimer( this )
147 // User2 => Dismiss All
148 // User3 => Dismiss Selected
151 connect( calendar
.data(), SIGNAL(calendarChanged()), SLOT(slotCalendarChanged()) );
153 KIconLoader::global()->addAppDir( QLatin1String("korgac") );
155 KSharedConfig::Ptr config
= KGlobal::config();
156 KConfigGroup
generalConfig( config
, "General" );
157 QPoint pos
= generalConfig
.readEntry( "Position", QPoint( 0, 0 ) );
159 QWidget
*topBox
= new QWidget( this );
160 if ( !pos
.isNull() ) {
162 topBox
->move( mPos
);
164 setMainWidget( topBox
);
165 setCaption( i18nc( "@title:window", "Reminders" ) );
166 setWindowIcon( KIcon( QLatin1String("korgac") ) );
167 setButtons( Ok
| User1
| User2
| User3
);
168 setDefaultButton( NoDefault
);
169 setButtonText( User3
, i18nc( "@action:button", "Dismiss Reminder" ) );
170 setButtonToolTip( User3
, i18nc( "@info:tooltip",
171 "Dismiss the reminders for the selected incidences" ) );
172 setButtonText( User2
, i18nc( "@action:button", "Dismiss All" ) );
173 setButtonToolTip( User2
, i18nc( "@info:tooltip",
174 "Dismiss the reminders for all listed incidences" ) );
175 setButtonText( User1
, i18nc( "@action:button", "Edit..." ) );
176 setButtonToolTip( User1
, i18nc( "@info:tooltip",
177 "Edit the selected incidence" ) );
178 setButtonText( Ok
, i18nc( "@action:button", "Suspend" ) );
179 setButtonToolTip( Ok
, i18nc( "@info:tooltip",
180 "Suspend the reminders for the selected incidences "
181 "by the specified interval" ) );
183 // Try to keep the dialog small and non-obtrusive.
184 setMinimumWidth( 575 );
185 setMinimumHeight( 300 );
187 QVBoxLayout
*mTopLayout
= new QVBoxLayout( topBox
);
189 QLabel
*label
= new QLabel(
192 "Click on a title to toggle the details viewer for that item" ),
194 mTopLayout
->addWidget( label
);
196 mIncidenceTree
= new ReminderTree( topBox
);
197 mIncidenceTree
->setColumnCount( 3 );
198 mIncidenceTree
->setSortingEnabled( true );
199 const QStringList headerLabels
=
200 ( QStringList( i18nc( "@title:column reminder title", "Title" ) )
201 << i18nc( "@title:column happens at date/time", "Date Time" )
202 << i18nc( "@title:column trigger date/time", "Trigger Time" ) );
203 mIncidenceTree
->setHeaderLabels( headerLabels
);
204 mIncidenceTree
->headerItem()->setToolTip(
206 i18nc( "@info:tooltip", "The event or to-do title" ) );
207 mIncidenceTree
->headerItem()->setToolTip(
209 i18nc( "@info:tooltip", "The reminder is set for this date/time" ) );
210 mIncidenceTree
->headerItem()->setToolTip(
212 i18nc( "@info:tooltip", "The date/time the reminder was triggered" ) );
214 mIncidenceTree
->setWordWrap( true );
215 mIncidenceTree
->setAllColumnsShowFocus( true );
216 mIncidenceTree
->setSelectionMode( QAbstractItemView::ExtendedSelection
);
217 mIncidenceTree
->setRootIsDecorated( false );
219 mTopLayout
->addWidget( mIncidenceTree
);
221 connect( mIncidenceTree
, SIGNAL(itemActivated(QTreeWidgetItem
*,int)),
223 connect( mIncidenceTree
, SIGNAL(itemDoubleClicked(QTreeWidgetItem
*,int)),
225 connect( mIncidenceTree
, SIGNAL(customContextMenuRequested(QPoint
)), SLOT(popupItemMenu(QPoint
)) );
227 mDetailView
= new CalendarSupport::IncidenceViewer( mCalendar
.data(), topBox
);
229 s
= i18nc( "@info default incidence details string",
230 "<emphasis>Select an event or to-do from the list above "
231 "to view its details here.</emphasis>" );
232 mDetailView
->setDefaultMessage( s
);
233 mTopLayout
->addWidget( mDetailView
);
237 KHBox
*suspendBox
= new KHBox( topBox
);
238 suspendBox
->setSpacing( spacingHint() );
239 mTopLayout
->addWidget( suspendBox
);
241 QLabel
*l
= new QLabel( i18nc( "@label:spinbox", "Suspend &duration:" ), suspendBox
);
243 mSuspendSpin
= new QSpinBox( suspendBox
);
244 mSuspendSpin
->setRange( 1, 9999 );
245 mSuspendSpin
->setValue( defSuspendVal
); // default suspend duration
246 mSuspendSpin
->setToolTip(
247 i18nc( "@info:tooltip",
248 "Suspend the reminders by this amount of time" ) );
249 mSuspendSpin
->setWhatsThis(
250 i18nc( "@info:whatsthis",
251 "Each reminder for the selected incidences will be suspended "
252 "by this number of time units. You can choose the time units "
253 "(typically minutes) in the adjacent selector." ) );
255 l
->setBuddy( mSuspendSpin
);
257 mSuspendUnit
= new KComboBox( suspendBox
);
258 mSuspendUnit
->addItem( i18nc( "@item:inlistbox suspend in terms of minutes", "minute(s)" ) );
259 mSuspendUnit
->addItem( i18nc( "@item:inlistbox suspend in terms of hours", "hour(s)" ) );
260 mSuspendUnit
->addItem( i18nc( "@item:inlistbox suspend in terms of days", "day(s)" ) );
261 mSuspendUnit
->addItem( i18nc( "@item:inlistbox suspend in terms of weeks", "week(s)" ) );
262 mSuspendUnit
->setToolTip(
263 i18nc( "@info:tooltip",
264 "Suspend the reminders using this time unit" ) );
265 mSuspendUnit
->setWhatsThis(
266 i18nc( "@info:whatsthis",
267 "Each reminder for the selected incidences will be suspended "
268 "using this time unit. You can set the number of time units "
269 "in the adjacent number entry input." ) );
271 mSuspendUnit
->setCurrentIndex( defSuspendUnit
);
273 connect( &mSuspendTimer
, SIGNAL(timeout()), SLOT(wakeUp()) );
275 connect( this, SIGNAL(okClicked()), this, SLOT(slotOk()) );
276 connect( this, SIGNAL(user1Clicked()), this, SLOT(slotUser1()) );
277 connect( this, SIGNAL(user2Clicked()), this, SLOT(slotUser2()) );
278 connect( this, SIGNAL(user3Clicked()), this, SLOT(slotUser3()) );
280 mIdentityManager
= new CalendarSupport::IdentityManager
;
283 AlarmDialog::~AlarmDialog()
285 mIncidenceTree
->clear();
286 delete mIdentityManager
;
289 ReminderTreeItem
*AlarmDialog::searchByItem( const Akonadi::Item
&incidence
)
291 ReminderTreeItem
*found
= 0;
292 QTreeWidgetItemIterator
it( mIncidenceTree
);
294 ReminderTreeItem
*item
= static_cast<ReminderTreeItem
*>( *it
);
295 if ( item
->mIncidence
== incidence
) {
304 static QString
cleanSummary( const QString
&summary
)
306 static QString etc
= i18nc( "@label an elipsis", "..." );
308 QString retStr
= summary
;
309 retStr
.replace( QLatin1Char('\n'), QLatin1Char(' ') );
310 if ( retStr
.length() > maxLen
) {
311 maxLen
-= etc
.length();
312 retStr
= retStr
.left( maxLen
);
318 void AlarmDialog::addIncidence( const Akonadi::Item
&incidenceitem
,
319 const QDateTime
&reminderAt
,
320 const QString
&displayText
)
322 Incidence::Ptr incidence
= CalendarSupport::incidence( incidenceitem
);
323 ReminderTreeItem
*item
= searchByItem( incidenceitem
);
325 item
= new ReminderTreeItem( incidenceitem
, mIncidenceTree
);
327 item
->mNotified
= false;
328 item
->mHappening
= KDateTime();
329 item
->mRemindAt
= reminderAt
;
330 item
->mTrigger
= KDateTime::currentLocalDateTime();
331 item
->mDisplayText
= displayText
;
332 item
->setText( 0, cleanSummary( incidence
->summary() ) );
338 const KDateTime dateTime
= triggerDateForIncidence( incidence
, reminderAt
,
341 if ( incidence
->type() == Incidence::TypeEvent
) {
342 item
->setIcon( 0, SmallIcon( QLatin1String("view-calendar-day") ) );
343 } else if ( incidence
->type() == Incidence::TypeTodo
) {
344 item
->setIcon( 0, SmallIcon( QLatin1String("view-calendar-tasks")) );
347 item
->mHappening
= dateTime
;
348 item
->setText( 1, displayStr
);
350 item
->setText( 2, IncidenceFormatter::dateTimeToString(
351 item
->mTrigger
, false, true, KDateTime::Spec::LocalZone() ) );
353 IncidenceFormatter::toolTipStr(
354 CalendarSupport::displayName( mCalendar
.data(), incidenceitem
.parentCollection() ),
356 item
->mRemindAt
.date(), true,
357 KDateTime::Spec::LocalZone() );
358 if ( !item
->mDisplayText
.isEmpty() ) {
359 tip
+= QLatin1String("<br>") + item
->mDisplayText
;
361 item
->setToolTip( 0, tip
);
362 item
->setToolTip( 1, tip
);
363 item
->setToolTip( 2, tip
);
364 item
->setData( 0, QTreeWidgetItem::UserType
, false );
366 mIncidenceTree
->setCurrentItem( item
);
371 void AlarmDialog::slotOk()
376 void AlarmDialog::slotUser1()
381 void AlarmDialog::slotUser2()
386 void AlarmDialog::slotUser3()
391 void AlarmDialog::dismissCurrent()
393 dismiss( selectedItems() );
395 if ( activeCount() == 0 ) {
400 emit
reminderCount( activeCount() );
403 void AlarmDialog::dismissAll()
405 ReminderList selections
;
407 QTreeWidgetItemIterator
it( mIncidenceTree
);
409 if ( !(*it
)->isDisabled() ) { //do not disable suspended reminders
410 selections
.append( static_cast<ReminderTreeItem
*>( *it
) );
414 dismiss( selections
);
418 emit
reminderCount( activeCount() );
421 void AlarmDialog::dismiss( ReminderList selections
)
423 QList
<Akonadi::Item::Id
> ids
;
424 for ( ReminderList::Iterator it
= selections
.begin(); it
!= selections
.end(); ++it
) {
425 kDebug() << "removing " << CalendarSupport::incidence( (*it
)->mIncidence
)->summary();
426 if ( mIncidenceTree
->itemBelow( *it
) ) {
427 mIncidenceTree
->setCurrentItem( mIncidenceTree
->itemBelow( *it
) );
428 } else if ( mIncidenceTree
->itemAbove( *it
) ) {
429 mIncidenceTree
->setCurrentItem( mIncidenceTree
->itemAbove( *it
) );
431 mIncidenceTree
->removeItemWidget( *it
, 0 );
432 ids
.append( (*it
)->mIncidence
.id() );
436 removeFromConfig( ids
);
439 void AlarmDialog::edit()
441 ReminderList selection
= selectedItems();
442 if ( selection
.count() != 1 ) {
445 Incidence::Ptr incidence
= CalendarSupport::incidence( selection
.first()->mIncidence
);
446 if ( !mCalendar
->hasRight( selection
.first()->mIncidence
, Akonadi::Collection::CanChangeItem
) ) {
450 "\"%1\" is a read-only item so modifications are not possible.",
451 cleanSummary( incidence
->summary() ) ) );
455 #if !defined(KDEPIM_MOBILE_UI)
456 openIncidenceEditorNG( selection
.first()->mIncidence
);
458 openIncidenceEditorThroughKOrganizer( incidence
);
462 void AlarmDialog::suspend()
464 if ( !isVisible() ) { //do nothing if the dialog is hidden
469 switch ( mSuspendUnit
->currentIndex() ) {
482 ReminderTreeItem
*selitem
= 0;
483 QTreeWidgetItemIterator
it( mIncidenceTree
);
485 if ( (*it
)->isSelected() && !(*it
)->isDisabled() ) { //suspend selected, non-suspended reminders
486 (*it
)->setSelected( false );
487 (*it
)->setDisabled( true );
488 ReminderTreeItem
*item
= static_cast<ReminderTreeItem
*>( *it
);
489 item
->mRemindAt
= QDateTime::currentDateTime().addSecs( unit
* mSuspendSpin
->value() );
490 item
->mHappening
= KDateTime( item
->mRemindAt
, KDateTime::Spec::LocalZone() );
491 item
->mNotified
= false;
492 (*it
)->setText( 1, KGlobal::locale()->formatDateTime( item
->mHappening
) );
499 if ( mIncidenceTree
->itemBelow( selitem
) ) {
500 mIncidenceTree
->setCurrentItem( mIncidenceTree
->itemBelow( selitem
) );
501 } else if ( mIncidenceTree
->itemAbove( selitem
) ) {
502 mIncidenceTree
->setCurrentItem( mIncidenceTree
->itemAbove( selitem
) );
506 // save suspended alarms too so they can be restored on restart
511 if ( activeCount() == 0 ) {
516 emit
reminderCount( activeCount() );
519 void AlarmDialog::setTimer()
521 int nextReminderAt
= -1;
523 QTreeWidgetItemIterator
it( mIncidenceTree
);
525 ReminderTreeItem
*item
= static_cast<ReminderTreeItem
*>( *it
);
526 if ( item
->mRemindAt
> QDateTime::currentDateTime() ) {
527 const int secs
= QDateTime::currentDateTime().secsTo( item
->mRemindAt
);
528 nextReminderAt
= nextReminderAt
<= 0 ? secs
: qMin( nextReminderAt
, secs
);
533 if ( nextReminderAt
>= 0 ) {
534 mSuspendTimer
.stop();
535 mSuspendTimer
.start( 1000 * ( nextReminderAt
+ 1 ) );
536 mSuspendTimer
.setSingleShot( true );
540 void AlarmDialog::show()
542 mIncidenceTree
->resizeColumnToContents( 0 );
543 mIncidenceTree
->resizeColumnToContents( 1 );
544 mIncidenceTree
->resizeColumnToContents( 2 );
545 mIncidenceTree
->sortItems( 1, Qt::AscendingOrder
);
547 // select the first item that hasn't already been notified
548 QTreeWidgetItemIterator
it( mIncidenceTree
);
550 ReminderTreeItem
*item
= static_cast<ReminderTreeItem
*>( *it
);
551 if ( !item
->mNotified
) {
552 (*it
)->setSelected( true );
558 // reset the default suspend time
559 // Allen: commented-out the following lines on 17 Sept 2013
560 // mSuspendSpin->setValue( defSuspendVal );
561 // mSuspendUnit->setCurrentIndex( defSuspendUnit );
564 if ( !mPos
.isNull() ) {
565 KDialog::move( mPos
);
567 KWindowSystem::unminimizeWindow( winId(), false );
568 KWindowSystem::setState( winId(), NET::KeepAbove
| NET::DemandsAttention
);
569 KWindowSystem::setOnAllDesktops( winId(), true );
570 KWindowSystem::activateWindow( winId() );
572 // Audio, Procedure, and EMail alarms
576 void AlarmDialog::suspendAll()
578 mIncidenceTree
->clearSelection();
579 QTreeWidgetItemIterator
it( mIncidenceTree
);
581 // first, select all non-suspended reminders
583 if ( !(*it
)->isDisabled() ) { //do not suspend suspended reminders
584 (*it
)->setSelected( true );
589 //suspend all selected reminders
593 void AlarmDialog::eventNotification()
600 QTreeWidgetItemIterator
it( mIncidenceTree
);
602 ReminderTreeItem
*item
= static_cast<ReminderTreeItem
*>( *it
);
604 if ( item
->isDisabled() || item
->mNotified
) {
605 //skip suspended reminders or reminders that have been notified
609 item
->mNotified
= true;
610 Incidence::Ptr incidence
= CalendarSupport::incidence( item
->mIncidence
);
611 Alarm::List alarms
= incidence
->alarms();
612 Alarm::List::ConstIterator ait
;
613 for ( ait
= alarms
.constBegin(); ait
!= alarms
.constEnd(); ++ait
) {
614 Alarm::Ptr alarm
= *ait
;
615 // FIXME: Check whether this should be done for all multiple alarms
616 if ( alarm
->type() == Alarm::Procedure
) {
617 // FIXME: Add a message box asking whether the procedure should really be executed
618 kDebug() << "Starting program: '" << alarm
->programFile() << "'";
620 QString program
= alarm
->programFile();
622 // if the program name contains spaces escape it
623 if ( program
.contains( QLatin1Char(' ') ) &&
624 !( program
.startsWith( QLatin1Char('\"') ) &&
625 program
.endsWith( QLatin1Char('\"') ) ) ) {
626 program
= QLatin1Char('\"') + program
+ QLatin1Char('\"');
629 QProcess::startDetached( program
+ QLatin1Char(' ') + alarm
->programArguments() );
630 } else if ( alarm
->type() == Alarm::Audio
) {
632 Phonon::MediaObject
*player
=
633 Phonon::createPlayer( Phonon::NotificationCategory
,
634 KUrl( alarm
->audioFile() ) );
635 player
->setParent( this );
636 connect( player
, SIGNAL(finished()), player
, SLOT(deleteLater()) );
638 } else if ( alarm
->type() == Alarm::Email
) {
639 QString from
= CalendarSupport::KCalPrefs::instance()->email();
640 Identity id
= mIdentityManager
->identityForAddress( from
);
642 if ( alarm
->mailAddresses().isEmpty() ) {
645 const Person::List addresses
= alarm
->mailAddresses();
647 for ( Person::List::ConstIterator it
= addresses
.constBegin();
648 it
!= addresses
.constEnd(); ++it
) {
649 add
<< (*it
)->fullName();
651 to
= add
.join( QLatin1String(", ") );
656 Akonadi::Item parentItem
= mCalendar
->item( alarm
->parentUid() );
657 Incidence::Ptr parent
= CalendarSupport::incidence( parentItem
);
659 if ( alarm
->mailSubject().isEmpty() ) {
660 if ( parent
->summary().isEmpty() ) {
661 subject
= i18nc( "@title", "Reminder" );
663 subject
= i18nc( "@title", "Reminder: %1", cleanSummary( parent
->summary() ) );
666 subject
= i18nc( "@title", "Reminder: %1", alarm
->mailSubject() );
670 IncidenceFormatter::mailBodyStr(
671 parent
.staticCast
<IncidenceBase
>(), KSystemTimeZones::local() );
672 if ( !alarm
->mailText().isEmpty() ) {
673 body
+= QLatin1Char('\n') + alarm
->mailText();
675 //TODO: support attachments
676 KOrg::MailClient mailer
;
677 mailer
.send( id
, from
, to
, QString(), subject
, body
, true, false, QString(),
678 MailTransport::TransportManager::self()->defaultTransportName() );
683 if ( !beeped
&& found
) {
684 KNotification::beep();
688 void AlarmDialog::wakeUp()
690 bool activeReminders
= false;
691 QTreeWidgetItemIterator
it( mIncidenceTree
);
692 QTreeWidgetItem
*firstItem
= 0;
697 ReminderTreeItem
*item
= static_cast<ReminderTreeItem
*>( *it
);
698 Incidence::Ptr incidence
= CalendarSupport::incidence( item
->mIncidence
);
700 if ( item
->mRemindAt
<= QDateTime::currentDateTime() ) {
701 if ( item
->isDisabled() ) { //do not wakeup non-suspended reminders
702 item
->setDisabled( false );
703 item
->setSelected( false );
705 activeReminders
= true;
707 item
->setDisabled( true );
713 if ( activeReminders
) {
717 showDetails( firstItem
);
718 emit
reminderCount( activeCount() );
721 void AlarmDialog::slotSave()
723 KSharedConfig::Ptr config
= KGlobal::config();
724 KConfigGroup
generalConfig( config
, "General" );
725 int numReminders
= 0;
727 QTreeWidgetItemIterator
it( mIncidenceTree
);
729 ReminderTreeItem
*item
= static_cast<ReminderTreeItem
*>( *it
);
730 KConfigGroup
incidenceConfig( config
,
731 QString::fromLatin1( "Incidence-%1" ).arg( numReminders
+ 1 ) );
733 Incidence::Ptr incidence
= CalendarSupport::incidence( item
->mIncidence
);
734 incidenceConfig
.writeEntry( "AkonadiUrl", item
->mIncidence
.url() );
735 incidenceConfig
.writeEntry( "RemindAt", item
->mRemindAt
);
740 generalConfig
.writeEntry( "Reminders", numReminders
);
741 generalConfig
.writeEntry( "Position", pos() );
745 ReminderList
AlarmDialog::selectedItems() const
749 QTreeWidgetItemIterator
it( mIncidenceTree
);
751 if ( (*it
)->isSelected() ) {
752 list
.append( static_cast<ReminderTreeItem
*>( *it
) );
759 int AlarmDialog::activeCount()
762 QTreeWidgetItemIterator
it( mIncidenceTree
);
764 if ( !(*it
)->isDisabled() ) { //suspended reminders are non-active
769 kDebug() << "computed " << count
<< " active reminders";
773 void AlarmDialog::closeEvent( QCloseEvent
* )
779 void AlarmDialog::updateButtons()
781 const int count
= selectedItems().count();
782 kDebug() << "selected items=" << count
;
783 enableButton( User3
, count
> 0 ); // enable Dismiss, if >1 selected
784 enableButton( User1
, count
== 1 ); // enable Edit, if only 1 selected
785 enableButton( Ok
, count
> 0 ); // enable Suspend, if >1 selected
788 void AlarmDialog::toggleDetails( QTreeWidgetItem
*item
)
794 if ( !mDetailView
->isHidden() ) {
795 if ( mLastItem
== item
) {
796 resize( size().width(), size().height() - mDetailView
->height() - 50 );
802 resize( size().width(), size().height() + mDetailView
->height() + 50 );
809 void AlarmDialog::showDetails( QTreeWidgetItem
*item
)
815 ReminderTreeItem
*reminderItem
= dynamic_cast<ReminderTreeItem
*>( item
);
817 if ( !reminderItem
) {
818 mDetailView
->setIncidence( Akonadi::Item() );
820 if ( !reminderItem
->mDisplayText
.isEmpty() ) {
821 QString txt
= QLatin1String("<qt><p><b>") + reminderItem
->mDisplayText
+ QLatin1String("</b></p></qt>");
822 mDetailView
->setHeaderText( txt
);
824 mDetailView
->setHeaderText( QString() );
826 Incidence::Ptr incidence
= CalendarSupport::incidence( reminderItem
->mIncidence
);
827 mDetailView
->setIncidence( reminderItem
->mIncidence
, reminderItem
->mRemindAt
.date() );
831 void AlarmDialog::update()
834 if ( !mIncidenceTree
->selectedItems().isEmpty() ) {
835 QTreeWidgetItem
*item
= mIncidenceTree
->selectedItems().first();
836 toggleDetails( item
);
840 void AlarmDialog::popupItemMenu( const QPoint
&point
)
842 QTreeWidgetItem
*item
= mIncidenceTree
->itemAt( point
);
847 ReminderTreeItem
*reminderItem
= dynamic_cast<ReminderTreeItem
*>( item
);
848 if ( reminderItem
) {
849 Incidence::Ptr incidence
= CalendarSupport::incidence( reminderItem
->mIncidence
);
854 void AlarmDialog::accept()
856 if ( activeCount() == 0 ) {
863 KDateTime
AlarmDialog::triggerDateForIncidence( const Incidence::Ptr
&incidence
,
864 const QDateTime
&reminderAt
,
865 QString
&displayStr
)
869 if ( incidence
->alarms().isEmpty() ) {
873 Alarm::Ptr alarm
= incidence
->alarms().first();
875 if ( incidence
->recurs() ) {
876 result
= incidence
->recurrence()->getNextDateTime(
877 KDateTime( reminderAt
, KDateTime::Spec::LocalZone( ) ) );
879 displayStr
= KGlobal::locale()->formatDateTime( result
.toLocalZone() );
882 if ( !result
.isValid() ) {
883 result
= incidence
->dateTime( Incidence::RoleAlarm
);
884 displayStr
= IncidenceFormatter::dateTimeToString( result
, false,
886 KDateTime::Spec::LocalZone() );
892 void AlarmDialog::slotCalendarChanged()
894 KCalCore::Incidence::List incidences
= mCalendar
->incidences();
895 Akonadi::Item::List items
= mCalendar
->itemList( incidences
);
896 for ( Akonadi::Item::List::ConstIterator it
= items
.constBegin();
897 it
!= items
.constEnd(); ++it
) {
898 ReminderTreeItem
*item
= searchByItem( *it
);
901 Incidence::Ptr incidence
= CalendarSupport::incidence( *it
);
904 // Yes, alarms can be empty, if someone edited the incidence and removed all alarms
905 if ( !incidence
->alarms().isEmpty() ) {
906 const KDateTime dateTime
= triggerDateForIncidence( incidence
,
910 const QString summary
= cleanSummary( incidence
->summary() );
912 if ( displayStr
!= item
->text( 1 ) || summary
!= item
->text( 0 ) ) {
913 item
->setText( 1, displayStr
);
914 item
->setText( 0, summary
);
921 void AlarmDialog::keyPressEvent( QKeyEvent
*e
)
923 const int key
= e
->key() | e
->modifiers();
925 if ( key
== Qt::Key_Enter
|| key
== Qt::Key_Return
) {
930 KDialog::keyPressEvent( e
);
933 bool AlarmDialog::openIncidenceEditorThroughKOrganizer( const Incidence::Ptr
&incidence
)
935 if ( !QDBusConnection::sessionBus().interface()->isServiceRegistered( QLatin1String("org.kde.korganizer") ) ) {
936 if ( KToolInvocation::startServiceByDesktopName( QLatin1String("korganizer"), QString() ) ) {
940 "Could not start KOrganizer so editing is not possible." ) );
944 org::kde::korganizer::Korganizer
korganizer(
945 QLatin1String("org.kde.korganizer"), QLatin1String("/Korganizer"), QDBusConnection::sessionBus() );
947 kDebug() << "editing incidence " << incidence
->summary();
948 if ( !korganizer
.editIncidence( incidence
->uid() ) ) {
952 "An internal KOrganizer error occurred attempting to modify \"%1\"",
953 cleanSummary( incidence
->summary() ) ) );
956 // get desktop # where korganizer (or kontact) runs
958 QDBusConnection::sessionBus().interface()->isServiceRegistered( QLatin1String("org.kde.kontact") ) ?
959 QLatin1String("kontact/MainWindow_1") : QLatin1String("korganizer/MainWindow_1");
960 QDBusInterface
korganizerObj( QLatin1String("org.kde.korganizer"), QLatin1Char('/') + object
);
962 QDBusReply
<int> reply
= korganizerObj
.call( QLatin1String("winId") );
963 if ( reply
.isValid() ) {
965 int desktop
= KWindowSystem::windowInfo( window
, NET::WMDesktop
).desktop();
966 if ( KWindowSystem::currentDesktop() == desktop
) {
967 KWindowSystem::minimizeWindow( winId(), false );
969 KWindowSystem::setCurrentDesktop( desktop
);
971 KWindowSystem::activateWindow( KWindowSystem::transientFor( window
) );
973 #elif defined(Q_WS_WIN)
974 // WId is a typedef to a void* on windows
975 QDBusReply
<qlonglong
> reply
= korganizerObj
.call( QLatin1String("winId") );
976 if ( reply
.isValid() ) {
977 qlonglong window
= reply
;
978 KWindowSystem::minimizeWindow( winId(), false );
979 KWindowSystem::allowExternalProcessWindowActivation();
980 KWindowSystem::activateWindow( reinterpret_cast<WId
>(window
) );
988 bool AlarmDialog::openIncidenceEditorNG( const Akonadi::Item
&item
)
990 Incidence::Ptr incidence
= CalendarSupport::incidence( item
);
991 IncidenceEditorNG::IncidenceDialog
*dialog
=
992 IncidenceEditorNG::IncidenceDialogFactory::create(
993 false, /*doesn't need initial saving*/
994 incidence
->type(), 0, this );
995 dialog
->load( item
);
999 void AlarmDialog::removeFromConfig( const QList
<Akonadi::Item::Id
> &ids
)
1001 KSharedConfig::Ptr config
= KGlobal::config();
1002 KConfigGroup
genGroup( config
, "General" );
1004 const int oldNumReminders
= genGroup
.readEntry( "Reminders", 0 );
1006 QList
<ConfItem
> newReminders
;
1007 // Delete everything
1008 for ( int i
= 1; i
<= oldNumReminders
; ++i
) {
1009 const QString
group( QString::fromLatin1( "Incidence-%1" ).arg( i
) );
1010 KConfigGroup
incGroup( config
, group
);
1011 const QString uid
= incGroup
.readEntry( "UID" );
1012 const QDateTime remindAtDate
= incGroup
.readEntry( "RemindAt", QDateTime() );
1013 const KUrl akonadiUrl
= incGroup
.readEntry( "AkonadiUrl" );
1014 const Akonadi::Item::Id id
= Akonadi::Item::fromUrl( akonadiUrl
).id();
1015 if ( !ids
.contains( id
) ) {
1017 ci
.akonadiUrl
= akonadiUrl
;
1018 ci
.remindAt
= remindAtDate
;
1020 newReminders
.append( ci
);
1022 config
->deleteGroup( group
);
1025 genGroup
.writeEntry( "Reminders", newReminders
.count() );
1027 //Write everything except those which have an uid we don't want
1028 for ( int i
= 0; i
< newReminders
.count(); ++i
) {
1029 const QString
group( QString::fromLatin1( "Incidence-%1" ).arg( i
+ 1 ) );
1030 KConfigGroup
incGroup( config
, group
);
1031 incGroup
.writeEntry( "UID", newReminders
[i
].uid
);
1032 incGroup
.writeEntry( "RemindAt", newReminders
[i
].remindAt
);
1033 incGroup
.writeEntry( "AkonadiUrl", newReminders
[i
].akonadiUrl
);