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