24 #include "kdganttgraphicsscene_p.h"
30 #include "kdganttdatetimegrid.h"
33 #include <QApplication>
34 #include <QGraphicsSceneHelpEvent>
37 #include <QTextDocument>
48 #ifndef QT_VERSION_CHECK
49 # define QT_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
65 using namespace KDGantt;
72 grid( &default_grid ),
75 drawColumnLabels( true ),
80 default_grid.setStartDateTime( QDateTime::currentDateTime().addDays( -1 ) );
83 void GraphicsScene::Private::resetConstraintItems()
85 q->clearConstraintItems();
86 if ( constraintModel.isNull() )
return;
89 createConstraintItem( c );
94 void GraphicsScene::Private::createConstraintItem(
const Constraint& c )
99 if ( sitem && eitem ) {
121 item = items.value( summaryHandlingModel->mapFromSource( c.
endIndex() ), 0 );
128 void GraphicsScene::Private::deleteConstraintItem(
const Constraint& c )
130 deleteConstraintItem( findConstraintItem( c ) );
139 for ( ; it != clst.end() ; ++it ) {
143 if ( it != clst.end() ) {
147 item = items.value( summaryHandlingModel->mapFromSource( c.
endIndex() ), 0 );
151 for ( ; it != clst.end() ; ++it ) {
155 if ( it != clst.end() ) {
162 GraphicsScene::GraphicsScene(
QObject* parent )
171 qDeleteAll( items() );
177 void GraphicsScene::init()
179 setItemIndexMethod( QGraphicsScene::NoIndex );
181 connect(
d->grid, SIGNAL(
gridChanged() ),
this, SLOT( slotGridChanged() ) );
190 if ( !
d->itemDelegate.isNull() &&
d->itemDelegate->parent()==this )
delete d->itemDelegate;
191 d->itemDelegate = delegate;
197 return d->itemDelegate;
202 assert(!
d->summaryHandlingModel.isNull());
203 return d->summaryHandlingModel->sourceModel();
208 assert(!
d->summaryHandlingModel.isNull());
209 d->summaryHandlingModel->setSourceModel(model);
210 d->grid->setModel(
d->summaryHandlingModel );
216 return d->summaryHandlingModel;
221 proxyModel->setSourceModel(
model() );
222 d->summaryHandlingModel = proxyModel;
227 d->grid->setRootIndex( idx );
232 return d->grid->rootIndex();
237 return d->constraintModel;
242 if ( !
d->constraintModel.isNull() ) {
243 d->constraintModel->disconnect(
this );
245 d->constraintModel = cm;
251 d->resetConstraintItems();
256 d->selectionModel = smodel;
262 return d->selectionModel;
267 d->rowController = rc;
272 return d->rowController;
277 QAbstractItemModel*
model = 0;
278 if ( grid == 0 ) grid = &
d->default_grid;
280 d->grid->disconnect(
this );
281 model =
d->grid->model();
284 connect(
d->grid, SIGNAL(
gridChanged() ),
this, SLOT( slotGridChanged() ) );
285 d->grid->setModel( model );
312 if ( idx.isValid() ) {
313 return idx.model()->index( idx.row(), 0,idx.parent() );
315 return QModelIndex();
329 if ( idx.isValid() ) {
330 const QAbstractItemModel*
model = idx.model();
331 return model->index( idx.row(), model->columnCount( idx.parent() )-1,idx.parent() );
333 return QModelIndex();
359 void GraphicsScene::Private::recursiveUpdateMultiItem(
const Span& span,
const QModelIndex& idx )
363 const int itemtype = summaryHandlingModel->data( idx,
ItemTypeRole ).toInt();
365 item = q->createItem( static_cast<ItemType>( itemtype ) );
367 q->insertItem( idx, item);
372 while ( ( child = idx.child( cr, 0 ) ).isValid() ) {
373 recursiveUpdateMultiItem( span, child );
381 if ( !rowidx.isValid() )
return;
382 const QAbstractItemModel*
model = rowidx.model();
389 for ( QModelIndex treewalkidx = sidx; treewalkidx.isValid(); treewalkidx = treewalkidx.parent() ) {
396 bool blocked = blockSignals(
true );
406 if ( itemtype ==
TypeMulti && !isExpanded ) {
407 d->recursiveUpdateMultiItem( rg, idx );
415 item =
createItem( static_cast<ItemType>( itemtype ) );
423 blockSignals( blocked );
428 if ( !
d->constraintModel.isNull() ) {
433 QModelIndex other_idx;
437 if ( !other_item )
continue;
442 }
else if ( c.
endIndex() == sidx ) {
445 if ( !other_item )
continue;
455 d->items.insert( idx, item );
462 QHash<QPersistentModelIndex,GraphicsItem*>::iterator it =
d->items.find( idx );
463 if ( it !=
d->items.end() ) {
468 d->items.erase( it );
471 const QSet<ConstraintGraphicsItem*> clst = QSet<ConstraintGraphicsItem*>::fromList( item->
startConstraints() ) +
472 QSet<ConstraintGraphicsItem*>::fromList( item->
endConstraints() );
474 d->deleteConstraintItem( citem );
484 if ( !idx.isValid() )
return 0;
486 QHash<QPersistentModelIndex,GraphicsItem*>::const_iterator it =
d->items.find( idx );
487 return ( it !=
d->items.end() )?*it:0;
492 if ( !idx.isValid() )
return 0;
494 QHash<QPersistentModelIndex,GraphicsItem*>::const_iterator it =
d->items.find( idx );
495 return ( it !=
d->items.end() )?*it:0;
501 QHash<QPersistentModelIndex, GraphicsItem*>::const_iterator it =
d->items.constBegin();
502 for ( ; it !=
d->items.constEnd(); ++it ) {
510 for ( QHash<QPersistentModelIndex,GraphicsItem*>::iterator it =
d->items.begin();
511 it !=
d->items.end(); ++it ) {
513 const QPersistentModelIndex& idx = it.key();
516 invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
522 if ( !idx.model() )
return;
523 const QModelIndex parent( idx.parent() );
524 const int colcount = idx.model()->columnCount( parent );
525 {
for (
int i = 0; i < colcount; ++i ) {
529 {
for (
int i = 0; i < rowcount; ++i ) {
537 return d->findConstraintItem( c );
548 d->createConstraintItem( c );
553 d->deleteConstraintItem( c );
556 void GraphicsScene::slotGridChanged()
565 #ifndef QT_NO_TOOLTIP
566 QGraphicsItem *item = itemAt( helpEvent->scenePos(), QTransform() );
567 if (
GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
568 QToolTip::showText(helpEvent->screenPos(), gitem->ganttToolTip());
570 QToolTip::showText(helpEvent->screenPos(), citem->
ganttToolTip());
572 QGraphicsScene::helpEvent( helpEvent );
579 QRectF scn( sceneRect() );
580 QRectF rect( _rect );
581 if (
d->isPrinting &&
d->drawColumnLabels ) {
582 QRectF headerRect( scn.topLeft()+QPointF(
d->labelsWidth, 0 ),
583 QSizeF( scn.width()-
d->labelsWidth,
d->rowController->headerHeight() ));
585 d->grid->paintHeader( painter, headerRect, rect, 0, 0 );
591 QRectF labelsTabRect( scn.topLeft(), QSizeF(
d->labelsWidth, headerRect.height() ) );
593 QStyleOptionHeader opt;
594 opt.rect = labelsTabRect.toRect();
595 opt.text = QLatin1String(
"");
596 opt.textAlignment = Qt::AlignCenter;
597 #if QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)
598 style()->drawControl(QStyle::CE_Header, &opt, painter, 0);
600 QApplication::style()->drawControl(QStyle::CE_Header, &opt, painter, 0);
604 scn.setTop( headerRect.bottom() );
605 scn.setLeft( headerRect.left() );
606 rect = rect.intersected( scn );
608 d->grid->paintGrid( painter, scn, rect,
d->rowController );
610 d->grid->drawBackground(painter, rect);
615 d->grid->drawForeground(painter, rect);
640 d->dragSource = item;
645 return d->dragSource;
660 Q_UNUSED( drawRowLabels );
661 Q_UNUSED( drawColumnLabels );
663 QPainter painter( printer );
664 doPrint( &painter, printer->pageRect(), sceneRect().left(), sceneRect().right(), printer, drawRowLabels, drawColumnLabels );
680 void GraphicsScene::print( QPrinter* printer, qreal start, qreal end,
bool drawRowLabels,
bool drawColumnLabels )
686 Q_UNUSED( drawRowLabels );
687 Q_UNUSED( drawColumnLabels );
689 QPainter painter( printer );
690 doPrint( &painter, printer->pageRect(), start, end, printer, drawRowLabels, drawColumnLabels );
700 void GraphicsScene::print( QPainter* painter,
const QRectF& _targetRect,
bool drawRowLabels,
bool drawColumnLabels )
702 QRectF targetRect( _targetRect );
703 if ( targetRect.isNull() ) {
704 targetRect = sceneRect();
707 doPrint( painter, targetRect, sceneRect().left(), sceneRect().right(), 0, drawRowLabels, drawColumnLabels );
721 const QRectF& _targetRect,
bool drawRowLabels,
bool drawColumnLabels )
723 QRectF targetRect( _targetRect );
724 if ( targetRect.isNull() ) {
725 targetRect = sceneRect();
728 doPrint( painter, targetRect, start, end, 0, drawRowLabels, drawColumnLabels );
733 void GraphicsScene::doPrint( QPainter* painter,
const QRectF& targetRect,
734 qreal start, qreal end,
735 QPrinter* printer,
bool drawRowLabels,
bool drawColumnLabels )
738 d->isPrinting =
true;
739 d->drawColumnLabels = drawColumnLabels;
740 d->labelsWidth = 0.0;
741 #if QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)
742 QFont sceneFont( font() );
745 sceneFont = QFont( font(), printer );
746 if ( font().pointSizeF() >= 0.0 )
747 sceneFont.setPointSizeF( font().pointSizeF() );
748 else if ( font().pointSize() >= 0 )
749 sceneFont.setPointSize( font().pointSize() );
751 sceneFont.setPixelSize( font().pixelSize() );
755 QFont sceneFont( painter->font() );
758 sceneFont = QFont( painter->font(), printer );
759 if ( painter->font().pointSizeF() >= 0.0 )
760 sceneFont.setPointSizeF( painter->font().pointSizeF() );
761 else if ( painter->font().pointSize() >= 0 )
762 sceneFont.setPointSize( painter->font().pointSize() );
764 sceneFont.setPixelSize( painter->font().pixelSize() );
769 QGraphicsTextItem dummyTextItem( QLatin1String(
"X") );
770 dummyTextItem.adjustSize();
771 QFontMetrics fm(dummyTextItem.font());
772 sceneFont.setPixelSize( fm.height() );
774 const QRectF oldScnRect( sceneRect() );
775 QRectF scnRect( oldScnRect );
776 scnRect.setLeft( start );
777 scnRect.setRight( end );
778 bool b = blockSignals(
true );
781 if (
d->drawColumnLabels ) {
782 QRectF headerRect( scnRect );
783 headerRect.setHeight( -
d->rowController->headerHeight() );
784 scnRect.setTop(scnRect.top() -
d->rowController->headerHeight());
789 if ( drawRowLabels ) {
790 qreal textWidth = 0.;
795 const QString txt = idx.data( Qt::DisplayRole ).toString();
796 QGraphicsTextItem* item =
new QGraphicsTextItem( txt );
800 textWidth = qMax( item->textWidth(), textWidth );
801 item->setPos( 0, rg.
start() );
802 }
while ( ( sidx =
rowController()->indexBelow( sidx ) ).isValid() );
804 textWidth += QFontMetricsF(sceneFont).width( QString::fromLatin1(
"X" ) );
805 Q_FOREACH( QGraphicsTextItem* item, textLabels ) {
806 item->setPos( scnRect.left()-textWidth, item->y() );
809 scnRect.setLeft( scnRect.left()-textWidth );
810 d->labelsWidth = textWidth;
813 setSceneRect( scnRect );
816 painter->setClipRect( targetRect );
818 qreal yratio = targetRect.height()/scnRect.height();
822 if ( !printer && targetRect.width()/scnRect.width() < yratio ) {
823 yratio = targetRect.width()/scnRect.width();
826 qreal offset = scnRect.left();
828 while ( offset < scnRect.right() ) {
829 painter->setFont( sceneFont );
830 render( painter, targetRect, QRectF( QPointF( offset, scnRect.top()),
831 QSizeF( targetRect.width()/yratio, scnRect.height() ) ) );
832 offset += targetRect.width()/yratio;
834 if ( printer && offset < scnRect.right() ) {
843 d->isPrinting =
false;
844 d->drawColumnLabels =
true;
845 d->labelsWidth = 0.0;
846 qDeleteAll( textLabels );
848 setSceneRect( oldScnRect );
852 #include "moc_kdganttgraphicsscene.cpp"
855 #ifndef KDAB_NO_UNIT_TESTS
858 #include <QGraphicsLineItem>
860 #include <QStandardItemModel>
866 static const int ROW_HEIGHT;
867 QPointer<QAbstractItemModel> m_model;
870 SceneTestRowController()
874 void setModel( QAbstractItemModel* model )
879 int headerHeight()
const {
return 40; }
881 bool isRowVisible(
const QModelIndex& )
const {
return true;}
882 bool isRowExpanded(
const QModelIndex& )
const {
return false; }
887 int maximumItemHeight()
const {
890 int totalHeight()
const {
891 return m_model->rowCount()* ROW_HEIGHT;
894 QModelIndex indexAt(
int height )
const {
895 return m_model->index( height/ROW_HEIGHT, 0 );
898 QModelIndex indexBelow(
const QModelIndex& idx )
const {
899 if ( !idx.isValid() )
return QModelIndex();
900 return idx.model()->index( idx.row()+1, idx.column(), idx.parent() );
902 QModelIndex indexAbove(
const QModelIndex& idx )
const {
903 if ( !idx.isValid() )
return QModelIndex();
904 return idx.model()->index( idx.row()-1, idx.column(), idx.parent() );
909 class TestLineItem :
public QGraphicsLineItem
912 TestLineItem(
bool *destroyedFlag )
913 : QGraphicsLineItem( 0, 0, 10, 10 ),
914 m_destroyedFlag( destroyedFlag )
918 { *m_destroyedFlag =
true; }
921 bool *m_destroyedFlag;
924 const int SceneTestRowController::ROW_HEIGHT = 30;
927 QStandardItemModel model;
929 QStandardItem* item =
new QStandardItem();
931 item->setData( QString::fromLatin1(
"Decide on new product" ) );
935 QStandardItem* item2 =
new QStandardItem();
937 item2->setData( QString::fromLatin1(
"Educate personnel" ) );
941 model.appendRow( item );
942 model.appendRow( item2 );
944 SceneTestRowController rowController;
945 rowController.setModel( &model );
953 bool foreignItemDestroyed =
false;
954 TestLineItem *foreignItem =
new TestLineItem( &foreignItemDestroyed );
955 graphicsView.scene()->addItem( foreignItem );