00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <qhbox.h>
00027 #include <qvbox.h>
00028 #include <qlabel.h>
00029 #include <qfile.h>
00030 #include <qspinbox.h>
00031 #include <qlayout.h>
00032 #include <qpushbutton.h>
00033 #include <qcstring.h>
00034 #include <qdatastream.h>
00035
00036 #include <kapplication.h>
00037 #include <kconfig.h>
00038 #include <kiconloader.h>
00039 #include <dcopclient.h>
00040 #include <klocale.h>
00041 #include <kprocess.h>
00042 #include <kaudioplayer.h>
00043 #include <kdebug.h>
00044 #include <kmessagebox.h>
00045 #include <knotifyclient.h>
00046 #include <kcombobox.h>
00047 #include <klistview.h>
00048 #include <kwin.h>
00049 #include <klockfile.h>
00050
00051 #include <libkcal/event.h>
00052 #include <libkcal/incidenceformatter.h>
00053
00054 #include "koeventviewer.h"
00055
00056 #include "alarmdialog.h"
00057 #include "alarmdialog.moc"
00058
00059 class AlarmListItem : public KListViewItem
00060 {
00061 public:
00062 AlarmListItem( Incidence *incidence, QListView *parent ) :
00063 KListViewItem( parent ),
00064 mIncidence( incidence->clone() ),
00065 mNotified( false )
00066 {}
00067
00068 ~AlarmListItem()
00069 {
00070 delete mIncidence;
00071 }
00072
00073 int compare( KListViewItem *item, int iCol, bool bAscending ) const;
00074
00075 Incidence *mIncidence;
00076 QDateTime mRemindAt;
00077 QDateTime mHappening;
00078 bool mNotified;
00079 };
00080
00081 int AlarmListItem::compare( KListViewItem *item, int iCol, bool bAscending ) const
00082 {
00083 if ( iCol == 1 ) {
00084 AlarmListItem *pItem = dynamic_cast<AlarmListItem *>( item );
00085 return mHappening < pItem->mHappening;
00086 } else {
00087 return KListViewItem::compare( item, iCol, bAscending );
00088 }
00089 }
00090
00091 typedef QValueList<AlarmListItem*> ItemList;
00092
00093 AlarmDialog::AlarmDialog( KCal::Calendar *calendar, QWidget *parent, const char *name )
00094 : KDialogBase( Plain, WType_TopLevel | WStyle_Customize | WStyle_StaysOnTop |
00095 WStyle_DialogBorder,
00096 parent, name, false, i18n("Reminder"),
00097 Ok | User1 | User2 | User3, NoDefault,
00098 false, i18n("Edit..."), i18n("Dismiss All"), i18n("Dismiss Reminder") ),
00099 mCalendar( calendar ), mSuspendTimer(this)
00100 {
00101
00102
00103
00104
00105
00106 KGlobal::iconLoader()->addAppDir( "kdepim" );
00107 setButtonOK( i18n( "Suspend" ) );
00108
00109 QWidget *topBox = plainPage();
00110 QBoxLayout *topLayout = new QVBoxLayout( topBox );
00111 topLayout->setSpacing( spacingHint() );
00112
00113 QLabel *label = new QLabel( i18n("The following events triggered reminders:"),
00114 topBox );
00115 topLayout->addWidget( label );
00116
00117 mIncidenceListView = new KListView( topBox );
00118 mIncidenceListView->addColumn( i18n( "Summary" ) );
00119 mIncidenceListView->addColumn( i18n( "Due" ) );
00120 mIncidenceListView->setSorting( 0, true );
00121 mIncidenceListView->setSorting( 1, true );
00122 mIncidenceListView->setSortColumn( 1 );
00123 mIncidenceListView->setShowSortIndicator( true );
00124 mIncidenceListView->setAllColumnsShowFocus( true );
00125 mIncidenceListView->setSelectionMode( QListView::Extended );
00126 topLayout->addWidget( mIncidenceListView );
00127 connect( mIncidenceListView, SIGNAL(selectionChanged()), SLOT(updateButtons()) );
00128 connect( mIncidenceListView, SIGNAL(doubleClicked(QListViewItem*)), SLOT(edit()) );
00129 connect( mIncidenceListView, SIGNAL(currentChanged(QListViewItem*)), SLOT(showDetails()) );
00130 connect( mIncidenceListView, SIGNAL(selectionChanged()), SLOT(showDetails()) );
00131
00132 mDetailView = new KOEventViewer( mCalendar, topBox );
00133 mDetailView->setFocus();
00134
00135 topLayout->addWidget( mDetailView );
00136
00137 QHBox *suspendBox = new QHBox( topBox );
00138 suspendBox->setSpacing( spacingHint() );
00139 topLayout->addWidget( suspendBox );
00140
00141 QLabel *l = new QLabel( i18n("Suspend &duration:"), suspendBox );
00142 mSuspendSpin = new QSpinBox( 1, 9999, 1, suspendBox );
00143 mSuspendSpin->setValue( 5 );
00144 l->setBuddy( mSuspendSpin );
00145
00146 mSuspendUnit = new KComboBox( suspendBox );
00147 mSuspendUnit->insertItem( i18n("minute(s)") );
00148 mSuspendUnit->insertItem( i18n("hour(s)") );
00149 mSuspendUnit->insertItem( i18n("day(s)") );
00150 mSuspendUnit->insertItem( i18n("week(s)") );
00151 connect( &mSuspendTimer, SIGNAL(timeout()), SLOT(wakeUp()) );
00152
00153 setMinimumSize( 300, 200 );
00154 }
00155
00156 AlarmDialog::~AlarmDialog()
00157 {
00158 mIncidenceListView->clear();
00159 }
00160
00161 void AlarmDialog::addIncidence( Incidence *incidence, const QDateTime &reminderAt )
00162 {
00163 AlarmListItem *item = new AlarmListItem( incidence, mIncidenceListView );
00164 item->setText( 0, incidence->summary() );
00165 item->mRemindAt = reminderAt;
00166 Todo *todo;
00167 if ( dynamic_cast<Event*>( incidence ) ) {
00168 item->setPixmap( 0, SmallIcon( "appointment" ) );
00169 if ( incidence->doesRecur() ) {
00170 QDateTime nextStart = incidence->recurrence()->getNextDateTime( reminderAt );
00171 if ( nextStart.isValid() ) {
00172 item->mHappening = nextStart;
00173 item->setText( 1, KGlobal::locale()->formatDateTime( nextStart ) );
00174 }
00175 }
00176 if ( item->text( 1 ).isEmpty() )
00177 item->mHappening = incidence->dtStart();
00178 item->setText( 1, IncidenceFormatter::dateTimeToString( incidence->dtStart(), false, true ) );
00179 } else if ( (todo = dynamic_cast<Todo*>( incidence )) ) {
00180 item->setPixmap( 0, SmallIcon( "todo" ) );
00181 item->mHappening = todo->dtDue();
00182 item->setText( 1, IncidenceFormatter::dateTimeToString( todo->dtDue(), false, true ) );
00183 }
00184 if ( activeCount() == 1 ) {
00185 mIncidenceListView->clearSelection();
00186 item->setSelected( true );
00187 }
00188 showDetails();
00189 }
00190
00191 void AlarmDialog::slotOk()
00192 {
00193 suspend();
00194 }
00195
00196 void AlarmDialog::slotUser1()
00197 {
00198 edit();
00199 }
00200
00201 void AlarmDialog::slotUser2()
00202 {
00203 dismissAll();
00204 }
00205
00206 void AlarmDialog::slotUser3()
00207 {
00208 dismissCurrent();
00209 }
00210
00211 void AlarmDialog::dismissCurrent()
00212 {
00213 ItemList selection = selectedItems();
00214 for ( ItemList::Iterator it = selection.begin(); it != selection.end(); ++it ) {
00215 if ( (*it)->itemBelow() )
00216 (*it)->itemBelow()->setSelected( true );
00217 else if ( (*it)->itemAbove() )
00218 (*it)->itemAbove()->setSelected( true );
00219 delete *it;
00220 }
00221 if ( activeCount() == 0 )
00222 accept();
00223 else {
00224 updateButtons();
00225 showDetails();
00226 }
00227 emit reminderCount( activeCount() );
00228 }
00229
00230 void AlarmDialog::dismissAll()
00231 {
00232 for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ) {
00233 AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
00234 if ( !item->isVisible() ) {
00235 ++it;
00236 continue;
00237 }
00238 delete item;
00239 }
00240 setTimer();
00241 accept();
00242 emit reminderCount( activeCount() );
00243 }
00244
00245 void AlarmDialog::edit()
00246 {
00247 ItemList selection = selectedItems();
00248 if ( selection.count() != 1 ) {
00249 return;
00250 }
00251 Incidence *incidence = selection.first()->mIncidence;
00252 if ( incidence->isReadOnly() ) {
00253 KMessageBox::sorry(
00254 this,
00255 i18n( "\"%1\" is a read-only item so modifications are not possible." ).
00256 arg( incidence->summary() ) );
00257 return;
00258 }
00259
00260 if ( !kapp->dcopClient()->isApplicationRegistered( "korganizer" ) ) {
00261 if ( kapp->startServiceByDesktopName( "korganizer", QString::null ) ) {
00262 KMessageBox::error(
00263 this,
00264 i18n( "Could not start KOrganizer so editing is not possible.") );
00265 return;
00266 }
00267 }
00268
00269 kdDebug(5890) << "editing incidence " << incidence->summary() << endl;
00270 if ( !kapp->dcopClient()->send( "korganizer", "KOrganizerIface",
00271 "editIncidence(QString)",
00272 incidence->uid() ) ) {
00273 KMessageBox::error(
00274 this,
00275 i18n( "An internal KOrganizer error occurred attempting to modify \"%1\"" ).
00276 arg( incidence->summary() ) );
00277 }
00278
00279
00280 QByteArray replyData;
00281 QCString object, replyType;
00282 object = kapp->dcopClient()->isApplicationRegistered( "kontact" ) ?
00283 "kontact-mainwindow#1" : "KOrganizer MainWindow";
00284 if (!kapp->dcopClient()->call( "korganizer", object,
00285 "getWinID()", 0, replyType, replyData, true, -1 ) ) {
00286 }
00287
00288 if ( replyType == "int" ) {
00289 int desktop, window;
00290 QDataStream ds( replyData, IO_ReadOnly );
00291 ds >> window;
00292 desktop = KWin::windowInfo( window ).desktop();
00293
00294 if ( KWin::currentDesktop() == desktop ) {
00295 KWin::iconifyWindow( winId(), false );
00296 } else {
00297 KWin::setCurrentDesktop( desktop );
00298 }
00299 KWin::activateWindow( KWin::transientFor( window ) );
00300 }
00301 }
00302
00303 void AlarmDialog::suspend()
00304 {
00305 if ( !isVisible() )
00306 return;
00307
00308 int unit=1;
00309 switch (mSuspendUnit->currentItem()) {
00310 case 3:
00311 unit *= 7;
00312 case 2:
00313 unit *= 24;
00314 case 1:
00315 unit *= 60;
00316 case 0:
00317 unit *= 60;
00318 default:
00319 break;
00320 }
00321
00322 for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00323 AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00324 if ( item->isSelected() && item->isVisible() ) {
00325 item->setVisible( false );
00326 item->setSelected( false );
00327 item->mRemindAt = QDateTime::currentDateTime().addSecs( unit * mSuspendSpin->value() );
00328 item->mNotified = false;
00329 }
00330 }
00331
00332 setTimer();
00333 if ( activeCount() == 0 )
00334 accept();
00335 else {
00336 updateButtons();
00337 showDetails();
00338 }
00339 emit reminderCount( activeCount() );
00340 }
00341
00342 void AlarmDialog::setTimer()
00343 {
00344 int nextReminderAt = -1;
00345 for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00346 AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00347 if ( item->mRemindAt > QDateTime::currentDateTime() ) {
00348 int secs = QDateTime::currentDateTime().secsTo( item->mRemindAt );
00349 nextReminderAt = nextReminderAt <= 0 ? secs : QMIN( nextReminderAt, secs );
00350 }
00351 }
00352
00353 if ( nextReminderAt >= 0 ) {
00354 mSuspendTimer.stop();
00355 mSuspendTimer.start( 1000 * (nextReminderAt + 1), true );
00356 }
00357 }
00358
00359 void AlarmDialog::show()
00360 {
00361 mIncidenceListView->sort();
00362
00363 mIncidenceListView->clearSelection();
00364 if ( mIncidenceListView->firstChild() )
00365 mIncidenceListView->firstChild()->setSelected( true );
00366
00367 updateButtons();
00368 showDetails();
00369
00370 KDialogBase::show();
00371 KWin::setState( winId(), NET::KeepAbove );
00372 KWin::setOnAllDesktops( winId(), true );
00373 eventNotification();
00374 }
00375
00376 void AlarmDialog::eventNotification()
00377 {
00378 bool beeped = false, found = false;
00379
00380 QValueList<AlarmListItem*> list;
00381 for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00382 AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
00383 if ( !item->isVisible() || item->mNotified )
00384 continue;
00385 found = true;
00386 item->mNotified = true;
00387 Alarm::List alarms = item->mIncidence->alarms();
00388 Alarm::List::ConstIterator it;
00389 for ( it = alarms.begin(); it != alarms.end(); ++it ) {
00390 Alarm *alarm = *it;
00391
00392 if (alarm->type() == Alarm::Procedure) {
00393
00394 kdDebug(5890) << "Starting program: '" << alarm->programFile() << "'" << endl;
00395 KProcess proc;
00396 proc << QFile::encodeName(alarm->programFile());
00397 proc.start(KProcess::DontCare);
00398 }
00399 else if (alarm->type() == Alarm::Audio) {
00400 beeped = true;
00401 KAudioPlayer::play(QFile::encodeName(alarm->audioFile()));
00402 }
00403 }
00404 }
00405
00406 if ( !beeped && found ) {
00407 KNotifyClient::beep();
00408 }
00409 }
00410
00411 void AlarmDialog::wakeUp()
00412 {
00413 bool activeReminders = false;
00414 for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00415 AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00416 if ( item->mRemindAt <= QDateTime::currentDateTime() ) {
00417 if ( !item->isVisible() ) {
00418 item->setVisible( true );
00419 item->setSelected( false );
00420 }
00421 activeReminders = true;
00422 } else {
00423 item->setVisible( false );
00424 }
00425 }
00426
00427 if ( activeReminders )
00428 show();
00429 setTimer();
00430 showDetails();
00431 emit reminderCount( activeCount() );
00432 }
00433
00434 void AlarmDialog::slotSave()
00435 {
00436 KConfig *config = kapp->config();
00437 KLockFile::Ptr lock = config->lockFile();
00438 if ( lock.data()->lock() != KLockFile::LockOK )
00439 return;
00440
00441 config->setGroup( "General" );
00442 int numReminders = config->readNumEntry("Reminders", 0);
00443
00444 for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00445 AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00446 config->setGroup( QString("Incidence-%1").arg(numReminders + 1) );
00447 config->writeEntry( "UID", item->mIncidence->uid() );
00448 config->writeEntry( "RemindAt", item->mRemindAt );
00449 ++numReminders;
00450 }
00451
00452 config->setGroup( "General" );
00453 config->writeEntry( "Reminders", numReminders );
00454 config->sync();
00455 lock.data()->unlock();
00456 }
00457
00458 void AlarmDialog::updateButtons()
00459 {
00460 ItemList selection = selectedItems();
00461 enableButton( User1, selection.count() == 1 );
00462 enableButton( User3, selection.count() > 0 );
00463 enableButton( Ok, selection.count() > 0 );
00464 }
00465
00466 QValueList< AlarmListItem * > AlarmDialog::selectedItems() const
00467 {
00468 QValueList<AlarmListItem*> list;
00469 for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00470 if ( it.current()->isSelected() )
00471 list.append( static_cast<AlarmListItem*>( it.current() ) );
00472 }
00473 return list;
00474 }
00475
00476 int AlarmDialog::activeCount()
00477 {
00478 int count = 0;
00479 for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00480 AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00481 if ( item->isVisible() )
00482 ++count;
00483 }
00484 return count;
00485 }
00486
00487 void AlarmDialog::suspendAll()
00488 {
00489 mIncidenceListView->clearSelection();
00490 for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00491 if ( it.current()->isVisible() )
00492 it.current()->setSelected( true );
00493 }
00494 suspend();
00495 }
00496
00497 void AlarmDialog::showDetails()
00498 {
00499 mDetailView->clearEvents( true );
00500 mDetailView->clear();
00501 AlarmListItem *item = static_cast<AlarmListItem*>( mIncidenceListView->currentItem() );
00502 if ( !item || !item->isVisible() )
00503 return;
00504 mDetailView->appendIncidence( item->mIncidence, item->mRemindAt.date() );
00505 }