File indexing completed on 2024-05-12 15:54:27

0001 /*
0002  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB.  All rights reserved.
0003  *
0004  * This file is part of the KGantt library.
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public License as
0008  * published by the Free Software Foundation; either version 2 of
0009  * the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "kganttgraphicsview.h"
0021 #include "kganttgraphicsview_p.h"
0022 #include "kganttabstractrowcontroller.h"
0023 #include "kganttgraphicsitem.h"
0024 #include "kganttconstraintmodel.h"
0025 #include "kganttdatetimetimelinedialog.h"
0026 
0027 #include <QMenu>
0028 #include <QPainter>
0029 #include <QPaintEvent>
0030 #include <QResizeEvent>
0031 #include <QScrollBar>
0032 #include <QAbstractProxyModel>
0033 #include <QPrinter>
0034 #include <QItemSelectionModel>
0035 #include <QGraphicsSceneMouseEvent>
0036 #include <QGuiApplication>
0037 
0038 #include <cassert>
0039 
0040 #if defined KDAB_EVAL
0041 #include "../evaldialog/evaldialog.h"
0042 #endif
0043 
0044 /*\class KGantt::HeaderWidget
0045  * \internal
0046  */
0047 
0048 using namespace KGantt;
0049 
0050 HeaderWidget::HeaderWidget( GraphicsView* parent )
0051     : QWidget( parent ), m_offset( 0. ), m_headerType( DateTimeGrid::NoHeader )
0052 {
0053     assert( parent ); // Parent must be set
0054     setMouseTracking(true);
0055 }
0056 
0057 HeaderWidget::~HeaderWidget()
0058 {
0059 }
0060 
0061 void HeaderWidget::scrollTo( int v )
0062 {
0063     m_offset = v;
0064     // QWidget::scroll() wont work properly for me on Mac
0065     //scroll( static_cast<int>( old-v ), 0 );
0066     update();
0067 }
0068 
0069 void HeaderWidget::paintEvent( QPaintEvent* ev )
0070 {
0071     QPainter p( this );
0072     view()->grid()->paintHeader( &p, rect(), ev->rect(), m_offset, this );
0073 }
0074 
0075 bool HeaderWidget::event( QEvent* event )
0076 {
0077     if ( event->type() == QEvent::ToolTip ) {
0078         DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
0079         if ( grid ) {
0080             QHelpEvent *e = static_cast<QHelpEvent*>( event );
0081             QDateTime dt = grid->mapFromChart( view()->mapToScene( e->x(), 0 ).x() ).toDateTime();
0082             setToolTip( dt.toString() );
0083         }
0084     }
0085     return QWidget::event( event );
0086 }
0087 
0088 void HeaderWidget::mousePressEvent(QMouseEvent *event)
0089 {
0090     DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
0091     int mousePosX = event->x();
0092     m_headerType = grid->sectionHandleAtPos( view()->mapToScene( event->x(), 0 ).x(), event->pos().y(), geometry() );
0093     if (m_headerType != DateTimeGrid::NoHeader) {
0094         bool hasCursor = testAttribute(Qt::WA_SetCursor);
0095         if (!hasCursor) {
0096             setCursor(QCursor(Qt::SplitHCursor));
0097         }
0098         m_mousePosX = mousePosX;
0099         event->accept();
0100         return;
0101     }
0102     QWidget::mousePressEvent( event );
0103 }
0104 
0105 void HeaderWidget::mouseReleaseEvent(QMouseEvent *event)
0106 {
0107     if ( m_headerType > 0 ) {
0108         DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
0109         int mousePosX = view()->mapToScene( event->x(), 0 ).x();
0110         if ( grid->sectionHandleAtPos( mousePosX, event->pos().y(), geometry() ) == DateTimeGrid::NoHeader ) {
0111             bool hasCursor = testAttribute(Qt::WA_SetCursor);
0112             if (hasCursor) {
0113                 unsetCursor();
0114             }
0115         }
0116         m_headerType = DateTimeGrid::NoHeader;
0117         m_mousePosX = event->x();
0118         QGuiApplication::restoreOverrideCursor();
0119     }
0120     QWidget::mouseReleaseEvent(event);
0121 }
0122 
0123 void HeaderWidget::mouseMoveEvent(QMouseEvent *event)
0124 {
0125     DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
0126     int mousePosX = event->x();
0127     qreal gridX = view()->mapToScene( event->x(), 0.0 ).x();
0128     switch ( m_headerType ) {
0129         case DateTimeGrid::UpperHeader:
0130         {
0131             if ( mousePosX > m_mousePosX )  {
0132                 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() * 1.05 ) );
0133             } else {
0134                 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() / 1.05 ) );
0135             }
0136             m_mousePosX = mousePosX;
0137             event->accept();
0138             return;
0139         }
0140         case DateTimeGrid::LowerHeader:
0141         {
0142             if ( mousePosX > m_mousePosX )  {
0143                 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() * 1.01 ) );
0144             } else {
0145                 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() / 1.01 ) );
0146             }
0147             m_mousePosX = mousePosX;
0148             event->accept();
0149             return;
0150         }
0151         default: {
0152             bool hasCursor = testAttribute(Qt::WA_SetCursor);
0153             DateTimeGrid::HeaderType type = grid->sectionHandleAtPos( gridX, event->pos().y(), geometry());
0154             if (type != DateTimeGrid::NoHeader) {
0155                 if (!hasCursor) {
0156                     setCursor(QCursor(Qt::SplitHCursor));
0157                 }
0158                 event->accept();
0159                 return;
0160             }
0161             if (hasCursor) {
0162                 unsetCursor();
0163             }
0164             break;
0165         }
0166     }
0167     QWidget::mouseMoveEvent(event);
0168 }
0169 
0170 void HeaderWidget::wheelEvent( QWheelEvent *event )
0171 {
0172     DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
0173     if ( event->angleDelta().y() > 0 ) {
0174         grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() * 1.1 ) );
0175     } else {
0176         grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() / 1.1 ) );
0177     }
0178     event->accept();
0179 }
0180 
0181 void HeaderWidget::contextMenuEvent( QContextMenuEvent* event )
0182 {
0183     QMenu contextMenu;
0184 
0185     DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
0186     QAction* actionScaleAuto = nullptr;
0187     QAction* actionScaleMonth = nullptr;
0188     QAction* actionScaleWeek = nullptr;
0189     QAction* actionScaleDay = nullptr;
0190     QAction* actionScaleHour = nullptr;
0191     QAction* actionZoomIn = nullptr;
0192     QAction* actionZoomOut = nullptr;
0193     QAction* actionTimeline = nullptr;
0194     if ( grid != nullptr )
0195     {
0196         QMenu* menuScale = new QMenu( tr( "Scale", "@title:menu" ), &contextMenu );
0197         QActionGroup* scaleGroup = new QActionGroup( &contextMenu );
0198         scaleGroup->setExclusive( true );
0199 
0200         actionScaleAuto = new QAction( tr( "Auto", "@item:inmenu Automatic scale" ), menuScale );
0201         actionScaleAuto->setCheckable( true );
0202         actionScaleAuto->setChecked( grid->scale() == DateTimeGrid::ScaleAuto );
0203         actionScaleMonth = new QAction( tr( "Month", "@item:inmenu" ), menuScale );
0204         actionScaleMonth->setCheckable( true );
0205         actionScaleMonth->setChecked( grid->scale() == DateTimeGrid::ScaleMonth );
0206         actionScaleWeek = new QAction( tr( "Week", "@item:inmenu" ), menuScale );
0207         actionScaleWeek->setCheckable( true );
0208         actionScaleWeek->setChecked( grid->scale() == DateTimeGrid::ScaleWeek );
0209         actionScaleDay = new QAction( tr( "Day", "@item:inmenu" ), menuScale );
0210         actionScaleDay->setCheckable( true );
0211         actionScaleDay->setChecked( grid->scale() == DateTimeGrid::ScaleDay );
0212         actionScaleHour = new QAction( tr( "Hour", "@item:inmenu" ), menuScale );
0213         actionScaleHour->setCheckable( true );
0214         actionScaleHour->setChecked( grid->scale() == DateTimeGrid::ScaleHour );
0215 
0216         scaleGroup->addAction( actionScaleAuto );
0217         menuScale->addAction( actionScaleAuto );
0218 
0219         scaleGroup->addAction( actionScaleMonth );
0220         menuScale->addAction( actionScaleMonth );
0221 
0222         scaleGroup->addAction( actionScaleWeek );
0223         menuScale->addAction( actionScaleWeek );
0224 
0225         scaleGroup->addAction( actionScaleDay );
0226         menuScale->addAction( actionScaleDay );
0227 
0228         scaleGroup->addAction( actionScaleHour );
0229         menuScale->addAction( actionScaleHour );
0230 
0231         contextMenu.addMenu( menuScale );
0232 
0233         contextMenu.addSeparator();
0234 
0235         actionZoomIn = new QAction( tr( "Zoom In", "@action:inmenu" ), &contextMenu );
0236         contextMenu.addAction( actionZoomIn );
0237         actionZoomOut = new QAction( tr( "Zoom Out", "@action:inmenu" ), &contextMenu );
0238         contextMenu.addAction( actionZoomOut );
0239 
0240         contextMenu.addSeparator();
0241         actionTimeline = new QAction( tr( "Timeline...", "@action:inmenu" ), &contextMenu );
0242         contextMenu.addAction( actionTimeline );
0243     }
0244 
0245     if ( contextMenu.isEmpty() )
0246     {
0247         event->ignore();
0248         return;
0249     }
0250 
0251     const QAction* const action = contextMenu.exec( event->globalPos() );
0252     if ( action == nullptr ) {}
0253     else if ( action == actionScaleAuto )
0254     {
0255         assert( grid != nullptr );
0256         grid->setScale( DateTimeGrid::ScaleAuto );
0257     }
0258     else if ( action == actionScaleMonth )
0259     {
0260         assert( grid != nullptr );
0261         grid->setScale( DateTimeGrid::ScaleMonth );
0262     }
0263     else if ( action == actionScaleWeek )
0264     {
0265         assert( grid != nullptr );
0266         grid->setScale( DateTimeGrid::ScaleWeek );
0267     }
0268     else if ( action == actionScaleDay )
0269     {
0270         assert( grid != nullptr );
0271         grid->setScale( DateTimeGrid::ScaleDay );
0272     }
0273     else if ( action == actionScaleHour )
0274     {
0275         assert( grid != nullptr );
0276         grid->setScale( DateTimeGrid::ScaleHour );
0277     }
0278     else if ( action == actionZoomIn )
0279     {
0280         assert( grid != nullptr );
0281         grid->setDayWidth( grid->dayWidth() * 1.25 );
0282     }
0283     else if ( action == actionZoomOut )
0284     {
0285         assert( grid != nullptr );
0286         // daywidth *MUST NOT* go below 1.0, it is used as an integer later on
0287         grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() * 0.8 ) );
0288     }
0289     else if ( action == actionTimeline )
0290     {
0291         assert( grid != nullptr );
0292         DateTimeTimeLineDialog dlg(grid->timeLine());
0293         dlg.exec();
0294     }
0295     event->accept();
0296 }
0297 
0298 GraphicsView::Private::Private( GraphicsView* _q )
0299   : q( _q ), rowcontroller(nullptr), headerwidget( _q )
0300 {
0301 }
0302 
0303 GraphicsView::Private::~Private()
0304 {
0305 }
0306 
0307 void GraphicsView::Private::updateHeaderGeometry()
0308 {
0309     q->setViewportMargins(0,rowcontroller->headerHeight(),0,0);
0310     headerwidget.setGeometry( q->viewport()->x(),
0311                               q->viewport()->y() - rowcontroller->headerHeight(),
0312                               q->viewport()->width(),
0313                               rowcontroller->headerHeight() );
0314 }
0315 
0316 void GraphicsView::Private::slotGridChanged()
0317 {
0318     updateHeaderGeometry();
0319     headerwidget.update();
0320     q->updateSceneRect();
0321     q->update();
0322 }
0323 
0324 void GraphicsView::Private::slotHorizontalScrollValueChanged( int val )
0325 {
0326     const QRectF viewRect = q->transform().mapRect( q->sceneRect() );
0327     headerwidget.scrollTo( val-q->horizontalScrollBar()->minimum()+static_cast<int>( viewRect.left() ) );
0328 }
0329 
0330 void GraphicsView::Private::slotColumnsInserted( const QModelIndex& parent,  int start, int end )
0331 {
0332     Q_UNUSED( start );
0333     Q_UNUSED( end );
0334     QModelIndex idx = scene.model()->index( 0, 0, scene.summaryHandlingModel()->mapToSource( parent ) );
0335     do {
0336         scene.updateRow( scene.summaryHandlingModel()->mapFromSource( idx ) );
0337     } while ( ( idx = rowcontroller->indexBelow( idx ) ) != QModelIndex() && rowcontroller->isRowVisible( idx ) );
0338         //} while ( ( idx = d->treeview.indexBelow( idx ) ) != QModelIndex() && d->treeview.visualRect(idx).isValid() );
0339      q->updateSceneRect();
0340 }
0341 
0342 void GraphicsView::Private::slotColumnsRemoved( const QModelIndex& parent,  int start, int end )
0343 {
0344     // TODO
0345     Q_UNUSED( start );
0346     Q_UNUSED( end );
0347     Q_UNUSED( parent );
0348     q->updateScene();
0349 }
0350 
0351 void GraphicsView::Private::slotDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight )
0352 {
0353     //qDebug() << "GraphicsView::slotDataChanged("<<topLeft<<bottomRight<<")";
0354     const QModelIndex parent = topLeft.parent();
0355     for ( int row = topLeft.row(); row <= bottomRight.row(); ++row ) {
0356         scene.updateRow( scene.summaryHandlingModel()->index( row, 0, parent ) );
0357     }
0358 }
0359 
0360 void GraphicsView::Private::slotLayoutChanged()
0361 {
0362     //qDebug() << "slotLayoutChanged()";
0363     q->updateScene();
0364 }
0365 
0366 void GraphicsView::Private::slotModelReset()
0367 {
0368     //qDebug() << "slotModelReset()";
0369     q->updateScene();
0370 }
0371 
0372 void GraphicsView::Private::slotRowsInserted( const QModelIndex& parent,  int start, int end )
0373 {
0374     Q_UNUSED( parent );
0375     Q_UNUSED( start );
0376     Q_UNUSED( end );
0377     q->updateScene(); // TODO: This might be optimised
0378 }
0379 
0380 void GraphicsView::Private::removeConstraintsRecursive( QAbstractProxyModel *summaryModel, const QModelIndex& index )
0381 {
0382     if ( summaryModel->hasChildren( index ) ) {
0383         //qDebug() << "removing constraints from children of"<<index;
0384         for ( int row = 0; row < summaryModel->rowCount( index ); ++row ) {
0385             const QModelIndex child = summaryModel->index( row, index.column(), index );
0386             removeConstraintsRecursive( summaryModel, child );
0387         }
0388     }
0389     //qDebug() << "removing constraints from"<<index;
0390     // NOTE: Constraints are mapped to indexes in the summaryModel->sourceModel()
0391     const QList<Constraint> clst = scene.constraintModel()->constraintsForIndex( summaryModel->mapToSource( index ) );
0392     for ( const Constraint &c : clst ) {
0393         scene.constraintModel()->removeConstraint( c );
0394     }
0395 }
0396 
0397 void GraphicsView::Private::slotRowsAboutToBeRemoved( const QModelIndex& parent,  int start, int end )
0398 {
0399     //qDebug() << "GraphicsView::Private::slotRowsAboutToBeRemoved("<<parent<<start<<end<<")";
0400     QAbstractProxyModel *summaryModel = scene.summaryHandlingModel();
0401     for ( int row = start; row <= end; ++row ) {
0402         for ( int col = 0; col < summaryModel->columnCount( parent ); ++col ) {
0403             const QModelIndex idx = summaryModel->index( row, col, parent );
0404             removeConstraintsRecursive( summaryModel, idx );
0405             scene.removeItem( idx );
0406         }
0407     }
0408 }
0409 
0410 void GraphicsView::Private::slotRowsRemoved( const QModelIndex& parent,  int start, int end )
0411 {
0412     //qDebug() << "GraphicsView::Private::slotRowsRemoved("<<parent<<start<<end<<")";
0413     // TODO
0414     Q_UNUSED( parent );
0415     Q_UNUSED( start );
0416     Q_UNUSED( end );
0417 
0418     q->updateScene();
0419 }
0420 
0421 void GraphicsView::Private::slotItemClicked( const QModelIndex& idx )
0422 {
0423     QModelIndex sidx = idx;//scene.summaryHandlingModel()->mapToSource( idx );
0424     Q_EMIT q->clicked( sidx );
0425     if (q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, q))
0426         Q_EMIT q->activated( sidx );
0427 }
0428 
0429 void GraphicsView::Private::slotItemDoubleClicked( const QModelIndex& idx )
0430 {
0431     QModelIndex sidx = idx;//scene.summaryHandlingModel()->mapToSource( idx );
0432     Q_EMIT q->qrealClicked( sidx );
0433     if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, q))
0434         Q_EMIT q->activated( sidx );
0435 }
0436 
0437 void GraphicsView::Private::slotHeaderContextMenuRequested( const QPoint& pt )
0438 {
0439     Q_EMIT q->headerContextMenuRequested( headerwidget.mapToGlobal( pt ) );
0440 }
0441 
0442 GraphicsView::GraphicsView( QWidget* parent )
0443     : QGraphicsView( parent ), _d( new Private( this ) )
0444 {
0445 #if defined KDAB_EVAL
0446   EvalDialog::checkEvalLicense( "KD Gantt" );
0447 #endif
0448     connect( horizontalScrollBar(), SIGNAL(valueChanged(int)),
0449              this, SLOT(slotHorizontalScrollValueChanged(int)) );
0450     connect( &_d->scene, SIGNAL(gridChanged()),
0451              this, SLOT(slotGridChanged()) );
0452     connect( &_d->scene, SIGNAL(entered(QModelIndex)),
0453              this, SIGNAL(entered(QModelIndex)) );
0454     connect( &_d->scene, SIGNAL(pressed(QModelIndex)),
0455              this, SIGNAL(pressed(QModelIndex)) );
0456     connect( &_d->scene, SIGNAL(clicked(QModelIndex)),
0457              this, SLOT(slotItemClicked(QModelIndex)) );
0458     connect( &_d->scene, SIGNAL(qrealClicked(QModelIndex)),
0459              this, SLOT(slotItemDoubleClicked(QModelIndex)) );
0460     connect( &_d->scene, SIGNAL(sceneRectChanged(QRectF)),
0461              this, SLOT(updateSceneRect()) );
0462     connect( &_d->headerwidget, SIGNAL(customContextMenuRequested(QPoint)),
0463              this, SLOT(slotHeaderContextMenuRequested(QPoint)) );
0464     setScene( &_d->scene );
0465 
0466     // HACK!
0467     setSummaryHandlingModel( _d->scene.summaryHandlingModel() );
0468 
0469     // So that AbstractGrid::drawBackground() and AbstractGrid::drawForeground()
0470     // works properly
0471     setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
0472 
0473     //setCacheMode( CacheBackground );
0474 }
0475 
0476 
0477 GraphicsView::~GraphicsView()
0478 {
0479     delete _d;
0480 }
0481 
0482 #define d d_func()
0483 
0484 
0485 void GraphicsView::setModel( QAbstractItemModel* model )
0486 {
0487     if ( d->scene.model() ) {
0488         disconnect( d->scene.model() );
0489     }
0490 
0491     d->scene.setModel( model );
0492     if (model) {
0493         connect( model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
0494                 this, SLOT(updateSceneRect()) );
0495     }
0496     updateScene();
0497 }
0498 
0499 
0500 QAbstractItemModel* GraphicsView::model() const
0501 {
0502     return d->scene.model();
0503 }
0504 
0505 void GraphicsView::setSummaryHandlingModel( QAbstractProxyModel* proxyModel )
0506 {
0507     disconnect( d->scene.summaryHandlingModel() );
0508     d->scene.setSummaryHandlingModel( proxyModel );
0509 
0510     /* Connections. We have to rely on the treeview
0511      * to receive the signals before we do(!)
0512      */
0513     connect( proxyModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
0514              this,  SLOT(slotColumnsInserted(QModelIndex,int,int)) );
0515     connect( proxyModel, SIGNAL(columnsRemoved(QModelIndex,int,int)),
0516              this,  SLOT(slotColumnsRemoved(QModelIndex,int,int)) );
0517     connect( proxyModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
0518              this,  SLOT(slotDataChanged(QModelIndex,QModelIndex)) );
0519     connect( proxyModel, SIGNAL(layoutChanged()),
0520              this,  SLOT(slotLayoutChanged()) );
0521     connect( proxyModel, SIGNAL(modelReset()),
0522              this,  SLOT(slotModelReset()) );
0523     connect( proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
0524              this,  SLOT(slotRowsInserted(QModelIndex,int,int)) );
0525     connect( proxyModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
0526              this,  SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)) );
0527     connect( proxyModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
0528              this,  SLOT(slotRowsRemoved(QModelIndex,int,int)) );
0529 
0530     updateScene();
0531 }
0532 
0533 
0534 void GraphicsView::setConstraintModel( ConstraintModel* cmodel )
0535 {
0536     d->scene.setConstraintModel( cmodel );
0537 }
0538 
0539 
0540 ConstraintModel* GraphicsView::constraintModel() const
0541 {
0542     return d->scene.constraintModel();
0543 }
0544 
0545 
0546 QAbstractProxyModel* GraphicsView::summaryHandlingModel() const
0547 {
0548     return d->scene.summaryHandlingModel();
0549 }
0550 
0551 
0552 void GraphicsView::setRootIndex( const QModelIndex& idx )
0553 {
0554     d->scene.setRootIndex( idx );
0555 }
0556 
0557 
0558 QModelIndex GraphicsView::rootIndex() const
0559 {
0560     return d->scene.rootIndex();
0561 }
0562 
0563 
0564 void GraphicsView::setSelectionModel( QItemSelectionModel* model )
0565 {
0566     d->scene.setSelectionModel( model );
0567 }
0568 
0569 
0570 QItemSelectionModel* GraphicsView::selectionModel() const
0571 {
0572     return d->scene.selectionModel();
0573 }
0574 
0575 
0576 void GraphicsView::setItemDelegate( ItemDelegate* delegate )
0577 {
0578     d->scene.setItemDelegate( delegate );
0579 }
0580 
0581 
0582 ItemDelegate* GraphicsView::itemDelegate() const
0583 {
0584     return d->scene.itemDelegate();
0585 }
0586 
0587 
0588 void GraphicsView::setRowController( AbstractRowController* rowcontroller )
0589 {
0590     d->rowcontroller = rowcontroller;
0591     d->scene.setRowController( rowcontroller );
0592     updateScene();
0593 }
0594 
0595 
0596 AbstractRowController* GraphicsView::rowController() const
0597 {
0598     return d->rowcontroller;
0599 }
0600 
0601 
0602 void GraphicsView::setGrid( AbstractGrid* grid )
0603 {
0604     d->scene.setGrid( grid );
0605     d->slotGridChanged();
0606 }
0607 
0608 
0609 AbstractGrid* GraphicsView::grid() const
0610 {
0611     return d->scene.grid();
0612 }
0613 
0614 
0615 AbstractGrid* GraphicsView::takeGrid()
0616 {
0617     return d->scene.takeGrid();
0618 }
0619 
0620 
0621 void GraphicsView::setReadOnly( bool ro )
0622 {
0623     d->scene.setReadOnly( ro );
0624 }
0625 
0626 
0627 bool GraphicsView::isReadOnly() const
0628 {
0629     return d->scene.isReadOnly();
0630 }
0631 
0632 
0633 void GraphicsView::setHeaderContextMenuPolicy( Qt::ContextMenuPolicy p )
0634 {
0635     d->headerwidget.setContextMenuPolicy( p );
0636 }
0637 
0638 
0639 Qt::ContextMenuPolicy GraphicsView::headerContextMenuPolicy() const
0640 {
0641     return d->headerwidget.contextMenuPolicy();
0642 }
0643 
0644 
0645 void GraphicsView::addConstraint( const QModelIndex& from,
0646                                   const QModelIndex& to,
0647                                   Qt::KeyboardModifiers modifiers )
0648 {
0649     if ( isReadOnly() ) return;
0650     ConstraintModel* cmodel = constraintModel();
0651     assert( cmodel );
0652     Constraint c( from, to, ( modifiers&Qt::ShiftModifier )?Constraint::TypeHard:Constraint::TypeSoft );
0653     if ( cmodel->hasConstraint( c ) ) cmodel->removeConstraint( c );
0654     else cmodel->addConstraint( c );
0655 }
0656 
0657 void GraphicsView::resizeEvent( QResizeEvent* ev )
0658 {
0659     d->updateHeaderGeometry();
0660     QRectF r = scene()->itemsBoundingRect();
0661     // To scroll more to the left than the actual item start, bug #4516
0662     r.setLeft( qMin<qreal>( 0.0, r.left() ) );
0663     // TODO: take scrollbars into account (if not always on)
0664     // The scene should be at least the size of the viewport
0665     QSizeF size = viewport()->size();
0666     //TODO: why -2 below? size should be ex. frames etc?
0667     if ( size.width() > r.width() ) {
0668         r.setWidth( size.width() - 2 );
0669     }
0670     if ( size.height() > r.height() ) {
0671         r.setHeight( size.height() - 2 );
0672     }
0673     const int totalh = rowController()->totalHeight();
0674     if ( r.height() < totalh ) {
0675         r.setHeight( totalh );
0676     }
0677 
0678     scene()->setSceneRect( r );
0679 
0680     QGraphicsView::resizeEvent( ev );
0681 }
0682 
0683 
0684 QModelIndex GraphicsView::indexAt( const QPoint& pos ) const
0685 {
0686     QGraphicsItem* item = itemAt( pos );
0687     if ( GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
0688         return d->scene.summaryHandlingModel()->mapToSource( gitem->index() );
0689     } else {
0690         return QModelIndex();
0691     }
0692 }
0693 
0694 
0695 void GraphicsView::clearItems()
0696 {
0697     d->scene.clearItems();
0698 }
0699 
0700 
0701 void GraphicsView::updateRow( const QModelIndex& idx )
0702 {
0703     d->scene.updateRow( d->scene.summaryHandlingModel()->mapFromSource( idx ) );
0704 }
0705 
0706 
0707 void GraphicsView::updateSceneRect()
0708 {
0709     /* What to do with this? We need to shrink the view to
0710      * make collapsing items work
0711      */
0712     qreal range = horizontalScrollBar()->maximum()-horizontalScrollBar()->minimum();
0713     const qreal hscroll = horizontalScrollBar()->value()/( range>0?range:1 );
0714     QRectF r = d->scene.itemsBoundingRect();
0715     // To scroll more to the left than the actual item start, bug #4516
0716     r.setTop( 0. );
0717     r.setLeft( qMin<qreal>( 0.0, r.left() ) );
0718     r.setSize( r.size().expandedTo( viewport()->size() ) );
0719     const int totalh = rowController()->totalHeight();
0720     if ( r.height() < totalh ) r.setHeight( totalh );
0721     d->scene.setSceneRect( r );
0722 
0723     /* set scrollbar to keep the same time in view */
0724     range = horizontalScrollBar()->maximum()-horizontalScrollBar()->minimum();
0725     if ( range>0 ) {
0726         horizontalScrollBar()->setValue( qRound( hscroll*range ) );
0727     } else {
0728         // keep header in sync with scene
0729         d->headerwidget.scrollTo(r.left());
0730     }
0731     /* We have to update here to adjust for any rows with no
0732      * information because they are painted with a different
0733      * background brush
0734      */
0735     d->scene.invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
0736 }
0737 
0738 
0739 void GraphicsView::updateScene()
0740 {
0741     clearItems();
0742     if ( !model()) return;
0743     if ( !rowController()) return;
0744     QModelIndex idx = model()->index( 0, 0, rootIndex() );
0745     do {
0746         updateRow( idx );
0747     } while ( ( idx = rowController()->indexBelow( idx ) ) != QModelIndex() && rowController()->isRowVisible(idx) );
0748     //constraintModel()->cleanup();
0749     //qDebug() << constraintModel();
0750     updateSceneRect();
0751     if ( scene() ) scene()->invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
0752 }
0753 
0754 #if 0
0755 TODO: For 3.0
0756 
0757 GraphicsItem* GraphicsView::createItem( ItemType type ) const
0758 {
0759     Q_UNUSED(type)
0760     return new GraphicsItem;
0761 }
0762 #endif
0763 
0764 
0765 void GraphicsView::deleteSubtree( const QModelIndex& idx )
0766 {
0767     d->scene.deleteSubtree( d->scene.summaryHandlingModel()->mapFromSource( idx ) );
0768 }
0769 
0770 
0771 void GraphicsView::print( QPrinter* printer, bool drawRowLabels, bool drawColumnLabels )
0772 {
0773     d->scene.print( printer, drawRowLabels, drawColumnLabels );
0774 }
0775 
0776 
0777 void GraphicsView::print( QPrinter* printer,  qreal start, qreal end, bool drawRowLabels, bool drawColumnLabels )
0778 {
0779     d->scene.print( printer, start, end, drawRowLabels, drawColumnLabels );
0780 }
0781 
0782 
0783 void GraphicsView::print( QPainter* painter, const QRectF& targetRect, bool drawRowLabels, bool drawColumnLabels )
0784 {
0785   d->scene.print(painter, targetRect, drawRowLabels, drawColumnLabels);
0786 }
0787 
0788 
0789 void GraphicsView::print( QPainter* painter, qreal start, qreal end,
0790                           const QRectF& targetRect, bool drawRowLabels, bool drawColumnLabels )
0791 {
0792   d->scene.print(painter, start, end, targetRect, drawRowLabels, drawColumnLabels);
0793 }
0794 
0795 void GraphicsView::printDiagram( QPrinter *printer, const PrintingContext &context )
0796 {
0797     d->scene.printDiagram( printer, context );
0798 }
0799 
0800 #include "moc_kganttgraphicsview.cpp"