You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
998 lines
30 KiB
998 lines
30 KiB
/*
|
|
This file is part of KOrganizer.
|
|
|
|
Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org>
|
|
Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
|
|
|
|
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 Qt, and distribute the resulting executable,
|
|
without including the source code for Qt in the source distribution.
|
|
*/
|
|
|
|
#include <tqtooltip.h>
|
|
#include <tqdragobject.h>
|
|
#include <tqpainter.h>
|
|
|
|
#include <kiconloader.h>
|
|
#include <kdebug.h>
|
|
#include <klocale.h>
|
|
#include <kwordwrap.h>
|
|
#include <kmessagebox.h>
|
|
|
|
#include <libkcal/icaldrag.h>
|
|
#include <libkcal/vcaldrag.h>
|
|
#include <libkdepim/kvcarddrag.h>
|
|
#include <libemailfunctions/email.h>
|
|
#ifndef KORG_NOKABC
|
|
#include <kabc/addressee.h>
|
|
#include <kabc/vcardconverter.h>
|
|
#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 *parent,
|
|
int itemPos, int itemCount,
|
|
const char *name, WFlags f ) :
|
|
TQWidget( parent, 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( Qt::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> KOAgendaItem::conflictItems()
|
|
{
|
|
return mConflictItems;
|
|
}
|
|
|
|
void KOAgendaItem::setConflictItems( TQPtrList<KOAgendaItem> ci )
|
|
{
|
|
mConflictItems = ci;
|
|
KOAgendaItem *item;
|
|
for ( item = mConflictItems.first(); item != 0;
|
|
item = mConflictItems.next() ) {
|
|
item->addConflictItem( this );
|
|
}
|
|
}
|
|
|
|
void KOAgendaItem::addConflictItem( KOAgendaItem *ci )
|
|
{
|
|
if ( mConflictItems.find( ci ) < 0 ) mConflictItems.append( ci );
|
|
}
|
|
|
|
TQString KOAgendaItem::label() const
|
|
{
|
|
return mLabelText;
|
|
}
|
|
|
|
bool KOAgendaItem::overlaps( KOrg::CellItem *o ) const
|
|
{
|
|
KOAgendaItem *other = static_cast<KOAgendaItem *>( 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<Todo *>( 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 repainted area is clipped
|
|
// to the newly visible area, which is a problem since the content changes when visRect
|
|
// changes, so repaint the full item in that case
|
|
if ( ev->rect() != visRect && visRect.isValid() && ev->rect().isValid() ) {
|
|
repaint( visRect );
|
|
return;
|
|
}
|
|
|
|
TQPainter p( this );
|
|
const int ft = 2; // frame thickness for layout, 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<Todo*>(mIncidence)->isOverdue() )
|
|
bgColor = KOPrefs::instance()->todoOverdueColor();
|
|
else if ( static_cast<Todo*>(mIncidence)->dtDue().date() ==
|
|
TQDateTime::currentDateTime().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 = QMAX(fm.boundingRect(longH).height(),
|
|
QMAX(alarmPxmp->height(), QMAX(recurPxmp->height(),
|
|
QMAX(readonlyPxmp->height(), QMAX(replyPxmp->height(),
|
|
QMAX(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, Qt::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 ).find( '\n' ) >= 0 )
|
|
ww->drawText( &p, eventX, y,
|
|
Qt::AlignAuto | KWordWrap::FadeOut );
|
|
else
|
|
ww->drawText( &p, eventX + (txtWidth-ww->boundingRect().width()-2*margin)/2,
|
|
y, Qt::AlignHCenter | KWordWrap::FadeOut );
|
|
delete ww;
|
|
}
|
|
|