~ubuntu-branches/ubuntu/oneiric/kdepim/oneiric-updates

« back to all changes in this revision

Viewing changes to calendarviews/eventviews/agenda/agendaitem.cpp

  • Committer: Package Import Robot
  • Author(s): Philip Muškovac
  • Date: 2011-06-28 19:33:24 UTC
  • mfrom: (0.2.13) (0.1.13 sid)
  • Revision ID: package-import@ubuntu.com-20110628193324-8yvjs8sdv9rdoo6c
Tags: 4:4.7.0-0ubuntu1
* New upstream release
  - update install files
  - add missing kdepim-doc package to control file
  - Fix Vcs lines
  - kontact breaks/replaces korganizer << 4:4.6.80
  - tighten the dependency of kdepim-dev on libkdepim4 to fix lintian error

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (c) 2000,2001,2003 Cornelius Schumacher <schumacher@kde.org>
 
3
  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
 
4
 
 
5
  This program is free software; you can redistribute it and/or modify
 
6
  it under the terms of the GNU General Public License as published by
 
7
  the Free Software Foundation; either version 2 of the License, or
 
8
  (at your option) any later version.
 
9
 
 
10
  This program is distributed in the hope that it will be useful,
 
11
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
13
  GNU General Public License for more details.
 
14
 
 
15
  You should have received a copy of the GNU General Public License along
 
16
  with this program; if not, write to the Free Software Foundation, Inc.,
 
17
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
18
 
 
19
  As a special exception, permission is given to link this program
 
20
  with any edition of Qt, and distribute the resulting executable,
 
21
  without including the source code for Qt in the source distribution.
 
22
*/
 
23
#include "agendaitem.h"
 
24
#include "eventview.h"
 
25
#include "helper.h"
 
26
#include "prefs.h"
 
27
#include "prefs_base.h" // for enums
 
28
 
 
29
#include <calendarsupport/kcalprefs.h>
 
30
#include <calendarsupport/utils.h>
 
31
 
 
32
#include <KABC/VCardDrag>
 
33
 
 
34
#include <KCalUtils/ICalDrag>
 
35
#include <KCalUtils/VCalDrag>
 
36
#include <KCalUtils/IncidenceFormatter>
 
37
 
 
38
#include <KPIMUtils/Email>
 
39
 
 
40
#include <KLocale>
 
41
#include <KMessageBox>
 
42
#include <KWordWrap>
 
43
 
 
44
#include <QDragEnterEvent>
 
45
#include <QPainter>
 
46
#include <QPixmapCache>
 
47
#include <QToolTip>
 
48
 
 
49
using namespace KCalCore;
 
50
using namespace EventViews;
 
51
 
 
52
//-----------------------------------------------------------------------------
 
53
 
 
54
QPixmap *AgendaItem::alarmPxmp = 0;
 
55
QPixmap *AgendaItem::recurPxmp = 0;
 
56
QPixmap *AgendaItem::readonlyPxmp = 0;
 
57
QPixmap *AgendaItem::replyPxmp = 0;
 
58
QPixmap *AgendaItem::groupPxmp = 0;
 
59
QPixmap *AgendaItem::groupPxmpTent = 0;
 
60
QPixmap *AgendaItem::organizerPxmp = 0;
 
61
QPixmap *AgendaItem::eventPxmp = 0;
 
62
 
 
63
//-----------------------------------------------------------------------------
 
64
 
 
65
AgendaItem::AgendaItem( EventView *eventView, CalendarSupport::Calendar *calendar,
 
66
                        const Akonadi::Item &item,
 
67
                        int itemPos, int itemCount,
 
68
                        const QDate &qd, bool isSelected, QWidget *parent )
 
69
  : QWidget( parent ), mEventView( eventView ), mCalendar( calendar ), mIncidence( item ),
 
70
    mDate( qd ), mValid( true ), mCloned( false ), mSelected( isSelected ), mSpecialEvent( false )
 
71
{
 
72
  if ( !CalendarSupport::hasIncidence( mIncidence ) ) {
 
73
    mValid = false;
 
74
    return;
 
75
  }
 
76
 
 
77
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
 
78
  Q_ASSERT( incidence );
 
79
  if ( incidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ||
 
80
       incidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
 
81
    const int years = EventViews::yearDiff( incidence->dtStart().date(), qd );
 
82
    if ( years > 0 ) {
 
83
      incidence = KCalCore::Incidence::Ptr( incidence->clone() );
 
84
      incidence->setReadOnly( false );
 
85
      incidence->setSummary( i18np( "%2 (1 year)", "%2 (%1 years)", years, incidence->summary() ) );
 
86
      incidence->setReadOnly( true );
 
87
      mCloned = true;
 
88
      mIncidence.setPayload<KCalCore::Incidence::Ptr>( incidence );
 
89
    }
 
90
  }
 
91
 
 
92
  mLabelText = incidence->summary();
 
93
  mIconAlarm = false;
 
94
  mIconRecur = false;
 
95
  mIconReadonly = false;
 
96
  mIconReply = false;
 
97
  mIconGroup = false;
 
98
  mIconGroupTent = false;
 
99
  mIconOrganizer = false;
 
100
  mMultiItemInfo = 0;
 
101
  mStartMoveInfo = 0;
 
102
 
 
103
  mItemPos = itemPos;
 
104
  mItemCount = itemCount;
 
105
 
 
106
  QPalette pal = palette();
 
107
  pal.setColor( QPalette::Window, Qt::transparent );
 
108
  setPalette( pal );
 
109
 
 
110
  setCellXY( 0, 0, 1 );
 
111
  setCellXRight( 0 );
 
112
  setMouseTracking( true );
 
113
  mResourceColor = QColor();
 
114
  updateIcons();
 
115
 
 
116
  setAcceptDrops( true );
 
117
}
 
118
 
 
119
AgendaItem::~AgendaItem()
 
120
{
 
121
}
 
122
 
 
123
void AgendaItem::updateIcons()
 
124
{
 
125
  if ( !mValid ) {
 
126
    return;
 
127
  }
 
128
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( mIncidence );
 
129
  Q_ASSERT( incidence );
 
130
  mIconReadonly = incidence->isReadOnly();
 
131
  mIconRecur = incidence->recurs();
 
132
  mIconAlarm = incidence->hasEnabledAlarms();
 
133
  if ( incidence->attendeeCount() > 1 ) {
 
134
    if ( mEventView->kcalPreferences()->thatIsMe( incidence->organizer()->email() ) ) {
 
135
      mIconReply = false;
 
136
      mIconGroup = false;
 
137
      mIconGroupTent = false;
 
138
      mIconOrganizer = true;
 
139
    } else {
 
140
      KCalCore::Attendee::Ptr me = incidence->attendeeByMails( mEventView->kcalPreferences()->allEmails() );
 
141
      if ( me ) {
 
142
        if ( me->status() == KCalCore::Attendee::NeedsAction && me->RSVP() ) {
 
143
          mIconReply = true;
 
144
          mIconGroup = false;
 
145
          mIconGroupTent = false;
 
146
          mIconOrganizer = false;
 
147
        } else if ( me->status() == KCalCore::Attendee::Tentative ) {
 
148
          mIconReply = false;
 
149
          mIconGroup = false;
 
150
          mIconGroupTent = true;
 
151
          mIconOrganizer = false;
 
152
        } else {
 
153
          mIconReply = false;
 
154
          mIconGroup = true;
 
155
          mIconGroupTent = false;
 
156
          mIconOrganizer = false;
 
157
        }
 
158
      } else {
 
159
        mIconReply = false;
 
160
        mIconGroup = true;
 
161
        mIconGroupTent = false;
 
162
        mIconOrganizer = false;
 
163
      }
 
164
    }
 
165
  }
 
166
  update();
 
167
}
 
168
 
 
169
void AgendaItem::select( bool selected )
 
170
{
 
171
  if ( mSelected != selected ) {
 
172
    mSelected = selected;
 
173
    update();
 
174
  }
 
175
}
 
176
 
 
177
bool AgendaItem::dissociateFromMultiItem()
 
