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