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 <tqevent.h>
00030 #include <tqpainter.h>
00031 #include <tqptrlist.h>
00032
00033 #include <tdeglobal.h>
00034 #include <kdebug.h>
00035 #include <tdelocale.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 <tqcursor.h>
00055 #include <tdepopupmenu.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( TQWidget * parent )
00068 : TQToolTip( parent )
00069 {
00070 mMatrix = static_cast<KODayMatrix *>( parent );
00071 }
00072
00073
00074 void DynamicTip::maybeTip( const TQPoint &pos )
00075 {
00076
00077 TQRect 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 TQRect rct( col * dwidth, row * dheight, dwidth, dheight );
00084
00085
00086
00087
00088
00089 TQString 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( TQWidget *parent, const char *name )
00103 : TQFrame( parent, name ), mCalendar( 0 ), mStartDate(), mPendingChanges( false )
00104 {
00105
00106 mDays = new TQDate[ NUMDAYS ];
00107 mDayLabels = new TQString[ 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, TQT_SIGNAL(signalResourceAdded(ResourceCalendar *)), TQT_SLOT(resourcesChanged()) );
00129 connect( calres, TQT_SIGNAL(signalResourceModified( ResourceCalendar *)), TQT_SLOT(resourcesChanged()) );
00130 connect( calres, TQT_SIGNAL(signalResourceDeleted(ResourceCalendar *)), TQT_SLOT(resourcesChanged()) );
00131 }
00132
00133 setAcceptDrops( mCalendar );
00134
00135 updateEvents();
00136 }
00137
00138 TQColor KODayMatrix::getShadedColor( const TQColor &color )
00139 {
00140 TQColor 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 TQDate &start, const TQDate &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 ] = TQString::number( KOGlobals::self()->calendarSystem()->day( mDays[i] ));
00215
00216
00217 if ( mDays[ i ].year() == TQDate::currentDate().year() &&
00218 mDays[ i ].month() == TQDate::currentDate().month() &&
00219 mDays[ i ].day() == TQDate::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 TQDate &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 TQStringList holidays = KOGlobals::self()->holiday( mDays[ i ] );
00282 TQString holiStr = TQString();
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 TQDate& 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 TQString 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 Q_UNUSED( incidence );
00348 mPendingChanges = true;
00349 }
00350
00351 void KODayMatrix::calendarIncidenceChanged(Incidence * incidence)
00352 {
00353 Q_UNUSED( incidence );
00354 mPendingChanges = true;
00355 }
00356
00357 void KODayMatrix::calendarIncidenceDeleted(Incidence * incidence)
00358 {
00359 Q_UNUSED( incidence );
00360 mPendingChanges = true;
00361 }
00362
00363 void KODayMatrix::resourcesChanged()
00364 {
00365 mPendingChanges = true;
00366 }
00367
00368
00369
00370
00371
00372
00373 void KODayMatrix::mousePressEvent( TQMouseEvent *e )
00374 {
00375 mSelStart = getDayIndexFrom(e->x(), e->y());
00376 if (mSelStart > NUMDAYS-1) mSelStart=NUMDAYS-1;
00377 mSelInit = mSelStart;
00378 }
00379
00380 void KODayMatrix::mouseReleaseEvent( TQMouseEvent *e )
00381 {
00382 int tmp = getDayIndexFrom(e->x(), e->y());
00383 if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
00384
00385 if (mSelInit > tmp) {
00386 mSelEnd = mSelInit;
00387 if (tmp != mSelStart) {
00388 mSelStart = tmp;
00389 repaint();
00390 }
00391 } else {
00392 mSelStart = mSelInit;
00393
00394
00395 if (tmp != mSelEnd) {
00396 mSelEnd = tmp;
00397 repaint();
00398 }
00399 }
00400
00401 DateList daylist;
00402 if ( mSelStart < 0 ) mSelStart = 0;
00403 for ( int i = mSelStart; i <= mSelEnd; ++i ) {
00404 daylist.append( mDays[i] );
00405 }
00406 emit selected((const DateList)daylist);
00407 }
00408
00409 void KODayMatrix::mouseMoveEvent( TQMouseEvent *e )
00410 {
00411 int tmp = getDayIndexFrom(e->x(), e->y());
00412 if (tmp > NUMDAYS-1) tmp=NUMDAYS-1;
00413
00414 if (mSelInit > tmp) {
00415 mSelEnd = mSelInit;
00416 if ( tmp != mSelStart ) {
00417 mSelStart = tmp;
00418 repaint();
00419 }
00420 } else {
00421 mSelStart = mSelInit;
00422
00423
00424 if ( tmp != mSelEnd ) {
00425 mSelEnd = tmp;
00426 repaint();
00427 }
00428 }
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438 enum {
00439 DRAG_COPY = 0,
00440 DRAG_MOVE = 1,
00441 DRAG_CANCEL = 2
00442 };
00443
00444 void KODayMatrix::dragEnterEvent( TQDragEnterEvent *e )
00445 {
00446 #ifndef KORG_NODND
00447 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00448 e->ignore();
00449 return;
00450 }
00451
00452
00453
00454
00455
00456 #endif
00457 }
00458
00459 void KODayMatrix::dragMoveEvent( TQDragMoveEvent *e )
00460 {
00461 #ifndef KORG_NODND
00462 if ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) {
00463 e->ignore();
00464 return;
00465 }
00466
00467 e->accept();
00468 #endif
00469 }
00470
00471 void KODayMatrix::dragLeaveEvent( TQDragLeaveEvent * )
00472 {
00473 #ifndef KORG_NODND
00474
00475
00476 #endif
00477 }
00478
00479 void KODayMatrix::dropEvent( TQDropEvent *e )
00480 {
00481 #ifndef KORG_NODND
00482 kdDebug(5850) << "KODayMatrix::dropEvent(e) begin" << endl;
00483
00484 if ( !mCalendar ||
00485 ( !ICalDrag::canDecode( e ) && !VCalDrag::canDecode( e ) ) ) {
00486 e->ignore();
00487 return;
00488 }
00489
00490 DndFactory factory( mCalendar );
00491 Event *event = factory.createDrop( e );
00492 Todo *todo = factory.createDropTodo( e );
00493 if ( !event && !todo ) {
00494 e->ignore();
00495 return;
00496 }
00497
00498 Todo *existingTodo = 0;
00499 Event *existingEvent = 0;
00500
00501
00502 if ( event ) existingEvent = mCalendar->event( event->uid() );
00503 if ( todo ) existingTodo = mCalendar->todo( todo->uid() );
00504
00505 int action = DRAG_CANCEL;
00506
00507 int root_x, root_y, win_x, win_y;
00508 uint keybstate;
00509 Window rootw, childw;
00510 XQueryPointer( tqt_xdisplay(), tqt_xrootwin(), &rootw, &childw,
00511 &root_x, &root_y, &win_x, &win_y, &keybstate );
00512
00513 if ( keybstate & ControlMask ) {
00514 action = DRAG_COPY;
00515 } else if ( keybstate & ShiftMask ) {
00516 action = DRAG_MOVE;
00517 } else {
00518 TDEPopupMenu *menu = new TDEPopupMenu( this );
00519 if ( existingEvent || existingTodo ) {
00520 menu->insertItem( i18n("Move"), DRAG_MOVE, 0 );
00521 if (existingEvent)
00522 menu->insertItem( KOGlobals::self()->smallIcon("edit-copy"), i18n("Copy"), DRAG_COPY, 1 );
00523 } else {
00524 menu->insertItem( i18n("Add"), DRAG_MOVE, 0 );
00525 }
00526 menu->insertSeparator();
00527 menu->insertItem( KOGlobals::self()->smallIcon("cancel"), i18n("Cancel"), DRAG_CANCEL, 3 );
00528 action = menu->exec( TQCursor::pos(), 0 );
00529 }
00530
00531 if ( action == DRAG_COPY || action == DRAG_MOVE ) {
00532 e->accept();
00533 int idx = getDayIndexFrom( e->pos().x(), e->pos().y() );
00534
00535 if ( action == DRAG_COPY ) {
00536 if ( event ) emit incidenceDropped( event, mDays[idx] );
00537 if ( todo ) emit incidenceDropped( todo, mDays[idx] );
00538 } else if ( action == DRAG_MOVE ) {
00539 if ( event ) emit incidenceDroppedMove( event, mDays[idx] );
00540 if ( todo ) emit incidenceDroppedMove( todo, mDays[idx] );
00541 }
00542 }
00543 delete event;
00544 delete todo;
00545 #endif
00546 }
00547
00548
00549
00550
00551
00552 void KODayMatrix::paintEvent( TQPaintEvent * )
00553 {
00554
00555
00556 TQPainter p;
00557 TQRect sz = frameRect();
00558 TQPixmap pm( sz.size() );
00559 int dheight = mDaySize.height();
00560 int dwidth = mDaySize.width();
00561 int row,col;
00562 int selw, selh;
00563 bool isRTL = KOGlobals::self()->reverseLayout();
00564
00565 TQColorGroup cg = palette().active();
00566
00567 p.begin( &pm, this );
00568 pm.fill( cg.base() );
00569
00570
00571 p.setPen( cg.mid() );
00572 p.drawRect(0, 0, sz.width()-1, sz.height()-1);
00573
00574 p.translate(1,1);
00575
00576
00577 if (mSelStart != NOSELECTION) {
00578
00579 row = mSelStart/7;
00580
00581 if ( row < 0 && mSelEnd > 0 ) row = 0;
00582 col = mSelStart -row*7;
00583 TQColor selcol = KOPrefs::instance()->mHighlightColor;
00584
00585 if ( row < 6 && row >= 0 ) {
00586 if (row == mSelEnd/7) {
00587
00588 p.fillRect(isRTL ? (7 - (mSelEnd-mSelStart+1) - col)*dwidth : col*dwidth,
00589 row*dheight, (mSelEnd-mSelStart+1)*dwidth, dheight, selcol);
00590 } else {
00591
00592 p.fillRect(isRTL ? 0 : col*dwidth, row*dheight, (7-col)*dwidth,
00593 dheight, selcol);
00594
00595 selh = mSelEnd/7-row;
00596 if ( selh + row >= 6 ) selh = 6-row;
00597 if ( selh > 1 ) {
00598 p.fillRect(0, (row+1)*dheight, 7*dwidth, (selh-1)*dheight,selcol);
00599 }
00600
00601 if ( mSelEnd/7 < 6 ) {
00602 selw = mSelEnd-7*(mSelEnd/7)+1;
00603 p.fillRect(isRTL ? (7-selw)*dwidth : 0, (row+selh)*dheight,
00604 selw*dwidth, dheight, selcol);
00605 }
00606 }
00607 }
00608 }
00609
00610
00611 TQColor textColor = cg.text();
00612 TQColor textColorShaded = getShadedColor( textColor );
00613 TQColor actcol = textColorShaded;
00614 p.setPen(actcol);
00615 TQPen tmppen;
00616 for ( int i = 0; i < NUMDAYS; ++i ) {
00617 row = i/7;
00618 col = isRTL ? 6-(i-row*7) : i-row*7;
00619
00620
00621 if ( KOGlobals::self()->calendarSystem()->day( mDays[i] ) == 1) {
00622 if (actcol == textColorShaded) {
00623 actcol = textColor;
00624 } else {
00625 actcol = textColorShaded;
00626 }
00627 p.setPen(actcol);
00628 }
00629
00630
00631 if (i == mSelEnd+1) {
00632 p.setPen(actcol);
00633 }
00634
00635 bool holiday = ! KOGlobals::self()->isWorkDay( mDays[ i ] );
00636
00637 TQColor holidayColorShaded = getShadedColor( KOPrefs::instance()->mHolidayColor );
00638
00639 if (mToday == i) {
00640 tmppen = p.pen();
00641 TQPen mTodayPen(p.pen());
00642
00643 mTodayPen.setWidth(mTodayMarginWidth);
00644
00645 if (holiday) {
00646 if (actcol == textColor) {
00647 mTodayPen.setColor(KOPrefs::instance()->mHolidayColor);
00648 } else {
00649 mTodayPen.setColor(holidayColorShaded);
00650 }
00651 }
00652
00653 if (i >= mSelStart && i <= mSelEnd) {
00654 TQColor grey("grey");
00655 mTodayPen.setColor(grey);
00656 }
00657 p.setPen(mTodayPen);
00658 p.drawRect(col*dwidth, row*dheight, dwidth, dheight);
00659 p.setPen(tmppen);
00660 }
00661
00662
00663 if (mEvents[i] > 0) {
00664 TQFont myFont = font();
00665 myFont.setBold(true);
00666 p.setFont(myFont);
00667 }
00668
00669
00670 if (holiday) {
00671 if (actcol == textColor) {
00672 p.setPen(KOPrefs::instance()->mHolidayColor);
00673 } else {
00674 p.setPen(holidayColorShaded);
00675 }
00676 }
00677
00678
00679 if ( i >= mSelStart && i <= mSelEnd && !holiday ) {
00680 p.setPen( TQColor( "white" ) );
00681 }
00682
00683 p.drawText(col*dwidth, row*dheight, dwidth, dheight,
00684 TQt::AlignHCenter | TQt::AlignVCenter, mDayLabels[i]);
00685
00686
00687 if ( holiday ) {
00688 p.setPen(actcol);
00689 }
00690
00691 if (mEvents[i] > 0) {
00692 TQFont myFont = font();
00693 myFont.setBold(false);
00694 p.setFont(myFont);
00695 }
00696 }
00697 p.end();
00698 bitBlt( this, 0, 0, &pm );
00699 }
00700
00701
00702
00703
00704
00705 void KODayMatrix::resizeEvent( TQResizeEvent * )
00706 {
00707 TQRect sz = frameRect();
00708 mDaySize.setHeight( sz.height() * 7 / NUMDAYS );
00709 mDaySize.setWidth( sz.width() / 7 );
00710 }
00711
00712
00713 TQPair<TQDate,TQDate> KODayMatrix::matrixLimits( const TQDate &month )
00714 {
00715 const KCalendarSystem *calSys = KOGlobals::self()->calendarSystem();
00716 TQDate d = month;
00717 calSys->setYMD( d, calSys->year( month ), calSys->month( month ), 1 );
00718
00719 const int dayOfWeek = calSys->dayOfWeek( d );
00720 const int weekstart = TDEGlobal::locale()->weekStartDay();
00721
00722 d = d.addDays( weekstart - dayOfWeek );
00723
00724 if ( dayOfWeek == weekstart ) {
00725 d = d.addDays( -7 );
00726 }
00727
00728 return tqMakePair( d, d.addDays( NUMDAYS-1 ) );
00729 }