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 QPair<ResourceCalendar *, QString>p = mCalendarView->viewSubResourceCalendar();
00903
00904
00905
00906 if ( clipperPos.y() < 0 || clipperPos.y() > visibleHeight() ||
00907 clipperPos.x() < 0 || clipperPos.x() > visibleWidth() ) {
00908 if ( mActionType == MOVE ) {
00909 mScrollUpTimer.stop();
00910 mScrollDownTimer.stop();
00911 mActionItem->resetMove();
00912 placeSubCells( mActionItem );
00913 emit startDragSignal( mActionItem->incidence() );
00914 setCursor( arrowCursor );
00915 mActionItem = 0;
00916 mActionType = NOP;
00917 mItemMoved = false;
00918 if ( mItemMoved && mChanger )
00919 mChanger->endChange( mActionItem->incidence(), p.first, p.second );
00920 return;
00921 }
00922 } else {
00923 setActionCursor( mActionType );
00924 }
00925
00926
00927 if (clipperPos.y() < mScrollBorderWidth) {
00928 mScrollUpTimer.start(mScrollDelay);
00929 } else if (visibleHeight() - clipperPos.y() <
00930 mScrollBorderWidth) {
00931 mScrollDownTimer.start(mScrollDelay);
00932 } else {
00933 mScrollUpTimer.stop();
00934 mScrollDownTimer.stop();
00935 }
00936
00937
00938 if ( mEndCell != gpos ) {
00939 if ( !mItemMoved ) {
00940 if ( !mChanger ||
00941 !mChanger->beginChange( mActionItem->incidence(), p.first, p.second ) ) {
00942 KMessageBox::information( this, i18n("Unable to lock item for "
00943 "modification. You cannot make any changes."),
00944 i18n("Locking Failed"), "AgendaLockingFailed" );
00945 mScrollUpTimer.stop();
00946 mScrollDownTimer.stop();
00947 mActionItem->resetMove();
00948 placeSubCells( mActionItem );
00949 setCursor( arrowCursor );
00950 mActionItem = 0;
00951 mActionType = NOP;
00952 mItemMoved = false;
00953 return;
00954 }
00955 mItemMoved = true;
00956 }
00957 mActionItem->raise();
00958 if (mActionType == MOVE) {
00959
00960 KOAgendaItem *firstItem = mActionItem->firstMultiItem();
00961 if (!firstItem) firstItem = mActionItem;
00962 KOAgendaItem *lastItem = mActionItem->lastMultiItem();
00963 if (!lastItem) lastItem = mActionItem;
00964 QPoint deltapos = gpos - mEndCell;
00965 KOAgendaItem *moveItem = firstItem;
00966 while (moveItem) {
00967 bool changed=false;
00968 if ( deltapos.x()!=0 ) {
00969 moveItem->moveRelative( deltapos.x(), 0 );
00970 changed=true;
00971 }
00972
00973 if ( moveItem==firstItem && !mAllDayMode ) {
00974 int newY = deltapos.y() + moveItem->cellYTop();
00975
00976 if ( newY<0 ) {
00977 moveItem->expandTop( -moveItem->cellYTop() );
00978
00979 KOAgendaItem *newFirst = firstItem->prevMoveItem();
00980
00981 if (newFirst) {
00982 newFirst->setCellXY(moveItem->cellXLeft()-1, rows()+newY, rows()-1);
00983 mItems.append( newFirst );
00984 moveItem->resize( int( mGridSpacingX * newFirst->cellWidth() ),
00985 int( mGridSpacingY * newFirst->cellHeight() ));
00986 QPoint cpos = gridToContents( QPoint( newFirst->cellXLeft(), newFirst->cellYTop() ) );
00987 addChild( newFirst, cpos.x(), cpos.y() );
00988 } else {
00989 newFirst = insertItem( moveItem->incidence(), moveItem->itemDate(),
00990 moveItem->cellXLeft()-1, rows()+newY, rows()-1 ) ;
00991 }
00992 if (newFirst) newFirst->show();
00993 moveItem->prependMoveItem(newFirst);
00994 firstItem=newFirst;
00995 } else if ( newY>=rows() ) {
00996
00997
00998 firstItem = moveItem->nextMultiItem();
00999 moveItem->hide();
01000 mItems.take( mItems.find( moveItem ) );
01001 removeChild( moveItem );
01002 mActionItem->removeMoveItem(moveItem);
01003 moveItem=firstItem;
01004
01005 if (moveItem) moveItem->expandTop( rows()-newY );
01006 } else {
01007 moveItem->expandTop(deltapos.y());
01008 }
01009 changed=true;
01010 }
01011 if ( !moveItem->lastMultiItem() && !mAllDayMode ) {
01012 int newY = deltapos.y()+moveItem->cellYBottom();
01013 if (newY<0) {
01014
01015 lastItem = moveItem->prevMultiItem();
01016 moveItem->hide();
01017 mItems.take( mItems.find(moveItem) );
01018 removeChild( moveItem );
01019 moveItem->removeMoveItem( moveItem );
01020 moveItem = lastItem;
01021 moveItem->expandBottom(newY+1);
01022 } else if (newY>=rows()) {
01023 moveItem->expandBottom( rows()-moveItem->cellYBottom()-1 );
01024
01025 KOAgendaItem *newLast = lastItem->nextMoveItem();
01026 if (newLast) {
01027 newLast->setCellXY( moveItem->cellXLeft()+1, 0, newY-rows()-1 );
01028 mItems.append(newLast);
01029 moveItem->resize( int( mGridSpacingX * newLast->cellWidth() ),
01030 int( mGridSpacingY * newLast->cellHeight() ));
01031 QPoint cpos = gridToContents( QPoint( newLast->cellXLeft(), newLast->cellYTop() ) ) ;
01032 addChild( newLast, cpos.x(), cpos.y() );
01033 } else {
01034 newLast = insertItem( moveItem->incidence(), moveItem->itemDate(),
01035 moveItem->cellXLeft()+1, 0, newY-rows()-1 ) ;
01036 }
01037 moveItem->appendMoveItem( newLast );
01038 newLast->show();
01039 lastItem = newLast;
01040 } else {
01041 moveItem->expandBottom( deltapos.y() );
01042 }
01043 changed=true;
01044 }
01045 if (changed) {
01046 adjustItemPosition( moveItem );
01047 }
01048 moveItem = moveItem->nextMultiItem();
01049 }
01050 } else if (mActionType == RESIZETOP) {
01051 if (mEndCell.y() <= mActionItem->cellYBottom()) {
01052 mActionItem->expandTop(gpos.y() - mEndCell.y());
01053 adjustItemPosition( mActionItem );
01054 }
01055 } else if (mActionType == RESIZEBOTTOM) {
01056 if (mEndCell.y() >= mActionItem->cellYTop()) {
01057 mActionItem->expandBottom(gpos.y() - mEndCell.y());
01058 adjustItemPosition( mActionItem );
01059 }
01060 } else if (mActionType == RESIZELEFT) {
01061 if (mEndCell.x() <= mActionItem->cellXRight()) {
01062 mActionItem->expandLeft( gpos.x() - mEndCell.x() );
01063 adjustItemPosition( mActionItem );
01064 }
01065 } else if (mActionType == RESIZERIGHT) {
01066 if (mEndCell.x() >= mActionItem->cellXLeft()) {
01067 mActionItem->expandRight(gpos.x() - mEndCell.x());
01068 adjustItemPosition( mActionItem );
01069 }
01070 }
01071 mEndCell = gpos;
01072 }
01073 }
01074
01075 void KOAgenda::endItemAction()
01076 {
01077
01078 mActionType = NOP;
01079 mScrollUpTimer.stop();
01080 mScrollDownTimer.stop();
01081 setCursor( arrowCursor );
01082 bool multiModify = false;
01083
01084 Incidence *inc = mActionItem->incidence();
01085
01086 mItemMoved = mItemMoved && !( mStartCell.x() == mEndCell.x() &&
01087 mStartCell.y() == mEndCell.y() );
01088 QPair<ResourceCalendar *, QString>p = mCalendarView->viewSubResourceCalendar();
01089
01090 if ( mItemMoved ) {
01091 Incidence *incToChange = inc;
01092 if ( mActionItem->incidence()->doesRecur() ) {
01093
01094 Incidence* oldIncSaved = inc->clone();
01095 KOGlobals::WhichOccurrences chosenOption;
01096 incToChange = mCalendarView->singleOccurrenceOrAll( inc,
01097 KOGlobals::EDIT,
01098 chosenOption,
01099 mActionItem->itemDate() );
01100
01101 if ( chosenOption == KOGlobals::ONLY_THIS_ONE ||
01102 chosenOption == KOGlobals::ONLY_FUTURE ) {
01103 multiModify = true;
01104 enableAgendaUpdate( false );
01105
01106 mChanger->addIncidence( incToChange, 0, QString(), this );
01107 enableAgendaUpdate( true );
01108 KOGlobals::WhatChanged wc = chosenOption == KOGlobals::ONLY_THIS_ONE ?
01109 KOGlobals::RECURRENCE_MODIFIED_ONE_ONLY :
01110 KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE;
01111
01112 mChanger->changeIncidence( oldIncSaved, inc, wc, this );
01113
01114 mActionItem->dissociateFromMultiItem();
01115 mActionItem->setIncidence( incToChange );
01116 }
01117 }
01118
01119 if ( incToChange ) {
01120 mActionItem->endMove();
01121 KOAgendaItem *placeItem = mActionItem->firstMultiItem();
01122 if ( !placeItem ) {
01123 placeItem = mActionItem;
01124 }
01125
01126 KOAgendaItem *modif = placeItem;
01127
01128 QPtrList<KOAgendaItem> oldconflictItems = placeItem->conflictItems();
01129 KOAgendaItem *item;
01130 for ( item = oldconflictItems.first(); item != 0;
01131 item = oldconflictItems.next() ) {
01132 placeSubCells( item );
01133 }
01134 while ( placeItem ) {
01135 placeSubCells( placeItem );
01136 placeItem = placeItem->nextMultiItem();
01137 }
01138
01139
01140
01141 mChanger->endChange( inc, p.first, p.second );
01142 emit itemModified( modif );
01143 } else {
01144
01145 mActionItem->resetMove();
01146 placeSubCells( mActionItem );
01147
01148
01149
01150 mChanger->endChange( inc, p.first, p.second );
01151 emit itemModified( mActionItem );
01152 }
01153 } else {
01154 mChanger->endChange( inc, p.first, p.second );
01155 }
01156
01157 mActionItem = 0;
01158 mItemMoved = false;
01159
01160 if ( multiModify ) {
01161 emit endMultiModify();
01162 }
01163
01164 kdDebug(5850) << "KOAgenda::endItemAction() done" << endl;
01165 }
01166
01167 void KOAgenda::setActionCursor( int actionType, bool acting )
01168 {
01169 switch ( actionType ) {
01170 case MOVE:
01171 if (acting) setCursor( sizeAllCursor );
01172 else setCursor( arrowCursor );
01173 break;
01174 case RESIZETOP:
01175 case RESIZEBOTTOM:
01176 setCursor( sizeVerCursor );
01177 break;
01178 case RESIZELEFT:
01179 case RESIZERIGHT:
01180 setCursor( sizeHorCursor );
01181 break;
01182 default:
01183 setCursor( arrowCursor );
01184 }
01185 }
01186
01187 void KOAgenda::setNoActionCursor( KOAgendaItem *moveItem, const QPoint& viewportPos )
01188 {
01189
01190
01191
01192
01193
01194
01195 QPoint pos = viewportToContents( viewportPos );
01196 bool noResize = (moveItem && moveItem->incidence() &&
01197 moveItem->incidence()->type() == "Todo");
01198
01199 KOAgenda::MouseActionType resizeType = MOVE;
01200 if ( !noResize ) resizeType = isInResizeArea( mAllDayMode, pos , moveItem);
01201 setActionCursor( resizeType );
01202 }
01203
01204
01207 double KOAgenda::calcSubCellWidth( KOAgendaItem *item )
01208 {
01209 QPoint pt, pt1;
01210 pt = gridToContents( QPoint( item->cellXLeft(), item->cellYTop() ) );
01211 pt1 = gridToContents( QPoint( item->cellXLeft(), item->cellYTop() ) +
01212 QPoint( 1, 1 ) );
01213 pt1 -= pt;
01214 int maxSubCells = item->subCells();
01215 double newSubCellWidth;
01216 if ( mAllDayMode ) {
01217 newSubCellWidth = double( pt1.y() ) / maxSubCells;
01218 } else {
01219 newSubCellWidth = double( pt1.x() ) / maxSubCells;
01220 }
01221 return newSubCellWidth;
01222 }
01223
01224 void KOAgenda::adjustItemPosition( KOAgendaItem *item )
01225 {
01226 if (!item) return;
01227 item->resize( int( mGridSpacingX * item->cellWidth() ),
01228 int( mGridSpacingY * item->cellHeight() ) );
01229 int clXLeft = item->cellXLeft();
01230 if ( KOGlobals::self()->reverseLayout() )
01231 clXLeft = item->cellXRight() + 1;
01232 QPoint cpos = gridToContents( QPoint( clXLeft, item->cellYTop() ) );
01233 moveChild( item, cpos.x(), cpos.y() );
01234 }
01235
01236 void KOAgenda::placeAgendaItem( KOAgendaItem *item, double subCellWidth )
01237 {
01238
01239
01240
01241
01242 QPoint pt = gridToContents( QPoint( item->cellXLeft(), item->cellYTop() ) );
01243
01244 QPoint pt1 = gridToContents( QPoint( item->cellXLeft() + item->cellWidth(),
01245 item->cellYBottom()+1 ) );
01246
01247 double subCellPos = item->subCell() * subCellWidth;
01248
01249
01250
01251 double delta=0.01;
01252 if (subCellWidth<0) delta=-delta;
01253 int height, width, xpos, ypos;
01254 if (mAllDayMode) {
01255 width = pt1.x()-pt.x();
01256 height = int( subCellPos + subCellWidth + delta ) - int( subCellPos );
01257 xpos = pt.x();
01258 ypos = pt.y() + int( subCellPos );
01259 } else {
01260 width = int( subCellPos + subCellWidth + delta ) - int( subCellPos );
01261 height = pt1.y()-pt.y();
01262 xpos = pt.x() + int( subCellPos );
01263 ypos = pt.y();
01264 }
01265 if ( KOGlobals::self()->reverseLayout() ) {
01266 xpos += width;
01267 width = -width;
01268 }
01269 if ( height<0 ) {
01270 ypos += height;
01271 height = -height;
01272 }
01273 item->resize( width, height );
01274 moveChild( item, xpos, ypos );
01275 }
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287 void KOAgenda::placeSubCells( KOAgendaItem *placeItem )
01288 {
01289 #if 0
01290 kdDebug(5850) << "KOAgenda::placeSubCells()" << endl;
01291 if ( placeItem ) {
01292 Incidence *event = placeItem->incidence();
01293 if ( !event ) {
01294 kdDebug(5850) << " event is 0" << endl;
01295 } else {
01296 kdDebug(5850) << " event: " << event->summary() << endl;
01297 }
01298 } else {
01299 kdDebug(5850) << " placeItem is 0" << endl;
01300 }
01301 kdDebug(5850) << "KOAgenda::placeSubCells()..." << endl;
01302 #endif
01303
01304 QPtrList<KOrg::CellItem> cells;
01305 KOAgendaItem *item;
01306 for ( item = mItems.first(); item != 0; item = mItems.next() ) {
01307 cells.append( item );
01308 }
01309
01310 QPtrList<KOrg::CellItem> items = KOrg::CellItem::placeItem( cells,
01311 placeItem );
01312
01313 placeItem->setConflictItems( QPtrList<KOAgendaItem>() );
01314 double newSubCellWidth = calcSubCellWidth( placeItem );
01315 KOrg::CellItem *i;
01316 for ( i = items.first(); i; i = items.next() ) {
01317 item = static_cast<KOAgendaItem *>( i );
01318 placeAgendaItem( item, newSubCellWidth );
01319 item->addConflictItem( placeItem );
01320 placeItem->addConflictItem( item );
01321 }
01322 if ( items.isEmpty() ) {
01323 placeAgendaItem( placeItem, newSubCellWidth );
01324 }
01325 placeItem->update();
01326 }
01327
01328 int KOAgenda::columnWidth( int column )
01329 {
01330 int start = gridToContents( QPoint( column, 0 ) ).x();
01331 if (KOGlobals::self()->reverseLayout() )
01332 column--;
01333 else
01334 column++;
01335 int end = gridToContents( QPoint( column, 0 ) ).x();
01336 return end - start;
01337 }
01338
01339
01340
01341 void KOAgenda::drawContents(QPainter* p, int cx, int cy, int cw, int ch)
01342 {
01343 QPixmap db(cw, ch);
01344 db.fill(KOPrefs::instance()->mAgendaBgColor);
01345 QPainter dbp(&db);
01346 dbp.translate(-cx,-cy);
01347
01348
01349 double lGridSpacingY = mGridSpacingY*2;
01350
01351
01352 if (mWorkingHoursEnable) {
01353 QPoint pt1( cx, mWorkingHoursYTop );
01354 QPoint pt2( cx+cw, mWorkingHoursYBottom );
01355 if ( pt2.x() >= pt1.x() ) {
01356 int gxStart = contentsToGrid( pt1 ).x();
01357 int gxEnd = contentsToGrid( pt2 ).x();
01358
01359 if ( gxStart > gxEnd ) {
01360 int tmp = gxStart;
01361 gxStart = gxEnd;
01362 gxEnd = tmp;
01363 }
01364 int xoffset = ( KOGlobals::self()->reverseLayout()?1:0 );
01365 while( gxStart <= gxEnd ) {
01366 int xStart = gridToContents( QPoint( gxStart+xoffset, 0 ) ).x();
01367 int xWidth = columnWidth( gxStart ) + 1;
01368 if ( pt2.y() < pt1.y() ) {
01369
01370 if ( ( (gxStart==0) && !mHolidayMask->at(mHolidayMask->count()-1) ) ||
01371 ( (gxStart>0) && (gxStart<int(mHolidayMask->count())) && (!mHolidayMask->at(gxStart-1) ) ) ) {
01372 if ( pt2.y() > cy ) {
01373 dbp.fillRect( xStart, cy, xWidth, pt2.y() - cy + 1,
01374 KOPrefs::instance()->mWorkingHoursColor);
01375 }
01376 }
01377 if ( (gxStart < int(mHolidayMask->count()-1)) && (!mHolidayMask->at(gxStart)) ) {
01378 if ( pt1.y() < cy + ch - 1 ) {
01379 dbp.fillRect( xStart, pt1.y(), xWidth, cy + ch - pt1.y() + 1,
01380 KOPrefs::instance()->mWorkingHoursColor);
01381 }
01382 }
01383 } else {
01384
01385 if ( gxStart < int(mHolidayMask->count()-1) && !mHolidayMask->at(gxStart)) {
01386 dbp.fillRect( xStart, pt1.y(), xWidth, pt2.y() - pt1.y() + 1,
01387 KOPrefs::instance()->mWorkingHoursColor );
01388 }
01389 }
01390 ++gxStart;
01391 }
01392 }
01393 }
01394
01395
01396 if ( mHasSelection ) {
01397 QPoint pt, pt1;
01398
01399 if ( mSelectionEndCell.x() > mSelectionStartCell.x() ) {
01400
01401 pt = gridToContents( mSelectionStartCell );
01402 pt1 = gridToContents( QPoint( mSelectionStartCell.x() + 1, mRows + 1 ) );
01403 dbp.fillRect( QRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor );
01404
01405 for ( int c = mSelectionStartCell.x() + 1; c < mSelectionEndCell.x(); ++c ) {
01406 pt = gridToContents( QPoint( c, 0 ) );
01407 pt1 = gridToContents( QPoint( c + 1, mRows + 1 ) );
01408 dbp.fillRect( QRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor );
01409 }
01410
01411 pt = gridToContents( QPoint( mSelectionEndCell.x(), 0 ) );
01412 pt1 = gridToContents( mSelectionEndCell + QPoint(1,1) );
01413 dbp.fillRect( QRect( pt, pt1), KOPrefs::instance()->mHighlightColor );
01414 } else {
01415 pt = gridToContents( mSelectionStartCell );
01416 pt1 = gridToContents( mSelectionEndCell + QPoint(1,1) );
01417 dbp.fillRect( QRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor );
01418 }
01419 }
01420
01421 QPen hourPen( KOPrefs::instance()->mAgendaBgColor.dark( 150 ) );
01422 QPen halfHourPen( KOPrefs::instance()->mAgendaBgColor.dark( 125 ) );
01423 dbp.setPen( hourPen );
01424
01425
01426
01427 double x = ( int( cx / mGridSpacingX ) ) * mGridSpacingX;
01428 while (x < cx + cw) {
01429 dbp.drawLine( int( x ), cy, int( x ), cy + ch );
01430 x+=mGridSpacingX;
01431 }
01432
01433
01434 double y = ( int( cy / (2*lGridSpacingY) ) ) * 2 * lGridSpacingY;
01435 while (y < cy + ch) {
01436
01437 dbp.drawLine( cx, int( y ), cx + cw, int( y ) );
01438 y += 2 * lGridSpacingY;
01439 }
01440 y = ( 2 * int( cy / (2*lGridSpacingY) ) + 1) * lGridSpacingY;
01441 dbp.setPen( halfHourPen );
01442 while (y < cy + ch) {
01443
01444 dbp.drawLine( cx, int( y ), cx + cw, int( y ) );
01445 y+=2*lGridSpacingY;
01446 }
01447 p->drawPixmap(cx,cy, db);
01448 }
01449
01450
01451
01452
01453 QPoint KOAgenda::contentsToGrid ( const QPoint &pos ) const
01454 {
01455 int gx = int( KOGlobals::self()->reverseLayout() ?
01456 mColumns - pos.x()/mGridSpacingX : pos.x()/mGridSpacingX );
01457 int gy = int( pos.y()/mGridSpacingY );
01458 return QPoint( gx, gy );
01459 }
01460
01461
01462
01463
01464 QPoint KOAgenda::gridToContents( const QPoint &gpos ) const
01465 {
01466 int x = int( KOGlobals::self()->reverseLayout() ?
01467 (mColumns - gpos.x())*mGridSpacingX : gpos.x()*mGridSpacingX );
01468 int y = int( gpos.y()*mGridSpacingY );
01469 return QPoint( x, y );
01470 }
01471
01472
01473
01474
01475
01476
01477 int KOAgenda::timeToY(const QTime &time)
01478 {
01479
01480 int minutesPerCell = 24 * 60 / mRows;
01481
01482 int timeMinutes = time.hour() * 60 + time.minute();
01483
01484 int Y = (timeMinutes + (minutesPerCell / 2)) / minutesPerCell;
01485
01486
01487 return Y;
01488 }
01489
01490
01491
01492
01493
01494
01495 QTime KOAgenda::gyToTime(int gy)
01496 {
01497
01498 int secondsPerCell = 24 * 60 * 60/ mRows;
01499
01500 int timeSeconds = secondsPerCell * gy;
01501
01502 QTime time( 0, 0, 0 );
01503 if ( timeSeconds < 24 * 60 * 60 ) {
01504 time = time.addSecs(timeSeconds);
01505 } else {
01506 time.setHMS( 23, 59, 59 );
01507 }
01508
01509
01510 return time;
01511 }
01512
01513 QMemArray<int> KOAgenda::minContentsY()
01514 {
01515 QMemArray<int> minArray;
01516 minArray.fill( timeToY( QTime(23, 59) ), mSelectedDates.count() );
01517 for ( KOAgendaItem *item = mItems.first();
01518 item != 0; item = mItems.next() ) {
01519 int ymin = item->cellYTop();
01520 int index = item->cellXLeft();
01521 if ( index>=0 && index<(int)(mSelectedDates.count()) ) {
01522 if ( ymin < minArray[index] && mItemsToDelete.findRef( item ) == -1 )
01523 minArray[index] = ymin;
01524 }
01525 }
01526
01527 return minArray;
01528 }
01529
01530 QMemArray<int> KOAgenda::maxContentsY()
01531 {
01532 QMemArray<int> maxArray;
01533 maxArray.fill( timeToY( QTime(0, 0) ), mSelectedDates.count() );
01534 for ( KOAgendaItem *item = mItems.first();
01535 item != 0; item = mItems.next() ) {
01536 int ymax = item->cellYBottom();
01537 int index = item->cellXLeft();
01538 if ( index>=0 && index<(int)(mSelectedDates.count()) ) {
01539 if ( ymax > maxArray[index] && mItemsToDelete.findRef( item ) == -1 )
01540 maxArray[index] = ymax;
01541 }
01542 }
01543
01544 return maxArray;
01545 }
01546
01547 void KOAgenda::setStartTime( const QTime &startHour )
01548 {
01549 double startPos = ( startHour.hour()/24. + startHour.minute()/1440. +
01550 startHour.second()/86400. ) * mRows * gridSpacingY();
01551 setContentsPos( 0, int( startPos ) );
01552 }
01553
01554
01555
01556
01557
01558 KOAgendaItem *KOAgenda::insertItem( Incidence *incidence, const QDate &qd, int X,
01559 int YTop, int YBottom )
01560 {
01561 #if 0
01562 kdDebug(5850) << "KOAgenda::insertItem:" << incidence->summary() << "-"
01563 << qd.toString() << " ;top, bottom:" << YTop << "," << YBottom
01564 << endl;
01565 #endif
01566
01567 if ( mAllDayMode ) {
01568 kdDebug(5850) << "KOAgenda: calling insertItem in all-day mode is illegal." << endl;
01569 return 0;
01570 }
01571
01572
01573 mActionType = NOP;
01574
01575 KOAgendaItem *agendaItem = new KOAgendaItem( mCalendar, incidence, qd, viewport() );
01576 connect( agendaItem, SIGNAL( removeAgendaItem( KOAgendaItem * ) ),
01577 SLOT( removeAgendaItem( KOAgendaItem * ) ) );
01578 connect( agendaItem, SIGNAL( showAgendaItem( KOAgendaItem * ) ),
01579 SLOT( showAgendaItem( KOAgendaItem * ) ) );
01580
01581 if ( YBottom <= YTop ) {
01582 kdDebug(5850) << "KOAgenda::insertItem(): Text: " << agendaItem->text() << " YSize<0" << endl;
01583 YBottom = YTop;
01584 }
01585
01586 agendaItem->resize( int( ( X + 1 ) * mGridSpacingX ) -
01587 int( X * mGridSpacingX ),
01588 int( YTop * mGridSpacingY ) -
01589 int( ( YBottom + 1 ) * mGridSpacingY ) );
01590 agendaItem->setCellXY( X, YTop, YBottom );
01591 agendaItem->setCellXRight( X );
01592 agendaItem->setResourceColor( KOHelper::resourceColor( mCalendar, incidence ) );
01593 agendaItem->installEventFilter( this );
01594
01595 addChild( agendaItem, int( X * mGridSpacingX ), int( YTop * mGridSpacingY ) );
01596 mItems.append( agendaItem );
01597
01598 placeSubCells( agendaItem );
01599
01600 agendaItem->show();
01601
01602 marcus_bains();
01603
01604 return agendaItem;
01605 }
01606
01607
01608
01609
01610 KOAgendaItem *KOAgenda::insertAllDayItem( Incidence *event, const QDate &qd,
01611 int XBegin, int XEnd )
01612 {
01613 if ( !mAllDayMode ) {
01614 kdDebug(5850) << "KOAgenda: calling insertAllDayItem in non all-day mode is illegal." << endl;
01615 return 0;
01616 }
01617
01618 mActionType = NOP;
01619
01620 KOAgendaItem *agendaItem = new KOAgendaItem( mCalendar, event, qd, viewport() );
01621 connect( agendaItem, SIGNAL( removeAgendaItem( KOAgendaItem* ) ),
01622 SLOT( removeAgendaItem( KOAgendaItem* ) ) );
01623 connect( agendaItem, SIGNAL( showAgendaItem( KOAgendaItem* ) ),
01624 SLOT( showAgendaItem( KOAgendaItem* ) ) );
01625
01626 agendaItem->setCellXY( XBegin, 0, 0 );
01627 agendaItem->setCellXRight( XEnd );
01628
01629 double startIt = mGridSpacingX * ( agendaItem->cellXLeft() );
01630 double endIt = mGridSpacingX * ( agendaItem->cellWidth() +
01631 agendaItem->cellXLeft() );
01632
01633 agendaItem->resize( int( endIt ) - int( startIt ), int( mGridSpacingY ) );
01634
01635 agendaItem->installEventFilter( this );
01636 agendaItem->setResourceColor( KOHelper::resourceColor( mCalendar, event ) );
01637 addChild( agendaItem, int( XBegin * mGridSpacingX ), 0 );
01638 mItems.append( agendaItem );
01639
01640 placeSubCells( agendaItem );
01641
01642 agendaItem->show();
01643
01644 return agendaItem;
01645 }
01646
01647
01648 void KOAgenda::insertMultiItem (Event *event,const QDate &qd,int XBegin,int XEnd,
01649 int YTop,int YBottom)
01650 {
01651 if (mAllDayMode) {
01652 kdDebug(5850) << "KOAgenda: calling insertMultiItem in all-day mode is illegal." << endl;
01653 return;
01654 }
01655 mActionType = NOP;
01656
01657 int cellX,cellYTop,cellYBottom;
01658 QString newtext;
01659 int width = XEnd - XBegin + 1;
01660 int count = 0;
01661 KOAgendaItem *current = 0;
01662 QPtrList<KOAgendaItem> multiItems;
01663 int visibleCount = mSelectedDates.first().daysTo(mSelectedDates.last());
01664 for ( cellX = XBegin; cellX <= XEnd; ++cellX ) {
01665 ++count;
01666
01667 if( cellX >=0 && cellX <= visibleCount ) {
01668 if ( cellX == XBegin ) cellYTop = YTop;
01669 else cellYTop = 0;
01670 if ( cellX == XEnd ) cellYBottom = YBottom;
01671 else cellYBottom = rows() - 1;
01672 newtext = QString("(%1/%2): ").arg( count ).arg( width );
01673 newtext.append( event->summary() );
01674
01675 current = insertItem( event, qd, cellX, cellYTop, cellYBottom );
01676 current->setText( newtext );
01677 multiItems.append( current );
01678 }
01679 }
01680
01681 KOAgendaItem *next = 0;
01682 KOAgendaItem *prev = 0;
01683 KOAgendaItem *last = multiItems.last();
01684 KOAgendaItem *first = multiItems.first();
01685 KOAgendaItem *setFirst,*setLast;
01686 current = first;
01687 while (current) {
01688 next = multiItems.next();
01689 if (current == first) setFirst = 0;
01690 else setFirst = first;
01691 if (current == last) setLast = 0;
01692 else setLast = last;
01693
01694 current->setMultiItem(setFirst, prev, next, setLast);
01695 prev=current;
01696 current = next;
01697 }
01698
01699 marcus_bains();
01700 }
01701
01702 void KOAgenda::removeIncidence( Incidence *incidence )
01703 {
01704
01705
01706
01707 QPtrList<KOAgendaItem> itemsToRemove;
01708
01709 KOAgendaItem *item = mItems.first();
01710 while ( item ) {
01711 if ( item->incidence() == incidence ) {
01712 itemsToRemove.append( item );
01713 }
01714 item = mItems.next();
01715 }
01716 item = itemsToRemove.first();
01717 while ( item ) {
01718 removeAgendaItem( item );
01719 item = itemsToRemove.next();
01720 }
01721 }
01722
01723 void KOAgenda::showAgendaItem( KOAgendaItem *agendaItem )
01724 {
01725 if ( !agendaItem ) return;
01726 agendaItem->hide();
01727 addChild( agendaItem );
01728 if ( !mItems.containsRef( agendaItem ) )
01729 mItems.append( agendaItem );
01730 placeSubCells( agendaItem );
01731
01732 agendaItem->show();
01733 }
01734
01735 bool KOAgenda::removeAgendaItem( KOAgendaItem *item )
01736 {
01737
01738 bool taken = false;
01739 KOAgendaItem *thisItem = item;
01740 QPtrList<KOAgendaItem> conflictItems = thisItem->conflictItems();
01741 removeChild( thisItem );
01742 int pos = mItems.find( thisItem );
01743 if ( pos>=0 ) {
01744 mItems.take( pos );
01745 taken = true;
01746 }
01747
01748 KOAgendaItem *confitem;
01749 for ( confitem = conflictItems.first(); confitem != 0;
01750 confitem = conflictItems.next() ) {
01751
01752 if ( confitem != thisItem ) placeSubCells(confitem);
01753
01754 }
01755 mItemsToDelete.append( thisItem );
01756 QTimer::singleShot( 0, this, SLOT( deleteItemsToDelete() ) );
01757 return taken;
01758 }
01759
01760 void KOAgenda::deleteItemsToDelete()
01761 {
01762 mItemsToDelete.clear();
01763 }
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783 void KOAgenda::resizeEvent ( QResizeEvent *ev )
01784 {
01785
01786
01787 QSize newSize( ev->size() );
01788 if (mAllDayMode) {
01789 mGridSpacingX = double( newSize.width() - 2 * frameWidth() ) / (double)mColumns;
01790 mGridSpacingY = newSize.height() - 2 * frameWidth();
01791 } else {
01792 int scrollbarWidth = vScrollBarMode() != AlwaysOff ? verticalScrollBar()->width() : 0;
01793 mGridSpacingX = double( newSize.width() - scrollbarWidth - 2 * frameWidth()) / double(mColumns);
01794
01795 mGridSpacingY = double(newSize.height() - 2 * frameWidth()) / double(mRows);
01796 if ( mGridSpacingY < mDesiredGridSpacingY )
01797 mGridSpacingY = mDesiredGridSpacingY;
01798 }
01799 calculateWorkingHours();
01800 QTimer::singleShot( 0, this, SLOT( resizeAllContents() ) );
01801 emit gridSpacingYChanged( mGridSpacingY * 4 );
01802 QScrollView::resizeEvent(ev);
01803 }
01804
01805 void KOAgenda::resizeAllContents()
01806 {
01807 double subCellWidth;
01808 if ( mItems.count() > 0 ) {
01809 KOAgendaItem *item;
01810 if (mAllDayMode) {
01811 for ( item=mItems.first(); item != 0; item=mItems.next() ) {
01812 subCellWidth = calcSubCellWidth( item );
01813 placeAgendaItem( item, subCellWidth );
01814 }
01815 } else {
01816 for ( item=mItems.first(); item != 0; item=mItems.next() ) {
01817 subCellWidth = calcSubCellWidth( item );
01818 placeAgendaItem( item, subCellWidth );
01819 }
01820 }
01821 }
01822 checkScrollBoundaries();
01823 marcus_bains();
01824 }
01825
01826 void KOAgenda::scrollUp()
01827 {
01828 scrollBy(0,-mScrollOffset);
01829 }
01830
01831
01832 void KOAgenda::scrollDown()
01833 {
01834 scrollBy(0,mScrollOffset);
01835 }
01836
01837
01838
01839
01840
01841 int KOAgenda::minimumWidth() const
01842 {
01843
01844 int min = 100;
01845
01846 return min;
01847 }
01848
01849 void KOAgenda::updateConfig()
01850 {
01851 double oldGridSpacingY = mGridSpacingY;
01852
01853 mDesiredGridSpacingY = KOPrefs::instance()->mHourSize;
01854 if ( mDesiredGridSpacingY < 4 || mDesiredGridSpacingY > 30 ) {
01855 mDesiredGridSpacingY = 10;
01856 }
01857
01858
01859 mGridSpacingY = (double)height() / (double)mRows;
01860 if ( mGridSpacingY < mDesiredGridSpacingY ) {
01861 mGridSpacingY = mDesiredGridSpacingY;
01862 }
01863
01864
01865 if ( fabs( oldGridSpacingY - mGridSpacingY ) > 0.1 ) {
01866 resizeContents( int( mGridSpacingX * mColumns ),
01867 int( mGridSpacingY * mRows ) );
01868 }
01869
01870 calculateWorkingHours();
01871
01872 marcus_bains();
01873 }
01874
01875 void KOAgenda::checkScrollBoundaries()
01876 {
01877
01878 mOldLowerScrollValue = -1;
01879 mOldUpperScrollValue = -1;
01880
01881 checkScrollBoundaries(verticalScrollBar()->value());
01882 }
01883
01884 void KOAgenda::checkScrollBoundaries( int v )
01885 {
01886 int yMin = int( (v) / mGridSpacingY );
01887 int yMax = int( ( v + visibleHeight() ) / mGridSpacingY );
01888
01889
01890
01891 if ( yMin != mOldLowerScrollValue ) {
01892 mOldLowerScrollValue = yMin;
01893 emit lowerYChanged(yMin);
01894 }
01895 if ( yMax != mOldUpperScrollValue ) {
01896 mOldUpperScrollValue = yMax;
01897 emit upperYChanged(yMax);
01898 }
01899 }
01900
01901 int KOAgenda::visibleContentsYMin()
01902 {
01903 int v = verticalScrollBar()->value();
01904 return int( v / mGridSpacingY );
01905 }
01906
01907 int KOAgenda::visibleContentsYMax()
01908 {
01909 int v = verticalScrollBar()->value();
01910 return int( ( v + visibleHeight() ) / mGridSpacingY );
01911 }
01912
01913 void KOAgenda::deselectItem()
01914 {
01915 if (mSelectedItem.isNull()) return;
01916 mSelectedItem->select(false);
01917 mSelectedItem = 0;
01918 }
01919
01920 void KOAgenda::selectItem(KOAgendaItem *item)
01921 {
01922 if ((KOAgendaItem *)mSelectedItem == item) return;
01923 deselectItem();
01924 if (item == 0) {
01925 emit incidenceSelected( 0, QDate() );
01926 return;
01927 }
01928 mSelectedItem = item;
01929 mSelectedItem->select();
01930 assert( mSelectedItem->incidence() );
01931 mSelectedUid = mSelectedItem->incidence()->uid();
01932 emit incidenceSelected( mSelectedItem->incidence(), mSelectedItem->itemDate() );
01933 }
01934
01935 void KOAgenda::selectItemByUID( const QString& uid )
01936 {
01937 KOAgendaItem *item;
01938 for ( item = mItems.first(); item != 0; item = mItems.next() ) {
01939 if( item->incidence() && item->incidence()->uid() == uid ) {
01940 selectItem( item );
01941 break;
01942 }
01943 }
01944 }
01945
01946
01947 void KOAgenda::keyPressEvent( QKeyEvent *kev )
01948 {
01949 switch(kev->key()) {
01950 case Key_PageDown:
01951 verticalScrollBar()->addPage();
01952 break;
01953 case Key_PageUp:
01954 verticalScrollBar()->subtractPage();
01955 break;
01956 case Key_Down:
01957 verticalScrollBar()->addLine();
01958 break;
01959 case Key_Up:
01960 verticalScrollBar()->subtractLine();
01961 break;
01962 default:
01963 ;
01964 }
01965 }
01966
01967 void KOAgenda::calculateWorkingHours()
01968 {
01969 mWorkingHoursEnable = !mAllDayMode;
01970
01971 QTime tmp = KOPrefs::instance()->mWorkingHoursStart.time();
01972 mWorkingHoursYTop = int( 4 * mGridSpacingY *
01973 ( tmp.hour() + tmp.minute() / 60. +
01974 tmp.second() / 3600. ) );
01975 tmp = KOPrefs::instance()->mWorkingHoursEnd.time();
01976 mWorkingHoursYBottom = int( 4 * mGridSpacingY *
01977 ( tmp.hour() + tmp.minute() / 60. +
01978 tmp.second() / 3600. ) - 1 );
01979 }
01980
01981
01982 DateList KOAgenda::dateList() const
01983 {
01984 return mSelectedDates;
01985 }
01986
01987 void KOAgenda::setDateList(const DateList &selectedDates)
01988 {
01989 mSelectedDates = selectedDates;
01990 marcus_bains();
01991 }
01992
01993 void KOAgenda::setHolidayMask(QMemArray<bool> *mask)
01994 {
01995 mHolidayMask = mask;
01996
01997 }
01998
01999 void KOAgenda::contentsMousePressEvent ( QMouseEvent *event )
02000 {
02001 kdDebug(5850) << "KOagenda::contentsMousePressEvent(): type: " << event->type() << endl;
02002 QScrollView::contentsMousePressEvent(event);
02003 }
02004
02005 void KOAgenda::setTypeAheadReceiver( QObject *o )
02006 {
02007 mTypeAheadReceiver = o;
02008 }
02009
02010 QObject *KOAgenda::typeAheadReceiver() const
02011 {
02012 return mTypeAheadReceiver;
02013 }