00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <qevent.h>
00029 #include <qpainter.h>
00030 #include <qptrlist.h>
00031
00032 #include <kglobal.h>
00033 #include <kdebug.h>
00034 #include <klocale.h>
00035 #include <kiconloader.h>
00036
00037 #include <libkcal/vcaldrag.h>
00038 #include <libkcal/icaldrag.h>
00039 #include <libkcal/dndfactory.h>
00040 #include <libkcal/calendarresources.h>
00041 #include <libkcal/resourcecalendar.h>
00042
00043 #include <kcalendarsystem.h>
00044
00045 #ifndef KORG_NOPLUGINS
00046 #include "kocore.h"
00047 #endif
00048 #include "koprefs.h"
00049 #include "koglobals.h"
00050 #include "kodialogmanager.h"
00051
00052 #include "kodaymatrix.h"
00053 #include "kodaymatrix.moc"
00054
00055 #ifndef NODND
00056 #include <qcursor.h>
00057 #include <kpopupmenu.h>
00058 #include <X11/Xlib.h>
00059 #undef KeyPress
00060 #undef None
00061 #undef Status
00062 #endif
00063
00064
00065
00066
00067
00068 DynamicTip::DynamicTip( QWidget * parent )
00069 : QToolTip( parent )
00070 {
00071 mMatrix = static_cast<KODayMatrix *>( parent );
00072 }
00073
00074
00075 void DynamicTip::maybeTip( const QPoint &pos )
00076 {
00077
00078 QRect sz = mMatrix->frameRect();
00079 int dheight = sz.height() * 7 / 42;
00080 int dwidth = sz.width() / 7;
00081 int row = pos.y() / dheight;
00082 int col = pos.x() / dwidth;
00083
00084 QRect rct( col * dwidth, row * dheight, dwidth, dheight );
00085
00086
00087
00088
00089
00090 QString str = mMatrix->getHolidayLabel( col + row * 7 );
00091 if ( str.isEmpty() ) return;
00092 tip( rct, str );
00093 }
00094
00095
00096
00097
00098
00099
00100 const int KODayMatrix::NOSELECTION = -1000;
00101 const int KODayMatrix::NUMDAYS = 42;
00102
00103 KODayMatrix::KODayMatrix( QWidget *parent, const char *name )
00104 : QFrame( parent, name ), mCalendar( 0 )
00105 {
00106
00107 mDays = new QDate[ NUMDAYS ];
00108 mDayLabels = new QString[ NUMDAYS ];
00109 mEvents = new int[ NUMDAYS ];
00110 mToolTip = new DynamicTip( this );
00111
00112
00113 mDefaultBackColor = palette().active().base();
00114 mDefaultTextColor = palette().active().foreground();
00115 mDefaultTextColorShaded = getShadedColor( mDefaultTextColor );
00116 mHolidayColorShaded = getShadedColor( KOPrefs::instance()->mHolidayColor );
00117 mSelectedDaysColor = QColor( "white" );
00118 mTodayMarginWidth = 2;
00119 mSelEnd = mSelStart = NOSELECTION;
00120 setBackgroundMode( NoBackground );
00121 }
00122
00123 void KODayMatrix::setCalendar( Calendar *cal )
00124 {
00125 mCalendar = cal;
00126
00127 setAcceptDrops( mCalendar );
00128
00129 updateEvents();
00130 }
00131
00132 QColor KODayMatrix::getShadedColor( QColor color )
00133 {
00134 QColor shaded;
00135 int h = 0;
00136 int s = 0;
00137 int v = 0;
00138 color.hsv( &h, &s, &v );
00139 s = s / 4;
00140 v = 192 + v / 4;
00141 shaded.setHsv( h, s, v );
00142
00143 return shaded;
00144 }
00145
00146 KODayMatrix::~KODayMatrix()
00147 {
00148 delete [] mDays;
00149 delete [] mDayLabels;
00150 delete [] mEvents;
00151 delete mToolTip;
00152 }
00153
00154 void KODayMatrix::addSelectedDaysTo( DateList &selDays )
00155 {
00156 kdDebug(5850) << "KODayMatrix::addSelectedDaysTo() - " << "mSelStart:" << mSelStart << endl;
00157
00158 if ( mSelStart == NOSELECTION ) {
00159 return;
00160 }
00161
00162
00163 int i0 = mSelStart;
00164 if ( i0 < 0 ) {
00165 for ( int i = i0; i < 0; i++ ) {
00166 selDays.append( mDays[ 0 ].addDays( i ) );
00167 }
00168 i0 = 0;
00169 }
00170
00171
00172 if ( mSelEnd > NUMDAYS-1 ) {
00173 for ( int i = i0; i <= NUMDAYS - 1; i++ ) {
00174 selDays.append( mDays[ i ] );
00175 }
00176 for ( int i = NUMDAYS; i < mSelEnd; i++ ) {
00177 selDays.append( mDays[ 0 ].addDays( i ) );
00178 }
00179 } else {
00180
00181 for ( int i = i0; i <= mSelEnd; i++ ) {
00182 selDays.append( mDays[ i ] );
00183 }
00184 }
00185 }
00186
00187 void KODayMatrix::setSelectedDaysFrom( const QDate &start, const QDate &end )
00188 {
00189 mSelStart = mStartDate.daysTo( start );
00190 mSelEnd = mStartDate.daysTo( end );
00191 }
00192
00193 void KODayMatrix::clearSelection()
00194 {
00195 mSelEnd = mSelStart = NOSELECTION;
00196 }
00197
00198 void KODayMatrix::recalculateToday()
00199 {
00200 mToday = -1;
00201 for ( int i = 0; i < NUMDAYS; i++ ) {
00202 mDays[ i ] = mStartDate.addDays( i );
00203 mDayLabels[ i ] = QString::number( KOGlobals::self()->calendarSystem()->day( mDays[i] ));
00204
00205
00206 if ( mDays[ i ].year() == QDate::currentDate().year() &&
00207 mDays[ i ].month() == QDate::currentDate().month() &&
00208 mDays[ i ].day() == QDate::currentDate().day() ) {
00209 mToday = i;
00210 }
00211 }
00212
00213 }
00214
00215 void KODayMatrix::updateView()
00216 {
00217 updateView( mStartDate );
00218 }
00219
00220 void KODayMatrix::updateView( QDate actdate )
00221 {
00222
00223
00224
00225 bool daychanged = false;
00226
00227
00228
00229 if ( actdate != mStartDate ) {
00230
00231 if ( mSelStart != NOSELECTION ) {
00232 int tmp = actdate.daysTo( mStartDate );
00233
00234
00235
00236 if ( mSelStart + tmp < NUMDAYS && mSelEnd + tmp >= 0 ) {
00237
00238
00239 if( mSelStart > NUMDAYS || mSelStart < 0 )
00240 mSelStart = mSelStart + tmp;
00241 if( mSelEnd > NUMDAYS || mSelEnd < 0 )
00242 mSelEnd = mSelEnd + tmp;
00243 }
00244 }
00245
00246 mStartDate = actdate;
00247 daychanged = true;
00248 }
00249
00250 if ( daychanged ) {
00251 recalculateToday();
00252 }
00253
00254 updateEvents();
00255 for( int i = 0; i < NUMDAYS; i++ ) {
00256
00257 #ifndef KORG_NOPLUGINS
00258 QString holiStr = KOCore::self()->holiday( mDays[ i ] );
00259 #else
00260 QString holiStr = QString::null;
00261 #endif
00262 if ( ( KOGlobals::self()->calendarSystem()->dayOfWeek( mDays[ i ] ) ==
00263 KOGlobals::self()->calendarSystem()->weekDayOfPray() ) ||
00264 !holiStr.isEmpty() ) {
00265 if ( holiStr.isNull() ) holiStr = "";
00266 mHolidays[ i ] = holiStr;
00267 } else {
00268 mHolidays[ i ] = QString::null;
00269 }
00270 }
00271 }
00272
00273 void KODayMatrix::updateEvents()
00274 {
00275 if ( !mCalendar ) return;
00276
00277 for( int i = 0; i < NUMDAYS; i++ ) {
00278
00279 Event::List eventlist = mCalendar->events( mDays[ i ] );
00280 int numEvents = eventlist.count();
00281 Event::List::ConstIterator it;
00282 for( it = eventlist.begin(); it != eventlist.end(); ++it ) {
00283 Event *event = *it;
00284 ushort recurType = event->doesRecur();
00285
00286 if ( ( recurType == Recurrence::rDaily &&
00287 !KOPrefs::instance()->mDailyRecur ) ||
00288 ( recurType == Recurrence::rWeekly &&
00289 !KOPrefs::instance()->mWeeklyRecur ) ) {
00290 numEvents--;
00291 }
00292 }
00293 mEvents[ i ] = numEvents;
00294 }
00295 }
00296
00297 const QDate& KODayMatrix::getDate( int offset )
00298 {
00299 if ( offset < 0 || offset > NUMDAYS - 1 ) {
00300 kdDebug(5850) << "Wrong offset (" << offset << ") in KODayMatrix::getDate(int)" << endl;
00301 return mDays[ 0 ];
00302 }
00303 return mDays[ offset ];
00304 }
00305
00306 QString KODayMatrix::getHolidayLabel( int offset )
00307 {
00308 if ( offset < 0 || offset > NUMDAYS - 1 ) {
00309 kdDebug(5850) << "Wrong offset (" << offset << ") in KODayMatrix::getHolidayLabel(int)" << endl;
00310 return 0;
00311 }
00312 return mHolidays[ offset ];
00313 }
00314
00315 int KODayMatrix::getDayIndexFrom( int x, int y )
00316 {
00317 return 7 * ( y / mDaySize.height() ) +
00318 ( KOGlobals::self()->reverseLayout() ?
00319 6 - x / mDaySize.width() : x / mDaySize.width() );
00320 }
00321
00322
00323
00324
00325
00326 void KODayMatrix::mousePressEvent( QMouseEvent *e )
00327 {
00328 mSelStart = getDayIndexFrom(e->x(), e->y());
00329 if (mSelStart > NUMDAYS-1) mSelStart=NUMDAYS-1;
00330 mSelInit = mSelStart;
00331 }
00332
00333 void KODayMatrix::mouseReleaseEvent( QMouseEvent *e )
00334 {
00335 int tmp = getDayIndexFrom(e->x(), e->y());
00336 if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
00337
00338 if (mSelInit > tmp) {
00339 mSelEnd = mSelInit;
00340 if (tmp != mSelStart) {
00341 mSelStart = tmp;
00342 repaint();
00343 }
00344 } else {
00345 mSelStart = mSelInit;
00346
00347
00348 if (tmp != mSelEnd) {
00349 mSelEnd = tmp;
00350 repaint();
00351 }
00352 }
00353
00354 DateList daylist;
00355 if ( mSelStart < 0 ) mSelStart = 0;
00356 for (int i = mSelStart; i <= mSelEnd; i++) {
00357 daylist.append(mDays[i]);
00358 }
00359 emit selected((const DateList)daylist);
00360 }
00361
00362 void KODayMatrix::mouseMoveEvent( QMouseEvent *e )
00363 {
00364 int tmp = getDayIndexFrom(e->x(), e->y());
00365 if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
00366
00367 if (mSelInit > tmp) {
00368 mSelEnd = mSelInit;
00369 if (tmp != mSelStart) {
00370 mSelStart = tmp;
00371 repaint();
00372 }
00373 } else {
00374 mSelStart = mSelInit;
00375
00376
00377 if (tmp != mSelEnd) {
00378 mSelEnd = tmp;
00379 repaint();
00380 }
00381 }
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391 enum {
00392 DRAG_COPY = 0,
00393 DRAG_MOVE = 1,
00394 DRAG_CANCEL = 2
00395 };
00396
00397 void KODayMatrix::dragEnterEvent( QDragEnterEvent *e )
00398 {
00399 #ifndef KORG_NODND
00400 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00401 e->ignore();
00402 return;
00403 }
00404
00405
00406
00407
00408
00409 #endif
00410 }
00411
00412 void KODayMatrix::dragMoveEvent( QDragMoveEvent *e )
00413 {
00414 #ifndef KORG_NODND
00415 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00416 e->ignore();
00417 return;
00418 }
00419
00420 e->accept();
00421 #endif
00422 }
00423
00424 void KODayMatrix::dragLeaveEvent( QDragLeaveEvent * )
00425 {
00426 #ifndef KORG_NODND
00427
00428
00429 #endif
00430 }
00431
00432 void KODayMatrix::dropEvent( QDropEvent *e )
00433 {
00434 #ifndef KORG_NODND
00435 kdDebug(5850) << "KODayMatrix::dropEvent(e) begin" << endl;
00436
00437 if ( !mCalendar ||
00438 ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) ) {
00439 e->ignore();
00440 return;
00441 }
00442
00443 DndFactory factory( mCalendar );
00444 Event *event = factory.createDrop( e );
00445 Todo *todo = factory.createDropTodo( e );
00446 if ( !event && !todo ) {
00447 e->ignore();
00448 return;
00449 }
00450
00451 Todo *existingTodo = 0, *oldTodo = 0;
00452 Event *existingEvent = 0, *oldEvent = 0;
00453
00454
00455 if ( event ) existingEvent = mCalendar->event( event->uid() );
00456 if ( todo ) existingTodo = mCalendar->todo( todo->uid() );
00457
00458 int action = DRAG_CANCEL;
00459
00460 int root_x, root_y, win_x, win_y;
00461 uint keybstate;
00462 Window rootw, childw;
00463 XQueryPointer( qt_xdisplay(), qt_xrootwin(), &rootw, &childw,
00464 &root_x, &root_y, &win_x, &win_y, &keybstate );
00465
00466 if ( keybstate & ControlMask ) {
00467 action = DRAG_COPY;
00468 } else if ( keybstate & ShiftMask ) {
00469 action = DRAG_MOVE;
00470 } else {
00471 KPopupMenu *menu = new KPopupMenu( this );
00472 if ( existingEvent || existingTodo ) {
00473 menu->insertItem( i18n("Move"), DRAG_MOVE, 0 );
00474 if (existingEvent)
00475 menu->insertItem( KOGlobals::self()->smallIcon("editcopy"), i18n("Copy"), DRAG_COPY, 1 );
00476 } else {
00477 menu->insertItem( i18n("Add"), DRAG_MOVE, 0 );
00478 }
00479 menu->insertSeparator();
00480 menu->insertItem( KOGlobals::self()->smallIcon("cancel"), i18n("Cancel"), DRAG_CANCEL, 3 );
00481 action = menu->exec( QCursor::pos(), 0 );
00482 }
00483
00484 if ( action == DRAG_COPY || action == DRAG_MOVE ) {
00485
00486
00487 if ( action == DRAG_COPY ) {
00488 if ( todo ) todo->recreate();
00489 if ( event ) event->recreate();
00490 } else {
00491 if ( existingEvent ) oldEvent = existingEvent->clone();
00492 if ( event ) delete event;
00493 event = existingEvent;
00494 if ( existingTodo ) oldTodo = existingTodo->clone();
00495 if ( todo ) delete todo;
00496 todo = existingTodo;
00497 }
00498
00499 e->accept();
00500 if ( event ) {
00501
00502 QDateTime start = event->dtStart();
00503 QDateTime end = event->dtEnd();
00504 int duration = start.daysTo( end );
00505 int idx = getDayIndexFrom( e->pos().x(), e->pos().y() );
00506
00507 start.setDate( mDays[idx] );
00508 end.setDate( mDays[idx].addDays( duration ) );
00509
00510 event->setDtStart( start );
00511 event->setDtEnd( end );
00512
00513 if ( action != DRAG_MOVE ) {
00514 if ( !mCalendar->addEvent( event ) ) {
00515 KODialogManager::errorSaveEvent( this );
00516 return;
00517 }
00518 }
00519
00520 if ( oldEvent ) {
00521 emit incidenceDroppedMove( oldEvent, event );
00522 } else {
00523 emit incidenceDropped( event );
00524 }
00525 }
00526 if ( todo ) {
00527
00528 QDateTime due = todo->dtDue();
00529 int idx = getDayIndexFrom( e->pos().x(), e->pos().y() );
00530 due.setDate( mDays[idx] );
00531
00532 todo->setDtDue( due );
00533 todo->setHasDueDate( true );
00534
00535
00536 if ( action != DRAG_MOVE ) {
00537 if ( !mCalendar->addTodo( todo ) ) {
00538 KODialogManager::errorSaveTodo( this );
00539 }
00540 }
00541
00542 if ( oldTodo ) {
00543 emit incidenceDroppedMove( oldTodo, todo );
00544 } else {
00545 emit incidenceDropped( todo );
00546 }
00547 }
00548 } else {
00549 if ( todo ) delete todo;
00550 if ( event ) delete event;
00551 e->ignore();
00552 }
00553 #endif
00554 }
00555
00556
00557
00558
00559
00560 void KODayMatrix::paintEvent( QPaintEvent * )
00561 {
00562
00563
00564 QPainter p;
00565 QRect sz = frameRect();
00566 QPixmap pm( sz.size() );
00567 int dheight = mDaySize.height();
00568 int dwidth = mDaySize.width();
00569 int row,col;
00570 int selw, selh;
00571 bool isRTL = KOGlobals::self()->reverseLayout();
00572
00573 p.begin( &pm, this );
00574 pm.fill( mDefaultBackColor );
00575
00576
00577 p.setPen(mDefaultTextColor);
00578 p.drawRect(0, 0, sz.width()+1, sz.height()+1);
00579
00580 p.translate(1,1);
00581
00582
00583 if (mSelStart != NOSELECTION) {
00584
00585 row = mSelStart/7;
00586 col = mSelStart -row*7;
00587 QColor selcol = KOPrefs::instance()->mHighlightColor;
00588
00589 if (row == mSelEnd/7) {
00590
00591 p.fillRect(isRTL ? (7 - (mSelEnd-mSelStart+1) - col)*dwidth : col*dwidth,
00592 row*dheight, (mSelEnd-mSelStart+1)*dwidth, dheight, selcol);
00593 } else {
00594
00595 p.fillRect(isRTL ? 0 : col*dwidth, row*dheight, (7-col)*dwidth,
00596 dheight, selcol);
00597
00598 selh = mSelEnd/7-row;
00599 if (selh > 1) {
00600 p.fillRect(0, (row+1)*dheight, 7*dwidth, (selh-1)*dheight,selcol);
00601 }
00602
00603 selw = mSelEnd-7*(mSelEnd/7)+1;
00604 p.fillRect(isRTL ? (7-selw)*dwidth : 0, (row+selh)*dheight,
00605 selw*dwidth, dheight, selcol);
00606 }
00607 }
00608
00609
00610 QColor actcol = mDefaultTextColorShaded;
00611 p.setPen(actcol);
00612 QPen tmppen;
00613 for(int i = 0; i < NUMDAYS; i++) {
00614 row = i/7;
00615 col = isRTL ? 6-(i-row*7) : i-row*7;
00616
00617
00618 if ( KOGlobals::self()->calendarSystem()->day( mDays[i] ) == 1) {
00619 if (actcol == mDefaultTextColorShaded) {
00620 actcol = mDefaultTextColor;
00621 } else {
00622 actcol = mDefaultTextColorShaded;
00623 }
00624 p.setPen(actcol);
00625 }
00626
00627
00628 if (i == mSelEnd+1) {
00629 p.setPen(actcol);
00630 }
00631
00632
00633 if (mToday == i) {
00634 tmppen = p.pen();
00635 QPen mTodayPen(p.pen());
00636
00637 mTodayPen.setWidth(mTodayMarginWidth);
00638
00639 if (!mHolidays[i].isNull()) {
00640 if (actcol == mDefaultTextColor) {
00641 mTodayPen.setColor(KOPrefs::instance()->mHolidayColor);
00642 } else {
00643 mTodayPen.setColor(mHolidayColorShaded);
00644 }
00645 }
00646
00647 if (i >= mSelStart && i <= mSelEnd) {
00648 QColor grey("grey");
00649 mTodayPen.setColor(grey);
00650 }
00651 p.setPen(mTodayPen);
00652 p.drawRect(col*dwidth, row*dheight, dwidth, dheight);
00653 p.setPen(tmppen);
00654 }
00655
00656
00657 if (mEvents[i] > 0) {
00658 QFont myFont = font();
00659 myFont.setBold(true);
00660 p.setFont(myFont);
00661 }
00662
00663
00664 if (!mHolidays[i].isNull()) {
00665 if (actcol == mDefaultTextColor) {
00666 p.setPen(KOPrefs::instance()->mHolidayColor);
00667 } else {
00668 p.setPen(mHolidayColorShaded);
00669 }
00670 }
00671
00672
00673
00674 if (i >= mSelStart && i <= mSelEnd) {
00675 p.setPen(mSelectedDaysColor);
00676 }
00677
00678 p.drawText(col*dwidth, row*dheight, dwidth, dheight,
00679 Qt::AlignHCenter | Qt::AlignVCenter, mDayLabels[i]);
00680
00681
00682 if (!mHolidays[i].isNull()) {
00683 p.setPen(actcol);
00684 }
00685
00686 if (mEvents[i] > 0) {
00687 QFont myFont = font();
00688 myFont.setBold(false);
00689 p.setFont(myFont);
00690 }
00691 }
00692 p.end();
00693 bitBlt( this, 0, 0, &pm );
00694 }
00695
00696
00697
00698
00699
00700 void KODayMatrix::resizeEvent( QResizeEvent * )
00701 {
00702 QRect sz = frameRect();
00703 mDaySize.setHeight( sz.height() * 7 / NUMDAYS );
00704 mDaySize.setWidth( sz.width() / 7 );
00705 }