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"