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