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