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> 66 static bool isZeroArea(
const QRect &r)
68 return !r.width() || !r.height();
71 static QString lineProlog(
int nestingDepth,
int lineno)
73 QString numbering(QString::number(lineno).rightJustified(5).append(QChar::fromAscii(
':')));
74 QString indent(nestingDepth * 4, QLatin1Char(
' '));
75 return numbering + indent;
78 static void dumpLayoutTreeRecurse(QLayout *l,
int *counter,
int depth)
80 const QLatin1String colorOn(isZeroArea(l->geometry()) ?
"\033[0m" :
"\033[32m");
81 const QLatin1String colorOff(
"\033[0m");
83 QString prolog = lineProlog(depth, *counter);
86 qDebug() << colorOn + prolog << l->metaObject()->className() << l->geometry()
87 <<
"hint" << l->sizeHint()
88 << l->hasHeightForWidth() <<
"min" << l->minimumSize()
89 <<
"max" << l->maximumSize()
90 << l->expandingDirections() << l->alignment()
92 for (
int i = 0; i < l->count(); i++) {
94 if (QLayout *childL = child->layout()) {
95 dumpLayoutTreeRecurse(childL, counter, depth + 1);
99 if (!isZeroArea(child->geometry())) {
100 prolog = lineProlog(depth + 1, *counter);
102 qDebug() << colorOn + prolog <<
typeid(*child).name() << child->geometry()
103 <<
"hint" << child->sizeHint()
104 << child->hasHeightForWidth() <<
"min" << child->minimumSize()
105 <<
"max" << child->maximumSize()
106 << child->expandingDirections() << child->alignment()
113 static void dumpLayoutTree(QLayout *l)
116 dumpLayoutTreeRecurse(l, &counter, 0);
121 { Qt::AlignTop | Qt::AlignLeft, Qt::AlignTop | Qt::AlignHCenter, Qt::AlignTop | Qt::AlignRight },
122 { Qt::AlignVCenter | Qt::AlignLeft, Qt::AlignVCenter | Qt::AlignHCenter, Qt::AlignVCenter | Qt::AlignRight },
123 { Qt::AlignBottom | Qt::AlignLeft, Qt::AlignBottom | Qt::AlignHCenter, Qt::AlignBottom | Qt::AlignRight }
147 default: *row = -1; *column = -1;
156 class MyWidgetItem :
public QWidgetItem
159 explicit MyWidgetItem(
QWidget *w, Qt::Alignment alignment = 0)
162 setAlignment( alignment );
172 QSize sizeHint()
const override 174 QWidget* w =
const_cast< MyWidgetItem *
>( this )->widget();
175 return w->sizeHint();
178 QSize minimumSize()
const override 180 QWidget* w =
const_cast< MyWidgetItem *
>( this )->widget();
181 return w->minimumSize();
184 QSize maximumSize()
const override 186 QWidget* w =
const_cast< MyWidgetItem *
>( this )->widget();
187 return w->maximumSize();
190 Qt::Orientations expandingDirections()
const override 192 QWidget* w =
const_cast< MyWidgetItem *
>( this )->widget();
194 return Qt::Orientations(0);
196 Qt::Orientations e = w->sizePolicy().expandingDirections();
200 void setGeometry(
const QRect &g)
override 202 QWidget* w =
const_cast< MyWidgetItem *
>( this )->widget();
206 QRect geometry()
const override 208 QWidget* w =
const_cast< MyWidgetItem *
>( this )->widget();
209 return w->geometry();
212 bool hasHeightForWidth()
const override 214 QWidget* w =
const_cast< MyWidgetItem *
>( this )->widget();
215 bool ret = !isEmpty() &&
216 qobject_cast<
Legend* >( w )->hasHeightForWidth();
220 int heightForWidth(
int width )
const override 222 QWidget* w =
const_cast< MyWidgetItem *
>( this )->widget();
223 int ret = w->heightForWidth( width );
227 bool isEmpty()
const override {
228 QWidget* w =
const_cast< MyWidgetItem *
>( this )->widget();
232 return w->isHidden() && w->testAttribute( Qt::WA_WState_ExplicitShowHide );
243 QLayout *layout = item->layout();
245 const int count = layout->count();
246 for (
int i = 0; i < count; i++ ) {
253 void Chart::Private::slotUnregisterDestroyedLegend(
Legend *l )
255 chart->takeLegend( l );
258 void Chart::Private::slotUnregisterDestroyedHeaderFooter(
HeaderFooter* hf )
260 chart->takeHeaderFooter( hf );
265 coordinatePlanes.removeAll( plane );
274 Chart::Private::Private(
Chart* chart_ )
276 , useNewLayoutSystem(
false )
282 , dataAndLegendLayout( 0 )
283 , leftOuterSpacer( 0 )
284 , rightOuterSpacer( 0 )
285 , topOuterSpacer( 0 )
286 , bottomOuterSpacer( 0 )
287 , isFloatingLegendsLayoutDirty(
true )
288 , isPlanesLayoutDirty(
true )
289 , globalLeadingLeft( 0 )
290 , globalLeadingRight( 0 )
291 , globalLeadingTop( 0 )
292 , globalLeadingBottom( 0 )
294 for (
int row = 0; row < 3; ++row ) {
295 for (
int column = 0; column < 3; ++column ) {
296 for (
int i = 0; i < 2; i++ ) {
297 innerHdFtLayouts[ i ][ row ][ column ] = 0;
303 Chart::Private::~Private()
308 struct ConnectedComponentsComparator{
309 bool operator()(
const LayoutGraphNode *lhs,
const LayoutGraphNode *rhs )
const 311 return lhs->priority < rhs->priority;
318 QHash< LayoutGraphNode*, VisitorState > visitedComponents;
319 Q_FOREACH ( LayoutGraphNode* node, nodeList )
320 visitedComponents[ node ] =
Unknown;
321 for (
int i = 0; i < nodeList.size(); ++i )
323 LayoutGraphNode *curNode = nodeList[ i ];
324 LayoutGraphNode *representativeNode = curNode;
325 if ( visitedComponents[ curNode ] !=
Visited )
327 QStack< LayoutGraphNode* > stack;
328 stack.push( curNode );
329 while ( !stack.isEmpty() )
331 curNode = stack.pop();
332 Q_ASSERT( visitedComponents[ curNode ] !=
Visited );
333 visitedComponents[ curNode ] =
Visited;
334 if ( curNode->bottomSuccesor && visitedComponents[ curNode->bottomSuccesor ] !=
Visited )
335 stack.push( curNode->bottomSuccesor );
336 if ( curNode->leftSuccesor && visitedComponents[ curNode->leftSuccesor ] !=
Visited )
337 stack.push( curNode->leftSuccesor );
338 if ( curNode->sharedSuccesor && visitedComponents[ curNode->sharedSuccesor ] !=
Visited )
339 stack.push( curNode->sharedSuccesor );
340 if ( curNode->priority < representativeNode->priority )
341 representativeNode = curNode;
343 connectedComponents.append( representativeNode );
346 std::sort( connectedComponents.begin(), connectedComponents.end(), ConnectedComponentsComparator() );
347 return connectedComponents;
350 struct PriorityComparator{
352 PriorityComparator( QHash< AbstractCoordinatePlane*, LayoutGraphNode* > mapping )
353 : m_mapping( mapping )
357 const LayoutGraphNode *lhsNode = m_mapping[ lhs ];
359 const LayoutGraphNode *rhsNode = m_mapping[ rhs ];
361 return lhsNode->priority < rhsNode->priority;
364 const QHash< AbstractCoordinatePlane*, LayoutGraphNode* > m_mapping;
369 if ( node && node->diagramPlane && node->diagramPlane->diagram() )
379 node->topAxesLayout =
true;
382 node->bottomAxesLayout =
true;
385 node->leftAxesLayout =
true;
388 node->rightAxesLayout =
true;
398 lhs->topAxesLayout |= rhs->topAxesLayout;
399 rhs->topAxesLayout = lhs->topAxesLayout;
401 lhs->bottomAxesLayout |= rhs->bottomAxesLayout;
402 rhs->bottomAxesLayout = lhs->bottomAxesLayout;
404 lhs->leftAxesLayout |= rhs->leftAxesLayout;
405 rhs->leftAxesLayout = lhs->leftAxesLayout;
407 lhs->rightAxesLayout |= rhs->rightAxesLayout;
408 rhs->rightAxesLayout = lhs->rightAxesLayout;
413 Chart::Private::AxisType type,
416 if ( !plane || !plane->
diagram() )
427 if ( ( type == Chart::Private::Ordinate &&
430 ( type == Chart::Private::Abscissa &&
445 if ( curSearchedAxis == curAxis )
447 result.append( curPlane );
448 if ( !sharedAxes->contains( curSearchedAxis ) )
449 sharedAxes->append( curSearchedAxis );
466 QHash< AbstractCoordinatePlane*, LayoutGraphNode* > planeNodeMapping;
473 allNodes.append(
new LayoutGraphNode );
474 allNodes[ allNodes.size() - 1 ]->diagramPlane = curPlane;
475 allNodes[ allNodes.size() - 1 ]->priority = allNodes.size();
477 planeNodeMapping[ curPlane ] = allNodes[ allNodes.size() - 1 ];
481 Q_FOREACH( LayoutGraphNode* curNode, allNodes )
485 Q_ASSERT( sharedAxes.size() < 2 );
487 if ( sharedAxes.size() == 1 && xSharedPlanes.size() > 1 )
491 for (
int i = 0; i < xSharedPlanes.size() - 1; ++i )
493 LayoutGraphNode *tmpNode = planeNodeMapping[ xSharedPlanes[ i ] ];
495 LayoutGraphNode *tmpNode2 = planeNodeMapping[ xSharedPlanes[ i + 1 ] ];
496 Q_ASSERT( tmpNode2 );
497 tmpNode->bottomSuccesor = tmpNode2;
509 LayoutGraphNode axisInfoNode;
510 for (
int count = 0; count < 2; ++count )
512 for (
int i = 0; i < xSharedPlanes.size(); ++i )
520 Q_ASSERT( sharedAxes.size() < 2 );
521 if ( sharedAxes.size() == 1 && ySharedPlanes.size() > 1 )
525 for (
int i = 0; i < ySharedPlanes.size() - 1; ++i )
527 LayoutGraphNode *tmpNode = planeNodeMapping[ ySharedPlanes[ i ] ];
529 LayoutGraphNode *tmpNode2 = planeNodeMapping[ ySharedPlanes[ i + 1 ] ];
530 Q_ASSERT( tmpNode2 );
531 tmpNode->leftSuccesor = tmpNode2;
543 LayoutGraphNode axisInfoNode;
544 for (
int count = 0; count < 2; ++count )
546 for (
int i = 0; i < ySharedPlanes.size(); ++i )
553 if ( curNode->diagramPlane->referenceCoordinatePlane() )
554 curNode->sharedSuccesor = planeNodeMapping[ curNode->diagramPlane->referenceCoordinatePlane() ];
560 QHash<AbstractCoordinatePlane*, PlaneInfo> Chart::Private::buildPlaneLayoutInfos()
574 QHash<CartesianAxis*, AxisInfo> axisInfos;
575 QHash<AbstractCoordinatePlane*, PlaneInfo> planeInfos;
580 planeInfos.insert( plane, p );
590 if ( !axisInfos.contains( axis ) ) {
597 axisInfos.insert( axis, i );
599 AxisInfo i = axisInfos[axis];
600 if ( i.plane == plane ) {
607 PlaneInfo pi = planeInfos[plane];
609 if ( !pi.referencePlane ) {
611 pi.referencePlane = i.plane;
614 pi.horizontalOffset += 1;
616 planeInfos[plane] = pi;
618 pi = planeInfos[i.plane];
621 pi.verticalOffset += 1;
624 planeInfos[i.plane] = pi;
630 p = planeInfos[plane];
631 if ( p.referencePlane == 0 ) {
632 p.gridLayout =
new QGridLayout();
633 p.gridLayout->setMargin( 0 );
634 planeInfos[plane] = p;
640 void Chart::Private::slotLayoutPlanes()
643 const QBoxLayout::Direction oldPlanesDirection = planesLayout ? planesLayout->direction()
644 : QBoxLayout::TopToBottom;
645 if ( planesLayout && dataAndLegendLayout )
646 dataAndLegendLayout->removeItem( planesLayout );
648 const bool hadPlanesLayout = planesLayout != 0;
649 int left, top, right, bottom;
650 if ( hadPlanesLayout )
651 planesLayout->getContentsMargins(&left, &top, &right, &bottom);
658 if ( dynamic_cast< AutoSpacerLayoutItem* >( plane ) )
662 planeLayoutItems.clear();
666 planesLayout =
new QBoxLayout( oldPlanesDirection );
668 isPlanesLayoutDirty =
true;
670 if ( useNewLayoutSystem )
672 gridPlaneLayout =
new QGridLayout;
673 planesLayout->addLayout( gridPlaneLayout );
676 planesLayout->setContentsMargins(left, top, right, bottom);
677 planesLayout->setObjectName( QString::fromLatin1(
"planesLayout" ) );
689 QSet< CartesianAxis* > laidOutAxes;
690 for (
int i = 0; i < connectedComponents.size(); ++i )
692 LayoutGraphNode *curComponent = connectedComponents[ i ];
693 for ( LayoutGraphNode *curRowComponent = curComponent; curRowComponent; curRowComponent = curRowComponent->bottomSuccesor )
696 for ( LayoutGraphNode *curColComponent = curRowComponent; curColComponent; curColComponent = curColComponent->leftSuccesor )
698 Q_ASSERT( curColComponent->diagramPlane->diagrams().size() == 1 );
699 Q_FOREACH(
AbstractDiagram* diagram, curColComponent->diagramPlane->diagrams() )
701 const int planeRowOffset = 1;
702 const int planeColOffset = 1;
706 planeLayoutItems << curColComponent->diagramPlane;
710 gridPlaneLayout->addItem( curColComponent->diagramPlane, row + planeRowOffset, col + planeColOffset, 2, 2 );
711 curColComponent->diagramPlane->setParentLayout( gridPlaneLayout );
712 QHBoxLayout *leftLayout = 0;
713 QHBoxLayout *rightLayout = 0;
714 QVBoxLayout *topLayout = 0;
715 QVBoxLayout *bottomLayout = 0;
716 if ( curComponent->sharedSuccesor )
718 gridPlaneLayout->addItem( curColComponent->sharedSuccesor->diagramPlane, row + planeRowOffset, col + planeColOffset, 2, 2 );
719 curColComponent->sharedSuccesor->diagramPlane->setParentLayout( gridPlaneLayout );
720 planeLayoutItems << curColComponent->sharedSuccesor->diagramPlane;
726 if ( curColComponent->bottomSuccesor )
729 if ( laidOutAxes.contains( axis ) )
737 topLayout =
new QVBoxLayout;
738 topLayout->addItem( axis );
743 bottomLayout =
new QVBoxLayout;
744 bottomLayout->addItem( axis );
749 leftLayout =
new QHBoxLayout;
750 leftLayout->addItem( axis );
756 rightLayout =
new QHBoxLayout;
758 rightLayout->addItem( axis );
762 planeLayoutItems << axis;
763 laidOutAxes.insert( axis );
766 gridPlaneLayout->addLayout( leftLayout, row + planeRowOffset, col, 2, 1,
767 Qt::AlignRight | Qt::AlignVCenter );
769 gridPlaneLayout->addLayout( rightLayout, row, col + planeColOffset + 2, 2, 1,
770 Qt::AlignLeft | Qt::AlignVCenter );
772 gridPlaneLayout->addLayout( topLayout, row, col + planeColOffset, 1, 2,
773 Qt::AlignBottom | Qt::AlignHCenter );
775 gridPlaneLayout->addLayout( bottomLayout, row + planeRowOffset + 2,
776 col + planeColOffset, 1, 2, Qt::AlignTop | Qt::AlignHCenter );
780 gridPlaneLayout->addItem( curColComponent->diagramPlane, row, col, 4, 4 );
783 col += planeColOffset + 2 + ( 1 );
788 const int rowOffset = axisOffset + 2;
800 if ( dataAndLegendLayout ) {
801 dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
802 dataAndLegendLayout->setRowStretch( 1, 1000 );
803 dataAndLegendLayout->setColumnStretch( 1, 1000 );
806 #ifdef NEW_LAYOUT_DEBUG 807 for (
int i = 0; i < gridPlaneLayout->rowCount(); ++i )
809 for (
int j = 0; j < gridPlaneLayout->columnCount(); ++j )
811 if ( gridPlaneLayout->itemAtPosition( i, j ) )
812 qDebug() << Q_FUNC_INFO <<
"item at" << i << j << gridPlaneLayout->itemAtPosition( i, j )->geometry();
814 qDebug() << Q_FUNC_INFO <<
"item at" << i << j <<
"no item present";
820 if ( hadPlanesLayout ) {
821 planesLayout->setContentsMargins( left, top, right, bottom );
824 planesLayout->setMargin( 0 );
825 planesLayout->setSpacing( 0 );
826 planesLayout->setObjectName( QString::fromLatin1(
"planesLayout" ) );
831 QHash<AbstractCoordinatePlane*, PlaneInfo> planeInfos = buildPlaneLayoutInfos();
832 QHash<AbstractAxis*, AxisInfo> axisInfos;
834 Q_ASSERT( planeInfos.contains(plane) );
835 PlaneInfo& pi = planeInfos[ plane ];
836 const int column = pi.horizontalOffset;
837 const int row = pi.verticalOffset;
839 QGridLayout *planeLayout = pi.gridLayout;
841 if ( !planeLayout ) {
842 PlaneInfo& refPi = pi;
845 while ( !planeLayout && refPi.referencePlane ) {
846 refPi = planeInfos[refPi.referencePlane];
847 planeLayout = refPi.gridLayout;
849 Q_ASSERT_X( planeLayout,
850 "Chart::Private::slotLayoutPlanes()",
851 "Invalid reference plane. Please check that the reference plane has been added to the Chart." );
853 planesLayout->addLayout( planeLayout );
859 planeLayoutItems << plane;
861 planeLayout->addItem( plane, row, column, 1, 1, 0 );
863 planeLayout->setRowStretch( row, 2 );
864 planeLayout->setColumnStretch( column, 2 );
873 if ( pi.referencePlane != 0 )
875 pi.topAxesLayout = planeInfos[ pi.referencePlane ].topAxesLayout;
876 pi.bottomAxesLayout = planeInfos[ pi.referencePlane ].bottomAxesLayout;
877 pi.leftAxesLayout = planeInfos[ pi.referencePlane ].leftAxesLayout;
878 pi.rightAxesLayout = planeInfos[ pi.referencePlane ].rightAxesLayout;
882 if ( pi.topAxesLayout == 0 )
884 pi.topAxesLayout =
new QVBoxLayout;
885 pi.topAxesLayout->setMargin( 0 );
886 pi.topAxesLayout->setObjectName( QString::fromLatin1(
"topAxesLayout" ) );
888 if ( pi.bottomAxesLayout == 0 )
890 pi.bottomAxesLayout =
new QVBoxLayout;
891 pi.bottomAxesLayout->setMargin( 0 );
892 pi.bottomAxesLayout->setObjectName( QString::fromLatin1(
"bottomAxesLayout" ) );
894 if ( pi.leftAxesLayout == 0 )
896 pi.leftAxesLayout =
new QHBoxLayout;
897 pi.leftAxesLayout->setMargin( 0 );
898 pi.leftAxesLayout->setObjectName( QString::fromLatin1(
"leftAxesLayout" ) );
900 if ( pi.rightAxesLayout == 0 )
902 pi.rightAxesLayout =
new QHBoxLayout;
903 pi.rightAxesLayout->setMargin( 0 );
904 pi.rightAxesLayout->setObjectName( QString::fromLatin1(
"rightAxesLayout" ) );
907 if ( pi.referencePlane != 0 )
909 planeInfos[ pi.referencePlane ].topAxesLayout = pi.topAxesLayout;
910 planeInfos[ pi.referencePlane ].bottomAxesLayout = pi.bottomAxesLayout;
911 planeInfos[ pi.referencePlane ].leftAxesLayout = pi.leftAxesLayout;
912 planeInfos[ pi.referencePlane ].rightAxesLayout = pi.rightAxesLayout;
917 if ( axisInfos.contains( axis ) ) {
923 planeLayoutItems << axis;
925 switch ( axis->position() ) {
927 axis->setParentLayout( pi.topAxesLayout );
928 pi.topAxesLayout->addItem( axis );
931 axis->setParentLayout( pi.bottomAxesLayout );
932 pi.bottomAxesLayout->addItem( axis );
935 axis->setParentLayout( pi.leftAxesLayout );
936 pi.leftAxesLayout->addItem( axis );
939 axis->setParentLayout( pi.rightAxesLayout );
940 pi.rightAxesLayout->addItem( axis );
943 Q_ASSERT_X(
false,
"Chart::paintEvent",
"unknown axis position" );
946 axisInfos.insert( axis, AxisInfo() );
953 if ( !pi.topAxesLayout->parent() ) {
954 planeLayout->addLayout( pi.topAxesLayout, row - 1, column );
956 if ( !pi.bottomAxesLayout->parent() ) {
957 planeLayout->addLayout( pi.bottomAxesLayout, row + 1, column );
959 if ( !pi.leftAxesLayout->parent() ) {
960 planeLayout->addLayout( pi.leftAxesLayout, row, column - 1 );
962 if ( !pi.rightAxesLayout->parent() ) {
963 planeLayout->addLayout( pi.rightAxesLayout,row, column + 1 );
968 #define ADD_AUTO_SPACER_IF_NEEDED( \ 969 spacerRow, spacerColumn, hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout ) \ 971 if ( hLayout || vLayout ) { \ 972 AutoSpacerLayoutItem * spacer \ 973 = new AutoSpacerLayoutItem( hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout ); \ 974 planeLayout->addItem( spacer, spacerRow, spacerColumn, 1, 1 ); \ 975 spacer->setParentLayout( planeLayout ); \ 976 planeLayoutItems << spacer; \ 980 if ( plane->isCornerSpacersEnabled() ) {
988 if ( dataAndLegendLayout ) {
989 dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
990 dataAndLegendLayout->setRowStretch( 1, 1000 );
991 dataAndLegendLayout->setColumnStretch( 1, 1000 );
998 void Chart::Private::createLayouts()
1001 layout =
new QHBoxLayout( chart );
1002 layout->setMargin( 0 );
1003 layout->setObjectName( QString::fromLatin1(
"Chart::Private::layout" ) );
1004 layout->addSpacing( globalLeadingLeft );
1005 leftOuterSpacer = layout->itemAt( layout->count() - 1 )->spacerItem();
1009 vLayout =
new QVBoxLayout();
1010 vLayout->setMargin( 0 );
1011 vLayout->setObjectName( QString::fromLatin1(
"vLayout" ) );
1013 layout->addLayout( vLayout, 1000 );
1014 layout->addSpacing( globalLeadingRight );
1015 rightOuterSpacer = layout->itemAt( layout->count() - 1 )->spacerItem();
1018 vLayout->addSpacing( globalLeadingTop );
1019 topOuterSpacer = vLayout->itemAt( vLayout->count() - 1 )->spacerItem();
1021 headerLayout =
new QGridLayout();
1022 headerLayout->setMargin( 0 );
1023 vLayout->addLayout( headerLayout );
1025 dataAndLegendLayout =
new QGridLayout();
1026 dataAndLegendLayout->setMargin( 0 );
1027 dataAndLegendLayout->setObjectName( QString::fromLatin1(
"dataAndLegendLayout" ) );
1028 vLayout->addLayout( dataAndLegendLayout, 1000 );
1030 footerLayout =
new QGridLayout();
1031 footerLayout->setMargin( 0 );
1032 footerLayout->setObjectName( QString::fromLatin1(
"footerLayout" ) );
1033 vLayout->addLayout( footerLayout );
1039 for (
int row = 0; row < 3; ++row ) {
1040 for (
int column = 0; column < 3; ++ column ) {
1041 const Qt::Alignment align = s_gridAlignments[ row ][ column ];
1042 for (
int headOrFoot = 0; headOrFoot < 2; headOrFoot++ ) {
1043 QVBoxLayout* innerLayout =
new QVBoxLayout();
1044 innerLayout->setMargin( 0 );
1045 innerLayout->setAlignment( align );
1046 innerHdFtLayouts[ headOrFoot ][ row ][ column ] = innerLayout;
1048 QGridLayout* outerLayout = headOrFoot == 0 ? headerLayout : footerLayout;
1049 outerLayout->addLayout( innerLayout, row, column, align );
1055 vLayout->addSpacing( globalLeadingBottom );
1056 bottomOuterSpacer = vLayout->itemAt( vLayout->count() - 1 )->spacerItem();
1059 dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
1060 dataAndLegendLayout->setRowStretch( 1, 1 );
1061 dataAndLegendLayout->setColumnStretch( 1, 1 );
1064 void Chart::Private::slotResizePlanes()
1066 if ( !dataAndLegendLayout ) {
1069 if ( !overrideSize.isValid() ) {
1082 void Chart::Private::updateDirtyLayouts()
1084 if ( isPlanesLayoutDirty ) {
1091 if ( isPlanesLayoutDirty || isFloatingLegendsLayoutDirty ) {
1092 chart->reLayoutFloatingLegends();
1094 isPlanesLayoutDirty =
false;
1095 isFloatingLegendsLayoutDirty =
false;
1098 void Chart::Private::reapplyInternalLayouts()
1100 QRect geo = layout->geometry();
1103 layout->setGeometry( geo );
1107 void Chart::Private::paintAll( QPainter* painter )
1109 updateDirtyLayouts();
1111 QRect rect( QPoint( 0, 0 ), overrideSize.isValid() ? overrideSize : chart->size() );
1120 chart->reLayoutFloatingLegends();
1123 planeLayoutItem->
paintAll( *painter );
1125 KDAB_FOREACH(
TextArea* textLayoutItem, textLayoutItems ) {
1126 textLayoutItem->
paintAll( *painter );
1128 KDAB_FOREACH(
Legend *legend, legends ) {
1129 const bool hidden = legend->isHidden() && legend->testAttribute( Qt::WA_WState_ExplicitShowHide );
1143 , _d( new Private( this ) )
1145 #if defined KDAB_EVAL 1146 EvalDialog::checkEvalLicense(
"KD Chart" );
1152 frameAttrs.
setPen( QPen( Qt::black ) );
1168 d->frameAttributes = a;
1173 return d->frameAttributes;
1178 d->backgroundAttributes = a;
1183 return d->backgroundAttributes;
1189 if (layout ==
d->planesLayout)
1191 if (
d->planesLayout) {
1194 for(
int i =
d->planesLayout->count() - 1; i >= 0; --i) {
1195 d->planesLayout->takeAt(i);
1197 delete d->planesLayout;
1199 d->planesLayout = qobject_cast<QBoxLayout*>( layout );
1200 d->slotLayoutPlanes();
1205 return d->planesLayout;
1210 if (
d->coordinatePlanes.isEmpty() ) {
1211 qWarning() <<
"Chart::coordinatePlane: warning: no coordinate plane defined.";
1214 return d->coordinatePlanes.first();
1220 return d->coordinatePlanes;
1231 if ( index < 0 || index >
d->coordinatePlanes.count() ) {
1237 connect( plane, SIGNAL( needUpdate() ),
this, SLOT( update() ) );
1238 connect( plane, SIGNAL( needRelayout() ),
d, SLOT( slotResizePlanes() ) ) ;
1239 connect( plane, SIGNAL( needLayoutPlanes() ),
d, SLOT( slotLayoutPlanes() ) ) ;
1241 d->coordinatePlanes.insert( index, plane );
1243 d->slotLayoutPlanes();
1249 if ( plane && oldPlane_ != plane ) {
1251 if (
d->coordinatePlanes.count() ) {
1253 oldPlane =
d->coordinatePlanes.first();
1254 if ( oldPlane == plane )
1266 const int idx =
d->coordinatePlanes.indexOf( plane );
1268 d->coordinatePlanes.takeAt( idx );
1269 disconnect( plane, 0,
d, 0 );
1270 disconnect( plane, 0,
this, 0 );
1273 d->mouseClickedPlanes.removeAll(plane);
1275 d->slotLayoutPlanes();
1291 d->globalLeadingLeft = leading;
1292 d->leftOuterSpacer->changeSize( leading, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
1293 d->reapplyInternalLayouts();
1298 return d->globalLeadingLeft;
1303 d->globalLeadingTop = leading;
1304 d->topOuterSpacer->changeSize( 0, leading, QSizePolicy::Minimum, QSizePolicy::Fixed );
1305 d->reapplyInternalLayouts();
1310 return d->globalLeadingTop;
1315 d->globalLeadingRight = leading;
1316 d->rightOuterSpacer->changeSize( leading, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
1317 d->reapplyInternalLayouts();
1322 return d->globalLeadingRight;
1327 d->globalLeadingBottom = leading;
1328 d->bottomOuterSpacer->changeSize( 0, leading, QSizePolicy::Minimum, QSizePolicy::Fixed );
1329 d->reapplyInternalLayouts();
1334 return d->globalLeadingBottom;
1339 if ( target.isEmpty() || !painter ) {
1347 if ( dynamic_cast< QWidget* >( painter->device() ) != 0 ) {
1349 qreal( target.height() ) / qreal( geometry().size().height() ) );
1354 const qreal resX = qreal( logicalDpiX() ) / qreal( painter->device()->logicalDpiX() );
1355 const qreal resY = qreal( logicalDpiY() ) / qreal( painter->device()->logicalDpiY() );
1358 qreal( target.height() ) / qreal( geometry().size().height() ) * resY );
1361 const QPoint translation = target.topLeft();
1362 painter->translate( translation );
1367 const bool differentSize = target.size() != size();
1369 if ( differentSize ) {
1370 oldGeometry = geometry();
1371 d->isPlanesLayoutDirty =
true;
1372 d->isFloatingLegendsLayoutDirty =
true;
1374 d->dataAndLegendLayout->setGeometry( QRect( QPoint(), target.size() ) );
1377 d->overrideSize = target.size();
1378 d->paintAll( painter );
1379 d->overrideSize = QSize();
1381 if ( differentSize ) {
1383 d->dataAndLegendLayout->setGeometry( oldGeometry );
1384 d->isPlanesLayoutDirty =
true;
1385 d->isFloatingLegendsLayoutDirty =
true;
1392 painter->translate( -translation.x(), -translation.y() );
1401 d->isPlanesLayoutDirty =
true;
1402 d->isFloatingLegendsLayoutDirty =
true;
1403 QWidget::resizeEvent( event );
1409 const bool hidden = legend->isHidden() && legend->testAttribute( Qt::WA_WState_ExplicitShowHide );
1412 const QSize legendSize( legend->
sizeHint() );
1413 legend->setGeometry( QRect( legend->geometry().topLeft(), legendSize ) );
1416 QPointF pt( relPos.calculatedPoint( size() ) );
1419 const Qt::Alignment alignTopLeft = Qt::AlignBottom | Qt::AlignLeft;
1420 if ( (relPos.alignment() & alignTopLeft) != alignTopLeft ) {
1421 if ( relPos.alignment() & Qt::AlignRight )
1422 pt.rx() -= legendSize.width();
1423 else if ( relPos.alignment() & Qt::AlignHCenter )
1424 pt.rx() -= 0.5 * legendSize.width();
1426 if ( relPos.alignment() & Qt::AlignBottom )
1427 pt.ry() -= legendSize.height();
1428 else if ( relPos.alignment() & Qt::AlignVCenter )
1429 pt.ry() -= 0.5 * legendSize.height();
1432 legend->move( static_cast<int>(pt.x()), static_cast<int>(pt.y()) );
1440 QPainter painter(
this );
1441 d->paintAll( &painter );
1452 qWarning(
"Unknown header/footer position" );
1456 d->headerFooters.append( hf );
1457 d->textLayoutItems.append( hf );
1458 connect( hf, SIGNAL( destroyedHeaderFooter(
HeaderFooter* ) ),
1459 d, SLOT( slotUnregisterDestroyedHeaderFooter(
HeaderFooter* ) ) );
1460 connect( hf, SIGNAL( positionChanged(
HeaderFooter* ) ),
1461 d, SLOT( slotHeaderFooterPositionChanged(
HeaderFooter* ) ) );
1466 Measure measure( textAttrs.fontSize() );
1468 measure.setValue( 20 );
1469 textAttrs.setFontSize( measure );
1475 QVBoxLayout* headerFooterLayout =
d->innerHdFtLayouts[ innerLayoutIdx ][ row ][ column ];
1478 hf->setAlignment( s_gridAlignments[ row ][ column ] );
1479 headerFooterLayout->addItem( hf );
1481 d->slotResizePlanes();
1487 if ( headerFooter && oldHeaderFooter_ != headerFooter ) {
1489 if (
d->headerFooters.count() ) {
1490 if ( ! oldHeaderFooter ) {
1491 oldHeaderFooter =
d->headerFooters.first();
1492 if ( oldHeaderFooter == headerFooter )
1497 delete oldHeaderFooter;
1504 const int idx =
d->headerFooters.indexOf( headerFooter );
1508 disconnect( headerFooter, SIGNAL( destroyedHeaderFooter(
HeaderFooter* ) ),
1509 d, SLOT( slotUnregisterDestroyedHeaderFooter(
HeaderFooter* ) ) );
1511 d->headerFooters.takeAt( idx );
1514 d->textLayoutItems.remove(
d->textLayoutItems.indexOf( headerFooter ) );
1516 d->slotResizePlanes();
1519 void Chart::Private::slotHeaderFooterPositionChanged(
HeaderFooter* hf )
1521 chart->takeHeaderFooter( hf );
1522 chart->addHeaderFooter( hf );
1527 if (
d->headerFooters.isEmpty() ) {
1530 return d->headerFooters.first();
1536 return d->headerFooters;
1543 chart->takeLegend( legend );
1544 chart->addLegendInternal( legend,
false );
1550 addLegendInternal( legend,
true );
1554 void Chart::addLegendInternal(
Legend*
legend,
bool setMeasures )
1562 qWarning(
"Not showing legend because PositionCenter is not supported for legends." );
1569 qWarning(
"Not showing legend because of unknown legend position." );
1573 d->legends.append( legend );
1574 legend->setParent(
this );
1578 if ( setMeasures ) {
1580 Measure measure( textAttrs.fontSize() );
1582 measure.setValue( 20 );
1583 textAttrs.setFontSize( measure );
1588 measure.setValue( 24 );
1603 QLayoutItem* edgeItem =
d->dataAndLegendLayout->itemAtPosition( row, column );
1604 QGridLayout* alignmentsLayout =
dynamic_cast< QGridLayout*
>( edgeItem );
1605 Q_ASSERT( !edgeItem || alignmentsLayout );
1606 if ( !alignmentsLayout ) {
1607 alignmentsLayout =
new QGridLayout;
1608 d->dataAndLegendLayout->addLayout( alignmentsLayout, row, column );
1609 alignmentsLayout->setMargin( 0 );
1617 for (
int i = 0; i < 3; i++ ) {
1618 for (
int j = 0; j < 3; j++ ) {
1619 Qt::Alignment align = s_gridAlignments[ i ][ j ];
1628 QLayoutItem* alignmentItem = alignmentsLayout->itemAtPosition( row, column );
1629 QVBoxLayout* sameAlignmentLayout =
dynamic_cast< QVBoxLayout*
>( alignmentItem );
1630 Q_ASSERT( !alignmentItem || sameAlignmentLayout );
1631 if ( !sameAlignmentLayout ) {
1632 sameAlignmentLayout =
new QVBoxLayout;
1633 alignmentsLayout->addLayout( sameAlignmentLayout, row, column );
1634 sameAlignmentLayout->setMargin( 0 );
1637 sameAlignmentLayout->addItem(
new MyWidgetItem( legend, legend->
alignment() ) );
1640 connect( legend, SIGNAL( destroyedLegend(
Legend* ) ),
1641 d, SLOT( slotUnregisterDestroyedLegend(
Legend* ) ) );
1646 d->slotResizePlanes();
1651 if ( legend && oldLegend_ != legend ) {
1652 Legend* oldLegend = oldLegend_;
1653 if (
d->legends.count() ) {
1654 if ( ! oldLegend ) {
1655 oldLegend =
d->legends.first();
1656 if ( oldLegend == legend )
1668 const int idx =
d->legends.indexOf( legend );
1673 d->legends.takeAt( idx );
1674 disconnect( legend, 0,
d, 0 );
1675 disconnect( legend, 0,
this, 0 );
1677 legend->setParent( 0 );
1679 d->slotResizePlanes();
1685 return d->legends.isEmpty() ? 0 :
d->legends.first();
1695 const QPoint pos = mapFromGlobal( event->globalPos() );
1698 if ( plane->
geometry().contains( event->pos() ) && plane->
diagrams().size() > 0 ) {
1699 QMouseEvent ev( QEvent::MouseButtonPress, pos, event->globalPos(),
1700 event->button(),
event->buttons(),
event->modifiers() );
1702 d->mouseClickedPlanes.append( plane );
1709 const QPoint pos = mapFromGlobal( event->globalPos() );
1712 if ( plane->
geometry().contains( event->pos() ) && plane->
diagrams().size() > 0 ) {
1713 QMouseEvent ev( QEvent::MouseButtonPress, pos, event->globalPos(),
1714 event->button(),
event->buttons(),
event->modifiers() );
1722 QSet< AbstractCoordinatePlane* > eventReceivers = QSet< AbstractCoordinatePlane* >::fromList(
d->mouseClickedPlanes );
1725 if ( plane->
geometry().contains( event->pos() ) && plane->
diagrams().size() > 0 ) {
1726 eventReceivers.insert( plane );
1730 const QPoint pos = mapFromGlobal( event->globalPos() );
1733 QMouseEvent ev( QEvent::MouseMove, pos, event->globalPos(),
1734 event->button(),
event->buttons(),
event->modifiers() );
1741 QSet< AbstractCoordinatePlane* > eventReceivers = QSet< AbstractCoordinatePlane* >::fromList(
d->mouseClickedPlanes );
1744 if ( plane->
geometry().contains( event->pos() ) && plane->
diagrams().size() > 0 ) {
1745 eventReceivers.insert( plane );
1749 const QPoint pos = mapFromGlobal( event->globalPos() );
1752 QMouseEvent ev( QEvent::MouseButtonRelease, pos, event->globalPos(),
1753 event->button(),
event->buttons(),
event->modifiers() );
1757 d->mouseClickedPlanes.clear();
1762 if ( event->type() == QEvent::ToolTip ) {
1763 const QHelpEvent*
const helpEvent =
static_cast< QHelpEvent*
>(
event );
1764 for (
int stage = 0; stage < 2; ++stage) {
1771 index = diagram->
indexAt(helpEvent->pos());
1775 const QModelIndexList indexes = diagram->
indexesIn(QRect( helpEvent->pos() - QPoint(15,15), QSize(30,30)));
1776 index = indexes.isEmpty() ? QModelIndex() : indexes.front();
1779 const QVariant toolTip = index.data( Qt::ToolTipRole );
1780 if ( toolTip.isValid() ) {
1781 const QPoint pos = mapFromGlobal( helpEvent->pos() );
1782 const QRect rect( pos - QPoint( 1, 1 ), QSize( 3, 3 ) );
1783 QToolTip::showText( QCursor::pos(), toolTip.toString(),
this, rect );
1790 return QWidget::event( event );
1795 return d_func()->useNewLayoutSystem;
1800 d_func()->useNewLayoutSystem = value;
Position position() const
Returns the position of a non-floating legend.
static void paintFrameAttributes(QPainter &painter, const QRect &rectangle, const KDChart::FrameAttributes &attributes)
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane.
KDChartEnums::PositionValue value() const
Returns an integer value corresponding to this Position.
void setPadding(int padding)
int globalLeadingBottom() const
The padding between the start of the widget and the start of the area that is used for drawing at the...
static CoordinatePlaneList findSharingAxisDiagrams(AbstractCoordinatePlane *plane, const CoordinatePlaneList &list, Chart::Private::AxisType type, QVector< CartesianAxis * > *sharedAxes)
bool event(QEvent *event) override
reimp
void mouseReleaseEvent(QMouseEvent *event) override
reimp
void replaceCoordinatePlane(AbstractCoordinatePlane *plane, AbstractCoordinatePlane *oldPlane=0)
Replaces the old coordinate plane, or appends the plane, it there is none yet.
static void setScaleFactor(const qreal scaleFactor)
static void paintBackgroundAttributes(QPainter &painter, const QRect &rectangle, const KDChart::BackgroundAttributes &attributes)
void setParent(Chart *parent)
Called internally by KDChart::Chart.
void reLayoutFloatingLegends()
void setReferenceArea(const QWidget *area)
Specifies the reference area for font size of title text, and for font size of the item texts...
QRect geometry() const override
pure virtual in QLayoutItem
static void invalidateLayoutTree(QLayoutItem *item)
A chart with one or more diagrams.
virtual void layoutDiagrams()=0
Distribute the available space among the diagrams and axes.
void setTextAttributes(const TextAttributes &a)
Definition of global enums.
void checkExistingAxes(LayoutGraphNode *node)
TextAttributes titleTextAttributes() const
LegendList legends()
The list of all legends associated with the chart.
void layoutPlanes()
Calling layoutPlanes() on the plane triggers the global KDChart::Chart::slotLayoutPlanes() ...
A set of attributes for frames around items.
TextAttributes textAttributes() const
Returns the text attributes to be used for this item.
HeaderFooter * headerFooter()
The first header or footer of the chart.
static void setPaintDevice(QPaintDevice *paintDevice)
Set the paint device to use for calculating font metrics.
void removeFromParentLayout()
void needSizeHint() override
Call this to trigger an conditional re-building of the widget's internals.
virtual void mouseMoveEvent(QMouseEvent *event)
A text area in the chart with a background, a frame, etc.
void setPen(const QPen &pen)
void mouseMoveEvent(QMouseEvent *event) override
reimp
static QVector< LayoutGraphNode * > getPrioritySortedConnectedComponents(QVector< LayoutGraphNode * > &nodeList)
void takeHeaderFooter(HeaderFooter *headerFooter)
Removes the header (or footer, resp.) from the chart, without deleting it.
static QPaintDevice * paintDevice()
Return the paint device to use for calculating font metrics.
void setCachedSizeDirty() const
QLayout * coordinatePlaneLayout()
CoordinatePlaneList coordinatePlanes()
The list of coordinate planes.
void setFrameAttributes(const FrameAttributes &a)
Specify the frame attributes to be used, by default is it a thin black line.
void setGlobalLeadingRight(int leading)
Set the padding between the start of the widget and the start of the area that is used for drawing on...
AbstractDiagram defines the interface for diagram classes.
void takeCoordinatePlane(AbstractCoordinatePlane *plane)
Removes the coordinate plane from the chart, without deleting it.
void paint(QPainter *painter, const QRect &target)
Paints all the contents of the chart.
void setUseNewLayoutSystem(bool value)
static void getRowAndColumnForPosition(KDChartEnums::PositionValue pos, int *row, int *column)
void insertCoordinatePlane(int index, AbstractCoordinatePlane *plane)
Inserts a coordinate plane to the chart at index index.
void setGlobalLeadingTop(int leading)
Set the padding between the start of the widget and the start of the area that is used for drawing at...
QSize sizeHint() const override
The class for cartesian axes.
static void resetScaleFactor()
void setTitleTextAttributes(const TextAttributes &a)
void paintAll(QPainter &painter) override
Call paintAll, if you want the background and the frame to be drawn before the normal paint() is invo...
void replaceHeaderFooter(HeaderFooter *headerFooter, HeaderFooter *oldHeaderFooter=0)
Replaces the old header (or footer, resp.), or appends the new header or footer, it there is none yet...
#define ADD_AUTO_SPACER_IF_NEEDED(spacerRow, spacerColumn, hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout)
virtual void paintAll(QPainter &painter)
Default impl: just call paint.
AbstractDiagram * diagram()
Class only listed here to document inheritance of some KDChart classes.
static GlobalMeasureScaling * instance()
void setReferenceCoordinatePlane(AbstractCoordinatePlane *plane)
Set another coordinate plane to be used as the reference plane for this one.
void setFontSize(const Measure &measure)
Set the size of the font used for rendering text.
void addLegend(Legend *legend)
Add the given legend to the chart.
BackgroundAttributes backgroundAttributes() const
Base class for all layout items of KD Chart.
Legend defines the interface for the legend drawing class.
virtual void mouseReleaseEvent(QMouseEvent *event)
static void mergeNodeAxisInformation(LayoutGraphNode *lhs, LayoutGraphNode *rhs)
virtual KDChart::CartesianAxisList axes() const
void setGlobalLeadingBottom(int leading)
Set the padding between the start of the widget and the start of the area that is used for drawing on...
void setTextAttributes(const TextAttributes &a)
Use this to specify the text attributes to be used for this item.
virtual bool isAbscissa() const
static void resetFactors()
Restore factors to the values before the previous call to setFactors.
void takeLegend(Legend *legend)
Removes the legend from the chart, without deleting it.
static const Qt::Alignment s_gridAlignments[3][3]
FrameAttributes frameAttributes() const
void addHeaderFooter(HeaderFooter *headerFooter)
Adds a header or a footer to the chart.
void setCoordinatePlaneLayout(QLayout *layout)
Set the coordinate plane layout that should be used as model for the internal used layout...
Base class for diagrams based on a cartesian coordianate system.
PositionValue
Numerical values of the static KDChart::Position instances, for using a Position::value() with a swit...
AbstractCoordinatePlane * referenceCoordinatePlane() const
There are two ways, in which planes can be caused to interact, in where they are put layouting wise: ...
virtual const Position position() const
void mouseDoubleClickEvent(QMouseEvent *event) override
reimp
bool useNewLayoutSystem() const
useNewLayoutSystem Be very careful activating the new layout system, its still experimental and works...
TextAttributes textAttributes() const
int globalLeadingLeft() const
The padding between the start of the widget and the start of the area that is used for drawing on the...
const RelativePosition floatingPosition() const
Returns the position of a floating legend.
void setRelativeMode(const QObject *area, KDChartEnums::MeasureOrientation orientation)
The reference area must either be derived from AbstractArea or from QWidget, so it can also be derive...
Measure is used to specify relative and absolute sizes in KDChart, e.g.
void addCoordinatePlane(AbstractCoordinatePlane *plane)
Adds a coordinate plane to the chart.
void resizeEvent(QResizeEvent *event) override
Adjusts the internal layout when the chart is resized.
void replaceLegend(Legend *legend, Legend *oldLegend=0)
Replaces the old legend, or appends the new legend, it there is none yet.
HeaderFooterList headerFooters()
The list of headers and footers associated with the chart.
Defines relative position information: reference area, position in this area (reference position)...
virtual void mouseDoubleClickEvent(QMouseEvent *event)
Cartesian coordinate plane.
void setBackgroundAttributes(const BackgroundAttributes &a)
Specify the background attributes to be used, by default there is no background.
void setParentLayout(QLayout *lay)
void setGlobalLeadingLeft(int leading)
Set the padding between the start of the widget and the start of the area that is used for drawing on...
AbstractDiagramList diagrams()
Qt::Alignment alignment() const
Returns the alignment of a non-floating legend.
int globalLeadingTop() const
The padding between the start of the widget and the start of the area that is used for drawing at the...
QModelIndexList indexesIn(const QRect &rect) const
Legend * legend()
The first legend of the chart or 0 if there was none added to the chart.
void propertiesChanged()
Emitted upon change of a property of the Chart or any of its components.
static void setFactors(qreal factorX, qreal factorY)
Set new factors to be used by all Measure objects from now on.
void setGlobalLeading(int left, int top, int right, int bottom)
Set the padding between the margin of the widget and the area that the contents are drawn into...
int globalLeadingRight() const
The padding between the start of the widget and the start of the area that is used for drawing on the...
void setGridNeedsRecalculate()
Used by the chart to clear the cached grid data.
QModelIndex indexAt(const QPoint &point) const override
[reimplemented]
AbstractCoordinatePlane * coordinatePlane()
Each chart must have at least one coordinate plane.
A set of text attributes.
QList< AbstractCoordinatePlane * > CoordinatePlaneList
Set of attributes usable for background pixmaps.
void mousePressEvent(QMouseEvent *event) override
reimp
void paintEvent(QPaintEvent *event) override
Draws the background and frame, then calls paint().
virtual void mousePressEvent(QMouseEvent *event)