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