00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <qcursor.h>
00026 #include <qlabel.h>
00027 #include <qlayout.h>
00028 #include <qimage.h>
00029 #include <qtooltip.h>
00030
00031 #include <dcopclient.h>
00032 #include <dcopref.h>
00033 #include <kabc/stdaddressbook.h>
00034 #include <libkdepim/stdcalendar.h>
00035 #include <kapplication.h>
00036 #include <kdialog.h>
00037 #include <kglobal.h>
00038 #include <kiconloader.h>
00039 #include <klocale.h>
00040 #include <kparts/part.h>
00041 #include <kpopupmenu.h>
00042 #include <kstandarddirs.h>
00043 #include <kurllabel.h>
00044 #include <libkcal/event.h>
00045 #include <libkcal/resourcecalendar.h>
00046 #include <libkcal/resourcelocal.h>
00047 #include <libkdepim/kpimprefs.h>
00048
00049 #include "core.h"
00050 #include "plugin.h"
00051
00052 #include "sdsummarywidget.h"
00053
00054 enum SDIncidenceType {
00055 IncidenceTypeContact, IncidenceTypeEvent
00056 };
00057 enum SDCategory {
00058 CategoryBirthday, CategoryAnniversary, CategoryHoliday, CategoryOther
00059 };
00060
00061 class SDEntry
00062 {
00063 public:
00064 SDIncidenceType type;
00065 SDCategory category;
00066 int yearsOld;
00067 int daysTo;
00068 QDate date;
00069 QString summary;
00070 QString desc;
00071 int span;
00072 KABC::Addressee addressee;
00073
00074 bool operator<( const SDEntry &entry ) const
00075 {
00076 return daysTo < entry.daysTo;
00077 }
00078 };
00079
00080 SDSummaryWidget::SDSummaryWidget( Kontact::Plugin *plugin, QWidget *parent,
00081 const char *name )
00082 : Kontact::Summary( parent, name ), mPlugin( plugin ), mCalendar( 0 ), mHolidays( 0 )
00083 {
00084
00085 QVBoxLayout *mainLayout = new QVBoxLayout( this, 3, 3 );
00086
00087 QPixmap icon = KGlobal::iconLoader()->loadIcon( "cookie",
00088 KIcon::Desktop, KIcon::SizeMedium );
00089
00090 QWidget *header = createHeader( this, icon, i18n( "Special Dates" ) );
00091 mainLayout->addWidget(header);
00092
00093 mLayout = new QGridLayout( mainLayout, 7, 6, 3 );
00094 mLayout->setRowStretch( 6, 1 );
00095
00096
00097 KABC::StdAddressBook *ab = KABC::StdAddressBook::self( true );
00098 connect( ab, SIGNAL( addressBookChanged( AddressBook* ) ),
00099 this, SLOT( updateView() ) );
00100 connect( mPlugin->core(), SIGNAL( dayChanged( const QDate& ) ),
00101 this, SLOT( updateView() ) );
00102
00103
00104 mCalendar = KCal::StdCalendar::self();
00105
00106 connect( mCalendar, SIGNAL( calendarChanged() ),
00107 this, SLOT( updateView() ) );
00108 connect( mPlugin->core(), SIGNAL( dayChanged( const QDate& ) ),
00109 this, SLOT( updateView() ) );
00110
00111
00112 configUpdated();
00113 }
00114
00115 void SDSummaryWidget::configUpdated()
00116 {
00117 KConfig config( "kcmsdsummaryrc" );
00118
00119 config.setGroup( "Days" );
00120 mDaysAhead = config.readNumEntry( "DaysToShow", 7 );
00121
00122 config.setGroup( "EventTypes" );
00123 mShowBirthdaysFromKAB =
00124 config.readBoolEntry( "ShowBirthdaysFromContacts", true );
00125 mShowBirthdaysFromCal =
00126 config.readBoolEntry( "ShowBirthdaysFromCalendar", true );
00127
00128 mShowAnniversariesFromKAB =
00129 config.readBoolEntry( "ShowAnniversariesFromContacts", true );
00130 mShowAnniversariesFromCal =
00131 config.readBoolEntry( "ShowAnniversariesFromCalendar", true );
00132
00133 mShowHolidays =
00134 config.readBoolEntry( "ShowHolidays", true );
00135
00136 mShowSpecialsFromCal =
00137 config.readBoolEntry( "ShowSpecialsFromCalendar", true );
00138
00139 updateView();
00140 }
00141
00142 bool SDSummaryWidget::initHolidays()
00143 {
00144 KConfig hconfig( "korganizerrc" );
00145 hconfig.setGroup( "Time & Date" );
00146 QString location = hconfig.readEntry( "Holidays" );
00147 if ( !location.isEmpty() ) {
00148 if ( mHolidays ) delete mHolidays;
00149 mHolidays = new KHolidays( location );
00150 return true;
00151 }
00152 return false;
00153 }
00154
00155
00156 int SDSummaryWidget::span( KCal::Event *event )
00157 {
00158 int span=1;
00159 if ( event->isMultiDay() && event->doesFloat() ) {
00160 QDate d = event->dtStart().date();
00161 if ( d < QDate::currentDate() ) {
00162 d = QDate::currentDate();
00163 }
00164 while ( d < event->dtEnd().date() ) {
00165 span++;
00166 d=d.addDays( 1 );
00167 }
00168 }
00169 return span;
00170 }
00171
00172
00173 int SDSummaryWidget::dayof( KCal::Event *event, const QDate& date )
00174 {
00175 int dayof=1;
00176 QDate d = event->dtStart().date();
00177 if ( d < QDate::currentDate() ) {
00178 d = QDate::currentDate();
00179 }
00180 while ( d < event->dtEnd().date() ) {
00181 if ( d < date ) {
00182 dayof++;
00183 }
00184 d = d.addDays( 1 );
00185 }
00186 return dayof;
00187 }
00188
00189
00190
00191 void SDSummaryWidget::updateView()
00192 {
00193 mLabels.setAutoDelete( true );
00194 mLabels.clear();
00195 mLabels.setAutoDelete( false );
00196
00197 KIconLoader loader( "kdepim" );
00198
00199 KABC::StdAddressBook *ab = KABC::StdAddressBook::self( true );
00200 QValueList<SDEntry> dates;
00201 QLabel *label = 0;
00202
00203
00204 QString savefmt = KGlobal::locale()->dateFormat();
00205 KGlobal::locale()->setDateFormat( KGlobal::locale()->
00206 dateFormat().replace( 'Y', ' ' ) );
00207
00208
00209 KABC::AddressBook::Iterator it;
00210 for ( it = ab->begin(); it != ab->end(); ++it ) {
00211 QDate birthday = (*it).birthday().date();
00212 if ( birthday.isValid() && mShowBirthdaysFromKAB ) {
00213 SDEntry entry;
00214 entry.type = IncidenceTypeContact;
00215 entry.category = CategoryBirthday;
00216 dateDiff( birthday, entry.daysTo, entry.yearsOld );
00217
00218 entry.date = birthday;
00219 entry.addressee = *it;
00220 entry.span = 1;
00221 if ( entry.daysTo <= mDaysAhead )
00222 dates.append( entry );
00223 }
00224
00225 QString anniversaryAsString =
00226 (*it).custom( "KADDRESSBOOK" , "X-Anniversary" );
00227 if ( !anniversaryAsString.isEmpty() ) {
00228 QDate anniversary = QDate::fromString( anniversaryAsString, Qt::ISODate );
00229 if ( anniversary.isValid() && mShowAnniversariesFromKAB ) {
00230 SDEntry entry;
00231 entry.type = IncidenceTypeContact;
00232 entry.category = CategoryAnniversary;
00233 dateDiff( anniversary, entry.daysTo, entry.yearsOld );
00234
00235 entry.date = anniversary;
00236 entry.addressee = *it;
00237 entry.span = 1;
00238 if ( entry.daysTo <= mDaysAhead )
00239 dates.append( entry );
00240 }
00241 }
00242 }
00243
00244
00245
00246 QDate dt;
00247 QDate currentDate = QDate::currentDate();
00248 for ( dt=currentDate;
00249 dt<=currentDate.addDays( mDaysAhead - 1 );
00250 dt=dt.addDays(1) ) {
00251 KCal::Event::List events = mCalendar->events( dt,
00252 KCal::EventSortStartDate,
00253 KCal::SortDirectionAscending );
00254 KCal::Event *ev;
00255 KCal::Event::List::ConstIterator it;
00256 for ( it=events.begin(); it!=events.end(); ++it ) {
00257 ev = *it;
00258 if ( !ev->categoriesStr().isEmpty() ) {
00259 QStringList::ConstIterator it2;
00260 QStringList c = ev->categories();
00261 for ( it2=c.begin(); it2!=c.end(); ++it2 ) {
00262
00263
00264 if ( mShowBirthdaysFromCal &&
00265 ( ( *it2 ).upper() == i18n( "BIRTHDAY" ) ) ) {
00266 SDEntry entry;
00267 entry.type = IncidenceTypeEvent;
00268 entry.category = CategoryBirthday;
00269 entry.date = dt;
00270 entry.summary = ev->summary();
00271 entry.desc = ev->description();
00272 dateDiff( ev->dtStart().date(), entry.daysTo, entry.yearsOld );
00273 entry.span = 1;
00274 dates.append( entry );
00275 break;
00276 }
00277
00278
00279 if ( mShowAnniversariesFromCal &&
00280 ( ( *it2 ).upper() == i18n( "ANNIVERSARY" ) ) ) {
00281 SDEntry entry;
00282 entry.type = IncidenceTypeEvent;
00283 entry.category = CategoryAnniversary;
00284 entry.date = dt;
00285 entry.summary = ev->summary();
00286 entry.desc = ev->description();
00287 dateDiff( ev->dtStart().date(), entry.daysTo, entry.yearsOld );
00288 entry.span = 1;
00289 dates.append( entry );
00290 break;
00291 }
00292
00293
00294 if ( mShowHolidays &&
00295 ( ( *it2 ).upper() == i18n( "HOLIDAY" ) ) ) {
00296 SDEntry entry;
00297 entry.type = IncidenceTypeEvent;
00298 entry.category = CategoryHoliday;
00299 entry.date = dt;
00300 entry.summary = ev->summary();
00301 entry.desc = ev->description();
00302 dateDiff( dt, entry.daysTo, entry.yearsOld );
00303 entry.yearsOld = -1;
00304 entry.span = span( ev );
00305 if ( entry.span > 1 && dayof( ev, dt ) > 1 )
00306 break;
00307 dates.append( entry );
00308 break;
00309 }
00310
00311
00312 if ( mShowSpecialsFromCal &&
00313 ( ( *it2 ).upper() == i18n( "SPECIAL OCCASION" ) ) ) {
00314 SDEntry entry;
00315 entry.type = IncidenceTypeEvent;
00316 entry.category = CategoryOther;
00317 entry.date = dt;
00318 entry.summary = ev->summary();
00319 entry.desc = ev->description();
00320 dateDiff( dt, entry.daysTo, entry.yearsOld );
00321 entry.yearsOld = -1;
00322 entry.span = span( ev );
00323 if ( entry.span > 1 && dayof( ev, dt ) > 1 )
00324 break;
00325 dates.append( entry );
00326 break;
00327 }
00328 }
00329 }
00330 }
00331 }
00332
00333
00334 if ( mShowHolidays ) {
00335 if ( initHolidays() ) {
00336 for ( dt=currentDate;
00337 dt<=currentDate.addDays( mDaysAhead - 1 );
00338 dt=dt.addDays(1) ) {
00339 QValueList<KHoliday> holidays = mHolidays->getHolidays( dt );
00340 QValueList<KHoliday>::ConstIterator it = holidays.begin();
00341 for ( ; it != holidays.end(); ++it ) {
00342 SDEntry entry;
00343 entry.type = IncidenceTypeEvent;
00344 entry.category = ((*it).Category==KHolidays::HOLIDAY)?CategoryHoliday:CategoryOther;
00345 entry.date = dt;
00346 entry.summary = (*it).text;
00347 dateDiff( dt, entry.daysTo, entry.yearsOld );
00348 entry.yearsOld = -1;
00349 entry.span = 1;
00350 dates.append( entry );
00351 }
00352 }
00353 }
00354 }
00355
00356
00357 qHeapSort( dates );
00358
00359 if ( !dates.isEmpty() ) {
00360 int counter = 0;
00361 QValueList<SDEntry>::Iterator addrIt;
00362 QString lines;
00363 for ( addrIt = dates.begin(); addrIt != dates.end(); ++addrIt ) {
00364 bool makeBold = (*addrIt).daysTo == 0;
00365
00366
00367 QImage icon_img;
00368 QString icon_name;
00369 KABC::Picture pic;
00370 switch( (*addrIt).category ) {
00371 case CategoryBirthday:
00372 icon_name = "calendarbirthday";
00373 pic = (*addrIt).addressee.photo();
00374 if ( pic.isIntern() && !pic.data().isNull() ) {
00375 QImage img = pic.data();
00376 if ( img.width() > img.height() ) {
00377 icon_img = img.scaleWidth( 32 );
00378 } else {
00379 icon_img = img.scaleHeight( 32 );
00380 }
00381 }
00382 break;
00383 case CategoryAnniversary:
00384 icon_name = "calendaranniversary";
00385 pic = (*addrIt).addressee.photo();
00386 if ( pic.isIntern() && !pic.data().isNull() ) {
00387 QImage img = pic.data();
00388 if ( img.width() > img.height() ) {
00389 icon_img = img.scaleWidth( 32 );
00390 } else {
00391 icon_img = img.scaleHeight( 32 );
00392 }
00393 }
00394 break;
00395 case CategoryHoliday:
00396 icon_name = "calendarholiday"; break;
00397 case CategoryOther:
00398 icon_name = "cookie"; break;
00399 }
00400 label = new QLabel( this );
00401 if ( icon_img.isNull() ) {
00402 label->setPixmap( KGlobal::iconLoader()->loadIcon( icon_name,
00403 KIcon::Small ) );
00404 } else {
00405 label->setPixmap( icon_img );
00406 }
00407 label->setMaximumWidth( label->minimumSizeHint().width() );
00408 label->setAlignment( AlignVCenter );
00409 mLayout->addWidget( label, counter, 0 );
00410 mLabels.append( label );
00411
00412
00413 QString datestr;
00414
00415
00416 int year = currentDate.addDays( (*addrIt).daysTo ).year();
00417 QDate sD = QDate( year, (*addrIt).date.month(), (*addrIt).date.day() );
00418
00419 if ( (*addrIt).daysTo == 0 ) {
00420 datestr = i18n( "Today" );
00421 } else if ( (*addrIt).daysTo == 1 ) {
00422 datestr = i18n( "Tomorrow" );
00423 } else {
00424 datestr = KGlobal::locale()->formatDate( sD );
00425 }
00426
00427
00428 if ( (*addrIt).span > 1 ) {
00429 QString endstr =
00430 KGlobal::locale()->formatDate( sD.addDays( (*addrIt).span - 1 ) );
00431 datestr += " -\n " + endstr;
00432 }
00433
00434 label = new QLabel( datestr, this );
00435 label->setAlignment( AlignLeft | AlignVCenter );
00436 mLayout->addWidget( label, counter, 1 );
00437 mLabels.append( label );
00438 if ( makeBold ) {
00439 QFont font = label->font();
00440 font.setBold( true );
00441 label->setFont( font );
00442 }
00443
00444
00445 label = new QLabel( this );
00446 if ( (*addrIt).daysTo == 0 ) {
00447 label->setText( i18n( "now" ) );
00448 } else {
00449 label->setText( i18n( "in 1 day", "in %n days", (*addrIt).daysTo ) );
00450 }
00451
00452 label->setAlignment( AlignLeft | AlignVCenter );
00453 mLayout->addWidget( label, counter, 2 );
00454 mLabels.append( label );
00455
00456
00457 QString what;
00458 switch( (*addrIt).category ) {
00459 case CategoryBirthday:
00460 what = i18n( "Birthday" ); break;
00461 case CategoryAnniversary:
00462 what = i18n( "Anniversary" ); break;
00463 case CategoryHoliday:
00464 what = i18n( "Holiday" ); break;
00465 case CategoryOther:
00466 what = i18n( "Special Occasion" ); break;
00467 }
00468 label = new QLabel( this );
00469 label->setText( what );
00470 label->setAlignment( AlignLeft | AlignVCenter );
00471 mLayout->addWidget( label, counter, 3 );
00472 mLabels.append( label );
00473
00474
00475 if ( (*addrIt).type == IncidenceTypeContact ) {
00476 KURLLabel *urlLabel = new KURLLabel( this );
00477 urlLabel->installEventFilter( this );
00478 urlLabel->setURL( (*addrIt).addressee.uid() );
00479 urlLabel->setText( (*addrIt).addressee.realName() );
00480 urlLabel->setTextFormat( Qt::RichText );
00481 mLayout->addWidget( urlLabel, counter, 4 );
00482 mLabels.append( urlLabel );
00483
00484 connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
00485 this, SLOT( mailContact( const QString& ) ) );
00486 connect( urlLabel, SIGNAL( rightClickedURL( const QString& ) ),
00487 this, SLOT( popupMenu( const QString& ) ) );
00488 } else {
00489 label = new QLabel( this );
00490 label->setText( (*addrIt).summary );
00491 label->setTextFormat( Qt::RichText );
00492 mLayout->addWidget( label, counter, 4 );
00493 mLabels.append( label );
00494 if ( !(*addrIt).desc.isEmpty() ) {
00495 QToolTip::add( label, (*addrIt).desc );
00496 }
00497 }
00498
00499
00500 if ( (*addrIt).category == CategoryBirthday ||
00501 (*addrIt).category == CategoryAnniversary ) {
00502 label = new QLabel( this );
00503 if ( (*addrIt).yearsOld <= 0 ) {
00504 label->setText( "" );
00505 } else {
00506 label->setText( i18n( "one year", "%n years", (*addrIt).yearsOld ) );
00507 }
00508 label->setAlignment( AlignLeft | AlignVCenter );
00509 mLayout->addWidget( label, counter, 5 );
00510 mLabels.append( label );
00511 }
00512
00513 counter++;
00514 }
00515 } else {
00516 label = new QLabel(
00517 i18n( "No special dates within the next 1 day",
00518 "No special dates pending within the next %n days",
00519 mDaysAhead ), this, "nothing to see" );
00520 label->setAlignment( AlignHCenter | AlignVCenter );
00521 mLayout->addMultiCellWidget( label, 0, 0, 0, 4 );
00522 mLabels.append( label );
00523 }
00524
00525 for ( label = mLabels.first(); label; label = mLabels.next() )
00526 label->show();
00527
00528 KGlobal::locale()->setDateFormat( savefmt );
00529 }
00530
00531 void SDSummaryWidget::mailContact( const QString &uid )
00532 {
00533 KABC::StdAddressBook *ab = KABC::StdAddressBook::self( true );
00534 QString email = ab->findByUid( uid ).fullEmail();
00535
00536 kapp->invokeMailer( email, QString::null );
00537 }
00538
00539 void SDSummaryWidget::viewContact( const QString &uid )
00540 {
00541 if ( !mPlugin->isRunningStandalone() )
00542 mPlugin->core()->selectPlugin( "kontact_kaddressbookplugin" );
00543 else
00544 mPlugin->bringToForeground();
00545
00546 DCOPRef dcopCall( "kaddressbook", "KAddressBookIface" );
00547 dcopCall.send( "showContactEditor(QString)", uid );
00548 }
00549
00550 void SDSummaryWidget::popupMenu( const QString &uid )
00551 {
00552 KPopupMenu popup( this );
00553 popup.insertItem( KGlobal::iconLoader()->loadIcon( "kmail", KIcon::Small ),
00554 i18n( "Send &Mail" ), 0 );
00555 popup.insertItem( KGlobal::iconLoader()->loadIcon( "kaddressbook", KIcon::Small ),
00556 i18n( "View &Contact" ), 1 );
00557
00558 switch ( popup.exec( QCursor::pos() ) ) {
00559 case 0:
00560 mailContact( uid );
00561 break;
00562 case 1:
00563 viewContact( uid );
00564 break;
00565 }
00566 }
00567
00568 bool SDSummaryWidget::eventFilter( QObject *obj, QEvent* e )
00569 {
00570 if ( obj->inherits( "KURLLabel" ) ) {
00571 KURLLabel* label = static_cast<KURLLabel*>( obj );
00572 if ( e->type() == QEvent::Enter )
00573 emit message( i18n( "Mail to:\"%1\"" ).arg( label->text() ) );
00574 if ( e->type() == QEvent::Leave )
00575 emit message( QString::null );
00576 }
00577
00578 return Kontact::Summary::eventFilter( obj, e );
00579 }
00580
00581 void SDSummaryWidget::dateDiff( const QDate &date, int &days, int &years )
00582 {
00583 QDate currentDate;
00584 QDate eventDate;
00585
00586 if ( QDate::leapYear( date.year() ) && date.month() == 2 && date.day() == 29 ) {
00587 currentDate = QDate( date.year(), QDate::currentDate().month(), QDate::currentDate().day() );
00588 if ( !QDate::leapYear( QDate::currentDate().year() ) )
00589 eventDate = QDate( date.year(), date.month(), 28 );
00590 else
00591 eventDate = QDate( date.year(), date.month(), date.day() );
00592 } else {
00593 currentDate = QDate( 0, QDate::currentDate().month(), QDate::currentDate().day() );
00594 eventDate = QDate( 0, date.month(), date.day() );
00595 }
00596
00597 int offset = currentDate.daysTo( eventDate );
00598 if ( offset < 0 ) {
00599 days = 365 + offset;
00600 years = QDate::currentDate().year() + 1 - date.year();
00601 } else {
00602 days = offset;
00603 years = QDate::currentDate().year() - date.year();
00604 }
00605 }
00606
00607 QStringList SDSummaryWidget::configModules() const
00608 {
00609 return QStringList( "kcmsdsummary.desktop" );
00610 }
00611
00612 #include "sdsummarywidget.moc"