00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kdganttitemdelegate_p.h"
00024 #include "kdganttglobal.h"
00025 #include "kdganttstyleoptionganttitem.h"
00026 #include "kdganttconstraint.h"
00027
00028 #include <QPainter>
00029 #include <QPainterPath>
00030 #include <QPen>
00031 #include <QModelIndex>
00032 #include <QAbstractItemModel>
00033 #include <QApplication>
00034
00035 #ifndef QT_NO_DEBUG_STREAM
00036
00037 #define PRINT_INTERACTIONSTATE(x) \
00038 case x: dbg << #x; break;
00039
00040
00041 QDebug operator<<( QDebug dbg, KDGantt::ItemDelegate::InteractionState state )
00042 {
00043 switch( state ) {
00044 PRINT_INTERACTIONSTATE( KDGantt::ItemDelegate::State_None );
00045 PRINT_INTERACTIONSTATE( KDGantt::ItemDelegate::State_Move );
00046 PRINT_INTERACTIONSTATE( KDGantt::ItemDelegate::State_ExtendLeft );
00047 PRINT_INTERACTIONSTATE( KDGantt::ItemDelegate::State_ExtendRight );
00048 default:
00049 break;
00050 }
00051 return dbg;
00052 }
00053
00054 #undef PRINT_INTERACTIONSTATE
00055
00056 #endif
00057
00058 using namespace KDGantt;
00059
00073 ItemDelegate::Private::Private()
00074 {
00075
00076 QLinearGradient taskgrad( 0., 0., 0., QApplication::fontMetrics().height() );
00077 taskgrad.setColorAt( 0., Qt::green );
00078 taskgrad.setColorAt( 1., Qt::darkGreen );
00079
00080 QLinearGradient summarygrad( 0., 0., 0., QApplication::fontMetrics().height() );
00081 summarygrad.setColorAt( 0., Qt::blue );
00082 summarygrad.setColorAt( 1., Qt::darkBlue );
00083
00084 QLinearGradient eventgrad( 0., 0., 0., QApplication::fontMetrics().height() );
00085 eventgrad.setColorAt( 0., Qt::red );
00086 eventgrad.setColorAt( 1., Qt::darkRed );
00087
00088 defaultbrush[TypeTask] = taskgrad;
00089 defaultbrush[TypeSummary] = summarygrad;
00090 defaultbrush[TypeEvent] = eventgrad;
00091
00092
00093 QPen pen( Qt::black, 1. );
00094
00095 defaultpen[TypeTask] = pen;
00096 defaultpen[TypeSummary] = pen;
00097 defaultpen[TypeEvent] = pen;
00098 }
00099
00101 ItemDelegate::ItemDelegate( QObject* parent )
00102 : QItemDelegate( parent ), _d( new Private )
00103 {
00104 }
00105
00107 ItemDelegate::~ItemDelegate()
00108 {
00109 delete _d;
00110 }
00111
00112 #define d d_func()
00113
00120 void ItemDelegate::setDefaultBrush( ItemType type, const QBrush& brush )
00121 {
00122 d->defaultbrush[type] = brush;
00123 }
00124
00129 QBrush ItemDelegate::defaultBrush( ItemType type ) const
00130 {
00131 return d->defaultbrush[type];
00132 }
00133
00140 void ItemDelegate::setDefaultPen( ItemType type, const QPen& pen )
00141 {
00142 d->defaultpen[type]=pen;
00143 }
00144
00149 QPen ItemDelegate::defaultPen( ItemType type ) const
00150 {
00151 return d->defaultpen[type];
00152 }
00153
00162 Span ItemDelegate::itemBoundingSpan( const StyleOptionGanttItem& opt,
00163 const QModelIndex& idx ) const
00164 {
00165
00166 if ( !idx.isValid() ) return Span();
00167
00168 QString txt = idx.model()->data( idx, Qt::DisplayRole ).toString();
00169 int typ = idx.model()->data( idx, ItemTypeRole ).toInt();
00170 QRectF itemRect = opt.itemRect;
00171
00172
00173 if ( typ == TypeEvent ) itemRect = QRectF( itemRect.left()-itemRect.height()/2.,
00174 itemRect.top(),
00175 itemRect.height(),
00176 itemRect.height() );
00177
00178 int tw = opt.fontMetrics.width( txt );
00179 tw += static_cast<int>( itemRect.height()/2. );
00180 switch ( opt.displayPosition ) {
00181 case StyleOptionGanttItem::Left:
00182 return Span( itemRect.left()-tw, itemRect.width()+tw );
00183 case StyleOptionGanttItem::Right:
00184 return Span( itemRect.left(), itemRect.width()+tw );
00185 case StyleOptionGanttItem::Center:
00186 return Span( itemRect.left(), itemRect.width() );
00187 }
00188 return Span();
00189 }
00190
00197 ItemDelegate::InteractionState ItemDelegate::interactionStateFor( const QPointF& pos,
00198 const StyleOptionGanttItem& opt,
00199 const QModelIndex& idx ) const
00200 {
00201 if ( !idx.isValid() ) return State_None;
00202 if ( !( idx.model()->flags( idx ) & Qt::ItemIsEditable ) ) return State_None;
00203
00204 int typ = static_cast<ItemType>( idx.model()->data( idx, ItemTypeRole ).toInt() );
00205 if ( typ == TypeNone || typ == TypeSummary ) return State_None;
00206 if ( typ == TypeEvent ) return State_Move;
00207 if ( !opt.itemRect.contains(pos) ) return State_None;
00208
00209 qreal delta = 5.;
00210 if ( opt.itemRect.width() < 15 ) delta = 1.;
00211 if( pos.x() >= opt.itemRect.left() && pos.x() < opt.itemRect.left()+delta ) {
00212 return State_ExtendLeft;
00213 } else if( pos.x() <= opt.itemRect.right() && pos.x() > opt.itemRect.right()-delta ) {
00214 return State_ExtendRight;
00215 } else {
00216 return State_Move;
00217 }
00218 }
00219
00222 void ItemDelegate::paintGanttItem( QPainter* painter,
00223 const StyleOptionGanttItem& opt,
00224 const QModelIndex& idx )
00225 {
00226 if ( !idx.isValid() ) return;
00227 const ItemType typ = static_cast<ItemType>( idx.model()->data( idx, ItemTypeRole ).toInt() );
00228 const QString& txt = opt.text;
00229 QRectF itemRect = opt.itemRect;
00230 QRectF boundingRect = opt.boundingRect;
00231 boundingRect.setY( itemRect.y() );
00232 boundingRect.setHeight( itemRect.height() );
00233
00234
00235 painter->save();
00236
00237 QPen pen = defaultPen( typ );
00238 if ( opt.state & QStyle::State_Selected ) pen.setWidth( 2*pen.width() );
00239 painter->setPen( pen );
00240 painter->setBrush( defaultBrush( typ ) );
00241
00242 qreal pw = painter->pen().width()/2.;
00243 switch( typ ) {
00244 case TypeTask:
00245 if ( itemRect.isValid() ) {
00246
00247 qreal pw = painter->pen().width()/2.;
00248 pw-=1;
00249 QRectF r = itemRect;
00250 r.translate( 0., r.height()/6. );
00251 r.setHeight( 2.*r.height()/3. );
00252 painter->setBrushOrigin( itemRect.topLeft() );
00253 painter->save();
00254 painter->translate( 0.5, 0.5 );
00255 painter->drawRect( r );
00256 bool ok;
00257 qreal completion = idx.model()->data( idx, KDGantt::TaskCompletionRole ).toDouble( &ok );
00258 if ( ok ) {
00259 qreal h = r.height();
00260 QRectF cr( r.x(), r.y()+h/4.,
00261 r.width()*completion/100., h/2.+1 );
00262 painter->fillRect( cr, painter->pen().brush() );
00263 }
00264 painter->restore();
00265 Qt::Alignment ta;
00266 switch( opt.displayPosition ) {
00267 case StyleOptionGanttItem::Left: ta = Qt::AlignLeft; break;
00268 case StyleOptionGanttItem::Right: ta = Qt::AlignRight; break;
00269 case StyleOptionGanttItem::Center: ta = Qt::AlignCenter; break;
00270 }
00271 painter->drawText( boundingRect, ta, txt );
00272 }
00273 break;
00274 case TypeSummary:
00275 if ( opt.itemRect.isValid() ) {
00276
00277 pw-=1;
00278 const QRectF r = QRectF( opt.itemRect ).adjusted( -pw, -pw, pw, pw );
00279 QPainterPath path;
00280 const qreal delta = r.height()/2.;
00281 path.moveTo( r.topLeft() );
00282 path.lineTo( r.topRight() );
00283 path.lineTo( QPointF( r.right(), r.top() + 2.*delta ) );
00284
00285 path.quadTo( QPointF( r.right()-.5*delta, r.top() + delta ), QPointF( r.right()-2.*delta, r.top() + delta ) );
00286
00287 path.lineTo( QPointF( r.left() + 2.*delta, r.top() + delta ) );
00288 path.quadTo( QPointF( r.left()+.5*delta, r.top() + delta ), QPointF( r.left(), r.top() + 2.*delta ) );
00289 path.closeSubpath();
00290 painter->setBrushOrigin( itemRect.topLeft() );
00291 painter->save();
00292 painter->translate( 0.5, 0.5 );
00293 painter->drawPath( path );
00294 painter->restore();
00295 Qt::Alignment ta;
00296 switch( opt.displayPosition ) {
00297 case StyleOptionGanttItem::Left: ta = Qt::AlignLeft; break;
00298 case StyleOptionGanttItem::Right: ta = Qt::AlignRight; break;
00299 case StyleOptionGanttItem::Center: ta = Qt::AlignCenter; break;
00300 }
00301 painter->drawText( boundingRect, ta | Qt::AlignVCenter, txt );
00302 }
00303 break;
00304 case TypeEvent:
00305
00306 if ( opt.boundingRect.isValid() ) {
00307 const qreal pw = painter->pen().width() / 2. - 1;
00308 const QRectF r = QRectF( opt.rect ).adjusted( -pw, -pw, pw, pw );
00309 QPainterPath path;
00310 const qreal delta = static_cast< int >( r.height() / 2 );
00311 path.moveTo( delta, 0. );
00312 path.lineTo( 2.*delta, delta );
00313 path.lineTo( delta, 2.*delta );
00314 path.lineTo( 0., delta );
00315 path.closeSubpath();
00316 painter->save();
00317 painter->translate( r.topLeft() );
00318 painter->translate( 0.5, 0.5 );
00319 painter->drawPath( path );
00320 painter->restore();
00321 Qt::Alignment ta;
00322 switch( opt.displayPosition ) {
00323 case StyleOptionGanttItem::Left: ta = Qt::AlignLeft; break;
00324 case StyleOptionGanttItem::Right: ta = Qt::AlignRight; break;
00325 case StyleOptionGanttItem::Center: ta = Qt::AlignCenter; break;
00326 }
00327 painter->drawText( boundingRect, ta | Qt::AlignVCenter, txt );
00328 }
00329 break;
00330 default:
00331 break;
00332 }
00333 painter->restore();
00334 }
00335
00336 static const qreal TURN = 10.;
00337 static const qreal PW = 1.5;
00338
00343 QRectF ItemDelegate::constraintBoundingRect( const QPointF& start, const QPointF& end, const Constraint &constraint ) const
00344 {
00345 QPolygonF poly;
00346 switch ( constraint.relationType() ) {
00347 case Constraint::FinishStart:
00348 poly = finishStartLine( start, end ) + finishStartArrow( start, end );
00349 break;
00350 case Constraint::FinishFinish:
00351 poly = finishFinishLine( start, end ) + finishFinishArrow( start, end );
00352 break;
00353 case Constraint::StartStart:
00354 poly = startStartLine( start, end ) + startStartArrow( start, end );
00355 break;
00356 case Constraint::StartFinish:
00357 poly = startFinishLine( start, end ) + startFinishArrow( start, end );
00358 break;
00359 default:
00360 break;
00361 }
00362 return poly.boundingRect().adjusted( -PW, -PW, PW, PW );
00363 }
00364
00365
00371 void ItemDelegate::paintConstraintItem( QPainter* painter, const QStyleOptionGraphicsItem& opt,
00372 const QPointF& start, const QPointF& end, const Constraint &constraint )
00373 {
00374
00375 switch ( constraint.relationType() ) {
00376 case Constraint::FinishStart:
00377 paintFinishStartConstraint( painter, opt, start, end, constraint );
00378 break;
00379 case Constraint::FinishFinish:
00380 paintFinishFinishConstraint( painter, opt, start, end, constraint );
00381 break;
00382 case Constraint::StartStart:
00383 paintStartStartConstraint( painter, opt, start, end, constraint );
00384 break;
00385 case Constraint::StartFinish:
00386 paintStartFinishConstraint( painter, opt, start, end, constraint );
00387 break;
00388 default:
00389 break;
00390 }
00391 }
00392
00393 void ItemDelegate::paintFinishStartConstraint( QPainter* painter, const QStyleOptionGraphicsItem& opt, const QPointF& start, const QPointF& end, const Constraint &constraint )
00394 {
00395 Q_UNUSED( opt );
00396
00397 QPen pen;
00398 QVariant dataPen;
00399
00400
00401 if ( start.x() <= end.x() ) {
00402 pen = QPen( Qt::black );
00403 dataPen = constraint.data( Constraint::ValidConstraintPen );
00404 } else {
00405 pen = QPen( Qt::red );
00406 dataPen = constraint.data( Constraint::InvalidConstraintPen );
00407 }
00408
00409
00410 if( qVariantCanConvert< QPen >( dataPen ) )
00411 pen = qVariantValue< QPen >( dataPen );
00412
00413 painter->setPen( pen );
00414 painter->setBrush( pen.color() );
00415
00416 painter->drawPolyline( finishStartLine( start, end ) );
00417 painter->drawPolygon( finishStartArrow( start, end ) );
00418 }
00419
00420 QPolygonF ItemDelegate::finishStartLine( const QPointF& start, const QPointF& end ) const
00421 {
00422 QPolygonF poly;
00423 qreal midx = end.x() - TURN;
00424 qreal midy = ( end.y()-start.y() )/2. + start.y();
00425
00426 if ( start.x() > end.x()-TURN ) {
00427 poly << start
00428 << QPointF( start.x()+TURN, start.y() )
00429 << QPointF( start.x()+TURN, midy )
00430 << QPointF( end.x()-TURN, midy )
00431 << QPointF( end.x()-TURN, end.y() )
00432 << end;
00433 } else {
00434 poly << start
00435 << QPointF( midx, start.y() )
00436 << QPointF( midx, end.y() )
00437 << end;
00438 }
00439 return poly;
00440 }
00441
00442 QPolygonF ItemDelegate::finishStartArrow( const QPointF& start, const QPointF& end ) const
00443 {
00444 QPolygonF poly;
00445 poly << end
00446 << QPointF( end.x()-TURN/2., end.y()-TURN/2. )
00447 << QPointF( end.x()-TURN/2., end.y()+TURN/2. );
00448 return poly;
00449 }
00450
00451 void ItemDelegate::paintFinishFinishConstraint( QPainter* painter, const QStyleOptionGraphicsItem& opt, const QPointF& start, const QPointF& end, const Constraint &constraint )
00452 {
00453 Q_UNUSED( opt );
00454
00455 QPen pen;
00456 QVariant dataPen;
00457
00458
00459 if ( start.x() <= end.x() ) {
00460 pen = QPen( Qt::black );
00461 dataPen = constraint.data( Constraint::ValidConstraintPen );
00462 } else {
00463 pen = QPen( Qt::red );
00464 dataPen = constraint.data( Constraint::InvalidConstraintPen );
00465 }
00466
00467
00468 if( qVariantCanConvert< QPen >( dataPen ) )
00469 pen = qVariantValue< QPen >( dataPen );
00470
00471 painter->setPen( pen );
00472 painter->setBrush( pen.color() );
00473
00474 painter->drawPolyline( finishFinishLine( start, end ) );
00475 painter->drawPolygon( finishFinishArrow( start, end ) );
00476 }
00477
00478 QPolygonF ItemDelegate::finishFinishLine( const QPointF& start, const QPointF& end ) const
00479 {
00480 QPolygonF poly;
00481 qreal midx = end.x() + TURN;
00482 qreal midy = ( end.y()-start.y() )/2. + start.y();
00483
00484 if ( start.x() > end.x()+TURN ) {
00485 poly << start
00486 << QPointF( start.x()+TURN, start.y() )
00487 << QPointF( start.x()+TURN, end.y() )
00488 << end;
00489 } else {
00490 poly << start
00491 << QPointF( midx, start.y() )
00492 << QPointF( midx, midy )
00493 << QPointF( end.x()+TURN, midy )
00494 << QPointF( end.x()+TURN, end.y() )
00495 << end;
00496 }
00497 return poly;
00498 }
00499
00500 QPolygonF ItemDelegate::finishFinishArrow( const QPointF& start, const QPointF& end ) const
00501 {
00502 QPolygonF poly;
00503 poly << end
00504 << QPointF( end.x()+TURN/2., end.y()-TURN/2. )
00505 << QPointF( end.x()+TURN/2., end.y()+TURN/2. );
00506 return poly;
00507 }
00508
00509 void ItemDelegate::paintStartStartConstraint( QPainter* painter, const QStyleOptionGraphicsItem& opt, const QPointF& start, const QPointF& end, const Constraint &constraint )
00510 {
00511 Q_UNUSED( opt );
00512
00513 QPen pen;
00514 QVariant dataPen;
00515
00516
00517 if ( start.x() <= end.x() ) {
00518 pen = QPen( Qt::black );
00519 dataPen = constraint.data( Constraint::ValidConstraintPen );
00520 } else {
00521 pen = QPen( Qt::red );
00522 dataPen = constraint.data( Constraint::InvalidConstraintPen );
00523 }
00524
00525
00526 if( qVariantCanConvert< QPen >( dataPen ) )
00527 pen = qVariantValue< QPen >( dataPen );
00528
00529 painter->setPen( pen );
00530 painter->setBrush( pen.color() );
00531
00532 painter->drawPolyline( startStartLine( start, end ) );
00533 painter->drawPolygon( startStartArrow( start, end ) );
00534
00535 }
00536
00537 QPolygonF ItemDelegate::startStartLine( const QPointF& start, const QPointF& end ) const
00538 {
00539 QPolygonF poly;
00540 qreal midx = start.x() - TURN;
00541 qreal midy = ( end.y()-start.y() )/2. + start.y();
00542
00543 if ( start.x() > end.x() ) {
00544 poly << start
00545 << QPointF( end.x()-TURN, start.y() )
00546 << QPointF( end.x()-TURN, end.y() )
00547 << end;
00548 } else {
00549 poly << start
00550 << QPointF( start.x()-TURN, start.y() )
00551 << QPointF( start.x()-TURN, end.y() )
00552 << QPointF( end.x()-TURN, end.y() )
00553 << end;
00554 }
00555 return poly;
00556 }
00557
00558 QPolygonF ItemDelegate::startStartArrow( const QPointF& start, const QPointF& end ) const
00559 {
00560 QPolygonF poly;
00561 poly << end
00562 << QPointF( end.x()-TURN/2., end.y()-TURN/2. )
00563 << QPointF( end.x()-TURN/2., end.y()+TURN/2. );
00564 return poly;
00565 }
00566
00567 void ItemDelegate::paintStartFinishConstraint( QPainter* painter, const QStyleOptionGraphicsItem& opt, const QPointF& start, const QPointF& end, const Constraint &constraint )
00568 {
00569 Q_UNUSED( opt );
00570
00571 QPen pen;
00572 QVariant dataPen;
00573
00574
00575 if ( start.x() <= end.x() ) {
00576 pen = QPen( Qt::black );
00577 dataPen = constraint.data( Constraint::ValidConstraintPen );
00578 } else {
00579 pen = QPen( Qt::red );
00580 dataPen = constraint.data( Constraint::InvalidConstraintPen );
00581 }
00582
00583
00584 if( qVariantCanConvert< QPen >( dataPen ) )
00585 pen = qVariantValue< QPen >( dataPen );
00586
00587 painter->setPen( pen );
00588 painter->setBrush( pen.color() );
00589
00590 painter->drawPolyline( startFinishLine( start, end ) );
00591 painter->drawPolygon( startFinishArrow( start, end ) );
00592 }
00593
00594 QPolygonF ItemDelegate::startFinishLine( const QPointF& start, const QPointF& end ) const
00595 {
00596 QPolygonF poly;
00597 qreal midx = end.x() + TURN;
00598 qreal midy = ( end.y()-start.y() )/2. + start.y();
00599
00600 if ( start.x()-TURN > end.x()+TURN ) {
00601 poly << start
00602 << QPointF( midx, start.y() )
00603 << QPointF( midx, end.y() )
00604 << end;
00605 } else {
00606 poly << start
00607 << QPointF( start.x()-TURN, start.y() )
00608 << QPointF( start.x()-TURN, midy )
00609 << QPointF( midx, midy )
00610 << QPointF( end.x()+TURN, end.y() )
00611 << end;
00612 }
00613 return poly;
00614 }
00615
00616 QPolygonF ItemDelegate::startFinishArrow( const QPointF& start, const QPointF& end ) const
00617 {
00618 QPolygonF poly;
00619 poly << end
00620 << QPointF( end.x()+TURN/2., end.y()-TURN/2. )
00621 << QPointF( end.x()+TURN/2., end.y()+TURN/2. );
00622 return poly;
00623 }
00624
00625
00626 #include "moc_kdganttitemdelegate.cpp"