2 This file is part of KOrganizer.
4 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 As a special exception, permission is given to link this program
22 with any edition of Qt, and distribute the resulting executable,
23 without including the source code for Qt in the source distribution.
26 #include "koeditoralarms.h"
27 #include <KPIMUtils/Email>
28 using namespace KPIMUtils
;
30 class AlarmListViewItem
: public QTreeWidgetItem
33 AlarmListViewItem( QTreeWidget
*parent
, KCal::Alarm
*alarm
);
34 virtual ~AlarmListViewItem();
36 KCal::Alarm
*alarm() const
41 enum AlarmViewColumns
{
50 AlarmListViewItem::AlarmListViewItem( QTreeWidget
*parent
, Alarm
*alarm
)
51 : QTreeWidgetItem( parent
)
54 mAlarm
= new Alarm( *alarm
);
56 mAlarm
= new Alarm( 0 );
61 AlarmListViewItem::~AlarmListViewItem()
66 void AlarmListViewItem::construct()
70 QString
type( i18nc( "@option unknown alarm type", "Unknown" ) );
71 switch ( mAlarm
->type() ) {
73 type
= i18nc( "@option popup reminder dialog", "Reminder Dialog" );
75 case Alarm::Procedure
:
76 type
= i18nc( "@option run application or script", "Application/Script" );
79 type
= i18nc( "@option send email reminder", "Email" );
82 type
= i18nc( "@option play a sound", "Audio" );
86 setText( ColAlarmType
, type
);
89 KLocalizedString offsetstr
;
91 if ( mAlarm
->hasStartOffset() ) {
92 offset
= mAlarm
->startOffset().asSeconds();
95 ki18nc( "@item@intable N days/hours/minutes before/after the start/end",
96 "%1 before the start" );
100 ki18nc( "@item@intable N days/hours/minutes before/after the start/end",
101 "%1 after the start" );
103 } else if ( mAlarm
->hasEndOffset() ) {
104 offset
= mAlarm
->endOffset().asSeconds();
107 ki18nc( "@item@intable N days/hours/minutes before/after the start/end",
108 "%1 before the end" );
112 ki18nc( "@item@intable N days/hours/minutes before/after the start/end",
113 "%1 after the end" );
117 offset
= offset
/ 60; // make minutes
118 int useoffset
= offset
;
120 if ( offset
% ( 24 * 60 ) == 0 && offset
> 0 ) { // divides evenly into days?
121 useoffset
= offset
/ ( 24 * 60 );
123 offsetstr
.subs( i18ncp( "@item@intable alarm offset specified in days",
124 "1 day", "%1 days", useoffset
) );
125 } else if ( offset
% 60 == 0 && offset
> 0 ) { // divides evenly into hours?
126 useoffset
= offset
/ 60;
128 offsetstr
.subs( i18ncp( "@item@intable alarm offset specified in hours",
129 "1 hour", "%1 hours", useoffset
) );
133 offsetstr
.subs( i18ncp( "@item@intable alarm offset specified in minutes",
134 "1 minute", "%1 minutes", useoffset
) );
136 setText( ColAlarmOffset
, offsetstr
.toString() );
139 if ( mAlarm
->repeatCount() > 0 ) {
140 setText( ColAlarmRepeat
, i18nc( "@item@intable yes, the alarm repeats", "Yes" ) );
145 KOEditorAlarms::KOEditorAlarms( const QByteArray
&type
,
146 Alarm::List
*alarms
, QWidget
*parent
)
147 : KDialog( parent
), mType( type
), mAlarms( alarms
), mCurrentItem( 0 )
149 if ( mType
!= "Todo" ) {
150 // only Todos and Events can have reminders
153 setCaption( i18nc( "@title", "Edit Reminders" ) );
154 setButtons( Ok
| Apply
| Cancel
);
155 setDefaultButton( Ok
);
156 QWidget
*widget
= new QWidget( this );
157 mWidget
.setupUi( widget
);
158 setMainWidget( widget
);
159 connect( mWidget
.mAlarmList
, SIGNAL(itemSelectionChanged()),
160 SLOT(itemSelectionChanged()) );
161 connect( mWidget
.mAddButton
, SIGNAL(clicked()), SLOT(slotAdd()) );
162 connect( mWidget
.mRemoveButton
, SIGNAL(clicked()), SLOT(slotRemove()) );
163 connect( mWidget
.mDuplicateButton
, SIGNAL(clicked()), SLOT(slotDuplicate()) );
165 connect( mWidget
.mAlarmOffset
, SIGNAL(valueChanged(int)), SLOT(changed()) );
166 connect( mWidget
.mOffsetUnit
, SIGNAL(activated(int)), SLOT(changed()) );
167 connect( mWidget
.mBeforeAfter
, SIGNAL(activated(int)), SLOT(changed()) );
168 connect( mWidget
.mRepeats
, SIGNAL(toggled(bool)), SLOT(changed()) );
169 connect( mWidget
.mRepeatCount
, SIGNAL(valueChanged(int)), SLOT(changed()) );
170 connect( mWidget
.mRepeatInterval
, SIGNAL(valueChanged(int)), SLOT(changed()) );
172 connect( mWidget
.mTypeDisplayRadio
, SIGNAL(clicked()), SLOT(slotDisplayRadioClicked()) );
173 connect( mWidget
.mTypeSoundRadio
, SIGNAL(clicked()), SLOT(slotSoundRadioClicked()) );
174 connect( mWidget
.mTypeAppRadio
, SIGNAL(clicked()), SLOT(slotAppRadioClicked() ));
175 connect( mWidget
.mTypeEmailRadio
, SIGNAL(clicked()), SLOT(slotEmailRadioClicked()) );
177 connect( mWidget
.mDisplayText
, SIGNAL(textChanged()), SLOT(changed()) );
178 connect( mWidget
.mSoundFile
, SIGNAL(textChanged(const QString
&)), SLOT(changed()) );
179 connect( mWidget
.mApplication
, SIGNAL(textChanged(const QString
&)), SLOT(changed()) );
180 connect( mWidget
.mAppArguments
, SIGNAL(textChanged(const QString
&)), SLOT(changed()) );
181 connect( mWidget
.mEmailAddress
, SIGNAL(textChanged(const QString
&)), SLOT(changed()) );
183 connect( mWidget
.mRepeats
, SIGNAL(toggled(bool)),
184 mWidget
.mIntervalLabel
, SLOT(setEnabled(bool)) );
185 connect( mWidget
.mRepeats
, SIGNAL(toggled(bool)),
186 mWidget
.mRepeatInterval
, SLOT(setEnabled(bool)) );
187 connect( mWidget
.mRepeats
, SIGNAL(toggled(bool)),
188 mWidget
.mHowOftenLabel
, SLOT(setEnabled(bool)) );
189 connect( mWidget
.mRepeats
, SIGNAL(toggled(bool)),
190 mWidget
.mRepeatCount
, SLOT(setEnabled(bool)) );
192 connect( mWidget
.mEmailText
, SIGNAL(textChanged()), SLOT(changed()) );
193 connect( this, SIGNAL(okClicked()), SLOT(slotOk()) );
194 connect( this, SIGNAL(applyClicked()), SLOT(slotApply()) );
198 KOEditorAlarms::~KOEditorAlarms()
202 void KOEditorAlarms::slotDisplayRadioClicked()
204 mWidget
.mTypeStack
->setCurrentIndex(0);
208 void KOEditorAlarms::slotSoundRadioClicked()
210 mWidget
.mTypeStack
->setCurrentIndex(1);
214 void KOEditorAlarms::slotAppRadioClicked()
216 mWidget
.mTypeStack
->setCurrentIndex(2);
220 void KOEditorAlarms::slotEmailRadioClicked()
222 mWidget
.mTypeStack
->setCurrentIndex(3);
226 void KOEditorAlarms::changed()
228 if ( !mInitializing
&& mCurrentItem
) {
229 writeAlarm( mCurrentItem
->alarm() );
230 mCurrentItem
->construct();
234 void KOEditorAlarms::readAlarm( Alarm
*alarm
)
240 mInitializing
= true;
244 int beforeafterpos
= 0;
245 if ( alarm
->hasEndOffset() ) {
247 offset
= alarm
->endOffset().asSeconds();
249 // TODO: Also allow alarms at fixed times, not relative to start/end
250 offset
= alarm
->startOffset().asSeconds();
252 // Negative offset means before the start/end...
258 mWidget
.mBeforeAfter
->setCurrentIndex( beforeafterpos
);
260 offset
= offset
/ 60; // make minutes
261 int useoffset
= offset
;
263 if ( offset
% ( 24 * 60 ) == 0 && offset
> 0 ) { // divides evenly into days?
264 useoffset
= offset
/ ( 24 * 60 );
265 mWidget
.mOffsetUnit
->setCurrentIndex( 2 );
266 } else if ( offset
% 60 == 0 && offset
> 0 ) { // divides evenly into hours?
267 useoffset
= offset
/ 60;
268 mWidget
.mOffsetUnit
->setCurrentIndex( 1 );
271 mWidget
.mOffsetUnit
->setCurrentIndex( 0 );
273 mWidget
.mAlarmOffset
->setValue( useoffset
);
276 mWidget
.mRepeats
->setChecked( alarm
->repeatCount() > 0 );
277 if ( alarm
->repeatCount() > 0 ) {
278 mWidget
.mRepeatCount
->setValue( alarm
->repeatCount() );
279 mWidget
.mRepeatInterval
->setValue( alarm
->snoozeTime().asSeconds() / 60 ); // show as minutes
283 switch ( alarm
->type() ) {
285 mWidget
.mTypeSoundRadio
->setChecked( true );
286 mWidget
.mSoundFile
->setUrl( alarm
->audioFile() );
289 case Alarm::Procedure
:
290 mWidget
.mTypeAppRadio
->setChecked( true );
291 mWidget
.mApplication
->setUrl( alarm
->programFile() );
292 mWidget
.mAppArguments
->setText( alarm
->programArguments() );
297 mWidget
.mTypeEmailRadio
->setChecked( true );
298 QList
<Person
> addresses
= alarm
->mailAddresses();
300 for ( QList
<Person
>::ConstIterator it
= addresses
.constBegin();
301 it
!= addresses
.constEnd(); ++it
) {
302 add
<< (*it
).fullName();
304 mWidget
.mEmailAddress
->setText( add
.join( ", " ) );
305 mWidget
.mEmailText
->setPlainText( alarm
->mailText() );
312 mWidget
.mTypeDisplayRadio
->setChecked( true );
313 mWidget
.mDisplayText
->setPlainText( alarm
->text() );
317 mWidget
.mTypeStack
->setCurrentIndex( id
);
319 mInitializing
= false;
322 void KOEditorAlarms::writeAlarm( Alarm
*alarm
)
325 int offset
= mWidget
.mAlarmOffset
->value() * 60; // minutes
326 int offsetunit
= mWidget
.mOffsetUnit
->currentIndex();
327 if ( offsetunit
>= 1 ) {
328 offset
*= 60; // hours
330 if ( offsetunit
>= 2 ) {
331 offset
*= 24; // days
333 if ( offsetunit
>= 3 ) {
334 offset
*= 7; // weeks
337 int beforeafterpos
= mWidget
.mBeforeAfter
->currentIndex();
338 if ( beforeafterpos
% 2 == 0 ) { // before -> negative
342 // TODO: Add possibility to specify a given time for the reminder
343 if ( beforeafterpos
/ 2 == 0 ) { // start offset
344 alarm
->setStartOffset( Duration( offset
) );
346 alarm
->setEndOffset( Duration( offset
) );
350 if ( mWidget
.mRepeats
->isChecked() ) {
351 alarm
->setRepeatCount( mWidget
.mRepeatCount
->value() );
352 alarm
->setSnoozeTime( mWidget
.mRepeatInterval
->value() * 60 ); // convert back to seconds
354 alarm
->setRepeatCount( 0 );
357 if ( mWidget
.mTypeSoundRadio
->isChecked() ) { // Audio
358 alarm
->setAudioAlarm( mWidget
.mSoundFile
->url().toLocalFile() );
359 } else if ( mWidget
.mTypeAppRadio
->isChecked() ) { // Procedure
360 alarm
->setProcedureAlarm( mWidget
.mApplication
->url().toLocalFile(),
361 mWidget
.mAppArguments
->text() );
362 } else if ( mWidget
.mTypeEmailRadio
->isChecked() ) { // Email
363 QStringList addresses
= KPIMUtils::splitAddressList( mWidget
.mEmailAddress
->text() );
365 for ( QStringList::Iterator it
= addresses
.begin(); it
!= addresses
.end(); ++it
) {
366 add
<< Person::fromFullName( *it
);
368 // TODO: Add a subject line and possibilities for attachments
369 alarm
->setEmailAlarm( QString(), mWidget
.mEmailText
->toPlainText(), add
);
371 alarm
->setDisplayAlarm( mWidget
.mDisplayText
->toPlainText() );
375 void KOEditorAlarms::itemSelectionChanged()
377 if ( mWidget
.mAlarmList
->currentItem() ) {
378 AlarmListViewItem
*item
=
379 dynamic_cast<AlarmListViewItem
*>( mWidget
.mAlarmList
->currentItem() );
381 mWidget
.mTimeGroup
->setEnabled( item
);
382 mWidget
.mTypeGroup
->setEnabled( item
);
384 readAlarm( item
->alarm() );
389 void KOEditorAlarms::slotApply()
391 // copy the mAlarms list
394 for ( int i
= 0; i
< mWidget
.mAlarmList
->topLevelItemCount(); ++i
) {
395 AlarmListViewItem
*item
=
396 dynamic_cast< AlarmListViewItem
*>( mWidget
.mAlarmList
->topLevelItem( i
) );
398 mAlarms
->append( new Alarm( *( item
->alarm() ) ) );
404 void KOEditorAlarms::slotOk()
410 void KOEditorAlarms::slotAdd()
412 mCurrentItem
= new AlarmListViewItem( mWidget
.mAlarmList
, 0 );
413 mWidget
.mAlarmList
->setCurrentItem( mCurrentItem
);
414 mWidget
.mBeforeAfter
->setCurrentIndex( 0 );
416 // selectionChanged( mCurrentItem );
419 void KOEditorAlarms::slotDuplicate()
421 if ( mCurrentItem
) {
422 mCurrentItem
= new AlarmListViewItem( mWidget
.mAlarmList
, mCurrentItem
->alarm() );
423 mWidget
.mAlarmList
->setCurrentItem( mCurrentItem
);
424 // selectionChanged( mCurrentItem );
428 void KOEditorAlarms::slotRemove()
430 if ( mCurrentItem
) {
432 mCurrentItem
= dynamic_cast<AlarmListViewItem
*>( mWidget
.mAlarmList
->currentItem() );
433 mWidget
.mAlarmList
->setCurrentItem( mCurrentItem
);
438 void KOEditorAlarms::init()
440 mInitializing
= true;
442 // Tweak some UI stuff depending on the Incidence type
443 if ( mType
== "Todo" ) {
444 // Replace before/after end datetime with before/after due datetime
445 mWidget
.mBeforeAfter
->setItemText( 0, i18nc( "@item:inlistbox",
446 "before the to-do starts" ) );
447 mWidget
.mBeforeAfter
->setItemText( 1, i18nc( "@item:inlistbox",
448 "after the to-do starts" ) );
449 mWidget
.mBeforeAfter
->setItemText( 2, i18nc( "@item:inlistbox",
450 "before the to-do is due" ) );
451 mWidget
.mBeforeAfter
->setItemText( 3, i18nc( "@item:inlistbox",
452 "after the to-do is due" ) );
453 mWidget
.mBeforeAfter
->setToolTip(
454 i18nc( "@info:tooltip",
455 "Select the reminder trigger relative to the start or due time" ) );
456 mWidget
.mBeforeAfter
->setWhatsThis(
457 i18nc( "@info:whatsthis",
458 "Use this combobox to specify if you want the reminder to "
459 "trigger before or after the start or due time." ) );
462 // Fill-in existing alarms
463 Alarm::List::ConstIterator it
;
464 for ( it
= mAlarms
->constBegin(); it
!= mAlarms
->constEnd(); ++it
) {
465 new AlarmListViewItem( mWidget
.mAlarmList
, *it
);
467 if ( mWidget
.mAlarmList
->topLevelItemCount() > 0 ) {
468 mWidget
.mAlarmList
->setCurrentItem( mWidget
.mAlarmList
->topLevelItem( 0 ) );
471 mWidget
.mAlarmOffset
->setFocus();
473 mInitializing
= false;
476 #include "koeditoralarms.moc"