KGantt

kganttgraphicsview.cpp
1/*
2 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3 *
4 * This file is part of the KGantt library.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "kganttgraphicsview.h"
10#include "kganttgraphicsview_p.h"
11#include "kganttabstractrowcontroller.h"
12#include "kganttgraphicsitem.h"
13#include "kganttconstraintmodel.h"
14#include "kganttdatetimetimelinedialog.h"
15
16#include <QLocale>
17#include <QMenu>
18#include <QPainter>
19#include <QPaintEvent>
20#include <QResizeEvent>
21#include <QScrollBar>
22#include <QAbstractProxyModel>
23#include <QPrinter>
24#include <QItemSelectionModel>
25#include <QGraphicsSceneMouseEvent>
26#include <QGuiApplication>
27#include <QActionGroup>
28
29#include <cassert>
30
31#if defined KDAB_EVAL
32#include "../evaldialog/evaldialog.h"
33#endif
34
35/*\class KGantt::HeaderWidget
36 * \internal
37 */
38
39using namespace KGantt;
40
41HeaderWidget::HeaderWidget( GraphicsView* parent )
42 : QWidget( parent ), m_offset( 0. ), m_headerType( DateTimeGrid::NoHeader )
43{
44 assert( parent ); // Parent must be set
45 setMouseTracking(true);
46}
47
48HeaderWidget::~HeaderWidget()
49{
50}
51
52void HeaderWidget::scrollTo( int v )
53{
54 m_offset = v;
55 // QWidget::scroll() won't work properly for me on Mac
56 //scroll( static_cast<int>( old-v ), 0 );
57 update();
58}
59
60void HeaderWidget::paintEvent( QPaintEvent* ev )
61{
62 QPainter p( this );
63 view()->grid()->paintHeader( &p, rect(), ev->rect(), m_offset, this );
64}
65
66bool HeaderWidget::event( QEvent* event )
67{
68 if ( event->type() == QEvent::ToolTip ) {
69 DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
70 if ( grid ) {
71 QHelpEvent *e = static_cast<QHelpEvent*>( event );
72 QDateTime dt = grid->mapFromChart( view()->mapToScene( e->x(), 0 ).x() ).toDateTime();
73 setToolTip(QLocale().toString(dt));
74 }
75 }
76 return QWidget::event( event );
77}
78
79void HeaderWidget::mousePressEvent(QMouseEvent *event)
80{
81 DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
82 int mousePosX = event->x();
83 m_headerType = grid->sectionHandleAtPos( view()->mapToScene( event->x(), 0 ).x(), event->pos().y(), geometry() );
84 if (m_headerType != DateTimeGrid::NoHeader) {
85 bool hasCursor = testAttribute(Qt::WA_SetCursor);
86 if (!hasCursor) {
87 setCursor(QCursor(Qt::SplitHCursor));
88 }
89 m_mousePosX = mousePosX;
90 event->accept();
91 return;
92 }
94}
95
96void HeaderWidget::mouseReleaseEvent(QMouseEvent *event)
97{
98 if ( m_headerType > 0 ) {
99 DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
100 int mousePosX = view()->mapToScene( event->x(), 0 ).x();
101 if ( grid->sectionHandleAtPos( mousePosX, event->pos().y(), geometry() ) == DateTimeGrid::NoHeader ) {
102 bool hasCursor = testAttribute(Qt::WA_SetCursor);
103 if (hasCursor) {
104 unsetCursor();
105 }
106 }
107 m_headerType = DateTimeGrid::NoHeader;
108 m_mousePosX = event->x();
110 }
112}
113
114void HeaderWidget::mouseMoveEvent(QMouseEvent *event)
115{
116 DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
117 int mousePosX = event->x();
118 qreal gridX = view()->mapToScene( event->x(), 0.0 ).x();
119 switch ( m_headerType ) {
120 case DateTimeGrid::UpperHeader:
121 {
122 if ( mousePosX > m_mousePosX ) {
123 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() * 1.05 ) );
124 } else {
125 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() / 1.05 ) );
126 }
127 m_mousePosX = mousePosX;
128 event->accept();
129 return;
130 }
131 case DateTimeGrid::LowerHeader:
132 {
133 if ( mousePosX > m_mousePosX ) {
134 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() * 1.01 ) );
135 } else {
136 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() / 1.01 ) );
137 }
138 m_mousePosX = mousePosX;
139 event->accept();
140 return;
141 }
142 default: {
143 bool hasCursor = testAttribute(Qt::WA_SetCursor);
144 DateTimeGrid::HeaderType type = grid->sectionHandleAtPos( gridX, event->pos().y(), geometry());
145 if (type != DateTimeGrid::NoHeader) {
146 if (!hasCursor) {
147 setCursor(QCursor(Qt::SplitHCursor));
148 }
149 event->accept();
150 return;
151 }
152 if (hasCursor) {
153 unsetCursor();
154 }
155 break;
156 }
157 }
159}
160
161void HeaderWidget::wheelEvent( QWheelEvent *event )
162{
163 DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
164 if ( event->angleDelta().y() > 0 ) {
165 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() * 1.1 ) );
166 } else {
167 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() / 1.1 ) );
168 }
169 event->accept();
170}
171
172void HeaderWidget::contextMenuEvent( QContextMenuEvent* event )
173{
174 QMenu contextMenu;
175
176 DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >( view()->grid() );
177 QAction* actionScaleAuto = nullptr;
178 QAction* actionScaleMonth = nullptr;
179 QAction* actionScaleWeek = nullptr;
180 QAction* actionScaleDay = nullptr;
181 QAction* actionScaleHour = nullptr;
182 QAction* actionZoomIn = nullptr;
183 QAction* actionZoomOut = nullptr;
184 QAction* actionTimeline = nullptr;
185 if ( grid != nullptr )
186 {
187 QMenu* menuScale = new QMenu( tr( "Scale", "@title:menu" ), &contextMenu );
188 QActionGroup* scaleGroup = new QActionGroup( &contextMenu );
189 scaleGroup->setExclusive( true );
190
191 actionScaleAuto = new QAction( tr( "Auto", "@item:inmenu Automatic scale" ), menuScale );
192 actionScaleAuto->setCheckable( true );
193 actionScaleAuto->setChecked( grid->scale() == DateTimeGrid::ScaleAuto );
194 actionScaleMonth = new QAction( tr( "Month", "@item:inmenu" ), menuScale );
195 actionScaleMonth->setCheckable( true );
196 actionScaleMonth->setChecked( grid->scale() == DateTimeGrid::ScaleMonth );
197 actionScaleWeek = new QAction( tr( "Week", "@item:inmenu" ), menuScale );
198 actionScaleWeek->setCheckable( true );
199 actionScaleWeek->setChecked( grid->scale() == DateTimeGrid::ScaleWeek );
200 actionScaleDay = new QAction( tr( "Day", "@item:inmenu" ), menuScale );
201 actionScaleDay->setCheckable( true );
202 actionScaleDay->setChecked( grid->scale() == DateTimeGrid::ScaleDay );
203 actionScaleHour = new QAction( tr( "Hour", "@item:inmenu" ), menuScale );
204 actionScaleHour->setCheckable( true );
205 actionScaleHour->setChecked( grid->scale() == DateTimeGrid::ScaleHour );
206
207 scaleGroup->addAction( actionScaleAuto );
208 menuScale->addAction( actionScaleAuto );
209
210 scaleGroup->addAction( actionScaleMonth );
211 menuScale->addAction( actionScaleMonth );
212
213 scaleGroup->addAction( actionScaleWeek );
214 menuScale->addAction( actionScaleWeek );
215
216 scaleGroup->addAction( actionScaleDay );
217 menuScale->addAction( actionScaleDay );
218
219 scaleGroup->addAction( actionScaleHour );
220 menuScale->addAction( actionScaleHour );
221
222 contextMenu.addMenu( menuScale );
223
224 contextMenu.addSeparator();
225
226 actionZoomIn = new QAction( tr( "Zoom In", "@action:inmenu" ), &contextMenu );
227 contextMenu.addAction( actionZoomIn );
228 actionZoomOut = new QAction( tr( "Zoom Out", "@action:inmenu" ), &contextMenu );
229 contextMenu.addAction( actionZoomOut );
230
231 contextMenu.addSeparator();
232 actionTimeline = new QAction( tr( "Timeline...", "@action:inmenu" ), &contextMenu );
233 contextMenu.addAction( actionTimeline );
234 }
235
236 if ( contextMenu.isEmpty() )
237 {
238 event->ignore();
239 return;
240 }
241
242 const QAction* const action = contextMenu.exec( event->globalPos() );
243 if ( action == nullptr ) {}
244 else if ( action == actionScaleAuto )
245 {
246 assert( grid != nullptr );
247 grid->setScale( DateTimeGrid::ScaleAuto );
248 }
249 else if ( action == actionScaleMonth )
250 {
251 assert( grid != nullptr );
252 grid->setScale( DateTimeGrid::ScaleMonth );
253 }
254 else if ( action == actionScaleWeek )
255 {
256 assert( grid != nullptr );
257 grid->setScale( DateTimeGrid::ScaleWeek );
258 }
259 else if ( action == actionScaleDay )
260 {
261 assert( grid != nullptr );
262 grid->setScale( DateTimeGrid::ScaleDay );
263 }
264 else if ( action == actionScaleHour )
265 {
266 assert( grid != nullptr );
267 grid->setScale( DateTimeGrid::ScaleHour );
268 }
269 else if ( action == actionZoomIn )
270 {
271 assert( grid != nullptr );
272 grid->setDayWidth( grid->dayWidth() * 1.25 );
273 }
274 else if ( action == actionZoomOut )
275 {
276 assert( grid != nullptr );
277 // daywidth *MUST NOT* go below 1.0, it is used as an integer later on
278 grid->setDayWidth( qMax<qreal>( 1.0, grid->dayWidth() * 0.8 ) );
279 }
280 else if ( action == actionTimeline )
281 {
282 assert( grid != nullptr );
283 DateTimeTimeLineDialog dlg(grid->timeLine());
284 dlg.exec();
285 }
286 event->accept();
287}
288
289GraphicsView::Private::Private( GraphicsView* _q )
290 : q( _q ), rowcontroller(nullptr), headerwidget( _q )
291{
292}
293
294GraphicsView::Private::~Private()
295{
296}
297
298void GraphicsView::Private::updateHeaderGeometry()
299{
300 q->setViewportMargins(0,rowcontroller->headerHeight(),0,0);
301 headerwidget.setGeometry( q->viewport()->x(),
302 q->viewport()->y() - rowcontroller->headerHeight(),
303 q->viewport()->width(),
304 rowcontroller->headerHeight() );
305}
306
307void GraphicsView::Private::slotGridChanged()
308{
309 updateHeaderGeometry();
310 headerwidget.update();
311 q->updateSceneRect();
312 q->update();
313}
314
315void GraphicsView::Private::slotHorizontalScrollValueChanged( int val )
316{
317 const QRectF viewRect = q->transform().mapRect( q->sceneRect() );
318 headerwidget.scrollTo( val-q->horizontalScrollBar()->minimum()+static_cast<int>( viewRect.left() ) );
319}
320
321void GraphicsView::Private::slotColumnsInserted( const QModelIndex& parent, int start, int end )
322{
323 Q_UNUSED( start );
324 Q_UNUSED( end );
325 QModelIndex idx = scene.model()->index( 0, 0, scene.summaryHandlingModel()->mapToSource( parent ) );
326 do {
327 scene.updateRow( scene.summaryHandlingModel()->mapFromSource( idx ) );
328 } while ( ( idx = rowcontroller->indexBelow( idx ) ) != QModelIndex() && rowcontroller->isRowVisible( idx ) );
329 //} while ( ( idx = d->treeview.indexBelow( idx ) ) != QModelIndex() && d->treeview.visualRect(idx).isValid() );
330 q->updateSceneRect();
331}
332
333void GraphicsView::Private::slotColumnsRemoved( const QModelIndex& parent, int start, int end )
334{
335 // TODO
336 Q_UNUSED( start );
337 Q_UNUSED( end );
338 Q_UNUSED( parent );
339 q->updateScene();
340}
341
342void GraphicsView::Private::slotDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight )
343{
344 //qDebug() << "GraphicsView::slotDataChanged("<<topLeft<<bottomRight<<")";
345 const QModelIndex parent = topLeft.parent();
346 for ( int row = topLeft.row(); row <= bottomRight.row(); ++row ) {
347 scene.updateRow( scene.summaryHandlingModel()->index( row, 0, parent ) );
348 }
349}
350
351void GraphicsView::Private::slotLayoutChanged()
352{
353 //qDebug() << "slotLayoutChanged()";
354 q->updateScene();
355}
356
357void GraphicsView::Private::slotModelReset()
358{
359 //qDebug() << "slotModelReset()";
360 q->updateScene();
361}
362
363void GraphicsView::Private::slotRowsInserted( const QModelIndex& parent, int start, int end )
364{
365 Q_UNUSED( parent );
366 Q_UNUSED( start );
367 Q_UNUSED( end );
368 q->updateScene(); // TODO: This might be optimised
369}
370
371void GraphicsView::Private::removeConstraintsRecursive( QAbstractProxyModel *summaryModel, const QModelIndex& index )
372{
373 if ( summaryModel->hasChildren( index ) ) {
374 //qDebug() << "removing constraints from children of"<<index;
375 for ( int row = 0; row < summaryModel->rowCount( index ); ++row ) {
376 const QModelIndex child = summaryModel->index( row, index.column(), index );
377 removeConstraintsRecursive( summaryModel, child );
378 }
379 }
380 //qDebug() << "removing constraints from"<<index;
381 // NOTE: Constraints are mapped to indexes in the summaryModel->sourceModel()
382 const QList<Constraint> clst = scene.constraintModel()->constraintsForIndex( summaryModel->mapToSource( index ) );
383 for ( const Constraint &c : clst ) {
384 scene.constraintModel()->removeConstraint( c );
385 }
386}
387
388void GraphicsView::Private::slotRowsAboutToBeRemoved( const QModelIndex& parent, int start, int end )
389{
390 //qDebug() << "GraphicsView::Private::slotRowsAboutToBeRemoved("<<parent<<start<<end<<")";
391 QAbstractProxyModel *summaryModel = scene.summaryHandlingModel();
392 for ( int row = start; row <= end; ++row ) {
393 for ( int col = 0; col < summaryModel->columnCount( parent ); ++col ) {
394 const QModelIndex idx = summaryModel->index( row, col, parent );
395 removeConstraintsRecursive( summaryModel, idx );
396 scene.removeItem( idx );
397 }
398 }
399}
400
401void GraphicsView::Private::slotRowsRemoved( const QModelIndex& parent, int start, int end )
402{
403 //qDebug() << "GraphicsView::Private::slotRowsRemoved("<<parent<<start<<end<<")";
404 // TODO
405 Q_UNUSED( parent );
406 Q_UNUSED( start );
407 Q_UNUSED( end );
408
409 q->updateScene();
410}
411
412void GraphicsView::Private::slotItemClicked( const QModelIndex& idx )
413{
414 QModelIndex sidx = idx;//scene.summaryHandlingModel()->mapToSource( idx );
415 Q_EMIT q->clicked( sidx );
416 if (q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, q))
417 Q_EMIT q->activated( sidx );
418}
419
420void GraphicsView::Private::slotItemDoubleClicked( const QModelIndex& idx )
421{
422 QModelIndex sidx = idx;//scene.summaryHandlingModel()->mapToSource( idx );
423 Q_EMIT q->qrealClicked( sidx );
424 if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, q))
425 Q_EMIT q->activated( sidx );
426}
427
428void GraphicsView::Private::slotHeaderContextMenuRequested( const QPoint& pt )
429{
430 Q_EMIT q->headerContextMenuRequested( headerwidget.mapToGlobal( pt ) );
431}
432
434 : QGraphicsView( parent ), _d( new Private( this ) )
435{
436#if defined KDAB_EVAL
437 EvalDialog::checkEvalLicense( "KD Gantt" );
438#endif
439 connect( horizontalScrollBar(), SIGNAL(valueChanged(int)),
440 this, SLOT(slotHorizontalScrollValueChanged(int)) );
441 connect( &_d->scene, SIGNAL(gridChanged()),
442 this, SLOT(slotGridChanged()) );
443 connect( &_d->scene, SIGNAL(entered(QModelIndex)),
444 this, SIGNAL(entered(QModelIndex)) );
445 connect( &_d->scene, SIGNAL(pressed(QModelIndex)),
446 this, SIGNAL(pressed(QModelIndex)) );
447 connect( &_d->scene, SIGNAL(clicked(QModelIndex)),
448 this, SLOT(slotItemClicked(QModelIndex)) );
449 connect( &_d->scene, SIGNAL(qrealClicked(QModelIndex)),
450 this, SLOT(slotItemDoubleClicked(QModelIndex)) );
451 connect( &_d->scene, SIGNAL(sceneRectChanged(QRectF)),
452 this, SLOT(updateSceneRect()) );
453 connect( &_d->headerwidget, SIGNAL(customContextMenuRequested(QPoint)),
454 this, SLOT(slotHeaderContextMenuRequested(QPoint)) );
455 setScene( &_d->scene );
456
457 // HACK!
458 setSummaryHandlingModel( _d->scene.summaryHandlingModel() );
459
460 // So that AbstractGrid::drawBackground() and AbstractGrid::drawForeground()
461 // works properly
463
464 //setCacheMode( CacheBackground );
465}
466
467
469{
470 delete _d;
471}
472
473#define d d_func()
474
475
477{
478 if ( d->scene.model() ) {
479 disconnect( d->scene.model() );
480 }
481
482 d->scene.setModel( model );
483 if (model) {
484 connect( model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
485 this, SLOT(updateSceneRect()) );
486 }
487 updateScene();
488}
489
490
492{
493 return d->scene.model();
494}
495
496void GraphicsView::setSummaryHandlingModel( QAbstractProxyModel* proxyModel )
497{
498 disconnect( d->scene.summaryHandlingModel() );
499 d->scene.setSummaryHandlingModel( proxyModel );
500
501 /* Connections. We have to rely on the treeview
502 * to receive the signals before we do(!)
503 */
504 connect( proxyModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
505 this, SLOT(slotColumnsInserted(QModelIndex,int,int)) );
506 connect( proxyModel, SIGNAL(columnsRemoved(QModelIndex,int,int)),
507 this, SLOT(slotColumnsRemoved(QModelIndex,int,int)) );
508 connect( proxyModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
509 this, SLOT(slotDataChanged(QModelIndex,QModelIndex)) );
510 connect( proxyModel, SIGNAL(layoutChanged()),
511 this, SLOT(slotLayoutChanged()) );
512 connect( proxyModel, SIGNAL(modelReset()),
513 this, SLOT(slotModelReset()) );
514 connect( proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
515 this, SLOT(slotRowsInserted(QModelIndex,int,int)) );
516 connect( proxyModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
517 this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)) );
518 connect( proxyModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
519 this, SLOT(slotRowsRemoved(QModelIndex,int,int)) );
520
521 updateScene();
522}
523
524
526{
527 d->scene.setConstraintModel( cmodel );
528}
529
530
532{
533 return d->scene.constraintModel();
534}
535
536
538{
539 return d->scene.summaryHandlingModel();
540}
541
542
544{
545 d->scene.setRootIndex( idx );
546}
547
548
550{
551 return d->scene.rootIndex();
552}
553
554
556{
557 d->scene.setSelectionModel( model );
558}
559
560
562{
563 return d->scene.selectionModel();
564}
565
566
568{
569 d->scene.setItemDelegate( delegate );
570}
571
572
574{
575 return d->scene.itemDelegate();
576}
577
578
580{
581 d->rowcontroller = rowcontroller;
582 d->scene.setRowController( rowcontroller );
583 updateScene();
584}
585
586
588{
589 return d->rowcontroller;
590}
591
592
594{
595 d->scene.setGrid( grid );
596 d->slotGridChanged();
597}
598
599
601{
602 return d->scene.grid();
603}
604
605
607{
608 return d->scene.takeGrid();
609}
610
611
613{
614 d->scene.setReadOnly( ro );
615}
616
617
619{
620 return d->scene.isReadOnly();
621}
622
623
625{
626 d->headerwidget.setContextMenuPolicy( p );
627}
628
629
631{
632 return d->headerwidget.contextMenuPolicy();
633}
634
635
637 const QModelIndex& to,
638 Qt::KeyboardModifiers modifiers )
639{
640 if ( isReadOnly() ) return;
642 assert( cmodel );
643 Constraint c( from, to, ( modifiers&Qt::ShiftModifier )?Constraint::TypeHard:Constraint::TypeSoft );
644 if ( cmodel->hasConstraint( c ) ) cmodel->removeConstraint( c );
645 else cmodel->addConstraint( c );
646}
647
648void GraphicsView::resizeEvent( QResizeEvent* ev )
649{
650 d->updateHeaderGeometry();
652 // To scroll more to the left than the actual item start, bug #4516
653 r.setLeft( qMin<qreal>( 0.0, r.left() ) );
654 // TODO: take scrollbars into account (if not always on)
655 // The scene should be at least the size of the viewport
656 QSizeF size = viewport()->size();
657 //TODO: why -2 below? size should be ex. frames etc?
658 if ( size.width() > r.width() ) {
659 r.setWidth( size.width() - 2 );
660 }
661 if ( size.height() > r.height() ) {
662 r.setHeight( size.height() - 2 );
663 }
664 const int totalh = rowController()->totalHeight();
665 if ( r.height() < totalh ) {
666 r.setHeight( totalh );
667 }
668
669 scene()->setSceneRect( r );
670
672}
673
674
676{
677 QGraphicsItem* item = itemAt( pos );
678 if ( GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
679 return d->scene.summaryHandlingModel()->mapToSource( gitem->index() );
680 } else {
681 return QModelIndex();
682 }
683}
684
685
687{
688 d->scene.clearItems();
689}
690
691
693{
694 d->scene.updateRow( d->scene.summaryHandlingModel()->mapFromSource( idx ) );
695}
696
697
699{
700 /* What to do with this? We need to shrink the view to
701 * make collapsing items work
702 */
704 const qreal hscroll = horizontalScrollBar()->value()/( range>0?range:1 );
705 QRectF r = d->scene.itemsBoundingRect();
706 // To scroll more to the left than the actual item start, bug #4516
707 r.setTop( 0. );
708 r.setLeft( qMin<qreal>( 0.0, r.left() ) );
709 r.setSize( r.size().expandedTo( viewport()->size() ) );
710 const int totalh = rowController()->totalHeight();
711 if ( r.height() < totalh ) r.setHeight( totalh );
712 d->scene.setSceneRect( r );
713
714 /* set scrollbar to keep the same time in view */
716 if ( range>0 ) {
717 horizontalScrollBar()->setValue( qRound( hscroll*range ) );
718 } else {
719 // keep header in sync with scene
720 d->headerwidget.scrollTo(r.left());
721 }
722 /* We have to update here to adjust for any rows with no
723 * information because they are painted with a different
724 * background brush
725 */
726 d->scene.invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
727}
728
729
731{
732 clearItems();
733 if ( !model()) return;
734 if ( !rowController()) return;
735 QModelIndex idx = model()->index( 0, 0, rootIndex() );
736 do {
737 updateRow( idx );
738 } while ( ( idx = rowController()->indexBelow( idx ) ) != QModelIndex() && rowController()->isRowVisible(idx) );
739 //constraintModel()->cleanup();
740 //qDebug() << constraintModel();
743}
744
745#if 0
746TODO: For 3.0
747
748GraphicsItem* GraphicsView::createItem( ItemType type ) const
749{
750 Q_UNUSED(type)
751 return new GraphicsItem;
752}
753#endif
754
755
757{
758 d->scene.deleteSubtree( d->scene.summaryHandlingModel()->mapFromSource( idx ) );
759}
760
761
762void GraphicsView::print( QPrinter* printer, bool drawRowLabels, bool drawColumnLabels )
763{
764 d->scene.print( printer, drawRowLabels, drawColumnLabels );
765}
766
767
768void GraphicsView::print( QPrinter* printer, qreal start, qreal end, bool drawRowLabels, bool drawColumnLabels )
769{
770 d->scene.print( printer, start, end, drawRowLabels, drawColumnLabels );
771}
772
773
774void GraphicsView::print( QPainter* painter, const QRectF& targetRect, bool drawRowLabels, bool drawColumnLabels )
775{
776 d->scene.print(painter, targetRect, drawRowLabels, drawColumnLabels);
777}
778
779
780void GraphicsView::print( QPainter* painter, qreal start, qreal end,
781 const QRectF& targetRect, bool drawRowLabels, bool drawColumnLabels )
782{
783 d->scene.print(painter, start, end, targetRect, drawRowLabels, drawColumnLabels);
784}
785
787{
788 d->scene.printDiagram( printer, context );
789}
790
791#include "moc_kganttgraphicsview.cpp"
Abstract baseclass for grids. A grid is used to convert between QModelIndex'es and gantt chart values...
Abstract baseclass for row controllers. A row controller is used by the GraphicsView to nagivate the ...
virtual int totalHeight() const =0
virtual void addConstraint(const Constraint &c)
bool hasConstraint(const Constraint &c) const
virtual bool removeConstraint(const Constraint &c)
A class used to represent a dependency.
bool mapFromChart(const Span &span, const QModelIndex &idx, const QList< Constraint > &constraints=QList< Constraint >()) const override
DateTimeTimeLine * timeLine() const
The GraphicsView class provides a model/view implementation of a gantt chart.
void setModel(QAbstractItemModel *)
QAbstractItemModel * model() const
void setGrid(KGantt::AbstractGrid *)
void setConstraintModel(KGantt::ConstraintModel *)
void setRootIndex(const QModelIndex &)
void print(QPrinter *printer, bool drawRowLabels=true, bool drawColumnLabels=true)
void setSelectionModel(QItemSelectionModel *)
void setRowController(KGantt::AbstractRowController *)
void setItemDelegate(KGantt::ItemDelegate *delegate)
void setHeaderContextMenuPolicy(Qt::ContextMenuPolicy)
QModelIndex rootIndex() const
ConstraintModel * constraintModel() const
GraphicsView(QWidget *parent=nullptr)
virtual void addConstraint(const QModelIndex &from, const QModelIndex &to, Qt::KeyboardModifiers modifiers)
QItemSelectionModel * selectionModel() const
AbstractGrid * grid() const
AbstractRowController * rowController() const
Qt::ContextMenuPolicy headerContextMenuPolicy() const
void updateRow(const QModelIndex &)
void printDiagram(QPrinter *printer, const PrintingContext &context)
ItemDelegate * itemDelegate() const
QModelIndex indexAt(const QPoint &pos) const
QAbstractProxyModel * summaryHandlingModel() const
void deleteSubtree(const QModelIndex &)
Class used to render gantt items in a KGantt::GraphicsView.
The PrintingContext class provides options for printing the gantt chart.
Q_SCRIPTABLE Q_NOREPLY void start()
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
Type type(const QSqlDatabase &db)
void update(Part *part, const QByteArray &data, qint64 dataSize)
char * toString(const EngineQuery &query)
Global namespace.
const QList< QKeySequence > & end()
virtual int columnCount(const QModelIndex &parent) const const=0
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
virtual int rowCount(const QModelIndex &parent) const const=0
virtual bool hasChildren(const QModelIndex &parent) const const override
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const const=0
QScrollBar * horizontalScrollBar() const const
QWidget * viewport() const const
void setCheckable(bool)
void setChecked(bool)
QAction * addAction(QAction *action)
void setExclusive(bool b)
void invalidate(const QRectF &rect, SceneLayers layers)
QRectF itemsBoundingRect() const const
void setSceneRect(const QRectF &rect)
QGraphicsItem * itemAt(const QPoint &pos) const const
virtual void resizeEvent(QResizeEvent *event) override
QGraphicsScene * scene() const const
void setScene(QGraphicsScene *scene)
void setViewportUpdateMode(ViewportUpdateMode mode)
void restoreOverrideCursor()
int x() const const
QAction * addAction(const QIcon &icon, const QString &text, Functor functor, const QKeySequence &shortcut)
QAction * addMenu(QMenu *menu)
QAction * addSeparator()
QAction * exec()
bool isEmpty() const const
int column() const const
const QAbstractItemModel * model() const const
QModelIndex parent() const const
int row() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
const QRect & rect() const const
qreal height() const const
qreal left() const const
void setHeight(qreal height)
void setLeft(qreal x)
void setSize(const QSizeF &size)
void setTop(qreal y)
void setWidth(qreal width)
QSizeF size() const const
qreal width() const const
QSizeF expandedTo(const QSizeF &otherSize) const const
SH_ItemView_ActivateItemOnSingleClick
ContextMenuPolicy
SplitHCursor
typedef KeyboardModifiers
WA_SetCursor
void customContextMenuRequested(const QPoint &pos)
virtual bool event(QEvent *event) override
virtual void mouseMoveEvent(QMouseEvent *event)
virtual void mousePressEvent(QMouseEvent *event)
virtual void mouseReleaseEvent(QMouseEvent *event)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:09:26 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.