178
{
 
179
  if ( !isMultiItem() ) {
 
180
    return false;
 
181
  }
 
182
 
 
183
  AgendaItem::QPtr firstItem = firstMultiItem();
 
184
  if ( firstItem == this ) {
 
185
    firstItem = nextMultiItem();
 
186
  }
 
187
 
 
188
  AgendaItem::QPtr lastItem = lastMultiItem();
 
189
  if ( lastItem == this ) {
 
190
    lastItem = prevMultiItem();
 
191
  }
 
192
 
 
193
  AgendaItem::QPtr prevItem = prevMultiItem();
 
194
  AgendaItem::QPtr nextItem = nextMultiItem();
 
195
 
 
196
  if ( prevItem ) {
 
197
    prevItem->setMultiItem( firstItem, prevItem->prevMultiItem(), nextItem, lastItem );
 
198
  }
 
199
  if ( nextItem ) {
 
200
    nextItem->setMultiItem( firstItem, prevItem, nextItem->prevMultiItem(), lastItem );
 
201
  }
 
202
  delete mMultiItemInfo;
 
203
  mMultiItemInfo = 0;
 
204
  return true;
 
205
}
 
206
 
 
207
void AgendaItem::setIncidence( const Akonadi::Item &incidence )
 
208
{
 
209
  mValid = false;
 
210
  if ( CalendarSupport::hasIncidence( incidence ) ) {
 
211
    mValid = true;
 
212
    mIncidence = incidence;
 
213
    mLabelText = CalendarSupport::incidence( incidence )->summary();
 
214
    updateIcons();
 
215
  }
 
216
}
 
217
 
 
218
/*
 
219
  Return height of item in units of agenda cells
 
220
*/
 
221
int AgendaItem::cellHeight() const
 
222
{
 
223
  return mCellYBottom - mCellYTop + 1;
 
224
}
 
225
 
 
226
/*
 
227
  Return height of item in units of agenda cells
 
228
*/
 
229
int AgendaItem::cellWidth() const
 
230
{
 
231
  return mCellXRight - mCellXLeft + 1;
 
232
}
 
233
 
 
234
void AgendaItem::setItemDate( const QDate &qd )
 
235
{
 
236
  mDate = qd;
 
237
}
 
238
 
 
239
void AgendaItem::setCellXY( int X, int YTop, int YBottom )
 
240
{
 
241
  mCellXLeft = X;
 
242
  mCellYTop = YTop;
 
243
  mCellYBottom = YBottom;
 
244
}
 
245
 
 
246
void AgendaItem::setCellXRight( int XRight )
 
247
{
 
248
  mCellXRight = XRight;
 
249
}
 
250
 
 
251
void AgendaItem::setCellX( int XLeft, int XRight )
 
252
{
 
253
  mCellXLeft = XLeft;
 
254
  mCellXRight = XRight;
 
255
}
 
256
 
 
257
void AgendaItem::setCellY( int YTop, int YBottom )
 
258
{
 
259
  mCellYTop = YTop;
 
260
  mCellYBottom = YBottom;
 
261
}
 
262
 
 
263
void AgendaItem::setMultiItem( AgendaItem::QPtr first, AgendaItem::QPtr prev,
 
264
                               AgendaItem::QPtr next, AgendaItem::QPtr last )
 
265
{
 
266
  if ( !mMultiItemInfo ) {
 
267
    mMultiItemInfo = new MultiItemInfo;
 
268
  }
 
269
  mMultiItemInfo->mFirstMultiItem = first;
 
270
  mMultiItemInfo->mPrevMultiItem = prev;
 
271
  mMultiItemInfo->mNextMultiItem = next;
 
272
  mMultiItemInfo->mLastMultiItem = last;
 
273
}
 
274
 
 
275
bool AgendaItem::isMultiItem() const
 
276
{
 
277
  return mMultiItemInfo;
 
278
}
 
279
 
 
280
AgendaItem::QPtr AgendaItem::prependMoveItem( AgendaItem::QPtr e )
 
281
{
 
282
  if ( !e ) {
 
283
    return 0;
 
284
  }
 
285
 
 
286
  AgendaItem::QPtr first = 0, last = 0;
 
287
  if ( isMultiItem() ) {
 
288
    first = mMultiItemInfo->mFirstMultiItem;
 
289
    last = mMultiItemInfo->mLastMultiItem;
 
290
  }
 
291
  if ( !first ) {
 
292
    first = this;
 
293
  }
 
294
  if ( !last ) {
 
295
    last = this;
 
296
  }
 
297
 
 
298
  e->setMultiItem( 0, 0, first, last );
 
299
  first->setMultiItem( e, e, first->nextMultiItem(), first->lastMultiItem() );
 
300
 
 
301
  AgendaItem::QPtr tmp = first->nextMultiItem();
 
302
  while ( tmp ) {
 
303
    tmp->setMultiItem( e, tmp->prevMultiItem(), tmp->nextMultiItem(), tmp->lastMultiItem() );
 
304
    tmp = tmp->nextMultiItem();
 
305
  }
 
306
 
 
307
  if ( mStartMoveInfo && !e->moveInfo() ) {
 
308
    e->mStartMoveInfo=new MultiItemInfo( *mStartMoveInfo );
 
309
//    e->moveInfo()->mFirstMultiItem = moveInfo()->mFirstMultiItem;
 
310
//    e->moveInfo()->mLastMultiItem = moveInfo()->mLastMultiItem;
 
311
    e->moveInfo()->mPrevMultiItem = 0;
 
312
    e->moveInfo()->mNextMultiItem = first;
 
313
  }
 
314
 
 
315
  if ( first && first->moveInfo() ) {
 
316
    first->moveInfo()->mPrevMultiItem = e;
 
317
  }
 
318
  return e;
 
319
}
 
320
 
 
321
AgendaItem::QPtr AgendaItem::appendMoveItem( AgendaItem::QPtr e )
 
322
{
 
323
  if ( !e ) {
 
324
    return 0;
 
325
  }
 
326
 
 
327
  AgendaItem::QPtr first = 0, last = 0;
 
328
  if ( isMultiItem() ) {
 
329
    first = mMultiItemInfo->mFirstMultiItem;
 
330
    last = mMultiItemInfo->mLastMultiItem;
 
331
  }
 
332
  if ( !first ) {
 
333
    first = this;
 
334
  }
 
335
  if ( !last ) {
 
336
    last = this;
 
337
  }
 
338
 
 
339
  e->setMultiItem( first, last, 0, 0 );
 
340
  AgendaItem::QPtr tmp = first;
 
341
 
 
342
  while ( tmp ) {
 
343
    tmp->setMultiItem( tmp->firstMultiItem(), tmp->prevMultiItem(), tmp->nextMultiItem(), e );
 
344
    tmp = tmp->nextMultiItem();
 
345
  }
 
346
  last->setMultiItem( last->firstMultiItem(), last->prevMultiItem(), e, e );
 
347
 
 
348
  if ( mStartMoveInfo && !e->moveInfo() ) {
 
349
    e->mStartMoveInfo=new MultiItemInfo( *mStartMoveInfo );
 
350
//    e->moveInfo()->mFirstMultiItem = moveInfo()->mFirstMultiItem;
 
351
//    e->moveInfo()->mLastMultiItem = moveInfo()->mLastMultiItem;
 
352
    e->moveInfo()->mPrevMultiItem = last;
 
353
    e->moveInfo()->mNextMultiItem = 0;
 
354
  }
 
355
  if ( last && last->moveInfo() ) {
 
356
    last->moveInfo()->mNextMultiItem = e;
 
357
  }
 
358
  return e;
 
359
}
 
360
 
 
361
AgendaItem::QPtr AgendaItem::removeMoveItem( AgendaItem::QPtr e )
 
362
{
 
363
  if ( isMultiItem() ) {
 
364
    AgendaItem::QPtr first = mMultiItemInfo->mFirstMultiItem;
 
365
    AgendaItem::QPtr next, prev;
 
366
    AgendaItem::QPtr last = mMultiItemInfo->mLastMultiItem;
 
367
    if ( !first ) {
 
368
      first = this;
 
369
    }
 
370
    if ( !last ) {
 
371
      last = this;
 
372
    }
 
373
    if ( first == e ) {
 
374
      first = first->nextMultiItem();
 
375
      first->setMultiItem( 0, 0, first->nextMultiItem(), first->lastMultiItem() );
 
376
    }
 
377
    if ( last == e ) {
 
378
      last = last->prevMultiItem();
 
379
      last->setMultiItem( last->firstMultiItem(), last->prevMultiItem(), 0, 0 );
 
380
    }
 
381
 
 
382
    AgendaItem::QPtr tmp =  first;
 
383
    if ( first == last ) {
 
384
      delete mMultiItemInfo;
 
385
      tmp = 0;
 
386
      mMultiItemInfo = 0;
 
387
    }
 
388
    while ( tmp ) {
 
389
      next = tmp->nextMultiItem();
 
390
      prev = tmp->prevMultiItem();
 
391
      if ( e == next ) {
 
392
        next = next->nextMultiItem();
 
393
      }
 
394
      if ( e == prev ) {
 
395
        prev = prev->prevMultiItem();
 
396
      }
 
397
      tmp->setMultiItem( ( tmp == first ) ? 0 : first,
 
398
                         ( tmp == prev ) ? 0 : prev,
 
399
                         ( tmp == next ) ? 0 : next,
 
400
                         ( tmp == last ) ? 0 : last );
 
401
      tmp = tmp->nextMultiItem();
 
402
    }
 
403
  }
 
404
 
 
405
  return e;
 
406
}
 
407
 
 
408
void AgendaItem::startMove()
 
409
{
 
410
  AgendaItem::QPtr first = this;
 
411
  if ( isMultiItem() && mMultiItemInfo->mFirstMultiItem ) {
 
412
    first=mMultiItemInfo->mFirstMultiItem;
 
413
  }
 
414
  first->startMovePrivate();
 
415
}
 
416
 
 
417
void AgendaItem::startMovePrivate()
 
418
{
 
419
  mStartMoveInfo = new MultiItemInfo;
 
420
  mStartMoveInfo->mStartCellXLeft = mCellXLeft;
 
421
  mStartMoveInfo->mStartCellXRight = mCellXRight;
 
422
  mStartMoveInfo->mStartCellYTop = mCellYTop;
 
423
  mStartMoveInfo->mStartCellYBottom = mCellYBottom;
 
424
  if ( mMultiItemInfo ) {
 
425
    mStartMoveInfo->mFirstMultiItem = mMultiItemInfo->mFirstMultiItem;
 
426
    mStartMoveInfo->mLastMultiItem = mMultiItemInfo->mLastMultiItem;
 
427
    mStartMoveInfo->mPrevMultiItem = mMultiItemInfo->mPrevMultiItem;
 
428
    mStartMoveInfo->mNextMultiItem = mMultiItemInfo->mNextMultiItem;
 
429
  } else {
 
430
    mStartMoveInfo->mFirstMultiItem = 0;
 
431
    mStartMoveInfo->mLastMultiItem = 0;
 
432
    mStartMoveInfo->mPrevMultiItem = 0;
 
433
    mStartMoveInfo->mNextMultiItem = 0;
 
434
  }
 
435
  if ( isMultiItem() && mMultiItemInfo->mNextMultiItem ) {
 
436
    mMultiItemInfo->mNextMultiItem->startMovePrivate();
 
437
  }
 
438
}
 
439
 
 
440
void AgendaItem::resetMove()
 
441
{
 
442
  if ( mStartMoveInfo ) {
 
443
    if ( mStartMoveInfo->mFirstMultiItem ) {
 
444
      mStartMoveInfo->mFirstMultiItem->resetMovePrivate();
 
445
    } else {
 
446
      resetMovePrivate();
 
447
    }
 
448
  }
 
449
}
 
450
 
 
451
void AgendaItem::resetMovePrivate()
 
452
{
 
453
  if ( mStartMoveInfo ) {
 
454
    mCellXLeft = mStartMoveInfo->mStartCellXLeft;
 
455
    mCellXRight = mStartMoveInfo->mStartCellXRight;
 
456
    mCellYTop = mStartMoveInfo->mStartCellYTop;
 
457
    mCellYBottom = mStartMoveInfo->mStartCellYBottom;
 
458
 
 
459
    // if we don't have mMultiItemInfo, the item didn't span two days before,
 
460
    // and wasn't moved over midnight, either, so we don't have to reset
 
461
    // anything. Otherwise, restore from mMoveItemInfo
 
462
    if ( mMultiItemInfo ) {
 
463
      // It was already a multi-day info
 
464
      mMultiItemInfo->mFirstMultiItem = mStartMoveInfo->mFirstMultiItem;
 
465
      mMultiItemInfo->mPrevMultiItem = mStartMoveInfo->mPrevMultiItem;
 
466
      mMultiItemInfo->mNextMultiItem = mStartMoveInfo->mNextMultiItem;
 
467
      mMultiItemInfo->mLastMultiItem = mStartMoveInfo->mLastMultiItem;
 
468
 
 
469
      if ( !mStartMoveInfo->mFirstMultiItem ) {
 
470
        // This was the first multi-item when the move started, delete all previous
 
471
        AgendaItem::QPtr toDel = mStartMoveInfo->mPrevMultiItem;
 
472
        AgendaItem::QPtr nowDel = 0;
 
473
        while ( toDel ) {
 
474
          nowDel = toDel;
 
475
          if ( nowDel->moveInfo() ) {
 
476
            toDel = nowDel->moveInfo()->mPrevMultiItem;
 
477
          }
 
478
          emit removeAgendaItem( nowDel );
 
479
        }
 
480
        mMultiItemInfo->mFirstMultiItem = 0;
 
481
        mMultiItemInfo->mPrevMultiItem = 0;
 
482
      }
 
483
      if ( !mStartMoveInfo->mLastMultiItem ) {
 
484
        // This was the last multi-item when the move started, delete all next
 
485
        AgendaItem::QPtr toDel = mStartMoveInfo->mNextMultiItem;
 
486
        AgendaItem::QPtr nowDel = 0;
 
487
        while ( toDel ) {
 
488
          nowDel = toDel;
 
489
          if ( nowDel->moveInfo() ) {
 
490
            toDel=nowDel->moveInfo()->mNextMultiItem;
 
491
          }
 
492
          emit removeAgendaItem( nowDel );
 
493
        }
 
494
        mMultiItemInfo->mLastMultiItem = 0;
 
495
        mMultiItemInfo->mNextMultiItem = 0;
 
496
      }
 
497
 
 
498
      if ( mStartMoveInfo->mFirstMultiItem == 0 && mStartMoveInfo->mLastMultiItem == 0 ) {
 
499
        // it was a single-day event before we started the move.
 
500
        delete mMultiItemInfo;
 
501
        mMultiItemInfo = 0;
 
502
      }
 
503
    }
 
504
    delete mStartMoveInfo;
 
505
    mStartMoveInfo = 0;
 
506
  }
 
507
  emit showAgendaItem( this );
 
508
  if ( nextMultiItem() ) {
 
509
    nextMultiItem()->resetMovePrivate();
 
510
  }
 
511
}
 
512
 
 
513
void AgendaItem::endMove()
 
514
{
 
515
  AgendaItem::QPtr first = firstMultiItem();
 
516
  if ( !first ) {
 
517
    first = this;
 
518
  }
 
519
  first->endMovePrivate();
 
520
}
 
521
 
 
522
void AgendaItem::endMovePrivate()
 
523
{
 
524
  if ( mStartMoveInfo ) {
 
525
    // if first, delete all previous
 
526
    if ( !firstMultiItem() || firstMultiItem() == this ) {
 
527
      AgendaItem::QPtr toDel = mStartMoveInfo->mPrevMultiItem;
 
528
      AgendaItem::QPtr nowDel = 0;
 
529
      while ( toDel ) {
 
530
        nowDel = toDel;
 
531
        if ( nowDel->moveInfo() ) {
 
532
          toDel=nowDel->moveInfo()->mPrevMultiItem;
 
533
        }
 
534
        emit removeAgendaItem( nowDel );
 
535
      }
 
536
    }
 
537
    // if last, delete all next
 
538
    if ( !lastMultiItem() || lastMultiItem() == this ) {
 
539
      AgendaItem::QPtr toDel=mStartMoveInfo->mNextMultiItem;
 
540
      AgendaItem::QPtr nowDel = 0;
 
541
      while ( toDel ) {
 
542
        nowDel = toDel;
 
543
        if ( nowDel->moveInfo() ) {
 
544
          toDel=nowDel->moveInfo()->mNextMultiItem;
 
545
        }
 
546
        emit removeAgendaItem( nowDel );
 
547
      }
 
548
    }
 
549
    // also delete the moving info
 
550
    delete mStartMoveInfo;
 
551
    mStartMoveInfo = 0;
 
552
    if ( nextMultiItem() ) {
 
553
      nextMultiItem()->endMovePrivate();
 
554
    }
 
555
  }
 
556
}
 
