00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kdganttgraphicsview.h"
00024 #include "kdganttgraphicsview_p.h"
00025 #include "kdganttabstractrowcontroller.h"
00026 #include "kdganttgraphicsitem.h"
00027 #include "kdganttconstraintmodel.h"
00028
00029 #include <QMenu>
00030 #include <QPainter>
00031 #include <QPaintEvent>
00032 #include <QResizeEvent>
00033 #include <QScrollBar>
00034 #include <QAbstractProxyModel>
00035
00036 #include <cassert>
00037
00038 #if defined KDAB_EVAL
00039 #include "../evaldialog/evaldialog.h"
00040 #endif
00041
00046 using namespace KDGantt;
00047
00048 HeaderWidget::HeaderWidget( GraphicsView* parent )
00049 : QWidget( parent ), m_offset( 0. )
00050 {
00051 assert( parent );
00052 }
00053
00054 HeaderWidget::~HeaderWidget()
00055 {
00056 }
00057
00058 void HeaderWidget::scrollTo( int v )
00059 {
00060 m_offset = v;
00061
00062
00063 update();
00064 }
00065
00066 void HeaderWidget::paintEvent( QPaintEvent* ev )
00067 {
00068 QPainter p( this );
00069 view()->grid()->paintHeader( &p, rect(), ev->rect(), m_offset, this );
00070 }
00071
00072 bool HeaderWidget::event( QEvent* event )
00073 {
00074 if ( event->type() == QEvent::ToolTip ) {
00075 DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
00076 if ( grid ) {
00077 QHelpEvent *e = static_cast<QHelpEvent*>( event );
00078 QDateTime dt = grid->mapFromChart( view()->mapToScene( e->x(), 0 ).x() ).toDateTime();
00079 setToolTip( dt.toString() );
00080 }
00081 }
00082 return QWidget::event( event );
00083 }
00084
00085 void HeaderWidget::contextMenuEvent( QContextMenuEvent* event )
00086 {
00087 QMenu contextMenu;
00088
00089 DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
00090 QAction* actionScaleAuto = 0;
00091 QAction* actionScaleMonth = 0;
00092 QAction* actionScaleWeek = 0;
00093 QAction* actionScaleDay = 0;
00094 QAction* actionScaleHour = 0;
00095 QAction* actionZoomIn = 0;
00096 QAction* actionZoomOut = 0;
00097 if( grid != 0 )
00098 {
00099 QMenu* menuScale = new QMenu( tr( "Scale" ), &contextMenu );
00100 QActionGroup* scaleGroup = new QActionGroup( &contextMenu );
00101 scaleGroup->setExclusive( true );
00102
00103 actionScaleAuto = new QAction( tr( "Auto" ), menuScale );
00104 actionScaleAuto->setCheckable( true );
00105 actionScaleAuto->setChecked( grid->scale() == DateTimeGrid::ScaleAuto );
00106 actionScaleMonth = new QAction( tr( "Month" ), menuScale );
00107 actionScaleMonth->setCheckable( true );
00108 actionScaleMonth->setChecked( grid->scale() == DateTimeGrid::ScaleMonth );
00109 actionScaleWeek = new QAction( tr( "Week" ), menuScale );
00110 actionScaleWeek->setCheckable( true );
00111 actionScaleWeek->setChecked( grid->scale() == DateTimeGrid::ScaleWeek );
00112 actionScaleDay = new QAction( tr( "Day" ), menuScale );
00113 actionScaleDay->setCheckable( true );
00114 actionScaleDay->setChecked( grid->scale() == DateTimeGrid::ScaleDay );
00115 actionScaleHour = new QAction( tr( "Hour" ), menuScale );
00116 actionScaleHour->setCheckable( true );
00117 actionScaleHour->setChecked( grid->scale() == DateTimeGrid::ScaleHour );
00118
00119 scaleGroup->addAction( actionScaleAuto );
00120 menuScale->addAction( actionScaleAuto );
00121
00122 scaleGroup->addAction( actionScaleMonth );
00123 menuScale->addAction( actionScaleMonth );
00124
00125 scaleGroup->addAction( actionScaleWeek );
00126 menuScale->addAction( actionScaleWeek );
00127
00128 scaleGroup->addAction( actionScaleDay );
00129 menuScale->addAction( actionScaleDay );
00130
00131 scaleGroup->addAction( actionScaleHour );
00132 menuScale->addAction( actionScaleHour );
00133
00134 contextMenu.addMenu( menuScale );
00135
00136 contextMenu.addSeparator();
00137
00138 actionZoomIn = new QAction( tr( "Zoom In" ), &contextMenu );
00139 contextMenu.addAction( actionZoomIn );
00140 actionZoomOut = new QAction( tr( "Zoom Out" ), &contextMenu );
00141 contextMenu.addAction( actionZoomOut );
00142 }
00143
00144 if( contextMenu.isEmpty() )
00145 {
00146 event->ignore();
00147 return;
00148 }
00149
00150 const QAction* const action = contextMenu.exec( event->globalPos() );
00151 if( action == 0 ) {}
00152 else if( action == actionScaleAuto )
00153 {
00154 assert( grid != 0 );
00155 grid->setScale( DateTimeGrid::ScaleAuto );
00156 }
00157 else if( action == actionScaleMonth )
00158 {
00159 assert( grid != 0 );
00160 grid->setScale( DateTimeGrid::ScaleMonth );
00161 }
00162 else if( action == actionScaleWeek )
00163 {
00164 assert( grid != 0 );
00165 grid->setScale( DateTimeGrid::ScaleWeek );
00166 }
00167 else if( action == actionScaleDay )
00168 {
00169 assert( grid != 0 );
00170 grid->setScale( DateTimeGrid::ScaleDay );
00171 }
00172 else if( action == actionScaleHour )
00173 {
00174 assert( grid != 0 );
00175 grid->setScale( DateTimeGrid::ScaleHour );
00176 }
00177 else if( action == actionZoomIn )
00178 {
00179 assert( grid != 0 );
00180 grid->setDayWidth( grid->dayWidth() + 10.0 );
00181 }
00182 else if( action == actionZoomOut )
00183 {
00184 assert( grid != 0 );
00185 grid->setDayWidth( grid->dayWidth() - 10.0 );
00186 }
00187
00188 event->accept();
00189 }
00190
00191 GraphicsView::Private::Private( GraphicsView* _q )
00192 : q( _q ), rowcontroller(0), headerwidget( _q )
00193 {
00194 }
00195
00196 void GraphicsView::Private::updateHeaderGeometry()
00197 {
00198 q->setViewportMargins(0,rowcontroller->headerHeight(),0,0);
00199 headerwidget.setGeometry( q->viewport()->x(),
00200 q->viewport()->y() - rowcontroller->headerHeight(),
00201 q->viewport()->width(),
00202 rowcontroller->headerHeight() );
00203 }
00204
00205 void GraphicsView::Private::slotGridChanged()
00206 {
00207 updateHeaderGeometry();
00208 headerwidget.update();
00209 q->updateSceneRect();
00210 q->update();
00211 }
00212
00213 void GraphicsView::Private::slotHorizontalScrollValueChanged( int val )
00214 {
00215 #if QT_VERSION >= 0x040300
00216 const QRectF viewRect = q->transform().mapRect( q->sceneRect() );
00217 #else
00218 const QRectF viewRect = q->sceneRect();
00219 #endif
00220 headerwidget.scrollTo( val-q->horizontalScrollBar()->minimum()+static_cast<int>( viewRect.left() ) );
00221 }
00222
00223 void GraphicsView::Private::slotColumnsInserted( const QModelIndex& parent, int start, int end )
00224 {
00225 Q_UNUSED( start );
00226 Q_UNUSED( end );
00227 QModelIndex idx = scene.model()->index( 0, 0, scene.summaryHandlingModel()->mapToSource( parent ) );
00228 do {
00229 scene.updateRow( scene.summaryHandlingModel()->mapFromSource( idx ) );
00230 } while ( ( idx = rowcontroller->indexBelow( idx ) ) != QModelIndex() && rowcontroller->isRowVisible( idx ) );
00231
00232 q->updateSceneRect();
00233 }
00234
00235 void GraphicsView::Private::slotColumnsRemoved( const QModelIndex& parent, int start, int end )
00236 {
00237
00238 Q_UNUSED( start );
00239 Q_UNUSED( end );
00240 Q_UNUSED( parent );
00241 q->updateScene();
00242 }
00243
00244 void GraphicsView::Private::slotDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight )
00245 {
00246
00247 const QModelIndex parent = topLeft.parent();
00248 for ( int row = topLeft.row(); row <= bottomRight.row(); ++row ) {
00249 scene.updateRow( scene.summaryHandlingModel()->index( row, 0, parent ) );
00250 }
00251 }
00252
00253 void GraphicsView::Private::slotLayoutChanged()
00254 {
00255
00256 q->updateScene();
00257 }
00258
00259 void GraphicsView::Private::slotModelReset()
00260 {
00261
00262 q->updateScene();
00263 }
00264
00265 void GraphicsView::Private::slotRowsInserted( const QModelIndex& parent, int start, int end )
00266 {
00267 Q_UNUSED( parent );
00268 Q_UNUSED( start );
00269 Q_UNUSED( end );
00270 q->updateScene();
00271 }
00272
00273 void GraphicsView::Private::slotRowsAboutToBeRemoved( const QModelIndex& parent, int start, int end )
00274 {
00275
00276 for ( int row = start; row <= end; ++row ) {
00277 for ( int col = 0; col < scene.summaryHandlingModel()->columnCount( parent ); ++col ) {
00278
00279 scene.removeItem( scene.summaryHandlingModel()->index( row, col, parent ) );
00280 }
00281 }
00282 }
00283
00284 void GraphicsView::Private::slotRowsRemoved( const QModelIndex& parent, int start, int end )
00285 {
00286
00287
00288 Q_UNUSED( parent );
00289 Q_UNUSED( start );
00290 Q_UNUSED( end );
00291
00292 q->updateScene();
00293 }
00294
00295 void GraphicsView::Private::slotItemClicked( const QModelIndex& idx )
00296 {
00297 QModelIndex sidx = idx;
00298 emit q->clicked( sidx );
00299 if (q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, q))
00300 emit q->activated( sidx );
00301 }
00302
00303 void GraphicsView::Private::slotItemDoubleClicked( const QModelIndex& idx )
00304 {
00305 QModelIndex sidx = idx;
00306 emit q->doubleClicked( sidx );
00307 if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, q))
00308 emit q->activated( sidx );
00309 }
00310
00311 void GraphicsView::Private::slotHeaderContextMenuRequested( const QPoint& pt )
00312 {
00313 emit q->headerContextMenuRequested( headerwidget.mapToGlobal( pt ) );
00314 }
00315
00337 GraphicsView::GraphicsView( QWidget* parent )
00338 : QGraphicsView( parent ), _d( new Private( this ) )
00339 {
00340
00341 #if defined KDAB_EVAL
00342 EvalDialog::checkEvalLicense( "KD Gantt" );
00343 #endif
00344 connect( horizontalScrollBar(), SIGNAL( valueChanged( int ) ),
00345 this, SLOT( slotHorizontalScrollValueChanged( int ) ) );
00346 connect( &_d->scene, SIGNAL( gridChanged() ),
00347 this, SLOT( slotGridChanged() ) );
00348 connect( &_d->scene, SIGNAL( entered( const QModelIndex& ) ),
00349 this, SIGNAL( entered( const QModelIndex& ) ) );
00350 connect( &_d->scene, SIGNAL( pressed( const QModelIndex& ) ),
00351 this, SIGNAL( pressed( const QModelIndex& ) ) );
00352 connect( &_d->scene, SIGNAL( clicked( const QModelIndex& ) ),
00353 this, SLOT( slotItemClicked( const QModelIndex& ) ) );
00354 connect( &_d->scene, SIGNAL( doubleClicked( const QModelIndex& ) ),
00355 this, SLOT( slotItemDoubleClicked( const QModelIndex& ) ) );
00356 connect( &_d->scene, SIGNAL( sceneRectChanged( const QRectF& ) ),
00357 this, SLOT( updateSceneRect() ) );
00358 connect( &_d->headerwidget, SIGNAL( customContextMenuRequested( const QPoint& ) ),
00359 this, SLOT( slotHeaderContextMenuRequested( const QPoint& ) ) );
00360 setScene( &_d->scene );
00361
00362
00363 setSummaryHandlingModel( _d->scene.summaryHandlingModel() );
00364
00365
00366
00367 setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
00368
00369
00370 }
00371
00373 GraphicsView::~GraphicsView()
00374 {
00375 delete _d;
00376 }
00377
00378 #define d d_func()
00379
00393 void GraphicsView::setModel( QAbstractItemModel* model )
00394 {
00395 if ( d->scene.model() ) {
00396 disconnect( d->scene.model() );
00397 }
00398
00399 d->scene.setModel( model );
00400 connect( model, SIGNAL( dataChanged( const QModelIndex&, const QModelIndex& ) ),
00401 this, SLOT( updateSceneRect() ) );
00402 updateScene();
00403 }
00404
00407 QAbstractItemModel* GraphicsView::model() const
00408 {
00409 return d->scene.model();
00410 }
00411
00412 void GraphicsView::setSummaryHandlingModel( QAbstractProxyModel* proxyModel )
00413 {
00414 disconnect( d->scene.summaryHandlingModel() );
00415 d->scene.setSummaryHandlingModel( proxyModel );
00416
00417
00418
00419
00420 connect( proxyModel, SIGNAL( columnsInserted( const QModelIndex&, int, int ) ),
00421 this, SLOT( slotColumnsInserted( const QModelIndex&, int, int ) ) );
00422 connect( proxyModel, SIGNAL( columnsRemoved( const QModelIndex&, int, int ) ),
00423 this, SLOT( slotColumnsRemoved( const QModelIndex&, int, int ) ) );
00424 connect( proxyModel, SIGNAL( dataChanged( const QModelIndex&, const QModelIndex& ) ),
00425 this, SLOT( slotDataChanged( const QModelIndex&, const QModelIndex& ) ) );
00426 connect( proxyModel, SIGNAL( layoutChanged() ),
00427 this, SLOT( slotLayoutChanged() ) );
00428 connect( proxyModel, SIGNAL( modelReset() ),
00429 this, SLOT( slotModelReset() ) );
00430 connect( proxyModel, SIGNAL( rowsInserted( const QModelIndex&, int, int ) ),
00431 this, SLOT( slotRowsInserted( const QModelIndex&, int, int ) ) );
00432 connect( proxyModel, SIGNAL( rowsAboutToBeRemoved( const QModelIndex&, int, int ) ),
00433 this, SLOT( slotRowsAboutToBeRemoved( const QModelIndex&, int, int ) ) );
00434 connect( proxyModel, SIGNAL( rowsRemoved( const QModelIndex&, int, int ) ),
00435 this, SLOT( slotRowsRemoved( const QModelIndex&, int, int ) ) );
00436
00437 updateScene();
00438 }
00439
00443 void GraphicsView::setConstraintModel( ConstraintModel* cmodel )
00444 {
00445 d->scene.setConstraintModel( cmodel );
00446 }
00447
00450 ConstraintModel* GraphicsView::constraintModel() const
00451 {
00452 return d->scene.constraintModel();
00453 }
00454
00457 QAbstractProxyModel* GraphicsView::summaryHandlingModel() const
00458 {
00459 return d->scene.summaryHandlingModel();
00460 }
00461
00465 void GraphicsView::setRootIndex( const QModelIndex& idx )
00466 {
00467 d->scene.setRootIndex( idx );
00468 }
00469
00472 QModelIndex GraphicsView::rootIndex() const
00473 {
00474 return d->scene.rootIndex();
00475 }
00476
00480 void GraphicsView::setSelectionModel( QItemSelectionModel* model )
00481 {
00482 d->scene.setSelectionModel( model );
00483 }
00484
00487 QItemSelectionModel* GraphicsView::selectionModel() const
00488 {
00489 return d->scene.selectionModel();
00490 }
00491
00495 void GraphicsView::setItemDelegate( ItemDelegate* delegate )
00496 {
00497 d->scene.setItemDelegate( delegate );
00498 }
00499
00502 ItemDelegate* GraphicsView::itemDelegate() const
00503 {
00504 return d->scene.itemDelegate();
00505 }
00506
00512 void GraphicsView::setRowController( AbstractRowController* rowcontroller )
00513 {
00514 d->rowcontroller = rowcontroller;
00515 d->scene.setRowController( rowcontroller );
00516 updateScene();
00517 }
00518
00522 AbstractRowController* GraphicsView::rowController() const
00523 {
00524 return d->rowcontroller;
00525 }
00526
00532 void GraphicsView::setGrid( AbstractGrid* grid )
00533 {
00534 d->scene.setGrid( grid );
00535 d->slotGridChanged();
00536 }
00537
00540 AbstractGrid* GraphicsView::grid() const
00541 {
00542 return d->scene.grid();
00543 }
00544
00548 void GraphicsView::setReadOnly( bool ro )
00549 {
00550 d->scene.setReadOnly( ro );
00551 }
00552
00555 bool GraphicsView::isReadOnly() const
00556 {
00557 return d->scene.isReadOnly();
00558 }
00559
00569 void GraphicsView::setHeaderContextMenuPolicy( Qt::ContextMenuPolicy p )
00570 {
00571 d->headerwidget.setContextMenuPolicy( p );
00572 }
00573
00576 Qt::ContextMenuPolicy GraphicsView::headerContextMenuPolicy() const
00577 {
00578 return d->headerwidget.contextMenuPolicy();
00579 }
00580
00589 void GraphicsView::addConstraint( const QModelIndex& from,
00590 const QModelIndex& to,
00591 Qt::KeyboardModifiers modifiers )
00592 {
00593 if ( isReadOnly() ) return;
00594 ConstraintModel* cmodel = constraintModel();
00595 assert( cmodel );
00596 Constraint c( from, to, ( modifiers&Qt::ShiftModifier )?Constraint::TypeHard:Constraint::TypeSoft );
00597 if ( cmodel->hasConstraint( c ) ) cmodel->removeConstraint( c );
00598 else cmodel->addConstraint( c );
00599 }
00600
00601 void GraphicsView::resizeEvent( QResizeEvent* ev )
00602 {
00603 d->updateHeaderGeometry();
00604 QRectF r = scene()->itemsBoundingRect();
00605
00606 r.setLeft( qMin( qreal(0.0), r.left() ) );
00607
00608
00609 QSizeF size = viewport()->size();
00610
00611 if ( size.width() > r.width() ) {
00612 r.setWidth( size.width() - 2 );
00613 }
00614 if ( size.height() > r.height() ) {
00615 r.setHeight( size.height() - 2 );
00616 }
00617 const int totalh = rowController()->totalHeight();
00618 if ( r.height() < totalh ) {
00619 r.setHeight( totalh );
00620 }
00621
00622 scene()->setSceneRect( r );
00623
00624 QGraphicsView::resizeEvent( ev );
00625 }
00626
00633 QModelIndex GraphicsView::indexAt( const QPoint& pos ) const
00634 {
00635 QGraphicsItem* item = itemAt( pos );
00636 if ( GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
00637 return d->scene.summaryHandlingModel()->mapToSource( gitem->index() );
00638 } else {
00639 return QModelIndex();
00640 }
00641 }
00642
00644 void GraphicsView::clearItems()
00645 {
00646 d->scene.clearItems();
00647 }
00648
00650 void GraphicsView::updateRow( const QModelIndex& idx )
00651 {
00652 d->scene.updateRow( d->scene.summaryHandlingModel()->mapFromSource( idx ) );
00653 }
00654
00658 void GraphicsView::updateSceneRect()
00659 {
00660
00661
00662
00663 qreal range = horizontalScrollBar()->maximum()-horizontalScrollBar()->minimum();
00664 const qreal hscroll = horizontalScrollBar()->value()/( range>0?range:1 );
00665 QRectF r = d->scene.itemsBoundingRect();
00666
00667 r.setTop( 0. );
00668 r.setLeft( qMin( qreal(0.0), r.left() ) );
00669 r.setSize( r.size().expandedTo( viewport()->size() ) );
00670 const int totalh = rowController()->totalHeight();
00671 if ( r.height() < totalh ) r.setHeight( totalh );
00672 d->scene.setSceneRect( r );
00673
00674
00675 range = horizontalScrollBar()->maximum()-horizontalScrollBar()->minimum();
00676 if ( range>0 ) horizontalScrollBar()->setValue( qRound( hscroll*range ) );
00677
00678
00679
00680
00681
00682 d->scene.invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
00683 }
00684
00688 void GraphicsView::updateScene()
00689 {
00690 clearItems();
00691 if( !model()) return;
00692 if( !rowController()) return;
00693 QModelIndex idx = model()->index( 0, 0, rootIndex() );
00694 do {
00695 updateRow( idx );
00696 } while ( ( idx = rowController()->indexBelow( idx ) ) != QModelIndex() && rowController()->isRowVisible(idx) );
00697
00698
00699 updateSceneRect();
00700 if ( scene() ) scene()->invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
00701 }
00702
00704 GraphicsItem* GraphicsView::createItem( ItemType type ) const
00705 {
00706 return d->scene.createItem( type );
00707 }
00708
00710 void GraphicsView::deleteSubtree( const QModelIndex& idx )
00711 {
00712 d->scene.deleteSubtree( d->scene.summaryHandlingModel()->mapFromSource( idx ) );
00713 }
00714
00721 void GraphicsView::print( QPrinter* printer, bool drawRowLabels )
00722 {
00723 d->scene.print( printer, drawRowLabels );
00724 }
00725
00736 void GraphicsView::print( QPrinter* printer, qreal start, qreal end, bool drawRowLabels )
00737 {
00738 d->scene.print( printer, start, end, drawRowLabels );
00739 }
00740
00745 void GraphicsView::print( QPainter* painter, const QRectF& targetRect, bool drawRowLabels )
00746 {
00747 d->scene.print(painter,targetRect,drawRowLabels);
00748 }
00749
00758 void GraphicsView::print( QPainter* painter, qreal start, qreal end,
00759 const QRectF& targetRect, bool drawRowLabels )
00760 {
00761 d->scene.print(painter, start, end, targetRect, drawRowLabels);
00762 }
00763
00764
00765 #include "moc_kdganttgraphicsview.cpp"