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 for ( dt=QDate::currentDate();
00272 dt<=QDate::currentDate().addDays( mDaysAhead - 1 );
00273 dt=dt.addDays(1) ) {
00274 KCal::Event::List events = mCalendar->events( dt,
00275 KCal::EventSortStartDate,
00276 KCal::SortDirectionAscending );
00277 KCal::Event *ev;
00278 KCal::Event::List::ConstIterator it;
00279 for ( it=events.begin(); it!=events.end(); ++it ) {
00280 ev = *it;
00281 if ( !ev->categoriesStr().isEmpty() ) {
00282 QStringList::ConstIterator it2;
00283 QStringList c = ev->categories();
00284 for ( it2=c.begin(); it2!=c.end(); ++it2 ) {
00285
00286
00287 if ( mShowBirthdaysFromCal &&
00288 ( ( *it2 ).upper() == i18n( "BIRTHDAY" ) ) ) {
00289 SDEntry entry;
00290 entry.type = IncidenceTypeEvent;
00291 entry.category = CategoryBirthday;
00292 entry.date = dt;
00293 entry.summary = ev->summary();
00294 entry.desc = ev->description();
00295 dateDiff( ev->dtStart().date(), entry.daysTo, entry.yearsOld );
00296 entry.span = 1;
00297 dates.append( entry );
00298 break;
00299 }
00300
00301
00302 if ( mShowAnniversariesFromCal &&
00303 ( ( *it2 ).upper() == i18n( "ANNIVERSARY" ) ) ) {
00304 SDEntry entry;
00305 entry.type = IncidenceTypeEvent;
00306 entry.category = CategoryAnniversary;
00307 entry.date = dt;
00308 entry.summary = ev->summary();
00309 entry.desc = ev->description();
00310 dateDiff( ev->dtStart().date(), entry.daysTo, entry.yearsOld );
00311 entry.span = 1;
00312 dates.append( entry );
00313 break;
00314 }
00315
00316
00317 if ( mShowHolidays &&
00318 ( ( *it2 ).upper() == i18n( "HOLIDAY" ) ) ) {
00319 SDEntry entry;
00320 entry.type = IncidenceTypeEvent;
00321 entry.category = CategoryHoliday;
00322 entry.date = dt;
00323 entry.summary = ev->summary();
00324 entry.desc = ev->description();
00325 dateDiff( dt, entry.daysTo, entry.yearsOld );
00326 entry.yearsOld = -1;
00327 entry.span = span( ev );
00328 if ( entry.span > 1 && dayof( ev, dt ) > 1 )
00329 break;
00330 dates.append( entry );
00331 break;
00332 }
00333
00334
00335 if ( mShowSpecialsFromCal &&
00336 ( ( *it2 ).upper() == i18n( "SPECIAL OCCASION" ) ) ) {
00337 SDEntry entry;
00338 entry.type = IncidenceTypeEvent;
00339 entry.category = CategoryOther;
00340 entry.date = dt;
00341 entry.summary = ev->summary();
00342 entry.desc = ev->description();
00343 dateDiff( dt, entry.daysTo, entry.yearsOld );
00344 entry.yearsOld = -1;
00345 entry.span = span( ev );
00346 if ( entry.span > 1 && dayof( ev, dt ) > 1 )
00347 break;
00348 dates.append( entry );
00349 break;
00350 }
00351 }
00352 }
00353 }
00354 }
00355
00356
00357 if ( mShowHolidays ) {
00358 if ( initHolidays() ) {
00359 for ( dt=QDate::currentDate();
00360 dt<=QDate::currentDate().addDays( mDaysAhead - 1 );
00361 dt=dt.addDays(1) ) {
00362 QValueList<KHoliday> holidays = mHolidays->getHolidays( dt );
00363 QValueList<KHoliday>::ConstIterator it = holidays.begin();
00364 for ( ; it != holidays.end(); ++it ) {
00365 SDEntry entry;
00366 entry.type = IncidenceTypeEvent;
00367 entry.category = ((*it).Category==KHolidays::HOLIDAY)?CategoryHoliday:CategoryOther;
00368 entry.date = dt;
00369 entry.summary = (*it).text;
00370 dateDiff( dt, entry.daysTo, entry.yearsOld );
00371 entry.yearsOld = -1;
00372 entry.span = 1;
00373 dates.append( entry );
00374 }
00375 }
00376 }
00377 }
00378
00379
00380 qHeapSort( dates );
00381
00382 if ( !dates.isEmpty() ) {
00383 int counter = 0;
00384 QValueList<SDEntry>::Iterator addrIt;
00385 QString lines;
00386 for ( addrIt = dates.begin(); addrIt != dates.end(); ++addrIt ) {
00387 bool makeBold = (*addrIt).daysTo == 0;
00388
00389
00390 QImage icon_img;
00391 QString icon_name;
00392 KABC::Picture pic;
00393 switch( (*addrIt).category ) {
00394 case CategoryBirthday:
00395 icon_name = "cookie";
00396 pic = (*addrIt).addressee.photo();
00397 if ( pic.isIntern() && !pic.data().isNull() ) {
00398 QImage img = pic.data();
00399 if ( img.width() > img.height() ) {
00400 icon_img = img.scaleWidth( 32 );
00401 } else {
00402 icon_img = img.scaleHeight( 32 );
00403 }
00404 }
00405 break;
00406 case CategoryAnniversary:
00407 icon_name = "kdmconfig";
00408 pic = (*addrIt).addressee.photo();
00409 if ( pic.isIntern() && !pic.data().isNull() ) {
00410 QImage img = pic.data();
00411 if ( img.width() > img.height() ) {
00412 icon_img = img.scaleWidth( 32 );
00413 } else {
00414 icon_img = img.scaleHeight( 32 );
00415 }
00416 }
00417 break;
00418 case CategoryHoliday:
00419 icon_name = "kdmconfig"; break;
00420 case CategoryOther:
00421 icon_name = "cookie"; break;
00422 }
00423 label = new QLabel( this );
00424 if ( icon_img.isNull() ) {
00425 label->setPixmap( KGlobal::iconLoader()->loadIcon( icon_name,
00426 KIcon::Small ) );
00427 } else {
00428 label->setPixmap( icon_img );
00429 }
00430 label->setMaximumWidth( label->minimumSizeHint().width() );
00431 label->setAlignment( AlignVCenter );
00432 mLayout->addWidget( label, counter, 0 );
00433 mLabels.append( label );
00434
00435
00436 QString datestr;
00437
00438
00439 int year = QDate::currentDate().addDays( (*addrIt).daysTo ).year();
00440 QDate sD = QDate::QDate( year,
00441 (*addrIt).date.month(), (*addrIt).date.day() );
00442
00443 if ( (*addrIt).daysTo == 0 ) {
00444 datestr = i18n( "Today" );
00445 } else if ( (*addrIt).daysTo == 1 ) {
00446 datestr = i18n( "Tomorrow" );
00447 } else {
00448 datestr = KGlobal::locale()->formatDate( sD );
00449 }
00450
00451
00452 if ( (*addrIt).span > 1 ) {
00453 QString endstr =
00454 KGlobal::locale()->formatDate( sD.addDays( (*addrIt).span - 1 ) );
00455 datestr += " -\n " + endstr;
00456 }
00457
00458 label = new QLabel( datestr, this );
00459 label->setAlignment( AlignLeft | AlignVCenter );
00460 mLayout->addWidget( label, counter, 1 );
00461 mLabels.append( label );
00462 if ( makeBold ) {
00463 QFont font = label->font();
00464 font.setBold( true );
00465 label->setFont( font );
00466 }
00467
00468
00469 label = new QLabel( this );
00470 if ( (*addrIt).daysTo == 0 ) {
00471 label->setText( i18n( "now" ) );
00472 } else {
00473 label->setText( i18n( "in 1 day", "in %n days", (*addrIt).daysTo ) );
00474 }
00475
00476 label->setAlignment( AlignLeft | AlignVCenter );
00477 mLayout->addWidget( label, counter, 2 );
00478 mLabels.append( label );
00479
00480
00481 QString what;
00482 switch( (*addrIt).category ) {
00483 case CategoryBirthday:
00484 what = i18n( "Birthday" ); break;
00485 case CategoryAnniversary:
00486 what = i18n( "Anniversary" ); break;
00487 case CategoryHoliday:
00488 what = i18n( "Holiday" ); break;
00489 case CategoryOther:
00490 what = i18n( "Special Occasion" ); break;
00491 }
00492 label = new QLabel( this );
00493 label->setText( what );
00494 label->setAlignment( AlignLeft | AlignVCenter );
00495 mLayout->addWidget( label, counter, 3 );
00496 mLabels.append( label );
00497
00498
00499 if ( (*addrIt).type == IncidenceTypeContact ) {
00500 KURLLabel *urlLabel = new KURLLabel( this );
00501 urlLabel->installEventFilter( this );
00502 urlLabel->setURL( (*addrIt).addressee.uid() );
00503 urlLabel->setText( (*addrIt).addressee.realName() );
00504 urlLabel->setTextFormat( Qt::RichText );
00505 mLayout->addWidget( urlLabel, counter, 4 );
00506 mLabels.append( urlLabel );
00507
00508 connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
00509 this, SLOT( mailContact( const QString& ) ) );
00510 connect( urlLabel, SIGNAL( rightClickedURL( const QString& ) ),
00511 this, SLOT( popupMenu( const QString& ) ) );
00512 } else {
00513 label = new QLabel( this );
00514 label->setText( (*addrIt).summary );
00515 label->setTextFormat( Qt::RichText );
00516 mLayout->addWidget( label, counter, 4 );
00517 mLabels.append( label );
00518 if ( !(*addrIt).desc.isEmpty() ) {
00519 QToolTip::add( label, (*addrIt).desc );
00520 }
00521 }
00522
00523
00524 if ( (*addrIt).category == CategoryBirthday ||
00525 (*addrIt).category == CategoryAnniversary ) {
00526 label = new QLabel( this );
00527 if ( (*addrIt).yearsOld <= 0 ) {
00528 label->setText( "" );
00529 } else {
00530 label->setText( i18n( "one year", "%n years", (*addrIt).yearsOld ) );
00531 }
00532 label->setAlignment( AlignLeft | AlignVCenter );
00533 mLayout->addWidget( label, counter, 5 );
00534 mLabels.append( label );
00535 }
00536
00537 counter++;
00538 }
00539 } else {
00540 label = new QLabel(
00541 i18n( "No special dates within the next 1 day",
00542 "No special dates pending within the next %n days",
00543 mDaysAhead ), this, "nothing to see" );
00544 label->setAlignment( AlignHCenter | AlignVCenter );
00545 mLayout->addMultiCellWidget( label, 0, 0, 0, 4 );
00546 mLabels.append( label );
00547 }
00548
00549 for ( label = mLabels.first(); label; label = mLabels.next() )
00550 label->show();
00551
00552 KGlobal::locale()->setDateFormat( savefmt );
00553 }
00554
00555 void SDSummaryWidget::mailContact( const QString &uid )
00556 {
00557 KABC::StdAddressBook *ab = KABC::StdAddressBook::self( true );
00558 QString email = ab->findByUid( uid ).fullEmail();
00559
00560 kapp->invokeMailer( email, QString::null );
00561 }
00562
00563 void SDSummaryWidget::viewContact( const QString &uid )
00564 {
00565 if ( !mPlugin->isRunningStandalone() )
00566 mPlugin->core()->selectPlugin( "kontact_kaddressbookplugin" );
00567 else
00568 mPlugin->bringToForeground();
00569
00570 DCOPRef dcopCall( "kaddressbook", "KAddressBookIface" );
00571 dcopCall.send( "showContactEditor(QString)", uid );
00572 }
00573
00574 void SDSummaryWidget::popupMenu( const QString &uid )
00575 {
00576 KPopupMenu popup( this );
00577 popup.insertItem( KGlobal::iconLoader()->loadIcon( "kmail", KIcon::Small ),
00578 i18n( "Send &Mail" ), 0 );
00579 popup.insertItem( KGlobal::iconLoader()->loadIcon( "kaddressbook", KIcon::Small ),
00580 i18n( "View &Contact" ), 1 );
00581
00582 switch ( popup.exec( QCursor::pos() ) ) {
00583 case 0:
00584 mailContact( uid );
00585 break;
00586 case 1:
00587 viewContact( uid );
00588 break;
00589 }
00590 }
00591
00592 bool SDSummaryWidget::eventFilter( QObject *obj, QEvent* e )
00593 {
00594 if ( obj->inherits( "KURLLabel" ) ) {
00595 KURLLabel* label = static_cast<KURLLabel*>( obj );
00596 if ( e->type() == QEvent::Enter )
00597 emit message( i18n( "Mail to:\"%1\"" ).arg( label->text() ) );
00598 if ( e->type() == QEvent::Leave )
00599 emit message( QString::null );
00600 }
00601
00602 return Kontact::Summary::eventFilter( obj, e );
00603 }
00604
00605 void SDSummaryWidget::dateDiff( const QDate &date, int &days, int &years )
00606 {
00607 QDate currentDate;
00608 QDate eventDate;
00609
00610 if ( QDate::leapYear( date.year() ) && date.month() == 2 && date.day() == 29 ) {
00611 currentDate = QDate( date.year(), QDate::currentDate().month(), QDate::currentDate().day() );
00612 if ( !QDate::leapYear( QDate::currentDate().year() ) )
00613 eventDate = QDate( date.year(), date.month(), 28 );
00614 else
00615 eventDate = QDate( date.year(), date.month(), date.day() );
00616 } else {
00617 currentDate = QDate( 0, QDate::currentDate().month(), QDate::currentDate().day() );
00618 eventDate = QDate( 0, date.month(), date.day() );
00619 }
00620
00621 int offset = currentDate.daysTo( eventDate );
00622 if ( offset < 0 ) {
00623 days = 365 + offset;
00624 years = QDate::currentDate().year() + 1 - date.year();
00625 } else {
00626 days = offset;
00627 years = QDate::currentDate().year() - date.year();
00628 }
00629 }
00630
00631 QStringList SDSummaryWidget::configModules() const
00632 {
00633 return QStringList( "kcmsdsummary.desktop" );
00634 }
00635
00636 #include "sdsummarywidget.moc"