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