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