28 #include <KontactInterface/Core>
29 #include <KontactInterface/Plugin>
31 #include <calendarsupport/utils.h>
32 #include <calendarsupport/calendarsingleton.h>
33 #include <Akonadi/ItemFetchJob>
34 #include <Akonadi/ItemFetchScope>
35 #include <Akonadi/EntityDisplayAttribute>
36 #include <Akonadi/Contact/ContactSearchJob>
37 #include <Akonadi/Contact/ContactViewerDialog>
39 #include <KCalCore/Calendar>
42 #include <KLocalizedString>
45 #include <KIconLoader>
46 #include <KConfigGroup>
47 #include <KToolInvocation>
48 #include <KHolidays/Holidays>
53 #include <QGridLayout>
55 using namespace KHolidays;
57 class BirthdaySearchJob :
public Akonadi::ItemSearchJob
60 BirthdaySearchJob(
QObject *parent,
int daysInAdvance );
63 BirthdaySearchJob::BirthdaySearchJob(
QObject *parent,
int daysInAdvance )
64 : ItemSearchJob(
QString(), parent )
66 fetchScope().fetchFullPayload();
68 "prefix nco:<http://www.semanticdesktop.org/ontologies/2007/03/22/nco#> "
69 "prefix xsd:<http://www.w3.org/2001/XMLSchema#> "
76 " ?r a nco:PersonContact . "
77 " ?r <%1> ?akonadiItemId . "
78 " ?r nco:birthDate ?birthDate . "
79 " FILTER( bif:dayofyear(?birthDate) >= bif:dayofyear(xsd:date(\"%2\")) ) "
80 " FILTER( bif:dayofyear(?birthDate) <= bif:dayofyear(xsd:date(\"%2\")) + %3 ) "
84 " ?r a nco:PersonContact . "
85 " ?r <%1> ?akonadiItemId . "
86 " ?r nco:birthDate ?birthDate . "
87 " FILTER( bif:dayofyear(?birthDate) + 365 >= bif:dayofyear(xsd:date(\"%2\")) ) "
88 " FILTER( bif:dayofyear(?birthDate) + 365 <= bif:dayofyear(xsd:date(\"%2\")) + %3 ) "
95 Akonadi::ItemSearchJob::setQuery( query );
121 KABC::Addressee addressee;
124 bool operator<(
const SDEntry &entry )
const
126 return daysTo < entry.daysTo;
131 : KontactInterface::Summary( parent ), mPlugin( plugin ), mHolidays( 0 )
133 mCalendar = CalendarSupport::calendarSingleton();
140 QWidget *header = createHeader(
141 this,
QLatin1String(
"favorites"), i18n(
"Upcoming Special Dates" ) );
145 mainLayout->
addItem( mLayout );
151 mShowBirthdaysFromKAB =
true;
152 mShowBirthdaysFromCal =
true;
153 mShowAnniversariesFromKAB =
true;
154 mShowAnniversariesFromCal =
true;
155 mShowHolidays =
true;
157 mShowSpecialsFromCal =
true;
160 connect( mPlugin->core(), SIGNAL(dayChanged(
QDate)),
161 this, SLOT(updateView()) );
163 connect( mCalendar.data(), SIGNAL(calendarChanged()),
164 this, SLOT(updateView()) );
165 connect( mPlugin->core(), SIGNAL(dayChanged(
QDate)),
166 this, SLOT(updateView()) );
181 KConfigGroup group = config.group(
"Days" );
182 mDaysAhead = group.readEntry(
"DaysToShow", 7 );
184 group = config.group(
"Show" );
185 mShowBirthdaysFromKAB = group.readEntry(
"BirthdaysFromContacts",
true );
186 mShowBirthdaysFromCal = group.readEntry(
"BirthdaysFromCalendar",
true );
188 mShowAnniversariesFromKAB = group.readEntry(
"AnniversariesFromContacts",
true );
189 mShowAnniversariesFromCal = group.readEntry(
"AnniversariesFromCalendar",
true );
191 mShowHolidays = group.readEntry(
"HolidaysFromCalendar",
true );
193 mShowSpecialsFromCal = group.readEntry(
"SpecialsFromCalendar",
true );
195 group = config.group(
"Groupware" );
196 mShowMineOnly = group.readEntry(
"ShowMineOnly",
false );
201 bool SDSummaryWidget::initHolidays()
204 KConfigGroup hconfig( &_hconfig,
"Time & Date" );
205 QString location = hconfig.readEntry(
"Holidays" );
208 mHolidays =
new HolidayRegion( location );
215 int SDSummaryWidget::span(
const KCalCore::Event::Ptr &event )
const
218 if ( event->isMultiDay() &&
event->allDay() ) {
219 QDate d =
event->dtStart().date();
223 while ( d < event->dtEnd().
date() ) {
232 int SDSummaryWidget::dayof(
const KCalCore::Event::Ptr &event,
const QDate &
date )
const
235 QDate d =
event->dtStart().date();
239 while ( d < event->dtEnd().
date() ) {
248 void SDSummaryWidget::slotBirthdayJobFinished(
KJob *job )
251 BirthdaySearchJob* bJob =
dynamic_cast< BirthdaySearchJob *
>( job );
253 foreach (
const Akonadi::Item &item, bJob->items() ) {
254 if ( item.hasPayload<KABC::Addressee>() ) {
255 const KABC::Addressee addressee = item.payload<KABC::Addressee>();
256 const QDate birthday = addressee.birthday().date();
257 if ( birthday.isValid() ) {
261 dateDiff( birthday, entry.daysTo, entry.yearsOld );
263 entry.date = birthday;
264 entry.addressee = addressee;
278 void SDSummaryWidget::createLabels()
286 setUpdatesEnabled(
false );
287 foreach ( label, mLabels ) {
298 KCalCore::Event::List events = mCalendar->events( dt, mCalendar->timeSpec(),
299 KCalCore::EventSortStartDate,
300 KCalCore::SortDirectionAscending );
301 foreach (
const KCalCore::Event::Ptr &ev, events ) {
311 if ( ev->customProperty(
"KABC",
"BIRTHDAY" ) ==
QLatin1String(
"YES") ) {
317 if ( !ev->categoriesStr().isEmpty() ) {
321 for ( it2 = c.
constBegin(); it2 != end; ++it2 ) {
323 const QString itUpper((*it2).toUpper());
325 if ( mShowBirthdaysFromCal && ( itUpper ==
QLatin1String(
"BIRTHDAY") ) ) {
330 entry.summary = ev->summary();
331 entry.desc = ev->description();
332 dateDiff( ev->dtStart().date(), entry.daysTo, entry.yearsOld );
347 if ( mShowAnniversariesFromCal && ( itUpper ==
QLatin1String(
"ANNIVERSARY") ) ) {
352 entry.summary = ev->summary();
353 entry.desc = ev->description();
354 dateDiff( ev->dtStart().date(), entry.daysTo, entry.yearsOld );
363 if ( mShowHolidays && ( itUpper ==
QLatin1String(
"HOLIDAY") ) ) {
368 entry.summary = ev->summary();
369 entry.desc = ev->description();
370 dateDiff( dt, entry.daysTo, entry.yearsOld );
372 entry.span = span( ev );
373 if ( entry.span > 1 && dayof( ev, dt ) > 1 ) {
381 if ( mShowSpecialsFromCal && ( itUpper ==
QLatin1String(
"SPECIAL OCCASION") ) ) {
386 entry.summary = ev->summary();
387 entry.desc = ev->description();
388 dateDiff( dt, entry.daysTo, entry.yearsOld );
390 entry.span = span( ev );
391 if ( entry.span > 1 && dayof( ev, dt ) > 1 ) {
403 if ( mShowHolidays ) {
404 if ( initHolidays() ) {
410 for ( ; it != holidays.
constEnd(); ++it ) {
413 entry.category = ( (*it).dayType() == Holiday::NonWorkday )?
416 entry.summary = (*it).text();
417 dateDiff( dt, entry.daysTo, entry.yearsOld );
434 for ( addrIt = mDates.
begin(); addrIt != addrEnd; ++addrIt ) {
435 const bool makeBold = (*addrIt).daysTo == 0;
441 switch( (*addrIt).category ) {
444 pic = (*addrIt).addressee.photo();
445 if ( pic.isIntern() && !pic.data().isNull() ) {
455 icon_name =
QLatin1String(
"view-calendar-wedding-anniversary");
456 pic = (*addrIt).addressee.photo();
457 if ( pic.isIntern() && !pic.data().isNull() ) {
473 label =
new QLabel(
this );
474 if ( icon_img.
isNull() ) {
475 label->
setPixmap( KIconLoader::global()->loadIcon( icon_name, KIconLoader::Small ) );
489 QDate sD =
QDate( year, (*addrIt).date.month(), (*addrIt).date.day() );
491 if ( (*addrIt).daysTo == 0 ) {
492 datestr = i18nc(
"the special day is today",
"Today" );
493 }
else if ( (*addrIt).daysTo == 1 ) {
494 datestr = i18nc(
"the special day is tomorrow",
"Tomorrow" );
496 datestr = KGlobal::locale()->formatDate( sD, KLocale::FancyLongDate );
500 if ( (*addrIt).span > 1 ) {
502 KGlobal::locale()->formatDate( sD.
addDays( (*addrIt).span - 1 ) );
506 label =
new QLabel( datestr,
this );
507 label->
setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
517 label =
new QLabel(
this );
518 if ( (*addrIt).daysTo == 0 ) {
519 label->
setText( i18n(
"now" ) );
521 label->
setText( i18np(
"in 1 day",
"in %1 days", (*addrIt).daysTo ) );
524 label->
setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
530 switch( (*addrIt).category ) {
532 what = i18n(
"Birthday" );
535 what = i18n(
"Anniversary" );
538 what = i18n(
"Holiday" );
541 what = i18n(
"Special Occasion" );
544 label =
new QLabel(
this );
546 label->
setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
552 KUrlLabel *urlLabel =
new KUrlLabel(
this );
553 urlLabel->installEventFilter(
this );
554 urlLabel->setUrl( (*addrIt).item.url( Akonadi::Item::UrlWithMimeType ).url() );
555 urlLabel->setText( (*addrIt).addressee.realName() );
556 urlLabel->setTextFormat( Qt::RichText );
557 urlLabel->setWordWrap(
true );
558 mLayout->
addWidget( urlLabel, counter, 4 );
559 mLabels.
append( urlLabel );
561 connect( urlLabel, SIGNAL(leftClickedUrl(
QString)),
562 this, SLOT(mailContact(
QString)) );
563 connect( urlLabel, SIGNAL(rightClickedUrl(
QString)),
564 this, SLOT(popupMenu(
QString)) );
566 label =
new QLabel(
this );
567 label->
setText( (*addrIt).summary );
571 if ( !(*addrIt).desc.isEmpty() ) {
579 label =
new QLabel(
this );
580 if ( (*addrIt).yearsOld <= 0 ) {
583 label->
setText( i18np(
"one year",
"%1 years", (*addrIt).yearsOld ) );
585 label->
setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
594 i18np(
"No special dates within the next 1 day",
595 "No special dates pending within the next %1 days",
596 mDaysAhead ),
this );
597 label->
setAlignment( Qt::AlignHCenter | Qt::AlignVCenter );
604 for ( lit = mLabels.
constBegin(); lit != endLit; ++lit ) {
607 setUpdatesEnabled(
true );
610 void SDSummaryWidget::updateView()
633 if ( mShowBirthdaysFromKAB && !mJobRunning ) {
634 BirthdaySearchJob *job =
new BirthdaySearchJob(
this, mDaysAhead );
636 connect( job, SIGNAL(result(
KJob*)),
this, SLOT(slotBirthdayJobFinished(
KJob*)) );
644 void SDSummaryWidget::mailContact(
const QString &url )
646 const Akonadi::Item item = Akonadi::Item::fromUrl( url );
647 if ( !item.isValid() ) {
652 Akonadi::ItemFetchJob *job =
new Akonadi::ItemFetchJob( item,
this );
653 job->fetchScope().fetchFullPayload();
654 connect( job, SIGNAL(result(
KJob*)), SLOT(slotItemFetchJobDone(
KJob*)) );
657 void SDSummaryWidget::slotItemFetchJobDone(
KJob* job)
659 if ( job->error() ) {
660 kWarning() << job->errorString();
663 const Akonadi::Item::List lst = qobject_cast<Akonadi::ItemFetchJob*>( job )->items();
664 if ( lst.isEmpty() ) {
667 const KABC::Addressee contact = lst.first().payload<KABC::Addressee>();
669 KToolInvocation::invokeMailer( contact.fullEmail(),
QString() );
672 void SDSummaryWidget::viewContact(
const QString &url )
674 const Akonadi::Item item = Akonadi::Item::fromUrl( url );
675 if ( !item.isValid() ) {
676 kDebug() <<
"Invalid item found";
680 Akonadi::ContactViewerDialog dlg(
this );
681 dlg.setContact( item );
685 void SDSummaryWidget::popupMenu(
const QString &url )
688 const QAction *sendMailAction = popup.addAction(
689 KIconLoader::global()->loadIcon(
QLatin1String(
"mail-message-new"), KIconLoader::Small ),
690 i18n(
"Send &Mail" ) );
691 const QAction *viewContactAction = popup.addAction(
692 KIconLoader::global()->loadIcon(
QLatin1String(
"view-pim-contacts"), KIconLoader::Small ),
693 i18n(
"View &Contact" ) );
696 if ( ret == sendMailAction ) {
698 }
else if ( ret == viewContactAction ) {
705 if ( obj->
inherits(
"KUrlLabel" ) ) {
706 KUrlLabel* label =
static_cast<KUrlLabel*
>( obj );
707 if ( e->
type() == QEvent::Enter ) {
708 emit message( i18n(
"Mail to:\"%1\"", label->text() ) );
710 if ( e->
type() == QEvent::Leave ) {
711 emit message( QString::null );
715 return KontactInterface::Summary::eventFilter( obj, e );
718 void SDSummaryWidget::dateDiff(
const QDate &date,
int &days,
int &years )
const
737 int offset = currentDate.
daysTo( eventDate );
int daysTo(const QDate &d) const
QImage scaledToWidth(int width, Qt::TransformationMode mode) const
void setPixmap(const QPixmap &)
void setAlignment(QFlags< Qt::AlignmentFlag >)
QPixmap fromImage(const QImage &image, QFlags< Qt::ImageConversionFlag > flags)
QImage scaledToHeight(int height, Qt::TransformationMode mode) const
void setSpacing(int spacing)
void setBold(bool enable)
void append(const T &value)
void setRowStretch(int row, int stretch)
bool inherits(const char *className) const
virtual void addItem(QLayoutItem *item)
void setTextFormat(Qt::TextFormat)
void setText(const QString &)
void setMargin(int margin)
bool isLeapYear(int year)
char * toString(const T &value)
virtual QSize minimumSizeHint() const
QString fromLatin1(const char *str, int size)
QDate addDays(int ndays) const
const_iterator constEnd() const
const_iterator constBegin() const
void setSpacing(int spacing)