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     Copyright (c) 2009-2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
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 <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 #include <qsplitter.h>
00036 #include <qvaluelist.h>
00037 
00038 #include <dcopclient.h>
00039 #include <dcopref.h>
00040 #include <kapplication.h>
00041 #include <kconfig.h>
00042 #include <kdcopservicestarter.h>
00043 #include <kiconloader.h>
00044 #include <klocale.h>
00045 #include <kprocess.h>
00046 #include <kaudioplayer.h>
00047 #include <kdebug.h>
00048 #include <kmessagebox.h>
00049 #include <knotifyclient.h>
00050 #include <kcombobox.h>
00051 #include <klistview.h>
00052 #include <kwin.h>
00053 #include <klockfile.h>
00054 
00055 #include <libkcal/event.h>
00056 #include <libkcal/incidenceformatter.h>
00057 
00058 #include "koeventviewer.h"
00059 
00060 #include "alarmdialog.h"
00061 #include "alarmdialog.moc"
00062 
00063 static int defSuspendVal = 5;
00064 static int defSuspendUnit = 0; // 0=>minutes, 1=>hours, 2=>days, 3=>weeks
00065 
00066 class AlarmListItem : public KListViewItem
00067 {
00068   public:
00069     AlarmListItem( const QString &uid, QListView *parent )
00070       : KListViewItem( parent ), mUid( uid ), mNotified( false )
00071     {
00072     }
00073 
00074     ~AlarmListItem()
00075     {
00076     }
00077 
00078     int compare( QListViewItem *item, int iCol, bool bAscending ) const;
00079 
00080     QString mDisplayText;
00081 
00082     QString mUid;
00083     QDateTime mRemindAt;
00084     QDateTime mHappening;
00085     bool mNotified;
00086 };
00087 
00088 int AlarmListItem::compare( QListViewItem *item, int iCol, bool bAscending ) const
00089 {
00090   if ( iCol == 1 ) {
00091     AlarmListItem *pItem = static_cast<AlarmListItem *>( item );
00092     return pItem->mHappening.secsTo( mHappening );
00093   } else {
00094     return KListViewItem::compare( item, iCol, bAscending );
00095   }
00096 }
00097 
00098 typedef QValueList<AlarmListItem*> ItemList;
00099 
00100 AlarmDialog::AlarmDialog( KCal::CalendarResources *calendar, QWidget *parent, const char *name )
00101   : KDialogBase( Plain,
00102                  WType_TopLevel | WStyle_Customize | WStyle_StaysOnTop | WStyle_DialogBorder,
00103                  parent, name, false, i18n("Reminder"),
00104                  Ok | User1 | User2 | User3, NoDefault,
00105                  false, i18n("Edit..."), i18n("Dismiss All"), i18n("Dismiss Reminder") ),
00106                  mCalendar( calendar ), mSuspendTimer(this)
00107 {
00108   // User1 => Edit...
00109   // User2 => Dismiss All
00110   // User3 => Dismiss Selected
00111   //    Ok => Suspend
00112 
00113   connect( calendar, SIGNAL(calendarChanged()),
00114            this, SLOT(slotCalendarChanged()) );
00115 
00116   KGlobal::iconLoader()->addAppDir( "kdepim" );
00117   setButtonOK( i18n( "Suspend" ) );
00118 
00119   QWidget *topBox = plainPage();
00120   QBoxLayout *topLayout = new QVBoxLayout( topBox );
00121   topLayout->setSpacing( spacingHint() );
00122 
00123   QLabel *label = new QLabel( i18n("The following items triggered reminders:"), topBox );
00124   topLayout->addWidget( label );
00125 
00126   mSplitter = new QSplitter( Qt::Vertical, topBox );
00127   mSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
00128   topLayout->addWidget( mSplitter );
00129 
00130   mIncidenceListView = new KListView( mSplitter );
00131   mIncidenceListView->addColumn( i18n( "Summary" ) );
00132   mIncidenceListView->addColumn( i18n( "Date, Time" ) );
00133   mIncidenceListView->setSorting( 0, true );
00134   mIncidenceListView->setSorting( 1, true );
00135   mIncidenceListView->setSortColumn( 1 );
00136   mIncidenceListView->setShowSortIndicator( true );
00137   mIncidenceListView->setAllColumnsShowFocus( true );
00138   mIncidenceListView->setSelectionMode( QListView::Extended );
00139   connect( mIncidenceListView, SIGNAL(selectionChanged()), SLOT(updateButtons()) );
00140   connect( mIncidenceListView, SIGNAL(doubleClicked(QListViewItem*)), SLOT(edit()) );
00141   connect( mIncidenceListView, SIGNAL(currentChanged(QListViewItem*)), SLOT(showDetails()) );
00142   connect( mIncidenceListView, SIGNAL(selectionChanged()), SLOT(showDetails()) );
00143 
00144   mDetailView = new KOEventViewer( mCalendar, mSplitter );
00145   mDetailView->setFocus(); // set focus here to start with to make it harder
00146                            // to hit return by mistake and dismiss a reminder.
00147 
00148   QHBox *suspendBox = new QHBox( topBox );
00149   suspendBox->setSpacing( spacingHint() );
00150   topLayout->addWidget( suspendBox );
00151 
00152   QLabel *l = new QLabel( i18n("Suspend &duration:"), suspendBox );
00153   mSuspendSpin = new QSpinBox( 1, 9999, 1, suspendBox );
00154   mSuspendSpin->setValue( defSuspendVal );  // default suspend duration
00155   l->setBuddy( mSuspendSpin );
00156 
00157   mSuspendUnit = new KComboBox( suspendBox );
00158   mSuspendUnit->insertItem( i18n("minute(s)") );
00159   mSuspendUnit->insertItem( i18n("hour(s)") );
00160   mSuspendUnit->insertItem( i18n("day(s)") );
00161   mSuspendUnit->insertItem( i18n("week(s)") );
00162   mSuspendUnit->setCurrentItem( defSuspendUnit );
00163 
00164   connect( &mSuspendTimer, SIGNAL(timeout()), SLOT(wakeUp()) );
00165 
00166   setMainWidget( mIncidenceListView );
00167   mIncidenceListView->setMinimumSize( 500, 50 );
00168 
00169   readLayout();
00170 }
00171 
00172 AlarmDialog::~AlarmDialog()
00173 {
00174   mIncidenceListView->clear();
00175 }
00176 
00177 AlarmListItem *AlarmDialog::searchByUid( const QString &uid )
00178 {
00179   AlarmListItem *found = 0;
00180   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ) {
00181     AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
00182     if ( item->mUid == uid ) {
00183       found = item;
00184       break;
00185     }
00186     ++it;
00187   }
00188   return found;
00189 }
00190 
00191 static QString etc = i18n( "elipsis", "..." );
00192 static QString cleanSummary( const QString &summary )
00193 {
00194   uint maxLen = 45;
00195   QString retStr = summary;
00196   retStr.replace( '\n', ' ' );
00197   if ( retStr.length() > maxLen ) {
00198     maxLen -= etc.length();
00199     retStr = retStr.left( maxLen );
00200     retStr += etc;
00201   }
00202   return retStr;
00203 }
00204 
00205 void AlarmDialog::readLayout()
00206 {
00207   KConfig *config = kapp->config();
00208   config->setGroup( "Layout" );
00209   QValueList<int> sizes = config->readIntListEntry( "SplitterSizes" );
00210   if ( sizes.count() == 2 ) {
00211     mSplitter->setSizes( sizes );
00212   }
00213   mSplitter->setCollapsible( mIncidenceListView, false );
00214   mSplitter->setCollapsible( mDetailView, false );
00215 }
00216 
00217 void AlarmDialog::writeLayout()
00218 {
00219   KConfig *config = kapp->config();
00220   config->setGroup( "Layout" );
00221   QValueList<int> list = mSplitter->sizes();
00222   config->writeEntry( "SplitterSizes", list );
00223 }
00224 
00225 void AlarmDialog::addIncidence( Incidence *incidence,
00226                                 const QDateTime &reminderAt,
00227                                 const QString &displayText )
00228 {
00229   AlarmListItem *item = searchByUid( incidence->uid() );
00230   if ( !item ) {
00231     item = new AlarmListItem( incidence->uid(), mIncidenceListView );
00232   }
00233   item->mNotified = false;
00234   item->mHappening = QDateTime();
00235   item->mRemindAt = reminderAt;
00236   item->mDisplayText = displayText;
00237   item->setText( 0, cleanSummary( incidence->summary() ) );
00238   item->setText( 1, QString() );
00239 
00240   QString displayStr;
00241   const QDateTime dateTime = triggerDateForIncidence( incidence, reminderAt, displayStr );
00242 
00243   item->mHappening = dateTime;
00244   item->setText( 1, displayStr );
00245 
00246   if ( incidence->type() == "Event" ) {
00247     item->setPixmap( 0, SmallIcon( "appointment" ) );
00248   } else {
00249     item->setPixmap( 0, SmallIcon( "todo" ) );
00250   }
00251 
00252   if ( activeCount() == 1 ) { // previously empty
00253     mIncidenceListView->clearSelection();
00254     item->setSelected( true );
00255   }
00256   showDetails();
00257 }
00258 
00259 void AlarmDialog::slotOk()
00260 {
00261   suspend();
00262 }
00263 
00264 void AlarmDialog::slotUser1()
00265 {
00266   edit();
00267 }
00268 
00269 void AlarmDialog::slotUser2()
00270 {
00271   dismissAll();
00272 }
00273 
00274 void AlarmDialog::slotUser3()
00275 {
00276   dismissCurrent();
00277 }
00278 
00279 void AlarmDialog::dismissCurrent()
00280 {
00281   ItemList selection = selectedItems();
00282   QStringList dismissedUids;
00283   for ( ItemList::Iterator it = selection.begin(); it != selection.end(); ++it ) {
00284     dismissedUids.append( (*it)->mUid );
00285     if ( (*it)->itemBelow() )
00286       (*it)->itemBelow()->setSelected( true );
00287     else if ( (*it)->itemAbove() )
00288       (*it)->itemAbove()->setSelected( true );
00289     delete *it;
00290   }
00291   if ( activeCount() == 0 ) {
00292     writeLayout();
00293     accept();
00294   } else {
00295     updateButtons();
00296     showDetails();
00297   }
00298 
00299   // Suspended alarms are stored in config. If we dismiss a suspended alarm we
00300   // must remove it from config, otherwise it popsup next time we start korgac
00301   removeFromConfig( dismissedUids );
00302 
00303   emit reminderCount( activeCount() );
00304 }
00305 
00306 void AlarmDialog::dismissAll()
00307 {
00308   QStringList uids;
00309   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ) {
00310     AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
00311     uids.append( item->mUid );
00312     if ( !item->isVisible() ) {
00313       ++it;
00314       continue;
00315     }
00316     mIncidenceListView->takeItem( item );
00317     delete item;
00318   }
00319   setTimer();
00320   writeLayout();
00321   accept();
00322 
00323   // We probably could just remove everything
00324   removeFromConfig( uids );
00325 
00326   emit reminderCount( activeCount() );
00327 }
00328 
00329 void AlarmDialog::edit()
00330 {
00331   ItemList selection = selectedItems();
00332   if ( selection.count() != 1 ) {
00333     return;
00334   }
00335   Incidence *incidence = mCalendar->incidence( selection.first()->mUid );
00336   if ( !incidence ) {
00337     return;
00338   }
00339   const QDate dt = selection.first()->mRemindAt.date();
00340 
00341   if ( incidence->isReadOnly() ) {
00342     KMessageBox::sorry(
00343       this,
00344       i18n( "\"%1\" is a read-only item so modifications are not possible." ).
00345       arg( cleanSummary( incidence->summary() ) ) );
00346     return;
00347   }
00348 
00349   if ( !ensureKorganizerRunning() ) {
00350     KMessageBox::error(
00351       this,
00352       i18n( "Could not start KOrganizer so editing is not possible." ) );
00353     return;
00354   }
00355 
00356   QByteArray data;
00357   QDataStream arg( data, IO_WriteOnly );
00358   arg << incidence->uid();
00359   arg << dt;
00360   //kdDebug(5890) << "editing incidence " << incidence->summary() << endl;
00361   if ( !kapp->dcopClient()->send( "korganizer", "KOrganizerIface",
00362                                   "editIncidence(QString,QDate)",
00363                                   data ) ) {
00364     KMessageBox::error(
00365       this,
00366       i18n( "An internal KOrganizer error occurred attempting to start the incidence editor" ) );
00367     return;
00368   }
00369 
00370   // get desktop # where korganizer (or kontact) runs
00371   QByteArray replyData;
00372   QCString object, replyType;
00373   object = kapp->dcopClient()->isApplicationRegistered( "kontact" ) ?
00374            "kontact-mainwindow#1" : "KOrganizer MainWindow";
00375   if (!kapp->dcopClient()->call( "korganizer", object,
00376                             "getWinID()", 0, replyType, replyData, true, -1 ) ) {
00377   }
00378 
00379   if ( replyType == "int" ) {
00380     int desktop, window;
00381     QDataStream ds( replyData, IO_ReadOnly );
00382     ds >> window;
00383     desktop = KWin::windowInfo( window ).desktop();
00384 
00385     if ( KWin::currentDesktop() == desktop ) {
00386       KWin::iconifyWindow( winId(), false );
00387     } else {
00388       KWin::setCurrentDesktop( desktop );
00389     }
00390     KWin::activateWindow( KWin::transientFor( window ) );
00391   }
00392 }
00393 
00394 void AlarmDialog::suspend()
00395 {
00396   if ( !isVisible() )
00397     return;
00398 
00399   int unit=1;
00400   switch (mSuspendUnit->currentItem()) {
00401     case 3: // weeks
00402       unit *=  7;
00403     case 2: // days
00404       unit *= 24;
00405     case 1: // hours
00406       unit *= 60;
00407     case 0: // minutes
00408       unit *= 60;
00409     default:
00410       break;
00411   }
00412 
00413   AlarmListItem *selitem = 0;
00414   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00415     AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00416     if ( item->isSelected() && item->isVisible() ) {
00417       item->setVisible( false );
00418       item->setSelected( false );
00419       item->mRemindAt = QDateTime::currentDateTime().addSecs( unit * mSuspendSpin->value() );
00420       item->mNotified = false;
00421       selitem = item;
00422     }
00423   }
00424   if ( selitem ) {
00425     if ( selitem->itemBelow() ) {
00426       selitem->itemBelow()->setSelected( true );
00427     } else if ( selitem->itemAbove() ) {
00428       selitem->itemAbove()->setSelected( true );
00429     }
00430   }
00431 
00432   // save suspended alarms too so they can be restored on restart
00433   // kolab/issue4108
00434   slotSave();
00435 
00436   setTimer();
00437   if ( activeCount() == 0 ) {
00438     writeLayout();
00439     accept();
00440   } else {
00441     updateButtons();
00442     showDetails();
00443   }
00444   emit reminderCount( activeCount() );
00445 }
00446 
00447 void AlarmDialog::setTimer()
00448 {
00449   int nextReminderAt = -1;
00450   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00451     AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00452     if ( item->mRemindAt > QDateTime::currentDateTime() ) {
00453       int secs = QDateTime::currentDateTime().secsTo( item->mRemindAt );
00454       nextReminderAt = nextReminderAt <= 0 ? secs : QMIN( nextReminderAt, secs );
00455     }
00456   }
00457 
00458   if ( nextReminderAt >= 0 ) {
00459     mSuspendTimer.stop();
00460     mSuspendTimer.start( 1000 * (nextReminderAt + 1), true );
00461   }
00462 }
00463 
00464 void AlarmDialog::show()
00465 {
00466   mIncidenceListView->sort();
00467 
00468   // select the first item that hasn't already been notified
00469   mIncidenceListView->clearSelection();
00470   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00471     AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
00472     if ( !item->mNotified ) {
00473       (*it)->setSelected( true );
00474       break;
00475     }
00476   }
00477 
00478   updateButtons();
00479   showDetails();
00480 
00481   // reset the default suspend time
00482   mSuspendSpin->setValue( defSuspendVal );
00483   mSuspendUnit->setCurrentItem( defSuspendUnit );
00484 
00485   KDialogBase::show();
00486   KWin::deIconifyWindow( winId(), false );
00487   KWin::setState( winId(), NET::KeepAbove | NET::DemandsAttention );
00488   KWin::setOnAllDesktops( winId(), true );
00489   KWin::activateWindow( winId() );
00490   raise();
00491   setActiveWindow();
00492   if ( isMinimized() ) {
00493     showNormal();
00494   }
00495   eventNotification();
00496 }
00497 
00498 void AlarmDialog::eventNotification()
00499 {
00500   bool beeped = false, found = false;
00501 
00502   QValueList<AlarmListItem*> list;
00503   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00504     AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
00505     if ( !item->isVisible() || item->mNotified ) {
00506       continue;
00507     }
00508     Incidence *incidence = mCalendar->incidence( item->mUid );
00509     if ( !incidence ) {
00510       continue;
00511     }
00512     found = true;
00513     item->mNotified = true;
00514     Alarm::List alarms = incidence->alarms();
00515     Alarm::List::ConstIterator it;
00516     for ( it = alarms.begin(); it != alarms.end(); ++it ) {
00517       Alarm *alarm = *it;
00518       // FIXME: Check whether this should be done for all multiple alarms
00519       if (alarm->type() == Alarm::Procedure) {
00520         // FIXME: Add a message box asking whether the procedure should really be executed
00521         kdDebug(5890) << "Starting program: '" << alarm->programFile() << "'" << endl;
00522         KProcess proc;
00523         proc << QFile::encodeName(alarm->programFile());
00524         proc.start(KProcess::DontCare);
00525       }
00526       else if (alarm->type() == Alarm::Audio) {
00527         beeped = true;
00528         KAudioPlayer::play(QFile::encodeName(alarm->audioFile()));
00529       }
00530     }
00531   }
00532 
00533   if ( !beeped && found ) {
00534     KNotifyClient::beep();
00535   }
00536 }
00537 
00538 void AlarmDialog::wakeUp()
00539 {
00540   bool activeReminders = false;
00541   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00542     AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
00543     Incidence *incidence = mCalendar->incidence( item->mUid );
00544     if ( !incidence ) {
00545       delete item;
00546       continue;
00547     }
00548 
00549     if ( item->mRemindAt <= QDateTime::currentDateTime() ) {
00550       if ( !item->isVisible() ) {
00551         item->setVisible( true );
00552         item->setSelected( false );
00553       }
00554       activeReminders = true;
00555     } else {
00556       item->setVisible( false );
00557     }
00558   }
00559 
00560   if ( activeReminders )
00561     show();
00562   setTimer();
00563   showDetails();
00564   emit reminderCount( activeCount() );
00565 }
00566 
00567 void AlarmDialog::slotSave()
00568 {
00569   KConfig *config = kapp->config();
00570   KLockFile::Ptr lock = config->lockFile();
00571   if ( lock.data()->lock() != KLockFile::LockOK )
00572     return;
00573 
00574   config->setGroup( "General" );
00575   int numReminders = config->readNumEntry("Reminders", 0);
00576 
00577   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00578     AlarmListItem *item = static_cast<AlarmListItem*>( it.current() );
00579     Incidence *incidence = mCalendar->incidence( item->mUid );
00580     if ( !incidence ) {
00581       continue;
00582     }
00583     config->setGroup( QString("Incidence-%1").arg(numReminders + 1) );
00584     config->writeEntry( "UID", incidence->uid() );
00585     config->writeEntry( "RemindAt", item->mRemindAt );
00586     ++numReminders;
00587   }
00588 
00589   config->setGroup( "General" );
00590   config->writeEntry( "Reminders", numReminders );
00591   config->sync();
00592   lock.data()->unlock();
00593 }
00594 
00595 void AlarmDialog::closeEvent( QCloseEvent * )
00596 {
00597   slotSave();
00598   writeLayout();
00599   accept();
00600 }
00601 
00602 void AlarmDialog::updateButtons()
00603 {
00604   ItemList selection = selectedItems();
00605   enableButton( User1, selection.count() == 1 ); // can only edit 1 at a time
00606   enableButton( User3, selection.count() > 0 );  // dismiss 1 or more
00607   enableButton( Ok, selection.count() > 0 );     // suspend 1 or more
00608 }
00609 
00610 QValueList< AlarmListItem * > AlarmDialog::selectedItems() const
00611 {
00612   QValueList<AlarmListItem*> list;
00613   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00614     if ( it.current()->isSelected() )
00615       list.append( static_cast<AlarmListItem*>( it.current() ) );
00616   }
00617   return list;
00618 }
00619 
00620 int AlarmDialog::activeCount()
00621 {
00622   int count = 0;
00623   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00624     AlarmListItem * item = static_cast<AlarmListItem*>( it.current() );
00625     if ( item->isVisible() )
00626       ++count;
00627   }
00628   return count;
00629 }
00630 
00631 void AlarmDialog::suspendAll()
00632 {
00633   mIncidenceListView->clearSelection();
00634   for ( QListViewItemIterator it( mIncidenceListView ) ; it.current() ; ++it ) {
00635     if ( it.current()->isVisible() )
00636       it.current()->setSelected( true );
00637   }
00638   suspend();
00639 }
00640 
00641 void AlarmDialog::showDetails()
00642 {
00643   mDetailView->clearEvents( true );
00644   mDetailView->clear();
00645   AlarmListItem *item = static_cast<AlarmListItem*>( mIncidenceListView->selectedItems().first() );
00646   if ( !item || !item->isVisible() )
00647     return;
00648 
00649   Incidence *incidence = mCalendar->incidence( item->mUid );
00650   if ( !incidence ) {
00651     return;
00652   }
00653 
00654   if ( !item->mDisplayText.isEmpty() ) {
00655     QString txt = "<qt><p><b>" + item->mDisplayText + "</b></p></qt>";
00656     mDetailView->addText( txt );
00657   }
00658   item->setText( 0, cleanSummary( incidence->summary() ) );
00659   mDetailView->appendIncidence( incidence, item->mRemindAt.date() );
00660 }
00661 
00662 bool AlarmDialog::ensureKorganizerRunning() const
00663 {
00664   QString error;
00665   QCString dcopService;
00666 
00667   int result = KDCOPServiceStarter::self()->findServiceFor(
00668     "DCOP/Organizer", QString::null, QString::null, &error, &dcopService );
00669 
00670   if ( result == 0 ) {
00671     // OK, so korganizer (or kontact) is running. Now ensure the object we
00672     // want is available [that's not the case when kontact was already running,
00673     // but korganizer not loaded into it...]
00674     static const char* const dcopObjectId = "KOrganizerIface";
00675     QCString dummy;
00676     if ( !kapp->dcopClient()->findObject(
00677            dcopService, dcopObjectId, "", QByteArray(), dummy, dummy ) ) {
00678       DCOPRef ref( dcopService, dcopService ); // talk to KUniqueApplication or its kontact wrapper
00679       DCOPReply reply = ref.call( "load()" );
00680       if ( reply.isValid() && (bool)reply ) {
00681         Q_ASSERT( kapp->dcopClient()->findObject(
00682                     dcopService, dcopObjectId, "", QByteArray(), dummy, dummy ) );
00683       } else {
00684         kdWarning() << "Error loading " << dcopService << endl;
00685       }
00686     }
00687 
00688     // We don't do anything with it we just need it to be running
00689     return true;
00690 
00691   } else {
00692     kdWarning() << "Couldn't start DCOP/Organizer: " << dcopService
00693                 << " " << error << endl;
00694   }
00695   return false;
00696 }
00697 
00699 QDateTime AlarmDialog::triggerDateForIncidence( Incidence *incidence,
00700                                                 const QDateTime &reminderAt,
00701                                                 QString &displayStr )
00702 {
00703   // Will be simplified in trunk, with roles.
00704   QDateTime result;
00705 
00706   Alarm *alarm = incidence->alarms().first();
00707 
00708   if ( incidence->doesRecur() ) {
00709     result = incidence->recurrence()->getNextDateTime( reminderAt );
00710     displayStr = KGlobal::locale()->formatDateTime( result );
00711   }
00712 
00713   if ( incidence->type() == "Event" ) {
00714     if ( !result.isValid() ) {
00715       Event *event = static_cast<Event *>( incidence );
00716       result = alarm->hasStartOffset() ? event->dtStart() :
00717                                          event->dtEnd();
00718       displayStr = IncidenceFormatter::dateTimeToString( result, false, true );
00719     }
00720   } else if ( incidence->type() == "Todo" ) {
00721     if ( !result.isValid() ) {
00722       Todo *todo = static_cast<Todo *>( incidence );
00723       result = alarm->hasStartOffset() && todo->dtStart().isValid() ? todo->dtStart():
00724                                                                       todo->dtDue();
00725      displayStr = IncidenceFormatter::dateTimeToString( result, false, true );
00726     }
00727   }
00728 
00729   return result;
00730 }
00731 
00732 void AlarmDialog::slotCalendarChanged()
00733 {
00734   Incidence::List incidences = mCalendar->incidences();
00735   for ( Incidence::List::ConstIterator it = incidences.begin();
00736         it != incidences.constEnd(); ++it ) {
00737     Incidence *incidence = *it;
00738     AlarmListItem *item = searchByUid( incidence->uid() );
00739 
00740     if ( item ) {
00741       QString displayStr;
00742       const QDateTime dateTime = triggerDateForIncidence( incidence,
00743                                                           item->mRemindAt,
00744                                                           displayStr );
00745 
00746       const QString summary = cleanSummary( incidence->summary() );
00747 
00748       if ( displayStr != item->text( 1 ) || summary != item->text( 0 ) ) {
00749         item->setText( 1, displayStr );
00750         item->setText( 0, summary );
00751       }
00752     }
00753   }
00754 }
00755 
00756 void AlarmDialog::keyPressEvent( QKeyEvent *e )
00757 {
00758   if ( e->state() == 0 ) {
00759     if ( e->key() == Key_Enter || e->key() == Key_Return ) {
00760       e->ignore();
00761       return;
00762     }
00763   }
00764   KDialog::keyPressEvent( e );
00765 }
00766 
00767 void AlarmDialog::removeFromConfig(const QStringList &uids )
00768 {
00769   KConfig *config = kapp->config();
00770   KLockFile::Ptr lock = config->lockFile();
00771   if ( lock.data()->lock() != KLockFile::LockOK ) {
00772     kdError() << "Could not aquire lock.";
00773     return;
00774   }
00775 
00776   config->setGroup( "General" );
00777   const int oldNumReminders = config->readNumEntry( "Reminders", 0 );
00778   QValueList<QPair<QString,QDateTime> > newReminders;
00779   // Delete everything
00780   for ( int i = 1; i <= oldNumReminders; ++i ) {
00781     const QString group( QString( "Incidence-%1" ).arg( i ) );
00782     config->setGroup( group );
00783     const QString uid = config->readEntry( "UID" );
00784     const QDateTime remindAtDate = config->readDateTimeEntry( "RemindAt" );
00785     if ( !uids.contains( uid ) ) {
00786       newReminders.append( qMakePair<QString,QDateTime>( uid, remindAtDate ) );
00787     }
00788     config->deleteGroup( group );
00789   }
00790 
00791   config->setGroup( "General" );
00792   config->writeEntry( "Reminders", newReminders.count() );
00793 
00794   //Write everything except those which have an uid we dont want
00795   for ( int i = 0; i < newReminders.count(); ++i ) {
00796     config->setGroup( QString( "Incidence-%1" ).arg( i + 1 ) );
00797     config->writeEntry( "UID", newReminders[i].first );
00798     config->writeEntry( "RemindAt", newReminders[i].second );
00799   }
00800   config->sync();
00801   lock.data()->unlock();
00802 }
KDE Home | KDE Accessibility Home | Description of Access Keys