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