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