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 #include <assert.h>
00028
00029 #include <qintdict.h>
00030 #include <qdatetime.h>
00031 #include <qapplication.h>
00032 #include <qpopupmenu.h>
00033 #include <qcursor.h>
00034 #include <qpainter.h>
00035 #include <qlabel.h>
00036
00037 #include <kdebug.h>
00038 #include <klocale.h>
00039 #include <kiconloader.h>
00040 #include <kglobal.h>
00041 #include <kmessagebox.h>
00042
00043 #include "koagendaitem.h"
00044 #include "koprefs.h"
00045 #include "koglobals.h"
00046 #include "komessagebox.h"
00047 #include "incidencechanger.h"
00048 #include "kohelper.h"
00049
00050 #include "koagenda.h"
00051 #include "koagenda.moc"
00052 #include <korganizer/baseview.h>
00053
00054 #include <libkcal/event.h>
00055 #include <libkcal/todo.h>
00056 #include <libkcal/dndfactory.h>
00057 #include <libkcal/icaldrag.h>
00058 #include <libkcal/vcaldrag.h>
00059 #include <libkcal/calendar.h>
00060 #include <libkcal/calendarresources.h>
00061 #include <math.h>
00062
00064 MarcusBains::MarcusBains(KOAgenda *_agenda,const char *name)
00065 : QFrame(_agenda->viewport(),name), agenda(_agenda)
00066 {
00067 setLineWidth(0);
00068 setMargin(0);
00069 setBackgroundColor(Qt::red);
00070 minutes = new QTimer(this);
00071 connect(minutes, SIGNAL(timeout()), this, SLOT(updateLocation()));
00072 minutes->start(0, true);
00073
00074 mTimeBox = new QLabel(this);
00075 mTimeBox->setAlignment(Qt::AlignRight | Qt::AlignBottom);
00076 QPalette pal = mTimeBox->palette();
00077 pal.setColor(QColorGroup::Foreground, Qt::red);
00078 mTimeBox->setPalette(pal);
00079 mTimeBox->setAutoMask(true);
00080
00081 agenda->addChild(mTimeBox);
00082
00083 mOldTime = QTime( 0, 0 );
00084 mOldToday = -1;
00085 }
00086
00087 MarcusBains::~MarcusBains()
00088 {
00089 delete minutes;
00090 }
00091
00092 int MarcusBains::todayColumn()
00093 {
00094 QDate currentDate = QDate::currentDate();
00095
00096 DateList dateList = agenda->dateList();
00097 DateList::ConstIterator it;
00098 int col = 0;
00099 for(it = dateList.begin(); it != dateList.end(); ++it) {
00100 if((*it) == currentDate)
00101 return KOGlobals::self()->reverseLayout() ?
00102 agenda->columns() - 1 - col : col;
00103 ++col;
00104 }
00105
00106 return -1;
00107 }
00108
00109 void MarcusBains::updateLocation()
00110 {
00111 updateLocationRecalc();
00112 }
00113
00114 void MarcusBains::updateLocationRecalc( bool recalculate )
00115 {
00116 QTime tim = QTime::currentTime();
00117 if((tim.hour() == 0) && (mOldTime.hour()==23))
00118 recalculate = true;
00119
00120 int mins = tim.hour()*60 + tim.minute();
00121 int minutesPerCell = 24 * 60 / agenda->rows();
00122 int y = int( mins * agenda->gridSpacingY() / minutesPerCell );
00123 int today = recalculate ? todayColumn() : mOldToday;
00124 int x = int( agenda->gridSpacingX() * today );
00125
00126 mOldTime = tim;
00127 mOldToday = today;
00128
00129 bool hideIt = !( KOPrefs::instance()->mMarcusBainsEnabled );
00130
00131 if ( !isHidden() && ( hideIt || ( today < 0 ) ) ) {
00132 hide();
00133 mTimeBox->hide();
00134 return;
00135 }
00136
00137 if ( isHidden() && !hideIt ) {
00138 show();
00139 mTimeBox->show();
00140 }
00141
00142 if ( recalculate ) setFixedSize( int( agenda->gridSpacingX() ), 1 );
00143 agenda->moveChild( this, x, y );
00144 raise();
00145
00146 if(recalculate)
00147 mTimeBox->setFont(KOPrefs::instance()->mMarcusBainsFont);
00148
00149 QString timeStr = KGlobal::locale()->formatTime(tim, KOPrefs::instance()->mMarcusBainsShowSeconds);
00150 QFontMetrics fm = fontMetrics();
00151 mTimeBox->setText( timeStr );
00152 QSize sz( fm.width( timeStr + ' ' ), fm.height() );
00153 mTimeBox->setFixedSize( sz );
00154
00155 if (y-mTimeBox->height()>=0) y-=mTimeBox->height(); else y++;
00156 if (x-mTimeBox->width()+agenda->gridSpacingX() > 0)
00157 x += int( agenda->gridSpacingX() - mTimeBox->width() - 1 );
00158 else x++;
00159 agenda->moveChild(mTimeBox,x,y);
00160 mTimeBox->raise();
00161 mTimeBox->setAutoMask(true);
00162
00163 minutes->start(1000,true);
00164 }
00165
00166
00168
00169
00170
00171
00172
00173 KOAgenda::KOAgenda( int columns, int rows, int rowSize, QWidget *parent,
00174 const char *name, WFlags f )
00175 : QScrollView( parent, name, f ), mChanger( 0 )
00176 {
00177 mColumns = columns;
00178 mRows = rows;
00179 mGridSpacingY = rowSize;
00180 if ( mGridSpacingY < 4 || mGridSpacingY > 30 ) {
00181 mGridSpacingY = 10;
00182 }
00183
00184 mAllDayMode = false;
00185
00186 init();
00187
00188 viewport()->setMouseTracking(true);
00189 }
00190
00191
00192
00193
00194
00195 KOAgenda::KOAgenda( int columns, QWidget *parent, const char *name, WFlags f )
00196 : QScrollView( parent, name, f )
00197 {
00198 mColumns = columns;
00199 mRows = 1;
00200 mGridSpacingY = 24;
00201 mAllDayMode = true;
00202 setVScrollBarMode( AlwaysOff );
00203
00204 init();
00205 }
00206
00207
00208 KOAgenda::~KOAgenda()
00209 {
00210 delete mMarcusBains;
00211 }
00212
00213
00214 Incidence *KOAgenda::selectedIncidence() const
00215 {
00216 return ( mSelectedItem ? mSelectedItem->incidence() : 0 );
00217 }
00218
00219
00220 QDate KOAgenda::selectedIncidenceDate() const
00221 {
00222 return ( mSelectedItem ? mSelectedItem->itemDate() : QDate() );
00223 }
00224
00225 const QString KOAgenda::lastSelectedUid() const
00226 {
00227 return mSelectedUid;
00228 }
00229
00230
00231 void KOAgenda::init()
00232 {
00233 mGridSpacingX = 100;
00234 mDesiredGridSpacingY = KOPrefs::instance()->mHourSize;
00235 if ( mDesiredGridSpacingY < 4 || mDesiredGridSpacingY > 30 ) {
00236 mDesiredGridSpacingY = 10;
00237 }
00238
00239
00240 mGridSpacingY = (double)height() / (double)mRows;
00241 if ( mGridSpacingY < mDesiredGridSpacingY ) {
00242 mGridSpacingY = mDesiredGridSpacingY;
00243 }
00244
00245 mResizeBorderWidth = 8;
00246 mScrollBorderWidth = 8;
00247 mScrollDelay = 30;
00248 mScrollOffset = 10;
00249
00250 enableClipper( true );
00251
00252
00253
00254 setFocusPolicy( WheelFocus );
00255
00256 connect( &mScrollUpTimer, SIGNAL( timeout() ), SLOT( scrollUp() ) );
00257 connect( &mScrollDownTimer, SIGNAL( timeout() ), SLOT( scrollDown() ) );
00258
00259 mStartCell = QPoint( 0, 0 );
00260 mEndCell = QPoint( 0, 0 );
00261
00262 mHasSelection = false;
00263 mSelectionStartPoint = QPoint( 0, 0 );
00264 mSelectionStartCell = QPoint( 0, 0 );
00265 mSelectionEndCell = QPoint( 0, 0 );
00266
00267 mOldLowerScrollValue = -1;
00268 mOldUpperScrollValue = -1;
00269
00270 mClickedItem = 0;
00271
00272 mActionItem = 0;
00273 mActionType = NOP;
00274 mItemMoved = false;
00275
00276 mSelectedItem = 0;
00277 mSelectedUid = QString::null;
00278
00279 setAcceptDrops( true );
00280 installEventFilter( this );
00281 mItems.setAutoDelete( true );
00282 mItemsToDelete.setAutoDelete( true );
00283
00284 resizeContents( int( mGridSpacingX * mColumns ),
00285 int( mGridSpacingY * mRows ) );
00286
00287 viewport()->update();
00288 viewport()->setBackgroundMode( NoBackground );
00289 viewport()->setFocusPolicy( WheelFocus );
00290
00291 setMinimumSize( 30, int( mGridSpacingY + 1 ) );
00292
00293
00294
00295
00296
00297 setHScrollBarMode( AlwaysOff );
00298
00299 setStartTime( KOPrefs::instance()->mDayBegins.time() );
00300
00301 calculateWorkingHours();
00302
00303 connect( verticalScrollBar(), SIGNAL( valueChanged( int ) ),
00304 SLOT( checkScrollBoundaries( int ) ) );
00305
00306
00307 if( mAllDayMode ) {
00308 mMarcusBains = 0;
00309 } else {
00310 mMarcusBains = new MarcusBains( this );
00311 addChild( mMarcusBains );
00312 }
00313
00314 mTypeAhead = false;
00315 mTypeAheadReceiver = 0;
00316
00317 mReturnPressed = false;
00318 }
00319
00320
00321 void KOAgenda::clear()
00322 {
00323
00324
00325 KOAgendaItem *item;
00326 for ( item = mItems.first(); item != 0; item = mItems.next() ) {
00327 removeChild( item );
00328 }
00329 mItems.clear();
00330 mItemsToDelete.clear();
00331
00332 mSelectedItem = 0;
00333
00334 clearSelection();
00335 }
00336
00337
00338 void KOAgenda::clearSelection()
00339 {
00340 mHasSelection = false;
00341 mActionType = NOP;
00342 updateContents();
00343 }
00344
00345 void KOAgenda::marcus_bains()
00346 {
00347 if(mMarcusBains) mMarcusBains->updateLocationRecalc( true );
00348 }
00349
00350
00351 void KOAgenda::changeColumns(int columns)
00352 {
00353 if (columns == 0) {
00354 kdDebug(5850) << "KOAgenda::changeColumns() called with argument 0" << endl;
00355 return;
00356 }
00357
00358 clear();
00359 mColumns = columns;
00360
00361
00362
00363
00364 QResizeEvent event( size(), size() );
00365
00366 QApplication::sendEvent( this, &event );
00367 }
00368
00369
00370
00371
00372
00373 bool KOAgenda::eventFilter ( QObject *object, QEvent *event )
00374 {
00375
00376
00377 switch( event->type() ) {
00378 case QEvent::MouseButtonPress:
00379 case QEvent::MouseButtonDblClick:
00380 case QEvent::MouseButtonRelease:
00381 case QEvent::MouseMove:
00382 return eventFilter_mouse( object, static_cast<QMouseEvent *>( event ) );
00383 #ifndef QT_NO_WHEELEVENT
00384 case QEvent::Wheel:
00385 return eventFilter_wheel( object, static_cast<QWheelEvent *>( event ) );
00386 #endif
00387 case QEvent::KeyPress:
00388 case QEvent::KeyRelease:
00389 return eventFilter_key( object, static_cast<QKeyEvent *>( event ) );
00390
00391 case ( QEvent::Leave ):
00392 if ( !mActionItem )
00393 setCursor( arrowCursor );
00394 if ( object == viewport() )
00395 emit leaveAgenda();
00396 return true;
00397
00398 case QEvent::Enter:
00399 emit enterAgenda();
00400 return QScrollView::eventFilter( object, event );
00401
00402 #ifndef KORG_NODND
00403 case QEvent::DragEnter:
00404 case QEvent::DragMove:
00405 case QEvent::DragLeave:
00406 case QEvent::Drop:
00407
00408 return eventFilter_drag(object, static_cast<QDropEvent*>(event));
00409 #endif
00410
00411 default:
00412 return QScrollView::eventFilter( object, event );
00413 }
00414 }
00415
00416 bool KOAgenda::eventFilter_drag( QObject *object, QDropEvent *de )
00417 {
00418 #ifndef KORG_NODND
00419 QPoint viewportPos;
00420 if ( object != viewport() && object != this ) {
00421 viewportPos = static_cast<QWidget *>( object )->mapToParent( de->pos() );
00422 } else {
00423 viewportPos = de->pos();
00424 }
00425
00426 switch ( de->type() ) {
00427 case QEvent::DragEnter:
00428 case QEvent::DragMove:
00429 if ( ICalDrag::canDecode( de ) || VCalDrag::canDecode( de ) ) {
00430
00431 DndFactory factory( mCalendar );
00432 Todo *todo = factory.createDropTodo( de );
00433 if ( todo ) {
00434 de->accept();
00435 delete todo;
00436 } else {
00437 de->ignore();
00438 }
00439 return true;
00440 } else return false;
00441 break;
00442 case QEvent::DragLeave:
00443 return false;
00444 break;
00445 case QEvent::Drop:
00446 {
00447 if ( !ICalDrag::canDecode( de ) && !VCalDrag::canDecode( de ) ) {
00448 return false;
00449 }
00450
00451 DndFactory factory( mCalendar );
00452 Todo *todo = factory.createDropTodo( de );
00453
00454 if ( todo ) {
00455 de->acceptAction();
00456 QPoint pos;
00457
00458
00459
00460 if ( object == this ) {
00461 pos = viewportPos + QPoint( contentsX(), contentsY() );
00462 } else {
00463 pos = viewportToContents( viewportPos );
00464 }
00465 QPoint gpos = contentsToGrid( pos );
00466 emit droppedToDo( todo, gpos, mAllDayMode );
00467 return true;
00468 }
00469 }
00470 break;
00471
00472 case QEvent::DragResponse:
00473 default:
00474 break;
00475 }
00476 #endif
00477
00478 return false;
00479 }
00480
00481 bool KOAgenda::eventFilter_key( QObject *, QKeyEvent *ke )
00482 {
00483
00484
00485
00486 if ( ke->key() == Key_Return ) {
00487 if ( ke->type() == QEvent::KeyPress ) mReturnPressed = true;
00488 else if ( ke->type() == QEvent::KeyRelease ) {
00489 if ( mReturnPressed ) {
00490 emitNewEventForSelection();
00491 mReturnPressed = false;
00492 return true;
00493 } else {
00494 mReturnPressed = false;
00495 }
00496 }
00497 }
00498
00499
00500 if ( ke->text().isEmpty() ) return false;
00501
00502 if ( ke->type() == QEvent::KeyPress || ke->type() == QEvent::KeyRelease ) {
00503 switch ( ke->key() ) {
00504 case Key_Escape:
00505 case Key_Return:
00506 case Key_Enter:
00507 case Key_Tab:
00508 case Key_Backtab:
00509 case Key_Left:
00510 case Key_Right:
00511 case Key_Up:
00512 case Key_Down:
00513 case Key_Backspace:
00514 case Key_Delete:
00515 case Key_Prior:
00516 case Key_Next:
00517 case Key_Home:
00518 case Key_End:
00519 case Key_Control:
00520 case Key_Meta:
00521 case Key_Alt:
00522 break;
00523 default:
00524 mTypeAheadEvents.append( new QKeyEvent( ke->type(), ke->key(),
00525 ke->ascii(), ke->state(),
00526 ke->text(), ke->isAutoRepeat(),
00527 ke->count() ) );
00528 if ( !mTypeAhead ) {
00529 mTypeAhead = true;
00530 emitNewEventForSelection();
00531 }
00532 return true;
00533 }
00534 }
00535 return false;
00536 }
00537
00538 void KOAgenda::emitNewEventForSelection()
00539 {
00540 emit newEventSignal();
00541 }
00542
00543 void KOAgenda::finishTypeAhead()
00544 {
00545
00546 if ( typeAheadReceiver() ) {
00547 for( QEvent *e = mTypeAheadEvents.first(); e;
00548 e = mTypeAheadEvents.next() ) {
00549
00550 QApplication::sendEvent( typeAheadReceiver(), e );
00551 }
00552 }
00553 mTypeAheadEvents.clear();
00554 mTypeAhead = false;
00555 }
00556 #ifndef QT_NO_WHEELEVENT
00557 bool KOAgenda::eventFilter_wheel ( QObject *object, QWheelEvent *e )
00558 {
00559 QPoint viewportPos;
00560 bool accepted=false;
00561 if ( ( e->state() & ShiftButton) == ShiftButton ) {
00562 if ( object != viewport() ) {
00563 viewportPos = ( (QWidget *) object )->mapToParent( e->pos() );
00564 } else {
00565 viewportPos = e->pos();
00566 }
00567
00568
00569 emit zoomView( -e->delta() ,
00570 contentsToGrid( viewportToContents( viewportPos ) ),
00571 Qt::Horizontal );
00572 accepted=true;
00573 }
00574
00575 if ( ( e->state() & ControlButton ) == ControlButton ){
00576 if ( object != viewport() ) {
00577 viewportPos = ( (QWidget *)object )->mapToParent( e->pos() );
00578 } else {
00579 viewportPos = e->pos();
00580 }
00581 emit zoomView( -e->delta() ,
00582 contentsToGrid( viewportToContents( viewportPos ) ),
00583 Qt::Vertical );
00584 emit mousePosSignal(gridToContents(contentsToGrid(viewportToContents( viewportPos ))));
00585 accepted=true;
00586 }
00587 if (accepted ) e->accept();
00588 return accepted;
00589 }
00590 #endif
00591 bool KOAgenda::eventFilter_mouse(QObject *object, QMouseEvent *me)
00592 {
00593 QPoint viewportPos;
00594 if (object != viewport()) {
00595 viewportPos = ((QWidget *)object)->mapToParent(me->pos());
00596 } else {
00597 viewportPos = me->pos();
00598 }
00599
00600 switch (me->type()) {
00601 case QEvent::MouseButtonPress:
00602
00603 if (object != viewport()) {
00604 if (me->button() == RightButton) {
00605 mClickedItem = dynamic_cast<KOAgendaItem *>(object);
00606 if (mClickedItem) {
00607 selectItem(mClickedItem);
00608 emit showIncidencePopupSignal( mCalendar,
00609 mClickedItem->incidence(),
00610 mClickedItem->itemDate() );
00611 }
00612 } else {
00613 KOAgendaItem* item = dynamic_cast<KOAgendaItem *>(object);
00614 if (item) {
00615 Incidence *incidence = item->incidence();
00616 if ( incidence->isReadOnly() ) {
00617 mActionItem = 0;
00618 } else {
00619 mActionItem = item;
00620 startItemAction(viewportPos);
00621 }
00622
00623
00624
00625
00626 selectItem( item );
00627 }
00628 }
00629 } else {
00630 if (me->button() == RightButton)
00631 {
00632
00633 QPoint gpos = contentsToGrid( viewportToContents( viewportPos ) );
00634 if ( !ptInSelection( gpos ) ) {
00635 mSelectionStartCell = gpos;
00636 mSelectionEndCell = gpos;
00637 mHasSelection = true;
00638 emit newStartSelectSignal();
00639 emit newTimeSpanSignal( mSelectionStartCell, mSelectionEndCell );
00640 updateContents();
00641 }
00642 showNewEventPopupSignal();
00643 }
00644 else
00645 {
00646
00647 QPoint gpos = contentsToGrid( viewportToContents( viewportPos ) );
00648 if ( !ptInSelection( gpos ) ) {
00649 selectItem(0);
00650 mActionItem = 0;
00651 setCursor(arrowCursor);
00652 startSelectAction(viewportPos);
00653 }
00654 }
00655 }
00656 break;
00657
00658 case QEvent::MouseButtonRelease:
00659 if (mActionItem) {
00660 endItemAction();
00661 } else if ( mActionType == SELECT ) {
00662 endSelectAction( viewportPos );
00663 }
00664
00665
00666 emit mousePosSignal( gridToContents(contentsToGrid(
00667 viewportToContents( viewportPos ) ) ));
00668 break;
00669
00670 case QEvent::MouseMove: {
00671
00672
00673 QPoint indicatorPos = gridToContents(contentsToGrid(
00674 viewportToContents( viewportPos )));
00675 if (object != viewport()) {
00676 KOAgendaItem *moveItem = dynamic_cast<KOAgendaItem *>(object);
00677 if (moveItem && !moveItem->incidence()->isReadOnly() ) {
00678 if (!mActionItem)
00679 setNoActionCursor(moveItem,viewportPos);
00680 else {
00681 performItemAction(viewportPos);
00682
00683 if ( mActionType == MOVE ) {
00684
00685 KOAgendaItem *firstItem = mActionItem->firstMultiItem();
00686 if (!firstItem) firstItem = mActionItem;
00687 indicatorPos = gridToContents( QPoint( firstItem->cellXLeft(),
00688 firstItem->cellYTop() ) );
00689
00690 } else if ( mActionType == RESIZEBOTTOM ) {
00691
00692 indicatorPos = gridToContents( QPoint( mActionItem->cellXLeft(),
00693 mActionItem->cellYBottom()+1 ) );
00694 }
00695
00696 }
00697 }
00698 } else {
00699 if ( mActionType == SELECT ) {
00700 performSelectAction( viewportPos );
00701
00702
00703 if ( ((mStartCell.y() < mEndCell.y()) && (mEndCell.x() >= mStartCell.x())) ||
00704 (mEndCell.x() > mStartCell.x()) )
00705 indicatorPos = gridToContents( QPoint(mEndCell.x(), mEndCell.y()+1) );
00706 else
00707 indicatorPos = gridToContents( mEndCell );
00708 }
00709 }
00710 emit mousePosSignal( indicatorPos );
00711 break; }
00712
00713 case QEvent::MouseButtonDblClick:
00714 if (object == viewport()) {
00715 selectItem(0);
00716 emit newEventSignal();
00717 } else {
00718 KOAgendaItem *doubleClickedItem = dynamic_cast<KOAgendaItem *>(object);
00719 if (doubleClickedItem) {
00720 selectItem(doubleClickedItem);
00721 emit editIncidenceSignal(doubleClickedItem->incidence());
00722 }
00723 }
00724 break;
00725
00726 default:
00727 break;
00728 }
00729
00730 return true;
00731 }
00732
00733 bool KOAgenda::ptInSelection( QPoint gpos ) const
00734 {
00735 if ( !mHasSelection ) {
00736 return false;
00737 } else if ( gpos.x()<mSelectionStartCell.x() || gpos.x()>mSelectionEndCell.x() ) {
00738 return false;
00739 } else if ( (gpos.x()==mSelectionStartCell.x()) && (gpos.y()<mSelectionStartCell.y()) ) {
00740 return false;
00741 } else if ( (gpos.x()==mSelectionEndCell.x()) && (gpos.y()>mSelectionEndCell.y()) ) {
00742 return false;
00743 }
00744 return true;
00745 }
00746
00747 void KOAgenda::startSelectAction( const QPoint &viewportPos )
00748 {
00749 emit newStartSelectSignal();
00750
00751 mActionType = SELECT;
00752 mSelectionStartPoint = viewportPos;
00753 mHasSelection = true;
00754
00755 QPoint pos = viewportToContents( viewportPos );
00756 QPoint gpos = contentsToGrid( pos );
00757
00758
00759 mStartCell = gpos;
00760 mEndCell = gpos;
00761 mSelectionStartCell = gpos;
00762 mSelectionEndCell = gpos;
00763
00764 updateContents();
00765 }
00766
00767 void KOAgenda::performSelectAction(const QPoint& viewportPos)
00768 {
00769 QPoint pos = viewportToContents( viewportPos );
00770 QPoint gpos = contentsToGrid( pos );
00771
00772 QPoint clipperPos = clipper()->
00773 mapFromGlobal(viewport()->mapToGlobal(viewportPos));
00774
00775
00776 if (clipperPos.y() < mScrollBorderWidth) {
00777 mScrollUpTimer.start(mScrollDelay);
00778 } else if (visibleHeight() - clipperPos.y() <
00779 mScrollBorderWidth) {
00780 mScrollDownTimer.start(mScrollDelay);
00781 } else {
00782 mScrollUpTimer.stop();
00783 mScrollDownTimer.stop();
00784 }
00785
00786 if ( gpos != mEndCell ) {
00787 mEndCell = gpos;
00788 if ( mStartCell.x()>mEndCell.x() ||
00789 ( mStartCell.x()==mEndCell.x() && mStartCell.y()>mEndCell.y() ) ) {
00790
00791 mSelectionStartCell = mEndCell;
00792 mSelectionEndCell = mStartCell;
00793 } else {
00794 mSelectionStartCell = mStartCell;
00795 mSelectionEndCell = mEndCell;
00796 }
00797
00798 updateContents();
00799 }
00800 }
00801
00802 void KOAgenda::endSelectAction( const QPoint ¤tPos )
00803 {
00804 mScrollUpTimer.stop();
00805 mScrollDownTimer.stop();
00806
00807 mActionType = NOP;
00808
00809 emit newTimeSpanSignal( mSelectionStartCell, mSelectionEndCell );
00810
00811 if ( KOPrefs::instance()->mSelectionStartsEditor ) {
00812 if ( ( mSelectionStartPoint - currentPos ).manhattanLength() >
00813 QApplication::startDragDistance() ) {
00814 emitNewEventForSelection();
00815 }
00816 }
00817 }
00818
00819 KOAgenda::MouseActionType KOAgenda::isInResizeArea( bool horizontal,
00820 const QPoint &pos, KOAgendaItem*item )
00821 {
00822 if (!item) return NOP;
00823 QPoint gridpos = contentsToGrid( pos );
00824 QPoint contpos = gridToContents( gridpos +
00825 QPoint( (KOGlobals::self()->reverseLayout())?1:0, 0 ) );
00826
00827
00828
00829
00830 if ( horizontal ) {
00831 int clXLeft = item->cellXLeft();
00832 int clXRight = item->cellXRight();
00833 if ( KOGlobals::self()->reverseLayout() ) {
00834 int tmp = clXLeft;
00835 clXLeft = clXRight;
00836 clXRight = tmp;
00837 }
00838 int gridDistanceX = int( pos.x() - contpos.x() );
00839 if (gridDistanceX < mResizeBorderWidth && clXLeft == gridpos.x() ) {
00840 if ( KOGlobals::self()->reverseLayout() ) return RESIZERIGHT;
00841 else return RESIZELEFT;
00842 } else if ((mGridSpacingX - gridDistanceX) < mResizeBorderWidth &&
00843 clXRight == gridpos.x() ) {
00844 if ( KOGlobals::self()->reverseLayout() ) return RESIZELEFT;
00845 else return RESIZERIGHT;
00846 } else {
00847 return MOVE;
00848 }
00849 } else {
00850 int gridDistanceY = int( pos.y() - contpos.y() );
00851 if (gridDistanceY < mResizeBorderWidth &&
00852 item->cellYTop() == gridpos.y() &&
00853 !item->firstMultiItem() ) {
00854 return RESIZETOP;
00855 } else if ((mGridSpacingY - gridDistanceY) < mResizeBorderWidth &&
00856 item->cellYBottom() == gridpos.y() &&
00857 !item->lastMultiItem() ) {
00858 return RESIZEBOTTOM;
00859 } else {
00860 return MOVE;
00861 }
00862 }
00863 }
00864
00865 void KOAgenda::startItemAction(const QPoint& viewportPos)
00866 {
00867 QPoint pos = viewportToContents( viewportPos );
00868 mStartCell = contentsToGrid( pos );
00869 mEndCell = mStartCell;
00870
00871 bool noResize = ( mActionItem->incidence()->type() == "Todo");
00872
00873 mActionType = MOVE;
00874 if ( !noResize ) {
00875 mActionType = isInResizeArea( mAllDayMode, pos, mActionItem );
00876 }
00877
00878
00879 mActionItem->startMove();
00880 setActionCursor( mActionType, true );
00881 }
00882
00883 void KOAgenda::performItemAction(const QPoint& viewportPos)
00884 {
00885
00886
00887
00888
00889
00890
00891 QPoint pos = viewportToContents( viewportPos );
00892
00893 QPoint gpos = contentsToGrid( pos );
00894 QPoint clipperPos = clipper()->
00895 mapFromGlobal(viewport()->mapToGlobal(viewportPos));
00896
00897
00898
00899 if ( clipperPos.y() < 0 || clipperPos.y() > visibleHeight() ||
00900 clipperPos.x() < 0 || clipperPos.x() > visibleWidth() ) {
00901 if ( mActionType == MOVE ) {
00902 mScrollUpTimer.stop();
00903 mScrollDownTimer.stop();
00904 mActionItem->resetMove();
00905 placeSubCells( mActionItem );
00906 emit startDragSignal( mActionItem->incidence() );
00907 setCursor( arrowCursor );
00908 mActionItem = 0;
00909 mActionType = NOP;
00910 mItemMoved = false;
00911 if ( mItemMoved && mChanger )
00912 mChanger->endChange( mActionItem->incidence() );
00913 return;
00914 }
00915 } else {
00916 setActionCursor( mActionType );
00917 }
00918
00919
00920 if (clipperPos.y() < mScrollBorderWidth) {
00921 mScrollUpTimer.start(mScrollDelay);
00922 } else if (visibleHeight() - clipperPos.y() <
00923 mScrollBorderWidth) {
00924 mScrollDownTimer.start(mScrollDelay);
00925 } else {
00926 mScrollUpTimer.stop();
00927 mScrollDownTimer.stop();
00928 }
00929
00930
00931 if ( mEndCell != gpos ) {
00932 if ( !mItemMoved ) {
00933 if ( !mChanger || !mChanger->beginChange( mActionItem->incidence() ) ) {
00934 KMessageBox::information( this, i18n("Unable to lock item for "
00935 "modification. You cannot make any changes."),
00936 i18n("Locking Failed"), "AgendaLockingFailed" );
00937 mScrollUpTimer.stop();
00938 mScrollDownTimer.stop();
00939 mActionItem->resetMove();
00940 placeSubCells( mActionItem );
00941 setCursor( arrowCursor );
00942 mActionItem = 0;
00943 mActionType = NOP;
00944 mItemMoved = false;
00945 return;
00946 }
00947 mItemMoved = true;
00948 }
00949 mActionItem->raise();
00950 if (mActionType == MOVE) {
00951
00952 KOAgendaItem *firstItem = mActionItem->firstMultiItem();
00953 if (!firstItem) firstItem = mActionItem;
00954 KOAgendaItem *lastItem = mActionItem->lastMultiItem();
00955 if (!lastItem) lastItem = mActionItem;
00956 QPoint deltapos = gpos - mEndCell;
00957 KOAgendaItem *moveItem = firstItem;
00958 while (moveItem) {
00959 bool changed=false;
00960 if ( deltapos.x()!=0 ) {
00961 moveItem->moveRelative( deltapos.x(), 0 );
00962 changed=true;
00963 }
00964
00965 if ( moveItem==firstItem && !mAllDayMode ) {
00966 int newY = deltapos.y() + moveItem->cellYTop();
00967
00968 if ( newY<0 ) {
00969 moveItem->expandTop( -moveItem->cellYTop() );
00970
00971 KOAgendaItem *newFirst = firstItem->prevMoveItem();
00972
00973 if (newFirst) {
00974 newFirst->setCellXY(moveItem->cellXLeft()-1, rows()+newY, rows()-1);
00975 mItems.append( newFirst );
00976 moveItem->resize( int( mGridSpacingX * newFirst->cellWidth() ),
00977 int( mGridSpacingY * newFirst->cellHeight() ));
00978 QPoint cpos = gridToContents( QPoint( newFirst->cellXLeft(), newFirst->cellYTop() ) );
00979 addChild( newFirst, cpos.x(), cpos.y() );
00980 } else {
00981 newFirst = insertItem( moveItem->incidence(), moveItem->itemDate(),
00982 moveItem->cellXLeft()-1, rows()+newY, rows()-1 ) ;
00983 }
00984 if (newFirst) newFirst->show();
00985 moveItem->prependMoveItem(newFirst);
00986 firstItem=newFirst;
00987 } else if ( newY>=rows() ) {
00988
00989
00990 firstItem = moveItem->nextMultiItem();
00991 moveItem->hide();
00992 mItems.take( mItems.find( moveItem ) );
00993 removeChild( moveItem );
00994 mActionItem->removeMoveItem(moveItem);
00995 moveItem=firstItem;
00996
00997 if (moveItem) moveItem->expandTop( rows()-newY );
00998 } else {
00999 moveItem->expandTop(deltapos.y());
01000 }
01001 changed=true;
01002 }
01003 if ( !moveItem->lastMultiItem() && !mAllDayMode ) {
01004 int newY = deltapos.y()+moveItem->cellYBottom();
01005 if (newY<0) {
01006
01007 lastItem = moveItem->prevMultiItem();
01008 moveItem->hide();
01009 mItems.take( mItems.find(moveItem) );
01010 removeChild( moveItem );
01011 moveItem->removeMoveItem( moveItem );
01012 moveItem = lastItem;
01013 moveItem->expandBottom(newY+1);
01014 } else if (newY>=rows()) {
01015 moveItem->expandBottom( rows()-moveItem->cellYBottom()-1 );
01016
01017 KOAgendaItem *newLast = lastItem->nextMoveItem();
01018 if (newLast) {
01019 newLast->setCellXY( moveItem->cellXLeft()+1, 0, newY-rows()-1 );
01020 mItems.append(newLast);
01021 moveItem->resize( int( mGridSpacingX * newLast->cellWidth() ),
01022 int( mGridSpacingY * newLast->cellHeight() ));
01023 QPoint cpos = gridToContents( QPoint( newLast->cellXLeft(), newLast->cellYTop() ) ) ;
01024 addChild( newLast, cpos.x(), cpos.y() );
01025 } else {
01026 newLast = insertItem( moveItem->incidence(), moveItem->itemDate(),
01027 moveItem->cellXLeft()+1, 0, newY-rows()-1 ) ;
01028 }
01029 moveItem->appendMoveItem( newLast );
01030 newLast->show();
01031 lastItem = newLast;
01032 } else {
01033 moveItem->expandBottom( deltapos.y() );
01034 }
01035 changed=true;
01036 }
01037 if (changed) {
01038 adjustItemPosition( moveItem );
01039 }
01040 moveItem = moveItem->nextMultiItem();
01041 }
01042 } else if (mActionType == RESIZETOP) {
01043 if (mEndCell.y() <= mActionItem->cellYBottom()) {
01044 mActionItem->expandTop(gpos.y() - mEndCell.y());
01045 adjustItemPosition( mActionItem );
01046 }
01047 } else if (mActionType == RESIZEBOTTOM) {
01048 if (mEndCell.y() >= mActionItem->cellYTop()) {
01049 mActionItem->expandBottom(gpos.y() - mEndCell.y());
01050 adjustItemPosition( mActionItem );
01051 }
01052 } else if (mActionType == RESIZELEFT) {
01053 if (mEndCell.x() <= mActionItem->cellXRight()) {
01054 mActionItem->expandLeft( gpos.x() - mEndCell.x() );
01055 adjustItemPosition( mActionItem );
01056 }
01057 } else if (mActionType == RESIZERIGHT) {
01058 if (mEndCell.x() >= mActionItem->cellXLeft()) {
01059 mActionItem->expandRight(gpos.x() - mEndCell.x());
01060 adjustItemPosition( mActionItem );
01061 }
01062 }
01063 mEndCell = gpos;
01064 }
01065 }
01066
01067 void KOAgenda::endItemAction()
01068 {
01069
01070 mActionType = NOP;
01071 mScrollUpTimer.stop();
01072 mScrollDownTimer.stop();
01073 setCursor( arrowCursor );
01074 bool multiModify = false;
01075
01076 Incidence* inc = mActionItem->incidence();
01077
01078 if ( mItemMoved ) {
01079 bool modify = true;
01080 if ( mActionItem->incidence()->doesRecur() ) {
01081 int res = KOMessageBox::fourBtnMsgBox( this, QMessageBox::Question,
01082 i18n("The item you try to change is a recurring item. Shall the changes "
01083 "be applied only to this single occurrence, only to the future items, "
01084 "or to all items in the recurrence?"),
01085 i18n("Changing Recurring Item"),
01086 i18n("Only &This Item"), i18n("Only &Future Items"), i18n("&All Occurrences") );
01087 switch ( res ) {
01088 case KMessageBox::Ok:
01089
01090 modify = true;
01091 break;
01092 case KMessageBox::Yes: {
01093
01094
01095
01096
01097
01098
01099 modify = true;
01100 multiModify = true;
01101 emit startMultiModify( i18n("Dissociate event from recurrence") );
01102 Incidence* oldInc = mActionItem->incidence();
01103 Incidence* oldIncSaved = mActionItem->incidence()->clone();
01104 Incidence* newInc = mCalendar->dissociateOccurrence(
01105 oldInc, mActionItem->itemDate() );
01106 if ( newInc ) {
01107
01108 emit enableAgendaUpdate( false );
01109 mActionItem->dissociateFromMultiItem();
01110 mActionItem->setIncidence( newInc );
01111 mChanger->addIncidence( newInc, this );
01112 emit enableAgendaUpdate( true );
01113 mChanger->changeIncidence( oldIncSaved, oldInc,
01114 KOGlobals::RECURRENCE_MODIFIED_ONE_ONLY, this );
01115 } else {
01116 KMessageBox::sorry( this, i18n("Unable to add the exception item to the "
01117 "calendar. No change will be done."), i18n("Error Occurred") );
01118 }
01119 delete oldIncSaved;
01120 break; }
01121 case KMessageBox::No: {
01122
01123
01124
01125
01126
01127
01128 modify = true;
01129 multiModify = true;
01130 emit startMultiModify( i18n("Split future recurrences") );
01131 Incidence* oldInc = mActionItem->incidence();
01132 Incidence* oldIncSaved = mActionItem->incidence()->clone();
01133 Incidence* newInc = mCalendar->dissociateOccurrence(
01134 oldInc, mActionItem->itemDate(), false );
01135 if ( newInc ) {
01136 emit enableAgendaUpdate( false );
01137 mActionItem->dissociateFromMultiItem();
01138 mActionItem->setIncidence( newInc );
01139 mChanger->addIncidence( newInc, this );
01140 emit enableAgendaUpdate( true );
01141 mChanger->changeIncidence( oldIncSaved, oldInc,
01142 KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE, this );
01143 } else {
01144 KMessageBox::sorry( this, i18n("Unable to add the future items to the "
01145 "calendar. No change will be done."), i18n("Error Occurred") );
01146 }
01147 delete oldIncSaved;
01148 break; }
01149 default:
01150 modify = false;
01151 mActionItem->resetMove();
01152 placeSubCells( mActionItem );
01153 }
01154 }
01155
01156 if ( modify ) {
01157 mActionItem->endMove();
01158 KOAgendaItem *placeItem = mActionItem->firstMultiItem();
01159 if ( !placeItem ) {
01160 placeItem = mActionItem;
01161 }
01162
01163 KOAgendaItem *modif = placeItem;
01164
01165 QPtrList<KOAgendaItem> oldconflictItems = placeItem->conflictItems();
01166 KOAgendaItem *item;
01167 for ( item = oldconflictItems.first(); item != 0;
01168 item = oldconflictItems.next() ) {
01169 placeSubCells( item );
01170 }
01171 while ( placeItem ) {
01172 placeSubCells( placeItem );
01173 placeItem = placeItem->nextMultiItem();
01174 }
01175
01176
01177
01178 emit itemModified( modif );
01179 }
01180
01181 mChanger->endChange( inc );
01182 }
01183
01184 mActionItem = 0;
01185 mItemMoved = false;
01186
01187 if ( multiModify ) emit endMultiModify();
01188
01189 kdDebug(5850) << "KOAgenda::endItemAction() done" << endl;
01190 }
01191
01192 void KOAgenda::setActionCursor( int actionType, bool acting )
01193 {
01194 switch ( actionType ) {
01195 case MOVE:
01196 if (acting) setCursor( sizeAllCursor );
01197 else setCursor( arrowCursor );
01198 break;
01199 case RESIZETOP:
01200 case RESIZEBOTTOM:
01201 setCursor( sizeVerCursor );
01202 break;
01203 case RESIZELEFT:
01204 case RESIZERIGHT:
01205 setCursor( sizeHorCursor );
01206 break;
01207 default:
01208 setCursor( arrowCursor );
01209 }
01210 }
01211
01212 void KOAgenda::setNoActionCursor( KOAgendaItem *moveItem, const QPoint& viewportPos )
01213 {
01214
01215
01216
01217
01218
01219
01220 QPoint pos = viewportToContents( viewportPos );
01221 bool noResize = (moveItem && moveItem->incidence() &&
01222 moveItem->incidence()->type() == "Todo");
01223
01224 KOAgenda::MouseActionType resizeType = MOVE;
01225 if ( !noResize ) resizeType = isInResizeArea( mAllDayMode, pos , moveItem);
01226 setActionCursor( resizeType );
01227 }
01228
01229
01232 double KOAgenda::calcSubCellWidth( KOAgendaItem *item )
01233 {
01234 QPoint pt, pt1;
01235 pt = gridToContents( QPoint( item->cellXLeft(), item->cellYTop() ) );
01236 pt1 = gridToContents( QPoint( item->cellXLeft(), item->cellYTop() ) +
01237 QPoint( 1, 1 ) );
01238 pt1 -= pt;
01239 int maxSubCells = item->subCells();
01240 double newSubCellWidth;
01241 if ( mAllDayMode ) {
01242 newSubCellWidth = double( pt1.y() ) / maxSubCells;
01243 } else {
01244 newSubCellWidth = double( pt1.x() ) / maxSubCells;
01245 }
01246 return newSubCellWidth;
01247 }
01248
01249 void KOAgenda::adjustItemPosition( KOAgendaItem *item )
01250 {
01251 if (!item) return;
01252 item->resize( int( mGridSpacingX * item->cellWidth() ),
01253 int( mGridSpacingY * item->cellHeight() ) );
01254 int clXLeft = item->cellXLeft();
01255 if ( KOGlobals::self()->reverseLayout() )
01256 clXLeft = item->cellXRight() + 1;
01257 QPoint cpos = gridToContents( QPoint( clXLeft, item->cellYTop() ) );
01258 moveChild( item, cpos.x(), cpos.y() );
01259 }
01260
01261 void KOAgenda::placeAgendaItem( KOAgendaItem *item, double subCellWidth )
01262 {
01263
01264
01265
01266
01267 QPoint pt = gridToContents( QPoint( item->cellXLeft(), item->cellYTop() ) );
01268
01269 QPoint pt1 = gridToContents( QPoint( item->cellXLeft() + item->cellWidth(),
01270 item->cellYBottom()+1 ) );
01271
01272 double subCellPos = item->subCell() * subCellWidth;
01273
01274
01275
01276 double delta=0.01;
01277 if (subCellWidth<0) delta=-delta;
01278 int height, width, xpos, ypos;
01279 if (mAllDayMode) {
01280 width = pt1.x()-pt.x();
01281 height = int( subCellPos + subCellWidth + delta ) - int( subCellPos );
01282 xpos = pt.x();
01283 ypos = pt.y() + int( subCellPos );
01284 } else {
01285 width = int( subCellPos + subCellWidth + delta ) - int( subCellPos );
01286 height = pt1.y()-pt.y();
01287 xpos = pt.x() + int( subCellPos );
01288 ypos = pt.y();
01289 }
01290 if ( KOGlobals::self()->reverseLayout() ) {
01291 xpos += width;
01292 width = -width;
01293 }
01294 if ( height<0 ) {
01295 ypos += height;
01296 height = -height;
01297 }
01298 item->resize( width, height );
01299 moveChild( item, xpos, ypos );
01300 }
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312 void KOAgenda::placeSubCells( KOAgendaItem *placeItem )
01313 {
01314 #if 0
01315 kdDebug(5850) << "KOAgenda::placeSubCells()" << endl;
01316 if ( placeItem ) {
01317 Incidence *event = placeItem->incidence();
01318 if ( !event ) {
01319 kdDebug(5850) << " event is 0" << endl;
01320 } else {
01321 kdDebug(5850) << " event: " << event->summary() << endl;
01322 }
01323 } else {
01324 kdDebug(5850) << " placeItem is 0" << endl;
01325 }
01326 kdDebug(5850) << "KOAgenda::placeSubCells()..." << endl;
01327 #endif
01328
01329 QPtrList<KOrg::CellItem> cells;
01330 KOAgendaItem *item;
01331 for ( item = mItems.first(); item != 0; item = mItems.next() ) {
01332 cells.append( item );
01333 }
01334
01335 QPtrList<KOrg::CellItem> items = KOrg::CellItem::placeItem( cells,
01336 placeItem );
01337
01338 placeItem->setConflictItems( QPtrList<KOAgendaItem>() );
01339 double newSubCellWidth = calcSubCellWidth( placeItem );
01340 KOrg::CellItem *i;
01341 for ( i = items.first(); i; i = items.next() ) {
01342 item = static_cast<KOAgendaItem *>( i );
01343 placeAgendaItem( item, newSubCellWidth );
01344 item->addConflictItem( placeItem );
01345 placeItem->addConflictItem( item );
01346 }
01347 if ( items.isEmpty() ) {
01348 placeAgendaItem( placeItem, newSubCellWidth );
01349 }
01350 placeItem->update();
01351 }
01352
01353 int KOAgenda::columnWidth( int column )
01354 {
01355 int start = gridToContents( QPoint( column, 0 ) ).x();
01356 if (KOGlobals::self()->reverseLayout() )
01357 column--;
01358 else
01359 column++;
01360 int end = gridToContents( QPoint( column, 0 ) ).x();
01361 return end - start;
01362 }
01363
01364
01365
01366 void KOAgenda::drawContents(QPainter* p, int cx, int cy, int cw, int ch)
01367 {
01368 QPixmap db(cw, ch);
01369 db.fill(KOPrefs::instance()->mAgendaBgColor);
01370 QPainter dbp(&db);
01371 dbp.translate(-cx,-cy);
01372
01373
01374 double lGridSpacingY = mGridSpacingY*2;
01375
01376
01377 if (mWorkingHoursEnable) {
01378 QPoint pt1( cx, mWorkingHoursYTop );
01379 QPoint pt2( cx+cw, mWorkingHoursYBottom );
01380 if ( pt2.x() >= pt1.x() ) {
01381 int gxStart = contentsToGrid( pt1 ).x();
01382 int gxEnd = contentsToGrid( pt2 ).x();
01383
01384 if ( gxStart > gxEnd ) {
01385 int tmp = gxStart;
01386 gxStart = gxEnd;
01387 gxEnd = tmp;
01388 }
01389 int xoffset = ( KOGlobals::self()->reverseLayout()?1:0 );
01390 while( gxStart <= gxEnd ) {
01391 int xStart = gridToContents( QPoint( gxStart+xoffset, 0 ) ).x();
01392 int xWidth = columnWidth( gxStart ) + 1;
01393 if ( pt2.y() < pt1.y() ) {
01394
01395 if ( ( (gxStart==0) && !mHolidayMask->at(mHolidayMask->count()-1) ) ||
01396 ( (gxStart>0) && (gxStart<int(mHolidayMask->count())) && (!mHolidayMask->at(gxStart-1) ) ) ) {
01397 if ( pt2.y() > cy ) {
01398 dbp.fillRect( xStart, cy, xWidth, pt2.y() - cy + 1,
01399 KOPrefs::instance()->mWorkingHoursColor);
01400 }
01401 }
01402 if ( (gxStart < int(mHolidayMask->count()-1)) && (!mHolidayMask->at(gxStart)) ) {
01403 if ( pt1.y() < cy + ch - 1 ) {
01404 dbp.fillRect( xStart, pt1.y(), xWidth, cy + ch - pt1.y() + 1,
01405 KOPrefs::instance()->mWorkingHoursColor);
01406 }
01407 }
01408 } else {
01409
01410 if ( gxStart < int(mHolidayMask->count()-1) && !mHolidayMask->at(gxStart)) {
01411 dbp.fillRect( xStart, pt1.y(), xWidth, pt2.y() - pt1.y() + 1,
01412 KOPrefs::instance()->mWorkingHoursColor );
01413 }
01414 }
01415 ++gxStart;
01416 }
01417 }
01418 }
01419
01420
01421 if ( mHasSelection ) {
01422 QPoint pt, pt1;
01423
01424 if ( mSelectionEndCell.x() > mSelectionStartCell.x() ) {
01425
01426 pt = gridToContents( mSelectionStartCell );
01427 pt1 = gridToContents( QPoint( mSelectionStartCell.x() + 1, mRows + 1 ) );
01428 dbp.fillRect( QRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor );
01429
01430 for ( int c = mSelectionStartCell.x() + 1; c < mSelectionEndCell.x(); ++c ) {
01431 pt = gridToContents( QPoint( c, 0 ) );
01432 pt1 = gridToContents( QPoint( c + 1, mRows + 1 ) );
01433 dbp.fillRect( QRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor );
01434 }
01435
01436 pt = gridToContents( QPoint( mSelectionEndCell.x(), 0 ) );
01437 pt1 = gridToContents( mSelectionEndCell + QPoint(1,1) );
01438 dbp.fillRect( QRect( pt, pt1), KOPrefs::instance()->mHighlightColor );
01439 } else {
01440 pt = gridToContents( mSelectionStartCell );
01441 pt1 = gridToContents( mSelectionEndCell + QPoint(1,1) );
01442 dbp.fillRect( QRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor );
01443 }
01444 }
01445
01446 QPen hourPen( KOPrefs::instance()->mAgendaBgColor.dark( 150 ) );
01447 QPen halfHourPen( KOPrefs::instance()->mAgendaBgColor.dark( 125 ) );
01448 dbp.setPen( hourPen );
01449
01450
01451
01452 double x = ( int( cx / mGridSpacingX ) ) * mGridSpacingX;
01453 while (x < cx + cw) {
01454 dbp.drawLine( int( x ), cy, int( x ), cy + ch );
01455 x+=mGridSpacingX;
01456 }
01457
01458
01459 double y = ( int( cy / (2*lGridSpacingY) ) ) * 2 * lGridSpacingY;
01460 while (y < cy + ch) {
01461
01462 dbp.drawLine( cx, int( y ), cx + cw, int( y ) );
01463 y += 2 * lGridSpacingY;
01464 }
01465 y = ( 2 * int( cy / (2*lGridSpacingY) ) + 1) * lGridSpacingY;
01466 dbp.setPen( halfHourPen );
01467 while (y < cy + ch) {
01468
01469 dbp.drawLine( cx, int( y ), cx + cw, int( y ) );
01470 y+=2*lGridSpacingY;
01471 }
01472 p->drawPixmap(cx,cy, db);
01473 }
01474
01475
01476
01477
01478 QPoint KOAgenda::contentsToGrid ( const QPoint &pos ) const
01479 {
01480 int gx = int( KOGlobals::self()->reverseLayout() ?
01481 mColumns - pos.x()/mGridSpacingX : pos.x()/mGridSpacingX );
01482 int gy = int( pos.y()/mGridSpacingY );
01483 return QPoint( gx, gy );
01484 }
01485
01486
01487
01488
01489 QPoint KOAgenda::gridToContents( const QPoint &gpos ) const
01490 {
01491 int x = int( KOGlobals::self()->reverseLayout() ?
01492 (mColumns - gpos.x())*mGridSpacingX : gpos.x()*mGridSpacingX );
01493 int y = int( gpos.y()*mGridSpacingY );
01494 return QPoint( x, y );
01495 }
01496
01497
01498
01499
01500
01501
01502 int KOAgenda::timeToY(const QTime &time)
01503 {
01504
01505 int minutesPerCell = 24 * 60 / mRows;
01506
01507 int timeMinutes = time.hour() * 60 + time.minute();
01508
01509 int Y = (timeMinutes + (minutesPerCell / 2)) / minutesPerCell;
01510
01511
01512 return Y;
01513 }
01514
01515
01516
01517
01518
01519
01520 QTime KOAgenda::gyToTime(int gy)
01521 {
01522
01523 int secondsPerCell = 24 * 60 * 60/ mRows;
01524
01525 int timeSeconds = secondsPerCell * gy;
01526
01527 QTime time( 0, 0, 0 );
01528 if ( timeSeconds < 24 * 60 * 60 ) {
01529 time = time.addSecs(timeSeconds);
01530 } else {
01531 time.setHMS( 23, 59, 59 );
01532 }
01533
01534
01535 return time;
01536 }
01537
01538 QMemArray<int> KOAgenda::minContentsY()
01539 {
01540 QMemArray<int> minArray;
01541 minArray.fill( timeToY( QTime(23, 59) ), mSelectedDates.count() );
01542 for ( KOAgendaItem *item = mItems.first();
01543 item != 0; item = mItems.next() ) {
01544 int ymin = item->cellYTop();
01545 int index = item->cellXLeft();
01546 if ( index>=0 && index<(int)(mSelectedDates.count()) ) {
01547 if ( ymin < minArray[index] && mItemsToDelete.findRef( item ) == -1 )
01548 minArray[index] = ymin;
01549 }
01550 }
01551
01552 return minArray;
01553 }
01554
01555 QMemArray<int> KOAgenda::maxContentsY()
01556 {
01557 QMemArray<int> maxArray;
01558 maxArray.fill( timeToY( QTime(0, 0) ), mSelectedDates.count() );
01559 for ( KOAgendaItem *item = mItems.first();
01560 item != 0; item = mItems.next() ) {
01561 int ymax = item->cellYBottom();
01562 int index = item->cellXLeft();
01563 if ( index>=0 && index<(int)(mSelectedDates.count()) ) {
01564 if ( ymax > maxArray[index] && mItemsToDelete.findRef( item ) == -1 )
01565 maxArray[index] = ymax;
01566 }
01567 }
01568
01569 return maxArray;
01570 }
01571
01572 void KOAgenda::setStartTime( const QTime &startHour )
01573 {
01574 double startPos = ( startHour.hour()/24. + startHour.minute()/1440. +
01575 startHour.second()/86400. ) * mRows * gridSpacingY();
01576 setContentsPos( 0, int( startPos ) );
01577 }
01578
01579
01580
01581
01582
01583 KOAgendaItem *KOAgenda::insertItem( Incidence *incidence, const QDate &qd, int X,
01584 int YTop, int YBottom )
01585 {
01586 #if 0
01587 kdDebug(5850) << "KOAgenda::insertItem:" << incidence->summary() << "-"
01588 << qd.toString() << " ;top, bottom:" << YTop << "," << YBottom
01589 << endl;
01590 #endif
01591
01592 if ( mAllDayMode ) {
01593 kdDebug(5850) << "KOAgenda: calling insertItem in all-day mode is illegal." << endl;
01594 return 0;
01595 }
01596
01597
01598 mActionType = NOP;
01599
01600 KOAgendaItem *agendaItem = new KOAgendaItem( mCalendar, incidence, qd, viewport() );
01601 connect( agendaItem, SIGNAL( removeAgendaItem( KOAgendaItem * ) ),
01602 SLOT( removeAgendaItem( KOAgendaItem * ) ) );
01603 connect( agendaItem, SIGNAL( showAgendaItem( KOAgendaItem * ) ),
01604 SLOT( showAgendaItem( KOAgendaItem * ) ) );
01605
01606 if ( YBottom <= YTop ) {
01607 kdDebug(5850) << "KOAgenda::insertItem(): Text: " << agendaItem->text() << " YSize<0" << endl;
01608 YBottom = YTop;
01609 }
01610
01611 agendaItem->resize( int( ( X + 1 ) * mGridSpacingX ) -
01612 int( X * mGridSpacingX ),
01613 int( YTop * mGridSpacingY ) -
01614 int( ( YBottom + 1 ) * mGridSpacingY ) );
01615 agendaItem->setCellXY( X, YTop, YBottom );
01616 agendaItem->setCellXRight( X );
01617 agendaItem->setResourceColor( KOHelper::resourceColor( mCalendar, incidence ) );
01618 agendaItem->installEventFilter( this );
01619
01620 addChild( agendaItem, int( X * mGridSpacingX ), int( YTop * mGridSpacingY ) );
01621 mItems.append( agendaItem );
01622
01623 placeSubCells( agendaItem );
01624
01625 agendaItem->show();
01626
01627 marcus_bains();
01628
01629 return agendaItem;
01630 }
01631
01632
01633
01634
01635 KOAgendaItem *KOAgenda::insertAllDayItem( Incidence *event, const QDate &qd,
01636 int XBegin, int XEnd )
01637 {
01638 if ( !mAllDayMode ) {
01639 kdDebug(5850) << "KOAgenda: calling insertAllDayItem in non all-day mode is illegal." << endl;
01640 return 0;
01641 }
01642
01643 mActionType = NOP;
01644
01645 KOAgendaItem *agendaItem = new KOAgendaItem( mCalendar, event, qd, viewport() );
01646 connect( agendaItem, SIGNAL( removeAgendaItem( KOAgendaItem* ) ),
01647 SLOT( removeAgendaItem( KOAgendaItem* ) ) );
01648 connect( agendaItem, SIGNAL( showAgendaItem( KOAgendaItem* ) ),
01649 SLOT( showAgendaItem( KOAgendaItem* ) ) );
01650
01651 agendaItem->setCellXY( XBegin, 0, 0 );
01652 agendaItem->setCellXRight( XEnd );
01653
01654 double startIt = mGridSpacingX * ( agendaItem->cellXLeft() );
01655 double endIt = mGridSpacingX * ( agendaItem->cellWidth() +
01656 agendaItem->cellXLeft() );
01657
01658 agendaItem->resize( int( endIt ) - int( startIt ), int( mGridSpacingY ) );
01659
01660 agendaItem->installEventFilter( this );
01661 agendaItem->setResourceColor( KOHelper::resourceColor( mCalendar, event ) );
01662 addChild( agendaItem, int( XBegin * mGridSpacingX ), 0 );
01663 mItems.append( agendaItem );
01664
01665 placeSubCells( agendaItem );
01666
01667 agendaItem->show();
01668
01669 return agendaItem;
01670 }
01671
01672
01673 void KOAgenda::insertMultiItem (Event *event,const QDate &qd,int XBegin,int XEnd,
01674 int YTop,int YBottom)
01675 {
01676 if (mAllDayMode) {
01677 kdDebug(5850) << "KOAgenda: calling insertMultiItem in all-day mode is illegal." << endl;
01678 return;
01679 }
01680 mActionType = NOP;
01681
01682 int cellX,cellYTop,cellYBottom;
01683 QString newtext;
01684 int width = XEnd - XBegin + 1;
01685 int count = 0;
01686 KOAgendaItem *current = 0;
01687 QPtrList<KOAgendaItem> multiItems;
01688 int visibleCount = mSelectedDates.first().daysTo(mSelectedDates.last());
01689 for ( cellX = XBegin; cellX <= XEnd; ++cellX ) {
01690 ++count;
01691
01692 if( cellX >=0 && cellX <= visibleCount ) {
01693 if ( cellX == XBegin ) cellYTop = YTop;
01694 else cellYTop = 0;
01695 if ( cellX == XEnd ) cellYBottom = YBottom;
01696 else cellYBottom = rows() - 1;
01697 newtext = QString("(%1/%2): ").arg( count ).arg( width );
01698 newtext.append( event->summary() );
01699
01700 current = insertItem( event, qd, cellX, cellYTop, cellYBottom );
01701 current->setText( newtext );
01702 multiItems.append( current );
01703 }
01704 }
01705
01706 KOAgendaItem *next = 0;
01707 KOAgendaItem *prev = 0;
01708 KOAgendaItem *last = multiItems.last();
01709 KOAgendaItem *first = multiItems.first();
01710 KOAgendaItem *setFirst,*setLast;
01711 current = first;
01712 while (current) {
01713 next = multiItems.next();
01714 if (current == first) setFirst = 0;
01715 else setFirst = first;
01716 if (current == last) setLast = 0;
01717 else setLast = last;
01718
01719 current->setMultiItem(setFirst, prev, next, setLast);
01720 prev=current;
01721 current = next;
01722 }
01723
01724 marcus_bains();
01725 }
01726
01727 void KOAgenda::removeIncidence( Incidence *incidence )
01728 {
01729
01730
01731
01732 QPtrList<KOAgendaItem> itemsToRemove;
01733
01734 KOAgendaItem *item = mItems.first();
01735 while ( item ) {
01736 if ( item->incidence() == incidence ) {
01737 itemsToRemove.append( item );
01738 }
01739 item = mItems.next();
01740 }
01741 item = itemsToRemove.first();
01742 while ( item ) {
01743 removeAgendaItem( item );
01744 item = itemsToRemove.next();
01745 }
01746 }
01747
01748 void KOAgenda::showAgendaItem( KOAgendaItem *agendaItem )
01749 {
01750 if ( !agendaItem ) return;
01751 agendaItem->hide();
01752 addChild( agendaItem );
01753 if ( !mItems.containsRef( agendaItem ) )
01754 mItems.append( agendaItem );
01755 placeSubCells( agendaItem );
01756
01757 agendaItem->show();
01758 }
01759
01760 bool KOAgenda::removeAgendaItem( KOAgendaItem *item )
01761 {
01762
01763 bool taken = false;
01764 KOAgendaItem *thisItem = item;
01765 QPtrList<KOAgendaItem> conflictItems = thisItem->conflictItems();
01766 removeChild( thisItem );
01767 int pos = mItems.find( thisItem );
01768 if ( pos>=0 ) {
01769 mItems.take( pos );
01770 taken = true;
01771 }
01772
01773 KOAgendaItem *confitem;
01774 for ( confitem = conflictItems.first(); confitem != 0;
01775 confitem = conflictItems.next() ) {
01776
01777 if ( confitem != thisItem ) placeSubCells(confitem);
01778
01779 }
01780 mItemsToDelete.append( thisItem );
01781 QTimer::singleShot( 0, this, SLOT( deleteItemsToDelete() ) );
01782 return taken;
01783 }
01784
01785 void KOAgenda::deleteItemsToDelete()
01786 {
01787 mItemsToDelete.clear();
01788 }
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808 void KOAgenda::resizeEvent ( QResizeEvent *ev )
01809 {
01810
01811
01812 QSize newSize( ev->size() );
01813 if (mAllDayMode) {
01814 mGridSpacingX = double( newSize.width() - 2 * frameWidth() ) / (double)mColumns;
01815 mGridSpacingY = newSize.height() - 2 * frameWidth();
01816 } else {
01817 int scrollbarWidth = vScrollBarMode() != AlwaysOff ? verticalScrollBar()->width() : 0;
01818 mGridSpacingX = double( newSize.width() - scrollbarWidth - 2 * frameWidth()) / double(mColumns);
01819
01820 mGridSpacingY = double(newSize.height() - 2 * frameWidth()) / double(mRows);
01821 if ( mGridSpacingY < mDesiredGridSpacingY )
01822 mGridSpacingY = mDesiredGridSpacingY;
01823 }
01824 calculateWorkingHours();
01825 QTimer::singleShot( 0, this, SLOT( resizeAllContents() ) );
01826 emit gridSpacingYChanged( mGridSpacingY * 4 );
01827 QScrollView::resizeEvent(ev);
01828 }
01829
01830 void KOAgenda::resizeAllContents()
01831 {
01832 double subCellWidth;
01833 if ( mItems.count() > 0 ) {
01834 KOAgendaItem *item;
01835 if (mAllDayMode) {
01836 for ( item=mItems.first(); item != 0; item=mItems.next() ) {
01837 subCellWidth = calcSubCellWidth( item );
01838 placeAgendaItem( item, subCellWidth );
01839 }
01840 } else {
01841 for ( item=mItems.first(); item != 0; item=mItems.next() ) {
01842 subCellWidth = calcSubCellWidth( item );
01843 placeAgendaItem( item, subCellWidth );
01844 }
01845 }
01846 }
01847 checkScrollBoundaries();
01848 marcus_bains();
01849 }
01850
01851 void KOAgenda::scrollUp()
01852 {
01853 scrollBy(0,-mScrollOffset);
01854 }
01855
01856
01857 void KOAgenda::scrollDown()
01858 {
01859 scrollBy(0,mScrollOffset);
01860 }
01861
01862
01863
01864
01865
01866 int KOAgenda::minimumWidth() const
01867 {
01868
01869 int min = 100;
01870
01871 return min;
01872 }
01873
01874 void KOAgenda::updateConfig()
01875 {
01876 double oldGridSpacingY = mGridSpacingY;
01877
01878 mDesiredGridSpacingY = KOPrefs::instance()->mHourSize;
01879 if ( mDesiredGridSpacingY < 4 || mDesiredGridSpacingY > 30 ) {
01880 mDesiredGridSpacingY = 10;
01881 }
01882
01883
01884 mGridSpacingY = (double)height() / (double)mRows;
01885 if ( mGridSpacingY < mDesiredGridSpacingY ) {
01886 mGridSpacingY = mDesiredGridSpacingY;
01887 }
01888
01889
01890 if ( fabs( oldGridSpacingY - mGridSpacingY ) > 0.1 ) {
01891 resizeContents( int( mGridSpacingX * mColumns ),
01892 int( mGridSpacingY * mRows ) );
01893 }
01894
01895 calculateWorkingHours();
01896
01897 marcus_bains();
01898 }
01899
01900 void KOAgenda::checkScrollBoundaries()
01901 {
01902
01903 mOldLowerScrollValue = -1;
01904 mOldUpperScrollValue = -1;
01905
01906 checkScrollBoundaries(verticalScrollBar()->value());
01907 }
01908
01909 void KOAgenda::checkScrollBoundaries( int v )
01910 {
01911 int yMin = int( (v) / mGridSpacingY );
01912 int yMax = int( ( v + visibleHeight() ) / mGridSpacingY );
01913
01914
01915
01916 if ( yMin != mOldLowerScrollValue ) {
01917 mOldLowerScrollValue = yMin;
01918 emit lowerYChanged(yMin);
01919 }
01920 if ( yMax != mOldUpperScrollValue ) {
01921 mOldUpperScrollValue = yMax;
01922 emit upperYChanged(yMax);
01923 }
01924 }
01925
01926 int KOAgenda::visibleContentsYMin()
01927 {
01928 int v = verticalScrollBar()->value();
01929 return int( v / mGridSpacingY );
01930 }
01931
01932 int KOAgenda::visibleContentsYMax()
01933 {
01934 int v = verticalScrollBar()->value();
01935 return int( ( v + visibleHeight() ) / mGridSpacingY );
01936 }
01937
01938 void KOAgenda::deselectItem()
01939 {
01940 if (mSelectedItem.isNull()) return;
01941 mSelectedItem->select(false);
01942 mSelectedItem = 0;
01943 }
01944
01945 void KOAgenda::selectItem(KOAgendaItem *item)
01946 {
01947 if ((KOAgendaItem *)mSelectedItem == item) return;
01948 deselectItem();
01949 if (item == 0) {
01950 emit incidenceSelected( 0, QDate() );
01951 return;
01952 }
01953 mSelectedItem = item;
01954 mSelectedItem->select();
01955 assert( mSelectedItem->incidence() );
01956 mSelectedUid = mSelectedItem->incidence()->uid();
01957 emit incidenceSelected( mSelectedItem->incidence(), mSelectedItem->itemDate() );
01958 }
01959
01960 void KOAgenda::selectItemByUID( const QString& uid )
01961 {
01962 KOAgendaItem *item;
01963 for ( item = mItems.first(); item != 0; item = mItems.next() ) {
01964 if( item->incidence() && item->incidence()->uid() == uid ) {
01965 selectItem( item );
01966 break;
01967 }
01968 }
01969 }
01970
01971
01972 void KOAgenda::keyPressEvent( QKeyEvent *kev )
01973 {
01974 switch(kev->key()) {
01975 case Key_PageDown:
01976 verticalScrollBar()->addPage();
01977 break;
01978 case Key_PageUp:
01979 verticalScrollBar()->subtractPage();
01980 break;
01981 case Key_Down:
01982 verticalScrollBar()->addLine();
01983 break;
01984 case Key_Up:
01985 verticalScrollBar()->subtractLine();
01986 break;
01987 default:
01988 ;
01989 }
01990 }
01991
01992 void KOAgenda::calculateWorkingHours()
01993 {
01994 mWorkingHoursEnable = !mAllDayMode;
01995
01996 QTime tmp = KOPrefs::instance()->mWorkingHoursStart.time();
01997 mWorkingHoursYTop = int( 4 * mGridSpacingY *
01998 ( tmp.hour() + tmp.minute() / 60. +
01999 tmp.second() / 3600. ) );
02000 tmp = KOPrefs::instance()->mWorkingHoursEnd.time();
02001 mWorkingHoursYBottom = int( 4 * mGridSpacingY *
02002 ( tmp.hour() + tmp.minute() / 60. +
02003 tmp.second() / 3600. ) - 1 );
02004 }
02005
02006
02007 DateList KOAgenda::dateList() const
02008 {
02009 return mSelectedDates;
02010 }
02011
02012 void KOAgenda::setDateList(const DateList &selectedDates)
02013 {
02014 mSelectedDates = selectedDates;
02015 marcus_bains();
02016 }
02017
02018 void KOAgenda::setHolidayMask(QMemArray<bool> *mask)
02019 {
02020 mHolidayMask = mask;
02021
02022 }
02023
02024 void KOAgenda::contentsMousePressEvent ( QMouseEvent *event )
02025 {
02026 kdDebug(5850) << "KOagenda::contentsMousePressEvent(): type: " << event->type() << endl;
02027 QScrollView::contentsMousePressEvent(event);
02028 }
02029
02030 void KOAgenda::setTypeAheadReceiver( QObject *o )
02031 {
02032 mTypeAheadReceiver = o;
02033 }
02034
02035 QObject *KOAgenda::typeAheadReceiver() const
02036 {
02037 return mTypeAheadReceiver;
02038 }