KGantt

kganttgraphicsscene.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 "kganttgraphicsscene.h"
10 #include "kganttgraphicsscene_p.h"
11 #include "kganttgraphicsitem.h"
12 #include "kganttconstraint.h"
13 #include "kganttconstraintgraphicsitem.h"
14 #include "kganttitemdelegate.h"
15 #include "kganttabstractrowcontroller.h"
16 #include "kganttabstractgrid.h"
17 #include "kganttdatetimegrid.h"
18 #include "kganttsummaryhandlingproxymodel.h"
19 #include "kganttgraphicsview.h"
20 #include "kganttprintingcontext.h"
21 
22 #include <QApplication>
23 #include <QGraphicsSceneHelpEvent>
24 #include <QPainter>
25 #include <QPrinter>
26 #include <QTextDocument>
27 #include <QToolTip>
28 #include <QSet>
29 
30 #include <QDebug>
31 
32 #include <functional>
33 #include <algorithm>
34 #include <cassert>
35 
36 // defines HAVE_PRINTER if support for printing should be included
37 #ifdef _WIN32_WCE
38  // There is no printer support under wince even if QT_NO_PRINTER is not set
39 #else
40 #ifndef QT_NO_PRINTER
41  #define HAVE_PRINTER
42 #endif
43 #endif
44 
45 
46 
47 using namespace KGantt;
48 
49 GraphicsScene::Private::Private( GraphicsScene* _q )
50  : q( _q ),
51  dragSource( nullptr ),
52  itemDelegate( new ItemDelegate( _q ) ),
53  rowController( nullptr ),
54  readOnly( false ),
55  isPrinting( false ),
56  drawColumnLabels( true ),
57  labelsWidth( 0.0 ),
58  summaryHandlingModel( new SummaryHandlingProxyModel( _q ) ),
59  selectionModel( nullptr )
60 {
61  default_grid.setStartDateTime( QDateTime::currentDateTime().addDays( -1 ) );
62 }
63 
64 GraphicsScene::Private::~Private()
65 {
66  delete grid;
67 }
68 
69 void GraphicsScene::Private::clearConstraintItems()
70 {
71  for(ConstraintGraphicsItem *citem : qAsConst(constraintItems)) {
72  // remove constraint from items first
73  for(GraphicsItem *item : qAsConst(items)) {
74  item->removeStartConstraint(citem);
75  item->removeEndConstraint(citem);
76  }
77  q->removeItem(citem);
78  delete citem;
79  }
80  constraintItems.clear();
81 }
82 
83 void GraphicsScene::Private::resetConstraintItems()
84 {
85  clearConstraintItems();
86  if ( constraintModel.isNull() ) return;
87  const QList<Constraint> clst = constraintModel->constraints();
88  for ( const Constraint& c : clst ) {
89  createConstraintItem( c );
90  }
91  q->updateItems();
92 }
93 
94 void GraphicsScene::Private::createConstraintItem( const Constraint& c )
95 {
96  GraphicsItem* sitem = q->findItem( summaryHandlingModel->mapFromSource( c.startIndex() ) );
97  GraphicsItem* eitem = q->findItem( summaryHandlingModel->mapFromSource( c.endIndex() ) );
98 
99  if ( sitem && eitem ) {
101  sitem->addStartConstraint( citem );
102  eitem->addEndConstraint( citem );
103  constraintItems.append( citem );
104  q->addItem( citem );
105  }
106 
107  //q->insertConstraintItem( c, citem );
108 }
109 
110 // Delete the constraint item, and clean up pointers in the start- and end item
111 void GraphicsScene::Private::deleteConstraintItem( ConstraintGraphicsItem *citem )
112 {
113  //qDebug()<<"GraphicsScene::Private::deleteConstraintItem citem="<<citem;
114  if ( citem == nullptr ) {
115  return;
116  }
117  Constraint c = citem->constraint();
118  GraphicsItem* item = items.value( summaryHandlingModel->mapFromSource( c.startIndex() ), nullptr );
119  if ( item ) {
120  item->removeStartConstraint( citem );
121  }
122  item = items.value( summaryHandlingModel->mapFromSource( c.endIndex() ), nullptr );
123  if ( item ) {
124  item->removeEndConstraint( citem );
125  }
126  constraintItems.removeAt(constraintItems.indexOf(citem));
127  delete citem;
128 }
129 
130 void GraphicsScene::Private::deleteConstraintItem( const Constraint& c )
131 {
132  deleteConstraintItem( findConstraintItem( c ) );
133 }
134 
135 ConstraintGraphicsItem* GraphicsScene::Private::findConstraintItem( const Constraint& c ) const
136 {
137  GraphicsItem* item = items.value( summaryHandlingModel->mapFromSource( c.startIndex() ), nullptr );
138  if ( item ) {
139  const QList<ConstraintGraphicsItem*> clst = item->startConstraints();
141  for ( ; it != clst.end() ; ++it ) {
142  if ( c.compareIndexes((*it)->constraint()) )
143  break;
144  }
145  if ( it != clst.end() ) {
146  return *it;
147  }
148  }
149  item = items.value( summaryHandlingModel->mapFromSource( c.endIndex() ), nullptr );
150  if ( item ) {
151  const QList<ConstraintGraphicsItem*> clst = item->endConstraints();
153  for ( ; it != clst.end() ; ++it ) {
154  if ( c.compareIndexes( (*it)->constraint() ) )
155  break;
156  }
157  if ( it != clst.end() ) {
158  return *it;
159  }
160  }
161  return nullptr;
162 }
163 
164 // NOTE: we might get here after indexes are invalidated, so cannot do any controlled cleanup
165 void GraphicsScene::Private::clearItems()
166 {
167  for(GraphicsItem *item : qAsConst(items)) {
168  q->removeItem(item);
169  delete item;
170  }
171  items.clear();
172  // do last to avoid cleaning up items
173  clearConstraintItems();
174 }
175 
176 AbstractGrid *GraphicsScene::Private::getGrid()
177 {
178  if (grid.isNull()) {
179  return static_cast<AbstractGrid*>(&default_grid);
180  }
181  return grid.data();
182 }
183 
184 const AbstractGrid *GraphicsScene::Private::getGrid() const
185 {
186  if (grid.isNull()) {
187  return static_cast<const AbstractGrid*>(&default_grid);
188  }
189  return grid.data();
190 }
191 
192 GraphicsScene::GraphicsScene( QObject* parent )
193  : QGraphicsScene( parent ), _d( new Private( this ) )
194 {
195  init();
196 }
197 
198 GraphicsScene::~GraphicsScene()
199 {
200  qDeleteAll( items() );
201  delete _d;
202 }
203 
204 #define d d_func()
205 
206 void GraphicsScene::init()
207 {
208  setItemIndexMethod( QGraphicsScene::NoIndex );
209  setConstraintModel( new ConstraintModel( this ) );
210  connect( d->getGrid(), SIGNAL(gridChanged()), this, SLOT(slotGridChanged()) );
211 }
212 
213 /* NOTE: The delegate should really be a property
214  * of the view, but that doesn't really fit at
215  * this time
216  */
217 void GraphicsScene::setItemDelegate( ItemDelegate* delegate )
218 {
219  if ( !d->itemDelegate.isNull() && d->itemDelegate->parent()==this ) delete d->itemDelegate;
220  d->itemDelegate = delegate;
221  update();
222 }
223 
224 ItemDelegate* GraphicsScene::itemDelegate() const
225 {
226  return d->itemDelegate;
227 }
228 
229 QAbstractItemModel* GraphicsScene::model() const
230 {
231  assert(!d->summaryHandlingModel.isNull());
232  return d->summaryHandlingModel->sourceModel();
233 }
234 
235 void GraphicsScene::setModel( QAbstractItemModel* model )
236 {
237  assert(!d->summaryHandlingModel.isNull());
238  d->summaryHandlingModel->setSourceModel(model);
239  d->getGrid()->setModel( d->summaryHandlingModel );
240  setSelectionModel( new QItemSelectionModel( model, this ) );
241 }
242 
243 QAbstractProxyModel* GraphicsScene::summaryHandlingModel() const
244 {
245  return d->summaryHandlingModel;
246 }
247 
248 void GraphicsScene::setSummaryHandlingModel( QAbstractProxyModel* proxyModel )
249 {
250  proxyModel->setSourceModel( model() );
251  d->summaryHandlingModel = proxyModel;
252 }
253 
254 void GraphicsScene::setRootIndex( const QModelIndex& idx )
255 {
256  d->getGrid()->setRootIndex( idx );
257 }
258 
259 QModelIndex GraphicsScene::rootIndex() const
260 {
261  return d->getGrid()->rootIndex();
262 }
263 
264 ConstraintModel* GraphicsScene::constraintModel() const
265 {
266  return d->constraintModel;
267 }
268 
269 void GraphicsScene::setConstraintModel( ConstraintModel* cm )
270 {
271  if ( !d->constraintModel.isNull() ) {
272  d->constraintModel->disconnect( this );
273  d->clearConstraintItems();
274  }
275  d->constraintModel = cm;
276 
277  connect( cm, SIGNAL(constraintAdded(KGantt::Constraint)),
278  this, SLOT(slotConstraintAdded(KGantt::Constraint)) );
279  connect( cm, SIGNAL(constraintRemoved(KGantt::Constraint)),
280  this, SLOT(slotConstraintRemoved(KGantt::Constraint)) );
281  d->resetConstraintItems();
282 }
283 
284 void GraphicsScene::setSelectionModel( QItemSelectionModel* smodel )
285 {
286  if (d->selectionModel) {
287  d->selectionModel->disconnect( this );
288  }
289  d->selectionModel = smodel;
290  if (smodel) {
291  connect(d->selectionModel, SIGNAL(modelChanged(QAbstractItemModel*)),
292  this, SLOT(selectionModelChanged(QAbstractItemModel*)));
293  connect( smodel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
294  this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection)) );
295  }
296 }
297 
298 QItemSelectionModel* GraphicsScene::selectionModel() const
299 {
300  return d->selectionModel;
301 }
302 
303 void GraphicsScene::setRowController( AbstractRowController* rc )
304 {
305  d->rowController = rc;
306 }
307 
308 AbstractRowController* GraphicsScene::rowController() const
309 {
310  return d->rowController;
311 }
312 
314 {
315  AbstractGrid *grid = d->grid;
316  grid->disconnect( this );
317  d->grid = nullptr;
318  if (grid) {
319  // revert to the default_grid
320  connect( &d->default_grid, SIGNAL(gridChanged()), this, SLOT(slotGridChanged()) );
321  }
322  return grid;
323 }
324 
326 {
327  QAbstractItemModel* model = nullptr;
328  if ( d->getGrid() ) {
329  d->getGrid()->disconnect( this );
330  model = d->getGrid()->model();
331  }
332  delete d->grid;
333  d->grid = grid;
334  connect( d->getGrid(), SIGNAL(gridChanged()), this, SLOT(slotGridChanged()) );
335  d->getGrid()->setModel( model );
336  slotGridChanged();
337 }
338 
339 // Returns the explicitly set grid
341 {
342  return d->grid;
343 }
344 
345 // May also return the default_grid if a grid has not been set
347 {
348  return d->getGrid();
349 }
350 
351 void GraphicsScene::setReadOnly( bool ro )
352 {
353  d->readOnly = ro;
354 }
355 
356 bool GraphicsScene::isReadOnly() const
357 {
358  return d->readOnly;
359 }
360 
361 /* Returns the index with column=0 fromt the
362  * same row as idx and with the same parent.
363  * This is used to traverse the tree-structure
364  * of the model
365  */
366 QModelIndex GraphicsScene::mainIndex( const QModelIndex& idx )
367 {
368 #if 0
369  if ( idx.isValid() ) {
370  return idx.model()->index( idx.row(), 0,idx.parent() );
371  } else {
372  return QModelIndex();
373  }
374 #else
375  return idx;
376 #endif
377 }
378 
379 
381 {
382 #if 0
383  if ( idx.isValid() ) {
384  const QAbstractItemModel* model = idx.model();
385  return model->index( idx.row(), model->columnCount( idx.parent() )-1,idx.parent() );
386  } else {
387  return QModelIndex();
388  }
389 #else
390  return idx;
391 #endif
392 }
393 
394 
396 {
397 #if 0
398  TODO For 3.0
399  assert(views().count() == 1);
400  GraphicsView *v = qobject_cast<GraphicsView*>(views().first());
401  assert(v);
402  return v->createItem(type);
403 #else
404  Q_UNUSED(type)
405  return new GraphicsItem;
406 #endif
407 }
408 
409 void GraphicsScene::Private::recursiveUpdateMultiItem( const Span& span, const QModelIndex& idx )
410 {
411  //qDebug() << "recursiveUpdateMultiItem("<<span<<idx<<")";
412  GraphicsItem* item = q->findItem( idx );
413  const int itemtype = summaryHandlingModel->data( idx, ItemTypeRole ).toInt();
414  if (!item) {
415  item = q->createItem( static_cast<ItemType>( itemtype ) );
416  item->setIndex( idx );
417  q->insertItem( idx, item);
418  }
419  item->updateItem( span, idx );
420  QModelIndex child;
421  int cr = 0;
422  while ( ( child = summaryHandlingModel->index( cr, 0, idx ) ).isValid() ) {
423  recursiveUpdateMultiItem( span, child );
424  ++cr;
425  }
426 }
427 
428 void GraphicsScene::updateRow( const QModelIndex& rowidx )
429 {
430  //qDebug() << "GraphicsScene::updateRow("<<rowidx<<")" << rowidx.data( Qt::DisplayRole );
431  if ( !rowidx.isValid() ) return;
432 #if !defined(NDEBUG)
433  const QAbstractItemModel* model = rowidx.model(); // why const?
434 #endif
435  assert( model );
436  assert( rowController() );
437  assert( model == summaryHandlingModel() );
438 
439  const QModelIndex sidx = summaryHandlingModel()->mapToSource( rowidx );
440  Span rg = rowController()->rowGeometry( sidx );
441  for ( QModelIndex treewalkidx = sidx; treewalkidx.isValid(); treewalkidx = treewalkidx.parent() ) {
442  if ( treewalkidx.data( ItemTypeRole ).toInt() == TypeMulti
443  && !rowController()->isRowExpanded( treewalkidx )) {
444  rg = rowController()->rowGeometry( treewalkidx );
445  }
446  }
447 
448  bool blocked = blockSignals( true );
449  for ( int col = 0; col < summaryHandlingModel()->columnCount( rowidx.parent() ); ++col ) {
450  const QModelIndex idx = summaryHandlingModel()->index( rowidx.row(), col, rowidx.parent() );
451  const QModelIndex sidx = summaryHandlingModel()->mapToSource( idx );
452  const int itemtype = summaryHandlingModel()->data( idx, ItemTypeRole ).toInt();
453  const bool isExpanded = rowController()->isRowExpanded( sidx );
454  if ( itemtype == TypeNone ) {
455  removeItem( idx );
456  continue;
457  }
458  if ( itemtype == TypeMulti && !isExpanded ) {
459  d->recursiveUpdateMultiItem( rg, idx );
460  } else {
461  if ( summaryHandlingModel()->data( rowidx.parent(), ItemTypeRole ).toInt() == TypeMulti && !isExpanded ) {
462  //continue;
463  }
464 
465  GraphicsItem* item = findItem( idx );
466  if (!item) {
467  item = createItem( static_cast<ItemType>( itemtype ) );
468  item->setIndex( idx );
469  insertItem(idx, item);
470  }
471  const Span span = rowController()->rowGeometry( sidx );
472  item->updateItem( span, idx );
473  }
474  }
475  blockSignals( blocked );
476 }
477 
478 void GraphicsScene::insertItem( const QPersistentModelIndex& idx, GraphicsItem* item )
479 {
480  if ( !d->constraintModel.isNull() ) {
481  // Create items for constraints
482  const QModelIndex sidx = summaryHandlingModel()->mapToSource( idx );
483  const QList<Constraint> clst = d->constraintModel->constraintsForIndex( sidx );
484  for ( const Constraint& c : clst ) {
485  QModelIndex other_idx;
486  if ( c.startIndex() == sidx ) {
487  other_idx = c.endIndex();
488  GraphicsItem* other_item = d->items.value(summaryHandlingModel()->mapFromSource( other_idx ),nullptr);
489  if ( !other_item ) continue;
491  item->addStartConstraint( citem );
492  other_item->addEndConstraint( citem );
493  d->constraintItems.append( citem );
494  addItem( citem );
495  } else if ( c.endIndex() == sidx ) {
496  other_idx = c.startIndex();
497  GraphicsItem* other_item = d->items.value(summaryHandlingModel()->mapFromSource( other_idx ),nullptr);
498  if ( !other_item ) continue;
500  other_item->addStartConstraint( citem );
501  item->addEndConstraint( citem );
502  d->constraintItems.append( citem );
503  addItem( citem );
504  } else {
505  assert( 0 ); // Impossible
506  }
507  }
508  }
509  d->items.insert( idx, item );
510  addItem( item );
511 }
512 
513 void GraphicsScene::removeItem( const QModelIndex& idx )
514 {
515  //qDebug() << "GraphicsScene::removeItem("<<idx<<")";
517  if ( it != d->items.end() ) {
518  GraphicsItem* item = *it;
519  assert( item );
520  // We have to remove the item from the list first because
521  // there is a good chance there will be reentrant calls
522  d->items.erase( it );
523  {
524  // Remove any constraintitems attached
525 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
526  // TODO remove when we depend on 5.14+
527  const QSet<ConstraintGraphicsItem*> clst = QSet<ConstraintGraphicsItem*>::fromList( item->startConstraints() ) +
528  QSet<ConstraintGraphicsItem*>::fromList( item->endConstraints() );
529 #else
530  const QList<ConstraintGraphicsItem*> lst1 = item->startConstraints();
531  const QList<ConstraintGraphicsItem*> lst2 = item->endConstraints();
533  QSet<ConstraintGraphicsItem*>( lst2.begin(), lst2.end() );
534 #endif
535  for ( ConstraintGraphicsItem* citem : clst ) {
536  d->deleteConstraintItem( citem );
537  }
538  }
539  // Get rid of the item
540  delete item;
541  }
542 }
543 
544 GraphicsItem* GraphicsScene::findItem( const QModelIndex& idx ) const
545 {
546  if ( !idx.isValid() ) return nullptr;
547  assert( idx.model() == summaryHandlingModel() );
549  return ( it != d->items.end() )?*it:nullptr;
550 }
551 
552 GraphicsItem* GraphicsScene::findItem( const QPersistentModelIndex& idx ) const
553 {
554  if ( !idx.isValid() ) return nullptr;
555  assert( idx.model() == summaryHandlingModel() );
557  return ( it != d->items.end() )?*it:nullptr;
558 }
559 
560 void GraphicsScene::clearItems()
561 {
562  d->clearItems();
563 }
564 
565 void GraphicsScene::updateItems()
566 {
567  for ( QHash<QPersistentModelIndex,GraphicsItem*>::iterator it = d->items.begin();
568  it != d->items.end(); ++it ) {
569  GraphicsItem* const item = it.value();
570  const QPersistentModelIndex& idx = it.key();
571  item->updateItem( Span( item->pos().y(), item->rect().height() ), idx );
572  }
573  invalidate( QRectF(), QGraphicsScene::BackgroundLayer );
574 }
575 
576 void GraphicsScene::deleteSubtree( const QModelIndex& _idx )
577 {
578  QModelIndex idx = dataIndex( _idx );
579  if ( !idx.model() ) return;
580  const QModelIndex parent( idx.parent() );
581  const int colcount = idx.model()->columnCount( parent );
582  {for ( int i = 0; i < colcount; ++i ) {
583  removeItem( summaryHandlingModel()->index(idx.row(), i, parent ) );
584  }}
585  const int rowcount = summaryHandlingModel()->rowCount( _idx );
586  {for ( int i = 0; i < rowcount; ++i ) {
587  deleteSubtree( summaryHandlingModel()->index( i, summaryHandlingModel()->columnCount(_idx)-1, _idx ) );
588  }}
589 }
590 
591 
592 ConstraintGraphicsItem* GraphicsScene::findConstraintItem( const Constraint& c ) const
593 {
594  return d->findConstraintItem( c );
595 }
596 
597 void GraphicsScene::slotConstraintAdded( const KGantt::Constraint& c )
598 {
599  d->createConstraintItem( c );
600 }
601 
602 void GraphicsScene::slotConstraintRemoved( const KGantt::Constraint& c )
603 {
604  d->deleteConstraintItem( c );
605 }
606 
607 void GraphicsScene::slotGridChanged()
608 {
609  updateItems();
610  update();
611  Q_EMIT gridChanged();
612 }
613 
614 void GraphicsScene::selectionModelChanged(QAbstractItemModel *model)
615 {
616  Q_UNUSED(model)
617 }
618 
619 void GraphicsScene::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
620 {
621  const auto desel = deselected.indexes();
622  for (const QModelIndex &idx : desel) {
623  GraphicsItem *item = findItem(idx.model() == d->summaryHandlingModel ? idx : d->summaryHandlingModel->mapFromSource(idx));
624  if (item) {
625  item->setSelected(false);
626  }
627  }
628  const auto sel = selected.indexes();
629  for (const QModelIndex &idx : sel) {
630  GraphicsItem *item = findItem(idx.model() == d->summaryHandlingModel ? idx : d->summaryHandlingModel->mapFromSource(idx));
631  if (item) {
632  item->setSelected(true);
633  }
634  }
635  update();
636 }
637 
638 void GraphicsScene::helpEvent( QGraphicsSceneHelpEvent *helpEvent )
639 {
640 #ifndef QT_NO_TOOLTIP
641  QGraphicsItem *item = itemAt( helpEvent->scenePos(), QTransform() );
642  if ( GraphicsItem* gitem = qgraphicsitem_cast<GraphicsItem*>( item ) ) {
643  QToolTip::showText(helpEvent->screenPos(), gitem->ganttToolTip());
644  } else if ( ConstraintGraphicsItem* citem = qgraphicsitem_cast<ConstraintGraphicsItem*>( item ) ) {
645  QToolTip::showText(helpEvent->screenPos(), citem->ganttToolTip());
646  } else {
647  QGraphicsScene::helpEvent( helpEvent );
648  }
649 #endif /* QT_NO_TOOLTIP */
650 }
651 
652 void GraphicsScene::drawBackground( QPainter* painter, const QRectF& _rect )
653 {
654  QRectF scn( sceneRect() );
655  QRectF rect( _rect );
656  if ( d->isPrinting && d->drawColumnLabels ) {
657  QRectF headerRect( scn.topLeft()+QPointF( d->labelsWidth, 0 ),
658  QSizeF( scn.width()-d->labelsWidth, d->rowController->headerHeight() ));
659 
660  d->getGrid()->paintHeader( painter, headerRect, rect, 0, nullptr );
661 
662 #if 0
663  /* We have to blank out the part of the header that is invisible during
664  * normal rendering when we are printing.
665  */
666  QRectF labelsTabRect( scn.topLeft(), QSizeF( d->labelsWidth, headerRect.height() ) );
667 
668  QStyleOptionHeader opt;
669  opt.rect = labelsTabRect.toRect();
670  opt.text = QLatin1String("");
671  opt.textAlignment = Qt::AlignCenter;
672  style()->drawControl(QStyle::CE_Header, &opt, painter, 0);
673 #endif
674 
675  scn.setTop( headerRect.bottom() );
676  scn.setLeft( headerRect.left() );
677  rect = rect.intersected( scn );
678  }
679  d->getGrid()->paintGrid( painter, scn, rect, d->rowController );
680 
681  d->getGrid()->drawBackground(painter, rect);
682 }
683 
684 void GraphicsScene::drawForeground( QPainter* painter, const QRectF& rect )
685 {
686  d->getGrid()->drawForeground(painter, rect);
687 }
688 
689 void GraphicsScene::itemEntered( const QModelIndex& idx )
690 {
691  Q_EMIT entered( idx );
692 }
693 
694 void GraphicsScene::itemPressed( const QModelIndex& idx, QGraphicsSceneMouseEvent *event )
695 {
696  if (event->button() == Qt::LeftButton) {
698  if (event->modifiers() & Qt::ControlModifier) {
700  } else {
702  }
703  d->selectionModel->select(d->summaryHandlingModel->mapToSource(idx), flags);
704  }
705  Q_EMIT pressed( idx );
706 }
707 
708 void GraphicsScene::itemClicked( const QModelIndex& idx )
709 {
710  Q_EMIT clicked( idx );
711 }
712 
713 void GraphicsScene::itemDoubleClicked( const QModelIndex& idx )
714 {
715  Q_EMIT qrealClicked( idx );
716 }
717 
718 void GraphicsScene::setDragSource( GraphicsItem* item )
719 {
720  d->dragSource = item;
721 }
722 
723 GraphicsItem* GraphicsScene::dragSource() const
724 {
725  return d->dragSource;
726 }
727 
728 
729 void GraphicsScene::print( QPrinter* printer, bool drawRowLabels, bool drawColumnLabels )
730 {
731 #ifndef HAVE_PRINTER
732  Q_UNUSED( printer );
733  Q_UNUSED( drawRowLabels );
734  Q_UNUSED( drawColumnLabels );
735 #else
736  QPainter painter( printer );
737  doPrint( &painter, printer->pageRect(), sceneRect().left(), sceneRect().right(), printer, drawRowLabels, drawColumnLabels );
738 #endif
739 }
740 
741 
742 void GraphicsScene::print( QPrinter* printer, qreal start, qreal end, bool drawRowLabels, bool drawColumnLabels )
743 {
744 #ifndef HAVE_PRINTER
745  Q_UNUSED( printer );
746  Q_UNUSED( start );
747  Q_UNUSED( end );
748  Q_UNUSED( drawRowLabels );
749  Q_UNUSED( drawColumnLabels );
750 #else
751  QPainter painter( printer );
752  doPrint( &painter, printer->pageRect(), start, end, printer, drawRowLabels, drawColumnLabels );
753 #endif
754 }
755 
756 
757 void GraphicsScene::print( QPainter* painter, const QRectF& _targetRect, bool drawRowLabels, bool drawColumnLabels )
758 {
759  QRectF targetRect( _targetRect );
760  if ( targetRect.isNull() ) {
761  targetRect = sceneRect();
762  }
763 
764  doPrint( painter, targetRect, sceneRect().left(), sceneRect().right(), nullptr, drawRowLabels, drawColumnLabels );
765 }
766 
767 
768 void GraphicsScene::print( QPainter* painter, qreal start, qreal end,
769  const QRectF& _targetRect, bool drawRowLabels, bool drawColumnLabels )
770 {
771  QRectF targetRect( _targetRect );
772  if ( targetRect.isNull() ) {
773  targetRect = sceneRect();
774  }
775 
776  doPrint( painter, targetRect, start, end, nullptr, drawRowLabels, drawColumnLabels );
777 }
778 
779 void GraphicsScene::printDiagram( QPrinter *printer, const PrintingContext &context )
780 {
781 #ifndef HAVE_PRINTER
782  Q_UNUSED( printer );
783  Q_UNUSED( context );
784 #else
785  PrintingContext ctx( context );
786  if (ctx.sceneRect().isNull()) {
787  ctx.setSceneRect(sceneRect());
788  }
789  QRectF targetRect = printer->pageRect( QPrinter::DevicePixel );
790  if ( printer->fullPage() ) {
791  // Handle margins
792  QPageLayout pl = printer->pageLayout();
793  targetRect = targetRect.marginsRemoved( pl.marginsPixels( printer->resolution() ) );
794  }
795  QPainter painter( printer );
796  doPrintScene( printer, &painter, targetRect, ctx );
797 #endif
798 }
799 
800 void GraphicsScene::doPrint( QPainter* painter, const QRectF& targetRect,
801  qreal start, qreal end,
802  QPrinter* printer, bool drawRowLabels, bool drawColumnLabels )
803 {
804  assert( painter );
805  PrintingContext ctx;
806  ctx.setFitting(PrintingContext::FitPageHeight); // keep old behavior (?)
807  ctx.setDrawRowLabels( drawRowLabels );
808  ctx.setDrawColumnLabels( drawColumnLabels );
809  ctx.setSceneRect( sceneRect() );
810  ctx.setLeft( start );
811  ctx.setRight( end );
812  doPrintScene( printer, painter, targetRect, ctx );
813 }
814 
815 void GraphicsScene::doPrintScene( QPrinter *printer, QPainter *painter, const QRectF &targetRect, const PrintingContext &context )
816 {
817  assert( painter );
818 
819  bool b = blockSignals( true );
820 
821  d->isPrinting = true;
822  d->drawColumnLabels = context.drawColumnLabels();
823  d->labelsWidth = 0.0;
824 
825  QFont sceneFont( font() );
826 #ifdef HAVE_PRINTER
827  if ( printer ) {
828  sceneFont = QFont( font(), printer );
829  if ( font().pointSizeF() >= 0.0 )
830  sceneFont.setPointSizeF( font().pointSizeF() );
831  else if ( font().pointSize() >= 0 )
832  sceneFont.setPointSize( font().pointSize() );
833  else
834  sceneFont.setPixelSize( font().pixelSize() );
835  }
836 #endif
837 
838  QGraphicsTextItem dummyTextItem( QLatin1String("X") );
839  dummyTextItem.adjustSize();
840  QFontMetrics fm(dummyTextItem.font());
841  sceneFont.setPixelSize( fm.height() );
842 
843  const QRectF oldScnRect( sceneRect() );
844  QRectF scnRect( oldScnRect );
845  QRectF sceneHeaderRect;
846  QRectF labelsHeaderRect;
847  QRectF labelsRect;
848 
849  /* column labels */
850  qreal headerHeight = 0.0;
851  if ( context.drawColumnLabels() ) {
852  headerHeight = d->rowController->headerHeight();
853  sceneHeaderRect = context.sceneRect();
854  sceneHeaderRect.setLeft( context.left() );
855  sceneHeaderRect.setTop( -headerHeight );
856  sceneHeaderRect.setHeight( headerHeight );
857  scnRect.setTop(scnRect.top() - headerHeight);
858  }
859 
860  /* row labels */
861  QVector<QGraphicsTextItem*> textLabels;
862  if ( context.drawRowLabels() ) {
863  qreal textWidth = 0.;
864  qreal charWidth = QFontMetricsF(sceneFont).boundingRect( QString::fromLatin1( "X" ) ).width();
865  QModelIndex sidx = summaryHandlingModel()->mapToSource( summaryHandlingModel()->index( 0, 0, rootIndex()) );
866  do {
867  QModelIndex idx = summaryHandlingModel()->mapFromSource( sidx );
868  const Span rg=rowController()->rowGeometry( sidx );
869  const QString txt = idx.data( Qt::DisplayRole ).toString();
870  QGraphicsTextItem* item = new QGraphicsTextItem( txt );
871  addItem( item );
872  textLabels << item;
873  item->setTextWidth( QFontMetricsF(sceneFont).boundingRect( txt ).width() + charWidth );
874  textWidth = qMax( item->textWidth(), textWidth );
875  item->setPos( 0, rg.start() );
876  } while ( ( sidx = rowController()->indexBelow( sidx ) ).isValid() );
877  d->labelsWidth = textWidth;
878  scnRect.setLeft( scnRect.left() - textWidth );
879  for( QGraphicsTextItem* item : qAsConst(textLabels) ) {
880  item->setPos( scnRect.left(), item->y() );
881  item->show();
882  }
883  if ( context.drawColumnLabels() ) {
884  labelsHeaderRect = sceneHeaderRect;
885  labelsHeaderRect.translate( -textWidth, 0.0 );
886  labelsHeaderRect.setWidth( textWidth );
887  }
888  labelsRect = QRectF( scnRect.left(), context.top(), textWidth, context.sceneRect().height() );
889  }
890  setSceneRect( scnRect );
891  scnRect.setRight( context.right() );
892 
893  // The scene looks like this:
894  // Labels Do not print Print Behind end
895  // 1 2 3 4
896  // !-------!---------------!------------!-----------
897  // sceneWidth is 1 to 2 + 3 to 4
898  qreal sceneWidth = d->labelsWidth + context.right() - context.left();
899  qreal sceneHeight = context.sceneRect().height() + sceneHeaderRect.height();
900  // qInfo()<<Q_FUNC_INFO<<targetRect<<scnRect<<sceneWidth;
901 
902  int horPages = 1;
903  int vertPages = 1;
904  qreal scaleFactor = targetRect.height() / scnRect.height(); // FitPageHeight (default)
905  if ( printer ) {
906  if ( context.fitting() & PrintingContext::NoFitting ) {
907  scaleFactor = printer->logicalDpiX() / views().at(0)->logicalDpiX(); // always have only one view
908  vertPages = qRound( ( sceneHeight * scaleFactor / targetRect.height() ) + 0.5 );
909  horPages = qRound( ( sceneWidth * scaleFactor / targetRect.width() ) + 0.5 );
910  } else if ( context.fitting() & PrintingContext::FitSinglePage ) {
911  scaleFactor = std::min( scaleFactor, targetRect.width() / sceneWidth );
912  } else /*FitPageHeight (default)*/ {
913  horPages = qRound( ( sceneWidth * scaleFactor / targetRect.width() ) + 0.5 );
914  }
915  } else {
916  // paint device has no pages so just fit inside the target
917  scaleFactor = std::min( scaleFactor, targetRect.width() / sceneWidth );
918  }
919  // qInfo()<<Q_FUNC_INFO<<"labels header:"<<labelsHeaderRect<<"labels:"<<labelsRect<<"scene header:"<<sceneHeaderRect<<"scene:"<<scnRect<<"scaleFactor:"<<scaleFactor;
920  painter->save();
921  painter->setFont( sceneFont );
922 
923  // qInfo()<<Q_FUNC_INFO<<'s'<<scaleFactor<<"pages="<<((sceneWidth * scaleFactor)/targetRect.width())<<'h'<<horPages<<'v'<<vertPages<<'s'<<scnRect<<'t'<<(targetRect.size()/scaleFactor);
924  qreal yPos = labelsRect.top();
925  for ( int vpage = 0; vpage < vertPages && yPos < context.bottom(); ++vpage ) {
926  // qInfo()<<Q_FUNC_INFO<<"print vertical page"<<vpage;
927  // Disable painting of noInformation during labels printing
928  // or else labels might be painted over
929  QBrush noInfoBrush;
930  DateTimeGrid *dateTimeGrid = qobject_cast<DateTimeGrid*>(grid());
931  if (dateTimeGrid) {
932  noInfoBrush = dateTimeGrid->noInformationBrush();
933  dateTimeGrid->setNoInformationBrush(QBrush());
934  }
935  int hpage = 0;
936  qreal targetLabelsOffset = 0.0;
937  qreal labelsOffsetX = 0.0;
938  while ( labelsOffsetX < labelsHeaderRect.width() ) {
939  // qInfo()<<Q_FUNC_INFO<<"print labels"<<"vert page:"<<vpage<<','<<hpage<<"yPos"<<yPos<<"label x:"<<labelsOffsetX;
940  // print labels, they might span multiple pages
941  QRectF target = targetRect;
942  target.setWidth(std::min(target.width(), (labelsHeaderRect.width() - labelsOffsetX) * scaleFactor) );
943  if ( vpage == 0 && headerHeight > 0.0 ) {
944  QRectF sourceHeader = labelsHeaderRect;
945  sourceHeader.translate( labelsOffsetX, 0.0 );
946  QRectF targetHeader = target;
947  targetHeader.setSize( sourceHeader.size() * scaleFactor );
948  drawLabelsHeader( painter, sourceHeader, targetHeader );
949  target.adjust( 0.0, targetHeader.height(), 0.0, 0.0 );
950  }
951  QRectF rect = labelsRect;
952  rect.setLeft( rect.left() + labelsOffsetX );
953  rect.setTop( yPos );
954  rect.setHeight( std::min(rect.height(), target.height() / scaleFactor ) );
955  painter->setClipRect(target);
956  // disable header, it has been drawn above
957  bool drawColumnLabels = d->drawColumnLabels;
958  d->drawColumnLabels = false;
959  // qInfo()<<Q_FUNC_INFO<<"print labels"<<"vert page:"<<vpage<<','<<hpage<<"scene rect:"<<rect<<"target:"<<target;
960  render( painter, target, rect );
961  d->drawColumnLabels = drawColumnLabels;
962  labelsOffsetX += rect.width();
963  if ( targetRect.right() <= target.right() ) {
964  // we have used the whole page
965  ++hpage;
966 #ifdef HAVE_PRINTER
967  if ( printer ) {
968  printer->newPage();
969  }
970 #endif
971  } else {
972  // labels might take part of the page
973  targetLabelsOffset = target.width();
974  // qInfo()<<Q_FUNC_INFO<<"print labels finished"<<"vert page:"<<vpage<<"hor page:"<<hpage<<"target offset:"<<targetLabelsOffset;
975  break;
976  }
977  }
978  if (dateTimeGrid) {
979  dateTimeGrid->setNoInformationBrush(noInfoBrush);
980  }
981  qreal xPos = context.left();
982  // qInfo()<<Q_FUNC_INFO<<"print diagram"<<"page:"<<vpage<<','<<hpage<<"xPos"<<xPos<<"yPos:"<<yPos;
983  for ( ; hpage < horPages && xPos < context.right(); ++hpage ) {
984  // Adjust for row labels (first time only)
985  QRectF target = targetRect.adjusted(targetLabelsOffset, 0., 0., 0.);
986  targetLabelsOffset = 0.0;
987  if (!sceneHeaderRect.isNull() && vpage == 0) {
988  // draw header
989  QRectF rect = sceneHeaderRect;
990  rect.setLeft( xPos );
991  QRectF targetHeader = target;
992  targetHeader.setHeight( rect.height() * scaleFactor );
993  rect.setWidth( std::min( rect.width(), target.width() / scaleFactor) );
994  // qInfo()<<Q_FUNC_INFO<<"scene header:"<<"page:"<<vpage<<','<<hpage<<"source:"<<rect<<"target:"<<targetHeader;
995  render( painter, targetHeader, rect );
996  target.adjust( 0.0, targetHeader.height(), 0.0, 0.0 );
997  }
998  QRectF rect = context.sceneRect();
999  rect.setLeft( xPos );
1000  rect.setTop( yPos );
1001  rect.setWidth( std::min( rect.width(), target.width() / scaleFactor) );
1002  rect.setHeight( std::min( rect.height(), target.height() / scaleFactor ) );
1003  target.setWidth( rect.width() * scaleFactor );
1004  painter->setClipRect( target );
1005  // disable header, it has been drawn above
1006  bool drawColumnLabels = d->drawColumnLabels;
1007  d->drawColumnLabels = false;
1008  // qInfo()<<Q_FUNC_INFO<<"scene:"<<"page:"<<vpage<<','<<hpage<<"source:"<<rect<<"target:"<<target;
1009  render( painter, target, rect );
1010  d->drawColumnLabels = drawColumnLabels;
1011 
1012  xPos += rect.width();
1013  // qInfo()<<Q_FUNC_INFO<<context<<"xPos:"<<xPos;
1014  if ( printer && xPos < context.right() ) {
1015 #ifdef HAVE_PRINTER
1016  printer->newPage();
1017 #endif
1018  } else {
1019  // qInfo()<<Q_FUNC_INFO<<"print horizontal finished if"<<xPos<<">="<<scnRect.right();
1020  break;
1021  }
1022  }
1023  yPos += targetRect.height() / scaleFactor;
1024  if ( vpage == 0 ) {
1025  yPos -= headerHeight;
1026  }
1027  // qInfo()<<Q_FUNC_INFO<<"yPos:"<<yPos<<"bottom:"<<context.bottom();
1028  if ( printer && yPos < context.bottom() ) {
1029 #ifdef HAVE_PRINTER
1030  // next vertical page
1031  printer->newPage();
1032 #endif
1033  }
1034  // qInfo()<<Q_FUNC_INFO<<"next vertical page if"<<yPos<<'<'<<scnRect.bottom();
1035  }
1036 
1037  d->isPrinting = false;
1038  d->drawColumnLabels = true;
1039  d->labelsWidth = 0.0;
1040  qDeleteAll( textLabels );
1041  blockSignals( b );
1042  setSceneRect( oldScnRect );
1043  painter->restore();
1044 }
1045 
1046 void GraphicsScene::drawLabelsHeader( QPainter *painter, const QRectF &sourceRect, const QRectF &targetRect )
1047 {
1048  // qInfo()<<Q_FUNC_INFO<<"header:"<<sourceRect<<targetRect;
1049  // TODO This should paint itemview header
1050  painter->setClipRect( targetRect );
1051  render( painter, targetRect, sourceRect );
1052 }
1053 
1054 #include "moc_kganttgraphicsscene.cpp"
1055 
1056 
1057 #ifndef KDAB_NO_UNIT_TESTS
1058 #include "unittest/test.h"
1059 
1060 #include <QGraphicsLineItem>
1061 #include <QPointer>
1062 #include <QStandardItemModel>
1063 
1064 #include "kganttgraphicsview.h"
1065 
1066 class SceneTestRowController : public KGantt::AbstractRowController {
1067 private:
1068  static const int ROW_HEIGHT;
1070 
1071 public:
1072  SceneTestRowController()
1073  {
1074  }
1075 
1076  void setModel( QAbstractItemModel* model )
1077  {
1078  m_model = model;
1079  }
1080 
1081  /*reimp*/int headerHeight() const override { return 40; }
1082 
1083  /*reimp*/ bool isRowVisible( const QModelIndex& ) const override { return true;}
1084  /*reimp*/ bool isRowExpanded( const QModelIndex& ) const override { return false; }
1085  /*reimp*/ KGantt::Span rowGeometry( const QModelIndex& idx ) const override
1086  {
1087  return KGantt::Span( idx.row() * ROW_HEIGHT, ROW_HEIGHT );
1088  }
1089  /*reimp*/ int maximumItemHeight() const override {
1090  return ROW_HEIGHT/2;
1091  }
1092  /*reimp*/int totalHeight() const override {
1093  return m_model->rowCount()* ROW_HEIGHT;
1094  }
1095 
1096  /*reimp*/ QModelIndex indexAt( int height ) const override {
1097  return m_model->index( height/ROW_HEIGHT, 0 );
1098  }
1099 
1100  /*reimp*/ QModelIndex indexBelow( const QModelIndex& idx ) const override {
1101  if ( !idx.isValid() )return QModelIndex();
1102  return idx.model()->index( idx.row()+1, idx.column(), idx.parent() );
1103  }
1104  /*reimp*/ QModelIndex indexAbove( const QModelIndex& idx ) const override {
1105  if ( !idx.isValid() )return QModelIndex();
1106  return idx.model()->index( idx.row()-1, idx.column(), idx.parent() );
1107  }
1108 
1109 };
1110 
1111 class TestLineItem : public QGraphicsLineItem
1112 {
1113 public:
1114  TestLineItem( bool *destroyedFlag )
1115  : QGraphicsLineItem( 0, 0, 10, 10 ), // geometry doesn't matter
1116  m_destroyedFlag( destroyedFlag )
1117  {}
1118 
1119  ~TestLineItem() override
1120  { *m_destroyedFlag = true; }
1121 
1122 private:
1123  bool *m_destroyedFlag;
1124 };
1125 
1126 const int SceneTestRowController::ROW_HEIGHT = 30;
1127 
1128 KDAB_SCOPED_UNITTEST_SIMPLE( KGantt, GraphicsView, "test" ) {
1129  QStandardItemModel model;
1130 
1131  QStandardItem* item = new QStandardItem();
1132  item->setData( KGantt::TypeTask, KGantt::ItemTypeRole );
1133  item->setData( QString::fromLatin1( "Decide on new product" ) );
1134  item->setData( QDateTime( QDate( 2007, 3, 1 ), QTime() ), KGantt::StartTimeRole );
1135  item->setData( QDateTime( QDate( 2007, 3, 3 ), QTime() ), KGantt::EndTimeRole );
1136 
1137  QStandardItem* item2 = new QStandardItem();
1138  item2->setData( KGantt::TypeTask, KGantt::ItemTypeRole );
1139  item2->setData( QString::fromLatin1( "Educate personnel" ) );
1140  item2->setData( QDateTime( QDate( 2007, 3, 3 ), QTime() ), KGantt::StartTimeRole );
1141  item2->setData( QDateTime( QDate( 2007, 3, 6 ), QTime() ), KGantt::EndTimeRole );
1142 
1143  model.appendRow( item );
1144  model.appendRow( item2 );
1145 
1146  SceneTestRowController rowController;
1147  rowController.setModel( &model );
1148 
1149  KGantt::GraphicsView graphicsView;
1150  graphicsView.setRowController( &rowController );
1151  graphicsView.setModel( &model );
1152 
1153  // Now the interesting stuff - the items above are just for a "realistic environment"
1154 
1155  bool foreignItemDestroyed = false;
1156  TestLineItem *foreignItem = new TestLineItem( &foreignItemDestroyed );
1157  graphicsView.scene()->addItem( foreignItem );
1158 
1159  assertFalse( foreignItemDestroyed );
1160  graphicsView.updateScene();
1161  assertFalse( foreignItemDestroyed );
1162 }
1163 #endif /* KDAB_NO_UNIT_TESTS */
QModelIndexList indexes() const const
void setSelected(bool selected)
The item type.
Definition: kganttglobal.h:217
QPoint screenPos() const const
qreal y() const const
ControlModifier
void setPointSize(int pointSize)
Scale diagram to fit on a single page.
void setNoInformationBrush(const QBrush &brush)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const =0
AbstractGrid * grid() const
QRect toRect() const const
Qt::KeyboardModifiers modifiers() const const
QPointF scenePos() const const
GraphicsItem * createItem(ItemType type) const
void setRight(qreal x)
void printDiagram(QPrinter *printer, const PrintingContext &context)
No scaling, print as many pages as needed.
Abstract baseclass for row controllers. A row controller is used by the GraphicsView to nagivate the ...
Start time (or other start value) for a gantt item.
Definition: kganttglobal.h:214
QSizeF size() const const
void save()
LeftButton
qreal top() const const
int resolution() const const
QRectF intersected(const QRectF &rectangle) const const
const QAbstractItemModel * model() const const
QGraphicsScene * scene() const const
QPageLayout pageLayout() const const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
void showText(const QPoint &pos, const QString &text, QWidget *w)
virtual void helpEvent(QGraphicsSceneHelpEvent *helpEvent)
qreal left() const const
void adjust(qreal dx1, qreal dy1, qreal dx2, qreal dy2)
void update(const QRectF &rect)
AlignCenter
void setLeft(qreal x)
virtual void setData(const QVariant &value, int role)
void setHeight(qreal height)
qreal bottom() const const
A class used to represent a dependency.
void setPixelSize(int pixelSize)
void setFitting(const Fitting &value)
bool isValid() const const
void setFont(const QFont &font)
QPointF pos() const const
bool isValid() const const
qreal y() const const
void print(QPrinter *printer, bool drawRowLabels=true, bool drawColumnLabels=true)
void translate(qreal dx, qreal dy)
QFont font() const const
int toInt(bool *ok) const const
QRectF boundingRect(const QString &text) const const
void setPos(const QPointF &pos)
int left() const const
Scale diagram height to fit one page.
DisplayRole
QPointF topLeft() const const
End time (or other end value) for a gantt item.
Definition: kganttglobal.h:215
int row() const const
virtual void setSourceModel(QAbstractItemModel *sourceModel)
QModelIndex endIndex() const
void setTextWidth(qreal width)
Qt::MouseButton button() const const
const AbstractGrid * getGrid() const
QGraphicsItem::GraphicsItemFlags flags() const const
Global namespace.
QModelIndex parent() const const
void setSceneRect(const QRectF &rect)
void setDrawColumnLabels(bool state)
int logicalDpiX() const const
QList::iterator end()
qreal right() const const
bool isNull() const const
QSet::iterator begin()
Abstract baseclass for grids. A grid is used to convert between QModelIndex&#39;es and gantt chart values...
static QModelIndex dataIndex(const QModelIndex &idx)
void setPointSizeF(qreal pointSize)
virtual bool newPage() override
void setGrid(AbstractGrid *grid)
Set the grid to grid.
void restore()
QMargins marginsPixels(int resolution) const const
The PrintingContext class provides options for printing the gantt chart.
QVariant data(int key) const const
QDateTime currentDateTime()
qreal width() const const
const QAbstractItemModel * model() const const
void setClipRect(const QRectF &rectangle, Qt::ClipOperation operation)
bool fullPage() const const
QVariant data(int role) const const
void setTop(qreal y)
void setWidth(qreal width)
QSet::iterator end()
void setModel(QAbstractItemModel *)
virtual int columnCount(const QModelIndex &parent) const const =0
QSet< T > fromList(const QList< T > &list)
int column() const const
QString fromLatin1(const char *str, int size)
QRectF adjusted(qreal dx1, qreal dy1, qreal dx2, qreal dy2) const const
qreal height() const const
void setSize(const QSizeF &size)
QModelIndex startIndex() const
QRect pageRect() const const
The GraphicsView class provides a model/view implementation of a gantt chart.
void setRowController(KGantt::AbstractRowController *)
void addItem(QGraphicsItem *item)
QString toString() const const
Class used to render gantt items in a KGantt::GraphicsView.
void appendRow(const QList< QStandardItem * > &items)
QList::iterator begin()
A class representing a start point and a length.
Definition: kganttglobal.h:240
QBrush noInformationBrush() const
Proxy model that supports summary gantt items.
QRectF marginsRemoved(const QMarginsF &margins) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Dec 5 2021 22:32:42 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.