00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kdganttgraphicsscene.h"
00024 #include "kdganttgraphicsscene_p.h"
00025 #include "kdganttgraphicsitem.h"
00026 #include "kdganttconstraint.h"
00027 #include "kdganttconstraintgraphicsitem.h"
00028 #include "kdganttitemdelegate.h"
00029 #include "kdganttabstractrowcontroller.h"
00030 #include "kdganttdatetimegrid.h"
00031 #include "kdganttsummaryhandlingproxymodel.h"
00032 #include "kdganttgraphicsview.h"
00033
00034 #include <QToolTip>
00035 #include <QGraphicsSceneHelpEvent>
00036 #include <QTextDocument>
00037
00038 #include <QDebug>
00039
00040 #include <functional>
00041 #include <algorithm>
00042 #include <cassert>
00043
00048 using namespace KDGantt;
00049
00050 GraphicsScene::Private::Private( GraphicsScene* _q )
00051 : q( _q ),
00052 dragSource( 0 ),
00053 itemDelegate( new ItemDelegate( _q ) ),
00054 rowController( 0 ),
00055 grid( &default_grid ),
00056 readOnly( false ),
00057 summaryHandlingModel( new SummaryHandlingProxyModel( _q ) ),
00058 selectionModel( 0 )
00059 {
00060 default_grid.setStartDateTime( QDateTime::currentDateTime().addDays( -1 ) );
00061 }
00062
00063 void GraphicsScene::Private::resetConstraintItems()
00064 {
00065 q->clearConstraintItems();
00066 if ( constraintModel.isNull() ) return;
00067 QList<Constraint> clst = constraintModel->constraints();
00068 Q_FOREACH( Constraint c, clst ) {
00069 createConstraintItem( c );
00070 }
00071 q->updateItems();
00072 }
00073
00074 void GraphicsScene::Private::createConstraintItem( const Constraint& c )
00075 {
00076 GraphicsItem* sitem = q->findItem( summaryHandlingModel->mapFromSource( c.startIndex() ) );
00077 GraphicsItem* eitem = q->findItem( summaryHandlingModel->mapFromSource( c.endIndex() ) );
00078
00079 if ( sitem && eitem ) {
00080 ConstraintGraphicsItem* citem = new ConstraintGraphicsItem( c );
00081 sitem->addStartConstraint( citem );
00082 eitem->addEndConstraint( citem );
00083 q->addItem( citem );
00084 }
00085
00086
00087
00088
00089 }
00090
00091
00092 void GraphicsScene::Private::deleteConstraintItem( ConstraintGraphicsItem *citem )
00093 {
00094
00095 if ( citem == 0 ) {
00096 return;
00097 }
00098 Constraint c = citem->constraint();
00099 GraphicsItem* item = items.value( summaryHandlingModel->mapFromSource( c.startIndex() ), 0 );
00100 if ( item ) {
00101
00102 item->removeStartConstraint( citem );
00103 }
00104 item = items.value( summaryHandlingModel->mapFromSource( c.endIndex() ), 0 );
00105 if ( item ) {
00106
00107 item->removeEndConstraint( citem );
00108 }
00109
00110 delete citem;
00111 }
00112
00113 void GraphicsScene::Private::deleteConstraintItem( const Constraint& c )
00114 {
00115
00116 deleteConstraintItem( findConstraintItem( c ) );
00117 }
00118
00119 namespace {
00120
00121
00122
00123 template<typename Operation1,typename Operation2>
00124 struct unary_compose : public std::unary_function<typename Operation1::result_type,typename Operation2::argument_type> {
00125 unary_compose( const Operation1& f, const Operation2& g ) : _f( f ), _g( g ) {}
00126
00127 inline typename Operation1::result_type operator()( const typename Operation2::argument_type& arg ) {
00128 return _f( _g( arg ) );
00129 }
00130
00131 Operation1 _f;
00132 Operation2 _g;
00133 };
00134
00135 template<typename Operation1,typename Operation2>
00136 inline unary_compose<Operation1,Operation2> compose1( const Operation1& f, const Operation2& g )
00137 {
00138 return unary_compose<Operation1,Operation2>( f, g );
00139 }
00140 }
00141
00142 ConstraintGraphicsItem* GraphicsScene::Private::findConstraintItem( const Constraint& c ) const
00143 {
00144 GraphicsItem* item = items.value( summaryHandlingModel->mapFromSource( c.startIndex() ), 0 );
00145 if ( item ) {
00146 QList<ConstraintGraphicsItem*> clst = item->startConstraints();
00147 QList<ConstraintGraphicsItem*>::iterator it = clst.begin();
00148
00149 for( ; it != clst.end() ; ++it )
00150 if ((*it)->constraint() == c )
00151 break;
00152 if ( it != clst.end() ) {
00153 return *it;
00154 }
00155 }
00156 item = items.value( summaryHandlingModel->mapFromSource( c.endIndex() ), 0 );
00157 if ( item ) {
00158 QList<ConstraintGraphicsItem*> clst = item->endConstraints();
00159 QList<ConstraintGraphicsItem*>::iterator it = clst.begin();
00160
00161 for( ; it != clst.end() ; ++it )
00162 if ((*it)->constraint() == c )
00163 break;
00164 if ( it != clst.end() ) {
00165 return *it;
00166 }
00167 }
00168
00169 return 0;
00170 }
00171
00172 GraphicsScene::GraphicsScene( QObject* parent )
00173 : QGraphicsScene( parent ), _d( new Private( this ) )
00174 {
00175 init();
00176 }
00177
00178 GraphicsScene::~GraphicsScene()
00179 {
00180 clearConstraintItems();
00181 clearItems();
00182 }
00183
00184 #define d d_func()
00185
00186 void GraphicsScene::init()
00187 {
00188 setConstraintModel( new ConstraintModel( this ) );
00189 connect( d->grid, SIGNAL( gridChanged() ), this, SLOT( slotGridChanged() ) );
00190 }
00191
00192
00193
00194
00195
00196 void GraphicsScene::setItemDelegate( ItemDelegate* delegate )
00197 {
00198 if ( !d->itemDelegate.isNull() && d->itemDelegate->parent()==this ) delete d->itemDelegate;
00199 d->itemDelegate = delegate;
00200 update();
00201 }
00202
00203 ItemDelegate* GraphicsScene::itemDelegate() const
00204 {
00205 return d->itemDelegate;
00206 }
00207
00208 QAbstractItemModel* GraphicsScene::model() const
00209 {
00210 assert(!d->summaryHandlingModel.isNull());
00211 return d->summaryHandlingModel->sourceModel();
00212 }
00213
00214 void GraphicsScene::setModel( QAbstractItemModel* model )
00215 {
00216 assert(!d->summaryHandlingModel.isNull());
00217 d->summaryHandlingModel->setSourceModel(model);
00218 d->grid->setModel( d->summaryHandlingModel );
00219 setSelectionModel( new QItemSelectionModel( model, this ) );
00220 }
00221
00222 QAbstractProxyModel* GraphicsScene::summaryHandlingModel() const
00223 {
00224 return d->summaryHandlingModel;
00225 }
00226
00227 void GraphicsScene::setSummaryHandlingModel( QAbstractProxyModel* proxyModel )
00228 {
00229 proxyModel->setSourceModel( model() );
00230 d->summaryHandlingModel = proxyModel;
00231 }
00232
00233 void GraphicsScene::setRootIndex( const QModelIndex& idx )
00234 {
00235 d->grid->setRootIndex( idx );
00236 }
00237
00238 QModelIndex GraphicsScene::rootIndex() const
00239 {
00240 return d->grid->rootIndex();
00241 }
00242
00243 ConstraintModel* GraphicsScene::constraintModel() const
00244 {
00245 return d->constraintModel;
00246 }
00247
00248 void GraphicsScene::setConstraintModel( ConstraintModel* cm )
00249 {
00250 if ( !d->constraintModel.isNull() ) {
00251 disconnect( d->constraintModel );
00252 }
00253 d->constraintModel = cm;
00254
00255 connect( cm, SIGNAL( constraintAdded( const Constraint& ) ), this, SLOT( slotConstraintAdded( const Constraint& ) ) );
00256 connect( cm, SIGNAL( constraintRemoved( const Constraint& ) ), this, SLOT( slotConstraintRemoved( const Constraint& ) ) );
00257 d->resetConstraintItems();
00258 }
00259
00260 void GraphicsScene::setSelectionModel( QItemSelectionModel* smodel )
00261 {
00262 d->selectionModel = smodel;
00263
00264 }
00265
00266 QItemSelectionModel* GraphicsScene::selectionModel() const
00267 {
00268 return d->selectionModel;
00269 }
00270
00271 void GraphicsScene::setRowController( AbstractRowController* rc )
00272 {
00273 d->rowController = rc;
00274 }
00275
00276 AbstractRowController* GraphicsScene::rowController() const
00277 {
00278 return d->rowController;
00279 }
00280
00281 void GraphicsScene::setGrid( AbstractGrid* grid )
00282 {
00283 QAbstractItemModel* model = d->grid->model();
00284 if ( grid == 0 ) grid = &d->default_grid;
00285 if ( d->grid ) disconnect( d->grid );
00286 d->grid = grid;
00287 connect( d->grid, SIGNAL( gridChanged() ), this, SLOT( slotGridChanged() ) );
00288 d->grid->setModel( model );
00289 slotGridChanged();
00290 }
00291
00292 AbstractGrid* GraphicsScene::grid() const
00293 {
00294 return d->grid;
00295 }
00296
00297 void GraphicsScene::setReadOnly( bool ro )
00298 {
00299 d->readOnly = ro;
00300 }
00301
00302 bool GraphicsScene::isReadOnly() const
00303 {
00304 return d->readOnly;
00305 }
00306
00307
00308
00309
00310
00311
00312 QModelIndex GraphicsScene::mainIndex( const QModelIndex& idx )
00313 {
00314 #if 0
00315 if ( idx.isValid() ) {
00316 return idx.model()->index( idx.row(), 0,idx.parent() );
00317 } else {
00318 return QModelIndex();
00319 }
00320 #else
00321 return idx;
00322 #endif
00323 }
00324
00329 QModelIndex GraphicsScene::dataIndex( const QModelIndex& idx )
00330 {
00331 #if 0
00332 if ( idx.isValid() ) {
00333 const QAbstractItemModel* model = idx.model();
00334 return model->index( idx.row(), model->columnCount( idx.parent() )-1,idx.parent() );
00335 } else {
00336 return QModelIndex();
00337 }
00338 #else
00339 return idx;
00340 #endif
00341 }
00342
00347 GraphicsItem* GraphicsScene::createItem( ItemType type ) const
00348 {
00349 #if 0
00350 switch( type ) {
00351 case TypeEvent: return 0;
00352 case TypeTask: return new TaskItem;
00353 case TypeSummary: return new SummaryItem;
00354 default: return 0;
00355 }
00356 #endif
00357
00358 Q_UNUSED( type );
00359 return new GraphicsItem;
00360 }
00361
00362 void GraphicsScene::updateRow( const QModelIndex& rowidx )
00363 {
00364
00365 if ( !rowidx.isValid() ) return;
00366 const QAbstractItemModel* model = rowidx.model();
00367 assert( model );
00368 assert( rowController() );
00369 assert( model == summaryHandlingModel() );
00370
00371 const QModelIndex sidx = summaryHandlingModel()->mapToSource( rowidx );
00372 const Span rg=rowController()->rowGeometry( sidx );
00373 for ( int col = 0; col < summaryHandlingModel()->columnCount( rowidx.parent() ); ++col ) {
00374 const QModelIndex idx = summaryHandlingModel()->index( rowidx.row(), col, rowidx.parent() );
00375 const int itemtype = summaryHandlingModel()->data( idx, ItemTypeRole ).toInt();
00376 if ( itemtype == TypeNone ) {
00377 removeItem( idx );
00378 continue;
00379 }
00380 if ( itemtype == TypeMulti ) {
00381 int cr=0;
00382 QModelIndex child;
00383 while ( ( child = idx.child( cr, 0 ) ).isValid() ) {
00384 GraphicsItem* item = findItem( child );
00385 if (!item) {
00386 item = createItem( static_cast<ItemType>( itemtype ) );
00387 item->setIndex( child );
00388 insertItem( child, item);
00389 }
00390 item->updateItem( rg, child );
00391 setSceneRect( sceneRect().united( item->boundingRect() ) );
00392 ++cr;
00393 }
00394 }
00395 {
00396 if ( summaryHandlingModel()->data( rowidx.parent(), ItemTypeRole ).toInt() == TypeMulti ) continue;
00397
00398 GraphicsItem* item = findItem( idx );
00399 if (!item) {
00400 item = createItem( static_cast<ItemType>( itemtype ) );
00401 item->setIndex( idx );
00402 insertItem(idx, item);
00403 }
00404 item->updateItem( rg, idx );
00405 setSceneRect( sceneRect().united( item->boundingRect() ) );
00406 }
00407 }
00408 }
00409
00410 void GraphicsScene::insertItem( const QPersistentModelIndex& idx, GraphicsItem* item )
00411 {
00412 if ( !d->constraintModel.isNull() ) {
00413
00414 const QModelIndex sidx = summaryHandlingModel()->mapToSource( idx );
00415 const QList<Constraint> clst = d->constraintModel->constraintsForIndex( sidx );
00416 Q_FOREACH( Constraint c, clst ) {
00417 QModelIndex other_idx;
00418 if ( c.startIndex() == sidx ) {
00419 other_idx = c.endIndex();
00420 GraphicsItem* other_item = d->items.value(summaryHandlingModel()->mapFromSource( other_idx ),0);
00421 if ( !other_item ) continue;
00422 ConstraintGraphicsItem* citem = new ConstraintGraphicsItem( c );
00423 item->addStartConstraint( citem );
00424 other_item->addEndConstraint( citem );
00425 addItem( citem );
00426 } else if ( c.endIndex() == sidx ) {
00427 other_idx = c.startIndex();
00428 GraphicsItem* other_item = d->items.value(summaryHandlingModel()->mapFromSource( other_idx ),0);
00429 if ( !other_item ) continue;
00430 ConstraintGraphicsItem* citem = new ConstraintGraphicsItem( c );
00431 other_item->addStartConstraint( citem );
00432 item->addEndConstraint( citem );
00433 addItem( citem );
00434 } else {
00435 assert( 0 );
00436 }
00437 }
00438 }
00439 d->items.insert( idx, item );
00440 addItem( item );
00441 }
00442
00443 void GraphicsScene::removeItem( const QModelIndex& idx )
00444 {
00445
00446 QHash<QPersistentModelIndex,GraphicsItem*>::iterator it = d->items.find( idx );
00447 if ( it != d->items.end() ) {
00448 GraphicsItem* item = *it;
00449
00450
00451 d->items.erase( it );
00452
00453 {
00454
00455 const QList<ConstraintGraphicsItem*> clst = item->startConstraints();
00456
00457 Q_FOREACH( ConstraintGraphicsItem* citem, clst ) {
00458
00459 d->deleteConstraintItem( citem );
00460 }
00461 }
00462 {
00463 const QList<ConstraintGraphicsItem*> clst = item->endConstraints();
00464
00465 Q_FOREACH( ConstraintGraphicsItem* citem, clst ) {
00466
00467 d->deleteConstraintItem( citem );
00468 }
00469 }
00470
00471 delete item;
00472 }
00473 }
00474
00475 GraphicsItem* GraphicsScene::findItem( const QModelIndex& idx ) const
00476 {
00477 if ( !idx.isValid() ) return 0;
00478 assert( idx.model() == summaryHandlingModel() );
00479 QHash<QPersistentModelIndex,GraphicsItem*>::const_iterator it = d->items.find( idx );
00480 return ( it != d->items.end() )?*it:0;
00481 }
00482
00483 GraphicsItem* GraphicsScene::findItem( const QPersistentModelIndex& idx ) const
00484 {
00485 if ( !idx.isValid() ) return 0;
00486 assert( idx.model() == summaryHandlingModel() );
00487 QHash<QPersistentModelIndex,GraphicsItem*>::const_iterator it = d->items.find( idx );
00488 return ( it != d->items.end() )?*it:0;
00489 }
00490
00491 void GraphicsScene::clearItems()
00492 {
00493
00494 qDeleteAll( items() );
00495 d->items.clear();
00496 }
00497
00498 void GraphicsScene::updateItems()
00499 {
00500 for ( QHash<QPersistentModelIndex,GraphicsItem*>::iterator it = d->items.begin();
00501 it != d->items.end(); ++it ) {
00502 GraphicsItem* const item = it.value();
00503 const QPersistentModelIndex& idx = it.key();
00504 item->updateItem( Span( item->pos().y(), item->rect().height() ), idx );
00505 }
00506 }
00507
00508 void GraphicsScene::deleteSubtree( const QModelIndex& _idx )
00509 {
00510 QModelIndex idx = dataIndex( _idx );
00511 removeItem( idx );
00512 for ( int i = 0; i < summaryHandlingModel()->rowCount( _idx ); ++i ) {
00513 deleteSubtree( summaryHandlingModel()->index( i, summaryHandlingModel()->columnCount(_idx)-1, _idx ) );
00514 }
00515 }
00516
00517
00518 ConstraintGraphicsItem* GraphicsScene::findConstraintItem( const Constraint& c ) const
00519 {
00520 return d->findConstraintItem( c );
00521 }
00522
00523 void GraphicsScene::clearConstraintItems()
00524 {
00525
00526
00527 }
00528
00529 void GraphicsScene::slotConstraintAdded( const Constraint& c )
00530 {
00531 d->createConstraintItem( c );
00532 }
00533
00534 void GraphicsScene::slotConstraintRemoved( const Constraint& c )
00535 {
00536 d->deleteConstraintItem( c );
00537 }
00538
00539 void GraphicsScene::slotGridChanged()
00540 {
00541 updateItems();
00542 update();
00543 emit gridChanged();
00544 }
00545
00546 void GraphicsScene::helpEvent( QGraphicsSceneHelpEvent *helpEvent )
00547 {
00548 #ifndef QT_NO_TOOLTIP
00549 QGraphicsItem *item = itemAt( helpEvent->scenePos() );
00550 if ( GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
00551 QToolTip::showText(helpEvent->screenPos(), gitem->ganttToolTip());
00552 } else if ( ConstraintGraphicsItem* citem = qgraphicsitem_cast<ConstraintGraphicsItem*>( item ) ) {
00553 QToolTip::showText(helpEvent->screenPos(), citem->ganttToolTip());
00554 } else {
00555 QGraphicsScene::helpEvent( helpEvent );
00556 }
00557 #endif
00558 }
00559
00560 void GraphicsScene::drawBackground( QPainter* painter, const QRectF& rect )
00561 {
00562 d->grid->paintGrid( painter, sceneRect(), rect, d->rowController );
00563 }
00564
00565 void GraphicsScene::itemEntered( const QModelIndex& idx )
00566 {
00567 emit entered( idx );
00568 }
00569
00570 void GraphicsScene::itemPressed( const QModelIndex& idx )
00571 {
00572 emit pressed( idx );
00573 }
00574
00575 void GraphicsScene::itemClicked( const QModelIndex& idx )
00576 {
00577 emit clicked( idx );
00578 }
00579
00580 void GraphicsScene::itemDoubleClicked( const QModelIndex& idx )
00581 {
00582 emit doubleClicked( idx );
00583 }
00584
00585 void GraphicsScene::setDragSource( GraphicsItem* item )
00586 {
00587 d->dragSource = item;
00588 }
00589
00590 GraphicsItem* GraphicsScene::dragSource() const
00591 {
00592 return d->dragSource;
00593 }
00594
00595 QRectF GraphicsScene::printRect(bool drawRowLabels )
00596 {
00597 assert(rowController());
00598
00599 qreal leftEdge = sceneRect().left();
00600 QVector<QGraphicsTextItem*> labelItems;
00601 if(drawRowLabels) {
00602 labelItems.reserve(d->items.size());
00603 qreal textWidth = 0.;
00604 qreal rowHeight = 0.;
00605 {Q_FOREACH( GraphicsItem* item, d->items ) {
00606 QModelIndex sidx = summaryHandlingModel()->mapToSource( item->index() );
00607 if( sidx.parent().isValid() && sidx.parent().data( ItemTypeRole ).toInt() == TypeMulti ) {
00608 continue;
00609 }
00610 const Span rg=rowController()->rowGeometry( sidx );
00611 const QString txt = item->index().data( Qt::DisplayRole ).toString();
00612 QGraphicsTextItem* ti = new QGraphicsTextItem(txt,0,this);
00613 ti->setPos( 0, rg.start() );
00614 if( ti->document()->size().width() > textWidth ) textWidth = ti->document()->size().width();
00615 if( rg.length() > rowHeight ) rowHeight = rg.length();
00616 labelItems << ti;
00617 }}
00618 {Q_FOREACH( QGraphicsTextItem* item, labelItems ) {
00619 item->setPos( leftEdge-textWidth-rowHeight, item->pos().y() );
00620 item->show();
00621 }}
00622 }
00623 QRectF res = itemsBoundingRect();
00624 qDeleteAll(labelItems);
00625
00626 return res;
00627 }
00628
00629 void GraphicsScene::print( QPainter* painter, const QRectF& target, const QRectF& source, bool drawRowLabels, GraphicsView *view )
00630 {
00631 QRectF targetRect(target);
00632
00633 assert(rowController());
00634
00635 QVector<QGraphicsTextItem*> labelItems;
00636 if(drawRowLabels) {
00637 labelItems.reserve(d->items.size());
00638 qreal leftEdge = sceneRect().left();
00639 qreal textWidth = 0.;
00640 qreal rowHeight = 0.;
00641 {Q_FOREACH( GraphicsItem* item, d->items ) {
00642 QModelIndex sidx = summaryHandlingModel()->mapToSource( item->index() );
00643 if( sidx.parent().isValid() && sidx.parent().data( ItemTypeRole ).toInt() == TypeMulti ) {
00644 continue;
00645 }
00646 const Span rg=rowController()->rowGeometry( sidx );
00647 const QString txt = item->index().data( Qt::DisplayRole ).toString();
00648 QGraphicsTextItem* ti = new QGraphicsTextItem(txt,0,this);
00649 ti->setPos( 0, rg.start() );
00650 if( ti->document()->size().width() > textWidth ) textWidth = ti->document()->size().width();
00651 if( rg.length() > rowHeight ) rowHeight = rg.length();
00652 labelItems << ti;
00653 }}
00654 {Q_FOREACH( QGraphicsTextItem* item, labelItems ) {
00655 item->setPos( leftEdge-textWidth-rowHeight, item->pos().y() );
00656 item->show();
00657 }}
00658 }
00659 QRectF oldSceneRect( sceneRect() );
00660 setSceneRect( itemsBoundingRect() );
00661 QRectF sourceRect = source;
00662
00663 if ( view ) {
00664 Qt::AspectRatioMode mode = Qt::KeepAspectRatio;
00665 QRectF s = sourceRect;
00666 s.setHeight( view->headerHeight() );
00667 qreal xr = targetRect.width() / sourceRect.width();
00668 qreal yr = (qreal)1.0;
00669 if ( sourceRect.height() > s.height() ) {
00670 yr = targetRect.height() / sourceRect.height();
00671 }
00672 xr = yr = qMin( xr, yr );
00673 QRectF t = targetRect;
00674 t.setHeight( s.height() * yr );
00675 view->renderHeader( painter, t, s, mode );
00676 targetRect.translate( (qreal)0.0, t.height() );
00677
00678 }
00679
00680 if ( targetRect.width() > sourceRect.width() && targetRect.height() > sourceRect.height() ) {
00681 targetRect.setSize( sourceRect.size() );
00682 render( painter, targetRect, sourceRect, Qt::IgnoreAspectRatio );
00683 } else {
00684 render( painter, targetRect, sourceRect );
00685 }
00686 qDeleteAll(labelItems);
00687
00688 setSceneRect( oldSceneRect );
00689 }
00690
00691
00692 #include "moc_kdganttgraphicsscene.cpp"
00693