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