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 #endif
00062
00063
00064
00065
00066
00067 DynamicTip::DynamicTip( QWidget * parent )
00068 : QToolTip( parent )
00069 {
00070 mMatrix = static_cast<KODayMatrix *>( parent );
00071 }
00072
00073
00074 void DynamicTip::maybeTip( const QPoint &pos )
00075 {
00076
00077 QRect sz = mMatrix->frameRect();
00078 int dheight = sz.height() * 7 / 42;
00079 int dwidth = sz.width() / 7;
00080 int row = pos.y() / dheight;
00081 int col = pos.x() / dwidth;
00082
00083 QRect rct( col * dwidth, row * dheight, dwidth, dheight );
00084
00085
00086
00087
00088
00089 QString str = mMatrix->getHolidayLabel( col + row * 7 );
00090 if ( str.isEmpty() ) return;
00091 tip( rct, str );
00092 }
00093
00094
00095
00096
00097
00098
00099 const int KODayMatrix::NOSELECTION = -1000;
00100 const int KODayMatrix::NUMDAYS = 42;
00101
00102 KODayMatrix::KODayMatrix( QWidget *parent, QDate date, const char *name )
00103 : QFrame( parent, name ), mCalendar( 0 )
00104 {
00105
00106 days = new QDate[ NUMDAYS ];
00107 daylbls = new QString[ NUMDAYS ];
00108 mEvents = new int[ NUMDAYS ];
00109 mToolTip = new DynamicTip( this );
00110
00111
00112 mDefaultBackColor = palette().active().base();
00113 mDefaultTextColor = palette().active().foreground();
00114 mDefaultTextColorShaded = getShadedColor( mDefaultTextColor );
00115 mHolidayColorShaded = getShadedColor( KOPrefs::instance()->mHolidayColor );
00116 mSelectedDaysColor = QColor( "white" );
00117 mTodayMarginWidth = 2;
00118 mSelEnd = mSelStart = NOSELECTION;
00119
00120 updateView( date );
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 [] days;
00149 delete [] daylbls;
00150 delete [] mEvents;
00151 delete mToolTip;
00152 }
00153
00154
00155
00156
00157
00158
00159
00160
00161 void KODayMatrix::addSelectedDaysTo( DateList &selDays )
00162 {
00163 kdDebug(5850) << "KODayMatrix::addSelectedDaysTo() - " << "mSelStart:" << mSelStart << endl;
00164
00165 if ( mSelStart == NOSELECTION ) {
00166 return;
00167 }
00168
00169
00170 int i0 = mSelStart;
00171 if ( i0 < 0 ) {
00172 for ( int i = i0; i < 0; i++ ) {
00173 selDays.append( days[ 0 ].addDays( i ) );
00174 }
00175 i0 = 0;
00176 }
00177
00178
00179 if ( mSelEnd > NUMDAYS-1 ) {
00180 for ( int i = i0; i <= NUMDAYS - 1; i++ ) {
00181 selDays.append( days[ i ] );
00182 }
00183 for ( int i = NUMDAYS; i < mSelEnd; i++ ) {
00184 selDays.append( days[ 0 ].addDays( i ) );
00185 }
00186 } else {
00187
00188 for ( int i = i0; i <= mSelEnd; i++ ) {
00189 selDays.append( days[ i ] );
00190 }
00191 }
00192 }
00193
00194 void KODayMatrix::setSelectedDaysFrom( const QDate &start, const QDate &end )
00195 {
00196 mSelStart = startdate.daysTo( start );
00197 mSelEnd = startdate.daysTo( end );
00198 }
00199
00200
00201 void KODayMatrix::recalculateToday()
00202 {
00203 today = -1;
00204 for ( int i = 0; i < NUMDAYS; i++ ) {
00205 days[ i ] = startdate.addDays( i );
00206 daylbls[ i ] = QString::number( KOGlobals::self()->calendarSystem()->day( days[i] ));
00207
00208
00209 if ( days[ i ].year() == QDate::currentDate().year() &&
00210 days[ i ].month() == QDate::currentDate().month() &&
00211 days[ i ].day() == QDate::currentDate().day() ) {
00212 today = i;
00213 }
00214 }
00215
00216 }
00217
00218 void KODayMatrix::updateView()
00219 {
00220 updateView( startdate );
00221 }
00222
00223 void KODayMatrix::updateView( QDate actdate )
00224 {
00225
00226
00227
00228 bool daychanged = false;
00229
00230
00231
00232 if ( actdate != startdate ) {
00233
00234 if ( mSelStart != NOSELECTION ) {
00235 int tmp = actdate.daysTo( startdate );
00236
00237
00238
00239 if ( mSelStart + tmp < NUMDAYS && mSelEnd + tmp >= 0 ) {
00240
00241
00242 if( mSelStart > NUMDAYS || mSelStart < 0 )
00243 mSelStart = mSelStart + tmp;
00244 if( mSelEnd > NUMDAYS || mSelEnd < 0 )
00245 mSelEnd = mSelEnd + tmp;
00246 }
00247 }
00248
00249 startdate = actdate;
00250 daychanged = true;
00251 }
00252
00253 if ( daychanged ) {
00254 recalculateToday();
00255 }
00256
00257 updateEvents();
00258 for( int i = 0; i < NUMDAYS; i++ ) {
00259
00260 #ifndef KORG_NOPLUGINS
00261 QString holiStr = KOCore::self()->holiday( days[ i ] );
00262 #else
00263 QString holiStr = QString::null;
00264 #endif
00265 if ( ( KOGlobals::self()->calendarSystem()->dayOfWeek( days[ i ] ) ==
00266 KOGlobals::self()->calendarSystem()->weekDayOfPray() ) ||
00267 !holiStr.isEmpty() ) {
00268 if ( holiStr.isNull() ) holiStr = "";
00269 mHolidays[ i ] = holiStr;
00270 } else {
00271 mHolidays[ i ] = QString::null;
00272 }
00273 }
00274 }
00275
00276 void KODayMatrix::updateEvents()
00277 {
00278 if ( !mCalendar ) return;
00279
00280 for( int i = 0; i < NUMDAYS; i++ ) {
00281
00282 Event::List eventlist = mCalendar->events( days[ i ] );
00283 int numEvents = eventlist.count();
00284 Event::List::ConstIterator it;
00285 for( it = eventlist.begin(); it != eventlist.end(); ++it ) {
00286 Event *event = *it;
00287 ushort recurType = event->doesRecur();
00288
00289 if ( ( recurType == Recurrence::rDaily &&
00290 !KOPrefs::instance()->mDailyRecur ) ||
00291 ( recurType == Recurrence::rWeekly &&
00292 !KOPrefs::instance()->mWeeklyRecur ) ) {
00293 numEvents--;
00294 }
00295 }
00296 mEvents[ i ] = numEvents;
00297 }
00298 }
00299
00300 const QDate& KODayMatrix::getDate( int offset )
00301 {
00302 if ( offset < 0 || offset > NUMDAYS - 1 ) {
00303 kdDebug(5850) << "Wrong offset (" << offset << ") in KODayMatrix::getDate(int)" << endl;
00304 return days[ 0 ];
00305 }
00306 return days[ offset ];
00307 }
00308
00309 QString KODayMatrix::getHolidayLabel( int offset )
00310 {
00311 if ( offset < 0 || offset > NUMDAYS - 1 ) {
00312 kdDebug(5850) << "Wrong offset (" << offset << ") in KODayMatrix::getHolidayLabel(int)" << endl;
00313 return 0;
00314 }
00315 return mHolidays[ offset ];
00316 }
00317
00318 int KODayMatrix::getDayIndexFrom( int x, int y )
00319 {
00320 return 7 * ( y / daysize.height() ) +
00321 ( KOGlobals::self()->reverseLayout() ?
00322 6 - x / daysize.width() : x / daysize.width() );
00323 }
00324
00325
00326
00327
00328
00329 void KODayMatrix::mousePressEvent( QMouseEvent *e )
00330 {
00331 mSelStart = getDayIndexFrom(e->x(), e->y());
00332 if (mSelStart > NUMDAYS-1) mSelStart=NUMDAYS-1;
00333 mSelInit = mSelStart;
00334 }
00335
00336 void KODayMatrix::mouseReleaseEvent( QMouseEvent *e )
00337 {
00338 int tmp = getDayIndexFrom(e->x(), e->y());
00339 if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
00340
00341 if (mSelInit > tmp) {
00342 mSelEnd = mSelInit;
00343 if (tmp != mSelStart) {
00344 mSelStart = tmp;
00345 repaint();
00346 }
00347 } else {
00348 mSelStart = mSelInit;
00349
00350
00351 if (tmp != mSelEnd) {
00352 mSelEnd = tmp;
00353 repaint();
00354 }
00355 }
00356
00357 DateList daylist;
00358 if ( mSelStart < 0 ) mSelStart = 0;
00359 for (int i = mSelStart; i <= mSelEnd; i++) {
00360 daylist.append(days[i]);
00361 }
00362 emit selected((const DateList)daylist);
00363 }
00364
00365 void KODayMatrix::mouseMoveEvent( QMouseEvent *e )
00366 {
00367 int tmp = getDayIndexFrom(e->x(), e->y());
00368 if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
00369
00370 if (mSelInit > tmp) {
00371 mSelEnd = mSelInit;
00372 if (tmp != mSelStart) {
00373 mSelStart = tmp;
00374 repaint();
00375 }
00376 } else {
00377 mSelStart = mSelInit;
00378
00379
00380 if (tmp != mSelEnd) {
00381 mSelEnd = tmp;
00382 repaint();
00383 }
00384 }
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394 enum {
00395 DRAG_COPY = 0,
00396 DRAG_MOVE = 1,
00397 DRAG_CANCEL = 2
00398 };
00399
00400 void KODayMatrix::dragEnterEvent( QDragEnterEvent *e )
00401 {
00402 #ifndef KORG_NODND
00403 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00404 e->ignore();
00405 return;
00406 }
00407
00408
00409
00410
00411
00412 #endif
00413 }
00414
00415 void KODayMatrix::dragMoveEvent( QDragMoveEvent *e )
00416 {
00417 #ifndef KORG_NODND
00418 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00419 e->ignore();
00420 return;
00421 }
00422
00423 e->accept();
00424 #endif
00425 }
00426
00427 void KODayMatrix::dragLeaveEvent( QDragLeaveEvent * )
00428 {
00429 #ifndef KORG_NODND
00430
00431
00432 #endif
00433 }
00434
00435 void KODayMatrix::dropEvent( QDropEvent *e )
00436 {
00437 #ifndef KORG_NODND
00438 kdDebug(5850) << "KODayMatrix::dropEvent(e) begin" << endl;
00439
00440 if ( !mCalendar ||
00441 ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) ) {
00442 e->ignore();
00443 return;
00444 }
00445
00446 DndFactory factory( mCalendar );
00447 Event *event = factory.createDrop( e );
00448 Todo *todo = factory.createDropTodo( e );
00449 if ( !event && !todo ) {
00450 e->ignore();
00451 return;
00452 }
00453
00454 Todo *existingTodo = 0, *oldTodo = 0;
00455 Event *existingEvent = 0, *oldEvent = 0;
00456
00457
00458 if ( event ) existingEvent = mCalendar->event( event->uid() );
00459 if ( todo ) existingTodo = mCalendar->todo( todo->uid() );
00460
00461 int action = DRAG_CANCEL;
00462
00463 int root_x, root_y, win_x, win_y;
00464 uint keybstate;
00465 Window rootw, childw;
00466 XQueryPointer( qt_xdisplay(), qt_xrootwin(), &rootw, &childw,
00467 &root_x, &root_y, &win_x, &win_y, &keybstate );
00468
00469 if ( keybstate & ControlMask ) {
00470 action = DRAG_COPY;
00471 } else if ( keybstate & ShiftMask ) {
00472 action = DRAG_MOVE;
00473 } else {
00474 KPopupMenu *menu = new KPopupMenu( this );
00475 if ( existingEvent || existingTodo ) {
00476 menu->insertItem( i18n("Move"), DRAG_MOVE, 0 );
00477 if (existingEvent)
00478 menu->insertItem( KOGlobals::self()->smallIcon("editcopy"), i18n("Copy"), DRAG_COPY, 1 );
00479 } else {
00480 menu->insertItem( i18n("Add"), DRAG_MOVE, 0 );
00481 }
00482 menu->insertSeparator();
00483 menu->insertItem( KOGlobals::self()->smallIcon("cancel"), i18n("Cancel"), DRAG_CANCEL, 3 );
00484 action = menu->exec( QCursor::pos(), 0 );
00485 }
00486
00487
00488 if ( action == DRAG_COPY ) {
00489 if ( todo ) todo->recreate();
00490 if ( event ) event->recreate();
00491 } else {
00492 if ( existingEvent ) oldEvent = existingEvent->clone();
00493 if ( event ) delete event;
00494 event = existingEvent;
00495 if ( existingTodo ) oldTodo = existingTodo->clone();
00496 if ( todo ) delete todo;
00497 todo = existingTodo;
00498 }
00499
00500 if ( action == DRAG_COPY || action == DRAG_MOVE ) {
00501 e->accept();
00502 if ( event ) {
00503
00504 QDateTime start = event->dtStart();
00505 QDateTime end = event->dtEnd();
00506 int duration = start.daysTo( end );
00507 int idx = getDayIndexFrom( e->pos().x(), e->pos().y() );
00508
00509 start.setDate( days[idx] );
00510 end.setDate( days[idx].addDays( duration ) );
00511
00512 event->setDtStart( start );
00513 event->setDtEnd( end );
00514
00515 if ( action != DRAG_MOVE ) {
00516 if ( !mCalendar->addEvent( event ) ) {
00517 KODialogManager::errorSaveEvent( this );
00518 return;
00519 }
00520 }
00521
00522 if ( oldEvent ) {
00523 emit eventDroppedMove( oldEvent, event );
00524 } else {
00525 emit eventDropped( event );
00526 }
00527 }
00528 if ( todo ) {
00529
00530 QDateTime due = todo->dtDue();
00531 int idx = getDayIndexFrom( e->pos().x(), e->pos().y() );
00532 due.setDate( days[idx] );
00533
00534 todo->setDtDue( due );
00535 todo->setHasDueDate( true );
00536
00537
00538 if ( action != DRAG_MOVE ) {
00539 if ( !mCalendar->addTodo( todo ) ) {
00540 KODialogManager::errorSaveTodo( this );
00541 }
00542 }
00543
00544 if ( oldTodo ) {
00545 emit todoDroppedMove( oldTodo, todo );
00546 } else {
00547 emit todoDropped( todo );
00548 }
00549 }
00550 } else {
00551 if ( todo ) delete todo;
00552 if ( event ) delete event;
00553 e->ignore();
00554 }
00555 #endif
00556 }
00557
00558
00559
00560
00561
00562 void KODayMatrix::paintEvent( QPaintEvent *pevent )
00563 {
00564
00565
00566 QPainter p(this);
00567
00568 QRect sz = frameRect();
00569 int dheight = daysize.height();
00570 int dwidth = daysize.width();
00571 int row,col;
00572 int selw, selh;
00573 bool isRTL = KOGlobals::self()->reverseLayout();
00574
00575
00576 p.fillRect(pevent->rect(), mDefaultBackColor);
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( days[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 (today == 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, daylbls[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 }
00693
00694
00695
00696
00697
00698 void KODayMatrix::resizeEvent( QResizeEvent * )
00699 {
00700 QRect sz = frameRect();
00701 daysize.setHeight( sz.height() * 7 / NUMDAYS );
00702 daysize.setWidth( sz.width() / 7 );
00703 }