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