krop's commit fixes my problem in a better way, reverting
[kdepim.git] / korganizer / koeditoralarms.cpp
blob95153f9efe7489aee3bcd19ec9797f4600b19ea8
1 /*
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
32 public:
33 AlarmListViewItem( QTreeWidget *parent, KCal::Alarm *alarm );
34 virtual ~AlarmListViewItem();
35 void construct();
36 KCal::Alarm *alarm() const
38 return mAlarm;
41 enum AlarmViewColumns {
42 ColAlarmType=0,
43 ColAlarmOffset,
44 ColAlarmRepeat };
46 protected:
47 Alarm *mAlarm;
50 AlarmListViewItem::AlarmListViewItem( QTreeWidget *parent, Alarm *alarm )
51 : QTreeWidgetItem( parent )
53 if ( alarm ) {
54 mAlarm = new Alarm( *alarm );
55 } else {
56 mAlarm = new Alarm( 0 );
58 construct();
61 AlarmListViewItem::~AlarmListViewItem()
63 delete mAlarm;
66 void AlarmListViewItem::construct()
68 if ( mAlarm ) {
69 // Alarm type:
70 QString type( i18nc( "@option unknown alarm type", "Unknown" ) );
71 switch ( mAlarm->type() ) {
72 case Alarm::Display:
73 type = i18nc( "@option popup reminder dialog", "Reminder Dialog" );
74 break;
75 case Alarm::Procedure:
76 type = i18nc( "@option run application or script", "Application/Script" );
77 break;
78 case Alarm::Email:
79 type = i18nc( "@option send email reminder", "Email" );
80 break;
81 case Alarm::Audio:
82 type = i18nc( "@option play a sound", "Audio" );
83 break;
84 default: break;
86 setText( ColAlarmType, type );
88 // Alarm offset:
89 KLocalizedString offsetstr;
90 int offset = 0;
91 if ( mAlarm->hasStartOffset() ) {
92 offset = mAlarm->startOffset().asSeconds();
93 if ( offset < 0 ) {
94 offsetstr =
95 ki18nc( "@item@intable N days/hours/minutes before/after the start/end",
96 "%1 before the start" );
97 offset = -offset;
98 } else {
99 offsetstr =
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();
105 if ( offset < 0 ) {
106 offsetstr =
107 ki18nc( "@item@intable N days/hours/minutes before/after the start/end",
108 "%1 before the end" );
109 offset = -offset;
110 } else {
111 offsetstr =
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 );
122 offsetstr =
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;
127 offsetstr =
128 offsetstr.subs( i18ncp( "@item@intable alarm offset specified in hours",
129 "1 hour", "%1 hours", useoffset ) );
130 } else {
131 useoffset = offset;
132 offsetstr =
133 offsetstr.subs( i18ncp( "@item@intable alarm offset specified in minutes",
134 "1 minute", "%1 minutes", useoffset ) );
136 setText( ColAlarmOffset, offsetstr.toString() );
138 // Alarm repeat
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
151 mType = "Event";
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()) );
195 init();
198 KOEditorAlarms::~KOEditorAlarms()
202 void KOEditorAlarms::slotDisplayRadioClicked()
204 mWidget.mTypeStack->setCurrentIndex(0);
205 changed();
208 void KOEditorAlarms::slotSoundRadioClicked()
210 mWidget.mTypeStack->setCurrentIndex(1);
211 changed();
214 void KOEditorAlarms::slotAppRadioClicked()
216 mWidget.mTypeStack->setCurrentIndex(2);
217 changed();
220 void KOEditorAlarms::slotEmailRadioClicked()
222 mWidget.mTypeStack->setCurrentIndex(3);
223 changed();
226 void KOEditorAlarms::changed()
228 if ( !mInitializing && mCurrentItem ) {
229 writeAlarm( mCurrentItem->alarm() );
230 mCurrentItem->construct();
234 void KOEditorAlarms::readAlarm( Alarm *alarm )
236 if ( !alarm ) {
237 return;
240 mInitializing = true;
242 // Offsets
243 int offset;
244 int beforeafterpos = 0;
245 if ( alarm->hasEndOffset() ) {
246 beforeafterpos = 2;
247 offset = alarm->endOffset().asSeconds();
248 } else {
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...
253 if ( offset < 0 ) {
254 offset = -offset;
255 } else {
256 ++beforeafterpos;
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 );
269 } else {
270 useoffset = offset;
271 mWidget.mOffsetUnit->setCurrentIndex( 0 );
273 mWidget.mAlarmOffset->setValue( useoffset );
275 // Repeating
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
281 int id = 0;
283 switch ( alarm->type() ) {
284 case Alarm::Audio:
285 mWidget.mTypeSoundRadio->setChecked( true );
286 mWidget.mSoundFile->setUrl( alarm->audioFile() );
287 id = 1;
288 break;
289 case Alarm::Procedure:
290 mWidget.mTypeAppRadio->setChecked( true );
291 mWidget.mApplication->setUrl( alarm->programFile() );
292 mWidget.mAppArguments->setText( alarm->programArguments() );
293 id = 2;
294 break;
295 case Alarm::Email:
297 mWidget.mTypeEmailRadio->setChecked( true );
298 QList<Person> addresses = alarm->mailAddresses();
299 QStringList add;
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() );
306 id = 3;
307 break;
309 case Alarm::Display:
310 case Alarm::Invalid:
311 default:
312 mWidget.mTypeDisplayRadio->setChecked( true );
313 mWidget.mDisplayText->setPlainText( alarm->text() );
314 break;
317 mWidget.mTypeStack->setCurrentIndex( id );
319 mInitializing = false;
322 void KOEditorAlarms::writeAlarm( Alarm *alarm )
324 // Offsets
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
339 offset = -offset;
342 // TODO: Add possibility to specify a given time for the reminder
343 if ( beforeafterpos / 2 == 0 ) { // start offset
344 alarm->setStartOffset( Duration( offset ) );
345 } else {
346 alarm->setEndOffset( Duration( offset ) );
349 // Repeating
350 if ( mWidget.mRepeats->isChecked() ) {
351 alarm->setRepeatCount( mWidget.mRepeatCount->value() );
352 alarm->setSnoozeTime( mWidget.mRepeatInterval->value() * 60 ); // convert back to seconds
353 } else {
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() );
364 QList<Person> add;
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 );
370 } else { // Display
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() );
380 mCurrentItem = item;
381 mWidget.mTimeGroup->setEnabled( item );
382 mWidget.mTypeGroup->setEnabled( item );
383 if ( item ) {
384 readAlarm( item->alarm() );
389 void KOEditorAlarms::slotApply()
391 // copy the mAlarms list
392 if ( mAlarms ) {
393 mAlarms->clear();
394 for ( int i = 0; i < mWidget.mAlarmList->topLevelItemCount(); ++i ) {
395 AlarmListViewItem *item =
396 dynamic_cast< AlarmListViewItem *>( mWidget.mAlarmList->topLevelItem( i ) );
397 if ( item ) {
398 mAlarms->append( new Alarm( *( item->alarm() ) ) );
404 void KOEditorAlarms::slotOk()
406 slotApply();
407 accept();
410 void KOEditorAlarms::slotAdd()
412 mCurrentItem = new AlarmListViewItem( mWidget.mAlarmList, 0 );
413 mWidget.mAlarmList->setCurrentItem( mCurrentItem );
414 mWidget.mBeforeAfter->setCurrentIndex( 0 );
415 changed();
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 ) {
431 delete 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"