557
 
 
558
void AgendaItem::moveRelative( int dx, int dy )
 
559
{
 
560
  int newXLeft = cellXLeft() + dx;
 
561
  int newXRight = cellXRight() + dx;
 
562
  int newYTop = cellYTop() + dy;
 
563
  int newYBottom = cellYBottom() + dy;
 
564
  setCellXY( newXLeft, newYTop, newYBottom );
 
565
  setCellXRight( newXRight );
 
566
}
 
567
 
 
568
void AgendaItem::expandTop( int dy, const bool allowOverLimit )
 
569
{
 
570
  int newYTop = cellYTop() + dy;
 
571
  int newYBottom = cellYBottom();
 
572
  if ( newYTop > newYBottom && !allowOverLimit ) {
 
573
    newYTop = newYBottom;
 
574
  }
 
575
  setCellY( newYTop, newYBottom );
 
576
}
 
577
 
 
578
void AgendaItem::expandBottom( int dy )
 
579
{
 
580
  int newYTop = cellYTop();
 
581
  int newYBottom = cellYBottom() + dy;
 
582
  if ( newYBottom < newYTop ) {
 
583
    newYBottom = newYTop;
 
584
  }
 
585
  setCellY( newYTop, newYBottom );
 
586
}
 
587
 
 
588
void AgendaItem::expandLeft( int dx )
 
589
{
 
590
  int newXLeft = cellXLeft() + dx;
 
591
  int newXRight = cellXRight();
 
592
  if ( newXLeft > newXRight ) {
 
593
    newXLeft = newXRight;
 
594
  }
 
595
  setCellX( newXLeft, newXRight );
 
596
}
 
597
 
 
598
void AgendaItem::expandRight( int dx )
 
599
{
 
600
  int newXLeft = cellXLeft();
 
601
  int newXRight = cellXRight() + dx;
 
602
  if ( newXRight < newXLeft ) {
 
603
    newXRight = newXLeft;
 
604
  }
 
605
  setCellX( newXLeft, newXRight );
 
606
}
 
607
 
 
608
void AgendaItem::dragEnterEvent( QDragEnterEvent *e )
 
609
{
 
610
#ifndef KORG_NODND
 
611
  const QMimeData *md = e->mimeData();
 
612
  if ( KCalUtils::ICalDrag::canDecode( md ) || KCalUtils::VCalDrag::canDecode( md ) ) {
 
613
    // TODO: Allow dragging events/todos onto other events to create a relation
 
614
    e->ignore();
 
615
    return;
 
616
  }
 
617
  if ( KABC::VCardDrag::canDecode( md ) || md->hasText() ) {
 
618
    e->accept();
 
619
  } else {
 
620
    e->ignore();
 
621
  }
 
622
#else
 
623
  Q_UNUSED( e );
 
624
#endif
 
625
}
 
626
 
 
627
void AgendaItem::addAttendee( const QString &newAttendee )
 
628
{
 
629
  if ( !mValid ) {
 
630
    return;
 
631
  }
 
632
 
 
633
  const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( mIncidence );
 
634
  QString name, email;
 
635
  KPIMUtils::extractEmailAddressAndName( newAttendee, email, name );
 
636
  if ( !( name.isEmpty() && email.isEmpty() ) ) {
 
637
    incidence->addAttendee( KCalCore::Attendee::Ptr( new KCalCore::Attendee( name, email ) ) );
 
638
    KMessageBox::information(
 
639
      this,
 
640
      i18n( "Attendee \"%1\" added to the calendar item \"%2\"",
 
641
            KPIMUtils::normalizedAddress( name, email, QString() ), text() ),
 
642
      i18n( "Attendee added" ), "AttendeeDroppedAdded" );
 
643
  }
 
644
}
 
645
 
 
646
void AgendaItem::dropEvent( QDropEvent *e )
 
647
{
 
648
  // TODO: Organize this better: First check for attachment
 
649
  // (not only file, also any other url!), then if it's a vcard,
 
650
  // otherwise check for attendees, then if the data is binary,
 
651
  // add a binary attachment.
 
652
#ifndef KORG_NODND
 
653
  if ( !mValid ) {
 
654
    return;
 
655
  }
 
656
 
 
657
  const QMimeData *md = e->mimeData();
 
658
 
 
659
  bool decoded = md->hasText();
 
660
  QString text = md->text();
 
661
  if ( decoded && text.startsWith( QLatin1String( "file:" ) ) ) {
 
662
    const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( mIncidence );
 
663
    incidence->addAttachment( KCalCore::Attachment::Ptr( new KCalCore::Attachment( text ) ) );
 
664
    return;
 
665
  }
 
666
 
 
667
  KABC::Addressee::List list;
 
668
 
 
669
  if ( KABC::VCardDrag::fromMimeData( md, list ) ) {
 
670
    Q_FOREACH( const KABC::Addressee &addressee, list ) {
 
671
      QString em( addressee.fullEmail() );
 
672
      if ( em.isEmpty() ) {
 
673
        em = addressee.realName();
 
674
      }
 
675
      addAttendee( em );
 
676
    }
 
677
  }
 
678
#else
 
679
  Q_UNUSED( e );
 
680
#endif // KORG_NODND
 
681
}
 
682
 
 
683
QList<AgendaItem::QPtr> &AgendaItem::conflictItems()
 
684
{
 
685
  return mConflictItems;
 
686
}
 
687
 
 
688
void AgendaItem::setConflictItems( QList<AgendaItem::QPtr> ci )
 
689
{
 
690
  mConflictItems = ci;
 
691
  QList<AgendaItem::QPtr>::iterator it;
 
692
  for ( it = mConflictItems.begin(); it != mConflictItems.end(); ++it ) {
 
693
    (*it)->addConflictItem( this );
 
694
  }
 
695
}
 
696
 
 
697
void AgendaItem::addConflictItem( AgendaItem::QPtr ci )
 
698
{
 
699
  if ( !mConflictItems.contains( ci ) ) {
 
700
    mConflictItems.append( ci );
 
701
  }
 
702
}
 
703
 
 
704
QString AgendaItem::label() const
 
705
{
 
706
  return mLabelText;
 
707
}
 
708
 
 
709
bool AgendaItem::overlaps( CellItem *o ) const
 
710
{
 
711
  AgendaItem::QPtr other = static_cast<AgendaItem*>( o );
 
712
 
 
713
  if ( cellXLeft() <= other->cellXRight() && cellXRight() >= other->cellXLeft() ) {
 
714
    if ( ( cellYTop() <= other->cellYBottom() ) && ( cellYBottom() >= other->cellYTop() ) ) {
 
715
      return true;
 
716
    }
 
717
  }
 
718
 
 
719
  return false;
 
720
}
 
721
 
 
722
static void conditionalPaint( QPainter *p, bool condition, int &x, int y,
 
723
                              int ft, const QPixmap &pxmp )
 
724
{
 
725
  if ( condition ) {
 
726
    p->drawPixmap( x, y, pxmp );
 
727
    x += pxmp.width() + ft;
 
728
   }
 
729
}
 
730
 
 
731
void AgendaItem::paintIcon( QPainter *p, int &x, int y, int ft )
 
732
{
 
733
  QString iconName;
 
734
  Incidence::Ptr incidence = mIncidence.payload<KCalCore::Incidence::Ptr>();
 
735
  if ( incidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
 
736
    mSpecialEvent = true;
 
737
    iconName =  "view-calendar-wedding-anniversary";
 
738
  } else if ( incidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
 
739
    mSpecialEvent = true;
 
740
    // We don't draw icon. The icon is drawn already, because it's the Akonadi::Collection's icon
 
741
  }
 
742
 
 
743
  conditionalPaint( p, !iconName.isEmpty(), x, y, ft, cachedSmallIcon( iconName ) );
 
744
}
 
745
 
 
746
void AgendaItem::paintIcons( QPainter *p, int &x, int y, int ft )
 
