KD Chart 2 [rev.2.4]

kdganttview.cpp

Go to the documentation of this file.
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 
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 /* KDAB_NO_UNIT_TESTS */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/