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