747
{
 
748
  if ( !mEventView->preferences()->enableAgendaItemIcons() ) {
 
749
    return;
 
750
  }
 
751
 
 
752
  paintIcon( p, x, y, ft );
 
753
 
 
754
  QSet<EventView::ItemIcon> icons = mEventView->preferences()->agendaViewIcons();
 
755
 
 
756
  if ( icons.contains( EventViews::EventView::CalendarCustomIcon ) ) {
 
757
    const QString iconName = EventView::iconForItem( mIncidence );
 
758
    if ( !iconName.isEmpty() && iconName != "view-calendar" && iconName != "office-calendar" ) {
 
759
      conditionalPaint( p, true, x, y, ft, SmallIcon( iconName ) );
 
760
    }
 
761
  }
 
762
 
 
763
  Incidence::Ptr incidence = mIncidence.payload<KCalCore::Incidence::Ptr>();
 
764
  const bool isTodo = incidence && incidence->type() == Incidence::TypeTodo;
 
765
 
 
766
  if ( isTodo && icons.contains( EventViews::EventView::TaskIcon ) ) {
 
767
    KDateTime occurrenceDateTime = incidence->dateTime( Incidence::RoleRecurrenceStart );
 
768
    occurrenceDateTime.setDate( mDate );
 
769
    const QString iconName = incidence->iconName( occurrenceDateTime );
 
770
    conditionalPaint( p, !mSpecialEvent, x, y, ft, SmallIcon( iconName ) );
 
771
  }
 
772
 
 
773
  if ( icons.contains( EventView::RecurringIcon ) )
 
774
    conditionalPaint( p, mIconRecur && !mSpecialEvent, x, y, ft, *recurPxmp );
 
775
 
 
776
  if ( icons.contains( EventView::ReminderIcon ) )
 
777
    conditionalPaint( p, mIconAlarm && !mSpecialEvent, x, y, ft, *alarmPxmp );
 
778
 
 
779
  if ( icons.contains( EventView::ReadOnlyIcon ) )
 
780
    conditionalPaint( p, mIconReadonly && !mSpecialEvent, x, y, ft, *readonlyPxmp );
 
781
 
 
782
  if ( icons.contains( EventView::ReplyIcon ) )
 
783
    conditionalPaint( p, mIconReply, x, y, ft, *replyPxmp );
 
784
 
 
785
  if ( icons.contains( EventView::AttendingIcon ) )
 
786
    conditionalPaint( p, mIconGroup, x, y, ft, *groupPxmp );
 
787
 
 
788
  if ( icons.contains( EventView::TentativeIcon ) )
 
789
    conditionalPaint( p, mIconGroupTent, x, y, ft, *groupPxmpTent );
 
790
 
 
791
  if ( icons.contains( EventView::OrganizerIcon ) )
 
792
    conditionalPaint( p, mIconOrganizer, x, y, ft, *organizerPxmp );
 
793
}
 
794
 
 
795
void AgendaItem::paintEvent( QPaintEvent *ev )
 
