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(&splitter),
00098 model(0)
00099 {
00100
00101 }
00102
00103 View::Private::~Private()
00104 {
00105 }
00106
00107 void View::Private::init()
00108 {
00109 KDGanttTreeView* tw = new KDGanttTreeView( &ganttProxyModel, &splitter );
00110 tw->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00111 tw->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
00112
00113 q->setLeftView( tw );
00114 q->setRowController( tw->rowController() );
00115
00116 gfxview.setAlignment(Qt::AlignTop|Qt::AlignLeft);
00117
00118
00119 tw->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
00120 gfxview.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
00121
00122 QVBoxLayout* layout = new QVBoxLayout(q);
00123 layout->setMargin(0);
00124 layout->addWidget(&splitter);
00125 q->setLayout(layout);
00126
00127 constraintProxy.setProxyModel( &ganttProxyModel );
00128 constraintProxy.setDestinationModel( &mappedConstraintModel );
00129 gfxview.setSelectionModel( leftWidget->selectionModel() );
00130 gfxview.setConstraintModel( &mappedConstraintModel );
00131 }
00132
00133 void View::Private::updateScene()
00134 {
00135 gfxview.clearItems();
00136 if( !model) return;
00137
00138 if( QTreeView* tw = qobject_cast<QTreeView*>(leftWidget)) {
00139 QModelIndex idx = ganttProxyModel.mapFromSource( model->index( 0, 0, leftWidget->rootIndex() ) );
00140 do {
00141 gfxview.updateRow( idx );
00142 } while ( ( idx = tw->indexBelow( idx ) ) != QModelIndex() &&
00143 gfxview.rowController()->isRowVisible(idx) );
00144 gfxview.updateSceneRect();
00145 } else {
00146 const QModelIndex rootidx = ganttProxyModel.mapFromSource( leftWidget->rootIndex() );
00147 for( int r = 0; r < ganttProxyModel.rowCount(rootidx); ++r ) {
00148 gfxview.updateRow( ganttProxyModel.index( r, 0, rootidx ) );
00149 }
00150 }
00151 }
00152
00153 void View::Private::slotCollapsed(const QModelIndex& _idx)
00154 {
00155 QTreeView* tw = qobject_cast<QTreeView*>(leftWidget);
00156 if(!tw) return;
00157
00158 bool blocked = gfxview.blockSignals( true );
00159
00160 QModelIndex idx( _idx );
00161 const QAbstractItemModel* model = leftWidget->model();
00162 const QModelIndex pidx = ganttProxyModel.mapFromSource(idx);
00163 bool isMulti = false;
00164 for( QModelIndex treewalkidx = pidx; treewalkidx.isValid(); treewalkidx = treewalkidx.parent() ) {
00165 if ( treewalkidx.data( ItemTypeRole ).toInt() == TypeMulti
00166 && !gfxview.rowController()->isRowExpanded( treewalkidx ) ) {
00167 isMulti = true;
00168 break;
00169 }
00170 }
00171
00172 if ( !isMulti ) {
00173 for ( int i = 0; i < model->rowCount( idx ); ++i ) {
00174 gfxview.deleteSubtree( ganttProxyModel.index( i, 0, pidx ) );
00175 }
00176 } else {
00177 gfxview.updateRow(pidx);
00178 }
00179
00180 while ( ( idx=tw->indexBelow( idx ) ) != QModelIndex() &&
00181 gfxview.rowController()->isRowVisible( ganttProxyModel.mapFromSource(idx) ) ) {
00182 const QModelIndex proxyidx( ganttProxyModel.mapFromSource( idx ) );
00183 gfxview.updateRow(proxyidx);
00184 }
00185 gfxview.blockSignals( blocked );
00186 gfxview.updateSceneRect();
00187 }
00188
00189 void View::Private::slotExpanded(const QModelIndex& _idx)
00190 {
00191 QModelIndex idx( ganttProxyModel.mapFromSource( _idx ) );
00192 do {
00193
00194 gfxview.updateRow(idx);
00195 } while( ( idx=gfxview.rowController()->indexBelow( idx ) ) != QModelIndex()
00196 && gfxview.rowController()->isRowVisible( idx ) );
00197 gfxview.updateSceneRect();
00198 }
00199
00200 void View::Private::slotVerticalScrollValueChanged( int val )
00201 {
00202 #if 0
00203 qDebug() << "View::Private::slotVerticalScrollValueChanged("<<val<<")="
00204 << val/gfxview.verticalScrollBar()->singleStep();
00205 #endif
00206 leftWidget->verticalScrollBar()->setValue( val/gfxview.verticalScrollBar()->singleStep() );
00207 }
00208
00209 void View::Private::slotLeftWidgetVerticalRangeChanged(int min, int max )
00210 {
00211
00212 gfxview.verticalScrollBar()->setRange( min, max );
00213 gfxview.updateSceneRect();
00214 }
00215
00216 void View::Private::slotGfxViewVerticalRangeChanged( int min, int max )
00217 {
00218
00219 int leftMin = leftWidget->verticalScrollBar()->minimum();
00220 int leftMax = leftWidget->verticalScrollBar()->maximum();
00221 bool blocked = gfxview.verticalScrollBar()->blockSignals( true );
00222 gfxview.verticalScrollBar()->setRange( qMax( min, leftMin ), qMax( max, leftMax ) );
00223 gfxview.verticalScrollBar()->blockSignals( blocked );
00224 }
00225
00239 View::View(QWidget* parent)
00240 : QWidget(parent),
00241 _d(new Private(this))
00242 {
00243 #if defined KDAB_EVAL
00244 EvalDialog::checkEvalLicense( "KD Gantt" );
00245 #endif
00246 _d->init();
00247 }
00248
00249 View::~View()
00250 {
00251 delete _d;
00252 }
00253
00254 #define d d_func()
00255
00261 void View::setLeftView( QAbstractItemView* aiv )
00262 {
00263 assert( aiv );
00264 if ( aiv==d->leftWidget ) return;
00265 if ( !d->leftWidget.isNull() ) {
00266 d->leftWidget->disconnect( this );
00267 d->leftWidget->hide();
00268 d->leftWidget->verticalScrollBar()->disconnect( d->gfxview.verticalScrollBar() );
00269 d->gfxview.verticalScrollBar()->disconnect( d->leftWidget->verticalScrollBar() );
00270 }
00271
00272 d->leftWidget = aiv;
00273 d->splitter.insertWidget( 0, d->leftWidget );
00274
00275 if( qobject_cast<QTreeView*>(d->leftWidget) ) {
00276 connect( d->leftWidget, SIGNAL( collapsed( const QModelIndex& ) ),
00277 this, SLOT( slotCollapsed( const QModelIndex& ) ) );
00278 connect( d->leftWidget, SIGNAL( expanded( const QModelIndex& ) ),
00279 this, SLOT( slotExpanded( const QModelIndex& ) ) );
00280 }
00281
00282 connect( d->gfxview.verticalScrollBar(), SIGNAL( valueChanged( int ) ),
00283 d->leftWidget->verticalScrollBar(), SLOT( setValue( int ) ) );
00284 connect( d->leftWidget->verticalScrollBar(), SIGNAL( valueChanged( int ) ),
00285 d->gfxview.verticalScrollBar(), SLOT( setValue( int ) ) );
00286 connect( d->leftWidget->verticalScrollBar(), SIGNAL( rangeChanged( int, int ) ),
00287 this, SLOT( slotLeftWidgetVerticalRangeChanged( int, int ) ) );
00288 connect( d->gfxview.verticalScrollBar(), SIGNAL( rangeChanged( int, int ) ),
00289 this, SLOT( slotGfxViewVerticalRangeChanged( int, int ) ) );
00290 }
00291
00297 void View::setRowController( AbstractRowController* ctrl )
00298 {
00299 if ( ctrl == d->rowController ) return;
00300 d->rowController = ctrl;
00301 d->gfxview.setRowController( d->rowController );
00302 }
00303
00307 AbstractRowController* View::rowController()
00308 {
00309 return d->rowController;
00310 }
00311
00314 const AbstractRowController* View::rowController() const
00315 {
00316 return d->rowController;
00317 }
00318
00323 const QAbstractItemView* View::leftView() const
00324 {
00325 return d->leftWidget;
00326 }
00327
00331 QAbstractItemView* View::leftView()
00332 {
00333 return d->leftWidget;
00334 }
00335
00339 const GraphicsView* View::graphicsView() const
00340 {
00341 return &d->gfxview;
00342 }
00343
00347 GraphicsView* View::graphicsView()
00348 {
00349 return &d->gfxview;
00350 }
00351
00355 const QSplitter* View::splitter() const
00356 {
00357 return &d->splitter;
00358 }
00359
00363 QSplitter* View::splitter()
00364 {
00365 return &d->splitter;
00366 }
00367
00368
00371 QAbstractItemModel* View::model() const
00372 {
00373 return leftView()->model();
00374 }
00375
00381 void View::setModel( QAbstractItemModel* model )
00382 {
00383 leftView()->setModel( model );
00384 d->ganttProxyModel.setSourceModel( model );
00385 d->gfxview.setModel( &d->ganttProxyModel );
00386 }
00387
00390 QItemSelectionModel* View::selectionModel() const
00391 {
00392 return leftView()->selectionModel();
00393 }
00394
00398 void View::setSelectionModel( QItemSelectionModel* smodel )
00399 {
00400 leftView()->setSelectionModel( smodel );
00401 d->gfxview.setSelectionModel( new QItemSelectionModel( &( d->ganttProxyModel ),this ) );
00402 }
00403
00409 void View::setGrid( AbstractGrid* grid )
00410 {
00411 d->gfxview.setGrid( grid );
00412 }
00413
00414 void View::expandAll( QModelIndex index )
00415 {
00416 KDGanttTreeView* tw = qobject_cast<KDGanttTreeView*>(leftView());
00417 tw->expandAll(index);
00418 }
00419
00420 void View::collapseAll( QModelIndex index )
00421 {
00422 KDGanttTreeView* tw = qobject_cast<KDGanttTreeView*>(leftView());
00423 tw->collapseAll(index);
00424 }
00425
00428 AbstractGrid* View::grid() const
00429 {
00430 return d->gfxview.grid();
00431 }
00432
00435 QModelIndex View::rootIndex() const
00436 {
00437 return leftView()->rootIndex();
00438 }
00439
00443 void View::setRootIndex( const QModelIndex& idx )
00444 {
00445 leftView()->setRootIndex( idx );
00446 d->gfxview.setRootIndex( idx );
00447 }
00448
00451 ItemDelegate* View::itemDelegate() const
00452 {
00453 return d->gfxview.itemDelegate();
00454 }
00455
00459 void View::setItemDelegate( ItemDelegate* delegate )
00460 {
00461 leftView()->setItemDelegate( delegate );
00462 d->gfxview.setItemDelegate( delegate );
00463 }
00464
00468 void View::setConstraintModel( ConstraintModel* cm )
00469 {
00470 d->constraintProxy.setSourceModel( cm );
00471 d->gfxview.setConstraintModel( &d->mappedConstraintModel );
00472 }
00473
00476 ConstraintModel* View::constraintModel() const
00477 {
00478 return d->constraintProxy.sourceModel();
00479 }
00480
00481 const QAbstractProxyModel* View::ganttProxyModel() const
00482 {
00483 return &( d->ganttProxyModel );
00484 }
00485
00486 QAbstractProxyModel* View::ganttProxyModel()
00487 {
00488 return &( d->ganttProxyModel );
00489 }
00490
00491 void View::ensureVisible(const QModelIndex& index)
00492 {
00493 QGraphicsView* view = graphicsView();
00494 KDGantt::GraphicsScene* scene = static_cast<KDGantt::GraphicsScene*>(view->scene());
00495 if(!scene)
00496 return;
00497
00498 KDGantt::SummaryHandlingProxyModel* model = static_cast<KDGantt::SummaryHandlingProxyModel*>(scene->summaryHandlingModel());
00499
00500 const QModelIndex pidx = d->ganttProxyModel.mapFromSource(index);
00501 const QModelIndex idx = model->mapFromSource( pidx );
00502 QGraphicsItem* item = scene->findItem(idx);
00503 view->ensureVisible(item);
00504 }
00505
00506 void View::resizeEvent(QResizeEvent*ev)
00507 {
00508 QWidget::resizeEvent(ev);
00509 }
00510
00517 QModelIndex View::indexAt( const QPoint& pos ) const
00518 {
00519 return d->gfxview.indexAt( pos );
00520 }
00521
00528 void View::print( QPrinter* printer, bool drawRowLabels )
00529 {
00530 graphicsView()->print( printer, drawRowLabels );
00531 }
00532
00543 void View::print( QPrinter* printer, qreal start, qreal end, bool drawRowLabels )
00544 {
00545 graphicsView()->print( printer, start, end, drawRowLabels );
00546 }
00547
00552 void View::print( QPainter* painter, const QRectF& target, bool drawRowLabels)
00553 {
00554 d->gfxview.print( painter,
00555 target,
00556 drawRowLabels);
00557 }
00558
00567 void View::print( QPainter* painter, qreal start, qreal end, const QRectF& target, bool drawRowLabels)
00568 {
00569 d->gfxview.print( painter,
00570 start, end,
00571 target,
00572 drawRowLabels);
00573 }
00574
00575
00576 #include "moc_kdganttview.cpp"
00577
00578 #ifndef KDAB_NO_UNIT_TESTS
00579 #include "unittest/test.h"
00580
00581 #include "kdganttlistviewrowcontroller.h"
00582 #include <QApplication>
00583 #include <QTimer>
00584 #include <QPixmap>
00585 #include <QListView>
00586
00587 namespace {
00588 std::ostream& operator<<( std::ostream& os, const QImage& img )
00589 {
00590 os << "QImage[ size=("<<img.width()<<", "<<img.height()<<")]";
00591 return os;
00592 }
00593 }
00594
00595 KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, View, "test" ) {
00596 View view( 0 );
00597 #if 0 // GUI tests do not work well on the server
00598 QTimer::singleShot( 1000, qApp, SLOT( quit() ) );
00599 view.show();
00600
00601 qApp->exec();
00602 QPixmap screenshot1 = QPixmap::grabWidget( &view );
00603
00604 QTreeView* tv = new QTreeView;
00605 view.setLeftView( tv );
00606 view.setRowController( new TreeViewRowController(tv,view.ganttProxyModel()) );
00607
00608 QTimer::singleShot( 1000, qApp, SLOT( quit() ) );
00609
00610 qApp->exec();
00611 QPixmap screenshot2 = QPixmap::grabWidget( &view );
00612
00613 assertEqual( screenshot1.toImage(), screenshot2.toImage() );
00614
00615 QListView* lv = new QListView;
00616 view.setLeftView(lv);
00617 view.setRowController( new ListViewRowController(lv,view.ganttProxyModel()));
00618 view.show();
00619 QTimer::singleShot( 1000, qApp, SLOT( quit() ) );
00620 qApp->exec();
00621 #endif
00622 }
00623 #endif