kdganttitemdelegate.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002  ** Copyright (C) 2001-2006 Klarälvdalens Datakonsult AB.  All rights reserved.
00003  **
00004  ** This file is part of the KD Gantt library.
00005  **
00006  ** This file may be distributed and/or modified under the terms of the
00007  ** GNU General Public License version 2 as published by the Free Software
00008  ** Foundation and appearing in the file LICENSE.GPL included in the
00009  ** packaging of this file.
00010  **
00011  ** Licensees holding valid commercial KD Gantt licenses may use this file in
00012  ** accordance with the KD Gantt Commercial License Agreement provided with
00013  ** the Software.
00014  **
00015  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00016  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00017  **
00018  ** See http://www.kdab.net/kdgantt for
00019  **   information about KD Gantt Commercial License Agreements.
00020  **
00021  ** Contact info@kdab.net if any conditions of this
00022  ** licensing are not clear to you.
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 /* QT_NO_DEBUG_STREAM */
00059 
00060 using namespace KDGantt;
00061 
00075 ItemDelegate::Private::Private()
00076 {
00077     // Brushes
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     // Pens
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     // Use default pens...
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     // ... unless constraint.data() returned a valid pen for this case
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     // An event item is infinitely thin, basically just a line, because it has only one date instead of two.
00234     // It is painted with an offset of -height/2, which is taken into account here.
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     //qDebug() << "itemRect="<<itemRect<<", boundingRect="<<boundingRect;
00270     //qDebug() << painter->font() << opt.fontMetrics.height() << painter->device()->width() << painter->device()->height();
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             // TODO
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             // TODO
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             //path.lineTo( QPointF( r.right()-3./2.*delta, r.top() + delta ) );
00324             path.quadTo( QPointF( r.right()-.5*delta, r.top() + delta ), QPointF( r.right()-2.*delta, r.top() + delta ) );
00325             //path.lineTo( QPointF( r.left()+3./2.*delta, r.top() + delta ) );
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: /* TODO */
00344         //qDebug() << opt.boundingRect << opt.itemRect;
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     //qDebug()<<"ItemDelegate::paintConstraintItem"<<start<<end<<constraint;
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"

Generated on Thu Mar 4 23:19:13 2010 for KD Chart 2 by  doxygen 1.5.4