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