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 <tqcursor.h>
00026 #include <tqlabel.h>
00027 #include <tqlayout.h>
00028 #include <tqimage.h>
00029 #include <tqtooltip.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 TQDate date;
00069 TQString summary;
00070 TQString 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, TQWidget *parent,
00081 const char *name )
00082 : Kontact::Summary( parent, name ), mPlugin( plugin ), mCalendar( 0 ), mHolidays( 0 )
00083 {
00084
00085 TQVBoxLayout *mainLayout = new TQVBoxLayout( this, 3, 3 );
00086
00087 TQPixmap icon = KGlobal::iconLoader()->loadIcon( "cookie",
00088 KIcon::Desktop, KIcon::SizeMedium );
00089
00090 TQWidget *header = createHeader( this, icon, i18n( "Special Dates" ) );
00091 mainLayout->addWidget(header);
00092
00093 mLayout = new TQGridLayout( mainLayout, 7, 6, 3 );
00094 mLayout->setRowStretch( 6, 1 );
00095
00096
00097 KABC::StdAddressBook *ab = KABC::StdAddressBook::self( true );
00098 connect( ab, TQT_SIGNAL( addressBookChanged( AddressBook* ) ),
00099 this, TQT_SLOT( updateView() ) );
00100 connect( mPlugin->core(), TQT_SIGNAL( dayChanged( const TQDate& ) ),
00101 this, TQT_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 TQString fileName = config.readPathEntry( "Active Calendar" );
00112
00113 TQString 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
00131 connect( mCalendar, TQT_SIGNAL( calendarChanged() ),
00132 this, TQT_SLOT( updateView() ) );
00133 connect( mPlugin->core(), TQT_SIGNAL( dayChanged( const TQDate& ) ),
00134 this, TQT_SLOT( updateView() ) );
00135
00136
00137 configUpdated();
00138 }
00139
00140 void SDSummaryWidget::configUpdated()
00141 {
00142 KConfig config( "kcmsdsummaryrc" );
00143
00144 config.setGroup( "Days" );
00145 mDaysAhead = config.readNumEntry( "DaysToShow", 7 );
00146
00147 config.setGroup( "EventTypes" );
00148 mShowBirthdaysFromKAB =
00149 config.readBoolEntry( "ShowBirthdaysFromContacts", true );
00150 mShowBirthdaysFromCal =
00151 config.readBoolEntry( "ShowBirthdaysFromCalendar", true );
00152
00153 mShowAnniversariesFromKAB =
00154 config.readBoolEntry( "ShowAnniversariesFromContacts", true );
00155 mShowAnniversariesFromCal =
00156 config.readBoolEntry( "ShowAnniversariesFromCalendar", true );
00157
00158 mShowHolidays =
00159 config.readBoolEntry( "ShowHolidays", true );
00160
00161 mShowSpecialsFromCal =
00162 config.readBoolEntry( "ShowSpecialsFromCalendar", true );
00163
00164 updateView();
00165 }
00166
00167 bool SDSummaryWidget::initHolidays()
00168 {
00169 KConfig hconfig( "korganizerrc" );
00170 hconfig.setGroup( "Time & Date" );
00171 TQString location = hconfig.readEntry( "Holidays" );
00172 if ( !location.isEmpty() ) {
00173 if ( mHolidays ) delete mHolidays;
00174 mHolidays = new KHolidays( location );
00175 return true;
00176 }
00177 return false;
00178 }
00179
00180
00181 int SDSummaryWidget::span( KCal::Event *event )
00182 {
00183 int span=1;
00184 if ( event->isMultiDay() && event->doesFloat() ) {
00185 TQDate d = event->dtStart().date();
00186 if ( d < TQDate::currentDate() ) {
00187 d = TQDate::currentDate();
00188 }
00189 while ( d < event->dtEnd().date() ) {
00190 span++;
00191 d=d.addDays( 1 );
00192 }
00193 }
00194 return span;
00195 }
00196
00197
00198 int SDSummaryWidget::dayof( KCal::Event *event, const TQDate& date )
00199 {
00200 int dayof=1;
00201 TQDate d = event->dtStart().date();
00202 if ( d < TQDate::currentDate() ) {
00203 d = TQDate::currentDate();
00204 }
00205 while ( d < event->dtEnd().date() ) {
00206 if ( d < date ) {
00207 dayof++;
00208 }
00209 d = d.addDays( 1 );
00210 }
00211 return dayof;
00212 }
00213
00214
00215
00216 void SDSummaryWidget::updateView()
00217 {
00218 mLabels.setAutoDelete( true );
00219 mLabels.clear();
00220 mLabels.setAutoDelete( false );
00221
00222 KIconLoader loader( "kdepim" );
00223
00224 KABC::StdAddressBook *ab = KABC::StdAddressBook::self( true );
00225 TQValueList<SDEntry> dates;
00226 TQLabel *label = 0;
00227
00228
00229 TQString savefmt = KGlobal::locale()->dateFormat();
00230 KGlobal::locale()->setDateFormat( KGlobal::locale()->
00231 dateFormat().replace( 'Y', ' ' ) );
00232
00233
00234 KABC::AddressBook::Iterator it;
00235 for ( it = ab->begin(); it != ab->end(); ++it ) {
00236 TQDate birthday = (*it).birthday().date();
00237 if ( birthday.isValid() && mShowBirthdaysFromKAB ) {
00238 SDEntry entry;
00239 entry.type = IncidenceTypeContact;
00240 entry.category = CategoryBirthday;
00241 dateDiff( birthday, entry.daysTo, entry.yearsOld );
00242
00243 entry.date = birthday;
00244 entry.addressee = *it;
00245 entry.span = 1;
00246 if ( entry.daysTo <= mDaysAhead )
00247 dates.append( entry );
00248 }
00249
00250 TQString anniversaryAsString =
00251 (*it).custom( "KADDRESSBOOK" , "X-Anniversary" );
00252 if ( !anniversaryAsString.isEmpty() ) {
00253 TQDate anniversary = TQDate::fromString( anniversaryAsString, Qt::ISODate );
00254 if ( anniversary.isValid() && mShowAnniversariesFromKAB ) {
00255 SDEntry entry;
00256 entry.type = IncidenceTypeContact;
00257 entry.category = CategoryAnniversary;
00258 dateDiff( anniversary, entry.daysTo, entry.yearsOld );
00259
00260 entry.date = anniversary;
00261 entry.addressee = *it;
00262 entry.span = 1;
00263 if ( entry.daysTo <= mDaysAhead )
00264 dates.append( entry );
00265 }
00266 }
00267 }
00268
00269
00270
00271 TQDate dt;
00272 TQDate currentDate = TQDate::currentDate();
00273 for ( dt=currentDate;
00274 dt<=currentDate.addDays( mDaysAhead - 1 );
00275 dt=dt.addDays(1) ) {
00276 KCal::Event::List events = mCalendar->events( dt,
00277 KCal::EventSortStartDate,
00278 KCal::SortDirectionAscending );
00279 KCal::Event *ev;
00280 KCal::Event::List::ConstIterator it;
00281 for ( it=events.begin(); it!=events.end(); ++it ) {
00282 ev = *it;
00283 if ( !ev->categoriesStr().isEmpty() ) {
00284 TQStringList::ConstIterator it2;
00285 TQStringList c = ev->categories();
00286 for ( it2=c.begin(); it2!=c.end(); ++it2 ) {
00287
00288
00289 if ( mShowBirthdaysFromCal &&
00290 ( ( *it2 ).upper() == i18n( "BIRTHDAY" ) ) ) {
00291 SDEntry entry;
00292 entry.type = IncidenceTypeEvent;
00293 entry.category = CategoryBirthday;
00294 entry.date = dt;
00295 entry.summary = ev->summary();
00296 entry.desc = ev->description();
00297 dateDiff( ev->dtStart().date(), entry.daysTo, entry.yearsOld );
00298 entry.span = 1;
00299 dates.append( entry );
00300 break;
00301 }
00302
00303
00304 if ( mShowAnniversariesFromCal &&
00305 ( ( *it2 ).upper() == i18n( "ANNIVERSARY" ) ) ) {
00306 SDEntry entry;
00307 entry.type = IncidenceTypeEvent;
00308 entry.category = CategoryAnniversary;
00309 entry.date = dt;
00310 entry.summary = ev->summary();
00311 entry.desc = ev->description();
00312 dateDiff( ev->dtStart().date(), entry.daysTo, entry.yearsOld );
00313 entry.span = 1;
00314 dates.append( entry );
00315 break;
00316 }
00317
00318
00319 if ( mShowHolidays &&
00320 ( ( *it2 ).upper() == i18n( "HOLIDAY" ) ) ) {
00321 SDEntry entry;
00322 entry.type = IncidenceTypeEvent;
00323 entry.category = CategoryHoliday;
00324 entry.date = dt;
00325 entry.summary = ev->summary();
00326 entry.desc = ev->description();
00327 dateDiff( dt, entry.daysTo, entry.yearsOld );
00328 entry.yearsOld = -1;
00329 entry.span = span( ev );
00330 if ( entry.span > 1 && dayof( ev, dt ) > 1 )
00331 break;
00332 dates.append( entry );
00333 break;
00334 }
00335
00336
00337 if ( mShowSpecialsFromCal &&
00338 ( ( *it2 ).upper() == i18n( "SPECIAL OCCASION" ) ) ) {
00339 SDEntry entry;
00340 entry.type = IncidenceTypeEvent;
00341 entry.category = CategoryOther;
00342 entry.date = dt;
00343 entry.summary = ev->summary();
00344 entry.desc = ev->description();
00345 dateDiff( dt, entry.daysTo, entry.yearsOld );
00346 entry.yearsOld = -1;
00347 entry.span = span( ev );
00348 if ( entry.span > 1 && dayof( ev, dt ) > 1 )
00349 break;
00350 dates.append( entry );
00351 break;
00352 }
00353 }
00354 }
00355 }
00356 }
00357
00358
00359 if ( mShowHolidays ) {
00360 if ( initHolidays() ) {
00361 for ( dt=currentDate;
00362 dt<=currentDate.addDays( mDaysAhead - 1 );
00363 dt=dt.addDays(1) ) {
00364 TQValueList<KHoliday> holidays = mHolidays->getHolidays( dt );
00365 TQValueList<KHoliday>::ConstIterator it = holidays.begin();
00366 for ( ; it != holidays.end(); ++it ) {
00367 SDEntry entry;
00368 entry.type = IncidenceTypeEvent;
00369 entry.category = ((*it).Category==KHolidays::HOLIDAY)?CategoryHoliday:CategoryOther;
00370 entry.date = dt;
00371 entry.summary = (*it).text;
00372 dateDiff( dt, entry.daysTo, entry.yearsOld );
00373 entry.yearsOld = -1;
00374 entry.span = 1;
00375 dates.append( entry );
00376 }
00377 }
00378 }
00379 }
00380
00381
00382 qHeapSort( dates );
00383
00384 if ( !dates.isEmpty() ) {
00385 int counter = 0;
00386 TQValueList<SDEntry>::Iterator addrIt;
00387 TQString lines;
00388 for ( addrIt = dates.begin(); addrIt != dates.end(); ++addrIt ) {
00389 bool makeBold = (*addrIt).daysTo == 0;
00390
00391
00392 TQImage icon_img;
00393 TQString icon_name;
00394 KABC::Picture pic;
00395 switch( (*addrIt).category ) {
00396 case CategoryBirthday:
00397 icon_name = "calendarbirthday";
00398 pic = (*addrIt).addressee.photo();
00399 if ( pic.isIntern() && !pic.data().isNull() ) {
00400 TQImage img = pic.data();
00401 if ( img.width() > img.height() ) {
00402 icon_img = img.scaleWidth( 32 );
00403 } else {
00404 icon_img = img.scaleHeight( 32 );
00405 }
00406 }
00407 break;
00408 case CategoryAnniversary:
00409 icon_name = "calendaranniversary";
00410 pic = (*addrIt).addressee.photo();
00411 if ( pic.isIntern() && !pic.data().isNull() ) {
00412 TQImage img = pic.data();
00413 if ( img.width() > img.height() ) {
00414 icon_img = img.scaleWidth( 32 );
00415 } else {
00416 icon_img = img.scaleHeight( 32 );
00417 }
00418 }
00419 break;
00420 case CategoryHoliday:
00421 icon_name = "calendarholiday"; break;
00422 case CategoryOther:
00423 icon_name = "cookie"; break;
00424 }
00425 label = new TQLabel( this );
00426 if ( icon_img.isNull() ) {
00427 label->setPixmap( KGlobal::iconLoader()->loadIcon( icon_name,
00428 KIcon::Small ) );
00429 } else {
00430 label->setPixmap( icon_img );
00431 }
00432 label->setMaximumWidth( label->minimumSizeHint().width() );
00433 label->setAlignment( AlignVCenter );
00434 mLayout->addWidget( label, counter, 0 );
00435 mLabels.append( label );
00436
00437
00438 TQString datestr;
00439
00440
00441 int year = currentDate.addDays( (*addrIt).daysTo ).year();
00442 TQDate sD = TQDate( year, (*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 TQString endstr =
00455 KGlobal::locale()->formatDate( sD.addDays( (*addrIt).span - 1 ) );
00456 datestr += " -\n " + endstr;
00457 }
00458
00459 label = new TQLabel( datestr, this );
00460 label->setAlignment( AlignLeft | AlignVCenter );
00461 mLayout->addWidget( label, counter, 1 );
00462 mLabels.append( label );
00463 if ( makeBold ) {
00464 TQFont font = label->font();
00465 font.setBold( true );
00466 label->setFont( font );
00467 }
00468
00469
00470 label = new TQLabel( 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 TQString 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 TQLabel( 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, TQT_SIGNAL( leftClickedURL( const TQString& ) ),
00510 this, TQT_SLOT( mailContact( const TQString& ) ) );
00511 connect( urlLabel, TQT_SIGNAL( rightClickedURL( const TQString& ) ),
00512 this, TQT_SLOT( popupMenu( const TQString& ) ) );
00513 } else {
00514 label = new TQLabel( 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 TQToolTip::add( label, (*addrIt).desc );
00521 }
00522 }
00523
00524
00525 if ( (*addrIt).category == CategoryBirthday ||
00526 (*addrIt).category == CategoryAnniversary ) {
00527 label = new TQLabel( 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 TQLabel(
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 TQString &uid )
00557 {
00558 KABC::StdAddressBook *ab = KABC::StdAddressBook::self( true );
00559 TQString email = ab->findByUid( uid ).fullEmail();
00560
00561 kapp->invokeMailer( email, TQString::null );
00562 }
00563
00564 void SDSummaryWidget::viewContact( const TQString &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(TQString)", uid );
00573 }
00574
00575 void SDSummaryWidget::popupMenu( const TQString &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( TQCursor::pos() ) ) {
00584 case 0:
00585 mailContact( uid );
00586 break;
00587 case 1:
00588 viewContact( uid );
00589 break;
00590 }
00591 }
00592
00593 bool SDSummaryWidget::eventFilter( TQObject *obj, TQEvent* e )
00594 {
00595 if ( obj->inherits( "KURLLabel" ) ) {
00596 KURLLabel* label = static_cast<KURLLabel*>( obj );
00597 if ( e->type() == TQEvent::Enter )
00598 emit message( i18n( "Mail to:\"%1\"" ).arg( label->text() ) );
00599 if ( e->type() == TQEvent::Leave )
00600 emit message( TQString::null );
00601 }
00602
00603 return Kontact::Summary::eventFilter( obj, e );
00604 }
00605
00606 void SDSummaryWidget::dateDiff( const TQDate &date, int &days, int &years )
00607 {
00608 TQDate currentDate;
00609 TQDate eventDate;
00610
00611 if ( TQDate::leapYear( date.year() ) && date.month() == 2 && date.day() == 29 ) {
00612 currentDate = TQDate( date.year(), TQDate::currentDate().month(), TQDate::currentDate().day() );
00613 if ( !TQDate::leapYear( TQDate::currentDate().year() ) )
00614 eventDate = TQDate( date.year(), date.month(), 28 );
00615 else
00616 eventDate = TQDate( date.year(), date.month(), date.day() );
00617 } else {
00618 currentDate = TQDate( 0, TQDate::currentDate().month(), TQDate::currentDate().day() );
00619 eventDate = TQDate( 0, date.month(), date.day() );
00620 }
00621
00622 int offset = currentDate.daysTo( eventDate );
00623 if ( offset < 0 ) {
00624 days = 365 + offset;
00625 years = TQDate::currentDate().year() + 1 - date.year();
00626 } else {
00627 days = offset;
00628 years = TQDate::currentDate().year() - date.year();
00629 }
00630 }
00631
00632 TQStringList SDSummaryWidget::configModules() const
00633 {
00634 return TQStringList( "kcmsdsummary.desktop" );
00635 }
00636
00637 #include "sdsummarywidget.moc"