796
{
 
797
  if ( !mValid ) {
 
798
    return;
 
799
  }
 
800
 
 
801
  QRect visRect = visibleRegion().boundingRect();
 
802
  // when scrolling horizontally in the side-by-side view, the repainted area is clipped
 
803
  // to the newly visible area, which is a problem since the content changes when visRect
 
804
  // changes, so repaint the full item in that case
 
805
  if ( ev->rect() != visRect && visRect.isValid() && ev->rect().isValid() ) {
 
806
    update( visRect );
 
807
    return;
 
808
  }
 
809
 
 
810
  QPainter p( this );
 
811
  p.setRenderHint( QPainter::Antialiasing );
 
812
  const int fmargin = 0; // frame margin
 
813
  const int ft = 1; // frame thickness for layout, see drawRoundedRect(),
 
814
                    // keep multiple of 2
 
815
  const int margin = 5 + ft + fmargin ; // frame + space between frame and content
 
816
 
 
817
  // General idea is to always show the icons (even in the all-day events).
 
818
  // This creates a consistent feeling for the user when the view mode
 
819
  // changes and therefore the available width changes.
 
820
  // Also look at #17984
 
821
 
 
822
  if ( !alarmPxmp ) {
 
823
    alarmPxmp     = new QPixmap( SmallIcon( "task-reminder" ) );
 
824
    recurPxmp     = new QPixmap( SmallIcon( "appointment-recurring" ) );
 
825
    readonlyPxmp  = new QPixmap( SmallIcon( "object-locked" ) );
 
826
    replyPxmp     = new QPixmap( SmallIcon( "mail-reply-sender" ) );
 
827
    groupPxmp     = new QPixmap( SmallIcon( "meeting-attending" ) );
 
828
    groupPxmpTent = new QPixmap( SmallIcon( "meeting-attending-tentative" ) );
 
829
    organizerPxmp = new QPixmap( SmallIcon( "meeting-organizer" ) );
 
830
  }
 
831
 
 
832
  QColor bgColor;
 
833
 
 
834
  if ( CalendarSupport::hasTodo( mIncidence ) &&
 
835
       !mEventView->preferences()->todosUseCategoryColors() ) {
 
836
    Todo::Ptr todo = CalendarSupport::todo( mIncidence );
 
837
    Q_ASSERT( todo );
 
838
    const QDate dueDate = todo->dtDue().toTimeSpec( CalendarSupport::KCalPrefs::instance()->timeSpec() ).date();
 
839
    const QDate today = KDateTime::currentDateTime( CalendarSupport::KCalPrefs::instance()->timeSpec() ).date();
 
840
    if ( todo->isOverdue() && today >= mDate ) {
 
841
      bgColor = mEventView->preferences()->todoOverdueColor();
 
842
    } else if ( dueDate == today && dueDate == mDate ) {
 
843
      bgColor = mEventView->preferences()->todoDueTodayColor();
 
844
    }
 
845
  }
 
846
 
 
847
  const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( mIncidence );
 
848
  Q_ASSERT( incidence );
 
849
  QColor categoryColor;
 
850
  const QStringList categories = incidence->categories();
 
851
  QString cat;
 
852
  if ( !categories.isEmpty() ) {
 
853
    cat = categories.first();
 
854
  }
 
855
 
 
856
  categoryColor = cat.isEmpty() ? CalendarSupport::KCalPrefs::instance()->unsetCategoryColor() :
 
857
                                  CalendarSupport::KCalPrefs::instance()->categoryColor( cat );
 
858
 
 
859
  QColor resourceColor = mResourceColor;
 
860
  if ( !resourceColor.isValid() ) {
 
861
    resourceColor = categoryColor;
 
862
  }
 
863
 
 
864
  QColor frameColor;
 
865
  // TODO PrefsBase enums should probably be redefined in Prefs
 
866
  if ( mEventView->preferences()->agendaViewColors() == PrefsBase::ResourceOnly ||
 
867
       mEventView->preferences()->agendaViewColors() == PrefsBase::CategoryInsideResourceOutside ) {
 
868
    frameColor = bgColor.isValid() ? bgColor : resourceColor;
 
869
  } else {
 
870
    frameColor = bgColor.isValid() ? bgColor : categoryColor;
 
871
  }
 
872
 
 
873
  if ( !bgColor.isValid() ) {
 
874
    if ( mEventView->preferences()->agendaViewColors() == PrefsBase::ResourceOnly ||
 
875
         mEventView->preferences()->agendaViewColors() == PrefsBase::ResourceInsideCategoryOutside ) {
 
876
      bgColor = resourceColor;
 
877
    } else {
 
878
      bgColor = categoryColor;
 
879
    }
 
880
  }
 
881
 
 
882
  if ( cat.isEmpty() &&
 
883
       mEventView->preferences()->agendaViewColors() == PrefsBase::ResourceInsideCategoryOutside ) {
 
884
    frameColor = bgColor;
 
885
  }
 
886
 
 
887
  if ( cat.isEmpty() &&
 
888
       mEventView->preferences()->agendaViewColors() == PrefsBase::CategoryInsideResourceOutside ) {
 
889
    bgColor = frameColor;
 
890
  }
 
891
 
 
892
  frameColor = EventView::itemFrameColor( frameColor, mSelected );
 
893
 
 
894
  if ( !CalendarSupport::KCalPrefs::instance()->hasCategoryColor( cat ) ) {
 
895
    categoryColor = resourceColor;
 
896
  }
 
897
 
 
898
  if ( !bgColor.isValid() ) {
 
899
    bgColor = categoryColor;
 
900
  }
 
901
 
 
902
  if ( mSelected ) {
 
903
    bgColor = bgColor.light( EventView::BRIGHTNESS_FACTOR );
 
904
  }
 
905
 
 
906
  const QColor textColor = EventViews::getTextColor( bgColor );
 
907
  p.setPen( textColor );
 
908
 
 
909
  p.setFont( mEventView->preferences()->agendaViewFont() );
 
910
  QFontMetrics fm = p.fontMetrics();
 
911
 
 
912
  const int singleLineHeight = fm.boundingRect( mLabelText ).height();
 
913
 
 
914
  const bool roundTop = !prevMultiItem();
 
915
  const bool roundBottom = !nextMultiItem();
 
916
 
 
917
  drawRoundedRect( &p, QRect( fmargin, fmargin, width() - fmargin * 2, height() - fmargin * 2 ),
 
918
                   mSelected, bgColor, true, ft, roundTop, roundBottom );
 
919
 
 
920
  // calculate the height of the full version (case 4) to test whether it is
 
921
  // possible
 
922
 
 
923
  QString shortH;
 
924
  QString longH;
 
925
  if ( !isMultiItem() ) {
 
926
    // TODO: When we depend on kdepimlibs 4.7, replace with: shortH
 
927
    // KGlobal::locale()->formatTime(incidence->dateTime( KCalCore::Incidence::RoleDisplayStart ).toTimeSpec( mEventView->preferences()->timeSpec() ).time() )
 
928
    if ( incidence->type() == Incidence::TypeEvent ) {
 
929
      shortH = KGlobal::locale()->formatTime( incidence->dtStart().toTimeSpec( mEventView->preferences()->timeSpec() ).time() );
 
930
    } else if ( incidence->type() == Incidence::TypeTodo ) {
 
931
      Todo::Ptr todo = CalendarSupport::todo( mIncidence );
 
932
      if ( todo )
 
933
        shortH = KGlobal::locale()->formatTime( todo->dtDue().toTimeSpec( mEventView->preferences()->timeSpec() ).time() );
 
934
    }
 
935
    if ( CalendarSupport::hasEvent( mIncidence ) ) {
 
936
      longH = i18n( "%1 - %2",
 
937
                    shortH,
 
938
                    KGlobal::locale()->formatTime(
 
939
                      incidence->dateTime( KCalCore::Incidence::RoleEnd ).toTimeSpec(
 
940
                        mEventView->preferences()->timeSpec() ).time() ) );
 
941
    } else {
 
942
      longH = shortH;
 
943
    }
 
944
  } else if ( !mMultiItemInfo->mFirstMultiItem ) {
 
945
    shortH = KGlobal::locale()->formatTime(
 
946
      incidence->dtStart().toTimeSpec( mEventView->preferences()->timeSpec() ).time() );
 
947
    longH = shortH;
 
948
  } else {
 
949
    shortH = KGlobal::locale()->formatTime(
 
950
      incidence->dateTime( KCalCore::Incidence::RoleEnd ).toTimeSpec(
 
951
        mEventView->preferences()->timeSpec() ).time() );
 
952
    longH = i18n( "- %1", shortH );
 
953
  }
 
954
 
 
955
  KWordWrap *ww = KWordWrap::formatText(
 
956
    fm, QRect( 0, 0, width() - ( 2 * margin ), -1 ), 0, mLabelText );
 
957
  int th = ww->boundingRect().height();
 
958
  delete ww;
 
959
 
 
960
  int hlHeight = qMax( fm.boundingRect( longH ).height(),
 
961
                       qMax( alarmPxmp->height(),
 
962
                            qMax( recurPxmp->height(),
 
963
                                 qMax( readonlyPxmp->height(),
 
964
                                      qMax( replyPxmp->height(),
 
965
                                           qMax( groupPxmp->height(),
 
966
                                                 organizerPxmp->height() ) ) ) ) ) );
 
967
 
 
968
  const bool completelyRenderable = th < ( height() - 2 * ft - 2 - hlHeight );
 
969
 
 
970
  // case 1: do not draw text when not even a single line fits
 
971
  // Don't do this any more, always try to print out the text.
 
972
  // Even if it's just a few pixel, one can still guess the whole
 
973
  // text from just four pixels' height!
 
974
  if ( //( singleLineHeight > height() - 4 ) ||
 
975
       ( width() < 16 ) ) {
 
976
    int x = qRound( ( width() - 16 ) / 2.0 );
 
977
    paintIcon( &p, x/*by-ref*/, margin, ft );
 
978
    return;
 
979
  }
 
980
 
 
981
  // case 2: draw a single line when no more space
 
982
  if ( ( 2 * singleLineHeight ) > ( height() - 2 * margin ) ) {
 
983
    int x = margin, txtWidth;
 
984
 
 
985
    if ( incidence->allDay() ) {
 
986
      x += visRect.left();
 
987
      const int y =  qRound( ( height() - 16 ) / 2.0 );
 
988
      paintIcons( &p, x, y, ft );
 
989
      txtWidth = visRect.right() - margin - x;
 
990
    } else {
 
991
      const int y =  qRound( ( height() - 16 ) / 2.0 );
 
992
      paintIcons( &p, x, y, ft );
 
993
      txtWidth = width() - margin - x;
 
994
    }
 
995
 
 
996
    const int y = ( ( height() - singleLineHeight ) / 2 ) + fm.ascent();
 
997
    KWordWrap::drawFadeoutText( &p, x, y, txtWidth, mLabelText );
 
998
    return;
 
999
  }
 
1000
 
 
1001
  // case 3: enough for 2-5 lines, but not for the header.
 
1002
  //         Also used for the middle days in multi-events
 
1003
  if ( ( ( !completelyRenderable ) &&
 
1004
         ( ( height() - ( 2 * margin ) ) <= ( 5 * singleLineHeight ) ) ) ||
 
1005
       ( isMultiItem() && mMultiItemInfo->mNextMultiItem && mMultiItemInfo->mFirstMultiItem ) ) {
 
1006
    int x = margin, txtWidth;
 
1007
 
 
1008
    if ( incidence->allDay() ) {
 
1009
      x += visRect.left();
 
1010
      paintIcons( &p, x, margin, ft );
 
1011
      txtWidth = visRect.right() - margin - x;
 
1012
    } else {
 
1013
      paintIcons( &p, x, margin, ft );
 
1014
      txtWidth = width() - margin - x;
 
1015
    }
 
1016
 
 
1017
    ww = KWordWrap::formatText(
 
1018
      fm, QRect( 0, 0, txtWidth, ( height() - ( 2 * margin ) ) ), 0, mLabelText );
 
1019
 
 
1020
    ww->drawText( &p, x, margin, Qt::AlignHCenter | KWordWrap::FadeOut );
 
1021
    delete ww;
 
1022
    return;
 
1023
  }
 
1024
 
 
1025
  // case 4: paint everything, with header:
 
1026
  // consists of (vertically) ft + headline&icons + ft + text + margin
 
1027
  int y = 2 * ft + hlHeight;
 
1028
  if ( completelyRenderable ) {
 
1029
    y += ( height() - ( 2 * ft ) - margin - hlHeight - th ) / 2;
 
1030
  }
 
1031
 
 
1032
  int x = margin, txtWidth, hTxtWidth, eventX;
 
1033
 
 
1034
  if ( incidence->allDay() ) {
 
1035
    shortH = longH = "";
 
1036
 
 
1037
    if ( const KCalCore::Event::Ptr event = CalendarSupport::event( mIncidence ) ) {
 
1038
      if ( event->isMultiDay( mEventView->preferences()->timeSpec() ) ) {
 
1039
        // multi-day, all-day event
 
1040
        shortH =
 
1041
          i18n( "%1 - %2",
 
1042
                KGlobal::locale()->formatDate(
 
1043
                  incidence->dtStart().toTimeSpec( mEventView->preferences()->timeSpec() ).date() ),
 
1044
                KGlobal::locale()->formatDate(
 
1045
                  incidence->dateTime( KCalCore::Incidence::RoleEnd ).toTimeSpec(
 
1046
                    mEventView->preferences()->timeSpec() ).date() ) );
 
1047
        longH = shortH;
 
1048
 
 
1049
        // paint headline
 
1050
        drawRoundedRect(
 
1051
          &p,
 
1052
          QRect( fmargin, fmargin, width() - fmargin * 2, - fmargin * 2 + margin + hlHeight ),
 
1053
          mSelected, frameColor, false, ft, roundTop, false );
 
1054
      } else {
 
1055
        // single-day, all-day event
 
1056
 
 
1057
        // paint headline
 
1058
        drawRoundedRect(
 
1059
          &p,
 
1060
          QRect( fmargin, fmargin, width() - fmargin * 2, - fmargin * 2 + margin + hlHeight ),
 
1061
          mSelected, frameColor, false, ft, roundTop, false );
 
1062
      }
 
1063
    } else {
 
1064
      // to-do
 
1065
 
 
1066
      // paint headline
 
1067
      drawRoundedRect(
 
1068
        &p,
 
1069
        QRect( fmargin, fmargin, width() - fmargin * 2, - fmargin * 2 + margin + hlHeight ),
 
1070
        mSelected, frameColor, false, ft, roundTop, false );
 
1071
    }
 
1072
 
 
1073
    x += visRect.left();
 
1074
    eventX = x;
 
1075
    txtWidth = visRect.right() - margin - x;
 
1076
    paintIcons( &p, x, margin, ft );
 
1077
    hTxtWidth = visRect.right() - margin - x;
 
1078
  } else {
 
1079
    // paint headline
 
1080
     drawRoundedRect(
 
1081
       &p,
 
1082
       QRect( fmargin, fmargin, width() - fmargin * 2, - fmargin * 2 + margin + hlHeight ),
 
1083
       mSelected, frameColor, false, ft, roundTop, false );
 
1084
 
 
1085
    txtWidth = width() - margin - x;
 
1086
    eventX = x;
 
1087
    paintIcons( &p, x, margin / 2, ft );
 
1088
    hTxtWidth = width() - margin - x;
 
1089
  }
 
1090
 
 
1091
  QString headline;
 
1092
  int hw = fm.boundingRect( longH ).width();
 
1093
  if ( hw > hTxtWidth ) {
 
1094
    headline = shortH;
 
1095
    hw = fm.boundingRect( shortH ).width();
 
1096
    if ( hw < txtWidth ) {
 
1097
      x += ( hTxtWidth - hw ) / 2;
 
1098
    }
 
1099
  } else {
 
1100
    headline = longH;
 
1101
    x += ( hTxtWidth - hw ) / 2;
 
1102
  }
 
1103
  p.setBackground( QBrush( frameColor ) );
 
1104
  p.setPen( EventViews::getTextColor( frameColor ) );
 
1105
  KWordWrap::drawFadeoutText( &p, x, ( margin + hlHeight + fm.ascent() ) / 2 - 2,
 
1106
                              hTxtWidth, headline );
 
1107
 
 
1108
  // draw event text
 
1109
  ww = KWordWrap::formatText(
 
1110
    fm, QRect( 0, 0, txtWidth, height() - margin - y ), 0, mLabelText );
 
1111
 
 
1112
  p.setBackground( QBrush( bgColor ) );
 
1113
  p.setPen( textColor );
 
1114
  QString ws = ww->wrappedString();
 
1115
  if ( ws.left( ws.length()-1 ).indexOf( '\n' ) >= 0 ) {
 
1116
    ww->drawText( &p, eventX, y, Qt::AlignLeft | KWordWrap::FadeOut );
 
1117
  } else {
 
1118
    ww->drawText( &p, eventX + ( txtWidth - ww->boundingRect().width() - 2 * margin ) / 2, y,
 
1119
                  Qt::AlignHCenter | KWordWrap::FadeOut );
 
1120
  }
 
1121
  delete ww;
 
1122
 
 
1123
}
 
