korganizer

alarmdialog.cpp

00001 /*
00002     This file is part of the KOrganizer alarm daemon.
00003 
00004     Copyright (c) 2000,2003 Cornelius Schumacher <schumacher@kde.org>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include <qhbox.h>
00026 #include <qvbox.h>
00027 #include <qlabel.h>
00028 #include <qfile.h>
00029 #include <qspinbox.h>
00030 #include <qlayout.h>
00031 #include <qpushbutton.h>
00032 #include <qcstring.h>
00033 #include <qdatastream.h>
00034 
00035 #include <kapplication.h>
00036 #include <kconfig.h>
00037 #include <kiconloader.h>
00038 #include <dcopclient.h>
00039 #include <klocale.h>
00040 #include <kprocess.h>
00041 #include <kaudioplayer.h>
00042 #include <kdebug.h>
00043 #include <kmessagebox.h>
00044 #include <knotifyclient.h>
00045 #include <kcombobox.h>
00046 #include <klistview.h>
00047 #include <kwin.h>
00048 #include <klockfile.h>
00049 
00050 #include <libkcal/event.h>
00051 
00052 #include "koeventviewer.h"
00053 
00054 #include "alarmdialog.h"
00055 #include "alarmdialog.moc"
00056 
00057 class AlarmListItem : public KListViewItem
00058 {
00059   public:
00060     AlarmListItem( Incidence *incidence, QListView *parent ) :
00061       KListViewItem( parent ),
00062       mIncidence( incidence->clone() ),
00063       mNotified( false )
00064     {}
00065 
00066     ~AlarmListItem()
00067     {
00068       delete mIncidence;
00069     }
00070 
00071     Incidence *mIncidence;
00072     QDateTime mRemindAt;
00073     bool mNotified;
00074 };
00075 
00076 typedef QValueList<AlarmListItem*> ItemList;
00077 
00078 AlarmDialog::AlarmDialog( QWidget *parent, const char *name )
00079   : KDialogBase( Plain, WType_TopLevel | WStyle_Customize | WStyle_StaysOnTop |
00080                  WStyle_DialogBorder,
00081                  parent, name, false, i18n("Reminder"), Ok | User1 | User2 | User3, User1/*3*/,
00082                  false, i18n("Dismiss all"), i18n("Edit..."), i18n("Suspend") ),
00083                  mSuspendTimer(this)
00084 {
00085   KGlobal::iconLoader()->addAppDir( "kdepim" );
00086   setButtonOK( i18n( "Dismiss" ) );
00087 
00088   QWidget *topBox = plainPage();
00089   QBoxLayout *topLayout = new QVBoxLayout( topBox );
00090   topLayout->setSpacing( spacingHint() );
00091 
00092   QLabel *label = new QLabel( i18n("The following events triggered reminders:"),
00093                               topBox );
00094   topLayout->addWidget( label );
00095 
00096   mIncidenceListView = new KListView( topBox );
00097   mIncidenceListView->addColumn( i18n( "Summary" ) );
00098   mIncidenceListView->addColumn( i18n( "Due" ) );
00099   mIncidenceListView->setAllColumnsShowFocus( true );
00100   mIncidenceListView->setSelectionMode( QListView::Extended );
00101   topLayout->addWidget( mIncidenceListView );
00102   connect( mIncidenceListView, SIGNAL(selectionChanged()), SLOT(updateButtons()) );
00103   connect( mIncidenceListView, SIGNAL(doubleClicked(QListViewItem*)), SLOT(slotUser2()) );
00104   connect( mIncidenceListView, SIGNAL(currentChanged(QListViewItem*)), SLOT(showDetails()) );
00105   connect( mIncidenceListView, SIGNAL(selectionChanged()), SLOT(showDetails()) );
00106 
00107   mDetailView = new KOEventViewer( topBox );
00108   topLayout->addWidget( mDetailView );
00109 
00110   QHBox *suspendBox = new QHBox( topBox );
00111   suspendBox->setSpacing( spacingHint() );
00112   topLayout->addWidget( suspendBox );
00113 
00114   QLabel *l = new QLabel( i18n("Suspend &duration:"), suspendBox );
00115   mSuspendSpin = new QSpinBox( 1, 9999, 1, suspendBox );
00116   mSuspendSpin->setValue( 5 );  // default suspend duration
00117   l->setBuddy( mSuspendSpin );
00118 
00119   mSuspendUnit = new KComboBox( suspendBox );
00120   mSuspendUnit->insertItem( i18n("minute(s)") );
00121   mSuspendUnit->insertItem( i18n("hour(s)") );
00122   mSuspendUnit->insertItem( i18n("day(s)") );
00123   mSuspendUnit->insertItem( i18n("week(s)") );
00124   connect( &mSuspendTimer, SIGNAL(timeout()), SLOT(wakeUp()) );
00125 
00126   // showButton( User2/*3*/, false );
00127 
00128   setMinimumSize( 300, 200 );
00129 }
00130 
00131 AlarmDialog::~AlarmDialog()
00132 {
00133   mIncidenceListView->clear();
00134 }
00135 
00136 void AlarmDialog::addIncidence( Incidence *incidence, const QDateTime &reminderAt )
00137 {
00138   AlarmListItem *item = new AlarmListItem( incidence, mIncidenceListView );
00139   item->setText( 0, incidence->summary() );
00140   item->mRemindAt = reminderAt;
00141   Todo *todo;
00142   if ( dynamic_cast<Event*>( incidence ) ) {
00143     item->setPixmap( 0, SmallIcon( "appointment" ) );
00144     if ( incidence->doesRecur() ) {
00145       QDateTime nextStart = incidence->recurrence()->getNextDateTime( reminderAt );
00146       if ( nextStart.isValid() )
00147         item->setText( 1, KGlobal::locale()->formatDateTime( nextStart ) );
00148     }
00149     if ( item->text( 1 ).isEmpty() )
00150       item->setText( 1, incidence->dtStartStr() );
00151   } else if ( (todo = dynamic_cast<Todo*>( incidence )) ) {
00152     item->setPixmap( 0, SmallIcon( "todo" ) );
00153     item->setText( 1, todo->dtDueStr() );
00154   }
00155   if ( activeCount() == 1 ) {// previously empty
00156     mIncidenceListView->clearSelection();
00157     item->setSelected( true );
00158   }
00159   showDetails();
00160 }
00161 
00162 void AlarmDialog::slotOk()
00163 {
00164   ItemList selection = selectedItems();
00165   for ( ItemList::Iterator it = selection.begin(); it != selection.end(); ++it )
00166     delete *it;
00167   if ( activeCount() == 0 )
00168     accept();
00169   else {
00170     updateButtons();
00171     showDetails();
00172   }
00173   emit reminderCount( activeCount() );
00174 }
00175 
00176 void AlarmDialog::slotUser1()
00177 {
00178   dismissAll();
00179 }
00180 
00181 void AlarmDialog::suspend()
00182 {
00183   if ( !isVisible() )
00184     return;
00185 
00186   int unit=1;
00187   switch (mSuspendUnit->currentItem()) {
00188     case 3: // weeks
00189       unit *=  7;
00190     case 2: // days
00191       unit *= 24;
00192     case 1: // hours
00193       unit *= 60;
00194     case 0: // minutes
00195       unit *= 60;
00196     default:
00197       break;
00198   }
00199 
00200   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00201     AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00202     if ( item->isSelected() && item->isVisible() ) {
00203       item->setVisible( false );
00204       item->setSelected( false );
00205       item->mRemindAt = QDateTime::currentDateTime().addSecs( unit * mSuspendSpin->value() );
00206       item->mNotified = false;
00207     }
00208   }
00209 
00210   setTimer();
00211   if ( activeCount() == 0 )
00212     accept();
00213   else {
00214     updateButtons();
00215     showDetails();
00216   }
00217   emit reminderCount( activeCount() );
00218 }
00219 
00220 void AlarmDialog::setTimer()
00221 {
00222   int nextReminderAt = -1;
00223   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00224     AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00225     if ( item->mRemindAt > QDateTime::currentDateTime() ) {
00226       int secs = QDateTime::currentDateTime().secsTo( item->mRemindAt );
00227       nextReminderAt = nextReminderAt <= 0 ? secs : QMIN( nextReminderAt, secs );
00228     }
00229   }
00230 
00231   if ( nextReminderAt >= 0 ) {
00232     mSuspendTimer.stop();
00233     mSuspendTimer.start( 1000 * (nextReminderAt + 1), true );
00234   }
00235 }
00236 
00237 void AlarmDialog::slotUser2()
00238 {
00239   ItemList selection = selectedItems();
00240   if ( selection.count() != 1 )
00241     return;
00242   Incidence *incidence = selection.first()->mIncidence;
00243 
00244   if ( !kapp->dcopClient()->isApplicationRegistered( "korganizer" ) ) {
00245     if ( kapp->startServiceByDesktopName( "korganizer", QString::null ) )
00246       KMessageBox::error( 0, i18n("Could not start KOrganizer.") );
00247   }
00248 
00249   kapp->dcopClient()->send( "korganizer", "KOrganizerIface",
00250                             "editIncidence(QString)",
00251                              incidence->uid() );
00252 
00253   // get desktop # where korganizer (or kontact) runs
00254   QByteArray replyData;
00255   QCString object, replyType;
00256   object = kapp->dcopClient()->isApplicationRegistered( "kontact" ) ?
00257            "kontact-mainwindow#1" : "KOrganizer MainWindow";
00258   if (!kapp->dcopClient()->call( "korganizer", object,
00259                             "getWinID()", 0, replyType, replyData, true, -1 ) ) {
00260   }
00261 
00262   if ( replyType == "int" ) {
00263     int desktop, window;
00264     QDataStream ds( replyData, IO_ReadOnly );
00265     ds >> window;
00266     desktop = KWin::windowInfo( window ).desktop();
00267 
00268     if ( KWin::currentDesktop() == desktop ) {
00269       KWin::iconifyWindow( winId(), false );
00270     }
00271     else
00272       KWin::setCurrentDesktop( desktop );
00273 
00274     KWin::activateWindow( KWin::transientFor( window ) );
00275   }
00276 }
00277 
00278 void AlarmDialog::slotUser3()
00279 {
00280   suspend();
00281 }
00282 
00283 void AlarmDialog::dismissAll()
00284 {
00285   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00286     AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
00287     if ( !item->isVisible() )
00288       continue;
00289     delete item;
00290   }
00291   setTimer();
00292   accept();
00293   emit reminderCount( activeCount() );
00294 }
00295 
00296 void AlarmDialog::show()
00297 {
00298   KDialogBase::show();
00299   KWin::setState( winId(), NET::KeepAbove );
00300   KWin::setOnAllDesktops( winId(), true );
00301   eventNotification();
00302 }
00303 
00304 void AlarmDialog::eventNotification()
00305 {
00306   bool beeped = false, found = false;
00307 
00308   QValueList<AlarmListItem*> list;
00309   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00310     AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
00311     if ( !item->isVisible() || item->mNotified )
00312       continue;
00313     found = true;
00314     item->mNotified = true;
00315     Alarm::List alarms = item->mIncidence->alarms();
00316     Alarm::List::ConstIterator it;
00317     for ( it = alarms.begin(); it != alarms.end(); ++it ) {
00318       Alarm *alarm = *it;
00319       // FIXME: Check whether this should be done for all multiple alarms
00320       if (alarm->type() == Alarm::Procedure) {
00321         // FIXME: Add a message box asking whether the procedure should really be executed
00322         kdDebug(5890) << "Starting program: '" << alarm->programFile() << "'" << endl;
00323         KProcess proc;
00324         proc << QFile::encodeName(alarm->programFile());
00325         proc.start(KProcess::DontCare);
00326       }
00327       else if (alarm->type() == Alarm::Audio) {
00328         beeped = true;
00329         KAudioPlayer::play(QFile::encodeName(alarm->audioFile()));
00330       }
00331     }
00332   }
00333 
00334   if ( !beeped && found ) {
00335     KNotifyClient::beep();
00336   }
00337 }
00338 
00339 void AlarmDialog::wakeUp()
00340 {
00341   bool activeReminders = false;
00342   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00343     AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00344     if ( item->mRemindAt <= QDateTime::currentDateTime() ) {
00345       if ( !item->isVisible() ) {
00346         item->setVisible( true );
00347         item->setSelected( false );
00348       }
00349       activeReminders = true;
00350     } else {
00351       item->setVisible( false );
00352     }
00353   }
00354 
00355   if ( activeReminders )
00356     show();
00357   setTimer();
00358   showDetails();
00359   emit reminderCount( activeCount() );
00360 }
00361 
00362 void AlarmDialog::slotSave()
00363 {
00364   KConfig *config = kapp->config();
00365   KLockFile::Ptr lock = config->lockFile();
00366   if ( lock.data()->lock() != KLockFile::LockOK )
00367     return;
00368 
00369   config->setGroup( "General" );
00370   int numReminders = config->readNumEntry("Reminders", 0);
00371 
00372   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00373     AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00374     config->setGroup( QString("Incidence-%1").arg(numReminders) );
00375     config->writeEntry( "UID", item->mIncidence->uid() );
00376     config->writeEntry( "RemindAt", item->mRemindAt );
00377     ++numReminders;
00378   }
00379 
00380   config->setGroup( "General" );
00381   config->writeEntry( "Reminders", numReminders );
00382   config->sync();
00383   lock.data()->unlock();
00384 }
00385 
00386 void AlarmDialog::updateButtons()
00387 {
00388   ItemList selection = selectedItems();
00389   enableButton( User2, selection.count() == 1 );
00390   enableButton( Ok, selection.count() > 0 );
00391   enableButton( User3, selection.count() > 0 );
00392 }
00393 
00394 QValueList< AlarmListItem * > AlarmDialog::selectedItems() const
00395 {
00396   QValueList<AlarmListItem*> list;
00397   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00398     if ( it.current()->isSelected() )
00399       list.append( static_cast<AlarmListItem*>( it.current() ) );
00400   }
00401   return list;
00402 }
00403 
00404 int AlarmDialog::activeCount()
00405 {
00406   int count = 0;
00407   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00408     AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00409     if ( item->isVisible() )
00410       ++count;
00411   }
00412   return count;
00413 }
00414 
00415 void AlarmDialog::suspendAll()
00416 {
00417   mIncidenceListView->clearSelection();
00418   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00419     if ( it.current()->isVisible() )
00420       it.current()->setSelected( true );
00421   }
00422   suspend();
00423 }
00424 
00425 void AlarmDialog::showDetails()
00426 {
00427   mDetailView->clearEvents( true );
00428   mDetailView->clear();
00429   AlarmListItem *item = static_cast<AlarmListItem*>( mIncidenceListView->currentItem() );
00430   if ( !item || !item->isVisible() )
00431     return;
00432   mDetailView->appendIncidence( item->mIncidence );
00433 }
KDE Home | KDE Accessibility Home | Description of Access Keys