/* This file is part of KOrganizer. Copyright (c) 2000,2001,2003 Cornelius Schumacher Copyright (C) 2003-2004 Reinhold Kainhofer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. As a special exception, permission is given to link this program with any edition of TQt, and distribute the resulting executable, without including the source code for TQt in the source distribution. */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef KORG_NOKABC #include #include #endif #include "koprefs.h" #include "koglobals.h" #include "koincidencetooltip.h" #include "koagendaitem.h" #include "koagendaitem.moc" //-------------------------------------------------------------------------- TQToolTipGroup *KOAgendaItem::mToolTipGroup = 0; TQPixmap *KOAgendaItem::alarmPxmp = 0; TQPixmap *KOAgendaItem::recurPxmp = 0; TQPixmap *KOAgendaItem::readonlyPxmp = 0; TQPixmap *KOAgendaItem::replyPxmp = 0; TQPixmap *KOAgendaItem::groupPxmp = 0; TQPixmap *KOAgendaItem::groupPxmpTentative = 0; TQPixmap *KOAgendaItem::organizerPxmp = 0; //-------------------------------------------------------------------------- KOAgendaItem::KOAgendaItem( Calendar *calendar, Incidence *incidence, const TQDate &qd, TQWidget *tqparent, int itemPos, int itemCount, const char *name, WFlags f ) : TQWidget( tqparent, name, f ), mCalendar( calendar ), mIncidence( incidence ), mDate( qd ), mLabelText( mIncidence->summary() ), mIconAlarm( false ), mIconRecur( false ), mIconReadonly( false ), mIconReply( false ), mIconGroup( false ), mIconGroupTentative( false ), mIconOrganizer( false ), mSpecialEvent( false ), mItemPos( itemPos ), mItemCount( itemCount ), mMultiItemInfo( 0 ), mStartMoveInfo( 0 ) { setBackgroundMode( TQt::NoBackground ); setCellXY( 0, 0, 1 ); setCellXRight( 0 ); setMouseTracking( true ); mResourceColor = TQColor(); updateIcons(); // select() does nothing, if state hasn't change, so preset mSelected. mSelected = true; select( false ); KOIncidenceToolTip::add( this, mCalendar, incidence, mDate, toolTipGroup() ); setAcceptDrops( true ); } void KOAgendaItem::updateIcons() { if ( !mIncidence ) return; mIconReadonly = mIncidence->isReadOnly(); mIconRecur = mIncidence->doesRecur(); mIconAlarm = mIncidence->isAlarmEnabled(); if ( mIncidence->attendeeCount() > 1 ) { if ( KOPrefs::instance()->thatIsMe( mIncidence->organizer().email() ) ) { mIconReply = false; mIconGroup = false; mIconGroupTentative = false; mIconOrganizer = true; } else { Attendee *me = mIncidence->attendeeByMails( KOPrefs::instance()->allEmails() ); if ( me ) { if ( me->status() == Attendee::NeedsAction && me->RSVP() ) { mIconReply = true; mIconGroup = false; mIconGroupTentative = false; mIconOrganizer = false; } else if ( me->status() == Attendee::Tentative ) { mIconReply = false; mIconGroup = false; mIconGroupTentative = true; mIconOrganizer = false; } else { mIconReply = false; mIconGroup = true; mIconGroupTentative = false; mIconOrganizer = false; } } else { mIconReply = false; mIconGroup = true; mIconGroupTentative = false; mIconOrganizer = false; } } } update(); } void KOAgendaItem::select( bool selected ) { if ( mSelected == selected ) return; mSelected = selected; update(); } bool KOAgendaItem::dissociateFromMultiItem() { if ( !isMultiItem() ) return false; KOAgendaItem *firstItem = firstMultiItem(); if ( firstItem == this ) firstItem = nextMultiItem(); KOAgendaItem *lastItem = lastMultiItem(); if ( lastItem == this ) lastItem = prevMultiItem(); KOAgendaItem *prevItem = prevMultiItem(); KOAgendaItem *nextItem = nextMultiItem(); if ( prevItem ) { prevItem->setMultiItem( firstItem, prevItem->prevMultiItem(), nextItem, lastItem ); } if ( nextItem ) { nextItem->setMultiItem( firstItem, prevItem, nextItem->prevMultiItem(), lastItem ); } delete mMultiItemInfo; mMultiItemInfo = 0; return true; } bool KOAgendaItem::setIncidence( Incidence *i ) { mIncidence = i; updateIcons(); return true; } /* Return height of item in units of agenda cells */ int KOAgendaItem::cellHeight() const { return mCellYBottom - mCellYTop + 1; } /* Return height of item in units of agenda cells */ int KOAgendaItem::cellWidth() const { return mCellXRight - mCellXLeft + 1; } void KOAgendaItem::setItemDate( const TQDate &qd ) { mDate = qd; } void KOAgendaItem::setCellXY( int X, int YTop, int YBottom ) { mCellXLeft = X; mCellYTop = YTop; mCellYBottom = YBottom; } void KOAgendaItem::setCellXRight( int xright ) { mCellXRight = xright; } void KOAgendaItem::setCellX( int XLeft, int XRight ) { mCellXLeft = XLeft; mCellXRight = XRight; } void KOAgendaItem::setCellY( int YTop, int YBottom ) { mCellYTop = YTop; mCellYBottom = YBottom; } void KOAgendaItem::setMultiItem( KOAgendaItem *first, KOAgendaItem *prev, KOAgendaItem *next, KOAgendaItem *last ) { if ( !mMultiItemInfo ) { mMultiItemInfo = new MultiItemInfo; } mMultiItemInfo->mFirstMultiItem = first; mMultiItemInfo->mPrevMultiItem = prev; mMultiItemInfo->mNextMultiItem = next; mMultiItemInfo->mLastMultiItem = last; } bool KOAgendaItem::isMultiItem() { return mMultiItemInfo; } KOAgendaItem* KOAgendaItem::prependMoveItem(KOAgendaItem* e) { if (!e) return e; KOAgendaItem*first=0, *last=0; if (isMultiItem()) { first=mMultiItemInfo->mFirstMultiItem; last=mMultiItemInfo->mLastMultiItem; } if (!first) first=this; if (!last) last=this; e->setMultiItem(0, 0, first, last); first->setMultiItem(e, e, first->nextMultiItem(), first->lastMultiItem() ); KOAgendaItem*tmp=first->nextMultiItem(); while (tmp) { tmp->setMultiItem( e, tmp->prevMultiItem(), tmp->nextMultiItem(), tmp->lastMultiItem() ); tmp = tmp->nextMultiItem(); } if ( mStartMoveInfo && !e->moveInfo() ) { e->mStartMoveInfo=new MultiItemInfo( *mStartMoveInfo ); // e->moveInfo()->mFirstMultiItem = moveInfo()->mFirstMultiItem; // e->moveInfo()->mLastMultiItem = moveInfo()->mLastMultiItem; e->moveInfo()->mPrevMultiItem = 0; e->moveInfo()->mNextMultiItem = first; } if (first && first->moveInfo()) { first->moveInfo()->mPrevMultiItem = e; } return e; } KOAgendaItem* KOAgendaItem::appendMoveItem(KOAgendaItem* e) { if (!e) return e; KOAgendaItem*first=0, *last=0; if (isMultiItem()) { first=mMultiItemInfo->mFirstMultiItem; last=mMultiItemInfo->mLastMultiItem; } if (!first) first=this; if (!last) last=this; e->setMultiItem( first, last, 0, 0 ); KOAgendaItem*tmp=first; while (tmp) { tmp->setMultiItem(tmp->firstMultiItem(), tmp->prevMultiItem(), tmp->nextMultiItem(), e); tmp = tmp->nextMultiItem(); } last->setMultiItem( last->firstMultiItem(), last->prevMultiItem(), e, e); if ( mStartMoveInfo && !e->moveInfo() ) { e->mStartMoveInfo=new MultiItemInfo( *mStartMoveInfo ); // e->moveInfo()->mFirstMultiItem = moveInfo()->mFirstMultiItem; // e->moveInfo()->mLastMultiItem = moveInfo()->mLastMultiItem; e->moveInfo()->mPrevMultiItem = last; e->moveInfo()->mNextMultiItem = 0; } if (last && last->moveInfo()) { last->moveInfo()->mNextMultiItem = e; } return e; } KOAgendaItem* KOAgendaItem::removeMoveItem(KOAgendaItem* e) { if (isMultiItem()) { KOAgendaItem *first = mMultiItemInfo->mFirstMultiItem; KOAgendaItem *next, *prev; KOAgendaItem *last = mMultiItemInfo->mLastMultiItem; if (!first) first = this; if (!last) last = this; if ( first==e ) { first = first->nextMultiItem(); first->setMultiItem( 0, 0, first->nextMultiItem(), first->lastMultiItem() ); } if ( last==e ) { last=last->prevMultiItem(); last->setMultiItem( last->firstMultiItem(), last->prevMultiItem(), 0, 0 ); } KOAgendaItem *tmp = first; if ( first==last ) { delete mMultiItemInfo; tmp = 0; mMultiItemInfo = 0; } while ( tmp ) { next = tmp->nextMultiItem(); prev = tmp->prevMultiItem(); if ( e==next ) { next = next->nextMultiItem(); } if ( e==prev ) { prev = prev->prevMultiItem(); } tmp->setMultiItem((tmp==first)?0:first, (tmp==prev)?0:prev, (tmp==next)?0:next, (tmp==last)?0:last); tmp = tmp->nextMultiItem(); } } return e; } void KOAgendaItem::startMove() { KOAgendaItem* first = this; if ( isMultiItem() && mMultiItemInfo->mFirstMultiItem ) { first=mMultiItemInfo->mFirstMultiItem; } first->startMovePrivate(); } void KOAgendaItem::startMovePrivate() { mStartMoveInfo = new MultiItemInfo; mStartMoveInfo->mStartCellXLeft = mCellXLeft; mStartMoveInfo->mStartCellXRight = mCellXRight; mStartMoveInfo->mStartCellYTop = mCellYTop; mStartMoveInfo->mStartCellYBottom = mCellYBottom; if (mMultiItemInfo) { mStartMoveInfo->mFirstMultiItem = mMultiItemInfo->mFirstMultiItem; mStartMoveInfo->mLastMultiItem = mMultiItemInfo->mLastMultiItem; mStartMoveInfo->mPrevMultiItem = mMultiItemInfo->mPrevMultiItem; mStartMoveInfo->mNextMultiItem = mMultiItemInfo->mNextMultiItem; } else { mStartMoveInfo->mFirstMultiItem = 0; mStartMoveInfo->mLastMultiItem = 0; mStartMoveInfo->mPrevMultiItem = 0; mStartMoveInfo->mNextMultiItem = 0; } if ( isMultiItem() && mMultiItemInfo->mNextMultiItem ) { mMultiItemInfo->mNextMultiItem->startMovePrivate(); } } void KOAgendaItem::resetMove() { if ( mStartMoveInfo ) { if ( mStartMoveInfo->mFirstMultiItem ) { mStartMoveInfo->mFirstMultiItem->resetMovePrivate(); } else { resetMovePrivate(); } } } void KOAgendaItem::resetMovePrivate() { if (mStartMoveInfo) { mCellXLeft = mStartMoveInfo->mStartCellXLeft; mCellXRight = mStartMoveInfo->mStartCellXRight; mCellYTop = mStartMoveInfo->mStartCellYTop; mCellYBottom = mStartMoveInfo->mStartCellYBottom; // if we don't have mMultiItemInfo, the item didn't span two days before, // and wasn't moved over midnight, either, so we don't have to reset // anything. Otherwise, restore from mMoveItemInfo if ( mMultiItemInfo ) { // It was already a multi-day info mMultiItemInfo->mFirstMultiItem = mStartMoveInfo->mFirstMultiItem; mMultiItemInfo->mPrevMultiItem = mStartMoveInfo->mPrevMultiItem; mMultiItemInfo->mNextMultiItem = mStartMoveInfo->mNextMultiItem; mMultiItemInfo->mLastMultiItem = mStartMoveInfo->mLastMultiItem; if ( !mStartMoveInfo->mFirstMultiItem ) { // This was the first multi-item when the move started, delete all previous KOAgendaItem*toDel=mStartMoveInfo->mPrevMultiItem; KOAgendaItem*nowDel=0L; while (toDel) { nowDel=toDel; if (nowDel->moveInfo()) { toDel=nowDel->moveInfo()->mPrevMultiItem; } emit removeAgendaItem( nowDel ); } mMultiItemInfo->mFirstMultiItem = 0L; mMultiItemInfo->mPrevMultiItem = 0L; } if ( !mStartMoveInfo->mLastMultiItem ) { // This was the last multi-item when the move started, delete all next KOAgendaItem*toDel=mStartMoveInfo->mNextMultiItem; KOAgendaItem*nowDel=0L; while (toDel) { nowDel=toDel; if (nowDel->moveInfo()) { toDel=nowDel->moveInfo()->mNextMultiItem; } emit removeAgendaItem( nowDel ); } mMultiItemInfo->mLastMultiItem = 0L; mMultiItemInfo->mNextMultiItem = 0L; } if ( mStartMoveInfo->mFirstMultiItem==0 && mStartMoveInfo->mLastMultiItem==0 ) { // it was a single-day event before we started the move. delete mMultiItemInfo; mMultiItemInfo = 0; } } delete mStartMoveInfo; mStartMoveInfo = 0; } emit showAgendaItem( this ); if ( nextMultiItem() ) { nextMultiItem()->resetMovePrivate(); } } void KOAgendaItem::endMove() { KOAgendaItem*first=firstMultiItem(); if (!first) first=this; first->endMovePrivate(); } void KOAgendaItem::endMovePrivate() { if ( mStartMoveInfo ) { // if first, delete all previous if ( !firstMultiItem() || firstMultiItem()==this ) { KOAgendaItem*toDel=mStartMoveInfo->mPrevMultiItem; KOAgendaItem*nowDel = 0; while (toDel) { nowDel=toDel; if (nowDel->moveInfo()) { toDel=nowDel->moveInfo()->mPrevMultiItem; } emit removeAgendaItem( nowDel ); } } // if last, delete all next if ( !lastMultiItem() || lastMultiItem()==this ) { KOAgendaItem*toDel=mStartMoveInfo->mNextMultiItem; KOAgendaItem*nowDel = 0; while (toDel) { nowDel=toDel; if (nowDel->moveInfo()) { toDel=nowDel->moveInfo()->mNextMultiItem; } emit removeAgendaItem( nowDel ); } } // also delete the moving info delete mStartMoveInfo; mStartMoveInfo=0; if ( nextMultiItem() ) nextMultiItem()->endMovePrivate(); } } void KOAgendaItem::moveRelative(int dx, int dy) { int newXLeft = cellXLeft() + dx; int newXRight = cellXRight() + dx; int newYTop = cellYTop() + dy; int newYBottom = cellYBottom() + dy; setCellXY(newXLeft,newYTop,newYBottom); setCellXRight(newXRight); } void KOAgendaItem::expandTop(int dy) { int newYTop = cellYTop() + dy; int newYBottom = cellYBottom(); if (newYTop > newYBottom) newYTop = newYBottom; setCellY(newYTop, newYBottom); } void KOAgendaItem::expandBottom(int dy) { int newYTop = cellYTop(); int newYBottom = cellYBottom() + dy; if (newYBottom < newYTop) newYBottom = newYTop; setCellY(newYTop, newYBottom); } void KOAgendaItem::expandLeft(int dx) { int newXLeft = cellXLeft() + dx; int newXRight = cellXRight(); if ( newXLeft > newXRight ) newXLeft = newXRight; setCellX( newXLeft, newXRight ); } void KOAgendaItem::expandRight(int dx) { int newXLeft = cellXLeft(); int newXRight = cellXRight() + dx; if ( newXRight < newXLeft ) newXRight = newXLeft; setCellX( newXLeft, newXRight ); } TQToolTipGroup *KOAgendaItem::toolTipGroup() { if (!mToolTipGroup) mToolTipGroup = new TQToolTipGroup(0); return mToolTipGroup; } void KOAgendaItem::dragEnterEvent( TQDragEnterEvent *e ) { #ifndef KORG_NODND if ( ICalDrag::canDecode( e ) || VCalDrag::canDecode( e ) ) { e->ignore(); return; } if ( KVCardDrag::canDecode( e ) || TQTextDrag::canDecode( e ) ) e->accept(); else e->ignore(); #endif } void KOAgendaItem::addAttendee( const TQString &newAttendee ) { kdDebug(5850) << " Email: " << newAttendee << endl; TQString name, email; KPIM::getNameAndMail( newAttendee, name, email ); if ( !( name.isEmpty() && email.isEmpty() ) ) { mIncidence->addAttendee(new Attendee(name,email)); KMessageBox::information( this, i18n("Attendee \"%1\" added to the calendar item \"%2\"").arg(KPIM::normalizedAddress(name, email, TQString())).arg(text()), i18n("Attendee added"), "AttendeeDroppedAdded" ); } } void KOAgendaItem::dropEvent( TQDropEvent *e ) { // 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. #ifndef KORG_NODND TQString text; bool decoded = TQTextDrag::decode( e, text ); if( decoded && text.startsWith( "file:" ) ) { mIncidence->addAttachment( new Attachment( text ) ); return; } #ifndef KORG_NOKABC KABC::Addressee::List list; if ( KVCardDrag::decode( e, list ) ) { KABC::Addressee::List::Iterator it; for ( it = list.begin(); it != list.end(); ++it ) { TQString em( (*it).fullEmail() ); if ( em.isEmpty() ) { em = (*it).realName(); } addAttendee( em ); } } #else if( decoded ) { kdDebug(5850) << "Dropped : " << text << endl; TQStringList emails = TQStringList::split( ",", text ); for( TQStringList::ConstIterator it = emails.begin(); it != emails.end(); ++it ) { addAttendee( *it ); } } #endif // KORG_NOKABC #endif // KORG_NODND } TQPtrList KOAgendaItem::conflictItems() { return mConflictItems; } void KOAgendaItem::setConflictItems( TQPtrList ci ) { mConflictItems = ci; KOAgendaItem *item; for ( item = mConflictItems.first(); item != 0; item = mConflictItems.next() ) { item->addConflictItem( this ); } } void KOAgendaItem::addConflictItem( KOAgendaItem *ci ) { if ( mConflictItems.tqfind( ci ) < 0 ) mConflictItems.append( ci ); } TQString KOAgendaItem::label() const { return mLabelText; } bool KOAgendaItem::overlaps( KOrg::CellItem *o ) const { KOAgendaItem *other = static_cast( o ); if ( cellXLeft() <= other->cellXRight() && cellXRight() >= other->cellXLeft() ) { if ( ( cellYTop() <= other->cellYBottom() ) && ( cellYBottom() >= other->cellYTop() ) ) { return true; } } return false; } void KOAgendaItem::paintFrame( TQPainter *p, const TQColor &color ) { TQColor oldpen(p->pen().color()); p->setPen( color ); p->drawRect( 0, 0, width(), height() ); p->drawRect( 1, 1, width() - 2, height() - 2 ); p->setPen( oldpen ); } static void conditionalPaint( TQPainter *p, bool cond, int &x, int ft, const TQPixmap &pxmp ) { if ( !cond ) return; p->drawPixmap( x, ft, pxmp ); x += pxmp.width() + ft; } void KOAgendaItem::paintEventIcon( TQPainter *p, int &x, int ft ) { if ( !mIncidence ) return; if ( mIncidence->type() == "Event" ) { TQPixmap eventPxmp; if ( mIncidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) { mSpecialEvent = true; if ( mIncidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) { eventPxmp = KOGlobals::self()->smallIcon( "calendaranniversary" ); } else { eventPxmp = KOGlobals::self()->smallIcon( "calendarbirthday" ); } conditionalPaint( p, true, x, ft, eventPxmp ); } // per kolab/issue4349 we don't draw a regular appointment icon (to save space) } } void KOAgendaItem::paintTodoIcon( TQPainter *p, int &x, int ft ) { if ( !mIncidence ) return; static const TQPixmap todoPxmp = KOGlobals::self()->smallIcon( "todo" ); static const TQPixmap completedPxmp = KOGlobals::self()->smallIcon( "checkedbox" ); if ( mIncidence->type() != "Todo" ) return; bool b = ( static_cast( mIncidence ) )->isCompleted(); conditionalPaint( p, !b, x, ft, todoPxmp ); conditionalPaint( p, b, x, ft, completedPxmp ); } void KOAgendaItem::paintAlarmIcon( TQPainter *p, int &x, int ft ) { if (!mIconAlarm) return; int y = ft; // if we can't fit it all, bottom align it, more or less, so // it can be guessed better, visually if ( visibleRect().height() - ft < alarmPxmp->height() ) y -= ( alarmPxmp->height() - visibleRect().height() - ft ); p->drawPixmap( x, y, *alarmPxmp ); x += alarmPxmp->width() + ft; } void KOAgendaItem::paintIcons( TQPainter *p, int &x, int ft ) { paintEventIcon( p, x, ft ); paintTodoIcon( p, x, ft ); if ( !mSpecialEvent ) { paintAlarmIcon( p, x, ft ); } conditionalPaint( p, mIconRecur && !mSpecialEvent, x, ft, *recurPxmp ); conditionalPaint( p, mIconReadonly && !mSpecialEvent, x, ft, *readonlyPxmp ); conditionalPaint( p, mIconReply, x, ft, *replyPxmp ); conditionalPaint( p, mIconGroup, x, ft, *groupPxmp ); conditionalPaint( p, mIconGroupTentative, x, ft, *groupPxmpTentative ); conditionalPaint( p, mIconOrganizer, x, ft, *organizerPxmp ); } void KOAgendaItem::paintEvent( TQPaintEvent *ev ) { //HACK // to reproduce a crash: // 1. start Kontact with the Calendar as the initial module // 2. immediately select the summary (which must include appt and to-do) // causes a crash for me every time in this method unless we make // the following check if ( !mIncidence )return; TQRect visRect = visibleRect(); // when scrolling horizontally in the side-by-side view, the tqrepainted area is clipped // to the newly visible area, which is a problem since the content changes when visRect // changes, so tqrepaint the full item in that case if ( ev->rect() != visRect && visRect.isValid() && ev->rect().isValid() ) { tqrepaint( visRect ); return; } TQPainter p( this ); const int ft = 2; // frame thickness for tqlayout, see paintFrame() const int margin = 1 + ft; // frame + space between frame and content // General idea is to always show the icons (even in the all-day events). // This creates a consistent fealing for the user when the view mode // changes and therefore the available width changes. // Also look at #17984 if ( !alarmPxmp ) { alarmPxmp = new TQPixmap( KOGlobals::self()->smallIcon("bell") ); recurPxmp = new TQPixmap( KOGlobals::self()->smallIcon("recur") ); readonlyPxmp = new TQPixmap( KOGlobals::self()->smallIcon("readonlyevent") ); replyPxmp = new TQPixmap( KOGlobals::self()->smallIcon("mail_reply") ); groupPxmp = new TQPixmap( KOGlobals::self()->smallIcon("groupevent") ); groupPxmpTentative = new TQPixmap( KOGlobals::self()->smallIcon("groupeventtentative") ); organizerPxmp = new TQPixmap( KOGlobals::self()->smallIcon("organizer") ); } TQColor bgColor; if ( mIncidence->type() == "Todo" ) { if ( static_cast(mIncidence)->isOverdue() ) bgColor = KOPrefs::instance()->todoOverdueColor(); else if ( static_cast(mIncidence)->dtDue().date() == TQDateTime::tqcurrentDateTime().date() ) bgColor = KOPrefs::instance()->todoDueTodayColor(); } TQColor categoryColor; TQStringList categories = mIncidence->categories(); TQString cat = categories.first(); if (cat.isEmpty()) categoryColor = KOPrefs::instance()->unsetCategoryColor(); else categoryColor = *(KOPrefs::instance()->categoryColor(cat)); TQColor resourceColor = mResourceColor; if ( !resourceColor.isValid() ) resourceColor = categoryColor; TQColor frameColor; if ( KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceOnly || KOPrefs::instance()->agendaViewColors() == KOPrefs::CategoryInsideResourceOutside ) { frameColor = bgColor.isValid() ? bgColor : resourceColor; } else { frameColor = bgColor.isValid() ? bgColor : categoryColor; } if ( !bgColor.isValid() ) { if ( KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceOnly || KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceInsideCategoryOutside ) { bgColor = resourceColor; } else { bgColor = categoryColor; } } if ( cat.isEmpty() && KOPrefs::instance()->agendaViewColors() == KOPrefs::ResourceInsideCategoryOutside ) { frameColor = bgColor; } if ( cat.isEmpty() && KOPrefs::instance()->agendaViewColors() == KOPrefs::CategoryInsideResourceOutside ) { bgColor = frameColor; } if ( mSelected ) { frameColor = TQColor( 85 + frameColor.red() * 2/3, 85 + frameColor.green() * 2/3, 85 + frameColor.blue() * 2/3 ); } else { frameColor = frameColor.dark( 115 ); } TQColor textColor = getTextColor(bgColor); p.setPen( textColor ); p.setBackgroundColor( bgColor ); p.setFont(KOPrefs::instance()->mAgendaViewFont); TQFontMetrics fm = p.fontMetrics(); int singleLineHeight = fm.boundingRect( mLabelText ).height(); p.eraseRect( 0, 0, width(), height() ); paintFrame( &p, frameColor ); // calculate the height of the full version (case 4) to test whether it is // possible TQString shortH; TQString longH; if ( !isMultiItem() ) { shortH = KGlobal::locale()->formatTime(mIncidence->dtStart().time()); if (mIncidence->type() != "Todo") longH = i18n("%1 - %2").arg(shortH) .arg(KGlobal::locale()->formatTime(mIncidence->dtEnd().time())); else longH = shortH; } else if ( !mMultiItemInfo->mFirstMultiItem ) { shortH = KGlobal::locale()->formatTime(mIncidence->dtStart().time()); longH = shortH; } else { shortH = KGlobal::locale()->formatTime(mIncidence->dtEnd().time()); longH = i18n("- %1").arg(shortH); } KWordWrap *ww = KWordWrap::formatText( fm, TQRect(0, 0, width() - (2 * margin), -1), 0, mLabelText ); int th = ww->boundingRect().height(); delete ww; int hlHeight = TQMAX(fm.boundingRect(longH).height(), TQMAX(alarmPxmp->height(), TQMAX(recurPxmp->height(), TQMAX(readonlyPxmp->height(), TQMAX(replyPxmp->height(), TQMAX(groupPxmp->height(), organizerPxmp->height())))))); bool completelyRenderable = th < (height() - 2 * ft - 2 - hlHeight); // case 1: do not draw text when not even a single line fits // Don't do this any more, always try to print out the text. Even if // it's just a few pixel, one can still guess the whole text from just four pixels' height! if ( //( singleLineHeight > height()-4 ) || // ignore margin, be gentle.. Even ignore 2 pixel outside the item ( width() < 16 ) ) { int x = margin; paintTodoIcon( &p, x, ft ); return; } // case 2: draw a single line when no more space if ( (2 * singleLineHeight) > (height() - 2 * margin) ) { int x = margin, txtWidth; if ( mIncidence->doesFloat() ) { x += visRect.left(); paintIcons( &p, x, ft ); txtWidth = visRect.right() - margin - x; } else { paintIcons( &p, x, ft ); txtWidth = width() - margin - x; } int y = ((height() - 2 * ft - singleLineHeight) / 2) + fm.ascent(); KWordWrap::drawFadeoutText( &p, x, y, txtWidth, mLabelText ); return; } // case 3: enough for 2-5 lines, but not for the header. // Also used for the middle days in multi-events if ( ((!completelyRenderable) && ((height() - (2 * margin)) <= (5 * singleLineHeight)) ) || (isMultiItem() && mMultiItemInfo->mNextMultiItem && mMultiItemInfo->mFirstMultiItem) ) { int x = margin, txtWidth; if ( mIncidence->doesFloat() ) { x += visRect.left(); paintIcons( &p, x, ft ); txtWidth = visRect.right() - margin - x; } else { paintIcons( &p, x, ft ); txtWidth = width() - margin - x; } ww = KWordWrap::formatText( fm, TQRect( 0, 0, txtWidth, (height() - (2 * margin)) ), 0, mLabelText ); //kdDebug() << "SIZES for " << mLabelText << ": " << width() << " :: " << txtWidth << endl; ww->drawText( &p, x, margin, TQt::AlignHCenter | KWordWrap::FadeOut ); delete ww; return; } // case 4: paint everything, with header: // consists of (vertically) ft + headline&icons + ft + text + margin int y = 2 * ft + hlHeight; if ( completelyRenderable ) y += (height() - (2 * ft) - margin - hlHeight - th) / 2; int x = margin, txtWidth, hTxtWidth, eventX; if ( mIncidence->doesFloat() ) { shortH = longH = ""; if ( (mIncidence->type() != "Todo") && (mIncidence->dtStart() != mIncidence->dtEnd()) ) { // multi days shortH = longH = i18n("%1 - %2") .arg(KGlobal::locale()->formatDate(mIncidence->dtStart().date())) .arg(KGlobal::locale()->formatDate(mIncidence->dtEnd().date())); // paint headline p.fillRect( 0, 0, width(), (ft/2) + margin + hlHeight, TQBrush( frameColor ) ); } x += visRect.left(); eventX = x; txtWidth = visRect.right() - margin - x; paintIcons( &p, x, ft ); hTxtWidth = visRect.right() - margin - x; } else { // paint headline p.fillRect( 0, 0, width(), (ft/2) + margin + hlHeight, TQBrush( frameColor ) ); txtWidth = width() - margin - x; eventX = x; paintIcons( &p, x, ft ); hTxtWidth = width() - margin - x; } TQString headline; int hw = fm.boundingRect( longH ).width(); if ( hw > hTxtWidth ) { headline = shortH; hw = fm.boundingRect( shortH ).width(); if ( hw < txtWidth ) x += (hTxtWidth - hw) / 2; } else { headline = longH; x += (hTxtWidth - hw) / 2; } p.setBackgroundColor( frameColor ); p.setPen( getTextColor( frameColor ) ); KWordWrap::drawFadeoutText( &p, x, ft + fm.ascent(), hTxtWidth, headline ); // draw event text ww = KWordWrap::formatText( fm, TQRect( 0, 0, txtWidth, height() - margin - y ), 0, mLabelText ); p.setBackgroundColor( bgColor ); p.setPen( textColor ); TQString ws = ww->wrappedString(); if ( ws.left( ws.length()-1 ).tqfind( '\n' ) >= 0 ) ww->drawText( &p, eventX, y, TQt::AlignAuto | KWordWrap::FadeOut ); else ww->drawText( &p, eventX + (txtWidth-ww->boundingRect().width()-2*margin)/2, y, TQt::AlignHCenter | KWordWrap::FadeOut ); delete ww; }