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