KD Chart 2
[rev.2.5]
|
00001 /**************************************************************************** 00002 ** Copyright (C) 2001-2012 Klaralvdalens Datakonsult AB. All rights reserved. 00003 ** 00004 ** This file is part of the KD Chart library. 00005 ** 00006 ** Licensees holding valid commercial KD Chart licenses may use this file in 00007 ** accordance with the KD Chart Commercial License Agreement provided with 00008 ** the Software. 00009 ** 00010 ** 00011 ** This file may be distributed and/or modified under the terms of the 00012 ** GNU General Public License version 2 and version 3 as published by the 00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included. 00014 ** 00015 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00016 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00017 ** 00018 ** Contact info@kdab.com if any conditions of this licensing are not 00019 ** clear to you. 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 //init(); 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 //gfxview.setRenderHints( QPainter::Antialiasing ); 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 //qDebug() << "Looking to update from " << idx; 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 //qDebug() << "Updating row" << idx << idx.data( Qt::DisplayRole ).toString(); 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 //qDebug() << "View::Private::slotLeftWidgetVerticalRangeChanged("<<min<<max<<")"; 00222 gfxview->verticalScrollBar()->setRange( min, max ); 00223 gfxview->updateSceneRect(); 00224 } 00225 00226 void View::Private::slotGfxViewVerticalRangeChanged( int min, int max ) 00227 { 00228 //qDebug() << "View::Private::slotGfxViewVerticalRangeChanged("<<min<<max<<")"; 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 00559 void View::print( QPrinter* printer, bool drawRowLabels, bool drawColumnLabels ) 00560 { 00561 graphicsView()->print( printer, drawRowLabels, drawColumnLabels ); 00562 } 00563 00576 void View::print( QPrinter* printer, qreal start, qreal end, bool drawRowLabels, bool drawColumnLabels ) 00577 { 00578 graphicsView()->print( printer, start, end, drawRowLabels, drawColumnLabels ); 00579 } 00580 00587 void View::print( QPainter* painter, const QRectF& target, bool drawRowLabels, bool drawColumnLabels) 00588 { 00589 d->gfxview->print( painter, 00590 target, 00591 drawRowLabels, 00592 drawColumnLabels); 00593 } 00594 00605 void View::print( QPainter* painter, qreal start, qreal end, const QRectF& target, bool drawRowLabels, bool drawColumnLabels) 00606 { 00607 d->gfxview->print( painter, 00608 start, end, 00609 target, 00610 drawRowLabels, 00611 drawColumnLabels); 00612 } 00613 00614 00615 #include "moc_kdganttview.cpp" 00616 00617 #ifndef KDAB_NO_UNIT_TESTS 00618 #include "unittest/test.h" 00619 00620 #include "kdganttlistviewrowcontroller.h" 00621 #include <QApplication> 00622 #include <QTimer> 00623 #include <QPixmap> 00624 #include <QListView> 00625 00626 KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, View, "test" ) { 00627 View view( 0 ); 00628 #if 0 // GUI tests do not work well on the server 00629 QTimer::singleShot( 1000, qApp, SLOT( quit() ) ); 00630 view.show(); 00631 00632 qApp->exec(); 00633 QPixmap screenshot1 = QPixmap::grabWidget( &view ); 00634 00635 QTreeView* tv = new QTreeView; 00636 view.setLeftView( tv ); 00637 view.setRowController( new TreeViewRowController(tv,view.ganttProxyModel()) ); 00638 00639 QTimer::singleShot( 1000, qApp, SLOT( quit() ) ); 00640 00641 qApp->exec(); 00642 QPixmap screenshot2 = QPixmap::grabWidget( &view ); 00643 00644 assertEqual( screenshot1.toImage(), screenshot2.toImage() ); 00645 00646 QListView* lv = new QListView; 00647 view.setLeftView(lv); 00648 view.setRowController( new ListViewRowController(lv,view.ganttProxyModel())); 00649 view.show(); 00650 QTimer::singleShot( 1000, qApp, SLOT( quit() ) ); 00651 qApp->exec(); 00652 #endif 00653 } 00654 #endif /* KDAB_NO_UNIT_TESTS */