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