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 #include "koprefs.h"
00029 
00030 #include <libkcal/duration.h>
00031 
00032 #include <qlayout.h>
00033 #include <qlistview.h>
00034 #include <qpushbutton.h>
00035 #include <qspinbox.h>
00036 #include <qcombobox.h>
00037 #include <qcheckbox.h>
00038 #include <qbuttongroup.h>
00039 #include <qtextedit.h>
00040 #include <qwidgetstack.h>
00041 #include <qradiobutton.h>
00042 #include <qtooltip.h>
00043 #include <qwhatsthis.h>
00044 
00045 #include <kurlrequester.h>
00046 #include <klocale.h>
00047 #include <kdebug.h>
00048 
00049 #include <libkcal/alarm.h>
00050 #include <libkcal/incidence.h>
00051 
00052 #include <libemailfunctions/email.h>
00053 
00054 class AlarmListViewItem : public QListViewItem
00055 {
00056   public:
00057     AlarmListViewItem( QListView *parent, KCal::Alarm *alarm, const QCString &inctype );
00058     virtual ~AlarmListViewItem();
00059     KCal::Alarm *alarm() const { return mAlarm; }
00060     void construct();
00061     enum AlarmViewColumns { ColAlarmType=0, ColAlarmOffset, ColAlarmRepeat };
00062 
00063   protected:
00064     KCal::Alarm *mAlarm;
00065 
00066   private:
00067     QCString mIncType;
00068 };
00069 
00070 AlarmListViewItem::AlarmListViewItem( QListView *parent, KCal::Alarm *alarm,
00071                                       const QCString &inctype )
00072     : QListViewItem( parent ), mIncType( inctype )
00073 {
00074   if ( alarm ) {
00075     mAlarm = new KCal::Alarm( *alarm );
00076   } else {
00077     mAlarm = new KCal::Alarm( 0 );
00078     mAlarm->setType( KCal::Alarm::Display );
00079     int duration; // in secs
00080     switch( KOPrefs::instance()->mReminderTimeUnits ) {
00081     default:
00082     case 0: // mins
00083       duration = KOPrefs::instance()->mReminderTime * 60;
00084       break;
00085     case 1: // hours
00086       duration = KOPrefs::instance()->mReminderTime * 60 * 60;
00087       break;
00088     case 2: // days
00089       duration = KOPrefs::instance()->mReminderTime * 60 * 60 * 24;
00090       break;
00091     }
00092     if ( mIncType == "Event" ) {
00093       mAlarm->setStartOffset( KCal::Duration( -duration ) );
00094     } else {
00095       mAlarm->setEndOffset( KCal::Duration( -duration ) );
00096     }
00097   }
00098   construct();
00099 }
00100 
00101 AlarmListViewItem::~AlarmListViewItem()
00102 {
00103   delete mAlarm;
00104 }
00105 
00106 void AlarmListViewItem::construct()
00107 {
00108   if ( mAlarm ) {
00109     // Alarm type:
00110     QString type;
00111     switch ( mAlarm->type() ) {
00112       case KCal::Alarm::Display:
00113         type = i18n("Reminder Dialog");
00114         break;
00115       case KCal::Alarm::Procedure:
00116         type = i18n("Program");
00117         break;
00118       case KCal::Alarm::Email:
00119         type = i18n("Email");
00120         break;
00121       case KCal::Alarm::Audio:
00122         type = i18n("Audio");
00123         break;
00124       default:
00125         type = i18n("Unknown");
00126         break;
00127     }
00128     setText( ColAlarmType, type );
00129 
00130     // Alarm offset:
00131     QString offsetstr;
00132     int offset = 0;
00133     if ( mAlarm->hasStartOffset() ) {
00134       offset = mAlarm->startOffset().asSeconds();
00135       if ( offset <= 0 ) {
00136         offsetstr = i18n( "N days/hours/minutes before/after the start/end",
00137                           "%1 before the start" );
00138         offset = -offset;
00139       } else {
00140         offsetstr = i18n( "N days/hours/minutes before/after the start/end",
00141                           "%1 after the start" );
00142       }
00143     } else if ( mAlarm->hasEndOffset() ) {
00144       offset = mAlarm->endOffset().asSeconds();
00145       if ( offset <= 0 ) {
00146         if ( mIncType == "Todo" ) {
00147           offsetstr = i18n( "N days/hours/minutes before/after the due date",
00148                             "%1 before the to-do is due" );
00149         } else {
00150           offsetstr = i18n( "N days/hours/minutes before/after the start/end",
00151                             "%1 before the end" );
00152         }
00153         offset = -offset;
00154       } else {
00155         if ( mIncType == "Todo" ) {
00156           offsetstr = i18n( "N days/hours/minutes before/after the due date",
00157                             "%1 after the to-do is due" );
00158         } else {
00159           offsetstr = i18n( "N days/hours/minutes before/after the start/end",
00160                             "%1 after the end" );
00161         }
00162       }
00163     }
00164 
00165     offset = offset / 60; // make minutes
00166     int useoffset = offset;
00167 
00168     if ( offset % (24*60) == 0 && offset>0 ) { // divides evenly into days?
00169       useoffset = offset / (24*60);
00170       offsetstr = offsetstr.arg( i18n("1 day", "%n days", useoffset ) );
00171     } else if (offset % 60 == 0 && offset>0 ) { // divides evenly into hours?
00172       useoffset = offset / 60;
00173       offsetstr = offsetstr.arg( i18n("1 hour", "%n hours", useoffset ) );
00174     } else {
00175       useoffset = offset;
00176       offsetstr = offsetstr.arg( i18n("1 minute", "%n minutes", useoffset ) );
00177     }
00178     setText( ColAlarmOffset, offsetstr );
00179 
00180     // Alarm repeat
00181     if ( mAlarm->repeatCount()>0 ) {
00182       setText( ColAlarmRepeat, i18n("Yes") );
00183     } else {
00184       setText( ColAlarmRepeat, i18n("No") );
00185     }
00186   }
00187 }
00188 
00189 
00190 KOEditorAlarms::KOEditorAlarms( const QCString &type,
00191                                 KCal::Alarm::List *alarms, QWidget *parent,
00192                                 const char *name )
00193   : KDialogBase( parent, name, true, i18n("Advanced Reminders"), Ok | Cancel ),
00194     mType( type ), mAlarms( alarms ),mCurrentItem( 0 )
00195 {
00196   if ( mType != "Todo" ) {
00197     // only Todos and Events can have reminders
00198     mType = "Event";
00199   }
00200   setMainWidget( mWidget = new KOEditorAlarms_base( this ) );
00201 
00202   // The text is set here, and not in the UI file, because the i18n context is not
00203   // properly extracted from the UI file.
00204   mWidget->mAddButton->setText( i18n( "Add a new alarm to the alarm list.", "&Add" ) );
00205 
00206   mWidget->mAlarmList->setResizeMode( QListView::LastColumn );
00207   mWidget->mAlarmList->setColumnWidthMode( 0, QListView::Maximum );
00208   mWidget->mAlarmList->setColumnWidthMode( 1, QListView::Maximum );
00209   connect( mWidget->mAlarmList, SIGNAL( selectionChanged( QListViewItem * ) ),
00210            SLOT( selectionChanged( QListViewItem * ) ) );
00211   connect( mWidget->mAddButton, SIGNAL( clicked() ), SLOT( slotAdd() ) );
00212   connect( mWidget->mRemoveButton, SIGNAL( clicked() ), SLOT( slotRemove() ) );
00213   connect( mWidget->mDuplicateButton, SIGNAL( clicked() ), SLOT( slotDuplicate() ) );
00214 
00215   connect( mWidget->mAlarmOffset, SIGNAL( valueChanged( int ) ), SLOT( changed() ) );
00216   connect( mWidget->mOffsetUnit, SIGNAL( activated( int ) ), SLOT( changed() ) );
00217   connect( mWidget->mBeforeAfter, SIGNAL( activated( int ) ), SLOT( changed() ) );
00218   connect( mWidget->mRepeats, SIGNAL( toggled( bool ) ), SLOT( changed() ) );
00219   connect( mWidget->mRepeatCount, SIGNAL( valueChanged( int ) ), SLOT( changed() ) );
00220   connect( mWidget->mRepeatInterval, SIGNAL( valueChanged( int ) ), SLOT( changed() ) );
00221   connect( mWidget->mAlarmType, SIGNAL(clicked(int)), SLOT( changed() ) );
00222   connect( mWidget->mDisplayText, SIGNAL( textChanged() ), SLOT( changed() ) );
00223   connect( mWidget->mSoundFile, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) );
00224   connect( mWidget->mApplication, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) );
00225   connect( mWidget->mAppArguments, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) );
00226   connect( mWidget->mEmailAddress, SIGNAL( textChanged( const QString & ) ), SLOT( changed() ) );
00227   connect( mWidget->mEmailText, SIGNAL( textChanged() ), SLOT( changed() ) );
00228 
00229   init();
00230 
00231   //TODO: backport email reminders from trunk
00232   mWidget->mTypeEmailRadio->hide(); //email reminders not implemented yet
00233 
00234   mWidget->setMinimumSize( 500, 500 );
00235 }
00236 
00237 KOEditorAlarms::~KOEditorAlarms()
00238 {
00239 }
00240 
00241 void KOEditorAlarms::changed()
00242 {
00243   if ( !mInitializing && mCurrentItem ) {
00244     writeAlarm( mCurrentItem->alarm() );
00245     mCurrentItem->construct();
00246   }
00247 }
00248 
00249 void KOEditorAlarms::readAlarm( KCal::Alarm *alarm )
00250 {
00251   if ( !alarm ) return;
00252 
00253   mInitializing = true;
00254 
00255   // Offsets
00256   int offset;
00257   int beforeafterpos = 0;
00258   if ( mType == "Todo" ) {
00259     if ( !alarm->hasStartOffset() ) {
00260       beforeafterpos = 2;
00261     }
00262   }
00263   if ( alarm->hasEndOffset() ) {
00264     beforeafterpos = 2;
00265     offset = alarm->endOffset().asSeconds();
00266   } else {
00267     // TODO: Also allow alarms at fixed times, not relative to start/end
00268     offset = alarm->startOffset().asSeconds();
00269   }
00270   // Negative offset means before the start/end...
00271   if ( offset <= 0 ) {
00272     offset = -offset;
00273   } else {
00274     ++beforeafterpos;
00275   }
00276   mWidget->mBeforeAfter->setCurrentItem( beforeafterpos );
00277 
00278   offset = offset / 60; // make minutes
00279   int useoffset = offset;
00280 
00281   if ( offset % (24*60) == 0 && offset>0 ) { // divides evenly into days?
00282     useoffset = offset / (24*60);
00283     mWidget->mOffsetUnit->setCurrentItem( 2 );
00284   } else if (offset % 60 == 0 && offset>0 ) { // divides evenly into hours?
00285     useoffset = offset / 60;
00286     mWidget->mOffsetUnit->setCurrentItem( 1 );
00287   } else {
00288     useoffset = offset;
00289     mWidget->mOffsetUnit->setCurrentItem( 0 );
00290   }
00291   mWidget->mAlarmOffset->setValue( useoffset );
00292 
00293 
00294   // Repeating
00295   mWidget->mRepeats->setChecked( alarm->repeatCount()>0 );
00296   if ( alarm->repeatCount()>0 ) {
00297     mWidget->mRepeatCount->setValue( alarm->repeatCount() );
00298     mWidget->mRepeatInterval->setValue( alarm->snoozeTime().asSeconds() / 60 ); // show as minutes
00299   }
00300 
00301   switch ( alarm->type() ) {
00302     case KCal::Alarm::Audio:
00303         mWidget->mAlarmType->setButton( 1 );
00304         mWidget->mSoundFile->setURL( alarm->audioFile() );
00305         break;
00306     case KCal::Alarm::Procedure:
00307         mWidget->mAlarmType->setButton( 2 );
00308         mWidget->mApplication->setURL( alarm->programFile() );
00309         mWidget->mAppArguments->setText( alarm->programArguments() );
00310         break;
00311     case KCal::Alarm::Email: {
00312         mWidget->mAlarmType->setButton( 3 );
00313         QValueList<KCal::Person> addresses = alarm->mailAddresses();
00314         QStringList add;
00315         for ( QValueList<KCal::Person>::ConstIterator it = addresses.begin();
00316               it != addresses.end(); ++it ) {
00317           add << (*it).fullName();
00318         }
00319         mWidget->mEmailAddress->setText( add.join(", ") );
00320         mWidget->mEmailText->setText( alarm->mailText() );
00321         break;}
00322     case KCal::Alarm::Display:
00323     case KCal::Alarm::Invalid:
00324     default:
00325         mWidget->mAlarmType->setButton( 0 );
00326         mWidget->mDisplayText->setText( alarm->text() );
00327         break;
00328   }
00329 
00330   mWidget->mTypeStack->raiseWidget( mWidget->mAlarmType->selectedId() );
00331 
00332   mInitializing = false;
00333 }
00334 
00335 void KOEditorAlarms::writeAlarm( KCal::Alarm *alarm )
00336 {
00337   // Offsets
00338   int offset = mWidget->mAlarmOffset->value()*60; // minutes
00339   int offsetunit = mWidget->mOffsetUnit->currentItem();
00340   if ( offsetunit >= 1 ) offset *= 60; // hours
00341   if ( offsetunit >= 2 ) offset *= 24; // days
00342   if ( offsetunit >= 3 ) offset *= 7; // weeks
00343 
00344   int beforeafterpos = mWidget->mBeforeAfter->currentItem();
00345   if ( beforeafterpos % 2 == 0 ) { // before -> negative
00346     offset = -offset;
00347   }
00348 
00349   // TODO: Add possibility to specify a given time for the reminder
00350   if ( beforeafterpos / 2 == 0 ) { // start offset
00351     alarm->setStartOffset( KCal::Duration( offset ) );
00352   } else {
00353     alarm->setEndOffset( KCal::Duration( offset ) );
00354   }
00355 
00356   // Repeating
00357   if ( mWidget->mRepeats->isChecked() ) {
00358     alarm->setRepeatCount( mWidget->mRepeatCount->value() );
00359     alarm->setSnoozeTime( KCal::Duration( mWidget->mRepeatInterval->value() * 60 ) ); // convert back to seconds
00360   } else {
00361     alarm->setRepeatCount( 0 );
00362   }
00363 
00364   switch ( mWidget->mAlarmType->selectedId() ) {
00365     case 1: // Audio
00366         alarm->setAudioAlarm( mWidget->mSoundFile->url() );
00367         break;
00368     case 2: // Procedure
00369         alarm->setProcedureAlarm( mWidget->mApplication->url(), mWidget->mAppArguments->text() );
00370         break;
00371     case 3: { // Email
00372         QStringList addresses = KPIM::splitEmailAddrList( mWidget->mEmailAddress->text() );
00373         QValueList<KCal::Person> add;
00374         for ( QStringList::Iterator it = addresses.begin(); it != addresses.end();
00375               ++it ) {
00376           add << KCal::Person( *it );
00377         }
00378         // TODO: Add a subject line and possibilities for attachments
00379         alarm->setEmailAlarm( QString::null, mWidget->mEmailText->text(),
00380                               add );
00381         break; }
00382     case 0: // Display
00383     default:
00384         alarm->setDisplayAlarm( mWidget->mDisplayText->text() );
00385         break;
00386   }
00387 }
00388 
00389 void KOEditorAlarms::selectionChanged( QListViewItem *listviewitem )
00390 {
00391   AlarmListViewItem *item = dynamic_cast<AlarmListViewItem*>(listviewitem);
00392   mCurrentItem = item;
00393   mWidget->mTimeGroup->setEnabled( item );
00394   mWidget->mTypeGroup->setEnabled( item );
00395   if ( item ) {
00396     readAlarm( item->alarm() );
00397   }
00398 }
00399 
00400 void KOEditorAlarms::slotOk()
00401 {
00402   // save the current item settings, if any
00403   changed();
00404 
00405   // copy the mAlarms list
00406   if ( mAlarms ) {
00407     mAlarms->clear();
00408     QListViewItemIterator it( mWidget->mAlarmList );
00409     while ( it.current() ) {
00410       AlarmListViewItem *item = dynamic_cast<AlarmListViewItem*>(*it);
00411       if ( item ) {
00412         mAlarms->append( new KCal::Alarm( *(item->alarm()) ) );
00413       }
00414       ++it;
00415     }
00416   }
00417   accept();
00418 }
00419 
00420 void KOEditorAlarms::slotAdd()
00421 {
00422   mCurrentItem = new AlarmListViewItem( mWidget->mAlarmList, 0, mType );
00423   mWidget->mAlarmList->setCurrentItem( mCurrentItem );
00424 }
00425 
00426 void KOEditorAlarms::slotDuplicate()
00427 {
00428   if ( mCurrentItem ) {
00429     mCurrentItem = new AlarmListViewItem( mWidget->mAlarmList, mCurrentItem->alarm(), mType );
00430     mWidget->mAlarmList->setCurrentItem( mCurrentItem );
00431   }
00432 }
00433 
00434 void KOEditorAlarms::slotRemove()
00435 {
00436   if ( mCurrentItem ) {
00437     delete mCurrentItem;
00438     mCurrentItem = dynamic_cast<AlarmListViewItem*>( mWidget->mAlarmList->currentItem() );
00439     mWidget->mAlarmList->setSelected( mCurrentItem, true );
00440   }
00441 }
00442 
00443 void KOEditorAlarms::init()
00444 {
00445   mInitializing = true;
00446 
00447   // Tweak some UI stuff depending on the Incidence type
00448   if ( mType == "Todo" ) {
00449     // Replace before/after end datetime with before/after due datetime
00450     mWidget->mBeforeAfter->clear();
00451     mWidget->mBeforeAfter->insertItem( i18n( "before the to-do starts" ), 0 );
00452     mWidget->mBeforeAfter->insertItem( i18n( "after the to-do starts" ), 1 );
00453     mWidget->mBeforeAfter->insertItem( i18n( "before the to-do is due" ), 2 );
00454     mWidget->mBeforeAfter->insertItem( i18n( "after the to-do is due" ), 3 );
00455     QToolTip::add(
00456       mWidget->mBeforeAfter,
00457       i18n( "Select the reminder trigger relative to the start or due time" ) );
00458     QWhatsThis::add(
00459       mWidget->mBeforeAfter,
00460       i18n( "Use this combobox to specify if you want the reminder to "
00461             "trigger before or after the start or due time." ) );
00462 
00463     mWidget->mBeforeAfter->setCurrentItem( 2 );  // default is before due start
00464   }
00465 
00466   // Fill-in existing alarms
00467   KCal::Alarm::List::ConstIterator it;
00468   for ( it = mAlarms->begin(); it != mAlarms->end(); ++it ) {
00469     new AlarmListViewItem( mWidget->mAlarmList, *it, mType );
00470   }
00471   mWidget->mAlarmList->setSelected( mWidget->mAlarmList->firstChild(), true );
00472   mInitializing = false;
00473 }
00474 
00475 #include "koeditoralarms.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys