00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kdganttview.h"
00024 #include "kdganttview_p.h"
00025
00026 #include "kdganttitemdelegate.h"
00027 #include "kdganttgraphicsitem.h"
00028 #include "kdganttsummaryhandlingproxymodel.h"
00029
00030 #include <QAbstractItemModel>
00031 #include <QHeaderView>
00032 #include <QVBoxLayout>
00033 #include <QGraphicsItem>
00034 #include <QGraphicsRectItem>
00035 #include <QScrollBar>
00036 #include <QPaintEvent>
00037
00038 #include <QDebug>
00039
00040 #include <cassert>
00041
00042 #if defined KDAB_EVAL
00043 #include "../evaldialog/evaldialog.h"
00044 #endif
00045
00046 using namespace KDGantt;
00047
00048 namespace {
00049 class HeaderView : public QHeaderView {
00050 public:
00051 explicit HeaderView( QWidget* parent=0 ) : QHeaderView( Qt::Horizontal, parent ) {
00052 }
00053
00054 QSize sizeHint() const { QSize s = QHeaderView::sizeHint(); s.rheight() *= 2; return s; }
00055 };
00056 }
00057
00058 KDGanttTreeView::KDGanttTreeView( QAbstractProxyModel* proxy, QWidget* parent )
00059 : QTreeView( parent ),
00060 m_controller( this, proxy )
00061 {
00062 setHeader( new HeaderView );
00063 }
00064
00065 KDGanttTreeView::~KDGanttTreeView()
00066 {
00067 }
00068
00069 void KDGanttTreeView::expandAll(QModelIndex index)
00070 {
00071 for(int i = 0; i < model()->rowCount(index); i++) {
00072 QModelIndex indexAt = model()->index(i, 0, index);
00073 if(model()->hasChildren(indexAt))
00074 expandAll(indexAt);
00075 if(isExpanded(indexAt))
00076 continue;
00077 expand(indexAt);
00078 }
00079 }
00080
00081 void KDGanttTreeView::collapseAll(QModelIndex index)
00082 {
00083 for(int i = 0; i < model()->rowCount(index); i++) {
00084 QModelIndex indexAt = model()->index(i, 0, index);
00085 if(model()->hasChildren(indexAt))
00086 collapseAll(indexAt);
00087 if(!isExpanded(indexAt))
00088 continue;
00089 collapse(indexAt);
00090 }
00091 }
00092
00093 View::Private::Private(View* v)
00094 : q(v),
00095 splitter(v),
00096 rowController(0),
00097 gfxview( new GraphicsView( &splitter ) ),
00098 model(0)
00099 {
00100
00101 }
00102
00103 View::Private::~Private()
00104 {
00105 delete gfxview;
00106 }
00107
00108 void View::Private::init()
00109 {
00110 KDGanttTreeView* tw = new KDGanttTreeView( &ganttProxyModel, &splitter );
00111 tw->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00112 tw->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
00113
00114 q->setLeftView( tw );
00115 q->setRowController( tw->rowController() );
00116
00117
00118
00119 tw->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
00120
00121 QVBoxLayout* layout = new QVBoxLayout(q);
00122 layout->setMargin(0);
00123 layout->addWidget(&splitter);
00124 q->setLayout(layout);
00125
00126 constraintProxy.setProxyModel( &ganttProxyModel );
00127 constraintProxy.setDestinationModel( &mappedConstraintModel );
00128 setupGraphicsView();
00129 }
00130
00131 void View::Private::setupGraphicsView()
00132 {
00133 gfxview->setParent( &splitter );
00134 gfxview->setAlignment(Qt::AlignTop|Qt::AlignLeft);
00135 gfxview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
00136 gfxview->setSelectionModel( leftWidget->selectionModel() );
00137 gfxview->setConstraintModel( &mappedConstraintModel );
00138 q->setLeftView( leftWidget );
00139 q->setRowController( rowController );
00140 updateScene();
00141 }
00142
00143 void View::Private::updateScene()
00144 {
00145 gfxview->clearItems();
00146 if( !model) return;
00147
00148 if( QTreeView* tw = qobject_cast<QTreeView*>(leftWidget)) {
00149 QModelIndex idx = ganttProxyModel.mapFromSource( model->index( 0, 0, leftWidget->rootIndex() ) );
00150 do {
00151 gfxview->updateRow( idx );
00152 } while ( ( idx = tw->indexBelow( idx ) ) != QModelIndex() &&
00153 gfxview->rowController()->isRowVisible(idx) );
00154 gfxview->updateSceneRect();
00155 } else {
00156 const QModelIndex rootidx = ganttProxyModel.mapFromSource( leftWidget->rootIndex() );
00157 for( int r = 0; r < ganttProxyModel.rowCount(rootidx); ++r ) {
00158 gfxview->updateRow( ganttProxyModel.index( r, 0, rootidx ) );
00159 }
00160 }
00161 }
00162
00163 void View::Private::slotCollapsed(const QModelIndex& _idx)
00164 {
00165 QTreeView* tw = qobject_cast<QTreeView*>(leftWidget);
00166 if(!tw) return;
00167
00168 bool blocked = gfxview->blockSignals( true );
00169
00170 QModelIndex idx( _idx );
00171 const QAbstractItemModel* model = leftWidget->model();
00172 const QModelIndex pidx = ganttProxyModel.mapFromSource(idx);
00173 bool isMulti = false;
00174 for( QModelIndex treewalkidx = pidx; treewalkidx.isValid(); treewalkidx = treewalkidx.parent() ) {
00175 if ( treewalkidx.data( ItemTypeRole ).toInt() == TypeMulti
00176 && !gfxview->rowController()->isRowExpanded( treewalkidx ) ) {
00177 isMulti = true;
00178 break;
00179 }
00180 }
00181
00182 if ( !isMulti ) {
00183 for ( int i = 0; i < model->rowCount( idx ); ++i ) {
00184 gfxview->deleteSubtree( ganttProxyModel.index( i, 0, pidx ) );
00185 }
00186 } else {
00187 gfxview->updateRow(pidx);
00188 }
00189
00190 while ( ( idx=tw->indexBelow( idx ) ) != QModelIndex() &&
00191 gfxview->rowController()->isRowVisible( ganttProxyModel.mapFromSource(idx) ) ) {
00192 const QModelIndex proxyidx( ganttProxyModel.mapFromSource( idx ) );
00193 gfxview->updateRow(proxyidx);
00194 }
00195 gfxview->blockSignals( blocked );
00196 gfxview->updateSceneRect();
00197 }
00198
00199 void View::Private::slotExpanded(const QModelIndex& _idx)
00200 {
00201 QModelIndex idx( ganttProxyModel.mapFromSource( _idx ) );
00202 do {
00203
00204 gfxview->updateRow(idx);
00205 } while( ( idx=gfxview->rowController()->indexBelow( idx ) ) != QModelIndex()
00206 && gfxview->rowController()->isRowVisible( idx ) );
00207 gfxview->updateSceneRect();
00208 }
00209
00210 void View::Private::slotVerticalScrollValueChanged( int val )
00211 {
00212 #if 0
00213 qDebug() << "View::Private::slotVerticalScrollValueChanged("<<val<<")="
00214 << val/gfxview->verticalScrollBar()->singleStep();
00215 #endif
00216 leftWidget->verticalScrollBar()->setValue( val/gfxview->verticalScrollBar()->singleStep() );
00217 }
00218
00219 void View::Private::slotLeftWidgetVerticalRangeChanged(int min, int max )
00220 {
00221
00222 gfxview->verticalScrollBar()->setRange( min, max );
00223 gfxview->updateSceneRect();
00224 }
00225
00226 void View::Private::slotGfxViewVerticalRangeChanged( int min, int max )
00227 {
00228
00229 if ( !leftWidget.isNull() && !gfxview.isNull() ) {
00230 int leftMin = leftWidget->verticalScrollBar()->minimum();
00231 int leftMax = leftWidget->verticalScrollBar()->maximum();
00232 bool blocked = gfxview->verticalScrollBar()->blockSignals( true );
00233 gfxview->verticalScrollBar()->setRange( qMax( min, leftMin ), qMax( max, leftMax ) );
00234 gfxview->verticalScrollBar()->blockSignals( blocked );
00235 }
00236 }
00237
00251 View::View(QWidget* parent)
00252 : QWidget(parent),
00253 _d(new Private(this))
00254 {
00255 #if defined KDAB_EVAL
00256 EvalDialog::checkEvalLicense( "KD Gantt" );
00257 #endif
00258 _d->init();
00259 }
00260
00261 View::~View()
00262 {
00263 delete _d;
00264 }
00265
00266 #define d d_func()
00267
00273 void View::setLeftView( QAbstractItemView* aiv )
00274 {
00275 assert( aiv );
00276 if ( aiv==d->leftWidget ) return;
00277 if ( !d->leftWidget.isNull() ) {
00278 d->leftWidget->disconnect( this );
00279 d->leftWidget->hide();
00280 d->leftWidget->verticalScrollBar()->disconnect( d->gfxview->verticalScrollBar() );
00281 d->gfxview->verticalScrollBar()->disconnect( d->leftWidget->verticalScrollBar() );
00282 }
00283
00284 d->leftWidget = aiv;
00285 d->splitter.insertWidget( 0, d->leftWidget );
00286
00287 if( qobject_cast<QTreeView*>(d->leftWidget) ) {
00288 connect( d->leftWidget, SIGNAL( collapsed( const QModelIndex& ) ),
00289 this, SLOT( slotCollapsed( const QModelIndex& ) ) );
00290 connect( d->leftWidget, SIGNAL( expanded( const QModelIndex& ) ),
00291 this, SLOT( slotExpanded( const QModelIndex& ) ) );
00292 }
00293
00294 connect( d->gfxview->verticalScrollBar(), SIGNAL( valueChanged( int ) ),
00295 d->leftWidget->verticalScrollBar(), SLOT( setValue( int ) ) );
00296 connect( d->leftWidget->verticalScrollBar(), SIGNAL( valueChanged( int ) ),
00297 d->gfxview->verticalScrollBar(), SLOT( setValue( int ) ) );
00298 connect( d->leftWidget->verticalScrollBar(), SIGNAL( rangeChanged( int, int ) ),
00299 this, SLOT( slotLeftWidgetVerticalRangeChanged( int, int ) ) );
00300 connect( d->gfxview->verticalScrollBar(), SIGNAL( rangeChanged( int, int ) ),
00301 this, SLOT( slotGfxViewVerticalRangeChanged( int, int ) ) );
00302 }
00303
00309 void View::setRowController( AbstractRowController* ctrl )
00310 {
00311 if ( ctrl == d->rowController && d->gfxview->rowController() == ctrl ) return;
00312 d->rowController = ctrl;
00313 d->gfxview->setRowController( d->rowController );
00314 }
00315
00319 AbstractRowController* View::rowController()
00320 {
00321 return d->rowController;
00322 }
00323
00326 const AbstractRowController* View::rowController() const
00327 {
00328 return d->rowController;
00329 }
00330
00335 const QAbstractItemView* View::leftView() const
00336 {
00337 return d->leftWidget;
00338 }
00339
00343 QAbstractItemView* View::leftView()
00344 {
00345 return d->leftWidget;
00346 }
00347
00354 void View::setGraphicsView( GraphicsView* gv )
00355 {
00356 if ( gv != d->gfxview ) {
00357 GraphicsView* old = d->gfxview;
00358 d->gfxview = gv;
00359 d->setupGraphicsView();
00360 d->gfxview->setGrid( old->grid() );
00361 delete old;
00362 }
00363 }
00364
00368 const GraphicsView* View::graphicsView() const
00369 {
00370 return d->gfxview;
00371 }
00372
00376 GraphicsView* View::graphicsView()
00377 {
00378 return d->gfxview;
00379 }
00380
00384 const QSplitter* View::splitter() const
00385 {
00386 return &d->splitter;
00387 }
00388
00392 QSplitter* View::splitter()
00393 {
00394 return &d->splitter;
00395 }
00396
00397
00400 QAbstractItemModel* View::model() const
00401 {
00402 return leftView()->model();
00403 }
00404
00410 void View::setModel( QAbstractItemModel* model )
00411 {
00412 leftView()->setModel( model );
00413 d->ganttProxyModel.setSourceModel( model );
00414 d->gfxview->setModel( &d->ganttProxyModel );
00415 }
00416
00419 QItemSelectionModel* View::selectionModel() const
00420 {
00421 return leftView()->selectionModel();
00422 }
00423
00427 void View::setSelectionModel( QItemSelectionModel* smodel )
00428 {
00429 leftView()->setSelectionModel( smodel );
00430 d->gfxview->setSelectionModel( new QItemSelectionModel( &( d->ganttProxyModel ),this ) );
00431 }
00432
00438 void View::setGrid( AbstractGrid* grid )
00439 {
00440 d->gfxview->setGrid( grid );
00441 }
00442
00443 void View::expandAll( QModelIndex index )
00444 {
00445 KDGanttTreeView* tw = qobject_cast<KDGanttTreeView*>(leftView());
00446 tw->expandAll(index);
00447 }
00448
00449 void View::collapseAll( QModelIndex index )
00450 {
00451 KDGanttTreeView* tw = qobject_cast<KDGanttTreeView*>(leftView());
00452 tw->collapseAll(index);
00453 }
00454
00457 AbstractGrid* View::grid() const
00458 {
00459 return d->gfxview->grid();
00460 }
00461
00464 QModelIndex View::rootIndex() const
00465 {
00466 return leftView()->rootIndex();
00467 }
00468
00472 void View::setRootIndex( const QModelIndex& idx )
00473 {
00474 leftView()->setRootIndex( idx );
00475 d->gfxview->setRootIndex( idx );
00476 }
00477
00480 ItemDelegate* View::itemDelegate() const
00481 {
00482 return d->gfxview->itemDelegate();
00483 }
00484
00488 void View::setItemDelegate( ItemDelegate* delegate )
00489 {
00490 leftView()->setItemDelegate( delegate );
00491 d->gfxview->setItemDelegate( delegate );
00492 }
00493
00497 void View::setConstraintModel( ConstraintModel* cm )
00498 {
00499 d->constraintProxy.setSourceModel( cm );
00500 d->gfxview->setConstraintModel( &d->mappedConstraintModel );
00501 }
00502
00505 ConstraintModel* View::constraintModel() const
00506 {
00507 return d->constraintProxy.sourceModel();
00508 }
00509
00510 const QAbstractProxyModel* View::ganttProxyModel() const
00511 {
00512 return &( d->ganttProxyModel );
00513 }
00514
00515 QAbstractProxyModel* View::ganttProxyModel()
00516 {
00517 return &( d->ganttProxyModel );
00518 }
00519
00520 void View::ensureVisible(const QModelIndex& index)
00521 {
00522 QGraphicsView* view = graphicsView();
00523 KDGantt::GraphicsScene* scene = static_cast<KDGantt::GraphicsScene*>(view->scene());
00524 if(!scene)
00525 return;
00526
00527 KDGantt::SummaryHandlingProxyModel* model = static_cast<KDGantt::SummaryHandlingProxyModel*>(scene->summaryHandlingModel());
00528
00529 const QModelIndex pidx = d->ganttProxyModel.mapFromSource(index);
00530 const QModelIndex idx = model->mapFromSource( pidx );
00531 QGraphicsItem* item = scene->findItem(idx);
00532 view->ensureVisible(item);
00533 }
00534
00535 void View::resizeEvent(QResizeEvent*ev)
00536 {
00537 QWidget::resizeEvent(ev);
00538 }
00539
00546 QModelIndex View::indexAt( const QPoint& pos ) const
00547 {
00548 return d->gfxview->indexAt( pos );
00549 }
00550
00557 void View::print( QPrinter* printer, bool drawRowLabels )
00558 {
00559 graphicsView()->print( printer, drawRowLabels );
00560 }
00561
00572 void View::print( QPrinter* printer, qreal start, qreal end, bool drawRowLabels )
00573 {
00574 graphicsView()->print( printer, start, end, drawRowLabels );
00575 }
00576
00581 void View::print( QPainter* painter, const QRectF& target, bool drawRowLabels)
00582 {
00583 d->gfxview->print( painter,
00584 target,
00585 drawRowLabels);
00586 }
00587
00596 void View::print( QPainter* painter, qreal start, qreal end, const QRectF& target, bool drawRowLabels)
00597 {
00598 d->gfxview->print( painter,
00599 start, end,
00600 target,
00601 drawRowLabels);
00602 }
00603
00604
00605 #include "moc_kdganttview.cpp"
00606
00607 #ifndef KDAB_NO_UNIT_TESTS
00608 #include "unittest/test.h"
00609
00610 #include "kdganttlistviewrowcontroller.h"
00611 #include <QApplication>
00612 #include <QTimer>
00613 #include <QPixmap>
00614 #include <QListView>
00615
00616 namespace {
00617 std::ostream& operator<<( std::ostream& os, const QImage& img )
00618 {
00619 os << "QImage[ size=("<<img.width()<<", "<<img.height()<<")]";
00620 return os;
00621 }
00622 }
00623
00624 KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, View, "test" ) {
00625 View view( 0 );
00626 #if 0 // GUI tests do not work well on the server
00627 QTimer::singleShot( 1000, qApp, SLOT( quit() ) );
00628 view.show();
00629
00630 qApp->exec();
00631 QPixmap screenshot1 = QPixmap::grabWidget( &view );
00632
00633 QTreeView* tv = new QTreeView;
00634 view.setLeftView( tv );
00635 view.setRowController( new TreeViewRowController(tv,view.ganttProxyModel()) );
00636
00637 QTimer::singleShot( 1000, qApp, SLOT( quit() ) );
00638
00639 qApp->exec();
00640 QPixmap screenshot2 = QPixmap::grabWidget( &view );
00641
00642 assertEqual( screenshot1.toImage(), screenshot2.toImage() );
00643
00644 QListView* lv = new QListView;
00645 view.setLeftView(lv);
00646 view.setRowController( new ListViewRowController(lv,view.ganttProxyModel()));
00647 view.show();
00648 QTimer::singleShot( 1000, qApp, SLOT( quit() ) );
00649 qApp->exec();
00650 #endif
00651 }
00652 #endif