1124
 
 
1125
void AgendaItem::drawRoundedRect( QPainter *p, const QRect &rect,
 
1126
                                    bool selected, const QColor &bgColor,
 
1127
                                    bool frame, int ft, bool roundTop,
 
1128
                                    bool roundBottom )
 
1129
{
 
1130
  Q_UNUSED( ft );
 
1131
  if ( !mValid ) {
 
1132
    return;
 
1133
  }
 
1134
 
 
1135
  QRect r = rect;
 
1136
  r.adjust( 0, 0, 1, 1 );
 
1137
 
 
1138
  p->save();
 
1139
 
 
1140
  QPainterPath path;
 
1141
 
 
1142
  bool shrinkWidth = r.width() < 16;
 
1143
  bool shrinkHeight = r.height() < 16;
 
1144
 
 
1145
  qreal rnd = 2.1;
 
1146
  int sw = shrinkWidth ? 10 : 11;
 
1147
  int sh = shrinkHeight ? 10 : 11;
 
1148
  QRectF tr( r.x() + r.width() - sw - rnd, r.y() + rnd, sw, sh );
 
1149
  QRectF tl( r.x() + rnd, r.y() + rnd, sw, sh );
 
1150
  QRectF bl( r.x() + rnd, r.y() + r.height() - sh - 1 - rnd, sw, sh );
 
1151
  QRectF br( r.x() + r.width() - sw - rnd, r.y() + r.height() - sh - 1 - rnd, sw, sh );
 
1152
 
 
1153
  if( roundTop ) {
 
1154
    path.moveTo( tr.topRight() );
 
1155
    path.arcTo( tr, 0.0, 90.0 );
 
1156
    path.lineTo( tl.topRight() );
 
1157
    path.arcTo( tl, 90.0, 90.0 );
 
1158
  } else {
 
1159
    path.moveTo( tr.topRight() );
 
1160
    path.lineTo( tl.topLeft() );
 
1161
  }
 
1162
 
 
1163
  if( roundBottom ) {
 
1164
    path.lineTo( bl.topLeft() );
 
1165
    path.arcTo( bl, 180.0, 90.0 );
 
1166
    path.lineTo( br.bottomLeft() );
 
1167
    path.arcTo( br, 270.0, 90.0 );
 
1168
  } else {
 
1169
    path.lineTo( bl.bottomLeft() );
 
1170
    path.lineTo( br.bottomRight() );
 
1171
  }
 
1172
  path.closeSubpath();
 
1173
 
 
1174
  // header
 
1175
  if ( !frame ) {
 
1176
    QLinearGradient gradient( QPointF( r.x(), r.y() ), QPointF( r.x(), r.height() ) );
 
1177
 
 
1178
    if ( selected ) {
 
1179
      QColor top = bgColor.dark( 250 );
 
1180
      top.setAlpha( 40 );
 
1181
      gradient.setColorAt( 0, top );
 
1182
      gradient.setColorAt( 1, QColor( 255, 255, 255, 30 ) );
 
1183
    } else {
 
1184
      gradient.setColorAt( 0, QColor( 255, 255, 255, 90 ) );
 
1185
      gradient.setColorAt( 1, QColor( 0, 0, 0, 10 ) );
 
1186
    }
 
1187
 
 
1188
    p->setBrush( bgColor );
 
1189
    p->setPen( Qt::NoPen );
 
1190
    p->drawPath( path );
 
1191
 
 
1192
    p->setBrush( gradient );
 
1193
    p->setPen( Qt::NoPen );
 
1194
    p->drawPath( path );
 
1195
 
 
1196
    QPixmap separator;
 
1197
    QString key( "ko_hsep" );
 
1198
    if ( !QPixmapCache::find( key, separator ) ) {
 
1199
      separator = QPixmap( ":/headerSeparator.png" );
 
1200
      QPixmapCache::insert( key, separator );
 
1201
    }
 
1202
    p->fillRect( QRect( r.x() + 3, r.y() + r.height() - 2, r.x() + r.width() - 4, 2 ),
 
1203
                 QBrush( separator ) );
 
1204
 
 
1205
    p->restore();
 
1206
    return;
 
1207
  }
 
1208
 
 
1209
  QLinearGradient gradient( QPointF( r.x(), r.y() ), QPointF( r.x(), r.height() ) );
 
1210
 
 
1211
  const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( mIncidence );
 
1212
  Q_ASSERT( incidence );
 
1213
 
 
1214
  if ( r.height() > 50 ) {
 
1215
    if ( incidence->allDay() &&
 
1216
         incidence->dtStart() == incidence->dateTime( KCalCore::Incidence::RoleEnd ) &&
 
1217
         CalendarSupport::hasEvent( mIncidence ) ) {
 
1218
      gradient.setColorAt( 0, bgColor.light( 130 ) );
 
1219
      qreal t = 1.0 - ( r.height() - 18.0 ) / r.height();
 
1220
      gradient.setColorAt( t, bgColor.light( 115 ) );
 
1221
      qreal b = ( r.height() - 20.0 ) / r.height();
 
1222
      gradient.setColorAt( b, bgColor );
 
1223
    } else {
 
1224
      gradient.setColorAt( 0, bgColor.light( 115 ) );
 
1225
      qreal b = ( r.height() - 20.0 ) / r.height();
 
1226
      gradient.setColorAt( b, bgColor );
 
1227
    }
 
1228
    gradient.setColorAt( 1, bgColor.dark( 110 ) );
 
1229
  } else {
 
1230
    if ( incidence->allDay() &&
 
1231
         incidence->dtStart() == incidence->dateTime( KCalCore::Incidence::RoleEnd ) &&
 
1232
         !CalendarSupport::hasTodo( mIncidence ) ) {
 
1233
      gradient.setColorAt( 0, bgColor.light( 130 ) );
 
1234
      gradient.setColorAt( 0.35, bgColor.light( 115 ) );
 
1235
      gradient.setColorAt( 0.65, bgColor );
 
1236
    } else {
 
1237
      gradient.setColorAt( 0, bgColor.light( 115 ) );
 
1238
      gradient.setColorAt( 0.65, bgColor );
 
1239
    }
 
1240
    gradient.setColorAt( 1, bgColor.dark( 110 ) );
 
1241
  }
 
1242
 
 
1243
  p->setBrush( gradient );
 
1244
  p->setPen( Qt::NoPen );
 
1245
  p->drawPath( path );
 
1246
 
 
1247
  p->setRenderHint( QPainter::Antialiasing, false );
 
1248
 
 
1249
  if ( r.width() - 16 > 0 ) {
 
1250
    QPixmap topLines;
 
1251
    QString key( "ko_t" );
 
1252
    if ( !QPixmapCache::find( key, topLines ) ) {
 
1253
      topLines = QPixmap( ":/topLines.png" );
 
1254
      QPixmapCache::insert( key, topLines );
 
1255
    }
 
1256
    p->setBrushOrigin( r.x() + 8, r.y() );
 
1257
    p->fillRect( QRect( r.x() + 8, r.y(), r.width() - 16, 5 ),
 
1258
                 QBrush( topLines ) );
 
1259
 
 
1260
    QPixmap bottomLines;
 
1261
    key = QString( "ko_b" );
 
1262
    if ( !QPixmapCache::find( key, bottomLines ) ) {
 
1263
      bottomLines = QPixmap( ":/bottomLines.png" );
 
1264
      QPixmapCache::insert( key, bottomLines );
 
1265
    }
 
1266
    p->setBrushOrigin( r.x() + 8, r.y() + r.height() - 6 );
 
1267
    p->fillRect( QRect( r.x() + 8, r.y() + r.height() - 6, r.width() - 16, 6 ),
 
1268
                 QBrush( bottomLines ) );
 
1269
 
 
1270
  }
 
1271
 
 
1272
  if ( r.height() - 16 > 0 ) {
 
1273
 
 
1274
    QPixmap leftLines;
 
1275
    QString key( "ko_l" );
 
1276
    if ( !QPixmapCache::find( key, leftLines ) ) {
 
1277
      leftLines = QPixmap( ":/leftLines.png" );
 
1278
      QPixmapCache::insert( key, leftLines );
 
1279
    }
 
1280
    p->setBrushOrigin( r.x(), r.y() + 8 );
 
1281
    p->fillRect( QRect( r.x(), r.y() + 8, 5, r.height() - 16 ),
 
1282
                 QBrush( leftLines ) );
 
1283
 
 
1284
    QPixmap rightLines;
 
1285
    key = QString( "ko_r" );
 
1286
    if ( !QPixmapCache::find( key, rightLines ) ) {
 
1287
      rightLines = QPixmap( ":/rightLines.png" );
 
1288
      QPixmapCache::insert( key, rightLines );
 
1289
    }
 
1290
    p->setBrushOrigin( r.x() + r.width() - 5, r.y() + 8 );
 
1291
    p->fillRect( QRect( r.x() + r.width() - 5, r.y() + 8, 5, r.height() - 16 ),
 
1292
                 QBrush( rightLines ) );
 
1293
  }
 
1294
 
 
1295
  // don't overlap the edges
 
1296
  int lw = shrinkWidth ? r.width() / 2 : 8;
 
1297
  int rw = shrinkWidth ? r.width() - lw : 8;
 
1298
  int th = shrinkHeight ? r.height() / 2 : 8;
 
1299
  int bh = shrinkHeight ? r.height() - th : 8;
 
1300
 
 
1301
  // keep the bottom round for items which ending at 00:15
 
1302
  if( shrinkHeight && !roundTop && roundBottom && r.height() > 3 ) {
 
1303
    bh += th - 3;
 
1304
    th = 3;
 
1305
  }
 
1306
 
 
1307
  QPixmap topLeft;
 
1308
  QString key = roundTop ? QString( "ko_tl" ) : QString( "ko_rtl" );
 
1309
  if ( !QPixmapCache::find( key, topLeft ) ) {
 
1310
    topLeft = roundTop ? QPixmap( ":/roundTopLeft.png" ) : QPixmap( ":/rectangularTopLeft.png" );
 
1311
    QPixmapCache::insert( key, topLeft );
 
1312
  }
 
1313
  p->drawPixmap( r.x(), r.y(), topLeft, 0, 0, lw, th );
 
1314
 
 
1315
  QPixmap topRight;
 
1316
  key = roundTop ? QString( "ko_tr" ) : QString( "ko_rtr" );
 
1317
  if ( !QPixmapCache::find( key, topRight ) ) {
 
1318
    topRight = roundTop ? QPixmap( ":/roundTopRight.png" ) : QPixmap( ":/rectangularTopRight.png" );
 
1319
    QPixmapCache::insert( key, topRight );
 
1320
  }
 
1321
  p->drawPixmap( r.x() + r.width() - rw, r.y(), topRight, 8 - rw, 0, rw, th );
 
1322
 
 
1323
  QPixmap bottomLeft;
 
1324
  key = roundBottom ? QString( "ko_bl" ) : QString( "ko_rbl" );
 
1325
  if ( !QPixmapCache::find( key, bottomLeft ) ) {
 
1326
    bottomLeft = roundBottom ? QPixmap( ":/roundBottomLeft.png" ) :
 
1327
                 QPixmap( ":/rectangularBottomLeft.png" );
 
1328
    QPixmapCache::insert( key, bottomLeft );
 
1329
  }
 
1330
  p->drawPixmap( r.x(), r.y() + r.height() - bh, bottomLeft, 0, 8 - bh, lw, bh );
 
1331
 
 
1332
  QPixmap bottomRight;
 
1333
  key = roundBottom ? QString( "ko_br" ) : QString( "ko_rbr" );
 
1334
  if ( !QPixmapCache::find( key, bottomRight ) ) {
 
1335
    bottomRight = roundBottom ? QPixmap( ":/roundBottomRight.png" ) :
 
1336
                  QPixmap( ":/rectangularBottomRight.png" );
 
1337
    QPixmapCache::insert( key, bottomRight );
 
1338
  }
 
1339
  p->drawPixmap( r.x() + r.width() - rw, r.y() + r.height() - bh, bottomRight,
 
1340
                 8 - rw, 8 - bh, rw, 8 );
 
1341
 
 
1342
  p->restore();
 
1343
}
 
