24 #include "KDChartChart_p.h"
28 #include <QGridLayout>
33 #include <QPaintEvent>
34 #include <QLayoutItem>
35 #include <QPushButton>
36 #include <QApplication>
47 #include "KDChartPainterSaver_p.h"
53 #include "../evaldialog/evaldialog.h"
56 #include <KDABLibFakes>
59 { Qt::AlignTop | Qt::AlignLeft, Qt::AlignTop | Qt::AlignHCenter, Qt::AlignTop | Qt::AlignRight },
60 { Qt::AlignVCenter | Qt::AlignLeft, Qt::AlignVCenter | Qt::AlignHCenter, Qt::AlignVCenter | Qt::AlignRight },
61 { Qt::AlignBottom | Qt::AlignLeft, Qt::AlignBottom | Qt::AlignHCenter, Qt::AlignBottom | Qt::AlignRight }
85 default: *row = -1; *column = -1;
91 class MyWidgetItem :
public QWidgetItem
94 explicit MyWidgetItem(
QWidget *w, Qt::Alignment alignment = 0)
97 setAlignment( alignment );
101 bool isEmpty()
const {
102 QWidget* w =
const_cast< MyWidgetItem *
>( this )->widget();
106 return w->isHidden() && w->testAttribute( Qt::WA_WState_ExplicitShowHide );
110 using namespace KDChart;
112 void Chart::Private::slotUnregisterDestroyedLegend(
Legend *l )
114 chart->takeLegend( l );
117 void Chart::Private::slotUnregisterDestroyedHeaderFooter(
HeaderFooter* hf )
119 chart->takeHeaderFooter( hf );
124 coordinatePlanes.removeAll( plane );
133 Chart::Private::Private(
Chart* chart_ )
135 , useNewLayoutSystem( false )
141 , dataAndLegendLayout( 0 )
142 , leftOuterSpacer( 0 )
143 , rightOuterSpacer( 0 )
144 , topOuterSpacer( 0 )
145 , bottomOuterSpacer( 0 )
146 , isFloatingLegendsLayoutDirty( true )
147 , isPlanesLayoutDirty( true )
148 , globalLeadingLeft( 0 )
149 , globalLeadingRight( 0 )
150 , globalLeadingTop( 0 )
151 , globalLeadingBottom( 0 )
153 for (
int row = 0; row < 3; ++row ) {
154 for (
int column = 0; column < 3; ++column ) {
155 for (
int i = 0; i < 2; i++ ) {
156 innerHdFtLayouts[ i ][ row ][ column ] = 0;
162 Chart::Private::~Private()
167 struct ConnectedComponentsComparator{
168 bool operator()(
const LayoutGraphNode *lhs,
const LayoutGraphNode *rhs )
const
170 return lhs->priority < rhs->priority;
177 QHash< LayoutGraphNode*, VisitorState > visitedComponents;
178 Q_FOREACH ( LayoutGraphNode* node, nodeList )
179 visitedComponents[ node ] =
Unknown;
180 for (
int i = 0; i < nodeList.size(); ++i )
182 LayoutGraphNode *curNode = nodeList[ i ];
183 LayoutGraphNode *representativeNode = curNode;
184 if ( visitedComponents[ curNode ] !=
Visited )
186 QStack< LayoutGraphNode* > stack;
187 stack.push( curNode );
188 while ( !stack.isEmpty() )
190 curNode = stack.pop();
191 Q_ASSERT( visitedComponents[ curNode ] !=
Visited );
192 visitedComponents[ curNode ] =
Visited;
193 if ( curNode->bottomSuccesor && visitedComponents[ curNode->bottomSuccesor ] !=
Visited )
194 stack.push( curNode->bottomSuccesor );
195 if ( curNode->leftSuccesor && visitedComponents[ curNode->leftSuccesor ] !=
Visited )
196 stack.push( curNode->leftSuccesor );
197 if ( curNode->sharedSuccesor && visitedComponents[ curNode->sharedSuccesor ] !=
Visited )
198 stack.push( curNode->sharedSuccesor );
199 if ( curNode->priority < representativeNode->priority )
200 representativeNode = curNode;
202 connectedComponents.append( representativeNode );
205 std::sort( connectedComponents.begin(), connectedComponents.end(), ConnectedComponentsComparator() );
206 return connectedComponents;
209 struct PriorityComparator{
211 PriorityComparator( QHash< AbstractCoordinatePlane*, LayoutGraphNode* > mapping )
212 : m_mapping( mapping )
216 const LayoutGraphNode *lhsNode = m_mapping[ lhs ];
218 const LayoutGraphNode *rhsNode = m_mapping[ rhs ];
220 return lhsNode->priority < rhsNode->priority;
223 const QHash< AbstractCoordinatePlane*, LayoutGraphNode* > m_mapping;
228 if ( node && node->diagramPlane && node->diagramPlane->diagram() )
237 case( CartesianAxis::Top ):
238 node->topAxesLayout =
true;
240 case( CartesianAxis::Bottom ):
241 node->bottomAxesLayout =
true;
243 case( CartesianAxis::Left ):
244 node->leftAxesLayout =
true;
246 case( CartesianAxis::Right ):
247 node->rightAxesLayout =
true;
257 lhs->topAxesLayout |= rhs->topAxesLayout;
258 rhs->topAxesLayout = lhs->topAxesLayout;
260 lhs->bottomAxesLayout |= rhs->bottomAxesLayout;
261 rhs->bottomAxesLayout = lhs->bottomAxesLayout;
263 lhs->leftAxesLayout |= rhs->leftAxesLayout;
264 rhs->leftAxesLayout = lhs->leftAxesLayout;
266 lhs->rightAxesLayout |= rhs->rightAxesLayout;
267 rhs->rightAxesLayout = lhs->rightAxesLayout;
272 Chart::Private::AxisType type,
275 if ( !plane || !plane->
diagram() )
286 if ( ( type == Chart::Private::Ordinate &&
287 ( axis->
position() == CartesianAxis::Left || axis->
position() == CartesianAxis::Right ) )
289 ( type == Chart::Private::Abscissa &&
290 ( axis->
position() == CartesianAxis::Top || axis->
position() == CartesianAxis::Bottom ) ) ) {
304 if ( curSearchedAxis == curAxis )
306 result.append( curPlane );
307 if ( !sharedAxes->contains( curSearchedAxis ) )
308 sharedAxes->append( curSearchedAxis );
325 QHash< AbstractCoordinatePlane*, LayoutGraphNode* > planeNodeMapping;
332 allNodes.append(
new LayoutGraphNode );
333 allNodes[ allNodes.size() - 1 ]->diagramPlane = curPlane;
334 allNodes[ allNodes.size() - 1 ]->priority = allNodes.size();
336 planeNodeMapping[ curPlane ] = allNodes[ allNodes.size() - 1 ];
340 Q_FOREACH( LayoutGraphNode* curNode, allNodes )
344 Q_ASSERT( sharedAxes.size() < 2 );
346 if ( sharedAxes.size() == 1 && xSharedPlanes.size() > 1 )
350 for (
int i = 0; i < xSharedPlanes.size() - 1; ++i )
352 LayoutGraphNode *tmpNode = planeNodeMapping[ xSharedPlanes[ i ] ];
354 LayoutGraphNode *tmpNode2 = planeNodeMapping[ xSharedPlanes[ i + 1 ] ];
355 Q_ASSERT( tmpNode2 );
356 tmpNode->bottomSuccesor = tmpNode2;
368 LayoutGraphNode axisInfoNode;
369 for (
int count = 0; count < 2; ++count )
371 for (
int i = 0; i < xSharedPlanes.size(); ++i )
379 Q_ASSERT( sharedAxes.size() < 2 );
380 if ( sharedAxes.size() == 1 && ySharedPlanes.size() > 1 )
384 for (
int i = 0; i < ySharedPlanes.size() - 1; ++i )
386 LayoutGraphNode *tmpNode = planeNodeMapping[ ySharedPlanes[ i ] ];
388 LayoutGraphNode *tmpNode2 = planeNodeMapping[ ySharedPlanes[ i + 1 ] ];
389 Q_ASSERT( tmpNode2 );
390 tmpNode->leftSuccesor = tmpNode2;
402 LayoutGraphNode axisInfoNode;
403 for (
int count = 0; count < 2; ++count )
405 for (
int i = 0; i < ySharedPlanes.size(); ++i )
412 if ( curNode->diagramPlane->referenceCoordinatePlane() )
413 curNode->sharedSuccesor = planeNodeMapping[ curNode->diagramPlane->referenceCoordinatePlane() ];
419 QHash<AbstractCoordinatePlane*, PlaneInfo> Chart::Private::buildPlaneLayoutInfos()
433 QHash<CartesianAxis*, AxisInfo> axisInfos;
434 QHash<AbstractCoordinatePlane*, PlaneInfo> planeInfos;
439 planeInfos.insert( plane, p );
449 if ( !axisInfos.contains( axis ) ) {
456 axisInfos.insert( axis, i );
458 AxisInfo i = axisInfos[axis];
459 if ( i.plane == plane ) {
466 PlaneInfo pi = planeInfos[plane];
468 if ( !pi.referencePlane ) {
470 pi.referencePlane = i.plane;
471 if ( axis->
position() == CartesianAxis::Left ||
472 axis->
position() == CartesianAxis::Right ) {
473 pi.horizontalOffset += 1;
475 planeInfos[plane] = pi;
477 pi = planeInfos[i.plane];
478 if ( axis->
position() == CartesianAxis::Top ||
479 axis->
position() == CartesianAxis::Bottom ) {
480 pi.verticalOffset += 1;
483 planeInfos[i.plane] = pi;
489 p = planeInfos[plane];
490 if ( p.referencePlane == 0 ) {
491 p.gridLayout =
new QGridLayout();
492 p.gridLayout->setMargin( 0 );
493 planeInfos[plane] = p;
499 void Chart::Private::slotLayoutPlanes()
502 const QBoxLayout::Direction oldPlanesDirection = planesLayout ? planesLayout->direction()
503 : QBoxLayout::TopToBottom;
504 if ( planesLayout && dataAndLegendLayout )
505 dataAndLegendLayout->removeItem( planesLayout );
507 const bool hadPlanesLayout = planesLayout != 0;
508 int left, top, right, bottom;
509 if ( hadPlanesLayout )
510 planesLayout->getContentsMargins(&left, &top, &right, &bottom);
517 if ( dynamic_cast< KDChart::AutoSpacerLayoutItem* >( plane ) )
521 planeLayoutItems.clear();
525 planesLayout =
new QBoxLayout( oldPlanesDirection );
527 isPlanesLayoutDirty =
true;
529 if ( useNewLayoutSystem )
531 gridPlaneLayout =
new QGridLayout;
532 planesLayout->addLayout( gridPlaneLayout );
535 planesLayout->setContentsMargins(left, top, right, bottom);
536 planesLayout->setObjectName( QString::fromLatin1(
"planesLayout" ) );
548 QHash< CartesianAxis*, bool > layoutedAxes;
549 for (
int i = 0; i < connectedComponents.size(); ++i )
551 LayoutGraphNode *curComponent = connectedComponents[ i ];
552 for ( LayoutGraphNode *curRowComponent = curComponent; curRowComponent; curRowComponent = curRowComponent->bottomSuccesor )
555 for ( LayoutGraphNode *curColComponent = curRowComponent; curColComponent; curColComponent = curColComponent->leftSuccesor )
557 Q_ASSERT( curColComponent->diagramPlane->diagrams().size() == 1 );
558 Q_FOREACH(
AbstractDiagram* diagram, curColComponent->diagramPlane->diagrams() )
560 const int planeRowOffset = 1;
561 const int planeColOffset = 1;
565 planeLayoutItems << curColComponent->diagramPlane;
569 gridPlaneLayout->addItem( curColComponent->diagramPlane, row + planeRowOffset, col + planeColOffset, 2, 2 );
570 curColComponent->diagramPlane->setParentLayout( gridPlaneLayout );
571 QHBoxLayout *leftLayout = 0;
572 QHBoxLayout *rightLayout = 0;
573 QVBoxLayout *topLayout = 0;
574 QVBoxLayout *bottomLayout = 0;
575 if ( curComponent->sharedSuccesor )
577 gridPlaneLayout->addItem( curColComponent->sharedSuccesor->diagramPlane, row + planeRowOffset, col + planeColOffset, 2, 2 );
578 curColComponent->sharedSuccesor->diagramPlane->setParentLayout( gridPlaneLayout );
579 planeLayoutItems << curColComponent->sharedSuccesor->diagramPlane;
585 if ( curColComponent->bottomSuccesor )
588 if ( layoutedAxes.contains( axis ) )
594 case( CartesianAxis::Top ):
596 topLayout =
new QVBoxLayout;
597 topLayout->addItem( axis );
600 case( CartesianAxis::Bottom ):
602 bottomLayout =
new QVBoxLayout;
603 bottomLayout->addItem( axis );
606 case( CartesianAxis::Left ):
608 leftLayout =
new QHBoxLayout;
609 leftLayout->addItem( axis );
612 case( CartesianAxis::Right ):
615 rightLayout =
new QHBoxLayout;
617 rightLayout->addItem( axis );
621 planeLayoutItems << axis;
622 layoutedAxes[ axis ] =
true;
625 gridPlaneLayout->addLayout( leftLayout, row + planeRowOffset, col, 2, 1 );
627 gridPlaneLayout->addLayout( rightLayout, row, col + planeColOffset + 2, 2, 1 );
629 gridPlaneLayout->addLayout( topLayout, row, col + planeColOffset, 1, 2 );
631 gridPlaneLayout->addLayout( bottomLayout, row + planeRowOffset + 2, col + planeColOffset, 1, 2 );
635 gridPlaneLayout->addItem( curColComponent->diagramPlane, row, col, 4, 4 );
638 col += planeColOffset + 2 + ( 1 );
643 const int rowOffset = axisOffset + 2;
655 if ( dataAndLegendLayout ) {
656 dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
657 dataAndLegendLayout->setRowStretch( 1, 1000 );
658 dataAndLegendLayout->setColumnStretch( 1, 1000 );
661 #ifdef NEW_LAYOUT_DEBUG
662 for (
int i = 0; i < gridPlaneLayout->rowCount(); ++i )
664 for (
int j = 0; j < gridPlaneLayout->columnCount(); ++j )
666 if ( gridPlaneLayout->itemAtPosition( i, j ) )
667 qDebug() << Q_FUNC_INFO <<
"item at" << i << j << gridPlaneLayout->itemAtPosition( i, j )->geometry();
669 qDebug() << Q_FUNC_INFO <<
"item at" << i << j <<
"no item present";
675 if ( hadPlanesLayout ) {
676 planesLayout->setContentsMargins( left, top, right, bottom );
679 planesLayout->setMargin( 0 );
680 planesLayout->setSpacing( 0 );
681 planesLayout->setObjectName( QString::fromLatin1(
"planesLayout" ) );
686 QHash<AbstractCoordinatePlane*, PlaneInfo> planeInfos = buildPlaneLayoutInfos();
687 QHash<AbstractAxis*, AxisInfo> axisInfos;
689 Q_ASSERT( planeInfos.contains(plane) );
690 PlaneInfo& pi = planeInfos[ plane ];
691 const int column = pi.horizontalOffset;
692 const int row = pi.verticalOffset;
694 QGridLayout *planeLayout = pi.gridLayout;
696 if ( !planeLayout ) {
697 PlaneInfo& refPi = pi;
700 while ( !planeLayout && refPi.referencePlane ) {
701 refPi = planeInfos[refPi.referencePlane];
702 planeLayout = refPi.gridLayout;
704 Q_ASSERT_X( planeLayout,
705 "Chart::Private::slotLayoutPlanes()",
706 "Invalid reference plane. Please check that the reference plane has been added to the Chart." );
708 planesLayout->addLayout( planeLayout );
714 planeLayoutItems << plane;
716 planeLayout->addItem( plane, row, column, 1, 1, 0 );
718 planeLayout->setRowStretch( row, 2 );
719 planeLayout->setColumnStretch( column, 2 );
728 if ( pi.referencePlane != 0 )
730 pi.topAxesLayout = planeInfos[ pi.referencePlane ].topAxesLayout;
731 pi.bottomAxesLayout = planeInfos[ pi.referencePlane ].bottomAxesLayout;
732 pi.leftAxesLayout = planeInfos[ pi.referencePlane ].leftAxesLayout;
733 pi.rightAxesLayout = planeInfos[ pi.referencePlane ].rightAxesLayout;
737 if ( pi.topAxesLayout == 0 )
739 pi.topAxesLayout =
new QVBoxLayout;
740 pi.topAxesLayout->setMargin( 0 );
741 pi.topAxesLayout->setObjectName( QString::fromLatin1(
"topAxesLayout" ) );
743 if ( pi.bottomAxesLayout == 0 )
745 pi.bottomAxesLayout =
new QVBoxLayout;
746 pi.bottomAxesLayout->setMargin( 0 );
747 pi.bottomAxesLayout->setObjectName( QString::fromLatin1(
"bottomAxesLayout" ) );
749 if ( pi.leftAxesLayout == 0 )
751 pi.leftAxesLayout =
new QHBoxLayout;
752 pi.leftAxesLayout->setMargin( 0 );
753 pi.leftAxesLayout->setObjectName( QString::fromLatin1(
"leftAxesLayout" ) );
755 if ( pi.rightAxesLayout == 0 )
757 pi.rightAxesLayout =
new QHBoxLayout;
758 pi.rightAxesLayout->setMargin( 0 );
759 pi.rightAxesLayout->setObjectName( QString::fromLatin1(
"rightAxesLayout" ) );
762 if ( pi.referencePlane != 0 )
764 planeInfos[ pi.referencePlane ].topAxesLayout = pi.topAxesLayout;
765 planeInfos[ pi.referencePlane ].bottomAxesLayout = pi.bottomAxesLayout;
766 planeInfos[ pi.referencePlane ].leftAxesLayout = pi.leftAxesLayout;
767 planeInfos[ pi.referencePlane ].rightAxesLayout = pi.rightAxesLayout;
772 if ( axisInfos.contains( axis ) ) {
778 planeLayoutItems << axis;
780 switch ( axis->position() ) {
781 case CartesianAxis::Top:
783 pi.topAxesLayout->addItem( axis );
785 case CartesianAxis::Bottom:
786 axis->setParentLayout( pi.bottomAxesLayout );
787 pi.bottomAxesLayout->addItem( axis );
789 case CartesianAxis::Left:
790 axis->setParentLayout( pi.leftAxesLayout );
791 pi.leftAxesLayout->addItem( axis );
793 case CartesianAxis::Right:
794 axis->setParentLayout( pi.rightAxesLayout );
795 pi.rightAxesLayout->addItem( axis );
798 Q_ASSERT_X(
false,
"Chart::paintEvent",
"unknown axis position" );
801 axisInfos.insert( axis, AxisInfo() );
808 if ( !pi.topAxesLayout->parent() ) {
809 planeLayout->addLayout( pi.topAxesLayout, row - 1, column );
811 if ( !pi.bottomAxesLayout->parent() ) {
812 planeLayout->addLayout( pi.bottomAxesLayout, row + 1, column );
814 if ( !pi.leftAxesLayout->parent() ) {
815 planeLayout->addLayout( pi.leftAxesLayout, row, column - 1 );
817 if ( !pi.rightAxesLayout->parent() ) {
818 planeLayout->addLayout( pi.rightAxesLayout,row, column + 1 );
823 #define ADD_AUTO_SPACER_IF_NEEDED( \
824 spacerRow, spacerColumn, hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout ) \
826 if ( hLayout || vLayout ) { \
827 AutoSpacerLayoutItem * spacer \
828 = new AutoSpacerLayoutItem( hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout ); \
829 planeLayout->addItem( spacer, spacerRow, spacerColumn, 1, 1 ); \
830 spacer->setParentLayout( planeLayout ); \
831 planeLayoutItems << spacer; \
835 if ( plane->isCornerSpacersEnabled() ) {
837 ADD_AUTO_SPACER_IF_NEEDED( row + 1, column - 1, true, pi.leftAxesLayout, false, pi.bottomAxesLayout )
838 ADD_AUTO_SPACER_IF_NEEDED( row - 1, column + 1, false, pi.rightAxesLayout, true, pi.topAxesLayout )
839 ADD_AUTO_SPACER_IF_NEEDED( row + 1, column + 1, true, pi.rightAxesLayout, true, pi.bottomAxesLayout )
843 if ( dataAndLegendLayout ) {
844 dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
845 dataAndLegendLayout->setRowStretch( 1, 1000 );
846 dataAndLegendLayout->setColumnStretch( 1, 1000 );
853 void Chart::Private::createLayouts()
856 layout =
new QHBoxLayout( chart );
857 layout->setMargin( 0 );
858 layout->setObjectName( QString::fromLatin1(
"Chart::Private::layout" ) );
859 layout->addSpacing( globalLeadingLeft );
860 leftOuterSpacer = layout->itemAt( layout->count() - 1 )->spacerItem();
864 vLayout =
new QVBoxLayout();
865 vLayout->setMargin( 0 );
866 vLayout->setObjectName( QString::fromLatin1(
"vLayout" ) );
868 layout->addLayout( vLayout, 1000 );
869 layout->addSpacing( globalLeadingRight );
870 rightOuterSpacer = layout->itemAt( layout->count() - 1 )->spacerItem();
873 vLayout->addSpacing( globalLeadingTop );
874 topOuterSpacer = vLayout->itemAt( vLayout->count() - 1 )->spacerItem();
876 headerLayout =
new QGridLayout();
877 headerLayout->setMargin( 0 );
878 vLayout->addLayout( headerLayout );
880 dataAndLegendLayout =
new QGridLayout();
881 dataAndLegendLayout->setMargin( 0 );
882 dataAndLegendLayout->setObjectName( QString::fromLatin1(
"dataAndLegendLayout" ) );
883 vLayout->addLayout( dataAndLegendLayout, 1000 );
885 footerLayout =
new QGridLayout();
886 footerLayout->setMargin( 0 );
887 footerLayout->setObjectName( QString::fromLatin1(
"footerLayout" ) );
888 vLayout->addLayout( footerLayout );
894 for (
int row = 0; row < 3; ++row ) {
895 for (
int column = 0; column < 3; ++ column ) {
897 for (
int headOrFoot = 0; headOrFoot < 2; headOrFoot++ ) {
898 QVBoxLayout* innerLayout =
new QVBoxLayout();
899 innerLayout->setMargin( 0 );
900 innerLayout->setAlignment( align );
901 innerHdFtLayouts[ headOrFoot ][ row ][ column ] = innerLayout;
903 QGridLayout* outerLayout = headOrFoot == 0 ? headerLayout : footerLayout;
904 outerLayout->addLayout( innerLayout, row, column, align );
910 vLayout->addSpacing( globalLeadingBottom );
911 bottomOuterSpacer = vLayout->itemAt( vLayout->count() - 1 )->spacerItem();
914 dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
915 dataAndLegendLayout->setRowStretch( 1, 1 );
916 dataAndLegendLayout->setColumnStretch( 1, 1 );
919 void Chart::Private::slotResizePlanes()
921 if ( !dataAndLegendLayout ) {
924 if ( !overrideSize.isValid() ) {
937 void Chart::Private::updateDirtyLayouts()
939 if ( isPlanesLayoutDirty ) {
946 if ( isPlanesLayoutDirty || isFloatingLegendsLayoutDirty ) {
947 chart->reLayoutFloatingLegends();
949 isPlanesLayoutDirty =
false;
950 isFloatingLegendsLayoutDirty =
false;
953 void Chart::Private::reapplyInternalLayouts()
955 QRect geo = layout->geometry();
956 layout->invalidate();
957 layout->setGeometry( geo );
961 void Chart::Private::paintAll( QPainter* painter )
963 updateDirtyLayouts();
965 QRect rect( QPoint( 0, 0 ), overrideSize.isValid() ? overrideSize : chart->size() );
974 chart->reLayoutFloatingLegends();
977 planeLayoutItem->
paintAll( *painter );
980 textLayoutItem->
paintAll( *painter );
982 KDAB_FOREACH(
Legend *legend, legends ) {
983 const bool hidden = legend->isHidden() && legend->testAttribute( Qt::WA_WState_ExplicitShowHide );
997 , _d( new Private( this ) )
999 #if defined KDAB_EVAL
1000 EvalDialog::checkEvalLicense(
"KD Chart" );
1006 frameAttrs.
setPen( QPen( Qt::black ) );
1022 d->frameAttributes = a;
1027 return d->frameAttributes;
1032 d->backgroundAttributes = a;
1037 return d->backgroundAttributes;
1043 delete d->planesLayout;
1044 d->planesLayout = qobject_cast<QBoxLayout*>( layout );
1045 d->slotLayoutPlanes();
1050 return d->planesLayout;
1055 if (
d->coordinatePlanes.isEmpty() ) {
1056 qWarning() <<
"Chart::coordinatePlane: warning: no coordinate plane defined.";
1059 return d->coordinatePlanes.first();
1065 return d->coordinatePlanes;
1076 if ( index < 0 || index >
d->coordinatePlanes.count() ) {
1082 connect( plane, SIGNAL( needUpdate() ),
this, SLOT( update() ) );
1083 connect( plane, SIGNAL( needRelayout() ),
d, SLOT( slotResizePlanes() ) ) ;
1084 connect( plane, SIGNAL( needLayoutPlanes() ),
d, SLOT( slotLayoutPlanes() ) ) ;
1086 d->coordinatePlanes.insert( index, plane );
1088 d->slotLayoutPlanes();
1094 if ( plane && oldPlane_ != plane ) {
1096 if (
d->coordinatePlanes.count() ) {
1098 oldPlane =
d->coordinatePlanes.first();
1099 if ( oldPlane == plane )
1111 const int idx =
d->coordinatePlanes.indexOf( plane );
1113 d->coordinatePlanes.takeAt( idx );
1114 disconnect( plane, 0,
d, 0 );
1115 disconnect( plane, 0,
this, 0 );
1118 d->mouseClickedPlanes.removeAll(plane);
1120 d->slotLayoutPlanes();
1136 d->globalLeadingLeft = leading;
1137 d->leftOuterSpacer->changeSize( leading, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
1138 d->reapplyInternalLayouts();
1143 return d->globalLeadingLeft;
1148 d->globalLeadingTop = leading;
1149 d->topOuterSpacer->changeSize( 0, leading, QSizePolicy::Minimum, QSizePolicy::Fixed );
1150 d->reapplyInternalLayouts();
1155 return d->globalLeadingTop;
1160 d->globalLeadingRight = leading;
1161 d->rightOuterSpacer->changeSize( leading, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
1162 d->reapplyInternalLayouts();
1167 return d->globalLeadingRight;
1172 d->globalLeadingBottom = leading;
1173 d->bottomOuterSpacer->changeSize( 0, leading, QSizePolicy::Minimum, QSizePolicy::Fixed );
1174 d->reapplyInternalLayouts();
1179 return d->globalLeadingBottom;
1184 if ( target.isEmpty() || !painter ) {
1192 if ( dynamic_cast< QWidget* >( painter->device() ) != 0 ) {
1194 qreal( target.height() ) / qreal( geometry().size().height() ) );
1199 const qreal resX = qreal( logicalDpiX() ) / qreal( painter->device()->logicalDpiX() );
1200 const qreal resY = qreal( logicalDpiY() ) / qreal( painter->device()->logicalDpiY() );
1203 qreal( target.height() ) / qreal( geometry().size().height() ) * resY );
1206 const QPoint translation = target.topLeft();
1207 painter->translate( translation );
1212 const bool differentSize = target.size() != size();
1214 if ( differentSize ) {
1215 oldGeometry = geometry();
1216 d->isPlanesLayoutDirty =
true;
1217 d->isFloatingLegendsLayoutDirty =
true;
1218 d->dataAndLegendLayout->setGeometry( QRect( QPoint(), target.size() ) );
1221 d->overrideSize = target.size();
1222 d->paintAll( painter );
1223 d->overrideSize = QSize();
1225 if ( differentSize ) {
1226 d->dataAndLegendLayout->setGeometry( oldGeometry );
1227 d->isPlanesLayoutDirty =
true;
1228 d->isFloatingLegendsLayoutDirty =
true;
1235 painter->translate( -translation.x(), -translation.y() );
1244 d->isPlanesLayoutDirty =
true;
1245 d->isFloatingLegendsLayoutDirty =
true;
1246 QWidget::resizeEvent( event );
1251 KDAB_FOREACH(
Legend *legend,
d->legends ) {
1252 const bool hidden = legend->isHidden() && legend->testAttribute( Qt::WA_WState_ExplicitShowHide );
1255 const QSize legendSize( legend->
sizeHint() );
1256 legend->setGeometry( QRect( legend->geometry().topLeft(), legendSize ) );
1259 QPointF pt( relPos.calculatedPoint( size() ) );
1262 const Qt::Alignment alignTopLeft = Qt::AlignBottom | Qt::AlignLeft;
1263 if ( (relPos.alignment() & alignTopLeft) != alignTopLeft ) {
1264 if ( relPos.alignment() & Qt::AlignRight )
1265 pt.rx() -= legendSize.width();
1266 else if ( relPos.alignment() & Qt::AlignHCenter )
1267 pt.rx() -= 0.5 * legendSize.width();
1269 if ( relPos.alignment() & Qt::AlignBottom )
1270 pt.ry() -= legendSize.height();
1271 else if ( relPos.alignment() & Qt::AlignVCenter )
1272 pt.ry() -= 0.5 * legendSize.height();
1275 legend->move( static_cast<int>(pt.x()), static_cast<int>(pt.y()) );
1283 QPainter painter(
this );
1284 d->paintAll( &painter );
1295 qWarning(
"Unknown header/footer position" );
1299 d->headerFooters.append( hf );
1300 d->textLayoutItems.append( hf );
1301 connect( hf, SIGNAL( destroyedHeaderFooter(
HeaderFooter* ) ),
1302 d, SLOT( slotUnregisterDestroyedHeaderFooter(
HeaderFooter* ) ) );
1303 connect( hf, SIGNAL( positionChanged(
HeaderFooter* ) ),
1304 d, SLOT( slotHeaderFooterPositionChanged(
HeaderFooter* ) ) );
1311 measure.setValue( 20 );
1312 textAttrs.setFontSize( measure );
1318 QVBoxLayout* headerFooterLayout =
d->innerHdFtLayouts[ innerLayoutIdx ][ row ][ column ];
1322 headerFooterLayout->addItem( hf );
1324 d->slotResizePlanes();
1330 if ( headerFooter && oldHeaderFooter_ != headerFooter ) {
1332 if (
d->headerFooters.count() ) {
1333 if ( ! oldHeaderFooter ) {
1334 oldHeaderFooter =
d->headerFooters.first();
1335 if ( oldHeaderFooter == headerFooter )
1340 delete oldHeaderFooter;
1347 const int idx =
d->headerFooters.indexOf( headerFooter );
1351 disconnect( headerFooter, SIGNAL( destroyedHeaderFooter(
HeaderFooter* ) ),
1352 d, SLOT( slotUnregisterDestroyedHeaderFooter(
HeaderFooter* ) ) );
1354 d->headerFooters.takeAt( idx );
1357 d->textLayoutItems.remove(
d->textLayoutItems.indexOf( headerFooter ) );
1359 d->slotResizePlanes();
1362 void Chart::Private::slotHeaderFooterPositionChanged(
HeaderFooter* hf )
1364 chart->takeHeaderFooter( hf );
1365 chart->addHeaderFooter( hf );
1370 if (
d->headerFooters.isEmpty() ) {
1373 return d->headerFooters.first();
1379 return d->headerFooters;
1386 chart->takeLegend( legend );
1387 chart->addLegendInternal( legend,
false );
1392 addLegendInternal( legend,
true );
1396 void Chart::addLegendInternal(
Legend* legend,
bool setMeasures )
1404 qWarning(
"Not showing legend because PositionCenter is not supported for legends." );
1411 qWarning(
"Not showing legend because of unknown legend position." );
1415 d->legends.append( legend );
1416 legend->setParent(
this );
1420 if ( setMeasures ) {
1424 measure.setValue( 20 );
1425 textAttrs.setFontSize( measure );
1430 measure.setValue( 24 );
1445 QLayoutItem* edgeItem =
d->dataAndLegendLayout->itemAtPosition( row, column );
1446 QGridLayout* alignmentsLayout =
dynamic_cast< QGridLayout*
>( edgeItem );
1447 Q_ASSERT( !edgeItem || alignmentsLayout );
1448 if ( !alignmentsLayout ) {
1449 alignmentsLayout =
new QGridLayout;
1450 d->dataAndLegendLayout->addLayout( alignmentsLayout, row, column );
1451 alignmentsLayout->setMargin( 0 );
1459 for (
int i = 0; i < 3; i++ ) {
1460 for (
int j = 0; j < 3; j++ ) {
1470 QLayoutItem* alignmentItem = alignmentsLayout->itemAtPosition( row, column );
1471 QVBoxLayout* sameAlignmentLayout =
dynamic_cast< QVBoxLayout*
>( alignmentItem );
1472 Q_ASSERT( !alignmentItem || sameAlignmentLayout );
1473 if ( !sameAlignmentLayout ) {
1474 sameAlignmentLayout =
new QVBoxLayout;
1475 alignmentsLayout->addLayout( sameAlignmentLayout, row, column );
1476 sameAlignmentLayout->setMargin( 0 );
1479 sameAlignmentLayout->addItem(
new MyWidgetItem( legend, legend->
alignment() ) );
1482 connect( legend, SIGNAL( destroyedLegend(
Legend* ) ),
1483 d, SLOT( slotUnregisterDestroyedLegend(
Legend* ) ) );
1488 d->slotResizePlanes();
1493 if ( legend && oldLegend_ != legend ) {
1494 Legend* oldLegend = oldLegend_;
1495 if (
d->legends.count() ) {
1496 if ( ! oldLegend ) {
1497 oldLegend =
d->legends.first();
1498 if ( oldLegend == legend )
1510 const int idx =
d->legends.indexOf( legend );
1515 d->legends.takeAt( idx );
1516 disconnect( legend, 0,
d, 0 );
1517 disconnect( legend, 0,
this, 0 );
1519 legend->setParent( 0 );
1521 d->slotResizePlanes();
1527 return d->legends.isEmpty() ? 0 :
d->legends.first();
1537 const QPoint pos = mapFromGlobal( event->globalPos() );
1540 if ( plane->
geometry().contains( event->pos() ) && plane->
diagrams().size() > 0 ) {
1541 QMouseEvent ev( QEvent::MouseButtonPress, pos, event->globalPos(),
1542 event->button(),
event->buttons(),
event->modifiers() );
1544 d->mouseClickedPlanes.append( plane );
1551 const QPoint pos = mapFromGlobal( event->globalPos() );
1554 if ( plane->
geometry().contains( event->pos() ) && plane->
diagrams().size() > 0 ) {
1555 QMouseEvent ev( QEvent::MouseButtonPress, pos, event->globalPos(),
1556 event->button(),
event->buttons(),
event->modifiers() );
1564 QSet< AbstractCoordinatePlane* > eventReceivers = QSet< AbstractCoordinatePlane* >::fromList(
d->mouseClickedPlanes );
1567 if ( plane->
geometry().contains( event->pos() ) && plane->
diagrams().size() > 0 ) {
1568 eventReceivers.insert( plane );
1572 const QPoint pos = mapFromGlobal( event->globalPos() );
1575 QMouseEvent ev( QEvent::MouseMove, pos, event->globalPos(),
1576 event->button(),
event->buttons(),
event->modifiers() );
1583 QSet< AbstractCoordinatePlane* > eventReceivers = QSet< AbstractCoordinatePlane* >::fromList(
d->mouseClickedPlanes );
1586 if ( plane->
geometry().contains( event->pos() ) && plane->
diagrams().size() > 0 ) {
1587 eventReceivers.insert( plane );
1591 const QPoint pos = mapFromGlobal( event->globalPos() );
1594 QMouseEvent ev( QEvent::MouseButtonRelease, pos, event->globalPos(),
1595 event->button(),
event->buttons(),
event->modifiers() );
1599 d->mouseClickedPlanes.clear();
1604 if ( event->type() == QEvent::ToolTip ) {
1605 const QHelpEvent*
const helpEvent =
static_cast< QHelpEvent*
>(
event );
1608 const QModelIndex index = diagram->
indexAt( helpEvent->pos() );
1609 const QVariant toolTip = index.data( Qt::ToolTipRole );
1610 if ( toolTip.isValid() ) {
1611 QPoint pos = mapFromGlobal( helpEvent->pos() );
1612 QRect rect( pos - QPoint( 1, 1 ), QSize( 3, 3 ) );
1613 QToolTip::showText( QCursor::pos(), toolTip.toString(),
this, rect );
1619 return QWidget::event( event );
1624 return d_func()->useNewLayoutSystem;
1629 d_func()->useNewLayoutSystem = value;