koagendaitem.cpp
00001 /* 00002 This file is part of KOrganizer. 00003 00004 Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org> 00005 Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software 00019 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00020 00021 As a special exception, permission is given to link this program 00022 with any edition of TQt, and distribute the resulting executable, 00023 without including the source code for TQt in the source distribution. 00024 */ 00025 00026 #include <tqtooltip.h> 00027 #include <tqdragobject.h> 00028 #include <tqpainter.h> 00029 00030 #include <kiconloader.h> 00031 #include <kdebug.h> 00032 #include <klocale.h> 00033 #include <kwordwrap.h> 00034 #include <kmessagebox.h> 00035 00036 #include <libkcal/icaldrag.h> 00037 #include <libkcal/vcaldrag.h> 00038 #include <libkdepim/kvcarddrag.h> 00039 #include <libemailfunctions/email.h> 00040 #ifndef KORG_NOKABC 00041 #include <kabc/addressee.h> 00042 #include <kabc/vcardconverter.h> 00043 #endif 00044 00045 #include "koprefs.h" 00046 #include "koglobals.h" 00047 00048 #include "koincidencetooltip.h" 00049 #include "koagendaitem.h" 00050 #include "koagendaitem.moc" 00051 00052 //-------------------------------------------------------------------------- 00053 00054 TQToolTipGroup *KOAgendaItem::mToolTipGroup = 0; 00055 00056 TQPixmap *KOAgendaItem::alarmPxmp = 0; 00057 TQPixmap *KOAgendaItem::recurPxmp = 0; 00058 TQPixmap *KOAgendaItem::readonlyPxmp = 0; 00059 TQPixmap *KOAgendaItem::replyPxmp = 0; 00060 TQPixmap *KOAgendaItem::groupPxmp = 0; 00061 TQPixmap *KOAgendaItem::groupPxmpTentative = 0; 00062 TQPixmap *KOAgendaItem::organizerPxmp = 0; 00063 00064 //-------------------------------------------------------------------------- 00065 00066 KOAgendaItem::KOAgendaItem( Calendar *calendar, Incidence *incidence, 00067 const TQDate &qd, TQWidget *parent, 00068 int itemPos, int itemCount, 00069 const char *name, WFlags f ) : 00070 TQWidget( parent, name, f ), mCalendar( calendar ), mIncidence( incidence ), mDate( qd ), 00071 mLabelText( mIncidence->summary() ), mIconAlarm( false ), 00072 mIconRecur( false ), mIconReadonly( false ), mIconReply( false ), 00073 mIconGroup( false ), mIconGroupTentative( false ), mIconOrganizer( false ), 00074 mSpecialEvent( false ), 00075 mItemPos( itemPos ), mItemCount( itemCount ), 00076 mMultiItemInfo( 0 ), mStartMoveInfo( 0 ) 00077 { 00078 setBackgroundMode( TQt::NoBackground ); 00079 00080 setCellXY( 0, 0, 1 ); 00081 setCellXRight( 0 ); 00082 setMouseTracking( true ); 00083 mResourceColor = TQColor(); 00084 updateIcons(); 00085 00086 // select() does nothing, if state hasn't change, so preset mSelected. 00087 mSelected = true; 00088 select( false ); 00089 00090 KOIncidenceToolTip::add( this, mCalendar, incidence, mDate, toolTipGroup() ); 00091 setAcceptDrops( true ); 00092 } 00093 00094 void KOAgendaItem::updateIcons() 00095 { 00096 if ( !mIncidence ) return; 00097 mIconReadonly = mIncidence->isReadOnly(); 00098 mIconRecur = mIncidence->doesRecur(); 00099 mIconAlarm = mIncidence->isAlarmEnabled(); 00100 if ( mIncidence->attendeeCount() > 1 ) { 00101 if ( KOPrefs::instance()->thatIsMe( mIncidence->organizer().email() ) ) { 00102 mIconReply = false; 00103 mIconGroup = false; 00104 mIconGroupTentative = false; 00105 mIconOrganizer = true; 00106 } else { 00107 Attendee *me = mIncidence->attendeeByMails( KOPrefs::instance()->allEmails() ); 00108 if ( me ) { 00109 if ( me->status() == Attendee::NeedsAction && me->RSVP() ) { 00110 mIconReply = true; 00111 mIconGroup = false; 00112 mIconGroupTentative = false; 00113 mIconOrganizer = false; 00114 } else if ( me->status() == Attendee::Tentative ) { 00115 mIconReply = false; 00116 mIconGroup = false; 00117 mIconGroupTentative = true; 00118 mIconOrganizer = false; 00119 } else { 00120 mIconReply = false; 00121 mIconGroup = true; 00122 mIconGroupTentative = false; 00123 mIconOrganizer = false; 00124 } 00125 } else { 00126 mIconReply = false; 00127 mIconGroup = true; 00128 mIconGroupTentative = false; 00129 mIconOrganizer = false; 00130 } 00131 } 00132 } 00133 update(); 00134 } 00135 00136 00137 void KOAgendaItem::select( bool selected ) 00138 { 00139 if ( mSelected == selected ) return; 00140 mSelected = selected; 00141 00142 update(); 00143 } 00144 00145 bool KOAgendaItem::dissociateFromMultiItem() 00146 { 00147 if ( !isMultiItem() ) return false; 00148 KOAgendaItem *firstItem = firstMultiItem(); 00149 if ( firstItem == this ) firstItem = nextMultiItem(); 00150 KOAgendaItem *lastItem = lastMultiItem(); 00151 if ( lastItem == this ) lastItem = prevMultiItem(); 00152 00153 KOAgendaItem *prevItem = prevMultiItem(); 00154 KOAgendaItem *nextItem = nextMultiItem(); 00155 00156 if ( prevItem ) { 00157 prevItem->setMultiItem( firstItem, 00158 prevItem->prevMultiItem(), 00159 nextItem, lastItem ); 00160 } 00161 if ( nextItem ) { 00162 nextItem->setMultiItem( firstItem, prevItem, 00163 nextItem->prevMultiItem(), 00164 lastItem ); 00165 } 00166 delete mMultiItemInfo; 00167 mMultiItemInfo = 0; 00168 return true; 00169 } 00170 00171 bool KOAgendaItem::setIncidence( Incidence *i ) 00172 { 00173 mIncidence = i; 00174 updateIcons(); 00175 return true; 00176 } 00177 00178 /* 00179 Return height of item in units of agenda cells 00180 */ 00181 int KOAgendaItem::cellHeight() const 00182 { 00183 return mCellYBottom - mCellYTop + 1; 00184 } 00185 00186 /* 00187 Return height of item in units of agenda cells 00188 */ 00189 int KOAgendaItem::cellWidth() const 00190 { 00191 return mCellXRight - mCellXLeft + 1; 00192 } 00193 00194 void KOAgendaItem::setItemDate( const TQDate &qd ) 00195 { 00196 mDate = qd; 00197 } 00198 00199 void KOAgendaItem::setCellXY( int X, int YTop, int YBottom ) 00200 { 00201 mCellXLeft = X; 00202 mCellYTop = YTop; 00203 mCellYBottom = YBottom; 00204 } 00205 00206 void KOAgendaItem::setCellXRight( int xright ) 00207 { 00208 mCellXRight = xright; 00209 } 00210 00211 void KOAgendaItem::setCellX( int XLeft, int XRight ) 00212 { 00213 mCellXLeft = XLeft; 00214 mCellXRight = XRight; 00215 } 00216 00217 void KOAgendaItem::setCellY( int YTop, int YBottom ) 00218 { 00219 mCellYTop = YTop; 00220 mCellYBottom = YBottom; 00221 } 00222 00223 void KOAgendaItem::setMultiItem( KOAgendaItem *first, KOAgendaItem *prev, 00224 KOAgendaItem *next, KOAgendaItem *last ) 00225 { 00226 if ( !mMultiItemInfo ) { 00227 mMultiItemInfo = new MultiItemInfo; 00228 } 00229 mMultiItemInfo->mFirstMultiItem = first; 00230 mMultiItemInfo->mPrevMultiItem = prev; 00231 mMultiItemInfo->mNextMultiItem = next; 00232 mMultiItemInfo->mLastMultiItem = last; 00233 } 00234 bool KOAgendaItem::isMultiItem() 00235 { 00236 return mMultiItemInfo; 00237 } 00238 KOAgendaItem* KOAgendaItem::prependMoveItem(KOAgendaItem* e) 00239 { 00240 if (!e) return e; 00241 00242 KOAgendaItem*first=0, *last=0; 00243 if (isMultiItem()) { 00244 first=mMultiItemInfo->mFirstMultiItem; 00245 last=mMultiItemInfo->mLastMultiItem; 00246 } 00247 if (!first) first=this; 00248 if (!last) last=this; 00249 00250 e->setMultiItem(0, 0, first, last); 00251 first->setMultiItem(e, e, first->nextMultiItem(), first->lastMultiItem() ); 00252 00253 KOAgendaItem*tmp=first->nextMultiItem(); 00254 while (tmp) { 00255 tmp->setMultiItem( e, tmp->prevMultiItem(), tmp->nextMultiItem(), tmp->lastMultiItem() ); 00256 tmp = tmp->nextMultiItem(); 00257 } 00258 00259 if ( mStartMoveInfo && !e->moveInfo() ) { 00260 e->mStartMoveInfo=new MultiItemInfo( *mStartMoveInfo ); 00261 // e->moveInfo()->mFirstMultiItem = moveInfo()->mFirstMultiItem; 00262 // e->moveInfo()->mLastMultiItem = moveInfo()->mLastMultiItem; 00263 e->moveInfo()->mPrevMultiItem = 0; 00264 e->moveInfo()->mNextMultiItem = first; 00265 } 00266 00267 if (first && first->moveInfo()) { 00268 first->moveInfo()->mPrevMultiItem = e; 00269 } 00270 return e; 00271 } 00272 00273 KOAgendaItem* KOAgendaItem::appendMoveItem(KOAgendaItem* e) 00274 { 00275 if (!e) return e; 00276 00277 KOAgendaItem*first=0, *last=0; 00278 if (isMultiItem()) { 00279 first=mMultiItemInfo->mFirstMultiItem; 00280 last=mMultiItemInfo->mLastMultiItem; 00281 } 00282 if (!first) first=this; 00283 if (!last) last=this; 00284 00285 e->setMultiItem( first, last, 0, 0 ); 00286 KOAgendaItem*tmp=first; 00287 00288 while (tmp) { 00289 tmp->setMultiItem(tmp->firstMultiItem(), tmp->prevMultiItem(), tmp->nextMultiItem(), e); 00290 tmp = tmp->nextMultiItem(); 00291 } 00292 last->setMultiItem( last->firstMultiItem(), last->prevMultiItem(), e, e); 00293 00294 if ( mStartMoveInfo && !e->moveInfo() ) { 00295 e->mStartMoveInfo=new MultiItemInfo( *mStartMoveInfo ); 00296 // e->moveInfo()->mFirstMultiItem = moveInfo()->mFirstMultiItem; 00297 // e->moveInfo()->mLastMultiItem = moveInfo()->mLastMultiItem; 00298 e->moveInfo()->mPrevMultiItem = last; 00299 e->moveInfo()->mNextMultiItem = 0; 00300 } 00301 if (last && last->moveInfo()) { 00302 last->moveInfo()->mNextMultiItem = e; 00303 } 00304 return e; 00305 } 00306 00307 KOAgendaItem* KOAgendaItem::removeMoveItem(KOAgendaItem* e) 00308 { 00309 if (isMultiItem()) { 00310 KOAgendaItem *first = mMultiItemInfo->mFirstMultiItem; 00311 KOAgendaItem *next, *prev; 00312 KOAgendaItem *last = mMultiItemInfo->mLastMultiItem; 00313 if (!first) first = this; 00314 if (!last) last = this; 00315 if ( first==e ) { 00316 first = first->nextMultiItem(); 00317 first->setMultiItem( 0, 0, first->nextMultiItem(), first->lastMultiItem() ); 00318 } 00319 if ( last==e ) { 00320 last=last->prevMultiItem(); 00321 last->setMultiItem( last->firstMultiItem(), last->prevMultiItem(), 0, 0 ); 00322 } 00323 00324 KOAgendaItem *tmp = first; 00325 if ( first==last ) { 00326 delete mMultiItemInfo; 00327 tmp = 0; 00328 mMultiItemInfo = 0; 00329 } 00330 while ( tmp ) { 00331 next = tmp->nextMultiItem(); 00332 prev = tmp->prevMultiItem(); 00333 if ( e==next ) { 00334 next = next->nextMultiItem(); 00335 } 00336 if ( e==prev ) { 00337 prev = prev->prevMultiItem(); 00338 } 00339 tmp->setMultiItem((tmp==first)?0:first, (tmp==prev)?0:prev, (tmp==next)?0:next, (tmp==last)?0:last); 00340 tmp = tmp->nextMultiItem(); 00341 } 00342 } 00343 00344 return e; 00345 } 00346 00347 00348 void KOAgendaItem::startMove() 00349 { 00350 KOAgendaItem* first = this; 00351 if ( isMultiItem() && mMultiItemInfo->mFirstMultiItem ) { 00352 first=mMultiItemInfo->mFirstMultiItem; 00353 } 00354 first->startMovePrivate(); 00355 } 00356 00357 void KOAgendaItem::startMovePrivate() 00358 { 00359 mStartMoveInfo = new MultiItemInfo; 00360 mStartMoveInfo->mStartCellXLeft = mCellXLeft; 00361 mStartMoveInfo->mStartCellXRight = mCellXRight; 00362 mStartMoveInfo->mStartCellYTop = mCellYTop; 00363 mStartMoveInfo->mStartCellYBottom = mCellYBottom; 00364 if (mMultiItemInfo) { 00365 mStartMoveInfo->mFirstMultiItem = mMultiItemInfo->mFirstMultiItem; 00366 mStartMoveInfo->mLastMultiItem = mMultiItemInfo->mLastMultiItem; 00367 mStartMoveInfo->mPrevMultiItem = mMultiItemInfo->mPrevMultiItem; 00368 mStartMoveInfo->mNextMultiItem = mMultiItemInfo->mNextMultiItem; 00369 } else { 00370 mStartMoveInfo->mFirstMultiItem = 0; 00371 mStartMoveInfo->mLastMultiItem = 0; 00372 mStartMoveInfo->mPrevMultiItem = 0; 00373 mStartMoveInfo->mNextMultiItem = 0; 00374 } 00375 if ( isMultiItem() && mMultiItemInfo->mNextMultiItem ) 00376 { 00377 mMultiItemInfo->mNextMultiItem->startMovePrivate(); 00378 } 00379 } 00380 00381 void KOAgendaItem::resetMove() 00382 { 00383 if ( mStartMoveInfo ) { 00384 if ( mStartMoveInfo->mFirstMultiItem ) { 00385 mStartMoveInfo->mFirstMultiItem->resetMovePrivate(); 00386 } else { 00387 resetMovePrivate(); 00388 } 00389 } 00390 } 00391 00392 void KOAgendaItem::resetMovePrivate() 00393 { 00394 if (mStartMoveInfo) { 00395 mCellXLeft = mStartMoveInfo->mStartCellXLeft; 00396 mCellXRight = mStartMoveInfo->mStartCellXRight; 00397 mCellYTop = mStartMoveInfo->mStartCellYTop; 00398 mCellYBottom = mStartMoveInfo->mStartCellYBottom; 00399 00400 // if we don't have mMultiItemInfo, the item didn't span two days before, 00401 // and wasn't moved over midnight, either, so we don't have to reset 00402 // anything. Otherwise, restore from mMoveItemInfo 00403 if ( mMultiItemInfo ) { 00404 // It was already a multi-day info 00405 mMultiItemInfo->mFirstMultiItem = mStartMoveInfo->mFirstMultiItem; 00406 mMultiItemInfo->mPrevMultiItem = mStartMoveInfo->mPrevMultiItem; 00407 mMultiItemInfo->mNextMultiItem = mStartMoveInfo->mNextMultiItem; 00408 mMultiItemInfo->mLastMultiItem = mStartMoveInfo->mLastMultiItem; 00409 00410 if ( !mStartMoveInfo->mFirstMultiItem ) { 00411 // This was the first multi-item when the move started, delete all previous 00412 KOAgendaItem*toDel=mStartMoveInfo->mPrevMultiItem; 00413 KOAgendaItem*nowDel=0L; 00414 while (toDel) { 00415 nowDel=toDel; 00416 if (nowDel->moveInfo()) { 00417 toDel=nowDel->moveInfo()->mPrevMultiItem; 00418 } 00419 emit removeAgendaItem( nowDel ); 00420 } 00421 mMultiItemInfo->mFirstMultiItem = 0L; 00422 mMultiItemInfo->mPrevMultiItem = 0L; 00423 } 00424 if ( !mStartMoveInfo->mLastMultiItem ) { 00425 // This was the last multi-item when the move started, delete all next 00426 KOAgendaItem*toDel=mStartMoveInfo->mNextMultiItem; 00427 KOAgendaItem*nowDel=0L; 00428 while (toDel) { 00429 nowDel=toDel; 00430 if (nowDel->moveInfo()) { 00431 toDel=nowDel->moveInfo()->mNextMultiItem; 00432 } 00433 emit removeAgendaItem( nowDel ); 00434 } 00435 mMultiItemInfo->mLastMultiItem = 0L; 00436 mMultiItemInfo->mNextMultiItem = 0L; 00437 } 00438 00439 if ( mStartMoveInfo->mFirstMultiItem==0 && mStartMoveInfo->mLastMultiItem==0 ) { 00440 // it was a single-day event before we started the move. 00441 delete mMultiItemInfo; 00442 mMultiItemInfo = 0; 00443 } 00444 } 00445 delete mStartMoveInfo; 00446 mStartMoveInfo = 0; 00447 } 00448 emit showAgendaItem( this ); 00449 if ( nextMultiItem() ) { 00450 nextMultiItem()->resetMovePrivate(); 00451 } 00452 } 00453 00454 void KOAgendaItem::endMove() 00455 { 00456 KOAgendaItem*first=firstMultiItem(); 00457 if (!first) first=this; 00458 first->endMovePrivate(); 00459 } 00460 00461 void KOAgendaItem::endMovePrivate() 00462 { 00463 if ( mStartMoveInfo ) { 00464 // if first, delete all previous 00465 if ( !firstMultiItem() || firstMultiItem()==this ) { 00466 KOAgendaItem*toDel=mStartMoveInfo->mPrevMultiItem; 00467 KOAgendaItem*nowDel = 0; 00468 while (toDel) { 00469 nowDel=toDel; 00470 if (nowDel->moveInfo()) { 00471 toDel=nowDel->moveInfo()->mPrevMultiItem; 00472 } 00473 emit removeAgendaItem( nowDel ); 00474 } 00475 } 00476 // if last, delete all next 00477 if ( !lastMultiItem() || lastMultiItem()==this ) { 00478 KOAgendaItem*toDel=mStartMoveInfo->mNextMultiItem; 00479 KOAgendaItem*nowDel = 0; 00480 while (toDel) { 00481 nowDel=toDel; 00482 if (nowDel->moveInfo()) { 00483 toDel=nowDel->moveInfo()->mNextMultiItem; 00484 } 00485 emit removeAgendaItem( nowDel ); 00486 } 00487 } 00488 // also delete the moving info 00489 delete mStartMoveInfo; 00490 mStartMoveInfo=0; 00491 if ( nextMultiItem() ) 00492 nextMultiItem()->endMovePrivate(); 00493 } 00494 } 00495 00496 void KOAgendaItem::moveRelative(int dx, int dy) 00497 { 00498 int newXLeft = cellXLeft() + dx; 00499 int newXRight = cellXRight() + dx; 00500 int newYTop = cellYTop() + dy; 00501 int newYBottom = cellYBottom() + dy; 00502 setCellXY(newXLeft,newYTop,newYBottom); 00503 setCellXRight(newXRight); 00504 } 00505 00506 void KOAgendaItem::expandTop(int dy) 00507 { 00508 int newYTop = cellYTop() + dy; 00509 int newYBottom = cellYBottom(); 00510 if (newYTop > newYBottom) newYTop = newYBottom; 00511 setCellY(newYTop, newYBottom); 00512 } 00513 00514 void KOAgendaItem::expandBottom(int dy) 00515 { 00516 int newYTop = cellYTop(); 00517 int newYBottom = cellYBottom() + dy; 00518 if (newYBottom < newYTop) newYBottom = newYTop; 00519 setCellY(newYTop, newYBottom); 00520 } 00521 00522 void KOAgendaItem::expandLeft(int dx) 00523 { 00524 int newXLeft = cellXLeft() + dx; 00525 int newXRight = cellXRight(); 00526 if ( newXLeft > newXRight ) newXLeft = newXRight; 00527 setCellX( newXLeft, newXRight ); 00528 } 00529 00530 void KOAgendaItem::expandRight(int dx) 00531 { 00532 int newXLeft = cellXLeft(); 00533 int newXRight = cellXRight() + dx; 00534 if ( newXRight < newXLeft ) newXRight = newXLeft; 00535 setCellX( newXLeft, newXRight ); 00536 } 00537 00538 TQToolTipGroup *KOAgendaItem::toolTipGroup() 00539 { 00540 if (!mToolTipGroup) mToolTipGroup = new TQToolTipGroup(0); 00541 return mToolTipGroup; 00542 } 00543 00544 void KOAgendaItem::dragEnterEvent( TQDragEnterEvent *e ) 00545 { 00546 #ifndef KORG_NODND 00547 if ( ICalDrag::canDecode( e ) || VCalDrag::canDecode( e ) ) { 00548 e->ignore(); 00549 return; 00550 } 00551 if ( KVCardDrag::canDecode( e ) || TQTextDrag::canDecode( e ) ) 00552 e->accept(); 00553 else 00554 e->ignore(); 00555 #endif 00556 } 00557 00558 void KOAgendaItem::addAttendee( const TQString &newAttendee ) 00559 { 00560 kdDebug(5850) << " Email: " << newAttendee << endl; 00561 TQString name, email; 00562 KPIM::getNameAndMail( newAttendee, name, email ); 00563 if ( !( name.isEmpty() && email.isEmpty() ) ) { 00564 mIncidence->addAttendee(new Attendee(name,email)); 00565 KMessageBox::information( this, i18n("Attendee \"%1\" added to the calendar item \"%2\"").arg(KPIM::normalizedAddress(name, email, TQString())).arg(text()), i18n("Attendee added"), "AttendeeDroppedAdded" ); 00566 } 00567 00568 } 00569 00570 void KOAgendaItem::dropEvent( TQDropEvent *e ) 00571 { 00572 // TODO: Organize this better: First check for attachment (not only file, also any other url!), then if it's a vcard, otherwise check for attendees, then if the data is binary, add a binary attachment. 00573 #ifndef KORG_NODND 00574 TQString text; 00575 00576 bool decoded = TQTextDrag::decode( e, text ); 00577 if( decoded && text.startsWith( "file:" ) ) { 00578 mIncidence->addAttachment( new Attachment( text ) ); 00579 return; 00580 } 00581 00582 #ifndef KORG_NOKABC 00583 KABC::Addressee::List list; 00584 if ( KVCardDrag::decode( e, list ) ) { 00585 KABC::Addressee::List::Iterator it; 00586 for ( it = list.begin(); it != list.end(); ++it ) { 00587 TQString em( (*it).fullEmail() ); 00588 if ( em.isEmpty() ) { 00589 em = (*it).realName(); 00590 } 00591 addAttendee( em ); 00592 } 00593 } 00594 #else 00595 if( decoded ) { 00596 kdDebug(5850) << "Dropped : " << text << endl; 00597 00598 TQStringList emails = TQStringList::split( ",", text ); 00599 for( TQStringList::ConstIterator it = emails.begin(); it != emails.end(); 00600 ++it ) { 00601 addAttendee( *it ); 00602 } 00603 } 00604 #endif // KORG_NOKABC 00605 00606 #endif // KORG_NODND 00607 } 00608 00609 00610 TQPtrList<KOAgendaItem> KOAgendaItem::conflictItems() 00611 { 00612 return mConflictItems; 00613 } 00614 00615 void KOAgendaItem::setConflictItems( TQPtrList<KOAgendaItem> ci ) 00616 { 00617 mConflictItems = ci; 00618 KOAgendaItem *item; 00619 for ( item = mConflictItems.first(); item != 0; 00620 item = mConflictItems.next() ) { 00621 item->addConflictItem( this ); 00622 } 00623 } 00624 00625 void KOAgendaItem::addConflictItem( KOAgendaItem *ci ) 00626 { 00627 if ( mConflictItems.find( ci ) < 0 ) mConflictItems.append( ci ); 00628 } 00629 00630 TQString KOAgendaItem::label() const 00631 { 00632 return mLabelText; 00633 } 00634 00635 bool KOAgendaItem::overlaps( KOrg::CellItem *o ) const 00636 { 00637 KOAgendaItem *other = static_cast<KOAgendaItem *>( o ); 00638 00639 if ( cellXLeft() <= other->cellXRight() && 00640 cellXRight() >= other->cellXLeft() ) { 00641 if ( ( cellYTop() <= other->cellYBottom() ) && 00642 ( cellYBottom() >= other->cellYTop() ) ) { 00643 return true; 00644 } 00645 } 00646 00647 return false; 00648 } 00649 00650 void KOAgendaItem::paintFrame( TQPainter *p, const TQColor &color ) 00651 { 00652 TQColor oldpen(p->pen().color()); 00653 p->setPen( color ); 00654 p->drawRect( 0, 0, width(), height() ); 00655 p->drawRect( 1, 1, width() - 2, height() - 2 ); 00656 p->setPen( oldpen ); 00657 } 00658 00659 static void conditionalPaint( TQPainter *p, bool cond, int &x, int ft, 00660 const TQPixmap &pxmp ) 00661 { 00662 if ( !cond ) return; 00663 00664 p->drawPixmap( x, ft, pxmp ); 00665 x += pxmp.width() + ft; 00666 } 00667 00668 void KOAgendaItem::paintEventIcon( TQPainter *p, int &x, int ft ) 00669 { 00670 if ( !mIncidence ) return; 00671 00672 if ( mIncidence->type() == "Event" ) { 00673 TQPixmap eventPxmp; 00674 if ( mIncidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) { 00675 mSpecialEvent = true; 00676 if ( mIncidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) { 00677 eventPxmp = KOGlobals::self()->smallIcon( "calendaranniversary" ); 00678 } else { 00679 eventPxmp = KOGlobals::self()->smallIcon( "calendarbirthday" ); 00680 } 00681 conditionalPaint( p, true, x, ft, eventPxmp ); 00682 } 00683 // per kolab/issue4349 we don't draw a regular appointment icon (to save space) 00684 } 00685 00686 } 00687 00688 void KOAgendaItem::paintTodoIcon( TQPainter *p, int &x, int ft ) 00689 { 00690 if ( !mIncidence ) return; 00691 static const TQPixmap todoPxmp = 00692 KOGlobals::self()->smallIcon( "todo" ); 00693 static const TQPixmap completedPxmp = 00694 KOGlobals::self()->smallIcon( "checkedbox" ); 00695 if ( mIncidence->type() != "Todo" ) 00696 return; 00697 bool b = ( static_cast<Todo *>( mIncidence ) )->isCompleted(); 00698 conditionalPaint( p, !b, x, ft, todoPxmp ); 00699 conditionalPaint( p, b, x, ft, completedPxmp ); 00700 } 00701 00702 void KOAgendaItem::paintAlarmIcon( TQPainter *p, int &x, int ft ) 00703 { 00704 if (!mIconAlarm) return; 00705 int y = ft; 00706 // if we can't fit it all, bottom align it, more or less, so 00707 // it can be guessed better, visually 00708 if ( visibleRect().height() - ft < alarmPxmp->height() ) 00709 y -= ( alarmPxmp->height() - visibleRect().height() - ft ); 00710 p->drawPixmap( x, y, *alarmPxmp ); 00711 x += alarmPxmp->width() + ft; 00712 } 00713 00714 void KOAgendaItem::paintIcons( TQPainter *p, int &x, int ft ) 00715 { 00716 paintEventIcon( p, x, ft ); 00717 paintTodoIcon( p, x, ft ); 00718 if ( !mSpecialEvent ) { 00719 paintAlarmIcon( p, x, ft ); 00720 } 00721 conditionalPaint( p, mIconRecur && !mSpecialEvent, x, ft, *recurPxmp ); 00722 conditionalPaint( p, mIconReadonly && !mSpecialEvent, x, ft, *readonlyPxmp ); 00723 conditionalPaint( p, mIconReply, x, ft, *replyPxmp ); 00724 conditionalPaint( p, mIconGroup, x, ft, *groupPxmp ); 00725 conditionalPaint( p, mIconGroupTentative, x, ft, *groupPxmpTentative ); 00726 conditionalPaint( p, mIconOrganizer, x, ft, *organizerPxmp ); 00727 } 00728 00729 void KOAgendaItem::paintEvent( TQPaintEvent *ev ) 00730 { 00731 //HACK 00732 // to reproduce a crash: 00733 // 1. start Kontact with the Calendar as the initial module 00734 // 2. immediately select the summary (which must include appt and to-do) 00735 // causes a crash for me every time in this method unless we make 00736 // the following check 00737 if ( !mIncidence )return; 00738 00739 TQRect visRect = visibleRect(); 00740 // when scrolling horizontally in the side-by-side view, the repainted area is clipped 00741 // to the newly visible area, which is a problem since the content changes when visRect 00742 // changes, so repaint the full item in that case 00743 if ( ev->rect() != visRect && visRect.isValid() && ev->rect().isValid() ) { 00744 repaint( visRect ); 00745 return; 00746 } 00747 00748 TQPainter p( this ); 00749 const int ft = 2; // frame thickness for layout, see paintFrame() 00750 const int margin = 1 + ft; // frame + space between frame and content 00751 00752 // General idea is to always show the icons (even in the all-day events). 00753 // This creates a consistent fealing for the user when the view mode 00754 // changes and therefore the available width changes. 00755 // Also look at #17984 00756 00757 if ( !alarmPxmp ) { 00758 alarmPxmp = new TQPixmap( KOGlobals::self()->smallIcon("bell") ); 00759 recurPxmp = new TQPixmap( KOGlobals::self()->smallIcon("recur") ); 00760 readonlyPxmp = new TQPixmap( KOGlobals::self()->smallIcon("readonlyevent") ); 00761 replyPxmp = new TQPixmap( KOGlobals::self()->smallIcon("mail_reply") ); 00762 groupPxmp = new TQPixmap( KOGlobals::self()->smallIcon("groupevent") ); 00763 groupPxmpTentative = new TQPixmap( KOGlobals::self()->smallIcon("groupeventtentative") ); 00764 organizerPxmp = new TQPixmap( KOGlobals::self()->smallIcon("organizer") ); 00765 } 00766 00767 TQColor bgColor; 00768 if ( mIncidence->type() == "Todo" ) { 00769 if ( static_cast<Todo*>(mIncidence)->isOverdue() ) 00770 bgColor = KOPrefs::instance()->todoOverdueColor(); 00771 else if ( static_cast<Todo*>(mIncidence)->dtDue().date() == 00772 TQDateTime::currentDateTime().date() ) 00773 bgColor = KOPrefs::instance()->todoDueTodayColor(); 00774 } 00775 00776 TQColor categoryColor; 00777 TQStringList categories = mIncidence->categories(); 00778 TQString cat = categories.first(); 00779 if (cat.isEmpty()) 00780 categoryColor = KOPrefs::instance()->unsetCategoryColor(); 00781 else 00782 categoryColor = *(KOPrefs::instance()->categoryColor(cat)); 00783 00784 TQColor resourceColor = mResourceColor; 00785 if ( !resourceColor.isValid() ) 00786 resourceColor = categoryColor; 00787 00788 TQColor frameColor; 00789 if ( KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceOnly || 00790 KOPrefs::instance()->agendaViewColors() == KOPrefs::CategoryInsideResourceOutside ) { 00791 frameColor = bgColor.isValid() ? bgColor : resourceColor; 00792 } else { 00793 frameColor = bgColor.isValid() ? bgColor : categoryColor; 00794 } 00795 00796 if ( !bgColor.isValid() ) { 00797 if ( KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceOnly || 00798 KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceInsideCategoryOutside ) { 00799 bgColor = resourceColor; 00800 } else { 00801 bgColor = categoryColor; 00802 } 00803 } 00804 00805 if ( cat.isEmpty() && 00806 KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceInsideCategoryOutside ) { 00807 frameColor = bgColor; 00808 } 00809 00810 if ( cat.isEmpty() && 00811 KOPrefs::instance()->agendaViewColors() == KOPrefs::CategoryInsideResourceOutside ) { 00812 bgColor = frameColor; 00813 } 00814 00815 if ( mSelected ) { 00816 frameColor = TQColor( 85 + frameColor.red() * 2/3, 00817 85 + frameColor.green() * 2/3, 00818 85 + frameColor.blue() * 2/3 ); 00819 } else { 00820 frameColor = frameColor.dark( 115 ); 00821 } 00822 TQColor textColor = getTextColor(bgColor); 00823 p.setPen( textColor ); 00824 p.setBackgroundColor( bgColor ); 00825 p.setFont(KOPrefs::instance()->mAgendaViewFont); 00826 TQFontMetrics fm = p.fontMetrics(); 00827 00828 int singleLineHeight = fm.boundingRect( mLabelText ).height(); 00829 00830 p.eraseRect( 0, 0, width(), height() ); 00831 paintFrame( &p, frameColor ); 00832 00833 // calculate the height of the full version (case 4) to test whether it is 00834 // possible 00835 00836 TQString shortH; 00837 TQString longH; 00838 if ( !isMultiItem() ) { 00839 shortH = KGlobal::locale()->formatTime(mIncidence->dtStart().time()); 00840 if (mIncidence->type() != "Todo") 00841 longH = i18n("%1 - %2").arg(shortH) 00842 .arg(KGlobal::locale()->formatTime(mIncidence->dtEnd().time())); 00843 else 00844 longH = shortH; 00845 } else if ( !mMultiItemInfo->mFirstMultiItem ) { 00846 shortH = KGlobal::locale()->formatTime(mIncidence->dtStart().time()); 00847 longH = shortH; 00848 } else { 00849 shortH = KGlobal::locale()->formatTime(mIncidence->dtEnd().time()); 00850 longH = i18n("- %1").arg(shortH); 00851 } 00852 00853 KWordWrap *ww = KWordWrap::formatText( fm, 00854 TQRect(0, 0, width() - (2 * margin), -1), 00855 0, 00856 mLabelText ); 00857 int th = ww->boundingRect().height(); 00858 delete ww; 00859 00860 int hlHeight = TQMAX(fm.boundingRect(longH).height(), 00861 TQMAX(alarmPxmp->height(), TQMAX(recurPxmp->height(), 00862 TQMAX(readonlyPxmp->height(), TQMAX(replyPxmp->height(), 00863 TQMAX(groupPxmp->height(), organizerPxmp->height())))))); 00864 00865 bool completelyRenderable = th < (height() - 2 * ft - 2 - hlHeight); 00866 00867 // case 1: do not draw text when not even a single line fits 00868 // Don't do this any more, always try to print out the text. Even if 00869 // it's just a few pixel, one can still guess the whole text from just four pixels' height! 00870 if ( //( singleLineHeight > height()-4 ) || // ignore margin, be gentle.. Even ignore 2 pixel outside the item 00871 ( width() < 16 ) ) { 00872 int x = margin; 00873 paintTodoIcon( &p, x, ft ); 00874 return; 00875 } 00876 00877 // case 2: draw a single line when no more space 00878 if ( (2 * singleLineHeight) > (height() - 2 * margin) ) { 00879 int x = margin, txtWidth; 00880 00881 if ( mIncidence->doesFloat() ) { 00882 x += visRect.left(); 00883 paintIcons( &p, x, ft ); 00884 txtWidth = visRect.right() - margin - x; 00885 } 00886 else { 00887 paintIcons( &p, x, ft ); 00888 txtWidth = width() - margin - x; 00889 } 00890 00891 int y = ((height() - 2 * ft - singleLineHeight) / 2) + fm.ascent(); 00892 KWordWrap::drawFadeoutText( &p, x, y, 00893 txtWidth, mLabelText ); 00894 return; 00895 } 00896 00897 // case 3: enough for 2-5 lines, but not for the header. 00898 // Also used for the middle days in multi-events 00899 if ( ((!completelyRenderable) && ((height() - (2 * margin)) <= (5 * singleLineHeight)) ) || 00900 (isMultiItem() && mMultiItemInfo->mNextMultiItem && mMultiItemInfo->mFirstMultiItem) ) { 00901 int x = margin, txtWidth; 00902 00903 if ( mIncidence->doesFloat() ) { 00904 x += visRect.left(); 00905 paintIcons( &p, x, ft ); 00906 txtWidth = visRect.right() - margin - x; 00907 } 00908 else { 00909 paintIcons( &p, x, ft ); 00910 txtWidth = width() - margin - x; 00911 } 00912 00913 ww = KWordWrap::formatText( fm, 00914 TQRect( 0, 0, txtWidth, 00915 (height() - (2 * margin)) ), 00916 0, 00917 mLabelText ); 00918 00919 //kdDebug() << "SIZES for " << mLabelText << ": " << width() << " :: " << txtWidth << endl; 00920 ww->drawText( &p, x, margin, TQt::AlignHCenter | KWordWrap::FadeOut ); 00921 delete ww; 00922 return; 00923 } 00924 00925 // case 4: paint everything, with header: 00926 // consists of (vertically) ft + headline&icons + ft + text + margin 00927 int y = 2 * ft + hlHeight; 00928 if ( completelyRenderable ) 00929 y += (height() - (2 * ft) - margin - hlHeight - th) / 2; 00930 00931 int x = margin, txtWidth, hTxtWidth, eventX; 00932 00933 if ( mIncidence->doesFloat() ) { 00934 shortH = longH = ""; 00935 00936 if ( (mIncidence->type() != "Todo") && 00937 (mIncidence->dtStart() != mIncidence->dtEnd()) ) { // multi days 00938 shortH = longH = 00939 i18n("%1 - %2") 00940 .arg(KGlobal::locale()->formatDate(mIncidence->dtStart().date())) 00941 .arg(KGlobal::locale()->formatDate(mIncidence->dtEnd().date())); 00942 00943 // paint headline 00944 p.fillRect( 0, 0, width(), (ft/2) + margin + hlHeight, 00945 TQBrush( frameColor ) ); 00946 } 00947 00948 x += visRect.left(); 00949 eventX = x; 00950 txtWidth = visRect.right() - margin - x; 00951 paintIcons( &p, x, ft ); 00952 hTxtWidth = visRect.right() - margin - x; 00953 } 00954 else { 00955 // paint headline 00956 p.fillRect( 0, 0, width(), (ft/2) + margin + hlHeight, 00957 TQBrush( frameColor ) ); 00958 00959 txtWidth = width() - margin - x; 00960 eventX = x; 00961 paintIcons( &p, x, ft ); 00962 hTxtWidth = width() - margin - x; 00963 } 00964 00965 TQString headline; 00966 int hw = fm.boundingRect( longH ).width(); 00967 if ( hw > hTxtWidth ) { 00968 headline = shortH; 00969 hw = fm.boundingRect( shortH ).width(); 00970 if ( hw < txtWidth ) 00971 x += (hTxtWidth - hw) / 2; 00972 } else { 00973 headline = longH; 00974 x += (hTxtWidth - hw) / 2; 00975 } 00976 p.setBackgroundColor( frameColor ); 00977 p.setPen( getTextColor( frameColor ) ); 00978 KWordWrap::drawFadeoutText( &p, x, ft + fm.ascent(), hTxtWidth, headline ); 00979 00980 // draw event text 00981 ww = KWordWrap::formatText( fm, 00982 TQRect( 0, 0, txtWidth, height() - margin - y ), 00983 0, 00984 mLabelText ); 00985 00986 p.setBackgroundColor( bgColor ); 00987 p.setPen( textColor ); 00988 TQString ws = ww->wrappedString(); 00989 if ( ws.left( ws.length()-1 ).find( '\n' ) >= 0 ) 00990 ww->drawText( &p, eventX, y, 00991 TQt::AlignAuto | KWordWrap::FadeOut ); 00992 else 00993 ww->drawText( &p, eventX + (txtWidth-ww->boundingRect().width()-2*margin)/2, 00994 y, TQt::AlignHCenter | KWordWrap::FadeOut ); 00995 delete ww; 00996 } 00997