28 #include "korganizer/korganizerinterface.h"
30 #include <calendarsupport/utils.h>
31 #include <calendarsupport/calendarsingleton.h>
33 #include <Akonadi/Collection>
34 #include <Akonadi/ItemFetchScope>
35 #include <Akonadi/Calendar/IncidenceChanger>
37 #include <KCalUtils/IncidenceFormatter>
39 #include <KontactInterface/Core>
41 #include <KConfigGroup>
42 #include <KIconLoader>
45 #include <KSystemTimeZones>
48 #include <QGridLayout>
50 #include <QTextDocument>
51 #include <QVBoxLayout>
53 using namespace KCalUtils;
56 : KontactInterface::Summary( parent ), mPlugin( plugin )
58 QVBoxLayout *mainLayout =
new QVBoxLayout(
this );
59 mainLayout->setSpacing( 3 );
60 mainLayout->setMargin( 3 );
62 QWidget *header = createHeader(
this, QLatin1String(
"korg-todo"), i18n(
"Pending To-dos" ) );
63 mainLayout->addWidget( header );
65 mLayout =
new QGridLayout();
66 mainLayout->addItem( mLayout );
67 mLayout->setSpacing( 3 );
68 mLayout->setRowStretch( 6, 1 );
69 mCalendar = CalendarSupport::calendarSingleton();
71 mChanger =
new Akonadi::IncidenceChanger( parent );
73 connect( mCalendar.data(), SIGNAL(calendarChanged()), SLOT(updateView()) );
74 connect( mPlugin->core(), SIGNAL(dayChanged(QDate)), SLOT(updateView()) );
83 void TodoSummaryWidget::updateView()
85 qDeleteAll( mLabels );
88 KConfig config( QLatin1String(
"kcmtodosummaryrc") );
89 KConfigGroup group = config.group(
"Days" );
90 int mDaysToGo = group.readEntry(
"DaysToShow", 7 );
92 group = config.group(
"Hide" );
93 mHideInProgress = group.readEntry(
"InProgress",
false );
94 mHideOverdue = group.readEntry(
"Overdue",
false );
95 mHideCompleted = group.readEntry(
"Completed",
true );
96 mHideOpenEnded = group.readEntry(
"OpenEnded",
true );
97 mHideNotStarted = group.readEntry(
"NotStarted",
false );
99 group = config.group(
"Groupware" );
100 mShowMineOnly = group.readEntry(
"ShowMineOnly",
false );
114 KCalCore::Todo::List prList;
116 const QDate currDate = QDate::currentDate();
117 KCalCore::Todo::List todos = mCalendar->todos();
118 Q_FOREACH (
const KCalCore::Todo::Ptr &todo, todos ) {
119 if ( todo->hasDueDate() ) {
120 const int daysTo = currDate.daysTo( todo->dtDue().date() );
121 if ( daysTo >= mDaysToGo ) {
126 if ( mHideOverdue && todo->isOverdue() ) {
129 if ( mHideInProgress && todo->isInProgress(
false ) ) {
132 if ( mHideCompleted && todo->isCompleted() ) {
135 if ( mHideOpenEnded && todo->isOpenEnded() ) {
138 if ( mHideNotStarted && todo->isNotStarted(
false ) ) {
142 prList.append( todo );
144 if ( !prList.isEmpty() ) {
145 prList = Akonadi::ETMCalendar::sortTodos( prList,
146 KCalCore::TodoSortSummary,
147 KCalCore::SortDirectionAscending );
148 prList = Akonadi::ETMCalendar::sortTodos( prList,
149 KCalCore::TodoSortPriority,
150 KCalCore::SortDirectionAscending );
151 prList = Akonadi::ETMCalendar::sortTodos( prList,
152 KCalCore::TodoSortDueDate,
153 KCalCore::SortDirectionAscending );
175 if ( !prList.isEmpty() ) {
177 KIconLoader loader( QLatin1String(
"korganizer") );
178 QPixmap pm = loader.loadIcon( QLatin1String(
"view-calendar-tasks"), KIconLoader::Small );
182 Q_FOREACH (
const KCalCore::Todo::Ptr &todo, prList ) {
183 bool makeBold =
false;
195 label =
new QLabel(
this );
196 label->setPixmap( pm );
197 label->setMaximumWidth( label->minimumSizeHint().width() );
198 mLayout->addWidget( label, counter, 0 );
199 mLabels.append( label );
203 if ( todo->hasDueDate() && todo->dtDue().date().isValid() ) {
204 daysTo = currDate.daysTo( todo->dtDue().date() );
208 str = i18nc(
"the to-do is due today",
"Today" );
209 }
else if ( daysTo == 1 ) {
210 str = i18nc(
"the to-do is due tomorrow",
"Tomorrow" );
212 str = KGlobal::locale()->formatDate( todo->dtDue().date(), KLocale::FancyLongDate );
216 label =
new QLabel( str,
this );
217 label->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
218 mLayout->addWidget( label, counter, 1 );
219 mLabels.append( label );
221 QFont font = label->font();
222 font.setBold(
true );
223 label->setFont( font );
228 if ( todo->hasDueDate() && todo->dtDue().date().isValid() ) {
230 str = i18np(
"in 1 day",
"in %1 days", daysTo );
231 }
else if ( daysTo < 0 ) {
232 str = i18np(
"1 day ago",
"%1 days ago", -daysTo );
234 str = i18nc(
"the to-do is due",
"due" );
237 label =
new QLabel( str,
this );
238 label->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
239 mLayout->addWidget( label, counter, 2 );
240 mLabels.append( label );
243 str = QLatin1Char(
'[') + QString::number( todo->priority() ) + QLatin1Char(
']');
244 label =
new QLabel( str,
this );
245 label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
246 mLayout->addWidget( label, counter, 3 );
247 mLabels.append( label );
250 str = todo->summary();
251 if ( !todo->relatedTo().isEmpty() ) {
252 KCalCore::Incidence::Ptr inc = mCalendar->incidence( todo->relatedTo() );
254 str = inc->summary() + QLatin1Char(
':') + str;
257 if ( !Qt::mightBeRichText( str ) ) {
258 str = Qt::escape( str );
261 KUrlLabel *urlLabel =
new KUrlLabel(
this );
262 urlLabel->setText( str );
263 urlLabel->setUrl( todo->uid() );
264 urlLabel->installEventFilter(
this );
265 urlLabel->setTextFormat( Qt::RichText );
266 urlLabel->setWordWrap(
true );
267 mLayout->addWidget( urlLabel, counter, 4 );
268 mLabels.append( urlLabel );
270 connect( urlLabel, SIGNAL(leftClickedUrl(QString)),
271 this, SLOT(viewTodo(QString)) );
272 connect( urlLabel, SIGNAL(rightClickedUrl(QString)),
273 this, SLOT(popupMenu(QString)) );
276 QString tipText( IncidenceFormatter::toolTipStr(
277 IncidenceFormatter::resourceString( mCalendar, todo ),
278 todo, currDate,
true, KSystemTimeZones::local() ) );
279 if ( !tipText.isEmpty() ) {
280 urlLabel->setToolTip( tipText );
284 str = stateStr( todo );
285 label =
new QLabel( str,
this );
286 label->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
287 mLayout->addWidget( label, counter, 5 );
288 mLabels.append( label );
294 if ( counter == 0 ) {
296 i18np(
"No pending to-dos due within the next day",
297 "No pending to-dos due within the next %1 days",
299 noTodos->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter );
300 mLayout->addWidget( noTodos, 0, 0 );
301 mLabels.append( noTodos );
304 Q_FOREACH ( label, mLabels ) {
309 void TodoSummaryWidget::viewTodo(
const QString &uid )
311 Akonadi::Item::Id
id = mCalendar->item( uid ).id();
314 mPlugin->core()->selectPlugin(QLatin1String(
"kontact_todoplugin") );
315 OrgKdeKorganizerKorganizerInterface korganizer(
316 QLatin1String(
"org.kde.korganizer"), QLatin1String(
"/Korganizer"), QDBusConnection::sessionBus() );
318 korganizer.editIncidence( QString::number(
id ) );
322 void TodoSummaryWidget::removeTodo(
const Akonadi::Item &item )
324 mChanger->deleteIncidence( item );
327 void TodoSummaryWidget::completeTodo( Akonadi::Item::Id
id )
329 Akonadi::Item todoItem = mCalendar->item(
id );
331 if ( todoItem.isValid() ) {
332 KCalCore::Todo::Ptr todo = CalendarSupport::todo( todoItem );
333 if ( !todo->isReadOnly() ) {
334 KCalCore::Todo::Ptr oldTodo( todo->clone() );
335 todo->setCompleted( KDateTime::currentLocalDateTime() );
336 mChanger->modifyIncidence( todoItem, oldTodo );
342 void TodoSummaryWidget::popupMenu(
const QString &uid )
344 KCalCore::Todo::Ptr todo = mCalendar->todo( uid );
347 Akonadi::Item item = mCalendar->item( uid );
349 QAction *editIt = popup.addAction( i18n(
"&Edit To-do..." ) );
350 QAction *delIt = popup.addAction( i18n(
"&Delete To-do" ) );
351 delIt->setIcon( KIconLoader::global()->loadIcon( QLatin1String(
"edit-delete"), KIconLoader::Small ) );
354 delIt->setEnabled( mCalendar->hasRight( item, Akonadi::Collection::CanDeleteItem ) );
356 if ( !todo->isCompleted() ) {
357 doneIt = popup.addAction( i18n(
"&Mark To-do Completed" ) );
358 doneIt->setIcon( KIconLoader::global()->loadIcon( QLatin1String(
"task-complete"), KIconLoader::Small ) );
359 doneIt->setEnabled( mCalendar->hasRight( item, Akonadi::Collection::CanChangeItem ) );
363 const QAction *selectedAction = popup.exec( QCursor::pos() );
364 if ( selectedAction == editIt ) {
366 }
else if ( selectedAction == delIt ) {
368 }
else if ( doneIt && selectedAction == doneIt ) {
369 completeTodo( item.id() );
375 if ( obj->inherits(
"KUrlLabel" ) ) {
376 KUrlLabel* label =
static_cast<KUrlLabel*
>( obj );
377 if ( e->type() == QEvent::Enter ) {
378 emit message( i18n(
"Edit To-do: \"%1\"", label->text() ) );
380 if ( e->type() == QEvent::Leave ) {
381 emit message( QString::null );
384 return KontactInterface::Summary::eventFilter( obj, e );
389 return QStringList() << QLatin1String(
"kcmtodosummary.desktop" );
392 bool TodoSummaryWidget::startsToday(
const KCalCore::Todo::Ptr &todo )
394 return todo->hasStartDate() &&
395 todo->dtStart().date() == QDate::currentDate();
398 const QString TodoSummaryWidget::stateStr(
const KCalCore::Todo::Ptr &todo )
402 if ( todo->isOpenEnded() ) {
403 str1 = i18n(
"open-ended" );
404 }
else if ( todo->isOverdue() ) {
405 str1 = QLatin1String(
"<font color=\"red\">") +
406 i18nc(
"the to-do is overdue",
"overdue" ) +
407 QLatin1String(
"</font>");
408 }
else if ( startsToday( todo ) ) {
409 str1 = i18nc(
"the to-do starts today",
"starts today" );
412 if ( todo->isNotStarted(
false ) ) {
413 str2 += i18nc(
"the to-do has not been started yet",
"not-started" );
414 }
else if ( todo->isCompleted() ) {
415 str2 += i18nc(
"the to-do is completed",
"completed" );
416 }
else if ( todo->isInProgress(
false ) ) {
417 str2 += i18nc(
"the to-do is in-progress",
"in-progress " );
418 str2 += QLatin1String(
" (") + QString::number( todo->percentComplete() ) + QLatin1String(
"%)");
421 if ( !str1.isEmpty() && !str2.isEmpty() ) {
422 str1 += i18nc(
"Separator for status like this: overdue, completed",
"," );
428 #include "todosummarywidget.moc"