00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "KDChartChart.h"
00027 #include "KDChartChart_p.h"
00028
00029 #include <QList>
00030 #include <QtDebug>
00031 #include <QGridLayout>
00032 #include <QLabel>
00033 #include <QHash>
00034 #include <QToolTip>
00035 #include <QPainter>
00036 #include <QPaintEvent>
00037 #include <QLayoutItem>
00038 #include <QPushButton>
00039 #include <QApplication>
00040 #include <QEvent>
00041
00042 #include "KDChartCartesianCoordinatePlane.h"
00043 #include "KDChartAbstractCartesianDiagram.h"
00044 #include "KDChartHeaderFooter.h"
00045 #include "KDChartEnums.h"
00046 #include "KDChartLegend.h"
00047 #include "KDChartLayoutItems.h"
00048 #include <KDChartTextAttributes.h>
00049 #include <KDChartMarkerAttributes>
00050 #include "KDChartPainterSaver_p.h"
00051 #include "KDChartPrintingParameters.h"
00052
00053 #include <KDABLibFakes>
00054
00055 #define SET_ALL_MARGINS_TO_ZERO
00056
00057
00058 class MyWidgetItem : public QWidgetItem
00059 {
00060 public:
00061 explicit MyWidgetItem(QWidget *w, Qt::Alignment alignment = 0)
00062 : QWidgetItem(w) {
00063 setAlignment( alignment );
00064 }
00065 bool isEmpty() const {
00066 QWidget* w = const_cast<MyWidgetItem *>(this)->widget();
00067
00068
00069
00070 return w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide);
00071 }
00072 };
00073
00074 using namespace KDChart;
00075
00076 void Chart::Private::slotUnregisterDestroyedLegend( Legend *l )
00077 {
00078 legends.removeAll( l );
00079 slotRelayout();
00080 }
00081
00082 void Chart::Private::slotUnregisterDestroyedHeaderFooter( HeaderFooter* hf )
00083 {
00084 headerFooters.removeAll( hf );
00085 hf->removeFromParentLayout();
00086 textLayoutItems.remove( textLayoutItems.indexOf( hf ) );
00087 slotRelayout();
00088 }
00089
00090 void Chart::Private::slotUnregisterDestroyedPlane( AbstractCoordinatePlane* plane )
00091 {
00092 coordinatePlanes.removeAll( plane );
00093 Q_FOREACH ( AbstractCoordinatePlane* p, coordinatePlanes )
00094 {
00095 if ( p->referenceCoordinatePlane() == plane) {
00096 p->setReferenceCoordinatePlane(0);
00097 }
00098 }
00099 plane->layoutPlanes();
00100 }
00101
00102 Chart::Private::Private( Chart* chart_ )
00103 : chart( chart_ )
00104 , layout( 0 )
00105 , vLayout( 0 )
00106 , planesLayout( 0 )
00107 , headerLayout( 0 )
00108 , footerLayout( 0 )
00109 , dataAndLegendLayout( 0 )
00110 , globalLeadingLeft( 0 )
00111 , globalLeadingRight( 0 )
00112 , globalLeadingTop( 0 )
00113 , globalLeadingBottom( 0 )
00114 {
00115 for( int row = 0; row < 3; ++row )
00116 {
00117 for( int column = 0; column < 3; ++column )
00118 {
00119 dummyHeaders[ row ][ column ] = HorizontalLineLayoutItem();
00120 dummyFooters[ row ][ column ] = HorizontalLineLayoutItem();
00121 innerHdFtLayouts[0][row][column] = 0;
00122 innerHdFtLayouts[1][row][column] = 0;
00123 }
00124 }
00125 }
00126
00127 Chart::Private::~Private()
00128 {
00129 removeDummyHeaderFooters();
00130 }
00131
00132 void Chart::Private::removeDummyHeaderFooters()
00133 {
00134 for ( int row = 0; row < 3; ++row )
00135 {
00136 for ( int column = 0; column < 3; ++ column )
00137 {
00138 if( innerHdFtLayouts[0][row][column] ){
00139 innerHdFtLayouts[0][row][column]->removeItem( &(dummyHeaders[row][column]) );
00140 innerHdFtLayouts[1][row][column]->removeItem( &(dummyFooters[row][column]) );
00141 }
00142 }
00143 }
00144 }
00145
00146 void Chart::Private::layoutHeadersAndFooters()
00147 {
00148 removeDummyHeaderFooters();
00149
00150 bool headersLineFilled[] = { false, false, false };
00151 bool footersLineFilled[] = { false, false, false };
00152
00153 Q_FOREACH( HeaderFooter *hf, headerFooters ) {
00154
00155
00156 int innerLayoutIdx;
00157 switch( hf->type() ){
00158 case HeaderFooter::Header:
00159 innerLayoutIdx = 0;
00160 break;
00161 case HeaderFooter::Footer:
00162 innerLayoutIdx = 1;
00163 break;
00164 default:
00165 Q_ASSERT( false );
00166 break;
00167 };
00168
00169 if( hf->position() != Position::Unknown ) {
00170 int row, column;
00171 Qt::Alignment hAlign, vAlign;
00172 if( hf->position().isNorthSide() ){
00173 row = 0;
00174 vAlign = Qt::AlignTop;
00175 }
00176 else if( hf->position().isSouthSide() ){
00177 row = 2;
00178 vAlign = Qt::AlignBottom;
00179 }
00180 else{
00181 row = 1;
00182 vAlign = Qt::AlignVCenter;
00183 }
00184 if( hf->position().isWestSide() ){
00185 column = 0;
00186 hAlign = Qt::AlignLeft;
00187 }
00188 else if( hf->position().isEastSide() ){
00189 column = 2;
00190 hAlign = Qt::AlignRight;
00191 }
00192 else{
00193 column = 1;
00194 hAlign = Qt::AlignHCenter;
00195 }
00196 switch( hf->type() ){
00197 case HeaderFooter::Header:
00198 if( !headersLineFilled[ row ] )
00199 {
00200 for( int col = 0; col < 3; ++col )
00201 innerHdFtLayouts[0][row][col]->addItem( &(dummyHeaders[ row ][ col ]) );
00202 headersLineFilled[ row ] = true;
00203 }
00204 break;
00205 case HeaderFooter::Footer:
00206 if( !footersLineFilled[ row ] )
00207 {
00208 for( int col = 0; col < 3; ++col )
00209 innerHdFtLayouts[1][row][col]->addItem( &(dummyFooters[ row ][ col ]) );
00210 footersLineFilled[ row ] = true;
00211 }
00212 break;
00213 };
00214 textLayoutItems << hf;
00215 QVBoxLayout* headerFooterLayout = innerHdFtLayouts[innerLayoutIdx][row][column];
00216 hf->setParentLayout( headerFooterLayout );
00217 hf->setAlignment( hAlign | vAlign );
00218 headerFooterLayout->addItem( hf );
00219 }
00220 else{
00221 qDebug( "Unknown header/footer position" );
00222 }
00223 }
00224 }
00225
00226 void Chart::Private::layoutLegends()
00227 {
00228
00229
00230
00231
00232 QList<Legend*> infos[3][3];
00233
00234 Q_FOREACH( Legend *legend, legends ) {
00235
00236 legend->needSizeHint();
00237
00238 bool bOK = true;
00239 int row, column;
00240
00241 switch( legend->position().value() ) {
00242 case KDChartEnums::PositionNorthWest: row = 0; column = 0;
00243 break;
00244 case KDChartEnums::PositionNorth: row = 0; column = 1;
00245 break;
00246 case KDChartEnums::PositionNorthEast: row = 0; column = 2;
00247 break;
00248 case KDChartEnums::PositionEast: row = 1; column = 2;
00249 break;
00250 case KDChartEnums::PositionSouthEast: row = 2; column = 2;
00251 break;
00252 case KDChartEnums::PositionSouth: row = 2; column = 1;
00253 break;
00254 case KDChartEnums::PositionSouthWest: row = 2; column = 0;
00255 break;
00256 case KDChartEnums::PositionWest: row = 1; column = 0;
00257 break;
00258 case KDChartEnums::PositionCenter:
00259 qDebug( "Sorry: Legend not shown, because position Center is not supported." );
00260 bOK = false;
00261 break;
00262 case KDChartEnums::PositionFloating:
00263 bOK = false;
00264 break;
00265 default:
00266 qDebug( "Sorry: Legend not shown, because of unknown legend position." );
00267 bOK = false;
00268 break;
00269 }
00270 if( bOK )
00271 infos[row][column] << legend;
00272 }
00273
00274
00275 for (int iR = 0; iR < 3; ++iR) {
00276 for (int iC = 0; iC < 3; ++iC) {
00277 QList<Legend*>& list = infos[iR][iC];
00278 const int count = list.size();
00279 switch( count ){
00280 case 0:
00281 break;
00282 case 1: {
00283 Legend* legend = list.first();
00284 dataAndLegendLayout->addItem( new MyWidgetItem(legend),
00285 iR, iC, 1, 1, legend->alignment() );
00286 }
00287 break;
00288 default: {
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 Legend* legend = list.first();
00301 Qt::Alignment alignment = legend->alignment();
00302 bool haveSameAlign = true;
00303 for (int i = 1; i < count; ++i) {
00304 legend = list.at(i);
00305 if( alignment != legend->alignment() ){
00306 haveSameAlign = false;
00307 break;
00308 }
00309 }
00310 if( haveSameAlign ){
00311 QVBoxLayout* vLayout = new QVBoxLayout();
00312 #if defined SET_ALL_MARGINS_TO_ZERO
00313 vLayout->setMargin(0);
00314 #endif
00315 for (int i = 0; i < count; ++i) {
00316 vLayout->addItem( new MyWidgetItem(list.at(i), Qt::AlignLeft) );
00317 }
00318 dataAndLegendLayout->addLayout( vLayout, iR, iC, 1, 1, alignment );
00319 }else{
00320 QGridLayout* gridLayout = new QGridLayout();
00321 #if defined SET_ALL_MARGINS_TO_ZERO
00322 gridLayout->setMargin(0);
00323 #endif
00324
00325
00326 #define ADD_VBOX_WITH_LEGENDS(row, column, align) \
00327 { \
00328 QVBoxLayout* innerLayout = new QVBoxLayout(); \
00329 for (int i = 0; i < count; ++i) { \
00330 legend = list.at(i); \
00331 if( legend->alignment() == ( align ) ) \
00332 innerLayout->addItem( new MyWidgetItem(legend, Qt::AlignLeft) ); \
00333 } \
00334 gridLayout->addLayout( innerLayout, row, column, ( align ) ); \
00335 }
00336 ADD_VBOX_WITH_LEGENDS( 0, 0, Qt::AlignTop | Qt::AlignLeft )
00337 ADD_VBOX_WITH_LEGENDS( 0, 1, Qt::AlignTop | Qt::AlignHCenter )
00338 ADD_VBOX_WITH_LEGENDS( 0, 2, Qt::AlignTop | Qt::AlignRight )
00339
00340 ADD_VBOX_WITH_LEGENDS( 1, 0, Qt::AlignVCenter | Qt::AlignLeft )
00341 ADD_VBOX_WITH_LEGENDS( 1, 1, Qt::AlignCenter )
00342 ADD_VBOX_WITH_LEGENDS( 1, 2, Qt::AlignVCenter | Qt::AlignRight )
00343
00344 ADD_VBOX_WITH_LEGENDS( 2, 0, Qt::AlignBottom | Qt::AlignLeft )
00345 ADD_VBOX_WITH_LEGENDS( 2, 1, Qt::AlignBottom | Qt::AlignHCenter )
00346 ADD_VBOX_WITH_LEGENDS( 2, 2, Qt::AlignBottom | Qt::AlignRight )
00347
00348 dataAndLegendLayout->addLayout( gridLayout, iR, iC, 1, 1 );
00349 }
00350 }
00351 }
00352 }
00353 }
00354
00355 }
00356
00357
00358 QHash<AbstractCoordinatePlane*, PlaneInfo> Chart::Private::buildPlaneLayoutInfos()
00359 {
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372 QHash<CartesianAxis*, AxisInfo> axisInfos;
00373 QHash<AbstractCoordinatePlane*, PlaneInfo> planeInfos;
00374 Q_FOREACH(AbstractCoordinatePlane* plane, coordinatePlanes )
00375 {
00376 PlaneInfo p;
00377
00378 p.referencePlane = plane->referenceCoordinatePlane();
00379 planeInfos.insert( plane, p );
00380
00381 Q_FOREACH( AbstractDiagram* abstractDiagram, plane->diagrams() ) {
00382 AbstractCartesianDiagram* diagram =
00383 dynamic_cast<AbstractCartesianDiagram*> ( abstractDiagram );
00384 if( !diagram ) continue;
00385
00386 Q_FOREACH( CartesianAxis* axis, diagram->axes() ) {
00387 if ( !axisInfos.contains( axis ) ) {
00388
00389
00390
00391
00392 AxisInfo i;
00393 i.plane = plane;
00394 axisInfos.insert( axis, i );
00395 } else {
00396 AxisInfo i = axisInfos[axis];
00397 if ( i.plane == plane ) continue;
00398
00399
00400
00401
00402 PlaneInfo pi = planeInfos[plane];
00403
00404 if ( !pi.referencePlane ) {
00405
00406 pi.referencePlane = i.plane;
00407 if ( axis->position() == CartesianAxis::Left
00408 || axis->position() == CartesianAxis::Right )
00409 pi.horizontalOffset += 1;
00410 planeInfos[plane] = pi;
00411
00412 pi = planeInfos[i.plane];
00413 if ( axis->position() == CartesianAxis::Top
00414 || axis->position() == CartesianAxis::Bottom )
00415 pi.verticalOffset += 1;
00416
00417 planeInfos[i.plane] = pi;
00418 }
00419 }
00420 }
00421 }
00422
00423 p = planeInfos[plane];
00424 if ( p.referencePlane == 0 ) {
00425 p.gridLayout = new QGridLayout();
00426
00427 #if defined SET_ALL_MARGINS_TO_ZERO
00428 p.gridLayout->setMargin(0);
00429 #endif
00430 planeInfos[plane] = p;
00431 }
00432 }
00433 return planeInfos;
00434 }
00435
00436 template <typename T>
00437 static T* findOrCreateLayoutByObjectName( QLayout * parentLayout, const char* name )
00438 {
00439 T *box = qFindChild<T*>( parentLayout, QString::fromLatin1( name ) );
00440 if ( !box ) {
00441 box = new T();
00442
00443 #if defined SET_ALL_MARGINS_TO_ZERO
00444 box->setMargin(0);
00445 #endif
00446 box->setObjectName( QString::fromLatin1( name ) );
00447 box->setSizeConstraint( QLayout::SetFixedSize );
00448 }
00449 return box;
00450 }
00451
00452 #if 0
00453 static QVBoxLayout* findOrCreateVBoxLayoutByObjectName( QLayout* parentLayout, const char* name )
00454 {
00455 return findOrCreateLayoutByObjectName<QVBoxLayout>( parentLayout, name );
00456 }
00457
00458 static QHBoxLayout* findOrCreateHBoxLayoutByObjectName( QLayout* parentLayout, const char* name )
00459 {
00460 return findOrCreateLayoutByObjectName<QHBoxLayout>( parentLayout, name );
00461 }
00462 #endif
00463
00464 void Chart::Private::slotLayoutPlanes()
00465 {
00466
00467 const QBoxLayout::Direction oldPlanesDirection =
00468 planesLayout ? planesLayout->direction() : QBoxLayout::TopToBottom;
00469 if ( planesLayout && dataAndLegendLayout )
00470 dataAndLegendLayout->removeItem( planesLayout );
00471
00472 KDAB_FOREACH( KDChart::AbstractLayoutItem* plane, planeLayoutItems ) {
00473 plane->removeFromParentLayout();
00474 }
00475 planeLayoutItems.clear();
00476 delete planesLayout;
00477
00478
00479 planesLayout = new QBoxLayout( oldPlanesDirection );
00480
00481
00482 #if defined SET_ALL_MARGINS_TO_ZERO
00483 planesLayout->setMargin(0);
00484 planesLayout->setSpacing(0);
00485 #endif
00486 planesLayout->setObjectName( QString::fromLatin1( "planesLayout" ) );
00487
00488
00489
00490
00491 QHash<AbstractCoordinatePlane*, PlaneInfo> planeInfos = buildPlaneLayoutInfos();
00492 QHash<AbstractAxis*, AxisInfo> axisInfos;
00493 KDAB_FOREACH( AbstractCoordinatePlane* plane, coordinatePlanes ) {
00494 Q_ASSERT( planeInfos.contains(plane) );
00495 PlaneInfo& pi = planeInfos[ plane ];
00496 int column = pi.horizontalOffset;
00497 int row = pi.verticalOffset;
00498
00499 QGridLayout *planeLayout = pi.gridLayout;
00500 if ( !planeLayout ) {
00501
00502
00503 planeLayout = planeInfos[pi.referencePlane].gridLayout;
00504 } else {
00505 planesLayout->addLayout( planeLayout );
00506 }
00507 Q_ASSERT( planeLayout );
00508
00509
00510
00511 planeLayoutItems << plane;
00512 plane->setParentLayout( planeLayout );
00513 planeLayout->addItem( plane, row, column, 1, 1, 0 );
00514
00515 planeLayout->setRowStretch( row, 2 );
00516 planeLayout->setColumnStretch( column, 2 );
00517
00518 KDAB_FOREACH( AbstractDiagram* abstractDiagram, plane->diagrams() )
00519 {
00520 AbstractCartesianDiagram* diagram =
00521 dynamic_cast<AbstractCartesianDiagram*> ( abstractDiagram );
00522
00523 if( !diagram ) continue;
00524
00525
00526 if( pi.referencePlane != 0 )
00527 {
00528 pi.topAxesLayout = planeInfos[ pi.referencePlane ].topAxesLayout;
00529 pi.bottomAxesLayout = planeInfos[ pi.referencePlane ].bottomAxesLayout;
00530 pi.leftAxesLayout = planeInfos[ pi.referencePlane ].leftAxesLayout;
00531 pi.rightAxesLayout = planeInfos[ pi.referencePlane ].rightAxesLayout;
00532 }
00533
00534
00535 if( pi.topAxesLayout == 0 )
00536 {
00537 pi.topAxesLayout = new QVBoxLayout;
00538 #if defined SET_ALL_MARGINS_TO_ZERO
00539 pi.topAxesLayout->setMargin(0);
00540 #endif
00541 pi.topAxesLayout->setObjectName( QString::fromLatin1( "topAxesLayout" ) );
00542 }
00543 if( pi.bottomAxesLayout == 0 )
00544 {
00545 pi.bottomAxesLayout = new QVBoxLayout;
00546 #if defined SET_ALL_MARGINS_TO_ZERO
00547 pi.bottomAxesLayout->setMargin(0);
00548 #endif
00549 pi.bottomAxesLayout->setObjectName( QString::fromLatin1( "bottomAxesLayout" ) );
00550 }
00551 if( pi.leftAxesLayout == 0 )
00552 {
00553 pi.leftAxesLayout = new QHBoxLayout;
00554 #if defined SET_ALL_MARGINS_TO_ZERO
00555 pi.leftAxesLayout->setMargin(0);
00556 #endif
00557 pi.leftAxesLayout->setObjectName( QString::fromLatin1( "leftAxesLayout" ) );
00558 }
00559 if( pi.rightAxesLayout == 0 )
00560 {
00561 pi.rightAxesLayout = new QHBoxLayout;
00562 #if defined SET_ALL_MARGINS_TO_ZERO
00563 pi.rightAxesLayout->setMargin(0);
00564 #endif
00565 pi.rightAxesLayout->setObjectName( QString::fromLatin1( "rightAxesLayout" ) );
00566 }
00567
00568 if( pi.referencePlane != 0 )
00569 {
00570 planeInfos[ pi.referencePlane ].topAxesLayout = pi.topAxesLayout;
00571 planeInfos[ pi.referencePlane ].bottomAxesLayout = pi.bottomAxesLayout;
00572 planeInfos[ pi.referencePlane ].leftAxesLayout = pi.leftAxesLayout;
00573 planeInfos[ pi.referencePlane ].rightAxesLayout = pi.rightAxesLayout;
00574 }
00575
00576
00577
00578 KDAB_FOREACH( CartesianAxis* axis, diagram->axes() ) {
00579 if ( axisInfos.contains( axis ) ) continue;
00580 Q_ASSERT ( axis );
00581 axis->setCachedSizeDirty();
00582
00583 planeLayoutItems << axis;
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 switch ( axis->position() )
00598 {
00599 case CartesianAxis::Top:
00600 axis->setParentLayout( pi.topAxesLayout );
00601 pi.topAxesLayout->addItem( axis );
00602 break;
00603 case CartesianAxis::Bottom:
00604 axis->setParentLayout( pi.bottomAxesLayout );
00605 pi.bottomAxesLayout->addItem( axis );
00606 break;
00607 case CartesianAxis::Left:
00608 axis->setParentLayout( pi.leftAxesLayout );
00609 pi.leftAxesLayout->addItem( axis );
00610 break;
00611 case CartesianAxis::Right:
00612 axis->setParentLayout( pi.rightAxesLayout );
00613 pi.rightAxesLayout->addItem( axis );
00614 break;
00615 default:
00616 Q_ASSERT_X( false, "Chart::paintEvent",
00617 "unknown axis position" );
00618 break;
00619 };
00620 axisInfos.insert( axis, AxisInfo() );
00621 }
00622
00623
00624
00625
00626 if ( !pi.topAxesLayout->parent() )
00627 planeLayout->addLayout( pi.topAxesLayout, row - 1, column );
00628 if ( !pi.bottomAxesLayout->parent() )
00629 planeLayout->addLayout( pi.bottomAxesLayout, row + 1, column );
00630 if ( !pi.leftAxesLayout->parent() ){
00631 planeLayout->addLayout( pi.leftAxesLayout, row, column - 1);
00632
00633
00634 }
00635 if ( !pi.rightAxesLayout->parent() )
00636 planeLayout->addLayout( pi.rightAxesLayout, row, column + 1);
00637 }
00638
00639
00640 #define ADD_AUTO_SPACER_IF_NEEDED( \
00641 spacerRow, spacerColumn, hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout ) \
00642 { \
00643 if( hLayout || vLayout ) { \
00644 AutoSpacerLayoutItem * spacer \
00645 = new AutoSpacerLayoutItem( hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout ); \
00646 planeLayout->addItem( spacer, spacerRow, spacerColumn, 1, 1 ); \
00647 spacer->setParentLayout( planeLayout ); \
00648 planeLayoutItems << spacer; \
00649 } \
00650 }
00651 ADD_AUTO_SPACER_IF_NEEDED( row-1, column-1, false, pi.leftAxesLayout, false, pi.topAxesLayout )
00652 ADD_AUTO_SPACER_IF_NEEDED( row+1, column-1, true, pi.leftAxesLayout, false, pi.bottomAxesLayout )
00653 ADD_AUTO_SPACER_IF_NEEDED( row-1, column+1, false, pi.rightAxesLayout, true, pi.topAxesLayout )
00654 ADD_AUTO_SPACER_IF_NEEDED( row+1, column+1, true, pi.rightAxesLayout, true, pi.bottomAxesLayout )
00655 }
00656
00657 if ( dataAndLegendLayout ){
00658 dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
00659 dataAndLegendLayout->setRowStretch( 1, 1000 );
00660 dataAndLegendLayout->setColumnStretch( 1, 1000 );
00661 }
00662
00663 slotRelayout();
00664
00665 }
00666
00667 void Chart::Private::createLayouts( QWidget* w )
00668 {
00669 KDAB_FOREACH( KDChart::TextArea* textLayoutItem, textLayoutItems ) {
00670 textLayoutItem->removeFromParentLayout();
00671 }
00672 textLayoutItems.clear();
00673
00674 KDAB_FOREACH( KDChart::AbstractArea* layoutItem, layoutItems ) {
00675 layoutItem->removeFromParentLayout();
00676 }
00677 layoutItems.clear();
00678
00679 removeDummyHeaderFooters();
00680
00681
00682 if ( dataAndLegendLayout) {
00683 dataAndLegendLayout->removeItem( planesLayout );
00684 planesLayout->setParent( 0 );
00685 }
00686
00687 delete layout;
00688
00689
00690 layout = new QHBoxLayout( w );
00691
00692 #if defined SET_ALL_MARGINS_TO_ZERO
00693 layout->setMargin(0);
00694 #endif
00695 layout->setObjectName( QString::fromLatin1( "Chart::Private::layout" ) );
00696 layout->addSpacing( globalLeadingLeft );
00697
00698
00699
00700 vLayout = new QVBoxLayout();
00701
00702 #if defined SET_ALL_MARGINS_TO_ZERO
00703 vLayout->setMargin(0);
00704 #endif
00705 vLayout->setObjectName( QString::fromLatin1( "vLayout" ) );
00706 layout->addLayout( vLayout, 1000 );
00707 layout->addSpacing( globalLeadingRight );
00708
00709
00710
00711
00712 vLayout->addSpacing( globalLeadingTop );
00713
00714 headerLayout = new QGridLayout();
00715
00716 #if defined SET_ALL_MARGINS_TO_ZERO
00717 headerLayout->setMargin(0);
00718 #endif
00719 vLayout->addLayout( headerLayout );
00720
00721 dataAndLegendLayout = new QGridLayout();
00722
00723 #if defined SET_ALL_MARGINS_TO_ZERO
00724 dataAndLegendLayout->setMargin(0);
00725 #endif
00726 dataAndLegendLayout->setObjectName( QString::fromLatin1( "dataAndLegendLayout" ) );
00727 vLayout->addLayout( dataAndLegendLayout, 1000 );
00728
00729 footerLayout = new QGridLayout();
00730
00731 #if defined SET_ALL_MARGINS_TO_ZERO
00732 footerLayout->setMargin(0);
00733 #endif
00734 footerLayout->setObjectName( QString::fromLatin1( "footerLayout" ) );
00735 vLayout->addLayout( footerLayout );
00736
00737
00738
00739
00740
00741 static const Qt::Alignment hdFtAlignments[3][3] = {
00742 { Qt::AlignTop | Qt::AlignLeft, Qt::AlignTop | Qt::AlignHCenter, Qt::AlignTop | Qt::AlignRight },
00743 { Qt::AlignVCenter | Qt::AlignLeft, Qt::AlignVCenter | Qt::AlignHCenter, Qt::AlignVCenter | Qt::AlignRight },
00744 { Qt::AlignBottom | Qt::AlignLeft, Qt::AlignBottom | Qt::AlignHCenter, Qt::AlignBottom | Qt::AlignRight }
00745 };
00746 for ( int row = 0; row < 3; ++row )
00747 {
00748 for ( int column = 0; column < 3; ++ column )
00749 {
00750 QVBoxLayout* innerHdLayout = new QVBoxLayout();
00751 QVBoxLayout* innerFtLayout = new QVBoxLayout();
00752 innerHdFtLayouts[0][row][column] = innerHdLayout;
00753 innerHdFtLayouts[1][row][column] = innerFtLayout;
00754 #if defined SET_ALL_MARGINS_TO_ZERO
00755 innerHdLayout->setMargin(0);
00756 innerFtLayout->setMargin(0);
00757 #endif
00758 const Qt::Alignment align = hdFtAlignments[row][column];
00759 innerHdLayout->setAlignment( align );
00760 innerFtLayout->setAlignment( align );
00761 headerLayout->addLayout( innerHdLayout, row, column, align );
00762 footerLayout->addLayout( innerFtLayout, row, column, align );
00763 }
00764 }
00765
00766
00767 vLayout->addSpacing( globalLeadingBottom );
00768
00769
00770 dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
00771 dataAndLegendLayout->setRowStretch( 1, 1 );
00772 dataAndLegendLayout->setColumnStretch( 1, 1 );
00773
00774
00775 }
00776
00777 void Chart::Private::slotRelayout()
00778 {
00779
00780 createLayouts( chart );
00781
00782 layoutHeadersAndFooters();
00783 layoutLegends();
00784
00785
00786
00787
00788 const QRect geo( QRect( 0, 0, currentLayoutSize.width(), currentLayoutSize.height() ) );
00789 if( geo.isValid() && geo != layout->geometry() ){
00790
00791
00792
00793 layout->setGeometry( geo );
00794
00795
00796
00797 }
00798
00799
00800 KDAB_FOREACH (AbstractCoordinatePlane* plane, coordinatePlanes ) {
00801 plane->layoutDiagrams();
00802 }
00803
00804 }
00805
00806
00807
00808
00809 void Chart::Private::resizeLayout( const QSize& size )
00810 {
00811 currentLayoutSize = size;
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 slotLayoutPlanes();
00828
00829
00830 }
00831
00832
00833 void Chart::Private::paintAll( QPainter* painter )
00834 {
00835 QRect rect( QPoint(0, 0), currentLayoutSize );
00836
00837
00838
00839
00840 KDChart::AbstractAreaBase::paintBackgroundAttributes(
00841 *painter, rect, backgroundAttributes );
00842
00843 KDChart::AbstractAreaBase::paintFrameAttributes(
00844 *painter, rect, frameAttributes );
00845
00846 chart->reLayoutFloatingLegends();
00847
00848 KDAB_FOREACH( KDChart::AbstractArea* layoutItem, layoutItems ) {
00849 layoutItem->paintAll( *painter );
00850 }
00851 KDAB_FOREACH( KDChart::AbstractLayoutItem* planeLayoutItem, planeLayoutItems ) {
00852 planeLayoutItem->paintAll( *painter );
00853 }
00854 KDAB_FOREACH( KDChart::TextArea* textLayoutItem, textLayoutItems ) {
00855 textLayoutItem->paintAll( *painter );
00856 }
00857 }
00858
00859
00860
00861 Chart::Chart ( QWidget* parent )
00862 : QWidget ( parent )
00863 , _d( new Private( this ) )
00864 {
00865 FrameAttributes frameAttrs;
00866
00867
00868 frameAttrs.setPen( QPen( Qt::black ) );
00869 frameAttrs.setPadding( 1 );
00870 setFrameAttributes( frameAttrs );
00871
00872 addCoordinatePlane( new CartesianCoordinatePlane ( this ) );
00873 }
00874
00875 Chart::~Chart()
00876 {
00877 delete _d;
00878 }
00879
00880 #define d d_func()
00881
00882 void Chart::setFrameAttributes( const FrameAttributes &a )
00883 {
00884 d->frameAttributes = a;
00885 }
00886
00887 FrameAttributes Chart::frameAttributes() const
00888 {
00889 return d->frameAttributes;
00890 }
00891
00892 void Chart::setBackgroundAttributes( const BackgroundAttributes &a )
00893 {
00894 d->backgroundAttributes = a;
00895 }
00896
00897 BackgroundAttributes Chart::backgroundAttributes() const
00898 {
00899 return d->backgroundAttributes;
00900 }
00901
00902
00903 void Chart::setCoordinatePlaneLayout( QLayout * layout )
00904 {
00905 delete d->planesLayout;
00906 d->planesLayout = dynamic_cast<QBoxLayout*>( layout );
00907 d->slotLayoutPlanes();
00908 }
00909
00910 QLayout* Chart::coordinatePlaneLayout()
00911 {
00912 return d->planesLayout;
00913 }
00914
00915 AbstractCoordinatePlane* Chart::coordinatePlane()
00916 {
00917 if ( d->coordinatePlanes.isEmpty() )
00918 {
00919 qWarning() << "Chart::coordinatePlane: warning: no coordinate plane defined.";
00920 return 0;
00921 } else {
00922 return d->coordinatePlanes.first();
00923 }
00924 }
00925
00926 CoordinatePlaneList Chart::coordinatePlanes()
00927 {
00928 return d->coordinatePlanes;
00929 }
00930
00931 void Chart::addCoordinatePlane( AbstractCoordinatePlane* plane )
00932 {
00933 connect( plane, SIGNAL( destroyedCoordinatePlane( AbstractCoordinatePlane* ) ),
00934 d, SLOT( slotUnregisterDestroyedPlane( AbstractCoordinatePlane* ) ) );
00935 connect( plane, SIGNAL( needUpdate() ), this, SLOT( update() ) );
00936 connect( plane, SIGNAL( needRelayout() ), d, SLOT( slotRelayout() ) ) ;
00937 connect( plane, SIGNAL( needLayoutPlanes() ), d, SLOT( slotLayoutPlanes() ) ) ;
00938 connect( plane, SIGNAL( propertiesChanged() ),this, SIGNAL( propertiesChanged() ) );
00939 d->coordinatePlanes.append( plane );
00940 plane->setParent( this );
00941 d->slotLayoutPlanes();
00942 }
00943
00944 void Chart::replaceCoordinatePlane( AbstractCoordinatePlane* plane,
00945 AbstractCoordinatePlane* oldPlane_ )
00946 {
00947 if( plane && oldPlane_ != plane ){
00948 AbstractCoordinatePlane* oldPlane = oldPlane_;
00949 if( d->coordinatePlanes.count() ){
00950 if( ! oldPlane ){
00951 oldPlane = d->coordinatePlanes.first();
00952 if( oldPlane == plane )
00953 return;
00954 }
00955 takeCoordinatePlane( oldPlane );
00956 }
00957 delete oldPlane;
00958 addCoordinatePlane( plane );
00959 }
00960 }
00961
00962 void Chart::takeCoordinatePlane( AbstractCoordinatePlane* plane )
00963 {
00964 const int idx = d->coordinatePlanes.indexOf( plane );
00965 if( idx != -1 ){
00966 d->coordinatePlanes.takeAt( idx );
00967 disconnect( plane, SIGNAL( destroyedCoordinatePlane( AbstractCoordinatePlane* ) ),
00968 d, SLOT( slotUnregisterDestroyedPlane( AbstractCoordinatePlane* ) ) );
00969 plane->removeFromParentLayout();
00970 plane->setParent( 0 );
00971 }
00972 d->slotLayoutPlanes();
00973
00974
00975 emit propertiesChanged();
00976 }
00977
00978 void Chart::setGlobalLeading( int left, int top, int right, int bottom )
00979 {
00980 setGlobalLeadingLeft( left );
00981 setGlobalLeadingTop( top );
00982 setGlobalLeadingRight( right );
00983 setGlobalLeadingBottom( bottom );
00984 d->slotRelayout();
00985 }
00986
00987 void Chart::setGlobalLeadingLeft( int leading )
00988 {
00989 d->globalLeadingLeft = leading;
00990 d->slotRelayout();
00991 }
00992
00993 int Chart::globalLeadingLeft() const
00994 {
00995 return d->globalLeadingLeft;
00996 }
00997
00998 void Chart::setGlobalLeadingTop( int leading )
00999 {
01000 d->globalLeadingTop = leading;
01001 d->slotRelayout();
01002 }
01003
01004 int Chart::globalLeadingTop() const
01005 {
01006 return d->globalLeadingTop;
01007 }
01008
01009 void Chart::setGlobalLeadingRight( int leading )
01010 {
01011 d->globalLeadingRight = leading;
01012 d->slotRelayout();
01013 }
01014
01015 int Chart::globalLeadingRight() const
01016 {
01017 return d->globalLeadingRight;
01018 }
01019
01020 void Chart::setGlobalLeadingBottom( int leading )
01021 {
01022 d->globalLeadingBottom = leading;
01023 d->slotRelayout();
01024 }
01025
01026 int Chart::globalLeadingBottom() const
01027 {
01028 return d->globalLeadingBottom;
01029 }
01030
01031 void Chart::paint( QPainter* painter, const QRect& target )
01032 {
01033 if( target.isEmpty() || !painter ) return;
01034
01035
01036 QPaintDevice* prevDevice = GlobalMeasureScaling::paintDevice();
01037 GlobalMeasureScaling::setPaintDevice( painter->device() );
01038
01039
01040 if( dynamic_cast< QWidget* >( painter->device() ) != 0 )
01041 {
01042 GlobalMeasureScaling::setFactors(
01043 static_cast< qreal >( target.width() ) /
01044 static_cast< qreal >( geometry().size().width() ),
01045 static_cast< qreal >( target.height() ) /
01046 static_cast< qreal >( geometry().size().height() ) );
01047 }
01048
01049 else
01050 {
01051 PrintingParameters::setScaleFactor( static_cast< qreal >( painter->device()->logicalDpiX() ) / static_cast< qreal >( logicalDpiX() ) );
01052
01053 const qreal resX = static_cast< qreal >( logicalDpiX() ) / static_cast< qreal >( painter->device()->logicalDpiX() );
01054 const qreal resY = static_cast< qreal >( logicalDpiY() ) / static_cast< qreal >( painter->device()->logicalDpiY() );
01055
01056 GlobalMeasureScaling::setFactors(
01057 static_cast< qreal >( target.width() ) /
01058 static_cast< qreal >( geometry().size().width() ) * resX,
01059 static_cast< qreal >( target.height() ) /
01060 static_cast< qreal >( geometry().size().height() ) * resY );
01061 }
01062
01063
01064 if( target.size() != d->currentLayoutSize ){
01065 d->resizeLayout( target.size() );
01066 }
01067 const QPoint translation = target.topLeft();
01068 painter->translate( translation );
01069
01070 d->paintAll( painter );
01071
01072
01073
01074
01075
01076 KDAB_FOREACH( Legend *legend, d->legends ) {
01077 const bool hidden = legend->isHidden() && legend->testAttribute(Qt::WA_WState_ExplicitShowHide);
01078 if ( !hidden ) {
01079
01080 legend->paintIntoRect( *painter, legend->geometry() );
01081
01082
01083 }
01084 }
01085
01086 painter->translate( -translation.x(), -translation.y() );
01087
01088 GlobalMeasureScaling::instance()->resetFactors();
01089 PrintingParameters::resetScaleFactor();
01090 GlobalMeasureScaling::setPaintDevice( prevDevice );
01091
01092
01093 }
01094
01095 void Chart::resizeEvent ( QResizeEvent * )
01096 {
01097 d->resizeLayout( size() );
01098 KDAB_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes ){
01099 plane->setGridNeedsRecalculate();
01100 }
01101 reLayoutFloatingLegends();
01102 }
01103
01104
01105 void Chart::reLayoutFloatingLegends()
01106 {
01107 KDAB_FOREACH( Legend *legend, d->legends ) {
01108 const bool hidden = legend->isHidden() && legend->testAttribute(Qt::WA_WState_ExplicitShowHide);
01109 if ( legend->position().isFloating() && !hidden ){
01110
01111 const QSize legendSize( legend->sizeHint() );
01112 legend->setGeometry( QRect( legend->geometry().topLeft(), legendSize ) );
01113
01114 const RelativePosition relPos( legend->floatingPosition() );
01115 QPointF pt( relPos.calculatedPoint( size() ) );
01116
01117
01118 const Qt::Alignment alignTopLeft = Qt::AlignBottom | Qt::AlignLeft;
01119 if( (relPos.alignment() & alignTopLeft) != alignTopLeft ){
01120 if( relPos.alignment() & Qt::AlignRight )
01121 pt.rx() -= legendSize.width();
01122 else if( relPos.alignment() & Qt::AlignHCenter )
01123 pt.rx() -= 0.5 * legendSize.width();
01124
01125 if( relPos.alignment() & Qt::AlignBottom )
01126 pt.ry() -= legendSize.height();
01127 else if( relPos.alignment() & Qt::AlignVCenter )
01128 pt.ry() -= 0.5 * legendSize.height();
01129 }
01130
01131 legend->move( static_cast<int>(pt.x()), static_cast<int>(pt.y()) );
01132 }
01133 }
01134 }
01135
01136
01137 void Chart::paintEvent( QPaintEvent* )
01138 {
01139 QPainter painter( this );
01140
01141 if( size() != d->currentLayoutSize ){
01142 d->resizeLayout( size() );
01143 reLayoutFloatingLegends();
01144 }
01145
01146
01147
01148 d->paintAll( &painter );
01149 }
01150
01151 void Chart::addHeaderFooter( HeaderFooter* headerFooter )
01152 {
01153 d->headerFooters.append( headerFooter );
01154 headerFooter->setParent( this );
01155 connect( headerFooter, SIGNAL( destroyedHeaderFooter( HeaderFooter* ) ),
01156 d, SLOT( slotUnregisterDestroyedHeaderFooter( HeaderFooter* ) ) );
01157 connect( headerFooter, SIGNAL( positionChanged( HeaderFooter* ) ),
01158 d, SLOT( slotRelayout() ) );
01159 d->slotRelayout();
01160 }
01161
01162 void Chart::replaceHeaderFooter( HeaderFooter* headerFooter,
01163 HeaderFooter* oldHeaderFooter_ )
01164 {
01165 if( headerFooter && oldHeaderFooter_ != headerFooter ){
01166 HeaderFooter* oldHeaderFooter = oldHeaderFooter_;
01167 if( d->headerFooters.count() ){
01168 if( ! oldHeaderFooter ){
01169 oldHeaderFooter = d->headerFooters.first();
01170 if( oldHeaderFooter == headerFooter )
01171 return;
01172 }
01173 takeHeaderFooter( oldHeaderFooter );
01174 }
01175 delete oldHeaderFooter;
01176 addHeaderFooter( headerFooter );
01177 }
01178 }
01179
01180 void Chart::takeHeaderFooter( HeaderFooter* headerFooter )
01181 {
01182 const int idx = d->headerFooters.indexOf( headerFooter );
01183 if( idx != -1 ){
01184 d->headerFooters.takeAt( idx );
01185 disconnect( headerFooter, SIGNAL( destroyedHeaderFooter( HeaderFooter* ) ),
01186 d, SLOT( slotUnregisterDestroyedHeaderFooter( HeaderFooter* ) ) );
01187 headerFooter->setParent( 0 );
01188 }
01189 d->slotRelayout();
01190
01191
01192 emit propertiesChanged();
01193 }
01194
01195 HeaderFooter* Chart::headerFooter()
01196 {
01197 if( d->headerFooters.isEmpty() ) {
01198 return 0;
01199 } else {
01200 return d->headerFooters.first();
01201 }
01202 }
01203
01204 HeaderFooterList Chart::headerFooters()
01205 {
01206 return d->headerFooters;
01207 }
01208
01209 void Chart::addLegend( Legend* legend )
01210 {
01211 if( ! legend ) return;
01212
01213
01214 d->legends.append( legend );
01215 legend->setParent( this );
01216
01217 TextAttributes textAttrs( legend->textAttributes() );
01218
01219 KDChart::Measure measure( textAttrs.fontSize() );
01220 measure.setRelativeMode( this, KDChartEnums::MeasureOrientationMinimum );
01221 measure.setValue( 20 );
01222 textAttrs.setFontSize( measure );
01223 legend->setTextAttributes( textAttrs );
01224
01225 textAttrs = legend->titleTextAttributes();
01226 measure.setRelativeMode( this, KDChartEnums::MeasureOrientationMinimum );
01227 measure.setValue( 24 );
01228 textAttrs.setFontSize( measure );
01229
01230 legend->setTitleTextAttributes( textAttrs );
01231
01232 legend->setReferenceArea( this );
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245 connect( legend, SIGNAL( destroyedLegend( Legend* ) ),
01246 d, SLOT( slotUnregisterDestroyedLegend( Legend* ) ) );
01247 connect( legend, SIGNAL( positionChanged( AbstractAreaWidget* ) ),
01248 d, SLOT( slotLayoutPlanes() ) );
01249 connect( legend, SIGNAL( propertiesChanged() ),
01250 this, SIGNAL( propertiesChanged() ) );
01251 legend->setVisible( true );
01252 d->slotRelayout();
01253 }
01254
01255
01256 void Chart::replaceLegend( Legend* legend, Legend* oldLegend_ )
01257 {
01258 if( legend && oldLegend_ != legend ){
01259 Legend* oldLegend = oldLegend_;
01260 if( d->legends.count() ){
01261 if( ! oldLegend ){
01262 oldLegend = d->legends.first();
01263 if( oldLegend == legend )
01264 return;
01265 }
01266 takeLegend( oldLegend );
01267 }
01268 delete oldLegend;
01269 addLegend( legend );
01270 }
01271 }
01272
01273 void Chart::takeLegend( Legend* legend )
01274 {
01275 const int idx = d->legends.indexOf( legend );
01276 if( idx != -1 ){
01277 d->legends.takeAt( idx );
01278 disconnect( legend, SIGNAL( destroyedLegend( Legend* ) ),
01279 d, SLOT( slotUnregisterDestroyedLegend( Legend* ) ) );
01280 disconnect( legend, SIGNAL( positionChanged( AbstractAreaWidget* ) ),
01281 d, SLOT( slotLayoutPlanes() ) );
01282 disconnect( legend, SIGNAL( propertiesChanged() ),
01283 this, SIGNAL( propertiesChanged() ) );
01284 legend->setParent( 0 );
01285 legend->setVisible( false );
01286 }
01287 d->slotRelayout();
01288
01289
01290
01291
01292
01293 emit propertiesChanged();
01294 }
01295
01296 Legend* Chart::legend()
01297 {
01298 if ( d->legends.isEmpty() )
01299 {
01300 return 0;
01301 } else {
01302 return d->legends.first();
01303 }
01304 }
01305
01306 LegendList Chart::legends()
01307 {
01308 return d->legends;
01309 }
01310
01311
01312 void Chart::mousePressEvent( QMouseEvent* event )
01313 {
01314 const QPoint pos = mapFromGlobal( event->globalPos() );
01315
01316 KDAB_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes )
01317 {
01318 if ( plane->geometry().contains( event->pos() ) )
01319 {
01320 if ( plane->diagrams().size() > 0 )
01321 {
01322 QMouseEvent ev( QEvent::MouseButtonPress, pos, event->globalPos(),
01323 event->button(), event->buttons(),
01324 event->modifiers() );
01325
01326 plane->mousePressEvent( &ev );
01327 d->mouseClickedPlanes.append( plane );
01328 }
01329 }
01330 }
01331 }
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503 void Chart::mouseDoubleClickEvent( QMouseEvent* event )
01504 {
01505 const QPoint pos = mapFromGlobal( event->globalPos() );
01506
01507 KDAB_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes )
01508 {
01509 if ( plane->geometry().contains( event->pos() ) )
01510 {
01511 if ( plane->diagrams().size() > 0 )
01512 {
01513 QMouseEvent ev( QEvent::MouseButtonPress, pos, event->globalPos(),
01514 event->button(), event->buttons(),
01515 event->modifiers() );
01516 plane->mouseDoubleClickEvent( &ev );
01517 }
01518 }
01519 }
01520 }
01521
01522 void Chart::mouseMoveEvent( QMouseEvent* event )
01523 {
01524 QSet< AbstractCoordinatePlane* > eventReceivers = QSet< AbstractCoordinatePlane* >::fromList( d->mouseClickedPlanes );
01525
01526 KDAB_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes )
01527 {
01528 if( plane->geometry().contains( event->pos() ) )
01529 {
01530 if( plane->diagrams().size() > 0 )
01531 {
01532 eventReceivers.insert( plane );
01533 }
01534 }
01535 }
01536
01537 const QPoint pos = mapFromGlobal( event->globalPos() );
01538
01539 KDAB_FOREACH( AbstractCoordinatePlane* plane, eventReceivers )
01540 {
01541 QMouseEvent ev( QEvent::MouseMove, pos, event->globalPos(),
01542 event->button(), event->buttons(),
01543 event->modifiers() );
01544 plane->mouseMoveEvent( &ev );
01545 }
01546 }
01547
01548 void Chart::mouseReleaseEvent( QMouseEvent* event )
01549 {
01550 QSet< AbstractCoordinatePlane* > eventReceivers = QSet< AbstractCoordinatePlane* >::fromList( d->mouseClickedPlanes );
01551
01552 KDAB_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes )
01553 {
01554 if ( plane->geometry().contains( event->pos() ) )
01555 {
01556 if( plane->diagrams().size() > 0 )
01557 {
01558 eventReceivers.insert( plane );
01559 }
01560 }
01561 }
01562
01563 const QPoint pos = mapFromGlobal( event->globalPos() );
01564
01565 KDAB_FOREACH( AbstractCoordinatePlane* plane, eventReceivers )
01566 {
01567 QMouseEvent ev( QEvent::MouseButtonRelease, pos, event->globalPos(),
01568 event->button(), event->buttons(),
01569 event->modifiers() );
01570 plane->mouseReleaseEvent( &ev );
01571 }
01572
01573 d->mouseClickedPlanes.clear();
01574 }
01575
01576 bool Chart::event( QEvent* event )
01577 {
01578 switch( event->type() )
01579 {
01580 case QEvent::ToolTip:
01581 {
01582 const QHelpEvent* const helpEvent = static_cast< QHelpEvent* >( event );
01583 KDAB_FOREACH( const AbstractCoordinatePlane* const plane, d->coordinatePlanes )
01584 {
01585 KDAB_FOREACH( const AbstractDiagram* const diag, plane->diagrams() )
01586 {
01587 const QModelIndex index = diag->indexAt( helpEvent->pos() );
01588 const QVariant toolTip = index.data( Qt::ToolTipRole );
01589 if( toolTip.isValid() )
01590 {
01591 QToolTip::showText( helpEvent->globalPos(), toolTip.toString() );
01592 return true;
01593 }
01594 }
01595 }
01596
01597 }
01598 default:
01599 return QWidget::event( event );
01600 }
01601 }