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