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