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 void HeaderWidget::contextMenuEvent( QContextMenuEvent* event )
00073 {
00074 QMenu contextMenu;
00075
00076 DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
00077 QAction* actionScaleAuto = 0;
00078 QAction* actionScaleWeek = 0;
00079 QAction* actionScaleDay = 0;
00080 QAction* actionScaleHour = 0;
00081 QAction* actionZoomIn = 0;
00082 QAction* actionZoomOut = 0;
00083 if( grid != 0 )
00084 {
00085 QMenu* menuScale = new QMenu( tr( "Scale" ), &contextMenu );
00086 QActionGroup* scaleGroup = new QActionGroup( &contextMenu );
00087 scaleGroup->setExclusive( true );
00088
00089 actionScaleAuto = new QAction( tr( "Auto" ), menuScale );
00090 actionScaleAuto->setCheckable( true );
00091 actionScaleAuto->setChecked( grid->scale() == DateTimeGrid::ScaleAuto );
00092 actionScaleWeek = new QAction( tr( "Week" ), menuScale );
00093 actionScaleWeek->setCheckable( true );
00094 actionScaleWeek->setChecked( grid->scale() == DateTimeGrid::ScaleWeek );
00095 actionScaleDay = new QAction( tr( "Day" ), menuScale );
00096 actionScaleDay->setCheckable( true );
00097 actionScaleDay->setChecked( grid->scale() == DateTimeGrid::ScaleDay );
00098 actionScaleHour = new QAction( tr( "Hour" ), menuScale );
00099 actionScaleHour->setCheckable( true );
00100 actionScaleHour->setChecked( grid->scale() == DateTimeGrid::ScaleHour );
00101
00102 scaleGroup->addAction( actionScaleAuto );
00103 menuScale->addAction( actionScaleAuto );
00104
00105 scaleGroup->addAction( actionScaleWeek );
00106 menuScale->addAction( actionScaleWeek );
00107
00108 scaleGroup->addAction( actionScaleDay );
00109 menuScale->addAction( actionScaleDay );
00110
00111 scaleGroup->addAction( actionScaleHour );
00112 menuScale->addAction( actionScaleHour );
00113
00114 contextMenu.addMenu( menuScale );
00115
00116 contextMenu.addSeparator();
00117
00118 actionZoomIn = new QAction( tr( "Zoom In" ), &contextMenu );
00119 contextMenu.addAction( actionZoomIn );
00120 actionZoomOut = new QAction( tr( "Zoom Out" ), &contextMenu );
00121 contextMenu.addAction( actionZoomOut );
00122 }
00123
00124 if( contextMenu.isEmpty() )
00125 {
00126 event->ignore();
00127 return;
00128 }
00129
00130 const QAction* const action = contextMenu.exec( event->globalPos() );
00131 if( action == 0 ) {}
00132 else if( action == actionScaleAuto )
00133 {
00134 assert( grid != 0 );
00135 grid->setScale( DateTimeGrid::ScaleAuto );
00136 }
00137 else if( action == actionScaleWeek )
00138 {
00139 assert( grid != 0 );
00140 grid->setScale( DateTimeGrid::ScaleWeek );
00141 }
00142 else if( action == actionScaleDay )
00143 {
00144 assert( grid != 0 );
00145 grid->setScale( DateTimeGrid::ScaleDay );
00146 }
00147 else if( action == actionScaleHour )
00148 {
00149 assert( grid != 0 );
00150 grid->setScale( DateTimeGrid::ScaleHour );
00151 }
00152 else if( action == actionZoomIn )
00153 {
00154 assert( grid != 0 );
00155 grid->setDayWidth( grid->dayWidth() + 10.0 );
00156 }
00157 else if( action == actionZoomOut )
00158 {
00159 assert( grid != 0 );
00160 grid->setDayWidth( grid->dayWidth() - 10.0 );
00161 }
00162
00163 event->accept();
00164 }
00165
00166 GraphicsView::Private::Private( GraphicsView* _q )
00167 : q( _q ), rowcontroller(0), headerwidget( _q )
00168 {
00169 }
00170
00171 void GraphicsView::Private::updateHeaderGeometry()
00172 {
00173 q->setViewportMargins(0,rowcontroller->headerHeight(),0,0);
00174 headerwidget.setGeometry( q->frameWidth(),
00175 q->frameWidth(),
00176 q->width()-2*q->frameWidth(),
00177 rowcontroller->headerHeight() );
00178 }
00179
00180 void GraphicsView::Private::slotGridChanged()
00181 {
00182 updateHeaderGeometry();
00183 headerwidget.update();
00184 q->updateSceneRect();
00185 q->update();
00186 }
00187
00188 void GraphicsView::Private::slotHorizontalScrollValueChanged( int val )
00189 {
00190 #if QT_VERSION >= 0x040300
00191 const QRectF viewRect = q->transform().mapRect( q->sceneRect() );
00192 #else
00193 const QRectF viewRect = q->sceneRect();
00194 #endif
00195 headerwidget.scrollTo( val-q->horizontalScrollBar()->minimum()+static_cast<int>( viewRect.left() ) );
00196 }
00197
00198 void GraphicsView::Private::slotColumnsInserted( const QModelIndex& parent, int start, int end )
00199 {
00200 Q_UNUSED( start );
00201 Q_UNUSED( end );
00202 QModelIndex idx = scene.model()->index( 0, 0, scene.summaryHandlingModel()->mapToSource( parent ) );
00203 do {
00204 scene.updateRow( scene.summaryHandlingModel()->mapFromSource( idx ) );
00205 } while ( ( idx = rowcontroller->indexBelow( idx ) ) != QModelIndex() && rowcontroller->isRowVisible( idx ) );
00206
00207 q->updateSceneRect();
00208 }
00209
00210 void GraphicsView::Private::slotColumnsRemoved( const QModelIndex& parent, int start, int end )
00211 {
00212
00213 Q_UNUSED( start );
00214 Q_UNUSED( end );
00215 Q_UNUSED( parent );
00216 q->updateScene();
00217 }
00218
00219 void GraphicsView::Private::slotDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight )
00220 {
00221
00222 const QModelIndex parent = topLeft.parent();
00223 for ( int row = topLeft.row(); row <= bottomRight.row(); ++row ) {
00224 scene.updateRow( scene.summaryHandlingModel()->index( row, 0, parent ) );
00225 }
00226 }
00227
00228 void GraphicsView::Private::slotLayoutChanged()
00229 {
00230
00231 q->updateScene();
00232 }
00233
00234 void GraphicsView::Private::slotModelReset()
00235 {
00236
00237 q->updateScene();
00238 }
00239
00240 void GraphicsView::Private::slotRowsInserted( const QModelIndex& parent, int start, int end )
00241 {
00242 Q_UNUSED( parent );
00243 Q_UNUSED( start );
00244 Q_UNUSED( end );
00245 q->updateScene();
00246 }
00247
00248 void GraphicsView::Private::slotRowsAboutToBeRemoved( const QModelIndex& parent, int start, int end )
00249 {
00250
00251 for ( int row = start; row <= end; ++row ) {
00252 for ( int col = 0; col < scene.summaryHandlingModel()->columnCount( parent ); ++col ) {
00253
00254 const QModelIndex idx = scene.summaryHandlingModel()->index( row, col, parent );
00255 QList<Constraint> clst = scene.constraintModel()->constraintsForIndex( idx );
00256 Q_FOREACH( Constraint c, clst ) {
00257 scene.constraintModel()->removeConstraint( c );
00258 }
00259 scene.removeItem( idx );
00260 }
00261 }
00262 }
00263
00264 void GraphicsView::Private::slotRowsRemoved( const QModelIndex& parent, int start, int end )
00265 {
00266
00267
00268 Q_UNUSED( parent );
00269 Q_UNUSED( start );
00270 Q_UNUSED( end );
00271
00272 q->updateScene();
00273 }
00274
00275 void GraphicsView::Private::slotItemClicked( const QModelIndex& idx )
00276 {
00277 QModelIndex sidx = idx;
00278 emit q->clicked( sidx );
00279 if (q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, q))
00280 emit q->activated( sidx );
00281 }
00282
00283 void GraphicsView::Private::slotItemDoubleClicked( const QModelIndex& idx )
00284 {
00285 QModelIndex sidx = idx;
00286 emit q->doubleClicked( sidx );
00287 if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, q))
00288 emit q->activated( sidx );
00289 }
00290
00304 typedef QGraphicsView BASE;
00305
00309 GraphicsView::GraphicsView( QWidget* parent )
00310 : BASE( parent ), _d( new Private( this ) )
00311 {
00312
00313 #if defined KDAB_EVAL
00314 EvalDialog::checkEvalLicense( "KD Gantt" );
00315 #endif
00316 connect( horizontalScrollBar(), SIGNAL( valueChanged( int ) ),
00317 this, SLOT( slotHorizontalScrollValueChanged( int ) ) );
00318 connect( &_d->scene, SIGNAL( gridChanged() ),
00319 this, SLOT( slotGridChanged() ) );
00320 connect( &_d->scene, SIGNAL( entered( const QModelIndex& ) ),
00321 this, SIGNAL( entered( const QModelIndex& ) ) );
00322 connect( &_d->scene, SIGNAL( pressed( const QModelIndex& ) ),
00323 this, SIGNAL( pressed( const QModelIndex& ) ) );
00324 connect( &_d->scene, SIGNAL( clicked( const QModelIndex& ) ),
00325 this, SLOT( slotItemClicked( const QModelIndex& ) ) );
00326 connect( &_d->scene, SIGNAL( doubleClicked( const QModelIndex& ) ),
00327 this, SLOT( slotItemDoubleClicked( const QModelIndex& ) ) );
00328 setScene( &_d->scene );
00329
00330
00331 setSummaryHandlingModel( _d->scene.summaryHandlingModel() );
00332 }
00333
00335 GraphicsView::~GraphicsView()
00336 {
00337 delete _d;
00338 }
00339
00340 #define d d_func()
00341
00355 void GraphicsView::setModel( QAbstractItemModel* model )
00356 {
00357 d->scene.setModel( model );
00358 updateScene();
00359 }
00360
00363 QAbstractItemModel* GraphicsView::model() const
00364 {
00365 return d->scene.model();
00366 }
00367
00368 void GraphicsView::setSummaryHandlingModel( QAbstractProxyModel* proxyModel )
00369 {
00370 disconnect( d->scene.summaryHandlingModel() );
00371 d->scene.setSummaryHandlingModel( proxyModel );
00372
00373
00374
00375
00376 connect( proxyModel, SIGNAL( columnsInserted( const QModelIndex&, int, int ) ),
00377 this, SLOT( slotColumnsInserted( const QModelIndex&, int, int ) ) );
00378 connect( proxyModel, SIGNAL( columnsRemoved( const QModelIndex&, int, int ) ),
00379 this, SLOT( slotColumnsRemoved( const QModelIndex&, int, int ) ) );
00380 connect( proxyModel, SIGNAL( dataChanged( const QModelIndex&, const QModelIndex& ) ),
00381 this, SLOT( slotDataChanged( const QModelIndex&, const QModelIndex& ) ) );
00382 connect( proxyModel, SIGNAL( layoutChanged() ),
00383 this, SLOT( slotLayoutChanged() ) );
00384 connect( proxyModel, SIGNAL( modelReset() ),
00385 this, SLOT( slotModelReset() ) );
00386 connect( proxyModel, SIGNAL( rowsInserted( const QModelIndex&, int, int ) ),
00387 this, SLOT( slotRowsInserted( const QModelIndex&, int, int ) ) );
00388 connect( proxyModel, SIGNAL( rowsAboutToBeRemoved( const QModelIndex&, int, int ) ),
00389 this, SLOT( slotRowsAboutToBeRemoved( const QModelIndex&, int, int ) ) );
00390 connect( proxyModel, SIGNAL( rowsRemoved( const QModelIndex&, int, int ) ),
00391 this, SLOT( slotRowsRemoved( const QModelIndex&, int, int ) ) );
00392
00393 updateScene();
00394 }
00395
00399 void GraphicsView::setConstraintModel( ConstraintModel* cmodel )
00400 {
00401 d->scene.setConstraintModel( cmodel );
00402 }
00403
00406 ConstraintModel* GraphicsView::constraintModel() const
00407 {
00408 return d->scene.constraintModel();
00409 }
00410
00414 void GraphicsView::setRootIndex( const QModelIndex& idx )
00415 {
00416 d->scene.setRootIndex( idx );
00417 }
00418
00421 QModelIndex GraphicsView::rootIndex() const
00422 {
00423 return d->scene.rootIndex();
00424 }
00425
00429 void GraphicsView::setSelectionModel( QItemSelectionModel* model )
00430 {
00431 d->scene.setSelectionModel( model );
00432 }
00433
00436 QItemSelectionModel* GraphicsView::selectionModel() const
00437 {
00438 return d->scene.selectionModel();
00439 }
00440
00444 void GraphicsView::setItemDelegate( ItemDelegate* delegate )
00445 {
00446 d->scene.setItemDelegate( delegate );
00447 }
00448
00451 ItemDelegate* GraphicsView::itemDelegate() const
00452 {
00453 return d->scene.itemDelegate();
00454 }
00455
00461 void GraphicsView::setRowController( AbstractRowController* rowcontroller )
00462 {
00463 d->rowcontroller = rowcontroller;
00464 d->scene.setRowController( rowcontroller );
00465 updateScene();
00466 }
00467
00471 AbstractRowController* GraphicsView::rowController() const
00472 {
00473 return d->rowcontroller;
00474 }
00475
00481 void GraphicsView::setGrid( AbstractGrid* grid )
00482 {
00483 d->scene.setGrid( grid );
00484 d->slotGridChanged();
00485 }
00486
00489 AbstractGrid* GraphicsView::grid() const
00490 {
00491 return d->scene.grid();
00492 }
00493
00497 void GraphicsView::setReadOnly( bool ro )
00498 {
00499 d->scene.setReadOnly( ro );
00500 }
00501
00504 bool GraphicsView::isReadOnly() const
00505 {
00506 return d->scene.isReadOnly();
00507 }
00508
00517 void GraphicsView::addConstraint( const QModelIndex& from,
00518 const QModelIndex& to,
00519 Qt::KeyboardModifiers modifiers )
00520 {
00521 if ( isReadOnly() ) return;
00522 ConstraintModel* cmodel = constraintModel();
00523 assert( cmodel );
00524 Constraint c( from, to, ( modifiers&Qt::ShiftModifier )?Constraint::TypeHard:Constraint::TypeSoft );
00525 if ( cmodel->hasConstraint( c ) ) cmodel->removeConstraint( c );
00526 else cmodel->addConstraint( c );
00527 }
00528
00529 void GraphicsView::resizeEvent( QResizeEvent* ev )
00530 {
00531 d->updateHeaderGeometry();
00532 QRectF r = scene()->itemsBoundingRect();
00533
00534 r.setLeft( qMin( qreal(0.0), r.left() ) );
00535
00536
00537
00538 QSizeF size = maximumViewportSize() - QSizeF( frameWidth()*2, frameWidth()*2 );
00539 if ( size.width() > r.width() ) {
00540 r.setWidth( size.width() );
00541 }
00542 if ( size.height() > r.height() ) {
00543 r.setHeight( size.height() );
00544 }
00545 scene()->setSceneRect( r );
00546 BASE::resizeEvent( ev );
00547 }
00548
00555 QModelIndex GraphicsView::indexAt( const QPoint& pos ) const
00556 {
00557 QGraphicsItem* item = itemAt( pos );
00558 if ( GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
00559 return d->scene.summaryHandlingModel()->mapToSource( gitem->index() );
00560 } else {
00561 return QModelIndex();
00562 }
00563 }
00564
00566 void GraphicsView::clearItems()
00567 {
00568 d->scene.clearItems();
00569 }
00570
00572 void GraphicsView::updateRow( const QModelIndex& idx )
00573 {
00574 d->scene.updateRow( d->scene.summaryHandlingModel()->mapFromSource( idx ) );
00575 }
00576
00580 void GraphicsView::updateSceneRect()
00581 {
00582
00583
00584
00585 QRectF r = d->scene.itemsBoundingRect();
00586
00587 r.setLeft( qMin( qreal(0.0), r.left() ) );
00588 r.setSize( r.size().expandedTo( maximumViewportSize() - QSizeF( frameWidth()*2, frameWidth()*2 ) ) );
00589
00590 d->scene.setSceneRect( r );
00591 }
00592
00596 void GraphicsView::updateScene()
00597 {
00598 clearItems();
00599 if( !model()) return;
00600 if( !rowController()) return;
00601 QModelIndex idx = model()->index( 0, 0, rootIndex() );
00602 do {
00603 updateRow( idx );
00604 } while ( ( idx = rowController()->indexBelow( idx ) ) != QModelIndex() && rowController()->isRowVisible(idx) );
00605
00606
00607 updateSceneRect();
00608 }
00609
00611 GraphicsItem* GraphicsView::createItem( ItemType type ) const
00612 {
00613 return d->scene.createItem( type );
00614 }
00615
00617 void GraphicsView::deleteSubtree( const QModelIndex& idx )
00618 {
00619 d->scene.deleteSubtree( d->scene.summaryHandlingModel()->mapFromSource( idx ) );
00620 }
00621
00628 void GraphicsView::print( QPainter* painter, const QRectF& target, bool drawRowLabels )
00629 {
00630 d->scene.print(painter,target,drawRowLabels);
00631 }
00632
00633
00634 #include "moc_kdganttgraphicsview.cpp"
00635 #include "moc_kdganttgraphicsview_p.cpp"