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)