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 <korganizer/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 = new KCal::CalendarResources( KPimPrefs::timezone() );
00105 mCalendar->readConfig();
00106
00107 KCal::CalendarResourceManager *manager = mCalendar->resourceManager();
00108 if ( manager->isEmpty() ) {
00109 KConfig config( "korganizerrc" );
00110 config.setGroup( "General" );
00111 QString fileName = config.readPathEntry( "Active Calendar" );
00112
00113 QString resourceName;
00114 if ( fileName.isEmpty() ) {
00115 fileName = locateLocal( "data", "korganizer/std.ics" );
00116 resourceName = i18n( "Default KOrganizer resource" );
00117 } else {
00118 resourceName = i18n( "Active Calendar" );
00119 }
00120
00121 KCal::ResourceCalendar *defaultResource =
00122 new KCal::ResourceLocal( fileName );
00123
00124 defaultResource->setResourceName( resourceName );
00125
00126 manager->add( defaultResource );
00127 manager->setStandardResource( defaultResource );
00128 }
00129 mCalendar = KOrg::StdCalendar::self();
00130 mCalendar->load();
00131
00132 connect( mCalendar, SIGNAL( calendarChanged() ),
00133 this, SLOT( updateView() ) );
00134 connect( mPlugin->core(), SIGNAL( dayChanged( const QDate& ) ),
00135 this, SLOT( updateView() ) );
00136
00137
00138 configUpdated();
00139 }
00140
00141 void SDSummaryWidget::configUpdated()
00142 {
00143 KConfig config( "kcmsdsummaryrc" );
00144
00145 config.setGroup( "Days" );
00146 mDaysAhead = config.readNumEntry( "DaysToShow", 7 );
00147
00148 config.setGroup( "EventTypes" );
00149 mShowBirthdaysFromKAB =
00150 config.readBoolEntry( "ShowBirthdaysFromContacts", true );
00151 mShowBirthdaysFromCal =
00152 config.readBoolEntry( "ShowBirthdaysFromCalendar", true );
00153
00154 mShowAnniversariesFromKAB =
00155 config.readBoolEntry( "ShowAnniversariesFromContacts", true );
00156 mShowAnniversariesFromCal =
00157 config.readBoolEntry( "ShowAnniversariesFromCalendar", true );
00158
00159 mShowHolidays =
00160 config.readBoolEntry( "ShowHolidays", true );
00161
00162 mShowSpecialsFromCal =
00163 config.readBoolEntry( "ShowSpecialsFromCalendar", true );
00164
00165 updateView();
00166 }
00167
00168 bool SDSummaryWidget::initHolidays()
00169 {
00170 KConfig hconfig( "korganizerrc" );
00171 hconfig.setGroup( "Time & Date" );
00172 QString location = hconfig.readEntry( "Holidays" );
00173 if ( !location.isEmpty() ) {
00174 if ( mHolidays ) delete mHolidays;
00175 mHolidays = new KHolidays( location );
00176 return true;
00177 }
00178 return false;
00179 }
00180
00181
00182 int SDSummaryWidget::span( KCal::Event *event )
00183 {
00184 int span=1;
00185 if ( event->isMultiDay() && event->doesFloat() ) {
00186 QDate d = event->dtStart().date();
00187 if ( d < QDate::currentDate() ) {
00188 d = QDate::currentDate();
00189 }
00190 while ( d < event->dtEnd().date() ) {
00191 span++;
00192 d=d.addDays( 1 );
00193 }
00194 }
00195 return span;
00196 }
00197
00198
00199 int SDSummaryWidget::dayof( KCal::Event *event, const QDate& date )
00200 {
00201 int dayof=1;
00202 QDate d = event->dtStart().date();
00203 if ( d < QDate::currentDate() ) {
00204 d = QDate::currentDate();
00205 }
00206 while ( d < event->dtEnd().date() ) {
00207 if ( d < date ) {
00208 dayof++;
00209 }
00210 d = d.addDays( 1 );
00211 }
00212 return dayof;
00213 }
00214
00215
00216
00217 void SDSummaryWidget::updateView()
00218 {
00219 mLabels.setAutoDelete( true );
00220 mLabels.clear();
00221 mLabels.setAutoDelete( false );
00222
00223 KABC::StdAddressBook *ab = KABC::StdAddressBook::self( true );
00224 QValueList<SDEntry> dates;
00225 QLabel *label = 0;
00226
00227
00228 QString savefmt = KGlobal::locale()->dateFormat();
00229 KGlobal::locale()->setDateFormat( KGlobal::locale()->
00230 dateFormat().replace( 'Y', ' ' ) );
00231
00232
00233 KABC::AddressBook::Iterator it;
00234 for ( it = ab->begin(); it != ab->end(); ++it ) {
00235 QDate birthday = (*it).birthday().date();
00236 if ( birthday.isValid() && mShowBirthdaysFromKAB ) {
00237 SDEntry entry;
00238 entry.type = IncidenceTypeContact;
00239 entry.category = CategoryBirthday;
00240 dateDiff( birthday, entry.daysTo, entry.yearsOld );
00241
00242 entry.date = birthday;
00243 entry.addressee = *it;
00244 entry.span = 1;
00245 if ( entry.daysTo <= mDaysAhead )
00246 dates.append( entry );
00247 }
00248
00249 QString anniversaryAsString =
00250 (*it).custom( "KADDRESSBOOK" , "X-Anniversary" );
00251 if ( !anniversaryAsString.isEmpty() ) {
00252 QDate anniversary = QDate::fromString( anniversaryAsString, Qt::ISODate );
00253 if ( anniversary.isValid() && mShowAnniversariesFromKAB ) {
00254 SDEntry entry;
00255 entry.type = IncidenceTypeContact;
00256 entry.category = CategoryAnniversary;
00257 dateDiff( anniversary, entry.daysTo, entry.yearsOld );
00258
00259 entry.date = anniversary;
00260 entry.addressee = *it;
00261 entry.span = 1;
00262 if ( entry.daysTo <= mDaysAhead )
00263 dates.append( entry );
00264 }
00265 }
00266 }
00267
00268
00269
00270 QDate dt;
00271 QDate currentDate = QDate::currentDate();
00272 for ( dt=currentDate;
00273 dt<=currentDate.addDays( mDaysAhead - 1 );
00274 dt=dt.addDays(1) ) {
00275 KCal::Event::List events = mCalendar->events( dt,
00276 KCal::EventSortStartDate,
00277 KCal::SortDirectionAscending );
00278 KCal::Event *ev;
00279 KCal::Event::List::ConstIterator it;
00280 for ( it=events.begin(); it!=events.end(); ++it ) {
00281 ev = *it;
00282 if ( !ev->categoriesStr().isEmpty() ) {
00283 QStringList::ConstIterator it2;
00284 QStringList c = ev->categories();
00285 for ( it2=c.begin(); it2!=c.end(); ++it2 ) {
00286
00287
00288 if ( mShowBirthdaysFromCal &&
00289 ( ( *it2 ).upper() == i18n( "BIRTHDAY" ) ) ) {
00290 SDEntry entry;
00291 entry.type = IncidenceTypeEvent;
00292 entry.category = CategoryBirthday;
00293 entry.date = dt;
00294 entry.summary = ev->summary();
00295 entry.desc = ev->description();
00296 dateDiff( ev->dtStart().date(), entry.daysTo, entry.yearsOld );
00297 entry.span = 1;
00298 dates.append( entry );
00299 break;
00300 }
00301
00302
00303 if ( mShowAnniversariesFromCal &&
00304 ( ( *it2 ).upper() == i18n( "ANNIVERSARY" ) ) ) {
00305 SDEntry entry;
00306 entry.type = IncidenceTypeEvent;
00307 entry.category = CategoryAnniversary;
00308 entry.date = dt;
00309 entry.summary = ev->summary();
00310 entry.desc = ev->description();
00311 dateDiff( ev->dtStart().date(), entry.daysTo, entry.yearsOld );
00312 entry.span = 1;
00313 dates.append( entry );
00314 break;
00315 }
00316
00317
00318 if ( mShowHolidays &&
00319 ( ( *it2 ).upper() == i18n( "HOLIDAY" ) ) ) {
00320 SDEntry entry;
00321 entry.type = IncidenceTypeEvent;
00322 entry.category = CategoryHoliday;
00323 entry.date = dt;
00324 entry.summary = ev->summary();
00325 entry.desc = ev->description();
00326 dateDiff( dt, entry.daysTo, entry.yearsOld );
00327 entry.yearsOld = -1;
00328 entry.span = span( ev );
00329 if ( entry.span > 1 && dayof( ev, dt ) > 1 )
00330 break;
00331 dates.append( entry );
00332 break;
00333 }
00334
00335
00336 if ( mShowSpecialsFromCal &&
00337 ( ( *it2 ).upper() == i18n( "SPECIAL OCCASION" ) ) ) {
00338 SDEntry entry;
00339 entry.type = IncidenceTypeEvent;
00340 entry.category = CategoryOther;
00341 entry.date = dt;
00342 entry.summary = ev->summary();
00343 entry.desc = ev->description();
00344 dateDiff( dt, entry.daysTo, entry.yearsOld );
00345 entry.yearsOld = -1;
00346 entry.span = span( ev );
00347 if ( entry.span > 1 && dayof( ev, dt ) > 1 )
00348 break;
00349 dates.append( entry );
00350 break;
00351 }
00352 }
00353 }
00354 }
00355 }
00356
00357
00358 if ( mShowHolidays ) {
00359 if ( initHolidays() ) {
00360 for ( dt=currentDate;
00361 dt<=currentDate.addDays( mDaysAhead - 1 );
00362 dt=dt.addDays(1) ) {
00363 QValueList<KHoliday> holidays = mHolidays->getHolidays( dt );
00364 QValueList<KHoliday>::ConstIterator it = holidays.begin();
00365 for ( ; it != holidays.end(); ++it ) {
00366 SDEntry entry;
00367 entry.type = IncidenceTypeEvent;
00368 entry.category = ((*it).Category==KHolidays::HOLIDAY)?CategoryHoliday:CategoryOther;
00369 entry.date = dt;
00370 entry.summary = (*it).text;
00371 dateDiff( dt, entry.daysTo, entry.yearsOld );
00372 entry.yearsOld = -1;
00373 entry.span = 1;
00374 dates.append( entry );
00375 }
00376 }
00377 }
00378 }
00379
00380
00381 qHeapSort( dates );
00382
00383 if ( !dates.isEmpty() ) {
00384 int counter = 0;
00385 QValueList<SDEntry>::Iterator addrIt;
00386 QString lines;
00387 for ( addrIt = dates.begin(); addrIt != dates.end(); ++addrIt ) {
00388 bool makeBold = (*addrIt).daysTo == 0;
00389
00390
00391 QImage icon_img;
00392 QString icon_name;
00393 KABC::Picture pic;
00394 switch( (*addrIt).category ) {
00395 case CategoryBirthday:
00396 icon_name = "cookie";
00397 pic = (*addrIt).addressee.photo();
00398 if ( pic.isIntern() && !pic.data().isNull() ) {
00399 QImage img = pic.data();
00400 if ( img.width() > img.height() ) {
00401 icon_img = img.scaleWidth( 32 );
00402 } else {
00403 icon_img = img.scaleHeight( 32 );
00404 }
00405 }
00406 break;
00407 case CategoryAnniversary:
00408 icon_name = "kdmconfig";
00409 pic = (*addrIt).addressee.photo();
00410 if ( pic.isIntern() && !pic.data().isNull() ) {
00411 QImage img = pic.data();
00412 if ( img.width() > img.height() ) {
00413 icon_img = img.scaleWidth( 32 );
00414 } else {
00415 icon_img = img.scaleHeight( 32 );
00416 }
00417 }
00418 break;
00419 case CategoryHoliday:
00420 icon_name = "kdmconfig"; break;
00421 case CategoryOther:
00422 icon_name = "cookie"; break;
00423 }
00424 label = new QLabel( this );
00425 if ( icon_img.isNull() ) {
00426 label->setPixmap( KGlobal::iconLoader()->loadIcon( icon_name,
00427 KIcon::Small ) );
00428 } else {
00429 label->setPixmap( icon_img );
00430 }
00431 label->setMaximumWidth( label->minimumSizeHint().width() );
00432 label->setAlignment( AlignVCenter );
00433 mLayout->addWidget( label, counter, 0 );
00434 mLabels.append( label );
00435
00436
00437 QString datestr;
00438
00439
00440 int year = currentDate.addDays( (*addrIt).daysTo ).year();
00441 QDate sD = QDate::QDate( year,
00442 (*addrIt).date.month(), (*addrIt).date.day() );
00443
00444 if ( (*addrIt).daysTo == 0 ) {
00445 datestr = i18n( "Today" );
00446 } else if ( (*addrIt).daysTo == 1 ) {
00447 datestr = i18n( "Tomorrow" );
00448 } else {
00449 datestr = KGlobal::locale()->formatDate( sD );
00450 }
00451
00452
00453 if ( (*addrIt).span > 1 ) {
00454 QString endstr =
00455 KGlobal::locale()->formatDate( sD.addDays( (*addrIt).span - 1 ) );
00456 datestr += " -\n " + endstr;
00457 }
00458
00459 label = new QLabel( datestr, this );
00460 label->setAlignment( AlignLeft | AlignVCenter );
00461 mLayout->addWidget( label, counter, 1 );
00462 mLabels.append( label );
00463 if ( makeBold ) {
00464 QFont font = label->font();
00465 font.setBold( true );
00466 label->setFont( font );
00467 }
00468
00469
00470 label = new QLabel( this );
00471 if ( (*addrIt).daysTo == 0 ) {
00472 label->setText( i18n( "now" ) );
00473 } else {
00474 label->setText( i18n( "in 1 day", "in %n days", (*addrIt).daysTo ) );
00475 }
00476
00477 label->setAlignment( AlignLeft | AlignVCenter );
00478 mLayout->addWidget( label, counter, 2 );
00479 mLabels.append( label );
00480
00481
00482 QString what;
00483 switch( (*addrIt).category ) {
00484 case CategoryBirthday:
00485 what = i18n( "Birthday" ); break;
00486 case CategoryAnniversary:
00487 what = i18n( "Anniversary" ); break;
00488 case CategoryHoliday:
00489 what = i18n( "Holiday" ); break;
00490 case CategoryOther:
00491 what = i18n( "Special Occasion" ); break;
00492 }
00493 label = new QLabel( this );
00494 label->setText( what );
00495 label->setAlignment( AlignLeft | AlignVCenter );
00496 mLayout->addWidget( label, counter, 3 );
00497 mLabels.append( label );
00498
00499
00500 if ( (*addrIt).type == IncidenceTypeContact ) {
00501 KURLLabel *urlLabel = new KURLLabel( this );
00502 urlLabel->installEventFilter( this );
00503 urlLabel->setURL( (*addrIt).addressee.uid() );
00504 urlLabel->setText( (*addrIt).addressee.realName() );
00505 urlLabel->setTextFormat( Qt::RichText );
00506 mLayout->addWidget( urlLabel, counter, 4 );
00507 mLabels.append( urlLabel );
00508
00509 connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
00510 this, SLOT( mailContact( const QString& ) ) );
00511 connect( urlLabel, SIGNAL( rightClickedURL( const QString& ) ),
00512 this, SLOT( popupMenu( const QString& ) ) );
00513 } else {
00514 label = new QLabel( this );
00515 label->setText( (*addrIt).summary );
00516 label->setTextFormat( Qt::RichText );
00517 mLayout->addWidget( label, counter, 4 );
00518 mLabels.append( label );
00519 if ( !(*addrIt).desc.isEmpty() ) {
00520 QToolTip::add( label, (*addrIt).desc );
00521 }
00522 }
00523
00524
00525 if ( (*addrIt).category == CategoryBirthday ||
00526 (*addrIt).category == CategoryAnniversary ) {
00527 label = new QLabel( this );
00528 if ( (*addrIt).yearsOld <= 0 ) {
00529 label->setText( "" );
00530 } else {
00531 label->setText( i18n( "one year", "%n years", (*addrIt).yearsOld ) );
00532 }
00533 label->setAlignment( AlignLeft | AlignVCenter );
00534 mLayout->addWidget( label, counter, 5 );
00535 mLabels.append( label );
00536 }
00537
00538 counter++;
00539 }
00540 } else {
00541 label = new QLabel(
00542 i18n( "No special dates within the next 1 day",
00543 "No special dates pending within the next %n days",
00544 mDaysAhead ), this, "nothing to see" );
00545 label->setAlignment( AlignHCenter | AlignVCenter );
00546 mLayout->addMultiCellWidget( label, 0, 0, 0, 4 );
00547 mLabels.append( label );
00548 }
00549
00550 for ( label = mLabels.first(); label; label = mLabels.next() )
00551 label->show();
00552
00553 KGlobal::locale()->setDateFormat( savefmt );
00554 }
00555
00556 void SDSummaryWidget::mailContact( const QString &uid )
00557 {
00558 KABC::StdAddressBook *ab = KABC::StdAddressBook::self( true );
00559 QString email = ab->findByUid( uid ).fullEmail();
00560
00561 kapp->invokeMailer( email, QString::null );
00562 }
00563
00564 void SDSummaryWidget::viewContact( const QString &uid )
00565 {
00566 if ( !mPlugin->isRunningStandalone() )
00567 mPlugin->core()->selectPlugin( "kontact_kaddressbookplugin" );
00568 else
00569 mPlugin->bringToForeground();
00570
00571 DCOPRef dcopCall( "kaddressbook", "KAddressBookIface" );
00572 dcopCall.send( "showContactEditor(QString)", uid );
00573 }
00574
00575 void SDSummaryWidget::popupMenu( const QString &uid )
00576 {
00577 KPopupMenu popup( this );
00578 popup.insertItem( KGlobal::iconLoader()->loadIcon( "kmail", KIcon::Small ),
00579 i18n( "Send &Mail" ), 0 );
00580 popup.insertItem( KGlobal::iconLoader()->loadIcon( "kaddressbook", KIcon::Small ),
00581 i18n( "View &Contact" ), 1 );
00582
00583 switch ( popup.exec( QCursor::pos() ) ) {
00584 case 0:
00585 mailContact( uid );
00586 break;
00587 case 1:
00588 viewContact( uid );
00589 break;
00590 }
00591 }
00592
00593 bool SDSummaryWidget::eventFilter( QObject *obj, QEvent* e )
00594 {
00595 if ( obj->inherits( "KURLLabel" ) ) {
00596 KURLLabel* label = static_cast<KURLLabel*>( obj );
00597 if ( e->type() == QEvent::Enter )
00598 emit message( i18n( "Mail to:\"%1\"" ).arg( label->text() ) );
00599 if ( e->type() == QEvent::Leave )
00600 emit message( QString::null );
00601 }
00602
00603 return Kontact::Summary::eventFilter( obj, e );
00604 }
00605
00606 void SDSummaryWidget::dateDiff( const QDate &date, int &days, int &years )
00607 {
00608 QDate currentDate;
00609 QDate eventDate;
00610
00611 if ( QDate::leapYear( date.year() ) && date.month() == 2 && date.day() == 29 ) {
00612 currentDate = QDate( date.year(), QDate::currentDate().month(), QDate::currentDate().day() );
00613 if ( !QDate::leapYear( QDate::currentDate().year() ) )
00614 eventDate = QDate( date.year(), date.month(), 28 );
00615 else
00616 eventDate = QDate( date.year(), date.month(), date.day() );
00617 } else {
00618 currentDate = QDate( 0, QDate::currentDate().month(), QDate::currentDate().day() );
00619 eventDate = QDate( 0, date.month(), date.day() );
00620 }
00621
00622 int offset = currentDate.daysTo( eventDate );
00623 if ( offset < 0 ) {
00624 days = 365 + offset;
00625 years = QDate::currentDate().year() + 1 - date.year();
00626 } else {
00627 days = offset;
00628 years = QDate::currentDate().year() - date.year();
00629 }
00630 }
00631
00632 QStringList SDSummaryWidget::configModules() const
00633 {
00634 return QStringList( "kcmsdsummary.desktop" );
00635 }
00636
00637 #include "sdsummarywidget.moc"