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