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