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