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

korgac

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

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