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