• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

kdgantt

kdganttgraphicsview.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002  ** Copyright (C) 2001-2006 Klarälvdalens Datakonsult AB.  All rights reserved.
00003  **
00004  ** This file is part of the KD Gantt library.
00005  **
00006  ** This file may be used under the terms of the GNU General Public
00007  ** License versions 2.0 or 3.0 as published by the Free Software
00008  ** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
00009  ** included in the packaging of this file.  Alternatively you may (at
00010  ** your option) use any later version of the GNU General Public
00011  ** License if such license has been publicly approved by
00012  ** Klarälvdalens Datakonsult AB (or its successors, if any).
00013  ** 
00014  ** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
00015  ** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
00016  ** A PARTICULAR PURPOSE. Klarälvdalens Datakonsult AB reserves all rights
00017  ** not expressly granted herein.
00018  ** 
00019  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
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 ); // Parent must be set
00052 }
00053 
00054 HeaderWidget::~HeaderWidget()
00055 {
00056 }
00057 
00058 void HeaderWidget::scrollTo( int v )
00059 {
00060     m_offset = v;
00061     // QWidget::scroll() wont work properly for me on Mac
00062     //scroll( static_cast<int>( old-v ), 0 );
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         //} while ( ( idx = d->treeview.indexBelow( idx ) ) != QModelIndex() && d->treeview.visualRect(idx).isValid() );
00207      q->updateSceneRect();
00208 }
00209 
00210 void GraphicsView::Private::slotColumnsRemoved( const QModelIndex& parent,  int start, int end )
00211 {
00212     // TODO
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     //qDebug() << "GraphicsView::slotDataChanged("<<topLeft<<bottomRight<<")";
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     //qDebug() << "slotLayoutChanged()";
00231     q->updateScene();
00232 }
00233 
00234 void GraphicsView::Private::slotModelReset()
00235 {
00236     //qDebug() << "slotModelReset()";
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(); // TODO: This might be optimised
00246 }
00247 
00248 void GraphicsView::Private::slotRowsAboutToBeRemoved( const QModelIndex& parent,  int start, int end )
00249 {
00250     //qDebug() << "GraphicsView::Private::slotRowsAboutToBeRemoved("<<parent<<start<<end<<")";
00251     for ( int row = start; row <= end; ++row ) {
00252         for ( int col = 0; col < scene.summaryHandlingModel()->columnCount( parent ); ++col ) {
00253             //qDebug() << "removing "<<scene.summaryHandlingModel()->index( row, col, parent );
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     //qDebug() << "GraphicsView::Private::slotRowsRemoved("<<parent<<start<<end<<")";
00267     // TODO
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;//scene.summaryHandlingModel()->mapToSource( 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;//scene.summaryHandlingModel()->mapToSource( 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     // HACK!
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     /* Connections. We have to rely on the treeview
00374      * to receive the signals before we do(!)
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     // To scroll more to the left than the actual item start, bug #4516
00534     r.setLeft( qMin( qreal(0.0), r.left() ) );
00535     // TODO: take scrollbars into account (if not always on)
00536     // The scene should be at least the size of the viewport
00537     // NOTE: scrollbar calculus uses maximumViewportSize() - frameWidth()*2 (not the same as viewport()->size())
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     /* What to do with this? We need to shrink the view to
00583      * make collapsing items work
00584      */
00585     QRectF r = d->scene.itemsBoundingRect();
00586     // To scroll more to the left than the actual item start, bug #4516
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     //constraintModel()->cleanup();
00606     //qDebug() << constraintModel();
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"

kdgantt

Skip menu "kdgantt"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdepim

Skip menu "kdepim"
  • akonadi
  •   clients
  •   kabc
  •   kcal
  •   kcm
  • akregator
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt
  • kdgantt1
  • kjots
  • kleopatra
  • kmail
  • kmobiletools
  • knode
  • knotes
  • kontact
  • kontactinterfaces
  • korganizer
  •   korgac
  • kpilot
  • ktimetracker
  •   doc
  • libkdepim
  • libkholidays
  • libkleo
  • libkpgp
  • maildir
Generated for kdepim by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal