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