28 #include "korganizer_interface.h"
31 #include <calendarsupport/next/incidenceviewer.h>
32 #include <calendarsupport/kcalprefs.h>
33 #include <calendarsupport/identitymanager.h>
34 #include <calendarsupport/utils.h>
36 #include <incidenceeditor-ng/incidencedialog.h>
37 #include <incidenceeditor-ng/incidencedialogfactory.h>
39 #include <KCalCore/Event>
40 #include <KCalCore/Todo>
41 #include <KCalUtils/IncidenceFormatter>
43 #include <KPIMIdentities/Identity>
44 #include <KPIMIdentities/IdentityManager>
46 #include <Akonadi/Item>
48 #include <Mailtransport/TransportManager>
54 #include <KMessageBox>
55 #include <KNotification>
56 #include <KSharedConfig>
57 #include <KSystemTimeZone>
58 #include <KToolInvocation>
59 #include <KWindowSystem>
61 #include <phonon/mediaobject.h>
65 #include <QTreeWidget>
66 #include <QVBoxLayout>
68 using namespace KPIMIdentities;
69 using namespace KCalCore;
70 using namespace KCalUtils;
87 ReminderTreeItem(
const Akonadi::Item &incidence,
QTreeWidget *parent )
88 :
QTreeWidgetItem( parent ), mIncidence( incidence ), mNotified( false )
95 const Akonadi::Item mIncidence;
110 switch( treeWidget()->sortColumn() ) {
113 const ReminderTreeItem *item =
static_cast<const ReminderTreeItem *
>( &other );
114 return item->mHappening < mHappening;
118 const ReminderTreeItem *item =
static_cast<const ReminderTreeItem *
>( &other );
119 return item->mTrigger < mTrigger;
127 :
KDialog( parent, Qt::WindowStaysOnTopHint ),
128 mCalendar( calendar ), mSuspendTimer( this )
139 KSharedConfig::Ptr config = KGlobal::config();
140 KConfigGroup generalConfig( config,
"General" );
141 QPoint pos = generalConfig.readEntry(
"Position",
QPoint( 0, 0 ) );
146 topBox->
move( mPos );
148 setMainWidget( topBox );
149 setCaption( i18nc(
"@title:window",
"Reminders" ) );
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" ) );
168 setMinimumWidth( 575 );
169 setMinimumHeight( 300 );
176 "Click on a title to toggle the details viewer for that item" ),
180 mIncidenceTree =
new ReminderTree( topBox );
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" ) );
190 i18nc(
"@info:tooltip",
"The event or to-do title" ) );
193 i18nc(
"@info:tooltip",
"The reminder is set for this date/time" ) );
196 i18nc(
"@info:tooltip",
"The date/time the reminder was triggered" ) );
207 connect( mIncidenceTree, SIGNAL(itemDoubleClicked(
QTreeWidgetItem*,
int)),
209 connect( mIncidenceTree, SIGNAL(itemSelectionChanged()),
210 SLOT(updateButtons()) );
212 mDetailView =
new CalendarSupport::IncidenceViewer( mCalendar.data(), topBox );
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 );
222 KHBox *suspendBox =
new KHBox( topBox );
223 suspendBox->setSpacing( spacingHint() );
226 QLabel *l =
new QLabel( i18nc(
"@label:spinbox",
"Suspend &duration:" ), suspendBox );
228 mSuspendSpin =
new QSpinBox( suspendBox );
232 i18nc(
"@info:tooltip",
233 "Suspend the reminders by this amount of time" ) );
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." ) );
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." ) );
258 connect( &mSuspendTimer, SIGNAL(timeout()), SLOT(
wakeUp()) );
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()) );
265 mIdentityManager =
new CalendarSupport::IdentityManager;
270 mIncidenceTree->
clear();
271 delete mIdentityManager;
274 ReminderTreeItem *AlarmDialog::searchByItem(
const Akonadi::Item &incidence )
276 ReminderTreeItem *found = 0;
279 ReminderTreeItem *item =
static_cast<ReminderTreeItem *
>( *it );
280 if ( item->mIncidence == incidence ) {
291 static QString etc = i18nc(
"@label an elipsis",
"..." );
295 if ( retStr.
length() > maxLen ) {
297 retStr = retStr.
left( maxLen );
307 Incidence::Ptr incidence = CalendarSupport::incidence( incidenceitem );
308 ReminderTreeItem *item = searchByItem( incidenceitem );
310 item =
new ReminderTreeItem( incidenceitem, mIncidenceTree );
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() ) );
320 const KDateTime dateTime = triggerDateForIncidence( incidence, reminderAt,
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")) );
329 item->mHappening = dateTime;
330 item->setText( 1, displayStr );
332 item->setText( 2, IncidenceFormatter::dateTimeToString(
333 item->mTrigger,
false,
true, KDateTime::Spec::LocalZone() ) );
335 IncidenceFormatter::toolTipStr(
336 CalendarSupport::displayName( mCalendar.data(), incidenceitem.parentCollection() ),
338 item->mRemindAt.date(),
true,
339 KDateTime::Spec::LocalZone() );
340 if ( !item->mDisplayText.isEmpty() ) {
343 item->setToolTip( 0, tip );
344 item->setToolTip( 1, tip );
345 item->setToolTip( 2, tip );
346 item->setData( 0, QTreeWidgetItem::UserType,
false );
362 ReminderTreeItem *item = selection.
first();
363 if(mCalendar->hasRight( item->mIncidence, Akonadi::Collection::CanChangeItem )){
381 dismiss( selectedItems() );
383 if ( activeCount() == 0 ) {
397 if ( !(*it)->isDisabled() ) {
398 selections.
append( static_cast<ReminderTreeItem *>( *it ) );
402 dismiss( selections );
409 void AlarmDialog::dismiss( ReminderList selections )
413 kDebug() <<
"removing " << CalendarSupport::incidence( (*it)->mIncidence )->summary();
414 if ( mIncidenceTree->
itemBelow( *it ) ) {
416 }
else if ( mIncidenceTree->
itemAbove( *it ) ) {
420 ids.
append( (*it)->mIncidence.id() );
424 removeFromConfig( ids );
430 if ( selection.
count() != 1 ) {
433 Incidence::Ptr incidence = CalendarSupport::incidence( selection.
first()->mIncidence );
434 if ( !mCalendar->hasRight( selection.
first()->mIncidence, Akonadi::Collection::CanChangeItem ) ) {
438 "\"%1\" is a read-only item so modifications are not possible.",
443 #if !defined(KDEPIM_MOBILE_UI)
444 openIncidenceEditorNG( selection.
first()->mIncidence );
446 openIncidenceEditorThroughKOrganizer( incidence );
452 if ( !isVisible() ) {
457 switch ( mSuspendUnit->currentIndex() ) {
470 ReminderTreeItem *selitem = 0;
473 if ( (*it)->isSelected() && !(*it)->isDisabled() ) {
474 (*it)->setSelected(
false );
475 (*it)->setDisabled(
true );
476 ReminderTreeItem *item =
static_cast<ReminderTreeItem *
>( *it );
478 item->mHappening = KDateTime( item->mRemindAt, KDateTime::Spec::LocalZone() );
479 item->mNotified =
false;
480 (*it)->setText( 1, KGlobal::locale()->formatDateTime( item->mHappening ) );
487 if ( mIncidenceTree->
itemBelow( selitem ) ) {
489 }
else if ( mIncidenceTree->
itemAbove( selitem ) ) {
499 if ( activeCount() == 0 ) {
507 void AlarmDialog::setTimer()
509 int nextReminderAt = -1;
513 ReminderTreeItem *item =
static_cast<ReminderTreeItem *
>( *it );
516 nextReminderAt = nextReminderAt <= 0 ? secs : qMin( nextReminderAt, secs );
521 if ( nextReminderAt >= 0 ) {
522 mSuspendTimer.
stop();
523 mSuspendTimer.
start( 1000 * ( nextReminderAt + 1 ) );
533 mIncidenceTree->
sortItems( 1, Qt::AscendingOrder );
538 ReminderTreeItem *item =
static_cast<ReminderTreeItem *
>( *it );
539 if ( !item->mNotified ) {
540 (*it)->setSelected(
true );
553 KDialog::move( mPos );
555 KWindowSystem::unminimizeWindow( winId(),
false );
556 KWindowSystem::setState( winId(), NET::KeepAbove | NET::DemandsAttention );
557 KWindowSystem::setOnAllDesktops( winId(),
true );
558 KWindowSystem::activateWindow( winId() );
571 if ( !(*it)->isDisabled() ) {
572 (*it)->setSelected(
true );
590 ReminderTreeItem *item =
static_cast<ReminderTreeItem *
>( *it );
592 if ( item->isDisabled() || item->mNotified ) {
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;
604 if ( alarm->type() == Alarm::Procedure ) {
606 kDebug() <<
"Starting program: '" << alarm->programFile() <<
"'";
608 QString program = alarm->programFile();
618 }
else if ( alarm->type() == Alarm::Audio ) {
622 KUrl( alarm->audioFile() ) );
624 connect( player, SIGNAL(finished()), player, SLOT(deleteLater()) );
626 }
else if ( alarm->type() == Alarm::Email ) {
627 QString from = CalendarSupport::KCalPrefs::instance()->email();
628 Identity
id = mIdentityManager->identityForAddress( from );
630 if ( alarm->mailAddresses().isEmpty() ) {
633 const Person::List addresses = alarm->mailAddresses();
635 for ( Person::List::ConstIterator it = addresses.constBegin();
636 it != addresses.constEnd(); ++it ) {
637 add << (*it)->fullName();
644 Akonadi::Item parentItem = mCalendar->item( alarm->parentUid() );
645 Incidence::Ptr parent = CalendarSupport::incidence( parentItem );
647 if ( alarm->mailSubject().isEmpty() ) {
648 if ( parent->summary().isEmpty() ) {
649 subject = i18nc(
"@title",
"Reminder" );
651 subject = i18nc(
"@title",
"Reminder: %1",
cleanSummary( parent->summary() ) );
654 subject = i18nc(
"@title",
"Reminder: %1", alarm->mailSubject() );
658 IncidenceFormatter::mailBodyStr(
659 parent.staticCast<IncidenceBase>(), KSystemTimeZones::local() );
660 if ( !alarm->mailText().isEmpty() ) {
666 MailTransport::TransportManager::self()->defaultTransportName() );
671 if ( !beeped && found ) {
672 KNotification::beep();
678 bool activeReminders =
false;
685 ReminderTreeItem *item =
static_cast<ReminderTreeItem *
>( *it );
686 Incidence::Ptr incidence = CalendarSupport::incidence( item->mIncidence );
689 if ( item->isDisabled() ) {
690 item->setDisabled(
false );
691 item->setSelected(
false );
693 activeReminders =
true;
695 item->setDisabled(
true );
701 if ( activeReminders ) {
705 showDetails( firstItem );
711 KSharedConfig::Ptr config = KGlobal::config();
712 KConfigGroup generalConfig( config,
"General" );
713 int numReminders = 0;
717 ReminderTreeItem *item =
static_cast<ReminderTreeItem *
>( *it );
718 KConfigGroup incidenceConfig( config,
721 Incidence::Ptr incidence = CalendarSupport::incidence( item->mIncidence );
722 incidenceConfig.writeEntry(
"AkonadiUrl", item->mIncidence.url() );
723 incidenceConfig.writeEntry(
"RemindAt", item->mRemindAt );
728 generalConfig.writeEntry(
"Reminders", numReminders );
729 generalConfig.writeEntry(
"Position", pos() );
739 if ( (*it)->isSelected() ) {
740 list.append( static_cast<ReminderTreeItem *>( *it ) );
747 int AlarmDialog::activeCount()
752 if ( !(*it)->isDisabled() ) {
757 kDebug() <<
"computed " << count <<
" active reminders";
767 void AlarmDialog::updateButtons()
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 );
775 ReminderTreeItem *item = selection.first();
776 enableButton( User1, (mCalendar->hasRight( item->mIncidence, Akonadi::Collection::CanChangeItem )));
778 enableButton( User1,
false);
780 enableButton( Ok, enabled );
789 if ( !mDetailView->isHidden() ) {
790 if ( mLastItem == item ) {
791 resize( size().width(), size().height() - mDetailView->height() - 50 );
797 resize( size().width(), size().height() + mDetailView->height() + 50 );
810 ReminderTreeItem *reminderItem =
dynamic_cast<ReminderTreeItem *
>( item );
812 if ( !reminderItem ) {
813 mDetailView->setIncidence( Akonadi::Item() );
815 if ( !reminderItem->mDisplayText.isEmpty() ) {
817 mDetailView->setHeaderText( txt );
819 mDetailView->setHeaderText(
QString() );
821 mDetailView->setIncidence( reminderItem->mIncidence, reminderItem->mRemindAt.date() );
825 void AlarmDialog::update()
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 );
839 if ( activeCount() == 0 ) {
846 KDateTime AlarmDialog::triggerDateForIncidence(
const Incidence::Ptr &incidence,
852 if ( incidence->alarms().isEmpty() ) {
856 Alarm::Ptr alarm = incidence->alarms().first();
858 if ( incidence->recurs() ) {
859 result = incidence->recurrence()->getNextDateTime(
860 KDateTime( reminderAt, KDateTime::Spec::LocalZone( ) ) );
862 displayStr = KGlobal::locale()->formatDateTime( result.toLocalZone() );
865 if ( !result.isValid() ) {
866 result = incidence->dateTime( Incidence::RoleAlarm );
867 displayStr = IncidenceFormatter::dateTimeToString( result,
false,
869 KDateTime::Spec::LocalZone() );
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 );
884 Incidence::Ptr incidence = CalendarSupport::incidence( *it );
888 if ( !incidence->alarms().isEmpty() ) {
889 const KDateTime dateTime = triggerDateForIncidence( incidence,
895 if ( displayStr != item->text( 1 ) || summary != item->text( 0 ) ) {
896 item->setText( 1, displayStr );
897 item->setText( 0, summary );
908 if ( key == Qt::Key_Enter || key == Qt::Key_Return ) {
913 KDialog::keyPressEvent( e );
916 bool AlarmDialog::openIncidenceEditorThroughKOrganizer(
const Incidence::Ptr &incidence )
923 "Could not start KOrganizer so editing is not possible." ) );
927 org::kde::korganizer::Korganizer korganizer(
930 kDebug() <<
"editing incidence " << incidence->summary();
931 if ( !korganizer.editIncidence( incidence->uid() ) ) {
935 "An internal KOrganizer error occurred attempting to modify \"%1\"",
948 int desktop = KWindowSystem::windowInfo( window, NET::WMDesktop ).desktop();
949 if ( KWindowSystem::currentDesktop() == desktop ) {
950 KWindowSystem::minimizeWindow( winId(),
false );
952 KWindowSystem::setCurrentDesktop( desktop );
954 KWindowSystem::activateWindow( KWindowSystem::transientFor( window ) );
956 #elif defined(Q_WS_WIN)
960 qlonglong window = reply;
961 KWindowSystem::minimizeWindow( winId(),
false );
962 KWindowSystem::allowExternalProcessWindowActivation();
963 KWindowSystem::activateWindow( reinterpret_cast<WId>(window) );
971 bool AlarmDialog::openIncidenceEditorNG(
const Akonadi::Item &item )
973 Incidence::Ptr incidence = CalendarSupport::incidence( item );
974 IncidenceEditorNG::IncidenceDialog *dialog =
975 IncidenceEditorNG::IncidenceDialogFactory::create(
977 incidence->type(), 0, this );
978 dialog->load( item );
984 KSharedConfig::Ptr config = KGlobal::config();
985 KConfigGroup genGroup( config,
"General" );
987 const int oldNumReminders = genGroup.readEntry(
"Reminders", 0 );
991 for (
int i = 1; i <= oldNumReminders; ++i ) {
993 KConfigGroup incGroup( config, group );
994 const QString uid = incGroup.readEntry(
"UID" );
996 const KUrl akonadiUrl = incGroup.readEntry(
"AkonadiUrl" );
997 const Akonadi::Item::Id
id = Akonadi::Item::fromUrl( akonadiUrl ).id();
1000 ci.akonadiUrl = akonadiUrl;
1001 ci.remindAt = remindAtDate;
1003 newReminders.
append( ci );
1005 config->deleteGroup( group );
1008 genGroup.writeEntry(
"Reminders", newReminders.
count() );
1011 for (
int i = 0; i < newReminders.
count(); ++i ) {
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 );
Qt::KeyboardModifiers modifiers() const
static int defSuspendUnit
void setSelectionMode(QAbstractItemView::SelectionMode mode)
void setWordWrap(bool on)
AlarmDialog(const Akonadi::ETMCalendar::Ptr &calendar, QWidget *parent=0)
void reminderCount(int count)
void closeEvent(QCloseEvent *)
QDBusConnectionInterface * interface() const
static QString cleanSummary(const QString &summary)
bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
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.
QDBusConnection sessionBus()
QString join(const QString &separator) const
MediaObject * createPlayer(Phonon::Category category, const MediaSource &source)
QDBusReply< bool > isServiceRegistered(const QString &serviceName) const
void setRange(int minimum, int maximum)
void setBuddy(QWidget *buddy)
int count(const T &value) const
void append(const T &value)
void resizeColumnToContents(int column)
void keyPressEvent(QKeyEvent *e)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
void setAllColumnsShowFocus(bool enable)
void setParent(QObject *parent)
bool contains(QChar ch, Qt::CaseSensitivity cs) const
void slotCalendarChanged()
If an incidence changed, for example in korg, we must update the date and summary shown in the list v...
bool contains(const T &value) const
QString & replace(int position, int n, QChar after)
void setSortingEnabled(bool enable)
QDateTime currentDateTime()
int secsTo(const QDateTime &other) const
QString left(int n) const
QString fromLatin1(const char *str, int size)
QDateTime addSecs(int s) const
void setRootIsDecorated(bool show)
void addIncidence(const Akonadi::Item &incidence, const QDateTime &reminderAt, const QString &displayText)
void setSingleShot(bool singleShot)