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