1344
 
 
1345
bool AgendaItem::eventFilter( QObject *obj, QEvent *event )
 
1346
{
 
1347
  if ( event->type() == QEvent::Paint ) {
 
1348
    return mValid;
 
1349
  } else {
 
1350
    // standard event processing
 
1351
    return QObject::eventFilter( obj, event );
 
1352
  }
 
1353
}
 
1354
 
 
1355
bool AgendaItem::event( QEvent *event )
 
1356
{
 
1357
  if ( event->type() == QEvent::ToolTip ) {
 
1358
    if( !mEventView->preferences()->enableToolTips() ) {
 
1359
      return true;
 
1360
    } else if ( mValid ) {
 
1361
      QHelpEvent *helpEvent = static_cast<QHelpEvent*>( event );
 
1362
      QToolTip::showText(
 
1363
        helpEvent->globalPos(),
 
1364
        KCalUtils::IncidenceFormatter::toolTipStr(
 
1365
          CalendarSupport::displayName( mIncidence.parentCollection() ),
 
1366
          CalendarSupport::incidence( mIncidence ),
 
1367
          mDate, true, mEventView->preferences()->timeSpec() ),
 
1368
        this );
 
1369
    }
 
1370
  }
 
1371
  return QWidget::event( event );
 
1372
}
 
1373
 
 
1374
#include "agendaitem.moc"