• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

korgac

  • sources
  • kde-4.12
  • kdepim
  • korgac
alarmdialog.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the KDE reminder agent.
3 
4  Copyright (c) 2000,2003 Cornelius Schumacher <schumacher@kde.org>
5  Copyright (c) 2008-2009 Allen Winter <winter@kde.org>
6  Copyright (c) 2009-2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License along
19  with this program; if not, write to the Free Software Foundation, Inc.,
20  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 
22  As a special exception, permission is given to link this program
23  with any edition of Qt, and distribute the resulting executable,
24  without including the source code for Qt in the source distribution.
25 */
26 
27 #include "alarmdialog.h"
28 #include "korganizer_interface.h"
29 #include "mailclient.h"
30 
31 #include <calendarsupport/next/incidenceviewer.h>
32 #include <calendarsupport/kcalprefs.h>
33 #include <calendarsupport/identitymanager.h>
34 #include <calendarsupport/utils.h>
35 
36 #include <incidenceeditor-ng/incidencedialog.h>
37 #include <incidenceeditor-ng/incidencedialogfactory.h>
38 
39 #include <KCalCore/Event>
40 #include <KCalCore/Todo>
41 #include <KCalUtils/IncidenceFormatter>
42 
43 #include <KPIMIdentities/Identity>
44 #include <KPIMIdentities/IdentityManager>
45 
46 #include <Akonadi/Item>
47 
48 #include <Mailtransport/TransportManager>
49 
50 #include <KComboBox>
51 #include <KDebug>
52 #include <KHBox>
53 #include <KLocale>
54 #include <KMessageBox>
55 #include <KNotification>
56 #include <KSharedConfig>
57 #include <KSystemTimeZone>
58 #include <KToolInvocation>
59 #include <KWindowSystem>
60 
61 #include <phonon/mediaobject.h>
62 #include <QLabel>
63 #include <QKeyEvent>
64 #include <QSpinBox>
65 #include <QTreeWidget>
66 #include <QVBoxLayout>
67 
68 using namespace KPIMIdentities;
69 using namespace KCalCore;
70 using namespace KCalUtils;
71 
72 static int defSuspendVal = 5;
73 static int defSuspendUnit = 0; // 0=>minutes, 1=>hours, 2=>days, 3=>weeks
74 
75 class ReminderTree : public QTreeWidget
76 {
77  public:
78  ReminderTree( QWidget *parent ) : QTreeWidget( parent )
79  {
80  }
81 
82  /*reimp*/
83  void mouseReleaseEvent( QMouseEvent *event );
84 };
85 
86 void ReminderTree::mouseReleaseEvent( QMouseEvent *event )
87 {
88  QTreeWidgetItem *item = itemAt( event->pos() );
89  if ( item ) {
90  if ( event->button() == Qt::LeftButton ) {
91  emit itemActivated( item, 0 );
92  } else if ( event->button() == Qt::RightButton ) {
93  emit customContextMenuRequested( event->pos() );
94  }
95  }
96 }
97 
98 class ReminderTreeItem : public QTreeWidgetItem
99 {
100  public:
101  ReminderTreeItem( const Akonadi::Item &incidence, QTreeWidget *parent )
102  : QTreeWidgetItem( parent ), mIncidence( incidence ), mNotified( false )
103  {
104  }
105  bool operator<( const QTreeWidgetItem & other ) const;
106 
107  QString mDisplayText;
108 
109  const Akonadi::Item mIncidence;
110  QDateTime mRemindAt;
111  KDateTime mTrigger;
112  KDateTime mHappening;
113  bool mNotified;
114 };
115 
116 struct ConfItem {
117  QString uid;
118  KUrl akonadiUrl;
119  QDateTime remindAt;
120 };
121 
122 bool ReminderTreeItem::operator<( const QTreeWidgetItem &other ) const
123 {
124  switch( treeWidget()->sortColumn() ) {
125  case 1: // happening datetime
126  {
127  const ReminderTreeItem *item = static_cast<const ReminderTreeItem *>( &other );
128  return item->mHappening.secsTo( mHappening );
129  }
130  case 2: // trigger datetime
131  {
132  const ReminderTreeItem *item = static_cast<const ReminderTreeItem *>( &other );
133  return item->mTrigger.secsTo( mTrigger );
134  }
135  default:
136  return QTreeWidgetItem::operator < ( other );
137  }
138 }
139 
140 typedef QList<ReminderTreeItem *> ReminderList;
141 
142 AlarmDialog::AlarmDialog( const Akonadi::ETMCalendar::Ptr &calendar, QWidget *parent )
143  : KDialog( parent, Qt::WindowStaysOnTopHint ),
144  mCalendar( calendar ), mSuspendTimer( this )
145 {
146  // User1 => Edit...
147  // User2 => Dismiss All
148  // User3 => Dismiss Selected
149  // Ok => Suspend
150 
151  connect( calendar.data(), SIGNAL(calendarChanged()), SLOT(slotCalendarChanged()) );
152 
153  KIconLoader::global()->addAppDir( QLatin1String("korgac") );
154 
155  KSharedConfig::Ptr config = KGlobal::config();
156  KConfigGroup generalConfig( config, "General" );
157  QPoint pos = generalConfig.readEntry( "Position", QPoint( 0, 0 ) );
158 
159  QWidget *topBox = new QWidget( this );
160  if ( !pos.isNull() ) {
161  mPos = pos;
162  topBox->move( mPos );
163  }
164  setMainWidget( topBox );
165  setCaption( i18nc( "@title:window", "Reminders" ) );
166  setWindowIcon( KIcon( QLatin1String("korgac") ) );
167  setButtons( Ok | User1 | User2 | User3 );
168  setDefaultButton( NoDefault );
169  setButtonText( User3, i18nc( "@action:button", "Dismiss Reminder" ) );
170  setButtonToolTip( User3, i18nc( "@info:tooltip",
171  "Dismiss the reminders for the selected incidences" ) );
172  setButtonText( User2, i18nc( "@action:button", "Dismiss All" ) );
173  setButtonToolTip( User2, i18nc( "@info:tooltip",
174  "Dismiss the reminders for all listed incidences" ) );
175  setButtonText( User1, i18nc( "@action:button", "Edit..." ) );
176  setButtonToolTip( User1, i18nc( "@info:tooltip",
177  "Edit the selected incidence" ) );
178  setButtonText( Ok, i18nc( "@action:button", "Suspend" ) );
179  setButtonToolTip( Ok, i18nc( "@info:tooltip",
180  "Suspend the reminders for the selected incidences "
181  "by the specified interval" ) );
182 
183  // Try to keep the dialog small and non-obtrusive.
184  setMinimumWidth( 575 );
185  setMinimumHeight( 300 );
186 
187  QVBoxLayout *mTopLayout = new QVBoxLayout( topBox );
188 
189  QLabel *label = new QLabel(
190  i18nc( "@label",
191  "Reminders: "
192  "Click on a title to toggle the details viewer for that item" ),
193  topBox );
194  mTopLayout->addWidget( label );
195 
196  mIncidenceTree = new ReminderTree( topBox );
197  mIncidenceTree->setColumnCount( 3 );
198  mIncidenceTree->setSortingEnabled( true );
199  const QStringList headerLabels =
200  ( QStringList( i18nc( "@title:column reminder title", "Title" ) )
201  << i18nc( "@title:column happens at date/time", "Date Time" )
202  << i18nc( "@title:column trigger date/time", "Trigger Time" ) );
203  mIncidenceTree->setHeaderLabels( headerLabels );
204  mIncidenceTree->headerItem()->setToolTip(
205  0,
206  i18nc( "@info:tooltip", "The event or to-do title" ) );
207  mIncidenceTree->headerItem()->setToolTip(
208  1,
209  i18nc( "@info:tooltip", "The reminder is set for this date/time" ) );
210  mIncidenceTree->headerItem()->setToolTip(
211  2,
212  i18nc( "@info:tooltip", "The date/time the reminder was triggered" ) );
213 
214  mIncidenceTree->setWordWrap( true );
215  mIncidenceTree->setAllColumnsShowFocus( true );
216  mIncidenceTree->setSelectionMode( QAbstractItemView::ExtendedSelection );
217  mIncidenceTree->setRootIsDecorated( false );
218 
219  mTopLayout->addWidget( mIncidenceTree );
220 
221  connect( mIncidenceTree, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
222  SLOT(update()) );
223  connect( mIncidenceTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
224  SLOT(edit()) );
225  connect( mIncidenceTree, SIGNAL(customContextMenuRequested(QPoint)), SLOT(popupItemMenu(QPoint)) );
226 
227  mDetailView = new CalendarSupport::IncidenceViewer( mCalendar.data(), topBox );
228  QString s;
229  s = i18nc( "@info default incidence details string",
230  "<emphasis>Select an event or to-do from the list above "
231  "to view its details here.</emphasis>" );
232  mDetailView->setDefaultMessage( s );
233  mTopLayout->addWidget( mDetailView );
234  mDetailView->hide();
235  mLastItem = 0;
236 
237  KHBox *suspendBox = new KHBox( topBox );
238  suspendBox->setSpacing( spacingHint() );
239  mTopLayout->addWidget( suspendBox );
240 
241  QLabel *l = new QLabel( i18nc( "@label:spinbox", "Suspend &duration:" ), suspendBox );
242 
243  mSuspendSpin = new QSpinBox( suspendBox );
244  mSuspendSpin->setRange( 1, 9999 );
245  mSuspendSpin->setValue( defSuspendVal ); // default suspend duration
246  mSuspendSpin->setToolTip(
247  i18nc( "@info:tooltip",
248  "Suspend the reminders by this amount of time" ) );
249  mSuspendSpin->setWhatsThis(
250  i18nc( "@info:whatsthis",
251  "Each reminder for the selected incidences will be suspended "
252  "by this number of time units. You can choose the time units "
253  "(typically minutes) in the adjacent selector." ) );
254 
255  l->setBuddy( mSuspendSpin );
256 
257  mSuspendUnit = new KComboBox( suspendBox );
258  mSuspendUnit->addItem( i18nc( "@item:inlistbox suspend in terms of minutes", "minute(s)" ) );
259  mSuspendUnit->addItem( i18nc( "@item:inlistbox suspend in terms of hours", "hour(s)" ) );
260  mSuspendUnit->addItem( i18nc( "@item:inlistbox suspend in terms of days", "day(s)" ) );
261  mSuspendUnit->addItem( i18nc( "@item:inlistbox suspend in terms of weeks", "week(s)" ) );
262  mSuspendUnit->setToolTip(
263  i18nc( "@info:tooltip",
264  "Suspend the reminders using this time unit" ) );
265  mSuspendUnit->setWhatsThis(
266  i18nc( "@info:whatsthis",
267  "Each reminder for the selected incidences will be suspended "
268  "using this time unit. You can set the number of time units "
269  "in the adjacent number entry input." ) );
270 
271  mSuspendUnit->setCurrentIndex( defSuspendUnit );
272 
273  connect( &mSuspendTimer, SIGNAL(timeout()), SLOT(wakeUp()) );
274 
275  connect( this, SIGNAL(okClicked()), this, SLOT(slotOk()) );
276  connect( this, SIGNAL(user1Clicked()), this, SLOT(slotUser1()) );
277  connect( this, SIGNAL(user2Clicked()), this, SLOT(slotUser2()) );
278  connect( this, SIGNAL(user3Clicked()), this, SLOT(slotUser3()) );
279 
280  mIdentityManager = new CalendarSupport::IdentityManager;
281 }
282 
283 AlarmDialog::~AlarmDialog()
284 {
285  mIncidenceTree->clear();
286  delete mIdentityManager;
287 }
288 
289 ReminderTreeItem *AlarmDialog::searchByItem( const Akonadi::Item &incidence )
290 {
291  ReminderTreeItem *found = 0;
292  QTreeWidgetItemIterator it( mIncidenceTree );
293  while ( *it ) {
294  ReminderTreeItem *item = static_cast<ReminderTreeItem *>( *it );
295  if ( item->mIncidence == incidence ) {
296  found = item;
297  break;
298  }
299  ++it;
300  }
301  return found;
302 }
303 
304 static QString cleanSummary( const QString &summary )
305 {
306  static QString etc = i18nc( "@label an elipsis", "..." );
307  int maxLen = 30;
308  QString retStr = summary;
309  retStr.replace( QLatin1Char('\n'), QLatin1Char(' ') );
310  if ( retStr.length() > maxLen ) {
311  maxLen -= etc.length();
312  retStr = retStr.left( maxLen );
313  retStr += etc;
314  }
315  return retStr;
316 }
317 
318 void AlarmDialog::addIncidence( const Akonadi::Item &incidenceitem,
319  const QDateTime &reminderAt,
320  const QString &displayText )
321 {
322  Incidence::Ptr incidence = CalendarSupport::incidence( incidenceitem );
323  ReminderTreeItem *item = searchByItem( incidenceitem );
324  if ( !item ) {
325  item = new ReminderTreeItem( incidenceitem, mIncidenceTree );
326  }
327  item->mNotified = false;
328  item->mHappening = KDateTime();
329  item->mRemindAt = reminderAt;
330  item->mTrigger = KDateTime::currentLocalDateTime();
331  item->mDisplayText = displayText;
332  item->setText( 0, cleanSummary( incidence->summary() ) );
333 
334  Event::Ptr event;
335  Todo::Ptr todo;
336 
337  QString displayStr;
338  const KDateTime dateTime = triggerDateForIncidence( incidence, reminderAt,
339  displayStr );
340 
341  if ( incidence->type() == Incidence::TypeEvent ) {
342  item->setIcon( 0, SmallIcon( QLatin1String("view-calendar-day") ) );
343  } else if ( incidence->type() == Incidence::TypeTodo ) {
344  item->setIcon( 0, SmallIcon( QLatin1String("view-calendar-tasks")) );
345  }
346 
347  item->mHappening = dateTime;
348  item->setText( 1, displayStr );
349 
350  item->setText( 2, IncidenceFormatter::dateTimeToString(
351  item->mTrigger, false, true, KDateTime::Spec::LocalZone() ) );
352  QString tip =
353  IncidenceFormatter::toolTipStr(
354  CalendarSupport::displayName( mCalendar.data(), incidenceitem.parentCollection() ),
355  incidence,
356  item->mRemindAt.date(), true,
357  KDateTime::Spec::LocalZone() );
358  if ( !item->mDisplayText.isEmpty() ) {
359  tip += QLatin1String("<br>") + item->mDisplayText;
360  }
361  item->setToolTip( 0, tip );
362  item->setToolTip( 1, tip );
363  item->setToolTip( 2, tip );
364  item->setData( 0, QTreeWidgetItem::UserType, false );
365 
366  mIncidenceTree->setCurrentItem( item );
367  showDetails( item );
368  slotSave();
369 }
370 
371 void AlarmDialog::slotOk()
372 {
373  suspend();
374 }
375 
376 void AlarmDialog::slotUser1()
377 {
378  edit();
379 }
380 
381 void AlarmDialog::slotUser2()
382 {
383  dismissAll();
384 }
385 
386 void AlarmDialog::slotUser3()
387 {
388  dismissCurrent();
389 }
390 
391 void AlarmDialog::dismissCurrent()
392 {
393  dismiss( selectedItems() );
394 
395  if ( activeCount() == 0 ) {
396  accept();
397  } else {
398  update();
399  }
400  emit reminderCount( activeCount() );
401 }
402 
403 void AlarmDialog::dismissAll()
404 {
405  ReminderList selections;
406 
407  QTreeWidgetItemIterator it( mIncidenceTree );
408  while ( *it ) {
409  if ( !(*it)->isDisabled() ) { //do not disable suspended reminders
410  selections.append( static_cast<ReminderTreeItem *>( *it ) );
411  }
412  ++it;
413  }
414  dismiss( selections );
415 
416  setTimer();
417  accept();
418  emit reminderCount( activeCount() );
419 }
420 
421 void AlarmDialog::dismiss( ReminderList selections )
422 {
423  QList<Akonadi::Item::Id> ids;
424  for ( ReminderList::Iterator it = selections.begin(); it != selections.end(); ++it ) {
425  kDebug() << "removing " << CalendarSupport::incidence( (*it)->mIncidence )->summary();
426  if ( mIncidenceTree->itemBelow( *it ) ) {
427  mIncidenceTree->setCurrentItem( mIncidenceTree->itemBelow( *it ) );
428  } else if ( mIncidenceTree->itemAbove( *it ) ) {
429  mIncidenceTree->setCurrentItem( mIncidenceTree->itemAbove( *it ) );
430  }
431  mIncidenceTree->removeItemWidget( *it, 0 );
432  ids.append( (*it)->mIncidence.id() );
433  delete *it;
434  }
435 
436  removeFromConfig( ids );
437 }
438 
439 void AlarmDialog::edit()
440 {
441  ReminderList selection = selectedItems();
442  if ( selection.count() != 1 ) {
443  return;
444  }
445  Incidence::Ptr incidence = CalendarSupport::incidence( selection.first()->mIncidence );
446  if ( !mCalendar->hasRight( selection.first()->mIncidence, Akonadi::Collection::CanChangeItem ) ) {
447  KMessageBox::sorry(
448  this,
449  i18nc( "@info",
450  "\"%1\" is a read-only item so modifications are not possible.",
451  cleanSummary( incidence->summary() ) ) );
452  return;
453  }
454 
455 #if !defined(KDEPIM_MOBILE_UI)
456  openIncidenceEditorNG( selection.first()->mIncidence );
457 #else
458  openIncidenceEditorThroughKOrganizer( incidence );
459 #endif
460 }
461 
462 void AlarmDialog::suspend()
463 {
464  if ( !isVisible() ) { //do nothing if the dialog is hidden
465  return;
466  }
467 
468  int unit = 1;
469  switch ( mSuspendUnit->currentIndex() ) {
470  case 3: // weeks
471  unit *= 7;
472  case 2: // days
473  unit *= 24;
474  case 1: // hours
475  unit *= 60;
476  case 0: // minutes
477  unit *= 60;
478  default:
479  break;
480  }
481 
482  ReminderTreeItem *selitem = 0;
483  QTreeWidgetItemIterator it( mIncidenceTree );
484  while ( *it ) {
485  if ( (*it)->isSelected() && !(*it)->isDisabled() ) { //suspend selected, non-suspended reminders
486  (*it)->setSelected( false );
487  (*it)->setDisabled( true );
488  ReminderTreeItem *item = static_cast<ReminderTreeItem *>( *it );
489  item->mRemindAt = QDateTime::currentDateTime().addSecs( unit * mSuspendSpin->value() );
490  item->mHappening = KDateTime( item->mRemindAt, KDateTime::Spec::LocalZone() );
491  item->mNotified = false;
492  (*it)->setText( 1, KGlobal::locale()->formatDateTime( item->mHappening ) );
493  selitem = item;
494  }
495  ++it;
496  }
497 
498  if ( selitem ) {
499  if ( mIncidenceTree->itemBelow( selitem ) ) {
500  mIncidenceTree->setCurrentItem( mIncidenceTree->itemBelow( selitem ) );
501  } else if ( mIncidenceTree->itemAbove( selitem ) ) {
502  mIncidenceTree->setCurrentItem( mIncidenceTree->itemAbove( selitem ) );
503  }
504  }
505 
506  // save suspended alarms too so they can be restored on restart
507  // kolab/issue4108
508  slotSave();
509 
510  setTimer();
511  if ( activeCount() == 0 ) {
512  accept();
513  } else {
514  update();
515  }
516  emit reminderCount( activeCount() );
517 }
518 
519 void AlarmDialog::setTimer()
520 {
521  int nextReminderAt = -1;
522 
523  QTreeWidgetItemIterator it( mIncidenceTree );
524  while ( *it ) {
525  ReminderTreeItem *item = static_cast<ReminderTreeItem *>( *it );
526  if ( item->mRemindAt > QDateTime::currentDateTime() ) {
527  const int secs = QDateTime::currentDateTime().secsTo( item->mRemindAt );
528  nextReminderAt = nextReminderAt <= 0 ? secs : qMin( nextReminderAt, secs );
529  }
530  ++it;
531  }
532 
533  if ( nextReminderAt >= 0 ) {
534  mSuspendTimer.stop();
535  mSuspendTimer.start( 1000 * ( nextReminderAt + 1 ) );
536  mSuspendTimer.setSingleShot( true );
537  }
538 }
539 
540 void AlarmDialog::show()
541 {
542  mIncidenceTree->resizeColumnToContents( 0 );
543  mIncidenceTree->resizeColumnToContents( 1 );
544  mIncidenceTree->resizeColumnToContents( 2 );
545  mIncidenceTree->sortItems( 1, Qt::AscendingOrder );
546 
547  // select the first item that hasn't already been notified
548  QTreeWidgetItemIterator it( mIncidenceTree );
549  while ( *it ) {
550  ReminderTreeItem *item = static_cast<ReminderTreeItem *>( *it );
551  if ( !item->mNotified ) {
552  (*it)->setSelected( true );
553  break;
554  }
555  ++it;
556  }
557 
558  // reset the default suspend time
559 // Allen: commented-out the following lines on 17 Sept 2013
560 // mSuspendSpin->setValue( defSuspendVal );
561 // mSuspendUnit->setCurrentIndex( defSuspendUnit );
562 
563  KDialog::show();
564  if ( !mPos.isNull() ) {
565  KDialog::move( mPos );
566  }
567  KWindowSystem::unminimizeWindow( winId(), false );
568  KWindowSystem::setState( winId(), NET::KeepAbove | NET::DemandsAttention );
569  KWindowSystem::setOnAllDesktops( winId(), true );
570  KWindowSystem::activateWindow( winId() );
571 
572  // Audio, Procedure, and EMail alarms
573  eventNotification();
574 }
575 
576 void AlarmDialog::suspendAll()
577 {
578  mIncidenceTree->clearSelection();
579  QTreeWidgetItemIterator it( mIncidenceTree );
580 
581  // first, select all non-suspended reminders
582  while ( *it ) {
583  if ( !(*it)->isDisabled() ) { //do not suspend suspended reminders
584  (*it)->setSelected( true );
585  }
586  ++it;
587  }
588 
589  //suspend all selected reminders
590  suspend();
591 }
592 
593 void AlarmDialog::eventNotification()
594 {
595  bool beeped = false;
596  bool found = false;
597 
598  ReminderList list;
599 
600  QTreeWidgetItemIterator it( mIncidenceTree );
601  while ( *it ) {
602  ReminderTreeItem *item = static_cast<ReminderTreeItem *>( *it );
603  ++it;
604  if ( item->isDisabled() || item->mNotified ) {
605  //skip suspended reminders or reminders that have been notified
606  continue;
607  }
608  found = true;
609  item->mNotified = true;
610  Incidence::Ptr incidence = CalendarSupport::incidence( item->mIncidence );
611  Alarm::List alarms = incidence->alarms();
612  Alarm::List::ConstIterator ait;
613  for ( ait = alarms.constBegin(); ait != alarms.constEnd(); ++ait ) {
614  Alarm::Ptr alarm = *ait;
615  // FIXME: Check whether this should be done for all multiple alarms
616  if ( alarm->type() == Alarm::Procedure ) {
617  // FIXME: Add a message box asking whether the procedure should really be executed
618  kDebug() << "Starting program: '" << alarm->programFile() << "'";
619 
620  QString program = alarm->programFile();
621 
622  // if the program name contains spaces escape it
623  if ( program.contains( QLatin1Char(' ') ) &&
624  !( program.startsWith( QLatin1Char('\"') ) &&
625  program.endsWith( QLatin1Char('\"') ) ) ) {
626  program = QLatin1Char('\"') + program + QLatin1Char('\"');
627  }
628 
629  QProcess::startDetached( program + QLatin1Char(' ') + alarm->programArguments() );
630  } else if ( alarm->type() == Alarm::Audio ) {
631  beeped = true;
632  Phonon::MediaObject *player =
633  Phonon::createPlayer( Phonon::NotificationCategory,
634  KUrl( alarm->audioFile() ) );
635  player->setParent( this );
636  connect( player, SIGNAL(finished()), player, SLOT(deleteLater()) );
637  player->play();
638  } else if ( alarm->type() == Alarm::Email ) {
639  QString from = CalendarSupport::KCalPrefs::instance()->email();
640  Identity id = mIdentityManager->identityForAddress( from );
641  QString to;
642  if ( alarm->mailAddresses().isEmpty() ) {
643  to = from;
644  } else {
645  const Person::List addresses = alarm->mailAddresses();
646  QStringList add;
647  for ( Person::List::ConstIterator it = addresses.constBegin();
648  it != addresses.constEnd(); ++it ) {
649  add << (*it)->fullName();
650  }
651  to = add.join( QLatin1String(", ") );
652  }
653 
654  QString subject;
655 
656  Akonadi::Item parentItem = mCalendar->item( alarm->parentUid() );
657  Incidence::Ptr parent = CalendarSupport::incidence( parentItem );
658 
659  if ( alarm->mailSubject().isEmpty() ) {
660  if ( parent->summary().isEmpty() ) {
661  subject = i18nc( "@title", "Reminder" );
662  } else {
663  subject = i18nc( "@title", "Reminder: %1", cleanSummary( parent->summary() ) );
664  }
665  } else {
666  subject = i18nc( "@title", "Reminder: %1", alarm->mailSubject() );
667  }
668 
669  QString body =
670  IncidenceFormatter::mailBodyStr(
671  parent.staticCast<IncidenceBase>(), KSystemTimeZones::local() );
672  if ( !alarm->mailText().isEmpty() ) {
673  body += QLatin1Char('\n') + alarm->mailText();
674  }
675  //TODO: support attachments
676  KOrg::MailClient mailer;
677  mailer.send( id, from, to, QString(), subject, body, true, false, QString(),
678  MailTransport::TransportManager::self()->defaultTransportName() );
679  }
680  }
681  }
682 
683  if ( !beeped && found ) {
684  KNotification::beep();
685  }
686 }
687 
688 void AlarmDialog::wakeUp()
689 {
690  bool activeReminders = false;
691  QTreeWidgetItemIterator it( mIncidenceTree );
692  QTreeWidgetItem *firstItem = 0;
693  while ( *it ) {
694  if ( !firstItem ) {
695  firstItem = *it;
696  }
697  ReminderTreeItem *item = static_cast<ReminderTreeItem *>( *it );
698  Incidence::Ptr incidence = CalendarSupport::incidence( item->mIncidence );
699 
700  if ( item->mRemindAt <= QDateTime::currentDateTime() ) {
701  if ( item->isDisabled() ) { //do not wakeup non-suspended reminders
702  item->setDisabled( false );
703  item->setSelected( false );
704  }
705  activeReminders = true;
706  } else {
707  item->setDisabled( true );
708  }
709 
710  ++it;
711  }
712 
713  if ( activeReminders ) {
714  show();
715  }
716  setTimer();
717  showDetails( firstItem );
718  emit reminderCount( activeCount() );
719 }
720 
721 void AlarmDialog::slotSave()
722 {
723  KSharedConfig::Ptr config = KGlobal::config();
724  KConfigGroup generalConfig( config, "General" );
725  int numReminders = 0;
726 
727  QTreeWidgetItemIterator it( mIncidenceTree );
728  while ( *it ) {
729  ReminderTreeItem *item = static_cast<ReminderTreeItem *>( *it );
730  KConfigGroup incidenceConfig( config,
731  QString::fromLatin1( "Incidence-%1" ).arg( numReminders + 1 ) );
732 
733  Incidence::Ptr incidence = CalendarSupport::incidence( item->mIncidence );
734  incidenceConfig.writeEntry( "AkonadiUrl", item->mIncidence.url() );
735  incidenceConfig.writeEntry( "RemindAt", item->mRemindAt );
736  ++numReminders;
737  ++it;
738  }
739 
740  generalConfig.writeEntry( "Reminders", numReminders );
741  generalConfig.writeEntry( "Position", pos() );
742  config->sync();
743 }
744 
745 ReminderList AlarmDialog::selectedItems() const
746 {
747  ReminderList list;
748 
749  QTreeWidgetItemIterator it( mIncidenceTree );
750  while ( *it ) {
751  if ( (*it)->isSelected() ) {
752  list.append( static_cast<ReminderTreeItem *>( *it ) );
753  }
754  ++it;
755  }
756  return list;
757 }
758 
759 int AlarmDialog::activeCount()
760 {
761  int count = 0;
762  QTreeWidgetItemIterator it( mIncidenceTree );
763  while ( *it ) {
764  if ( !(*it)->isDisabled() ) { //suspended reminders are non-active
765  ++count;
766  }
767  ++it;
768  }
769  kDebug() << "computed " << count << " active reminders";
770  return count;
771 }
772 
773 void AlarmDialog::closeEvent( QCloseEvent * )
774 {
775  slotSave();
776  accept();
777 }
778 
779 void AlarmDialog::updateButtons()
780 {
781  const int count = selectedItems().count();
782  kDebug() << "selected items=" << count;
783  enableButton( User3, count > 0 ); // enable Dismiss, if >1 selected
784  enableButton( User1, count == 1 ); // enable Edit, if only 1 selected
785  enableButton( Ok, count > 0 ); // enable Suspend, if >1 selected
786 }
787 
788 void AlarmDialog::toggleDetails( QTreeWidgetItem *item )
789 {
790  if ( !item ) {
791  return;
792  }
793 
794  if ( !mDetailView->isHidden() ) {
795  if ( mLastItem == item ) {
796  resize( size().width(), size().height() - mDetailView->height() - 50 );
797  mDetailView->hide();
798  } else {
799  showDetails( item );
800  }
801  } else {
802  resize( size().width(), size().height() + mDetailView->height() + 50 );
803  showDetails( item );
804  mDetailView->show();
805  }
806  mLastItem = item;
807 }
808 
809 void AlarmDialog::showDetails( QTreeWidgetItem *item )
810 {
811  if ( !item ) {
812  return;
813  }
814 
815  ReminderTreeItem *reminderItem = dynamic_cast<ReminderTreeItem *>( item );
816 
817  if ( !reminderItem ) {
818  mDetailView->setIncidence( Akonadi::Item() );
819  } else {
820  if ( !reminderItem->mDisplayText.isEmpty() ) {
821  QString txt = QLatin1String("<qt><p><b>") + reminderItem->mDisplayText + QLatin1String("</b></p></qt>");
822  mDetailView->setHeaderText( txt );
823  } else {
824  mDetailView->setHeaderText( QString() );
825  }
826  Incidence::Ptr incidence = CalendarSupport::incidence( reminderItem->mIncidence );
827  mDetailView->setIncidence( reminderItem->mIncidence, reminderItem->mRemindAt.date() );
828  }
829 }
830 
831 void AlarmDialog::update()
832 {
833  updateButtons();
834  if ( !mIncidenceTree->selectedItems().isEmpty() ) {
835  QTreeWidgetItem *item = mIncidenceTree->selectedItems().first();
836  toggleDetails( item );
837  }
838 }
839 
840 void AlarmDialog::popupItemMenu( const QPoint &point )
841 {
842  QTreeWidgetItem *item = mIncidenceTree->itemAt( point );
843  if ( !item ) {
844  return;
845  }
846 
847  ReminderTreeItem *reminderItem = dynamic_cast<ReminderTreeItem *>( item );
848  if ( reminderItem ) {
849  Incidence::Ptr incidence = CalendarSupport::incidence( reminderItem->mIncidence );
850  }
851 
852 }
853 
854 void AlarmDialog::accept()
855 {
856  if ( activeCount() == 0 ) {
857  mPos = pos();
858  hide();
859  }
860 }
861 
863 KDateTime AlarmDialog::triggerDateForIncidence( const Incidence::Ptr &incidence,
864  const QDateTime &reminderAt,
865  QString &displayStr )
866 {
867  KDateTime result;
868 
869  if ( incidence->alarms().isEmpty() ) {
870  return result;
871  }
872 
873  Alarm::Ptr alarm = incidence->alarms().first();
874 
875  if ( incidence->recurs() ) {
876  result = incidence->recurrence()->getNextDateTime(
877  KDateTime( reminderAt, KDateTime::Spec::LocalZone( ) ) );
878 
879  displayStr = KGlobal::locale()->formatDateTime( result.toLocalZone() );
880  }
881 
882  if ( !result.isValid() ) {
883  result = incidence->dateTime( Incidence::RoleAlarm );
884  displayStr = IncidenceFormatter::dateTimeToString( result, false,
885  true,
886  KDateTime::Spec::LocalZone() );
887  }
888 
889  return result;
890 }
891 
892 void AlarmDialog::slotCalendarChanged()
893 {
894  KCalCore::Incidence::List incidences = mCalendar->incidences();
895  Akonadi::Item::List items = mCalendar->itemList( incidences );
896  for ( Akonadi::Item::List::ConstIterator it = items.constBegin();
897  it != items.constEnd(); ++it ) {
898  ReminderTreeItem *item = searchByItem( *it );
899 
900  if ( item ) {
901  Incidence::Ptr incidence = CalendarSupport::incidence( *it );
902  QString displayStr;
903 
904  // Yes, alarms can be empty, if someone edited the incidence and removed all alarms
905  if ( !incidence->alarms().isEmpty() ) {
906  const KDateTime dateTime = triggerDateForIncidence( incidence,
907  item->mRemindAt,
908  displayStr );
909 
910  const QString summary = cleanSummary( incidence->summary() );
911 
912  if ( displayStr != item->text( 1 ) || summary != item->text( 0 ) ) {
913  item->setText( 1, displayStr );
914  item->setText( 0, summary );
915  }
916  }
917  }
918  }
919 }
920 
921 void AlarmDialog::keyPressEvent( QKeyEvent *e )
922 {
923  const int key = e->key() | e->modifiers();
924 
925  if ( key == Qt::Key_Enter || key == Qt::Key_Return ) {
926  e->ignore();
927  return;
928  }
929 
930  KDialog::keyPressEvent( e );
931 }
932 
933 bool AlarmDialog::openIncidenceEditorThroughKOrganizer( const Incidence::Ptr &incidence )
934 {
935  if ( !QDBusConnection::sessionBus().interface()->isServiceRegistered( QLatin1String("org.kde.korganizer") ) ) {
936  if ( KToolInvocation::startServiceByDesktopName( QLatin1String("korganizer"), QString() ) ) {
937  KMessageBox::error(
938  this,
939  i18nc( "@info",
940  "Could not start KOrganizer so editing is not possible." ) );
941  return false;
942  }
943  }
944  org::kde::korganizer::Korganizer korganizer(
945  QLatin1String("org.kde.korganizer"), QLatin1String("/Korganizer"), QDBusConnection::sessionBus() );
946 
947  kDebug() << "editing incidence " << incidence->summary();
948  if ( !korganizer.editIncidence( incidence->uid() ) ) {
949  KMessageBox::error(
950  this,
951  i18nc( "@info",
952  "An internal KOrganizer error occurred attempting to modify \"%1\"",
953  cleanSummary( incidence->summary() ) ) );
954  }
955 
956  // get desktop # where korganizer (or kontact) runs
957  QString object =
958  QDBusConnection::sessionBus().interface()->isServiceRegistered( QLatin1String("org.kde.kontact") ) ?
959  QLatin1String("kontact/MainWindow_1") : QLatin1String("korganizer/MainWindow_1");
960  QDBusInterface korganizerObj( QLatin1String("org.kde.korganizer"), QLatin1Char('/') + object );
961 #ifdef Q_WS_X11
962  QDBusReply<int> reply = korganizerObj.call( QLatin1String("winId") );
963  if ( reply.isValid() ) {
964  int window = reply;
965  int desktop = KWindowSystem::windowInfo( window, NET::WMDesktop ).desktop();
966  if ( KWindowSystem::currentDesktop() == desktop ) {
967  KWindowSystem::minimizeWindow( winId(), false );
968  } else {
969  KWindowSystem::setCurrentDesktop( desktop );
970  }
971  KWindowSystem::activateWindow( KWindowSystem::transientFor( window ) );
972  }
973 #elif defined(Q_WS_WIN)
974  // WId is a typedef to a void* on windows
975  QDBusReply<qlonglong> reply = korganizerObj.call( QLatin1String("winId") );
976  if ( reply.isValid() ) {
977  qlonglong window = reply;
978  KWindowSystem::minimizeWindow( winId(), false );
979  KWindowSystem::allowExternalProcessWindowActivation();
980  KWindowSystem::activateWindow( reinterpret_cast<WId>(window) );
981  }
982 #else
983  // TODO (mac)
984 #endif
985 return true;
986 }
987 
988 bool AlarmDialog::openIncidenceEditorNG( const Akonadi::Item &item )
989 {
990  Incidence::Ptr incidence = CalendarSupport::incidence( item );
991  IncidenceEditorNG::IncidenceDialog *dialog =
992  IncidenceEditorNG::IncidenceDialogFactory::create(
993  false, /*doesn't need initial saving*/
994  incidence->type(), 0, this );
995  dialog->load( item );
996  return true;
997 }
998 
999 void AlarmDialog::removeFromConfig( const QList<Akonadi::Item::Id> &ids )
1000 {
1001  KSharedConfig::Ptr config = KGlobal::config();
1002  KConfigGroup genGroup( config, "General" );
1003 
1004  const int oldNumReminders = genGroup.readEntry( "Reminders", 0 );
1005 
1006  QList<ConfItem> newReminders;
1007  // Delete everything
1008  for ( int i = 1; i <= oldNumReminders; ++i ) {
1009  const QString group( QString::fromLatin1( "Incidence-%1" ).arg( i ) );
1010  KConfigGroup incGroup( config, group );
1011  const QString uid = incGroup.readEntry( "UID" );
1012  const QDateTime remindAtDate = incGroup.readEntry( "RemindAt", QDateTime() );
1013  const KUrl akonadiUrl = incGroup.readEntry( "AkonadiUrl" );
1014  const Akonadi::Item::Id id = Akonadi::Item::fromUrl( akonadiUrl ).id();
1015  if ( !ids.contains( id ) ) {
1016  ConfItem ci;
1017  ci.akonadiUrl = akonadiUrl;
1018  ci.remindAt = remindAtDate;
1019  ci.uid = uid;
1020  newReminders.append( ci );
1021  }
1022  config->deleteGroup( group );
1023  }
1024 
1025  genGroup.writeEntry( "Reminders", newReminders.count() );
1026 
1027  //Write everything except those which have an uid we don't want
1028  for ( int i = 0; i < newReminders.count(); ++i ) {
1029  const QString group( QString::fromLatin1( "Incidence-%1" ).arg( i + 1 ) );
1030  KConfigGroup incGroup( config, group );
1031  incGroup.writeEntry( "UID", newReminders[i].uid );
1032  incGroup.writeEntry( "RemindAt", newReminders[i].remindAt );
1033  incGroup.writeEntry( "AkonadiUrl", newReminders[i].akonadiUrl );
1034  incGroup.sync();
1035  }
1036  genGroup.sync();
1037 }
1038 
1039 #include "alarmdialog.moc"
ReminderList
QList< ReminderTreeItem * > ReminderList
Definition: alarmdialog.cpp:140
defSuspendUnit
static int defSuspendUnit
Definition: alarmdialog.cpp:73
AlarmDialog::AlarmDialog
AlarmDialog(const Akonadi::ETMCalendar::Ptr &calendar, QWidget *parent=0)
Definition: alarmdialog.cpp:142
AlarmDialog::slotUser1
void slotUser1()
Definition: alarmdialog.cpp:376
AlarmDialog::reminderCount
void reminderCount(int count)
defSuspendVal
static int defSuspendVal
Definition: alarmdialog.cpp:72
alarmdialog.h
AlarmDialog::closeEvent
void closeEvent(QCloseEvent *)
Definition: alarmdialog.cpp:773
cleanSummary
static QString cleanSummary(const QString &summary)
Definition: alarmdialog.cpp:304
KOrg::MailClient::send
bool send(const KPIMIdentities::Identity &identity, const QString &from, const QString &to, const QString &cc, const QString &subject, const QString &body, bool hidden=false, bool bccMe=false, const QString &attachment=QString(), const QString &mailTransport=QString())
Sends mail with specified from, to and subject field and body as text.
Definition: mailclient.cpp:197
KDialog
AlarmDialog::eventNotification
void eventNotification()
Definition: alarmdialog.cpp:593
AlarmDialog::show
void show()
Definition: alarmdialog.cpp:540
AlarmDialog::accept
void accept()
Definition: alarmdialog.cpp:854
AlarmDialog::suspend
void suspend()
Definition: alarmdialog.cpp:462
AlarmDialog::slotUser2
void slotUser2()
Definition: alarmdialog.cpp:381
AlarmDialog::slotSave
void slotSave()
Definition: alarmdialog.cpp:721
mailclient.h
AlarmDialog::keyPressEvent
void keyPressEvent(QKeyEvent *e)
Definition: alarmdialog.cpp:921
AlarmDialog::slotOk
void slotOk()
Definition: alarmdialog.cpp:371
AlarmDialog::~AlarmDialog
~AlarmDialog()
Definition: alarmdialog.cpp:283
AlarmDialog::dismissCurrent
void dismissCurrent()
Definition: alarmdialog.cpp:391
KOrg::MailClient
Definition: mailclient.h:44
AlarmDialog::slotCalendarChanged
void slotCalendarChanged()
If an incidence changed, for example in korg, we must update the date and summary shown in the list v...
Definition: alarmdialog.cpp:892
AlarmDialog::edit
void edit()
Definition: alarmdialog.cpp:439
AlarmDialog::wakeUp
void wakeUp()
Definition: alarmdialog.cpp:688
AlarmDialog::dismissAll
void dismissAll()
Definition: alarmdialog.cpp:403
AlarmDialog::addIncidence
void addIncidence(const Akonadi::Item &incidence, const QDateTime &reminderAt, const QString &displayText)
Definition: alarmdialog.cpp:318
AlarmDialog::slotUser3
void slotUser3()
Definition: alarmdialog.cpp:386
AlarmDialog::suspendAll
void suspendAll()
Definition: alarmdialog.cpp:576
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:55:50 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

korgac

Skip menu "korgac"
  • Main Page
  • Namespace List
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal