korganizer

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