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