korganizer

koeditoralarms.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
00005     Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020 
00021     As a special exception, permission is given to link this program
00022     with any edition of Qt, and distribute the resulting executable,
00023     without including the source code for Qt in the source distribution.
00024 */
00025 
00026 #include "koeditoralarms_base.h"
00027 #include "koeditoralarms.h"
00028 
00029 #include <qlayout.h>
00030 #include <qlistview.h>
00031 #include <qpushbutton.h>
00032 #include <qspinbox.h>
00033 #include <qcombobox.h>
00034 #include <qcheckbox.h>
00035 #include <qbuttongroup.h>
00036 #include <qtextedit.h>
00037 #include <qwidgetstack.h>
00038 #include <qradiobutton.h>
00039 #include <qtooltip.h>
00040 #include <qwhatsthis.h>
00041 
00042 #include <kurlrequester.h>
00043 #include <klocale.h>
00044 #include <kdebug.h>
00045 
00046 #include <libkcal/alarm.h>
00047 #include <libkcal/incidence.h>
00048 
00049 #include <libemailfunctions/email.h>
00050 
00051 class AlarmListViewItem : public QListViewItem
00052 {
00053   public:
00054     AlarmListViewItem( QListView *parent, KCal::Alarm *alarm );
00055     virtual ~AlarmListViewItem();
00056     KCal::Alarm *alarm() const { return mAlarm; }
00057     void construct();
00058     enum AlarmViewColumns { ColAlarmType=0, ColAlarmOffset, ColAlarmRepeat };
00059   protected:
00060     KCal::Alarm *mAlarm;
00061 };
00062 
00063 AlarmListViewItem::AlarmListViewItem( QListView *parent, KCal::Alarm *alarm )
00064     : QListViewItem( parent )
00065 {
00066   if ( alarm ) {
00067     mAlarm = new KCal::Alarm( *alarm );
00068   } else {
00069     mAlarm = new KCal::Alarm( 0 );
00070   }
00071   construct();
00072 }
00073 
00074 AlarmListViewItem::~AlarmListViewItem()
00075 {
00076   delete mAlarm;
00077 }
00078 
00079 void AlarmListViewItem::construct()
00080 {
00081   if ( mAlarm ) {
00082     // Alarm type:
00083     QString type;
00084     switch ( mAlarm->type() ) {
00085       case KCal::Alarm::Display:
00086         type = i18n("Reminder Dialog");
00087         break;
00088       case KCal::Alarm::Procedure:
00089         type = i18n("Program");
00090         break;
00091       case KCal::Alarm::Email:
00092         type = i18n("Email");
00093         break;
00094       case KCal::Alarm::Audio:
00095         type = i18n("Audio");
00096         break;
00097       default:
00098         type = i18n("Unknown");
00099         break;
00100     }
00101     setText( ColAlarmType, type );
00102 
00103     // Alarm offset:
00104     QString offsetstr;
00105     int offset = 0;
00106     if ( mAlarm->hasStartOffset() ) {
00107       offset = mAlarm->startOffset().asSeconds();
00108       if ( offset < 0 ) {
00109         offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 before the start");
00110         offset = -offset;
00111       } else {
00112         offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 after the start");
00113       }
00114     } else if ( mAlarm->hasEndOffset() ) {
00115       offset = mAlarm->endOffset().asSeconds();
00116       if ( offset < 0 ) {
00117         offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 before the end");
00118         offset = -offset;
00119       } else {
00120         offsetstr = i18n("N days/hours/minutes before/after the start/end", "%1 after the end");
00121       }
00122     }
00123 
00124     offset = offset / 60; // make minutes
00125     int useoffset = offset;
00126 
00127     if ( offset % (24*60) == 0 && offset>0 ) { // divides evenly into days?
00128       useoffset = offset / (24*60);
00129       offsetstr = offsetstr.arg( i18n("1 day", "%n days", useoffset ) );
00130     } else if (offset % 60 == 0 && offset>0 ) { // divides evenly into hours?
00131       useoffset = offset / 60;
00132       offsetstr = offsetstr.arg( i18n("1 hour", "%n hours", useoffset ) );
00133     } else {
00134       useoffset = offset;
00135       offsetstr = offsetstr.arg( i18n("1 minute", "%n minutes", useoffset ) );
00136     }
00137     setText( ColAlarmOffset, offsetstr );
00138 
00139     // Alarm repeat
00140     if ( mAlarm->repeatCount()>0 ) {
00141       setText( ColAlarmRepeat, i18n("Yes") );
00142     } else {
00143       setText( ColAlarmRepeat, i18n("No") );
00144     }
00145   }
00146 }
00147 
00148 
00149 KOEditorAlarms::KOEditorAlarms( const QCString &type,
00150                                 KCal::Alarm::List *alarms, QWidget *parent,
00151                                 const char *name )
00152   : KDialogBase( parent, name, true, i18n("Edit Reminders"), Ok | Cancel ),
00153     mType( type ), mAlarms( alarms ),mCurrentItem(0L)
00154 {
00155   if ( mType != "Todo" ) {
00156     // only Todos and Events can have reminders
00157     mType = "Event";
00158   }
00159   setMainWidget( mWidget = new KOEditorAlarms_base( this ) );
00160   mWidget->mAlarmList->setColumnWidthMode( 0, QListView::Maximum );
00161   mWidget->mAlarmList->setColumnWidthMode( 1, QListView::Maximum );
00162   connect( mWidget->mAlarmList, SIGNAL( selectionChanged( QListViewItem * ) ),
00163            SLOT( selectionChanged( QListViewItem * ) ) );
00164   connect( mWidget->mAddButton, SIGNAL( clicked() ), SLOT( slotAdd() ) );
00165   connect( mWidget->mRemoveButton, SIGNAL( clicked() ), SLOT( slotRemove() ) );
00166   connect( mWidget->mDuplicateButton, SIGNAL( clicked() ), SLOT( slotDuplicate() ) );
00167 
00168   connect( mWidget->mAlarmOffset, SIGNAL( valueChanged( int ) ), SLOT( changed() ) );
00169   connect( mWidget->mOffsetUnit, SIGNAL( activated( int ) ), SLOT( changed() ) );
00170   connect( mWidget->mBeforeAfter, SIGNAL( activated( int ) ), SLOT( changed() ) );
00171   connect( mWidget->mRepeats, SIGNAL( toggled( bool ) ), SLOT( changed() ) );
00172   connect( mWidget->mRepeatCount, SIGNAL( valueChanged( int ) ), SLOT( changed() ) );
00173   connect( mWidget->mRepeatInterval, SIGNAL( valueChanged( int ) ), SLOT( changed() ) );
00174   connect( mWidget->mAlarmType, SIGNAL(clicked(int)), SLOT( changed() ) );
00175   connect( mWidget->mDisplayText, SIGNAL( textChanged() ), SLOT( changed() ) );
00176   connect( mWidget->mSoundFile, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) );
00177   connect( mWidget->mApplication, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) );
00178   connect( mWidget->mAppArguments, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) );
00179   connect( mWidget->mEmailAddress, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) );
00180   connect( mWidget->mEmailText, SIGNAL( textChanged() ), SLOT( changed() ) );
00181 
00182   init();
00183   mWidget->mTypeEmailRadio->hide();
00184 }
00185 
00186 KOEditorAlarms::~KOEditorAlarms()
00187 {
00188 }
00189 
00190 void KOEditorAlarms::changed()
00191 {
00192   if ( !mInitializing && mCurrentItem ) {
00193     writeAlarm( mCurrentItem->alarm() );
00194     mCurrentItem->construct();
00195   }
00196 }
00197 
00198 void KOEditorAlarms::readAlarm( KCal::Alarm *alarm )
00199 {
00200   if ( !alarm ) return;
00201 
00202   mInitializing = true;
00203 
00204   // Offsets
00205   int offset;
00206   int beforeafterpos = 0;
00207   if ( alarm->hasEndOffset() ) {
00208     beforeafterpos = 2;
00209     offset = alarm->endOffset().asSeconds();
00210   } else {
00211     // TODO: Also allow alarms at fixed times, not relative to start/end
00212     offset = alarm->startOffset().asSeconds();
00213   }
00214   // Negative offset means before the start/end...
00215   if ( offset < 0 ) {
00216     offset = -offset;
00217   } else {
00218     ++beforeafterpos;
00219   }
00220   mWidget->mBeforeAfter->setCurrentItem( beforeafterpos );
00221 
00222   offset = offset / 60; // make minutes
00223   int useoffset = offset;
00224 
00225   if ( offset % (24*60) == 0 && offset>0 ) { // divides evenly into days?
00226     useoffset = offset / (24*60);
00227     mWidget->mOffsetUnit->setCurrentItem( 2 );
00228   } else if (offset % 60 == 0 && offset>0 ) { // divides evenly into hours?
00229     useoffset = offset / 60;
00230     mWidget->mOffsetUnit->setCurrentItem( 1 );
00231   } else {
00232     useoffset = offset;
00233     mWidget->mOffsetUnit->setCurrentItem( 0 );
00234   }
00235   mWidget->mAlarmOffset->setValue( useoffset );
00236 
00237 
00238   // Repeating
00239   mWidget->mRepeats->setChecked( alarm->repeatCount()>0 );
00240   if ( alarm->repeatCount()>0 ) {
00241     mWidget->mRepeatCount->setValue( alarm->repeatCount() );
00242     mWidget->mRepeatInterval->setValue( alarm->snoozeTime() );
00243   }
00244 
00245   switch ( alarm->type() ) {
00246     case KCal::Alarm::Audio:
00247         mWidget->mAlarmType->setButton( 1 );
00248         mWidget->mSoundFile->setURL( alarm->audioFile() );
00249         break;
00250     case KCal::Alarm::Procedure:
00251         mWidget->mAlarmType->setButton( 2 );
00252         mWidget->mApplication->setURL( alarm->programFile() );
00253         mWidget->mAppArguments->setText( alarm->programArguments() );
00254         break;
00255     case KCal::Alarm::Email: {
00256         mWidget->mAlarmType->setButton( 3 );
00257         QValueList<KCal::Person> addresses = alarm->mailAddresses();
00258         QStringList add;
00259         for ( QValueList<KCal::Person>::ConstIterator it = addresses.begin();
00260               it != addresses.end(); ++it ) {
00261           add << (*it).fullName();
00262         }
00263         mWidget->mEmailAddress->setText( add.join(", ") );
00264         mWidget->mEmailText->setText( alarm->mailText() );
00265         break;}
00266     case KCal::Alarm::Display:
00267     case KCal::Alarm::Invalid:
00268     default:
00269         mWidget->mAlarmType->setButton( 0 );
00270         mWidget->mDisplayText->setText( alarm->text() );
00271         break;
00272   }
00273 
00274   mWidget->mTypeStack->raiseWidget( mWidget->mAlarmType->selectedId() );
00275 
00276   mInitializing = false;
00277 }
00278 
00279 void KOEditorAlarms::writeAlarm( KCal::Alarm *alarm )
00280 {
00281   // Offsets
00282   int offset = mWidget->mAlarmOffset->value()*60; // minutes
00283   int offsetunit = mWidget->mOffsetUnit->currentItem();
00284   if ( offsetunit >= 1 ) offset *= 60; // hours
00285   if ( offsetunit >= 2 ) offset *= 24; // days
00286   if ( offsetunit >= 3 ) offset *= 7; // weeks
00287 
00288   int beforeafterpos = mWidget->mBeforeAfter->currentItem();
00289   if ( beforeafterpos % 2 == 0 ) { // before -> negative
00290     offset = -offset;
00291   }
00292 
00293   // TODO: Add possibility to specify a given time for the reminder
00294   if ( beforeafterpos / 2 == 0 ) { // start offset
00295     alarm->setStartOffset( KCal::Duration( offset ) );
00296   } else {
00297     alarm->setEndOffset( KCal::Duration( offset ) );
00298   }
00299 
00300   // Repeating
00301   if ( mWidget->mRepeats->isChecked() ) {
00302     alarm->setRepeatCount( mWidget->mRepeatCount->value() );
00303     alarm->setSnoozeTime( mWidget->mRepeatInterval->value() );
00304   } else {
00305     alarm->setRepeatCount( 0 );
00306   }
00307 
00308   switch ( mWidget->mAlarmType->selectedId() ) {
00309     case 1: // Audio
00310         alarm->setAudioAlarm( mWidget->mSoundFile->url() );
00311         break;
00312     case 2: // Procedure
00313         alarm->setProcedureAlarm( mWidget->mApplication->url(), mWidget->mAppArguments->text() );
00314         break;
00315     case 3: { // Email
00316         QStringList addresses = KPIM::splitEmailAddrList( mWidget->mEmailAddress->text() );
00317         QValueList<KCal::Person> add;
00318         for ( QStringList::Iterator it = addresses.begin(); it != addresses.end();
00319               ++it ) {
00320           add << KCal::Person( *it );
00321         }
00322         // TODO: Add a subject line and possibilities for attachments
00323         alarm->setEmailAlarm( QString::null, mWidget->mEmailText->text(),
00324                               add );
00325         break; }
00326     case 0: // Display
00327     default:
00328         alarm->setDisplayAlarm( mWidget->mDisplayText->text() );
00329         break;
00330   }
00331 }
00332 
00333 void KOEditorAlarms::selectionChanged( QListViewItem *listviewitem )
00334 {
00335   AlarmListViewItem *item = dynamic_cast<AlarmListViewItem*>(listviewitem);
00336   mCurrentItem = item;
00337   mWidget->mTimeGroup->setEnabled( item );
00338   mWidget->mTypeGroup->setEnabled( item );
00339   if ( item ) {
00340     readAlarm( item->alarm() );
00341   }
00342 }
00343 
00344 void KOEditorAlarms::slotOk()
00345 {
00346   // copy the mAlarms list
00347   if ( mAlarms ) {
00348     mAlarms->clear();
00349     QListViewItemIterator it( mWidget->mAlarmList );
00350     while ( it.current() ) {
00351       AlarmListViewItem *item = dynamic_cast<AlarmListViewItem*>(*it);
00352       if ( item ) {
00353         mAlarms->append( new KCal::Alarm( *(item->alarm()) ) );
00354       }
00355       ++it;
00356     }
00357   }
00358   accept();
00359 }
00360 
00361 void KOEditorAlarms::slotAdd()
00362 {
00363   mCurrentItem = new AlarmListViewItem( mWidget->mAlarmList, 0 );
00364   mWidget->mAlarmList->setCurrentItem( mCurrentItem );
00365 //   selectionChanged( mCurrentItem );
00366 }
00367 
00368 void KOEditorAlarms::slotDuplicate()
00369 {
00370   if ( mCurrentItem ) {
00371     mCurrentItem = new AlarmListViewItem( mWidget->mAlarmList, mCurrentItem->alarm() );
00372     mWidget->mAlarmList->setCurrentItem( mCurrentItem );
00373 //     selectionChanged( mCurrentItem );
00374   }
00375 }
00376 
00377 void KOEditorAlarms::slotRemove()
00378 {
00379   if ( mCurrentItem ) {
00380     delete mCurrentItem;
00381     mCurrentItem = dynamic_cast<AlarmListViewItem*>( mWidget->mAlarmList->currentItem() );
00382     mWidget->mAlarmList->setSelected( mCurrentItem, true );
00383 
00384   }
00385 }
00386 
00387 void KOEditorAlarms::init()
00388 {
00389   mInitializing = true;
00390 
00391   // Tweak some UI stuff depending on the Incidence type
00392   if ( mType == "Todo" ) {
00393     // Replace before/after end datetime with before/after due datetime
00394     mWidget->mBeforeAfter->clear();
00395     mWidget->mBeforeAfter->insertItem( i18n( "before the to-do starts" ), 0 );
00396     mWidget->mBeforeAfter->insertItem( i18n( "after the to-do starts" ), 1 );
00397     mWidget->mBeforeAfter->insertItem( i18n( "before the to-do is due" ), 2 );
00398     mWidget->mBeforeAfter->insertItem( i18n( "after the to-do is due" ), 3 );
00399     QToolTip::add(
00400       mWidget->mBeforeAfter,
00401       i18n( "Select the reminder trigger relative to the start or due time" ) );
00402     QWhatsThis::add(
00403       mWidget->mBeforeAfter,
00404       i18n( "Use this combobox to specify if you want the reminder to "
00405             "trigger before or after the start or due time." ) );
00406   }
00407 
00408   // Fill-in existing alarms
00409   KCal::Alarm::List::ConstIterator it;
00410   for ( it = mAlarms->begin(); it != mAlarms->end(); ++it ) {
00411     new AlarmListViewItem( mWidget->mAlarmList, *it );
00412   }
00413   mWidget->mAlarmList->setSelected( mWidget->mAlarmList->firstChild(), true );
00414   mInitializing = false;
00415 }
00416 
00417 #include "koeditoralarms.moc"