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