KD Chart 2  [rev.2.8]
kdganttgraphicsscene.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2021 Klaralvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Chart library.
5 **
6 ** Licensees holding valid commercial KD Chart licenses may use this file in
7 ** accordance with the KD Chart Commercial License Agreement provided with
8 ** the Software.
9 **
10 **
11 ** This file may be distributed and/or modified under the terms of the
12 ** GNU General Public License version 2 and version 3 as published by the
13 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contact info@kdab.com if any conditions of this licensing are not
19 ** clear to you.
20 **
21 **********************************************************************/
22 
23 #include "kdganttgraphicsscene.h"
24 #include "kdganttgraphicsscene_p.h"
25 #include "kdganttgraphicsitem.h"
26 #include "kdganttconstraint.h"
28 #include "kdganttitemdelegate.h"
30 #include "kdganttdatetimegrid.h"
32 
33 #include <QApplication>
34 #include <QGraphicsSceneHelpEvent>
35 #include <QPainter>
36 #include <QPrinter>
37 #include <QTextDocument>
38 #include <QToolTip>
39 #include <QSet>
40 
41 #include <QDebug>
42 
43 #include <functional>
44 #include <algorithm>
45 #include <cassert>
46 
47 // defines HAVE_PRINTER if support for printing should be included
48 #ifdef _WIN32_WCE
49  // There is no printer support under wince even if QT_NO_PRINTER is not set
50 #else
51 #ifndef QT_NO_PRINTER
52  #define HAVE_PRINTER
53 #endif
54 #endif
55 
60 using namespace KDGantt;
61 
62 GraphicsScene::Private::Private( GraphicsScene* _q )
63  : q( _q ),
64  dragSource( 0 ),
65  itemDelegate( new ItemDelegate( _q ) ),
66  rowController( 0 ),
67  grid( &default_grid ),
68  readOnly( false ),
69  isPrinting( false ),
70  drawColumnLabels( true ),
71  labelsWidth( 0.0 ),
72  summaryHandlingModel( new SummaryHandlingProxyModel( _q ) ),
73  selectionModel( 0 )
74 {
75  default_grid.setStartDateTime( QDateTime::currentDateTime().addDays( -1 ) );
76 }
77 
78 void GraphicsScene::Private::resetConstraintItems()
79 {
80  q->clearConstraintItems();
81  if ( constraintModel.isNull() ) return;
82  QList<Constraint> clst = constraintModel->constraints();
83  Q_FOREACH( const Constraint& c, clst ) {
84  createConstraintItem( c );
85  }
86  q->updateItems();
87 }
88 
89 void GraphicsScene::Private::createConstraintItem( const Constraint& c )
90 {
91  GraphicsItem* sitem = q->findItem( summaryHandlingModel->mapFromSource( c.startIndex() ) );
92  GraphicsItem* eitem = q->findItem( summaryHandlingModel->mapFromSource( c.endIndex() ) );
93 
94  if ( sitem && eitem ) {
96  sitem->addStartConstraint( citem );
97  eitem->addEndConstraint( citem );
98  q->addItem( citem );
99  }
100 
101  //q->insertConstraintItem( c, citem );
102 }
103 
104 // Delete the constraint item, and clean up pointers in the start- and end item
105 void GraphicsScene::Private::deleteConstraintItem( ConstraintGraphicsItem *citem )
106 {
107  //qDebug()<<"GraphicsScene::Private::deleteConstraintItem citem="<<citem;
108  if ( citem == 0 ) {
109  return;
110  }
111  Constraint c = citem->constraint();
112  GraphicsItem* item = items.value( summaryHandlingModel->mapFromSource( c.startIndex() ), 0 );
113  if ( item ) {
114  item->removeStartConstraint( citem );
115  }
116  item = items.value( summaryHandlingModel->mapFromSource( c.endIndex() ), 0 );
117  if ( item ) {
118  item->removeEndConstraint( citem );
119  }
120  delete citem;
121 }
122 
123 void GraphicsScene::Private::deleteConstraintItem( const Constraint& c )
124 {
125  deleteConstraintItem( findConstraintItem( c ) );
126 }
127 
128 ConstraintGraphicsItem* GraphicsScene::Private::findConstraintItem( const Constraint& c ) const
129 {
130  GraphicsItem* item = items.value( summaryHandlingModel->mapFromSource( c.startIndex() ), 0 );
131  if ( item ) {
134  for ( ; it != clst.end() ; ++it ) {
135  if ( c.compareIndexes((*it)->constraint()) )
136  break;
137  }
138  if ( it != clst.end() ) {
139  return *it;
140  }
141  }
142  item = items.value( summaryHandlingModel->mapFromSource( c.endIndex() ), 0 );
143  if ( item ) {
144  const QList<ConstraintGraphicsItem*> clst = item->endConstraints();
146  for ( ; it != clst.end() ; ++it ) {
147  if ( c.compareIndexes( (*it)->constraint() ) )
148  break;
149  }
150  if ( it != clst.end() ) {
151  return *it;
152  }
153  }
154  return 0;
155 }
156 
157 GraphicsScene::GraphicsScene( QObject* parent )
158  : QGraphicsScene( parent ), _d( new Private( this ) )
159 {
160  init();
161 }
162 
164 {
166  qDeleteAll( items() );
167  delete _d;
168 }
169 
170 #define d d_func()
171 
172 void GraphicsScene::init()
173 {
174  setItemIndexMethod( QGraphicsScene::NoIndex );
175  setConstraintModel( new ConstraintModel( this ) );
176  connect( d->grid, SIGNAL( gridChanged() ), this, SLOT( slotGridChanged() ) );
177 }
178 
179 /* NOTE: The delegate should really be a property
180  * of the view, but that doesn't really fit at
181  * this time
182  */
184 {
185  if ( !d->itemDelegate.isNull() && d->itemDelegate->parent()==this ) delete d->itemDelegate;
186  d->itemDelegate = delegate;
187  update();
188 }
189 
191 {
192  return d->itemDelegate;
193 }
194 
195 QAbstractItemModel* GraphicsScene::model() const
196 {
197  assert(!d->summaryHandlingModel.isNull());
198  return d->summaryHandlingModel->sourceModel();
199 }
200 
201 void GraphicsScene::setModel( QAbstractItemModel* model )
202 {
203  assert(!d->summaryHandlingModel.isNull());
204  d->summaryHandlingModel->setSourceModel(model);
205  d->grid->setModel( d->summaryHandlingModel );
206  setSelectionModel( new QItemSelectionModel( model, this ) );
207 }
208 
210 {
211  return d->summaryHandlingModel;
212 }
213 
215 {
216  proxyModel->setSourceModel( model() );
217  d->summaryHandlingModel = proxyModel;
218 }
219 
220 void GraphicsScene::setRootIndex( const QModelIndex& idx )
221 {
222  d->grid->setRootIndex( idx );
223 }
224 
225 QModelIndex GraphicsScene::rootIndex() const
226 {
227  return d->grid->rootIndex();
228 }
229 
231 {
232  return d->constraintModel;
233 }
234 
236 {
237  if ( !d->constraintModel.isNull() ) {
238  d->constraintModel->disconnect( this );
239  }
240  d->constraintModel = cm;
241 
242  connect( cm, SIGNAL( constraintAdded( const KDGantt::Constraint& ) ),
243  this, SLOT( slotConstraintAdded( const KDGantt::Constraint& ) ) );
244  connect( cm, SIGNAL( constraintRemoved( const KDGantt::Constraint& ) ),
245  this, SLOT( slotConstraintRemoved( const KDGantt::Constraint& ) ) );
246  d->resetConstraintItems();
247 }
248 
249 void GraphicsScene::setSelectionModel( QItemSelectionModel* smodel )
250 {
251  d->selectionModel = smodel;
252  // TODO: update selection from model and connect signals
253 }
254 
255 QItemSelectionModel* GraphicsScene::selectionModel() const
256 {
257  return d->selectionModel;
258 }
259 
261 {
262  d->rowController = rc;
263 }
264 
266 {
267  return d->rowController;
268 }
269 
270 void GraphicsScene::setGrid( AbstractGrid* grid )
271 {
272  QAbstractItemModel* model = 0;
273  if ( grid == 0 ) grid = &d->default_grid;
274  if ( d->grid ) {
275  d->grid->disconnect( this );
276  model = d->grid->model();
277  }
278  d->grid = grid;
279  connect( d->grid, SIGNAL( gridChanged() ), this, SLOT( slotGridChanged() ) );
280  d->grid->setModel( model );
281  slotGridChanged();
282 }
283 
284 AbstractGrid* GraphicsScene::grid() const
285 {
286  return d->grid;
287 }
288 
290 {
291  d->readOnly = ro;
292 }
293 
295 {
296  return d->readOnly;
297 }
298 
299 /* Returns the index with column=0 fromt the
300  * same row as idx and with the same parent.
301  * This is used to traverse the tree-structure
302  * of the model
303  */
304 QModelIndex GraphicsScene::mainIndex( const QModelIndex& idx )
305 {
306 #if 0
307  if ( idx.isValid() ) {
308  return idx.model()->index( idx.row(), 0,idx.parent() );
309  } else {
310  return QModelIndex();
311  }
312 #else
313  return idx;
314 #endif
315 }
316 
321 QModelIndex GraphicsScene::dataIndex( const QModelIndex& idx )
322 {
323 #if 0
324  if ( idx.isValid() ) {
325  const QAbstractItemModel* model = idx.model();
326  return model->index( idx.row(), model->columnCount( idx.parent() )-1,idx.parent() );
327  } else {
328  return QModelIndex();
329  }
330 #else
331  return idx;
332 #endif
333 }
334 
340 {
341 #if 0
342  switch ( type ) {
343  case TypeEvent: return 0;
344  case TypeTask: return new TaskItem;
345  case TypeSummary: return new SummaryItem;
346  default: return 0;
347  }
348 #endif
349  //qDebug() << "GraphicsScene::createItem("<<type<<")";
350  Q_UNUSED( type );
351  return new GraphicsItem;
352 }
353 
354 void GraphicsScene::Private::recursiveUpdateMultiItem( const Span& span, const QModelIndex& idx )
355 {
356  //qDebug() << "recursiveUpdateMultiItem("<<span<<idx<<")";
357  GraphicsItem* item = q->findItem( idx );
358  const int itemtype = summaryHandlingModel->data( idx, ItemTypeRole ).toInt();
359  if (!item) {
360  item = q->createItem( static_cast<ItemType>( itemtype ) );
361  item->setIndex( idx );
362  q->insertItem( idx, item);
363  }
364  item->updateItem( span, idx );
365  QModelIndex child;
366  int cr = 0;
367  while ( ( child = idx.child( cr, 0 ) ).isValid() ) {
368  recursiveUpdateMultiItem( span, child );
369  ++cr;
370  }
371 }
372 
373 void GraphicsScene::updateRow( const QModelIndex& rowidx )
374 {
375  //qDebug() << "GraphicsScene::updateRow("<<rowidx<<")" << rowidx.data( Qt::DisplayRole );
376  if ( !rowidx.isValid() ) return;
377 #if !defined(NDEBUG)
378  const QAbstractItemModel* model = rowidx.model(); // why const?
379 #endif
380  assert( model );
381  assert( rowController() );
382  assert( model == summaryHandlingModel() );
383 
384  const QModelIndex sidx = summaryHandlingModel()->mapToSource( rowidx );
385  Span rg = rowController()->rowGeometry( sidx );
386  for ( QModelIndex treewalkidx = sidx; treewalkidx.isValid(); treewalkidx = treewalkidx.parent() ) {
387  if ( treewalkidx.data( ItemTypeRole ).toInt() == TypeMulti
388  && !rowController()->isRowExpanded( treewalkidx )) {
389  rg = rowController()->rowGeometry( treewalkidx );
390  }
391  }
392 
393  bool blocked = blockSignals( true );
394  for ( int col = 0; col < summaryHandlingModel()->columnCount( rowidx.parent() ); ++col ) {
395  const QModelIndex idx = summaryHandlingModel()->index( rowidx.row(), col, rowidx.parent() );
396  const QModelIndex sidx = summaryHandlingModel()->mapToSource( idx );
397  const int itemtype = summaryHandlingModel()->data( idx, ItemTypeRole ).toInt();
398  const bool isExpanded = rowController()->isRowExpanded( sidx );
399  if ( itemtype == TypeNone ) {
400  removeItem( idx );
401  continue;
402  }
403  if ( itemtype == TypeMulti && !isExpanded ) {
404  d->recursiveUpdateMultiItem( rg, idx );
405  } else {
406  if ( summaryHandlingModel()->data( rowidx.parent(), ItemTypeRole ).toInt() == TypeMulti && !isExpanded ) {
407  //continue;
408  }
409 
410  GraphicsItem* item = findItem( idx );
411  if (!item) {
412  item = createItem( static_cast<ItemType>( itemtype ) );
413  item->setIndex( idx );
414  insertItem(idx, item);
415  }
416  const Span span = rowController()->rowGeometry( sidx );
417  item->updateItem( span, idx );
418  }
419  }
420  blockSignals( blocked );
421 }
422 
423 void GraphicsScene::insertItem( const QPersistentModelIndex& idx, GraphicsItem* item )
424 {
425  if ( !d->constraintModel.isNull() ) {
426  // Create items for constraints
427  const QModelIndex sidx = summaryHandlingModel()->mapToSource( idx );
428  const QList<Constraint> clst = d->constraintModel->constraintsForIndex( sidx );
429  Q_FOREACH( const Constraint& c, clst ) {
430  QModelIndex other_idx;
431  if ( c.startIndex() == sidx ) {
432  other_idx = c.endIndex();
433  GraphicsItem* other_item = d->items.value(summaryHandlingModel()->mapFromSource( other_idx ),0);
434  if ( !other_item ) continue;
436  item->addStartConstraint( citem );
437  other_item->addEndConstraint( citem );
438  addItem( citem );
439  } else if ( c.endIndex() == sidx ) {
440  other_idx = c.startIndex();
441  GraphicsItem* other_item = d->items.value(summaryHandlingModel()->mapFromSource( other_idx ),0);
442  if ( !other_item ) continue;
444  other_item->addStartConstraint( citem );
445  item->addEndConstraint( citem );
446  addItem( citem );
447  } else {
448  assert( 0 ); // Impossible
449  }
450  }
451  }
452  d->items.insert( idx, item );
453  addItem( item );
454 }
455 
456 void GraphicsScene::removeItem( const QModelIndex& idx )
457 {
458  //qDebug() << "GraphicsScene::removeItem("<<idx<<")";
459  QHash<QPersistentModelIndex,GraphicsItem*>::iterator it = d->items.find( idx );
460  if ( it != d->items.end() ) {
461  GraphicsItem* item = *it;
462  assert( item );
463  // We have to remove the item from the list first because
464  // there is a good chance there will be reentrant calls
465  d->items.erase( it );
466  {
467  // Remove any constraintitems attached
468  const QSet<ConstraintGraphicsItem*> clst = QSet<ConstraintGraphicsItem*>::fromList( item->startConstraints() ) +
469  QSet<ConstraintGraphicsItem*>::fromList( item->endConstraints() );
470  Q_FOREACH( ConstraintGraphicsItem* citem, clst ) {
471  d->deleteConstraintItem( citem );
472  }
473  }
474  // Get rid of the item
475  delete item;
476  }
477 }
478 
479 GraphicsItem* GraphicsScene::findItem( const QModelIndex& idx ) const
480 {
481  if ( !idx.isValid() ) return 0;
482  assert( idx.model() == summaryHandlingModel() );
483  QHash<QPersistentModelIndex,GraphicsItem*>::const_iterator it = d->items.find( idx );
484  return ( it != d->items.end() )?*it:0;
485 }
486 
487 GraphicsItem* GraphicsScene::findItem( const QPersistentModelIndex& idx ) const
488 {
489  if ( !idx.isValid() ) return 0;
490  assert( idx.model() == summaryHandlingModel() );
491  QHash<QPersistentModelIndex,GraphicsItem*>::const_iterator it = d->items.find( idx );
492  return ( it != d->items.end() )?*it:0;
493 }
494 
496 {
497  // TODO constraints
498  QHash<QPersistentModelIndex, GraphicsItem*>::const_iterator it = d->items.constBegin();
499  for ( ; it != d->items.constEnd(); ++it ) {
500  delete *it;
501  }
502  d->items.clear();
503 }
504 
506 {
507  for ( QHash<QPersistentModelIndex,GraphicsItem*>::iterator it = d->items.begin();
508  it != d->items.end(); ++it ) {
509  GraphicsItem* const item = it.value();
510  const QPersistentModelIndex& idx = it.key();
511  item->updateItem( Span( item->pos().y(), item->rect().height() ), idx );
512  }
513  invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
514 }
515 
516 void GraphicsScene::deleteSubtree( const QModelIndex& _idx )
517 {
518  QModelIndex idx = dataIndex( _idx );
519  if ( !idx.model() ) return;
520  const QModelIndex parent( idx.parent() );
521  const int colcount = idx.model()->columnCount( parent );
522  {for ( int i = 0; i < colcount; ++i ) {
523  removeItem( parent.child( idx.row(), i ) );
524  }}
525  const int rowcount = summaryHandlingModel()->rowCount( _idx );
526  {for ( int i = 0; i < rowcount; ++i ) {
527  deleteSubtree( summaryHandlingModel()->index( i, summaryHandlingModel()->columnCount(_idx)-1, _idx ) );
528  }}
529 }
530 
531 
533 {
534  return d->findConstraintItem( c );
535 }
536 
538 {
539  // TODO
540  // d->constraintItems.clearConstraintItems();
541 }
542 
543 void GraphicsScene::slotConstraintAdded( const KDGantt::Constraint& c )
544 {
545  d->createConstraintItem( c );
546 }
547 
548 void GraphicsScene::slotConstraintRemoved( const KDGantt::Constraint& c )
549 {
550  d->deleteConstraintItem( c );
551 }
552 
553 void GraphicsScene::slotGridChanged()
554 {
555  updateItems();
556  update();
557  emit gridChanged();
558 }
559 
560 void GraphicsScene::helpEvent( QGraphicsSceneHelpEvent *helpEvent )
561 {
562 #ifndef QT_NO_TOOLTIP
563  QGraphicsItem *item = itemAt( helpEvent->scenePos(), QTransform() );
564  if ( GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
565  QToolTip::showText(helpEvent->screenPos(), gitem->ganttToolTip());
566  } else if ( ConstraintGraphicsItem* citem = qgraphicsitem_cast<ConstraintGraphicsItem*>( item ) ) {
567  QToolTip::showText(helpEvent->screenPos(), citem->ganttToolTip());
568  } else {
569  QGraphicsScene::helpEvent( helpEvent );
570  }
571 #endif /* QT_NO_TOOLTIP */
572 }
573 
574 void GraphicsScene::drawBackground( QPainter* painter, const QRectF& _rect )
575 {
576  QRectF scn( sceneRect() );
577  QRectF rect( _rect );
578  if ( d->isPrinting && d->drawColumnLabels ) {
579  QRectF headerRect( scn.topLeft()+QPointF( d->labelsWidth, 0 ),
580  QSizeF( scn.width()-d->labelsWidth, d->rowController->headerHeight() ));
581 
582  d->grid->paintHeader( painter, headerRect, rect, 0, 0 );
583 
584 #if 0
585  /* We have to blank out the part of the header that is invisible during
586  * normal rendering when we are printing.
587  */
588  QRectF labelsTabRect( scn.topLeft(), QSizeF( d->labelsWidth, headerRect.height() ) );
589 
590  QStyleOptionHeader opt;
591  opt.rect = labelsTabRect.toRect();
592  opt.text = QLatin1String("");
593  opt.textAlignment = Qt::AlignCenter;
594  style()->drawControl(QStyle::CE_Header, &opt, painter, 0);
595 #endif
596 
597  scn.setTop( headerRect.bottom() );
598  scn.setLeft( headerRect.left() );
599  rect = rect.intersected( scn );
600  }
601  d->grid->paintGrid( painter, scn, rect, d->rowController );
602 
603  d->grid->drawBackground(painter, rect);
604 }
605 
606 void GraphicsScene::drawForeground( QPainter* painter, const QRectF& rect )
607 {
608  d->grid->drawForeground(painter, rect);
609 }
610 
611 void GraphicsScene::itemEntered( const QModelIndex& idx )
612 {
613  emit entered( idx );
614 }
615 
616 void GraphicsScene::itemPressed( const QModelIndex& idx )
617 {
618  emit pressed( idx );
619 }
620 
621 void GraphicsScene::itemClicked( const QModelIndex& idx )
622 {
623  emit clicked( idx );
624 }
625 
626 void GraphicsScene::itemDoubleClicked( const QModelIndex& idx )
627 {
628  emit qrealClicked( idx );
629 }
630 
632 {
633  d->dragSource = item;
634 }
635 
637 {
638  return d->dragSource;
639 }
640 
649 void GraphicsScene::print( QPrinter* printer, bool drawRowLabels, bool drawColumnLabels )
650 {
651 #ifndef HAVE_PRINTER
652  Q_UNUSED( printer );
653  Q_UNUSED( drawRowLabels );
654  Q_UNUSED( drawColumnLabels );
655 #else
656  QPainter painter( printer );
657  doPrint( &painter, printer->pageRect(), sceneRect().left(), sceneRect().right(), printer, drawRowLabels, drawColumnLabels );
658 #endif
659 }
660 
673 void GraphicsScene::print( QPrinter* printer, qreal start, qreal end, bool drawRowLabels, bool drawColumnLabels )
674 {
675 #ifndef HAVE_PRINTER
676  Q_UNUSED( printer );
677  Q_UNUSED( start );
678  Q_UNUSED( end );
679  Q_UNUSED( drawRowLabels );
680  Q_UNUSED( drawColumnLabels );
681 #else
682  QPainter painter( printer );
683  doPrint( &painter, printer->pageRect(), start, end, printer, drawRowLabels, drawColumnLabels );
684 #endif
685 }
686 
693 void GraphicsScene::print( QPainter* painter, const QRectF& _targetRect, bool drawRowLabels, bool drawColumnLabels )
694 {
695  QRectF targetRect( _targetRect );
696  if ( targetRect.isNull() ) {
697  targetRect = sceneRect();
698  }
699 
700  doPrint( painter, targetRect, sceneRect().left(), sceneRect().right(), 0, drawRowLabels, drawColumnLabels );
701 }
702 
713 void GraphicsScene::print( QPainter* painter, qreal start, qreal end,
714  const QRectF& _targetRect, bool drawRowLabels, bool drawColumnLabels )
715 {
716  QRectF targetRect( _targetRect );
717  if ( targetRect.isNull() ) {
718  targetRect = sceneRect();
719  }
720 
721  doPrint( painter, targetRect, start, end, 0, drawRowLabels, drawColumnLabels );
722 }
723 
726 void GraphicsScene::doPrint( QPainter* painter, const QRectF& targetRect,
727  qreal start, qreal end,
728  QPrinter* printer, bool drawRowLabels, bool drawColumnLabels )
729 {
730  assert( painter );
731  d->isPrinting = true;
732  d->drawColumnLabels = drawColumnLabels;
733  d->labelsWidth = 0.0;
734  QFont sceneFont( font() );
735 #ifdef HAVE_PRINTER
736  if ( printer ) {
737  sceneFont = QFont( font(), printer );
738  if ( font().pointSizeF() >= 0.0 )
739  sceneFont.setPointSizeF( font().pointSizeF() );
740  else if ( font().pointSize() >= 0 )
741  sceneFont.setPointSize( font().pointSize() );
742  else
743  sceneFont.setPixelSize( font().pixelSize() );
744  }
745 #endif
746 
747  QGraphicsTextItem dummyTextItem( QLatin1String("X") );
748  dummyTextItem.adjustSize();
749  QFontMetrics fm(dummyTextItem.font());
750  sceneFont.setPixelSize( fm.height() );
751 
752  const QRectF oldScnRect( sceneRect() );
753  QRectF scnRect( oldScnRect );
754  scnRect.setLeft( start );
755  scnRect.setRight( end );
756  bool b = blockSignals( true );
757 
758  /* column labels */
759  if ( d->drawColumnLabels ) {
760  QRectF headerRect( scnRect );
761  headerRect.setHeight( - d->rowController->headerHeight() );
762  scnRect.setTop(scnRect.top() - d->rowController->headerHeight());
763  }
764 
765  /* row labels */
766  QVector<QGraphicsTextItem*> textLabels;
767  if ( drawRowLabels ) {
768  qreal textWidth = 0.;
769  QModelIndex sidx = summaryHandlingModel()->mapToSource( summaryHandlingModel()->index( 0, 0, rootIndex()) );
770  do {
771  QModelIndex idx = summaryHandlingModel()->mapFromSource( sidx );
772  const Span rg=rowController()->rowGeometry( sidx );
773  const QString txt = idx.data( Qt::DisplayRole ).toString();
774  QGraphicsTextItem* item = new QGraphicsTextItem( txt );
775  addItem( item );
776  textLabels << item;
777  item->adjustSize();
778  textWidth = qMax( item->textWidth(), textWidth );
779  item->setPos( 0, rg.start() );
780  } while ( ( sidx = rowController()->indexBelow( sidx ) ).isValid() );
781  // Add a little margin to textWidth
782  textWidth += QFontMetricsF(sceneFont).width( QString::fromLatin1( "X" ) );
783  Q_FOREACH( QGraphicsTextItem* item, textLabels ) {
784  item->setPos( scnRect.left()-textWidth, item->y() );
785  item->show();
786  }
787  scnRect.setLeft( scnRect.left()-textWidth );
788  d->labelsWidth = textWidth;
789  }
790 
791  setSceneRect( scnRect );
792 
793  painter->save();
794  painter->setClipRect( targetRect );
795 
796  qreal yratio = targetRect.height()/scnRect.height();
797  /* If we're not printing multiple pages,
798  * check if the span fits and adjust:
799  */
800  if ( !printer && targetRect.width()/scnRect.width() < yratio ) {
801  yratio = targetRect.width()/scnRect.width();
802  }
803 
804  qreal offset = scnRect.left();
805  int pagecount = 0;
806  while ( offset < scnRect.right() ) {
807  painter->setFont( sceneFont );
808  render( painter, targetRect, QRectF( QPointF( offset, scnRect.top()),
809  QSizeF( targetRect.width()/yratio, scnRect.height() ) ) );
810  offset += targetRect.width()/yratio;
811  ++pagecount;
812  if ( printer && offset < scnRect.right() ) {
813 #ifdef HAVE_PRINTER
814  printer->newPage();
815 #endif
816  } else {
817  break;
818  }
819  }
820 
821  d->isPrinting = false;
822  d->drawColumnLabels = true;
823  d->labelsWidth = 0.0;
824  qDeleteAll( textLabels );
825  blockSignals( b );
826  setSceneRect( oldScnRect );
827  painter->restore();
828 }
829 
830 #include "moc_kdganttgraphicsscene.cpp"
831 
832 
833 #ifndef KDAB_NO_UNIT_TESTS
834 #include "unittest/test.h"
835 
836 #include <QGraphicsLineItem>
837 #include <QPointer>
838 #include <QStandardItemModel>
839 
840 #include "kdganttgraphicsview.h"
841 
842 class SceneTestRowController : public KDGantt::AbstractRowController {
843 private:
844  static const int ROW_HEIGHT;
845  QPointer<QAbstractItemModel> m_model;
846 
847 public:
848  SceneTestRowController()
849  {
850  }
851 
852  void setModel( QAbstractItemModel* model )
853  {
854  m_model = model;
855  }
856 
857  /*reimp*/int headerHeight() const override { return 40; }
858 
859  /*reimp*/ bool isRowVisible( const QModelIndex& ) const override { return true;}
860  /*reimp*/ bool isRowExpanded( const QModelIndex& ) const override { return false; }
861  /*reimp*/ KDGantt::Span rowGeometry( const QModelIndex& idx ) const override
862  {
863  return KDGantt::Span( idx.row() * ROW_HEIGHT, ROW_HEIGHT );
864  }
865  /*reimp*/ int maximumItemHeight() const override {
866  return ROW_HEIGHT/2;
867  }
868  /*reimp*/int totalHeight() const override {
869  return m_model->rowCount()* ROW_HEIGHT;
870  }
871 
872  /*reimp*/ QModelIndex indexAt( int height ) const override {
873  return m_model->index( height/ROW_HEIGHT, 0 );
874  }
875 
876  /*reimp*/ QModelIndex indexBelow( const QModelIndex& idx ) const override {
877  if ( !idx.isValid() )return QModelIndex();
878  return idx.model()->index( idx.row()+1, idx.column(), idx.parent() );
879  }
880  /*reimp*/ QModelIndex indexAbove( const QModelIndex& idx ) const override {
881  if ( !idx.isValid() )return QModelIndex();
882  return idx.model()->index( idx.row()-1, idx.column(), idx.parent() );
883  }
884 
885 };
886 
887 class TestLineItem : public QGraphicsLineItem
888 {
889 public:
890  TestLineItem( bool *destroyedFlag )
891  : QGraphicsLineItem( 0, 0, 10, 10 ), // geometry doesn't matter
892  m_destroyedFlag( destroyedFlag )
893  {}
894 
895  ~TestLineItem() override
896  { *m_destroyedFlag = true; }
897 
898 private:
899  bool *m_destroyedFlag;
900 };
901 
902 const int SceneTestRowController::ROW_HEIGHT = 30;
903 
905  QStandardItemModel model;
906 
907  QStandardItem* item = new QStandardItem();
908  item->setData( KDGantt::TypeTask, KDGantt::ItemTypeRole );
909  item->setData( QString::fromLatin1( "Decide on new product" ) );
910  item->setData( QDateTime( QDate( 2007, 3, 1 ) ), KDGantt::StartTimeRole );
911  item->setData( QDateTime( QDate( 2007, 3, 3 ) ), KDGantt::EndTimeRole );
912 
913  QStandardItem* item2 = new QStandardItem();
914  item2->setData( KDGantt::TypeTask, KDGantt::ItemTypeRole );
915  item2->setData( QString::fromLatin1( "Educate personnel" ) );
916  item2->setData( QDateTime( QDate( 2007, 3, 3 ) ), KDGantt::StartTimeRole );
917  item2->setData( QDateTime( QDate( 2007, 3, 6 ) ), KDGantt::EndTimeRole );
918 
919  model.appendRow( item );
920  model.appendRow( item2 );
921 
922  SceneTestRowController rowController;
923  rowController.setModel( &model );
924 
925  KDGantt::GraphicsView graphicsView;
926  graphicsView.setRowController( &rowController );
927  graphicsView.setModel( &model );
928 
929  // Now the interesting stuff - the items above are just for a "realistic environment"
930 
931  bool foreignItemDestroyed = false;
932  TestLineItem *foreignItem = new TestLineItem( &foreignItemDestroyed );
933  graphicsView.scene()->addItem( foreignItem );
934 
935  assertFalse( foreignItemDestroyed );
936  graphicsView.updateScene();
937  assertFalse( foreignItemDestroyed );
938 }
939 #endif /* KDAB_NO_UNIT_TESTS */
KDGantt::GraphicsScene::grid
AbstractGrid * grid() const
Definition: kdganttgraphicsscene.cpp:284
KDGantt::AbstractRowController::rowGeometry
virtual Span rowGeometry(const QModelIndex &idx) const =0
KDGantt::GraphicsScene::selectionModel
QItemSelectionModel * selectionModel() const
Definition: kdganttgraphicsscene.cpp:255
KDGantt::GraphicsScene::createItem
GraphicsItem * createItem(ItemType type) const
Definition: kdganttgraphicsscene.cpp:339
KDGantt::Span::start
qreal start() const
Definition: kdganttglobal.h:245
KDGantt::TypeSummary
@ TypeSummary
Definition: kdganttglobal.h:229
kdganttgraphicsscene.h
KDGantt::GraphicsScene::qrealClicked
void qrealClicked(const QModelIndex &index)
assertFalse
#define assertFalse(x)
Definition: test.h:42
KDGantt::GraphicsScene::itemClicked
void itemClicked(const QModelIndex &)
Definition: kdganttgraphicsscene.cpp:621
KDGantt::GraphicsScene::constraintModel
ConstraintModel * constraintModel() const
Definition: kdganttgraphicsscene.cpp:230
QList
Definition: KDChartPosition.h:36
KDGantt::GraphicsItem
Definition: kdganttgraphicsitem.h:42
KDGantt::GraphicsItem::removeStartConstraint
void removeStartConstraint(ConstraintGraphicsItem *)
Definition: kdganttgraphicsitem.cpp:250
KDGantt::Constraint::compareIndexes
bool compareIndexes(const Constraint &other) const
Definition: kdganttconstraint.cpp:175
KDGantt::GraphicsView::updateScene
void updateScene()
Definition: kdganttgraphicsview.cpp:685
KDGantt::GraphicsView::setModel
void setModel(QAbstractItemModel *)
Definition: kdganttgraphicsview.cpp:390
KDGantt::GraphicsScene::print
void print(QPrinter *printer, bool drawRowLabels=true, bool drawColumnLabels=true)
Definition: kdganttgraphicsscene.cpp:649
kdganttconstraint.h
KDGantt::AbstractRowController::isRowExpanded
virtual bool isRowExpanded(const QModelIndex &idx) const =0
KDGantt::GraphicsScene::updateItems
void updateItems()
Definition: kdganttgraphicsscene.cpp:505
KDGantt::GraphicsScene
Definition: kdganttgraphicsscene.h:48
KDGantt::Constraint::startIndex
QModelIndex startIndex() const
Definition: kdganttconstraint.cpp:129
KDGantt::ConstraintGraphicsItem
Definition: kdganttconstraintgraphicsitem.h:33
KDGantt::GraphicsScene::itemDelegate
ItemDelegate * itemDelegate() const
Definition: kdganttgraphicsscene.cpp:190
kdganttgraphicsview.h
KDGantt::GraphicsScene::rowController
AbstractRowController * rowController() const
Definition: kdganttgraphicsscene.cpp:265
KDGantt::GraphicsScene::setConstraintModel
void setConstraintModel(ConstraintModel *)
Definition: kdganttgraphicsscene.cpp:235
KDGantt::GraphicsView
The GraphicsView class provides a model/view implementation of a gantt chart.
Definition: kdganttgraphicsview.h:45
KDGantt::GraphicsScene::clicked
void clicked(const QModelIndex &index)
KDGantt::GraphicsScene::model
QAbstractItemModel * model() const
Definition: kdganttgraphicsscene.cpp:195
KDGantt::GraphicsItem::addEndConstraint
void addEndConstraint(ConstraintGraphicsItem *)
Definition: kdganttgraphicsitem.cpp:242
KDGantt::AbstractRowController
Abstract baseclass for row controllers. A row controller is used by the GraphicsView to nagivate the ...
Definition: kdganttabstractrowcontroller.h:34
KDGantt
Definition: kdganttabstractrowcontroller.h:33
KDGantt::GraphicsItem::endConstraints
QList< ConstraintGraphicsItem * > endConstraints() const
Definition: kdganttgraphicsitem.h:77
KDGantt::GraphicsItem::setIndex
void setIndex(const QPersistentModelIndex &idx)
Definition: kdganttgraphicsitem.cpp:185
kdganttitemdelegate.h
KDGantt::GraphicsView::setRowController
void setRowController(AbstractRowController *)
Definition: kdganttgraphicsview.cpp:509
KDGantt::GraphicsScene::drawBackground
void drawBackground(QPainter *painter, const QRectF &rect) override
Definition: kdganttgraphicsscene.cpp:574
KDGantt::GraphicsScene::setSelectionModel
void setSelectionModel(QItemSelectionModel *selectionmodel)
Definition: kdganttgraphicsscene.cpp:249
KDGantt::ConstraintGraphicsItem::constraint
const Constraint & constraint() const
Definition: kdganttconstraintgraphicsitem.h:50
KDGantt::GraphicsScene::clearItems
void clearItems()
Definition: kdganttgraphicsscene.cpp:495
KDGantt::Constraint::endIndex
QModelIndex endIndex() const
Definition: kdganttconstraint.cpp:135
KDGantt::ItemDelegate
Class used to render gantt items in a KDGantt::GraphicsView.
Definition: kdganttitemdelegate.h:37
KDGantt::GraphicsScene::itemDoubleClicked
void itemDoubleClicked(const QModelIndex &)
Definition: kdganttgraphicsscene.cpp:626
KDAB_SCOPED_UNITTEST_SIMPLE
KDAB_SCOPED_UNITTEST_SIMPLE(KDGantt, GraphicsView, "test")
Definition: kdganttgraphicsscene.cpp:904
KDGantt::GraphicsScene::pressed
void pressed(const QModelIndex &index)
KDGantt::TypeMulti
@ TypeMulti
Definition: kdganttglobal.h:230
kdganttabstractrowcontroller.h
KDGantt::ItemTypeRole
@ ItemTypeRole
Definition: kdganttglobal.h:221
KDGantt::GraphicsScene::findConstraintItem
ConstraintGraphicsItem * findConstraintItem(const Constraint &) const
Definition: kdganttgraphicsscene.cpp:532
KDGantt::GraphicsScene::findItem
GraphicsItem * findItem(const QModelIndex &) const
Definition: kdganttgraphicsscene.cpp:479
KDGantt::GraphicsItem::removeEndConstraint
void removeEndConstraint(ConstraintGraphicsItem *)
Definition: kdganttgraphicsitem.cpp:257
QAbstractProxyModel
KDGantt::Span
A class representing a start point and a length.
Definition: kdganttglobal.h:234
KDGantt::Constraint
A class used to represent a dependency.
Definition: kdganttconstraint.h:38
KDGantt::GraphicsScene::~GraphicsScene
~GraphicsScene() override
Definition: kdganttgraphicsscene.cpp:163
KDGantt::GraphicsScene::mainIndex
static QModelIndex mainIndex(const QModelIndex &idx)
Definition: kdganttgraphicsscene.cpp:304
KDGantt::GraphicsItem::rect
QRectF rect() const
Definition: kdganttgraphicsitem.h:60
KDGantt::GraphicsScene::insertItem
void insertItem(const QPersistentModelIndex &, GraphicsItem *)
Definition: kdganttgraphicsscene.cpp:423
KDGantt::ConstraintGraphicsItem::ganttToolTip
QString ganttToolTip() const
Definition: kdganttconstraintgraphicsitem.cpp:82
KDGantt::GraphicsScene::summaryHandlingModel
QAbstractProxyModel * summaryHandlingModel() const
Definition: kdganttgraphicsscene.cpp:209
KDGantt::GraphicsScene::setRootIndex
void setRootIndex(const QModelIndex &idx)
Definition: kdganttgraphicsscene.cpp:220
test.h
QGraphicsScene
KDGantt::ConstraintModel
Definition: kdganttconstraintmodel.h:33
KDGantt::GraphicsItem::updateItem
void updateItem(const Span &rowgeometry, const QPersistentModelIndex &idx)
Definition: kdganttgraphicsitem.cpp:278
KDGantt::GraphicsScene::itemEntered
void itemEntered(const QModelIndex &)
Definition: kdganttgraphicsscene.cpp:611
KDGantt::GraphicsScene::setRowController
void setRowController(AbstractRowController *rc)
Definition: kdganttgraphicsscene.cpp:260
KDGantt::GraphicsScene::entered
void entered(const QModelIndex &index)
KDGantt::TypeEvent
@ TypeEvent
Definition: kdganttglobal.h:227
KDGantt::GraphicsScene::rootIndex
QModelIndex rootIndex() const
Definition: kdganttgraphicsscene.cpp:225
KDGantt::GraphicsScene::drawForeground
void drawForeground(QPainter *painter, const QRectF &rect) override
Definition: kdganttgraphicsscene.cpp:606
KDGantt::EndTimeRole
@ EndTimeRole
Definition: kdganttglobal.h:219
KDGantt::TypeNone
@ TypeNone
Definition: kdganttglobal.h:226
KDGantt::GraphicsItem::addStartConstraint
void addStartConstraint(ConstraintGraphicsItem *)
Definition: kdganttgraphicsitem.cpp:234
d
#define d
Definition: kdganttgraphicsscene.cpp:170
KDGantt::GraphicsScene::setItemDelegate
void setItemDelegate(ItemDelegate *)
Definition: kdganttgraphicsscene.cpp:183
KDGantt::GraphicsScene::setModel
void setModel(QAbstractItemModel *)
Definition: kdganttgraphicsscene.cpp:201
KDGantt::GraphicsScene::setReadOnly
void setReadOnly(bool)
Definition: kdganttgraphicsscene.cpp:289
KDGantt::SummaryHandlingProxyModel
Proxy model that supports summary gantt items.
Definition: kdganttsummaryhandlingproxymodel.h:29
KDGantt::GraphicsScene::deleteSubtree
void deleteSubtree(const QModelIndex &)
Definition: kdganttgraphicsscene.cpp:516
kdganttgraphicsitem.h
KDGantt::GraphicsItem::startConstraints
QList< ConstraintGraphicsItem * > startConstraints() const
Definition: kdganttgraphicsitem.h:76
KDGantt::GraphicsScene::helpEvent
void helpEvent(QGraphicsSceneHelpEvent *helpEvent) override
Definition: kdganttgraphicsscene.cpp:560
KDGantt::GraphicsScene::gridChanged
void gridChanged()
KDGantt::TypeTask
@ TypeTask
Definition: kdganttglobal.h:228
KDGantt::ItemType
ItemType
Definition: kdganttglobal.h:225
KDGantt::GraphicsScene::itemPressed
void itemPressed(const QModelIndex &)
Definition: kdganttgraphicsscene.cpp:616
KDGantt::GraphicsScene::updateRow
void updateRow(const QModelIndex &idx)
Definition: kdganttgraphicsscene.cpp:373
KDGantt::GraphicsScene::dragSource
GraphicsItem * dragSource() const
Definition: kdganttgraphicsscene.cpp:636
KDGantt::GraphicsScene::setDragSource
void setDragSource(GraphicsItem *item)
Definition: kdganttgraphicsscene.cpp:631
KDGantt::GraphicsScene::setSummaryHandlingModel
void setSummaryHandlingModel(QAbstractProxyModel *)
Definition: kdganttgraphicsscene.cpp:214
QObject
kdganttsummaryhandlingproxymodel.h
QVector
Definition: KDChartWidget.h:34
kdganttconstraintgraphicsitem.h
KDGantt::GraphicsScene::setGrid
void setGrid(AbstractGrid *grid)
Definition: kdganttgraphicsscene.cpp:270
KDGantt::StartTimeRole
@ StartTimeRole
Definition: kdganttglobal.h:218
KDGantt::GraphicsScene::dataIndex
static QModelIndex dataIndex(const QModelIndex &idx)
Definition: kdganttgraphicsscene.cpp:321
QGraphicsItem
KDGantt::GraphicsScene::clearConstraintItems
void clearConstraintItems()
Definition: kdganttgraphicsscene.cpp:537
KDGantt::GraphicsScene::removeItem
void removeItem(const QModelIndex &)
Definition: kdganttgraphicsscene.cpp:456
KDGantt::GraphicsScene::isReadOnly
bool isReadOnly() const
Definition: kdganttgraphicsscene.cpp:294

Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/

https://www.kdab.com/development-resources/qt-tools/kd-chart/