KD Chart 2  [rev.2.5.1]
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Pages
KDChartAbstractDiagram.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2013 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 "KDChartAbstractDiagram.h"
24 #include "KDChartAbstractDiagram_p.h"
25 
26 #include <QPainter>
27 #include <QDebug>
28 #include <QApplication>
29 #include <QAbstractProxyModel>
30 #include <QSizeF>
31 
33 #include "KDChartChart.h"
35 #include "KDChartTextAttributes.h"
39 #include "KDChartPainterSaver_p.h"
40 
41 #include <KDABLibFakes>
42 
43 #include <limits>
44 
45 using namespace KDChart;
46 
47 #define d d_func()
48 
50  : QAbstractItemView ( parent ), _d( new Private() )
51 {
52  _d->init( plane );
53  init();
54 }
55 
57 {
58  emit aboutToBeDestroyed();
59  delete _d;
60 }
61 
62 void AbstractDiagram::init()
63 {
64  _d->diagram = this;
65  d->reverseMapper.setDiagram( this );
66 }
67 
68 
69 bool AbstractDiagram::compare( const AbstractDiagram* other ) const
70 {
71  if ( other == this ) return true;
72  if ( !other ) {
73  return false;
74  }
75  return // compare QAbstractScrollArea properties
76  (horizontalScrollBarPolicy() == other->horizontalScrollBarPolicy()) &&
77  (verticalScrollBarPolicy() == other->verticalScrollBarPolicy()) &&
78  // compare QFrame properties
79  (frameShadow() == other->frameShadow()) &&
80  (frameShape() == other->frameShape()) &&
81 // frameWidth is a read-only property defined by the style, it should not be in here:
82  // (frameWidth() == other->frameWidth()) &&
83  (lineWidth() == other->lineWidth()) &&
84  (midLineWidth() == other->midLineWidth()) &&
85  // compare QAbstractItemView properties
86  (alternatingRowColors() == other->alternatingRowColors()) &&
87  (hasAutoScroll() == other->hasAutoScroll()) &&
88 #if QT_VERSION > 0x040199
89  (dragDropMode() == other->dragDropMode()) &&
90  (dragDropOverwriteMode() == other->dragDropOverwriteMode()) &&
91  (horizontalScrollMode() == other->horizontalScrollMode ()) &&
92  (verticalScrollMode() == other->verticalScrollMode()) &&
93 #endif
94  (dragEnabled() == other->dragEnabled()) &&
95  (editTriggers() == other->editTriggers()) &&
96  (iconSize() == other->iconSize()) &&
97  (selectionBehavior() == other->selectionBehavior()) &&
98  (selectionMode() == other->selectionMode()) &&
99  (showDropIndicator() == other->showDropIndicator()) &&
100  (tabKeyNavigation() == other->tabKeyNavigation()) &&
101  (textElideMode() == other->textElideMode()) &&
102  // compare all of the properties stored in the attributes model
103  attributesModel()->compare( other->attributesModel() ) &&
104  // compare own properties
105  (rootIndex().column() == other->rootIndex().column()) &&
106  (rootIndex().row() == other->rootIndex().row()) &&
108  (antiAliasing() == other->antiAliasing()) &&
109  (percentMode() == other->percentMode()) &&
110  (datasetDimension() == other->datasetDimension());
111 }
112 
114 {
115  return d->plane;
116 }
117 
119 {
120  if ( d->databoundariesDirty ) {
121  d->databoundaries = calculateDataBoundaries ();
122  d->databoundariesDirty = false;
123  }
124  return d->databoundaries;
125 }
126 
128 {
129  d->databoundariesDirty = true;
130  update();
131 }
132 
133 void AbstractDiagram::setModel( QAbstractItemModel * newModel )
134 {
135  if ( model() )
136  {
137  disconnect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
138  disconnect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
139  disconnect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
140  disconnect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
141  disconnect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
142  disconnect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
143  disconnect( model(), SIGNAL( dataChanged(QModelIndex,QModelIndex) ), this, SIGNAL( modelDataChanged() ));
144  }
145  QAbstractItemView::setModel( newModel );
146  AttributesModel* amodel = new PrivateAttributesModel( newModel, this );
147  amodel->initFrom( d->attributesModel );
148  d->setAttributesModel(amodel);
149  scheduleDelayedItemsLayout();
151  if ( model() )
152  {
153  connect( model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
154  connect( model(), SIGNAL( columnsInserted( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
155  connect( model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
156  connect( model(), SIGNAL( columnsRemoved( QModelIndex, int, int ) ), this, SLOT( setDataBoundariesDirty() ) );
157  connect( model(), SIGNAL( modelReset() ), this, SLOT( setDataBoundariesDirty() ) );
158  connect( model(), SIGNAL( layoutChanged() ), this, SLOT( setDataBoundariesDirty() ) );
159  connect( model(), SIGNAL( dataChanged(QModelIndex,QModelIndex) ), this, SIGNAL( modelDataChanged() ));
160  }
161  emit modelsChanged();
162 }
163 
164 void AbstractDiagram::setSelectionModel( QItemSelectionModel* newSelectionModel )
165 {
166  if ( selectionModel() )
167  {
168  disconnect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
169  disconnect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
170  }
171  QAbstractItemView::setSelectionModel( newSelectionModel );
172  if ( selectionModel() )
173  {
174  connect( selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SIGNAL( modelsChanged() ) );
175  connect( selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SIGNAL( modelsChanged() ) );
176  }
177  emit modelsChanged();
178 }
179 
188 {
189  if ( amodel->sourceModel() != model() ) {
190  qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
191  "Trying to set an attributesmodel which works on a different "
192  "model than the diagram.");
193  return;
194  }
195  if ( qobject_cast<PrivateAttributesModel*>(amodel) ) {
196  qWarning("KDChart::AbstractDiagram::setAttributesModel() failed: "
197  "Trying to set an attributesmodel that is private to another diagram.");
198  return;
199  }
200  d->setAttributesModel(amodel);
201  scheduleDelayedItemsLayout();
203  emit modelsChanged();
204 }
205 
207 {
208  return d->usesExternalAttributesModel();
209 }
210 
212 {
213  return d->attributesModel;
214 }
215 
216 QModelIndex AbstractDiagram::conditionallyMapFromSource( const QModelIndex & index ) const
217 {
218  Q_ASSERT( !index.isValid() || index.model() == attributesModel() || index.model() == attributesModel()->sourceModel() );
219  return index.model() == attributesModel() ? index : attributesModel()->mapFromSource( index );
220 }
221 
223 void AbstractDiagram::setRootIndex ( const QModelIndex& idx )
224 {
225  QAbstractItemView::setRootIndex( idx );
226  setAttributesModelRootIndex( d->attributesModel->mapFromSource( idx ) );
227 }
228 
230 void AbstractDiagram::setAttributesModelRootIndex( const QModelIndex& idx )
231 {
232  d->attributesModelRootIndex = idx;
234  scheduleDelayedItemsLayout();
235 }
236 
240 {
241  if ( !d->attributesModelRootIndex.isValid() )
242  d->attributesModelRootIndex = d->attributesModel->mapFromSource( rootIndex() );
243  return d->attributesModelRootIndex;
244 }
245 
247 {
248  d->plane = parent;
249 }
250 
252 {
253  if ( d->plane ) {
254  d->plane->layoutDiagrams();
255  update();
256  }
257  QAbstractItemView::doItemsLayout();
258 }
259 
260 #if QT_VERSION < 0x050000
261 void AbstractDiagram::dataChanged( const QModelIndex &topLeft,
262  const QModelIndex &bottomRight )
263 #else
264 void AbstractDiagram::dataChanged( const QModelIndex &topLeft,
265  const QModelIndex &bottomRight,
266  const QVector<int> & )
267 #endif
268 {
269  Q_UNUSED( topLeft );
270  Q_UNUSED( bottomRight );
271  // We are still too dumb to do intelligent updates...
272  setDataBoundariesDirty();
273  scheduleDelayedItemsLayout();
274 }
275 
276 
277 void AbstractDiagram::setHidden( const QModelIndex & index, bool hidden )
278 {
279  d->attributesModel->setData(
280  conditionallyMapFromSource( index ),
281  qVariantFromValue( hidden ),
282  DataHiddenRole );
283  emit dataHidden();
284 }
285 
286 void AbstractDiagram::setHidden( int dataset, bool hidden )
287 {
288  d->setDatasetAttrs( dataset, qVariantFromValue( hidden ), DataHiddenRole );
289  emit dataHidden();
290 }
291 
292 void AbstractDiagram::setHidden( bool hidden )
293 {
294  d->attributesModel->setModelData( qVariantFromValue( hidden ), DataHiddenRole );
295  emit dataHidden();
296 }
297 
299 {
300  return attributesModel()->modelData( DataHiddenRole ).value< bool >();
301 }
302 
303 bool AbstractDiagram::isHidden( int dataset ) const
304 {
305  const QVariant boolFlag( d->datasetAttrs( dataset, DataHiddenRole ) );
306  if ( boolFlag.isValid() )
307  return boolFlag.value< bool >();
308  return isHidden();
309 }
310 
311 bool AbstractDiagram::isHidden( const QModelIndex & index ) const
312 {
313  const QVariant boolFlag( attributesModel()->data( conditionallyMapFromSource( index ),
314  DataHiddenRole ) );
315  if ( boolFlag.isValid() ) {
316  return boolFlag.value< bool >();
317  }
318  int dataset = index.column() / d->datasetDimension;
319  return isHidden( dataset );
320 }
321 
322 
323 void AbstractDiagram::setDataValueAttributes( const QModelIndex & index,
324  const DataValueAttributes & a )
325 {
326  d->attributesModel->setData( conditionallyMapFromSource( index ), qVariantFromValue( a ),
328  emit propertiesChanged();
329 }
330 
331 
333 {
334  d->setDatasetAttrs( dataset, qVariantFromValue( a ), DataValueLabelAttributesRole );
335  emit propertiesChanged();
336 }
337 
339 {
341 }
342 
344 {
345  /*
346  The following did not work!
347  (khz, 2008-01-25)
348  If there was some attrs specified for the 0-th cells of a dataset,
349  then this logic would return the cell's settings instead of the header settings:
350 
351  return qVariantValue<DataValueAttributes>(
352  attributesModel()->data( attributesModel()->mapFromSource(columnToIndex( column )),
353  KDChart::DataValueLabelAttributesRole ) );
354  */
355 
356  const QVariant headerAttrs(
357  d->datasetAttrs( dataset, KDChart::DataValueLabelAttributesRole ) );
358  if ( headerAttrs.isValid() )
359  return headerAttrs.value< DataValueAttributes >();
360  return dataValueAttributes();
361 }
362 
364 {
365  return attributesModel()->data(
366  conditionallyMapFromSource( index ),
368 }
369 
371 {
372  d->attributesModel->setModelData( qVariantFromValue( a ), DataValueLabelAttributesRole );
373  emit propertiesChanged();
374 }
375 
377 {
379  attrs.setShowOverlappingDataLabels( allow );
380  setDataValueAttributes( attrs );
381  d->allowOverlappingDataValueTexts = allow;
382  emit propertiesChanged();
383 }
384 
386 {
387  return d->allowOverlappingDataValueTexts;
388 }
389 
391 {
392  d->antiAliasing = enabled;
393  emit propertiesChanged();
394 }
395 
397 {
398  return d->antiAliasing;
399 }
400 
401 void AbstractDiagram::setPercentMode ( bool percent )
402 {
403  d->percent = percent;
404  emit propertiesChanged();
405 }
406 
408 {
409  return d->percent;
410 }
411 
412 
413 void AbstractDiagram::paintDataValueText( QPainter* painter,
414  const QModelIndex& index,
415  const QPointF& pos,
416  qreal value )
417 {
418  d->paintDataValueText( painter, index, pos, value );
419 }
420 
421 
422 void AbstractDiagram::paintDataValueTexts( QPainter* painter )
423 {
424  if ( !checkInvariants() ) {
425  return;
426  }
427 
428  d->forgetAlreadyPaintedDataValues();
429  const int rowCount = model()->rowCount( rootIndex() );
430  const int columnCount = model()->columnCount( rootIndex() );
431  for ( int column = 0; column < columnCount; column += datasetDimension() ) {
432  for ( int row = 0; row < rowCount; ++row ) {
433  QModelIndex index = model()->index( row, column, rootIndex() ); // checked
434  qreal x;
435  qreal y;
436  if ( datasetDimension() == 1 ) {
437  x = row;
438  y = index.data().toReal();
439  } else {
440  x = index.data().toReal();
441  y = model()->index( row, column + 1, rootIndex() ).data().toReal();
442  }
443  paintDataValueText( painter, index, coordinatePlane()->translate( QPointF( x, y ) ), y );
444  }
445  }
446 }
447 
448 
449 void AbstractDiagram::paintMarker( QPainter* painter,
450  const DataValueAttributes& a,
451  const QModelIndex& index,
452  const QPointF& pos )
453 {
454  if ( !checkInvariants() || !a.isVisible() ) return;
455  const MarkerAttributes ma = a.markerAttributes();
456  if ( !ma.isVisible() ) return;
457 
458  const PainterSaver painterSaver( painter );
459  // the size of the marker - unscaled
460  const QSizeF maSize( ma.markerSize().width() / painter->matrix().m11(),
461  ma.markerSize().height() / painter->matrix().m22() );
462  QBrush indexBrush( brush( index ) );
463  QPen indexPen( ma.pen() );
464  if ( ma.markerColor().isValid() )
465  indexBrush.setColor( ma.markerColor() );
466 
467  paintMarker( painter, ma, indexBrush, indexPen, pos, maSize );
468 
469  // workaround: BC cannot be changed, otherwise we would pass the
470  // index down to next-lower paintMarker function. So far, we
471  // basically save a circle of radius maSize at pos in the
472  // reverseMapper. This means that ^^^ this version of paintMarker
473  // needs to be called to reverse-map the marker.
474  d->reverseMapper.addCircle( index.row(), index.column(), pos, 2 * maSize );
475 }
476 
477 void AbstractDiagram::paintMarker( QPainter* painter,
478  const QModelIndex& index,
479  const QPointF& pos )
480 {
481  if ( !checkInvariants() ) return;
482  paintMarker( painter, dataValueAttributes( index ), index, pos );
483 }
484 
485 void AbstractDiagram::paintMarker( QPainter* painter,
486  const MarkerAttributes& markerAttributes,
487  const QBrush& brush,
488  const QPen& pen,
489  const QPointF& pos,
490  const QSizeF& maSize )
491 {
492  const QPen oldPen( painter->pen() );
493  // Pen is used to paint 4Pixels - 1 Pixel - Ring and FastCross types.
494  // make sure to use the brush color - see above in those cases.
495  const bool isFourPixels = (markerAttributes.markerStyle() == MarkerAttributes::Marker4Pixels);
496  if ( isFourPixels || (markerAttributes.markerStyle() == MarkerAttributes::Marker1Pixel) ) {
497  // for high-performance point charts with tiny point markers:
498  painter->setPen( PrintingParameters::scalePen( QPen( brush.color().light() ) ) );
499  if ( isFourPixels ) {
500  const qreal x = pos.x();
501  const qreal y = pos.y();
502  painter->drawLine( QPointF(x-1.0,y-1.0),
503  QPointF(x+1.0,y-1.0) );
504  painter->drawLine( QPointF(x-1.0,y),
505  QPointF(x+1.0,y) );
506  painter->drawLine( QPointF(x-1.0,y+1.0),
507  QPointF(x+1.0,y+1.0) );
508  }
509  painter->drawPoint( pos );
510  } else {
511  const PainterSaver painterSaver( painter );
512  QPen painterPen( pen );
513  painter->setPen( PrintingParameters::scalePen( painterPen ) );
514  painter->setBrush( brush );
515  painter->setRenderHint ( QPainter::Antialiasing );
516  painter->translate( pos );
517  switch ( markerAttributes.markerStyle() ) {
519  {
520  if ( markerAttributes.threeD() ) {
521  QRadialGradient grad;
522  grad.setCoordinateMode( QGradient::ObjectBoundingMode );
523  QColor drawColor = brush.color();
524  grad.setCenter( 0.5, 0.5 );
525  grad.setRadius( 1.0 );
526  grad.setFocalPoint( 0.35, 0.35 );
527  grad.setColorAt( 0.00, drawColor.lighter( 150 ) );
528  grad.setColorAt( 0.20, drawColor );
529  grad.setColorAt( 0.50, drawColor.darker( 150 ) );
530  grad.setColorAt( 0.75, drawColor.darker( 200 ) );
531  grad.setColorAt( 0.95, drawColor.darker( 250 ) );
532  grad.setColorAt( 1.00, drawColor.darker( 200 ) );
533  QBrush newBrush( grad );
534  newBrush.setMatrix( brush.matrix() );
535  painter->setBrush( newBrush );
536  }
537  painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
538  maSize.height(), maSize.width()) );
539  }
540  break;
542  {
543  QRectF rect( 0 - maSize.width()/2, 0 - maSize.height()/2,
544  maSize.width(), maSize.height() );
545  painter->drawRect( rect );
546  break;
547  }
549  {
550  QVector <QPointF > diamondPoints;
551  QPointF top, left, bottom, right;
552  top = QPointF( 0, 0 - maSize.height()/2 );
553  left = QPointF( 0 - maSize.width()/2, 0 );
554  bottom = QPointF( 0, maSize.height()/2 );
555  right = QPointF( maSize.width()/2, 0 );
556  diamondPoints << top << left << bottom << right;
557  painter->drawPolygon( diamondPoints );
558  break;
559  }
560  // both handled on top of the method:
563  break;
565  {
566  painter->setBrush( Qt::NoBrush );
567  painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
568  painter->drawEllipse( QRectF( 0 - maSize.height()/2, 0 - maSize.width()/2,
569  maSize.height(), maSize.width()) );
570  break;
571  }
573  {
574  // Note: Markers can have outline,
575  // so just drawing two rects is NOT the solution here!
576  const qreal w02 = maSize.width() * 0.2;
577  const qreal w05 = maSize.width() * 0.5;
578  const qreal h02 = maSize.height()* 0.2;
579  const qreal h05 = maSize.height()* 0.5;
580  QVector <QPointF > crossPoints;
581  QPointF p[12];
582  p[ 0] = QPointF( -w02, -h05 );
583  p[ 1] = QPointF( w02, -h05 );
584  p[ 2] = QPointF( w02, -h02 );
585  p[ 3] = QPointF( w05, -h02 );
586  p[ 4] = QPointF( w05, h02 );
587  p[ 5] = QPointF( w02, h02 );
588  p[ 6] = QPointF( w02, h05 );
589  p[ 7] = QPointF( -w02, h05 );
590  p[ 8] = QPointF( -w02, h02 );
591  p[ 9] = QPointF( -w05, h02 );
592  p[10] = QPointF( -w05, -h02 );
593  p[11] = QPointF( -w02, -h02 );
594  for ( int i=0; i<12; ++i )
595  crossPoints << p[i];
596  crossPoints << p[0];
597  painter->drawPolygon( crossPoints );
598  break;
599  }
601  {
602  QPointF left, right, top, bottom;
603  left = QPointF( -maSize.width()/2, 0 );
604  right = QPointF( maSize.width()/2, 0 );
605  top = QPointF( 0, -maSize.height()/2 );
606  bottom= QPointF( 0, maSize.height()/2 );
607  painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
608  painter->drawLine( left, right );
609  painter->drawLine( top, bottom );
610  break;
611  }
613  break;
615  {
616  QPainterPath path = markerAttributes.customMarkerPath();
617  const QRectF pathBoundingRect = path.boundingRect();
618  const qreal xScaling = maSize.height() / pathBoundingRect.height();
619  const qreal yScaling = maSize.width() / pathBoundingRect.width();
620  const qreal scaling = qMin( xScaling, yScaling );
621  painter->scale( scaling, scaling );
622  painter->setPen( PrintingParameters::scalePen( QPen( brush.color() ) ) );
623  painter->drawPath(path);
624  break;
625  }
626  default:
627  Q_ASSERT_X ( false, "paintMarkers()",
628  "Type item does not match a defined Marker Type." );
629  }
630  }
631  painter->setPen( oldPen );
632 }
633 
634 void AbstractDiagram::paintMarkers( QPainter* painter )
635 {
636  if ( !checkInvariants() ) {
637  return;
638  }
639 
640  const int rowCount = model()->rowCount( rootIndex() );
641  const int columnCount = model()->columnCount( rootIndex() );
642  for ( int column = 0; column < columnCount; column += datasetDimension() ) {
643  for ( int row = 0; row < rowCount; ++row ) {
644  QModelIndex index = model()->index( row, column, rootIndex() ); // checked
645  qreal x;
646  qreal y;
647  if ( datasetDimension() == 1 ) {
648  x = row;
649  y = index.data().toReal();
650  } else {
651  x = index.data().toReal();
652  y = model()->index( row, column + 1, rootIndex() ).data().toReal();
653  }
654  paintMarker( painter, index, coordinatePlane()->translate( QPointF( x, y ) ) );
655  }
656  }
657 }
658 
659 
660 void AbstractDiagram::setPen( const QModelIndex& index, const QPen& pen )
661 {
663  conditionallyMapFromSource( index ),
664  qVariantFromValue( pen ), DatasetPenRole );
665  emit propertiesChanged();
666 }
667 
668 void AbstractDiagram::setPen( const QPen& pen )
669 {
671  qVariantFromValue( pen ), DatasetPenRole );
672  emit propertiesChanged();
673 }
674 
675 void AbstractDiagram::setPen( int dataset, const QPen& pen )
676 {
677  d->setDatasetAttrs( dataset, qVariantFromValue( pen ), DatasetPenRole );
678  emit propertiesChanged();
679 }
680 
682 {
683  return attributesModel()->data( DatasetPenRole ).value< QPen >();
684 }
685 
686 QPen AbstractDiagram::pen( int dataset ) const
687 {
688  const QVariant penSettings( d->datasetAttrs( dataset, DatasetPenRole ) );
689  if ( penSettings.isValid() )
690  return penSettings.value< QPen >();
691  return pen();
692 }
693 
694 QPen AbstractDiagram::pen( const QModelIndex& index ) const
695 {
696  return attributesModel()->data(
697  conditionallyMapFromSource( index ),
698  DatasetPenRole ).value< QPen >();
699 }
700 
701 void AbstractDiagram::setBrush( const QModelIndex& index, const QBrush& brush )
702 {
704  conditionallyMapFromSource( index ),
705  qVariantFromValue( brush ), DatasetBrushRole );
706  emit propertiesChanged();
707 }
708 
709 void AbstractDiagram::setBrush( const QBrush& brush )
710 {
712  qVariantFromValue( brush ), DatasetBrushRole );
713  emit propertiesChanged();
714 }
715 
716 void AbstractDiagram::setBrush( int dataset, const QBrush& brush )
717 {
718  d->setDatasetAttrs( dataset, qVariantFromValue( brush ), DatasetBrushRole );
719  emit propertiesChanged();
720 }
721 
723 {
724  return attributesModel()->data( DatasetBrushRole ).value< QBrush >();
725 }
726 
727 QBrush AbstractDiagram::brush( int dataset ) const
728 {
729  const QVariant brushSettings( d->datasetAttrs( dataset, DatasetBrushRole ) );
730  if ( brushSettings.isValid() )
731  return brushSettings.value< QBrush >();
732  return brush();
733 }
734 
735 QBrush AbstractDiagram::brush( const QModelIndex& index ) const
736 {
737  return
738  attributesModel()->data( conditionallyMapFromSource( index ), DatasetBrushRole ).value< QBrush >();
739 }
740 
747 void AbstractDiagram::setUnitPrefix( const QString& prefix, int column, Qt::Orientation orientation )
748 {
749  d->unitPrefixMap[ column ][ orientation ]= prefix;
750 }
751 
757 void AbstractDiagram::setUnitPrefix( const QString& prefix, Qt::Orientation orientation )
758 {
759  d->unitPrefix[ orientation ] = prefix;
760 }
761 
768 void AbstractDiagram::setUnitSuffix( const QString& suffix, int column, Qt::Orientation orientation )
769 {
770  d->unitSuffixMap[ column ][ orientation ]= suffix;
771 }
772 
778 void AbstractDiagram::setUnitSuffix( const QString& suffix, Qt::Orientation orientation )
779 {
780  d->unitSuffix[ orientation ] = suffix;
781 }
782 
790 QString AbstractDiagram::unitPrefix( int column, Qt::Orientation orientation, bool fallback ) const
791 {
792  if ( !fallback || d->unitPrefixMap[ column ].contains( orientation ) )
793  return d->unitPrefixMap[ column ][ orientation ];
794  return d->unitPrefix[ orientation ];
795 }
796 
801 QString AbstractDiagram::unitPrefix( Qt::Orientation orientation ) const
802 {
803  return d->unitPrefix[ orientation ];
804 }
805 
813 QString AbstractDiagram::unitSuffix( int column, Qt::Orientation orientation, bool fallback ) const
814 {
815  if ( !fallback || d->unitSuffixMap[ column ].contains( orientation ) )
816  return d->unitSuffixMap[ column ][ orientation ];
817  return d->unitSuffix[ orientation ];
818 }
819 
824 QString AbstractDiagram::unitSuffix( Qt::Orientation orientation ) const
825 {
826  return d->unitSuffix[ orientation ];
827 }
828 
829 // implement QAbstractItemView:
830 QRect AbstractDiagram::visualRect( const QModelIndex &index ) const
831 {
832  return d->reverseMapper.boundingRect( index.row(), index.column() ).toRect();
833 }
834 
835 void AbstractDiagram::scrollTo(const QModelIndex &, ScrollHint )
836 {}
837 
838 // indexAt ... down below
839 
840 QModelIndex AbstractDiagram::moveCursor(CursorAction, Qt::KeyboardModifiers )
841 { return QModelIndex(); }
842 
844 { return 0; }
845 
847 { return 0; }
848 
849 bool AbstractDiagram::isIndexHidden(const QModelIndex &) const
850 { return true; }
851 
852 void AbstractDiagram::setSelection(const QRect& rect , QItemSelectionModel::SelectionFlags command )
853 {
854  const QModelIndexList indexes = d->indexesIn( rect );
855  QItemSelection selection;
856  KDAB_FOREACH( const QModelIndex& index, indexes )
857  {
858  selection.append( QItemSelectionRange( index ) );
859  }
860  selectionModel()->select( selection, command );
861 }
862 
863 QRegion AbstractDiagram::visualRegionForSelection(const QItemSelection &selection) const
864 {
865  QPolygonF polygon;
866  KDAB_FOREACH( const QModelIndex& index, selection.indexes() )
867  {
868  polygon << d->reverseMapper.polygon(index.row(), index.column());
869  }
870  return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
871 }
872 
873 QRegion AbstractDiagram::visualRegion(const QModelIndex &index) const
874 {
875  QPolygonF polygon = d->reverseMapper.polygon(index.row(), index.column());
876  return polygon.isEmpty() ? QRegion() : QRegion( polygon.toPolygon() );
877 }
878 
880 {
881  d->attributesModel->setPaletteType( AttributesModel::PaletteTypeDefault );
882 }
883 
885 {
886  d->attributesModel->setPaletteType( AttributesModel::PaletteTypeSubdued );
887 }
888 
890 {
891  d->attributesModel->setPaletteType( AttributesModel::PaletteTypeRainbow );
892 }
893 
895 {
896  QStringList ret;
897  if ( model() ) {
898  //qDebug() << "AbstractDiagram::itemRowLabels(): " << attributesModel()->rowCount(attributesModelRootIndex()) << "entries";
899  const int rowCount = attributesModel()->rowCount(attributesModelRootIndex());
900  for ( int i = 0; i < rowCount; ++i ) {
901  //qDebug() << "item row label: " << attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString();
902  ret << unitPrefix( i, Qt::Horizontal, true ) +
903  attributesModel()->headerData( i, Qt::Vertical, Qt::DisplayRole ).toString() +
904  unitSuffix( i, Qt::Horizontal, true );
905  }
906  }
907  return ret;
908 }
909 
911 {
912  QStringList ret;
913  if ( !model() ) {
914  return ret;
915  }
916  const int datasetCount = d->datasetCount();
917  for ( int i = 0; i < datasetCount; ++i ) {
918  ret << d->datasetAttrs( i, Qt::DisplayRole ).toString();
919  }
920  return ret;
921 }
922 
924 {
925  QList<QBrush> ret;
926  if ( !model() ) {
927  return ret;
928  }
929  const int datasetCount = d->datasetCount();
930  for ( int i = 0; i < datasetCount; ++i ) {
931  ret << brush( i );
932  }
933  return ret;
934 }
935 
937 {
938  QList<QPen> ret;
939  if ( !model() ) {
940  return ret;
941  }
942  const int datasetCount = d->datasetCount();
943  for ( int i = 0; i < datasetCount; ++i ) {
944  ret << pen( i );
945  }
946  return ret;
947 }
948 
950 {
952  if ( !model() ) {
953  return ret;
954  }
955  const int datasetCount = d->datasetCount();
956  for ( int i = 0; i < datasetCount; ++i ) {
958  }
959  return ret;
960 }
961 
962 bool AbstractDiagram::checkInvariants( bool justReturnTheStatus ) const
963 {
964  if ( ! justReturnTheStatus ) {
965  Q_ASSERT_X ( model(), "AbstractDiagram::checkInvariants()",
966  "There is no usable model set, for the diagram." );
967 
968  Q_ASSERT_X ( coordinatePlane(), "AbstractDiagram::checkInvariants()",
969  "There is no usable coordinate plane set, for the diagram." );
970  }
971  return model() && coordinatePlane();
972 }
973 
975 {
976  return d->datasetDimension;
977 }
978 
980 {
981  Q_UNUSED( dimension );
982  qDebug() << "Setting the dataset dimension using AbstractDiagram::setDatasetDimension is "
983  "obsolete. Use the specific diagram types instead.";
984 }
985 
987 {
988  Q_ASSERT( dimension != 0 );
989  if ( d->datasetDimension == dimension ) {
990  return;
991  }
992  d->datasetDimension = dimension;
993  d->attributesModel->setDatasetDimension( dimension );
995  emit layoutChanged( this );
996 }
997 
998 qreal AbstractDiagram::valueForCell( int row, int column ) const
999 {
1000  if ( !d->attributesModel->hasIndex( row, column, attributesModelRootIndex() ) ) {
1001  qWarning() << "AbstractDiagram::valueForCell(): Requesting value for invalid index!";
1002  return std::numeric_limits<qreal>::quiet_NaN();
1003  }
1004  return d->attributesModel->data(
1005  d->attributesModel->index( row, column, attributesModelRootIndex() ) ).toReal(); // checked
1006 }
1007 
1009 {
1010  if ( d->plane ) {
1011  d->plane->update();
1012  }
1013 }
1014 
1015 QModelIndex AbstractDiagram::indexAt( const QPoint& point ) const
1016 {
1017  return d->indexAt( point );
1018 }
1019 
1020 QModelIndexList AbstractDiagram::indexesAt( const QPoint& point ) const
1021 {
1022  return d->indexesAt( point );
1023 }
1024 
1025 QModelIndexList AbstractDiagram::indexesIn( const QRect& rect ) const
1026 {
1027  return d->indexesIn( rect );
1028 }

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