00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "kdganttgraphicsview.h"
00026 #include "kdganttgraphicsview_p.h"
00027 #include "kdganttabstractrowcontroller.h"
00028 #include "kdganttgraphicsitem.h"
00029 #include "kdganttconstraintmodel.h"
00030
00031 #include <QMenu>
00032 #include <QPainter>
00033 #include <QPaintEvent>
00034 #include <QResizeEvent>
00035 #include <QScrollBar>
00036 #include <QAbstractProxyModel>
00037
00038 #include <cassert>
00039
00044 using namespace KDGantt;
00045
00046 HeaderWidget::HeaderWidget( GraphicsView* parent )
00047 : QWidget( parent ), m_offset( 0. )
00048 {
00049 assert( parent );
00050 }
00051
00052 HeaderWidget::~HeaderWidget()
00053 {
00054 }
00055
00056 void HeaderWidget::scrollTo( int v )
00057 {
00058 m_offset = v;
00059
00060
00061 update();
00062 }
00063
00064 void HeaderWidget::paintEvent( QPaintEvent* ev )
00065 {
00066 QPainter p( this );
00067 view()->grid()->paintHeader( &p, rect(), ev->rect(), m_offset, this );
00068 }
00069
00070 void HeaderWidget::contextMenuEvent( QContextMenuEvent* event )
00071 {
00072 QMenu contextMenu;
00073
00074 DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
00075 QAction* actionScaleAuto = 0;
00076 QAction* actionScaleMonth = 0;
00077 QAction* actionScaleWeek = 0;
00078 QAction* actionScaleDay = 0;
00079 QAction* actionScaleHour = 0;
00080 QAction* actionZoomIn = 0;
00081 QAction* actionZoomOut = 0;
00082 if( grid != 0 )
00083 {
00084 QMenu* menuScale = new QMenu( tr( "Scale" ), &contextMenu );
00085 QActionGroup* scaleGroup = new QActionGroup( &contextMenu );
00086 scaleGroup->setExclusive( true );
00087
00088 actionScaleAuto = new QAction( tr( "Auto" ), menuScale );
00089 actionScaleAuto->setCheckable( true );
00090 actionScaleAuto->setChecked( grid->scale() == DateTimeGrid::ScaleAuto );
00091 actionScaleMonth = new QAction( tr( "Month" ), menuScale );
00092 actionScaleMonth->setCheckable( true );
00093 actionScaleMonth->setChecked( grid->scale() == DateTimeGrid::ScaleMonth );
00094 actionScaleWeek = new QAction( tr( "Week" ), menuScale );
00095 actionScaleWeek->setCheckable( true );
00096 actionScaleWeek->setChecked( grid->scale() == DateTimeGrid::ScaleWeek );
00097 actionScaleDay = new QAction( tr( "Day" ), menuScale );
00098 actionScaleDay->setCheckable( true );
00099 actionScaleDay->setChecked( grid->scale() == DateTimeGrid::ScaleDay );
00100 actionScaleHour = new QAction( tr( "Hour" ), menuScale );
00101 actionScaleHour->setCheckable( true );
00102 actionScaleHour->setChecked( grid->scale() == DateTimeGrid::ScaleHour );
00103
00104 scaleGroup->addAction( actionScaleAuto );
00105 menuScale->addAction( actionScaleAuto );
00106
00107 scaleGroup->addAction( actionScaleMonth );
00108 menuScale->addAction( actionScaleMonth );
00109
00110 scaleGroup->addAction( actionScaleWeek );
00111 menuScale->addAction( actionScaleWeek );
00112
00113 scaleGroup->addAction( actionScaleDay );
00114 menuScale->addAction( actionScaleDay );
00115
00116 scaleGroup->addAction( actionScaleHour );
00117 menuScale->addAction( actionScaleHour );
00118
00119 contextMenu.addMenu( menuScale );
00120
00121 contextMenu.addSeparator();
00122
00123 actionZoomIn = new QAction( tr( "Zoom In" ), &contextMenu );
00124 contextMenu.addAction( actionZoomIn );
00125 actionZoomOut = new QAction( tr( "Zoom Out" ), &contextMenu );
00126 contextMenu.addAction( actionZoomOut );
00127 }
00128
00129 if( contextMenu.isEmpty() )
00130 {
00131 event->ignore();
00132 return;
00133 }
00134
00135 const QAction* const action = contextMenu.exec( event->globalPos() );
00136 if( action == 0 ) {}
00137 else if( action == actionScaleAuto )
00138 {
00139 assert( grid != 0 );
00140 grid->setScale( DateTimeGrid::ScaleAuto );
00141 }
00142 else if( action == actionScaleMonth )
00143 {
00144 assert( grid != 0 );
00145 grid->setScale( DateTimeGrid::ScaleMonth );
00146 }
00147 else if( action == actionScaleWeek )
00148 {
00149 assert( grid != 0 );
00150 grid->setScale( DateTimeGrid::ScaleWeek );
00151 }
00152 else if( action == actionScaleDay )
00153 {
00154 assert( grid != 0 );
00155 grid->setScale( DateTimeGrid::ScaleDay );
00156 }
00157 else if( action == actionScaleHour )
00158 {
00159 assert( grid != 0 );
00160 grid->setScale( DateTimeGrid::ScaleHour );
00161 }
00162 else if( action == actionZoomIn )
00163 {
00164 assert( grid != 0 );
00165 grid->setDayWidth( grid->dayWidth() + 10.0 );
00166 }
00167 else if( action == actionZoomOut )
00168 {
00169 assert( grid != 0 );
00170 grid->setDayWidth( grid->dayWidth() - 10.0 );
00171 }
00172
00173 event->accept();
00174 }
00175
00176 GraphicsView::Private::Private( GraphicsView* _q )
00177 : q( _q ), rowcontroller(0), headerwidget( _q )
00178 {
00179 }
00180
00181 void GraphicsView::Private::updateHeaderGeometry()
00182 {
00183 q->setViewportMargins(0,rowcontroller->headerHeight(),0,0);
00184 headerwidget.setGeometry( q->viewport()->x(),
00185 q->viewport()->y() - rowcontroller->headerHeight(),
00186 q->viewport()->width(),
00187 rowcontroller->headerHeight() );
00188 }
00189
00190 void GraphicsView::Private::slotGridChanged()
00191 {
00192 updateHeaderGeometry();
00193 headerwidget.update();
00194 q->updateSceneRect();
00195 q->update();
00196 }
00197
00198 void GraphicsView::Private::slotHorizontalScrollValueChanged( int val )
00199 {
00200 #if QT_VERSION >= 0x040300
00201 const QRectF viewRect = q->transform().mapRect( q->sceneRect() );
00202 #else
00203 const QRectF viewRect = q->sceneRect();
00204 #endif
00205 headerwidget.scrollTo( val-q->horizontalScrollBar()->minimum()+static_cast<int>( viewRect.left() ) );
00206 }
00207
00208 void GraphicsView::Private::slotColumnsInserted( const QModelIndex& parent, int start, int end )
00209 {
00210 Q_UNUSED( start );
00211 Q_UNUSED( end );
00212 QModelIndex idx = scene.model()->index( 0, 0, scene.summaryHandlingModel()->mapToSource( parent ) );
00213 do {
00214 scene.updateRow( scene.summaryHandlingModel()->mapFromSource( idx ) );
00215 } while ( ( idx = rowcontroller->indexBelow( idx ) ) != QModelIndex() && rowcontroller->isRowVisible( idx ) );
00216
00217 q->updateSceneRect();
00218 }
00219
00220 void GraphicsView::Private::slotColumnsRemoved( const QModelIndex& parent, int start, int end )
00221 {
00222
00223 Q_UNUSED( start );
00224 Q_UNUSED( end );
00225 Q_UNUSED( parent );
00226 q->updateScene();
00227 }
00228
00229 void GraphicsView::Private::slotDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight )
00230 {
00231
00232 const QModelIndex parent = topLeft.parent();
00233 for ( int row = topLeft.row(); row <= bottomRight.row(); ++row ) {
00234 scene.updateRow( scene.summaryHandlingModel()->index( row, 0, parent ) );
00235 }
00236 }
00237
00238 void GraphicsView::Private::slotLayoutChanged()
00239 {
00240
00241 q->updateScene();
00242 }
00243
00244 void GraphicsView::Private::slotModelReset()
00245 {
00246
00247 q->updateScene();
00248 }
00249
00250 void GraphicsView::Private::slotRowsInserted( const QModelIndex& parent, int start, int end )
00251 {
00252 Q_UNUSED( parent );
00253 Q_UNUSED( start );
00254 Q_UNUSED( end );
00255 q->updateScene();
00256 }
00257
00258 void GraphicsView::Private::slotRowsAboutToBeRemoved( const QModelIndex& parent, int start, int end )
00259 {
00260
00261 for ( int row = start; row <= end; ++row ) {
00262 for ( int col = 0; col < scene.summaryHandlingModel()->columnCount( parent ); ++col ) {
00263
00264 scene.removeItem( scene.summaryHandlingModel()->index( row, col, parent ) );
00265 }
00266 }
00267 }
00268
00269 void GraphicsView::Private::slotRowsRemoved( const QModelIndex& parent, int start, int end )
00270 {
00271
00272
00273 Q_UNUSED( parent );
00274 Q_UNUSED( start );
00275 Q_UNUSED( end );
00276
00277 q->updateScene();
00278 }
00279
00280 void GraphicsView::Private::slotItemClicked( const QModelIndex& idx )
00281 {
00282 QModelIndex sidx = idx;
00283 emit q->clicked( sidx );
00284 if (q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, q))
00285 emit q->activated( sidx );
00286 }
00287
00288 void GraphicsView::Private::slotItemDoubleClicked( const QModelIndex& idx )
00289 {
00290 QModelIndex sidx = idx;
00291 emit q->doubleClicked( sidx );
00292 if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, q))
00293 emit q->activated( sidx );
00294 }
00295
00296 void GraphicsView::Private::slotHeaderContextMenuRequested( const QPoint& pt )
00297 {
00298 emit q->headerContextMenuRequested( headerwidget.mapToGlobal( pt ) );
00299 }
00300
00322 GraphicsView::GraphicsView( QWidget* parent )
00323 : QGraphicsView( parent ), _d( new Private( this ) )
00324 {
00325 connect( horizontalScrollBar(), SIGNAL( valueChanged( int ) ),
00326 this, SLOT( slotHorizontalScrollValueChanged( int ) ) );
00327 connect( &_d->scene, SIGNAL( gridChanged() ),
00328 this, SLOT( slotGridChanged() ) );
00329 connect( &_d->scene, SIGNAL( entered( const QModelIndex& ) ),
00330 this, SIGNAL( entered( const QModelIndex& ) ) );
00331 connect( &_d->scene, SIGNAL( pressed( const QModelIndex& ) ),
00332 this, SIGNAL( pressed( const QModelIndex& ) ) );
00333 connect( &_d->scene, SIGNAL( clicked( const QModelIndex& ) ),
00334 this, SLOT( slotItemClicked( const QModelIndex& ) ) );
00335 connect( &_d->scene, SIGNAL( doubleClicked( const QModelIndex& ) ),
00336 this, SLOT( slotItemDoubleClicked( const QModelIndex& ) ) );
00337 connect( &_d->scene, SIGNAL( sceneRectChanged( const QRectF& ) ),
00338 this, SLOT( updateSceneRect() ) );
00339 connect( &_d->headerwidget, SIGNAL( customContextMenuRequested( const QPoint& ) ),
00340 this, SLOT( slotHeaderContextMenuRequested( const QPoint& ) ) );
00341 setScene( &_d->scene );
00342
00343
00344 setSummaryHandlingModel( _d->scene.summaryHandlingModel() );
00345
00346
00347 }
00348
00350 GraphicsView::~GraphicsView()
00351 {
00352 delete _d;
00353 }
00354
00355 #define d d_func()
00356
00370 void GraphicsView::setModel( QAbstractItemModel* model )
00371 {
00372 if ( d->scene.model() ) {
00373 disconnect( d->scene.model() );
00374 }
00375
00376 d->scene.setModel( model );
00377 connect( model, SIGNAL( dataChanged( const QModelIndex&, const QModelIndex& ) ),
00378 this, SLOT( updateSceneRect() ) );
00379 updateScene();
00380 }
00381
00384 QAbstractItemModel* GraphicsView::model() const
00385 {
00386 return d->scene.model();
00387 }
00388
00389 void GraphicsView::setSummaryHandlingModel( QAbstractProxyModel* proxyModel )
00390 {
00391 disconnect( d->scene.summaryHandlingModel() );
00392 d->scene.setSummaryHandlingModel( proxyModel );
00393
00394
00395
00396
00397 connect( proxyModel, SIGNAL( columnsInserted( const QModelIndex&, int, int ) ),
00398 this, SLOT( slotColumnsInserted( const QModelIndex&, int, int ) ) );
00399 connect( proxyModel, SIGNAL( columnsRemoved( const QModelIndex&, int, int ) ),
00400 this, SLOT( slotColumnsRemoved( const QModelIndex&, int, int ) ) );
00401 connect( proxyModel, SIGNAL( dataChanged( const QModelIndex&, const QModelIndex& ) ),
00402 this, SLOT( slotDataChanged( const QModelIndex&, const QModelIndex& ) ) );
00403 connect( proxyModel, SIGNAL( layoutChanged() ),
00404 this, SLOT( slotLayoutChanged() ) );
00405 connect( proxyModel, SIGNAL( modelReset() ),
00406 this, SLOT( slotModelReset() ) );
00407 connect( proxyModel, SIGNAL( rowsInserted( const QModelIndex&, int, int ) ),
00408 this, SLOT( slotRowsInserted( const QModelIndex&, int, int ) ) );
00409 connect( proxyModel, SIGNAL( rowsAboutToBeRemoved( const QModelIndex&, int, int ) ),
00410 this, SLOT( slotRowsAboutToBeRemoved( const QModelIndex&, int, int ) ) );
00411 connect( proxyModel, SIGNAL( rowsRemoved( const QModelIndex&, int, int ) ),
00412 this, SLOT( slotRowsRemoved( const QModelIndex&, int, int ) ) );
00413
00414 updateScene();
00415 }
00416
00420 void GraphicsView::setConstraintModel( ConstraintModel* cmodel )
00421 {
00422 d->scene.setConstraintModel( cmodel );
00423 }
00424
00427 ConstraintModel* GraphicsView::constraintModel() const
00428 {
00429 return d->scene.constraintModel();
00430 }
00431
00434 QAbstractProxyModel* GraphicsView::summaryHandlingModel() const
00435 {
00436 return d->scene.summaryHandlingModel();
00437 }
00438
00442 void GraphicsView::setRootIndex( const QModelIndex& idx )
00443 {
00444 d->scene.setRootIndex( idx );
00445 }
00446
00449 QModelIndex GraphicsView::rootIndex() const
00450 {
00451 return d->scene.rootIndex();
00452 }
00453
00457 void GraphicsView::setSelectionModel( QItemSelectionModel* model )
00458 {
00459 d->scene.setSelectionModel( model );
00460 }
00461
00464 QItemSelectionModel* GraphicsView::selectionModel() const
00465 {
00466 return d->scene.selectionModel();
00467 }
00468
00472 void GraphicsView::setItemDelegate( ItemDelegate* delegate )
00473 {
00474 d->scene.setItemDelegate( delegate );
00475 }
00476
00479 ItemDelegate* GraphicsView::itemDelegate() const
00480 {
00481 return d->scene.itemDelegate();
00482 }
00483
00489 void GraphicsView::setRowController( AbstractRowController* rowcontroller )
00490 {
00491 d->rowcontroller = rowcontroller;
00492 d->scene.setRowController( rowcontroller );
00493 updateScene();
00494 }
00495
00499 AbstractRowController* GraphicsView::rowController() const
00500 {
00501 return d->rowcontroller;
00502 }
00503
00509 void GraphicsView::setGrid( AbstractGrid* grid )
00510 {
00511 d->scene.setGrid( grid );
00512 d->slotGridChanged();
00513 }
00514
00517 AbstractGrid* GraphicsView::grid() const
00518 {
00519 return d->scene.grid();
00520 }
00521
00525 void GraphicsView::setReadOnly( bool ro )
00526 {
00527 d->scene.setReadOnly( ro );
00528 }
00529
00532 bool GraphicsView::isReadOnly() const
00533 {
00534 return d->scene.isReadOnly();
00535 }
00536
00546 void GraphicsView::setHeaderContextMenuPolicy( Qt::ContextMenuPolicy p )
00547 {
00548 d->headerwidget.setContextMenuPolicy( p );
00549 }
00550
00553 Qt::ContextMenuPolicy GraphicsView::headerContextMenuPolicy() const
00554 {
00555 return d->headerwidget.contextMenuPolicy();
00556 }
00557
00566 void GraphicsView::addConstraint( const QModelIndex& from,
00567 const QModelIndex& to,
00568 Qt::KeyboardModifiers modifiers )
00569 {
00570 if ( isReadOnly() ) return;
00571 ConstraintModel* cmodel = constraintModel();
00572 assert( cmodel );
00573 Constraint c( from, to, ( modifiers&Qt::ShiftModifier )?Constraint::TypeHard:Constraint::TypeSoft );
00574 if ( cmodel->hasConstraint( c ) ) cmodel->removeConstraint( c );
00575 else cmodel->addConstraint( c );
00576 }
00577
00578 void GraphicsView::resizeEvent( QResizeEvent* ev )
00579 {
00580 d->updateHeaderGeometry();
00581 QRectF r = scene()->itemsBoundingRect();
00582
00583 r.setLeft( qMin( qreal(0.0), r.left() ) );
00584
00585
00586 QSizeF size = viewport()->size();
00587
00588 if ( size.width() > r.width() ) {
00589 r.setWidth( size.width() - 2 );
00590 }
00591 if ( size.height() > r.height() ) {
00592 r.setHeight( size.height() - 2 );
00593 }
00594 const int totalh = rowController()->totalHeight();
00595 if ( r.height() < totalh ) {
00596 r.setHeight( totalh );
00597 }
00598
00599 scene()->setSceneRect( r );
00600
00601 QGraphicsView::resizeEvent( ev );
00602 }
00603
00610 QModelIndex GraphicsView::indexAt( const QPoint& pos ) const
00611 {
00612 QGraphicsItem* item = itemAt( pos );
00613 if ( GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
00614 return d->scene.summaryHandlingModel()->mapToSource( gitem->index() );
00615 } else {
00616 return QModelIndex();
00617 }
00618 }
00619
00621 void GraphicsView::clearItems()
00622 {
00623 d->scene.clearItems();
00624 }
00625
00627 void GraphicsView::updateRow( const QModelIndex& idx )
00628 {
00629 d->scene.updateRow( d->scene.summaryHandlingModel()->mapFromSource( idx ) );
00630 }
00631
00635 void GraphicsView::updateSceneRect()
00636 {
00637
00638
00639
00640 qreal range = horizontalScrollBar()->maximum()-horizontalScrollBar()->minimum();
00641 const qreal hscroll = horizontalScrollBar()->value()/( range>0?range:1 );
00642 QRectF r = d->scene.itemsBoundingRect();
00643
00644 r.setTop( 0. );
00645 r.setLeft( qMin( qreal(0.0), r.left() ) );
00646 r.setSize( r.size().expandedTo( viewport()->size() ) );
00647 const int totalh = rowController()->totalHeight();
00648 if ( r.height() < totalh ) r.setHeight( totalh );
00649 d->scene.setSceneRect( r );
00650
00651
00652 range = horizontalScrollBar()->maximum()-horizontalScrollBar()->minimum();
00653 if ( range>0 ) horizontalScrollBar()->setValue( qRound( hscroll*range ) );
00654
00655
00656
00657
00658
00659 d->scene.invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
00660 }
00661
00665 void GraphicsView::updateScene()
00666 {
00667 clearItems();
00668 if( !model()) return;
00669 if( !rowController()) return;
00670 QModelIndex idx = model()->index( 0, 0, rootIndex() );
00671 do {
00672 updateRow( idx );
00673 } while ( ( idx = rowController()->indexBelow( idx ) ) != QModelIndex() && rowController()->isRowVisible(idx) );
00674
00675
00676 updateSceneRect();
00677 if ( scene() ) scene()->invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
00678 }
00679
00681 GraphicsItem* GraphicsView::createItem( ItemType type ) const
00682 {
00683 return d->scene.createItem( type );
00684 }
00685
00687 void GraphicsView::deleteSubtree( const QModelIndex& idx )
00688 {
00689 d->scene.deleteSubtree( d->scene.summaryHandlingModel()->mapFromSource( idx ) );
00690 }
00691
00698 void GraphicsView::print( QPrinter* printer, bool drawRowLabels )
00699 {
00700 d->scene.print( printer, drawRowLabels );
00701 }
00702
00713 void GraphicsView::print( QPrinter* printer, qreal start, qreal end, bool drawRowLabels )
00714 {
00715 d->scene.print( printer, start, end, drawRowLabels );
00716 }
00717
00722 void GraphicsView::print( QPainter* painter, const QRectF& targetRect, bool drawRowLabels )
00723 {
00724 d->scene.print(painter,targetRect,drawRowLabels);
00725 }
00726
00735 void GraphicsView::print( QPainter* painter, qreal start, qreal end,
00736 const QRectF& targetRect, bool drawRowLabels )
00737 {
00738 d->scene.print(painter, start, end, targetRect, drawRowLabels);
00739 }
00740
00741
00742 #include "moc_kdganttgraphicsview.cpp"