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
00510 if(!planeLayout){
00511 PlaneInfo& refPi = pi;
00512
00513
00514 while ( !planeLayout && refPi.referencePlane) {
00515 refPi = planeInfos[refPi.referencePlane];
00516 planeLayout = refPi.gridLayout;
00517 }
00518 Q_ASSERT_X(planeLayout,
00519 "Chart::Private::slotLayoutPlanes()",
00520 "Invalid reference plane. Please Check whether the reference plane is added to the Chart or not" );
00521 } else {
00522 planesLayout->addLayout( planeLayout );
00523 }
00524
00525
00526
00527
00528 planeLayoutItems << plane;
00529 plane->setParentLayout( planeLayout );
00530 planeLayout->addItem( plane, row, column, 1, 1, 0 );
00531
00532 planeLayout->setRowStretch( row, 2 );
00533 planeLayout->setColumnStretch( column, 2 );
00534 KDAB_FOREACH( AbstractDiagram* abstractDiagram, plane->diagrams() )
00535 {
00536 AbstractCartesianDiagram* diagram =
00537 dynamic_cast<AbstractCartesianDiagram*> ( abstractDiagram );
00538
00539 if( !diagram ) continue;
00540
00541
00542 if( pi.referencePlane != 0 )
00543 {
00544 pi.topAxesLayout = planeInfos[ pi.referencePlane ].topAxesLayout;
00545 pi.bottomAxesLayout = planeInfos[ pi.referencePlane ].bottomAxesLayout;
00546 pi.leftAxesLayout = planeInfos[ pi.referencePlane ].leftAxesLayout;
00547 pi.rightAxesLayout = planeInfos[ pi.referencePlane ].rightAxesLayout;
00548 }
00549
00550
00551 if( pi.topAxesLayout == 0 )
00552 {
00553 pi.topAxesLayout = new QVBoxLayout;
00554 #if defined SET_ALL_MARGINS_TO_ZERO
00555 pi.topAxesLayout->setMargin(0);
00556 #endif
00557 pi.topAxesLayout->setObjectName( QString::fromLatin1( "topAxesLayout" ) );
00558 }
00559 if( pi.bottomAxesLayout == 0 )
00560 {
00561 pi.bottomAxesLayout = new QVBoxLayout;
00562 #if defined SET_ALL_MARGINS_TO_ZERO
00563 pi.bottomAxesLayout->setMargin(0);
00564 #endif
00565 pi.bottomAxesLayout->setObjectName( QString::fromLatin1( "bottomAxesLayout" ) );
00566 }
00567 if( pi.leftAxesLayout == 0 )
00568 {
00569 pi.leftAxesLayout = new QHBoxLayout;
00570 #if defined SET_ALL_MARGINS_TO_ZERO
00571 pi.leftAxesLayout->setMargin(0);
00572 #endif
00573 pi.leftAxesLayout->setObjectName( QString::fromLatin1( "leftAxesLayout" ) );
00574 }
00575 if( pi.rightAxesLayout == 0 )
00576 {
00577 pi.rightAxesLayout = new QHBoxLayout;
00578 #if defined SET_ALL_MARGINS_TO_ZERO
00579 pi.rightAxesLayout->setMargin(0);
00580 #endif
00581 pi.rightAxesLayout->setObjectName( QString::fromLatin1( "rightAxesLayout" ) );
00582 }
00583
00584 if( pi.referencePlane != 0 )
00585 {
00586 planeInfos[ pi.referencePlane ].topAxesLayout = pi.topAxesLayout;
00587 planeInfos[ pi.referencePlane ].bottomAxesLayout = pi.bottomAxesLayout;
00588 planeInfos[ pi.referencePlane ].leftAxesLayout = pi.leftAxesLayout;
00589 planeInfos[ pi.referencePlane ].rightAxesLayout = pi.rightAxesLayout;
00590 }
00591
00592
00593 KDAB_FOREACH( CartesianAxis* axis, diagram->axes() ) {
00594 if ( axisInfos.contains( axis ) ) continue;
00595 Q_ASSERT ( axis );
00596 axis->setCachedSizeDirty();
00597
00598 planeLayoutItems << axis;
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 switch ( axis->position() )
00613 {
00614 case CartesianAxis::Top:
00615 axis->setParentLayout( pi.topAxesLayout );
00616 pi.topAxesLayout->addItem( axis );
00617 break;
00618 case CartesianAxis::Bottom:
00619 axis->setParentLayout( pi.bottomAxesLayout );
00620 pi.bottomAxesLayout->addItem( axis );
00621 break;
00622 case CartesianAxis::Left:
00623 axis->setParentLayout( pi.leftAxesLayout );
00624 pi.leftAxesLayout->addItem( axis );
00625 break;
00626 case CartesianAxis::Right:
00627 axis->setParentLayout( pi.rightAxesLayout );
00628 pi.rightAxesLayout->addItem( axis );
00629 break;
00630 default:
00631 Q_ASSERT_X( false, "Chart::paintEvent",
00632 "unknown axis position" );
00633 break;
00634 };
00635 axisInfos.insert( axis, AxisInfo() );
00636 }
00637
00638
00639
00640
00641 if ( !pi.topAxesLayout->parent() )
00642 planeLayout->addLayout( pi.topAxesLayout, row - 1, column );
00643 if ( !pi.bottomAxesLayout->parent() )
00644 planeLayout->addLayout( pi.bottomAxesLayout, row + 1, column );
00645 if ( !pi.leftAxesLayout->parent() ){
00646 planeLayout->addLayout( pi.leftAxesLayout, row, column - 1);
00647
00648
00649 }
00650 if ( !pi.rightAxesLayout->parent() )
00651 planeLayout->addLayout( pi.rightAxesLayout, row, column + 1);
00652 }
00653
00654
00655 #define ADD_AUTO_SPACER_IF_NEEDED( \
00656 spacerRow, spacerColumn, hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout ) \
00657 { \
00658 if( hLayout || vLayout ) { \
00659 AutoSpacerLayoutItem * spacer \
00660 = new AutoSpacerLayoutItem( hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout ); \
00661 planeLayout->addItem( spacer, spacerRow, spacerColumn, 1, 1 ); \
00662 spacer->setParentLayout( planeLayout ); \
00663 planeLayoutItems << spacer; \
00664 } \
00665 }
00666 ADD_AUTO_SPACER_IF_NEEDED( row-1, column-1, false, pi.leftAxesLayout, false, pi.topAxesLayout )
00667 ADD_AUTO_SPACER_IF_NEEDED( row+1, column-1, true, pi.leftAxesLayout, false, pi.bottomAxesLayout )
00668 ADD_AUTO_SPACER_IF_NEEDED( row-1, column+1, false, pi.rightAxesLayout, true, pi.topAxesLayout )
00669 ADD_AUTO_SPACER_IF_NEEDED( row+1, column+1, true, pi.rightAxesLayout, true, pi.bottomAxesLayout )
00670 }
00671
00672 if ( dataAndLegendLayout ){
00673 dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
00674 dataAndLegendLayout->setRowStretch( 1, 1000 );
00675 dataAndLegendLayout->setColumnStretch( 1, 1000 );
00676 }
00677
00678 slotRelayout();
00679
00680 }
00681
00682 void Chart::Private::createLayouts( QWidget* w )
00683 {
00684 KDAB_FOREACH( KDChart::TextArea* textLayoutItem, textLayoutItems ) {
00685 textLayoutItem->removeFromParentLayout();
00686 }
00687 textLayoutItems.clear();
00688
00689 KDAB_FOREACH( KDChart::AbstractArea* layoutItem, layoutItems ) {
00690 layoutItem->removeFromParentLayout();
00691 }
00692 layoutItems.clear();
00693
00694 removeDummyHeaderFooters();
00695
00696
00697 if ( dataAndLegendLayout) {
00698 dataAndLegendLayout->removeItem( planesLayout );
00699 planesLayout->setParent( 0 );
00700 }
00701
00702 delete layout;
00703
00704
00705 layout = new QHBoxLayout( w );
00706
00707 #if defined SET_ALL_MARGINS_TO_ZERO
00708 layout->setMargin(0);
00709 #endif
00710 layout->setObjectName( QString::fromLatin1( "Chart::Private::layout" ) );
00711 layout->addSpacing( globalLeadingLeft );
00712
00713
00714
00715 vLayout = new QVBoxLayout();
00716
00717 #if defined SET_ALL_MARGINS_TO_ZERO
00718 vLayout->setMargin(0);
00719 #endif
00720 vLayout->setObjectName( QString::fromLatin1( "vLayout" ) );
00721 layout->addLayout( vLayout, 1000 );
00722 layout->addSpacing( globalLeadingRight );
00723
00724
00725
00726
00727 vLayout->addSpacing( globalLeadingTop );
00728
00729 headerLayout = new QGridLayout();
00730
00731 #if defined SET_ALL_MARGINS_TO_ZERO
00732 headerLayout->setMargin(0);
00733 #endif
00734 vLayout->addLayout( headerLayout );
00735
00736 dataAndLegendLayout = new QGridLayout();
00737
00738 #if defined SET_ALL_MARGINS_TO_ZERO
00739 dataAndLegendLayout->setMargin(0);
00740 #endif
00741 dataAndLegendLayout->setObjectName( QString::fromLatin1( "dataAndLegendLayout" ) );
00742 vLayout->addLayout( dataAndLegendLayout, 1000 );
00743
00744 footerLayout = new QGridLayout();
00745
00746 #if defined SET_ALL_MARGINS_TO_ZERO
00747 footerLayout->setMargin(0);
00748 #endif
00749 footerLayout->setObjectName( QString::fromLatin1( "footerLayout" ) );
00750 vLayout->addLayout( footerLayout );
00751
00752
00753
00754
00755
00756 static const Qt::Alignment hdFtAlignments[3][3] = {
00757 { Qt::AlignTop | Qt::AlignLeft, Qt::AlignTop | Qt::AlignHCenter, Qt::AlignTop | Qt::AlignRight },
00758 { Qt::AlignVCenter | Qt::AlignLeft, Qt::AlignVCenter | Qt::AlignHCenter, Qt::AlignVCenter | Qt::AlignRight },
00759 { Qt::AlignBottom | Qt::AlignLeft, Qt::AlignBottom | Qt::AlignHCenter, Qt::AlignBottom | Qt::AlignRight }
00760 };
00761 for ( int row = 0; row < 3; ++row )
00762 {
00763 for ( int column = 0; column < 3; ++ column )
00764 {
00765 QVBoxLayout* innerHdLayout = new QVBoxLayout();
00766 QVBoxLayout* innerFtLayout = new QVBoxLayout();
00767 innerHdFtLayouts[0][row][column] = innerHdLayout;
00768 innerHdFtLayouts[1][row][column] = innerFtLayout;
00769 #if defined SET_ALL_MARGINS_TO_ZERO
00770 innerHdLayout->setMargin(0);
00771 innerFtLayout->setMargin(0);
00772 #endif
00773 const Qt::Alignment align = hdFtAlignments[row][column];
00774 innerHdLayout->setAlignment( align );
00775 innerFtLayout->setAlignment( align );
00776 headerLayout->addLayout( innerHdLayout, row, column, align );
00777 footerLayout->addLayout( innerFtLayout, row, column, align );
00778 }
00779 }
00780
00781
00782 vLayout->addSpacing( globalLeadingBottom );
00783
00784
00785 dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
00786 dataAndLegendLayout->setRowStretch( 1, 1 );
00787 dataAndLegendLayout->setColumnStretch( 1, 1 );
00788
00789
00790 }
00791
00792 void Chart::Private::slotRelayout()
00793 {
00794
00795 createLayouts( chart );
00796
00797 layoutHeadersAndFooters();
00798 layoutLegends();
00799
00800
00801
00802
00803 const QRect geo( QRect( 0, 0, currentLayoutSize.width(), currentLayoutSize.height() ) );
00804 if( geo.isValid() && geo != layout->geometry() ){
00805
00806
00807
00808 layout->setGeometry( geo );
00809
00810
00811
00812 }
00813
00814
00815 KDAB_FOREACH (AbstractCoordinatePlane* plane, coordinatePlanes ) {
00816 plane->layoutDiagrams();
00817 }
00818
00819 }
00820
00821
00822
00823
00824 void Chart::Private::resizeLayout( const QSize& size )
00825 {
00826 currentLayoutSize = size;
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842 slotLayoutPlanes();
00843
00844
00845 }
00846
00847
00848 void Chart::Private::paintAll( QPainter* painter )
00849 {
00850 QRect rect( QPoint(0, 0), currentLayoutSize );
00851
00852
00853
00854
00855 KDChart::AbstractAreaBase::paintBackgroundAttributes(
00856 *painter, rect, backgroundAttributes );
00857
00858 KDChart::AbstractAreaBase::paintFrameAttributes(
00859 *painter, rect, frameAttributes );
00860
00861 chart->reLayoutFloatingLegends();
00862
00863 KDAB_FOREACH( KDChart::AbstractArea* layoutItem, layoutItems ) {
00864 layoutItem->paintAll( *painter );
00865 }
00866 KDAB_FOREACH( KDChart::AbstractLayoutItem* planeLayoutItem, planeLayoutItems ) {
00867 planeLayoutItem->paintAll( *painter );
00868 }
00869 KDAB_FOREACH( KDChart::TextArea* textLayoutItem, textLayoutItems ) {
00870 textLayoutItem->paintAll( *painter );
00871 }
00872 }
00873
00874
00875
00876 Chart::Chart ( QWidget* parent )
00877 : QWidget ( parent )
00878 , _d( new Private( this ) )
00879 {
00880 #if defined KDAB_EVAL
00881 EvalDialog::checkEvalLicense( "KD Chart" );
00882 #endif
00883
00884 FrameAttributes frameAttrs;
00885
00886
00887 frameAttrs.setPen( QPen( Qt::black ) );
00888 frameAttrs.setPadding( 1 );
00889 setFrameAttributes( frameAttrs );
00890
00891 addCoordinatePlane( new CartesianCoordinatePlane ( this ) );
00892 }
00893
00894 Chart::~Chart()
00895 {
00896 delete _d;
00897 }
00898
00899 #define d d_func()
00900
00901 void Chart::setFrameAttributes( const FrameAttributes &a )
00902 {
00903 d->frameAttributes = a;
00904 }
00905
00906 FrameAttributes Chart::frameAttributes() const
00907 {
00908 return d->frameAttributes;
00909 }
00910
00911 void Chart::setBackgroundAttributes( const BackgroundAttributes &a )
00912 {
00913 d->backgroundAttributes = a;
00914 }
00915
00916 BackgroundAttributes Chart::backgroundAttributes() const
00917 {
00918 return d->backgroundAttributes;
00919 }
00920
00921
00922 void Chart::setCoordinatePlaneLayout( QLayout * layout )
00923 {
00924 delete d->planesLayout;
00925 d->planesLayout = dynamic_cast<QBoxLayout*>( layout );
00926 d->slotLayoutPlanes();
00927 }
00928
00929 QLayout* Chart::coordinatePlaneLayout()
00930 {
00931 return d->planesLayout;
00932 }
00933
00934 AbstractCoordinatePlane* Chart::coordinatePlane()
00935 {
00936 if ( d->coordinatePlanes.isEmpty() )
00937 {
00938 qWarning() << "Chart::coordinatePlane: warning: no coordinate plane defined.";
00939 return 0;
00940 } else {
00941 return d->coordinatePlanes.first();
00942 }
00943 }
00944
00945 CoordinatePlaneList Chart::coordinatePlanes()
00946 {
00947 return d->coordinatePlanes;
00948 }
00949
00950 void Chart::addCoordinatePlane( AbstractCoordinatePlane* plane )
00951 {
00952 connect( plane, SIGNAL( destroyedCoordinatePlane( AbstractCoordinatePlane* ) ),
00953 d, SLOT( slotUnregisterDestroyedPlane( AbstractCoordinatePlane* ) ) );
00954 connect( plane, SIGNAL( needUpdate() ), this, SLOT( update() ) );
00955 connect( plane, SIGNAL( needRelayout() ), d, SLOT( slotRelayout() ) ) ;
00956 connect( plane, SIGNAL( needLayoutPlanes() ), d, SLOT( slotLayoutPlanes() ) ) ;
00957 connect( plane, SIGNAL( propertiesChanged() ),this, SIGNAL( propertiesChanged() ) );
00958 d->coordinatePlanes.append( plane );
00959 plane->setParent( this );
00960 d->slotLayoutPlanes();
00961 }
00962
00963 void Chart::replaceCoordinatePlane( AbstractCoordinatePlane* plane,
00964 AbstractCoordinatePlane* oldPlane_ )
00965 {
00966 if( plane && oldPlane_ != plane ){
00967 AbstractCoordinatePlane* oldPlane = oldPlane_;
00968 if( d->coordinatePlanes.count() ){
00969 if( ! oldPlane ){
00970 oldPlane = d->coordinatePlanes.first();
00971 if( oldPlane == plane )
00972 return;
00973 }
00974 takeCoordinatePlane( oldPlane );
00975 }
00976 delete oldPlane;
00977 addCoordinatePlane( plane );
00978 }
00979 }
00980
00981 void Chart::takeCoordinatePlane( AbstractCoordinatePlane* plane )
00982 {
00983 const int idx = d->coordinatePlanes.indexOf( plane );
00984 if( idx != -1 ){
00985 d->coordinatePlanes.takeAt( idx );
00986 disconnect( plane, SIGNAL( destroyedCoordinatePlane( AbstractCoordinatePlane* ) ),
00987 d, SLOT( slotUnregisterDestroyedPlane( AbstractCoordinatePlane* ) ) );
00988 plane->removeFromParentLayout();
00989 plane->setParent( 0 );
00990 d->mouseClickedPlanes.removeAll(plane);
00991 }
00992 d->slotLayoutPlanes();
00993
00994
00995 emit propertiesChanged();
00996 }
00997
00998 void Chart::setGlobalLeading( int left, int top, int right, int bottom )
00999 {
01000 setGlobalLeadingLeft( left );
01001 setGlobalLeadingTop( top );
01002 setGlobalLeadingRight( right );
01003 setGlobalLeadingBottom( bottom );
01004 d->slotRelayout();
01005 }
01006
01007 void Chart::setGlobalLeadingLeft( int leading )
01008 {
01009 d->globalLeadingLeft = leading;
01010 d->slotRelayout();
01011 }
01012
01013 int Chart::globalLeadingLeft() const
01014 {
01015 return d->globalLeadingLeft;
01016 }
01017
01018 void Chart::setGlobalLeadingTop( int leading )
01019 {
01020 d->globalLeadingTop = leading;
01021 d->slotRelayout();
01022 }
01023
01024 int Chart::globalLeadingTop() const
01025 {
01026 return d->globalLeadingTop;
01027 }
01028
01029 void Chart::setGlobalLeadingRight( int leading )
01030 {
01031 d->globalLeadingRight = leading;
01032 d->slotRelayout();
01033 }
01034
01035 int Chart::globalLeadingRight() const
01036 {
01037 return d->globalLeadingRight;
01038 }
01039
01040 void Chart::setGlobalLeadingBottom( int leading )
01041 {
01042 d->globalLeadingBottom = leading;
01043 d->slotRelayout();
01044 }
01045
01046 int Chart::globalLeadingBottom() const
01047 {
01048 return d->globalLeadingBottom;
01049 }
01050
01051 void Chart::paint( QPainter* painter, const QRect& target )
01052 {
01053 if( target.isEmpty() || !painter ) return;
01054
01055
01056 QPaintDevice* prevDevice = GlobalMeasureScaling::paintDevice();
01057 GlobalMeasureScaling::setPaintDevice( painter->device() );
01058
01059
01060 if( dynamic_cast< QWidget* >( painter->device() ) != 0 )
01061 {
01062 GlobalMeasureScaling::setFactors(
01063 static_cast< qreal >( target.width() ) /
01064 static_cast< qreal >( geometry().size().width() ),
01065 static_cast< qreal >( target.height() ) /
01066 static_cast< qreal >( geometry().size().height() ) );
01067 }
01068
01069 else
01070 {
01071 PrintingParameters::setScaleFactor( static_cast< qreal >( painter->device()->logicalDpiX() ) / static_cast< qreal >( logicalDpiX() ) );
01072
01073 const qreal resX = static_cast< qreal >( logicalDpiX() ) / static_cast< qreal >( painter->device()->logicalDpiX() );
01074 const qreal resY = static_cast< qreal >( logicalDpiY() ) / static_cast< qreal >( painter->device()->logicalDpiY() );
01075
01076 GlobalMeasureScaling::setFactors(
01077 static_cast< qreal >( target.width() ) /
01078 static_cast< qreal >( geometry().size().width() ) * resX,
01079 static_cast< qreal >( target.height() ) /
01080 static_cast< qreal >( geometry().size().height() ) * resY );
01081 }
01082
01083
01084 if( target.size() != d->currentLayoutSize ){
01085 d->resizeLayout( target.size() );
01086 }
01087 const QPoint translation = target.topLeft();
01088 painter->translate( translation );
01089
01090 d->paintAll( painter );
01091
01092
01093
01094
01095
01096 KDAB_FOREACH( Legend *legend, d->legends ) {
01097 const bool hidden = legend->isHidden() && legend->testAttribute(Qt::WA_WState_ExplicitShowHide);
01098 if ( !hidden ) {
01099
01100 legend->paintIntoRect( *painter, legend->geometry() );
01101
01102
01103 }
01104 }
01105
01106 painter->translate( -translation.x(), -translation.y() );
01107
01108 GlobalMeasureScaling::instance()->resetFactors();
01109 PrintingParameters::resetScaleFactor();
01110 GlobalMeasureScaling::setPaintDevice( prevDevice );
01111
01112
01113 }
01114
01115 void Chart::resizeEvent ( QResizeEvent * )
01116 {
01117 d->resizeLayout( size() );
01118 KDAB_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes ){
01119 plane->setGridNeedsRecalculate();
01120 }
01121 reLayoutFloatingLegends();
01122 }
01123
01124
01125 void Chart::reLayoutFloatingLegends()
01126 {
01127 KDAB_FOREACH( Legend *legend, d->legends ) {
01128 const bool hidden = legend->isHidden() && legend->testAttribute(Qt::WA_WState_ExplicitShowHide);
01129 if ( legend->position().isFloating() && !hidden ){
01130
01131 const QSize legendSize( legend->sizeHint() );
01132 legend->setGeometry( QRect( legend->geometry().topLeft(), legendSize ) );
01133
01134 const RelativePosition relPos( legend->floatingPosition() );
01135 QPointF pt( relPos.calculatedPoint( size() ) );
01136
01137
01138 const Qt::Alignment alignTopLeft = Qt::AlignBottom | Qt::AlignLeft;
01139 if( (relPos.alignment() & alignTopLeft) != alignTopLeft ){
01140 if( relPos.alignment() & Qt::AlignRight )
01141 pt.rx() -= legendSize.width();
01142 else if( relPos.alignment() & Qt::AlignHCenter )
01143 pt.rx() -= 0.5 * legendSize.width();
01144
01145 if( relPos.alignment() & Qt::AlignBottom )
01146 pt.ry() -= legendSize.height();
01147 else if( relPos.alignment() & Qt::AlignVCenter )
01148 pt.ry() -= 0.5 * legendSize.height();
01149 }
01150
01151 legend->move( static_cast<int>(pt.x()), static_cast<int>(pt.y()) );
01152 }
01153 }
01154 }
01155
01156
01157 void Chart::paintEvent( QPaintEvent* )
01158 {
01159 QPainter painter( this );
01160
01161 if( size() != d->currentLayoutSize ){
01162 d->resizeLayout( size() );
01163 reLayoutFloatingLegends();
01164 }
01165
01166
01167
01168 d->paintAll( &painter );
01169 }
01170
01171 void Chart::addHeaderFooter( HeaderFooter* headerFooter )
01172 {
01173 d->headerFooters.append( headerFooter );
01174 headerFooter->setParent( this );
01175 connect( headerFooter, SIGNAL( destroyedHeaderFooter( HeaderFooter* ) ),
01176 d, SLOT( slotUnregisterDestroyedHeaderFooter( HeaderFooter* ) ) );
01177 connect( headerFooter, SIGNAL( positionChanged( HeaderFooter* ) ),
01178 d, SLOT( slotRelayout() ) );
01179 d->slotRelayout();
01180 }
01181
01182 void Chart::replaceHeaderFooter( HeaderFooter* headerFooter,
01183 HeaderFooter* oldHeaderFooter_ )
01184 {
01185 if( headerFooter && oldHeaderFooter_ != headerFooter ){
01186 HeaderFooter* oldHeaderFooter = oldHeaderFooter_;
01187 if( d->headerFooters.count() ){
01188 if( ! oldHeaderFooter ){
01189 oldHeaderFooter = d->headerFooters.first();
01190 if( oldHeaderFooter == headerFooter )
01191 return;
01192 }
01193 takeHeaderFooter( oldHeaderFooter );
01194 }
01195 delete oldHeaderFooter;
01196 addHeaderFooter( headerFooter );
01197 }
01198 }
01199
01200 void Chart::takeHeaderFooter( HeaderFooter* headerFooter )
01201 {
01202 const int idx = d->headerFooters.indexOf( headerFooter );
01203 if( idx != -1 ){
01204 d->headerFooters.takeAt( idx );
01205 disconnect( headerFooter, SIGNAL( destroyedHeaderFooter( HeaderFooter* ) ),
01206 d, SLOT( slotUnregisterDestroyedHeaderFooter( HeaderFooter* ) ) );
01207 headerFooter->setParent( 0 );
01208 }
01209 d->slotRelayout();
01210
01211
01212 emit propertiesChanged();
01213 }
01214
01215 HeaderFooter* Chart::headerFooter()
01216 {
01217 if( d->headerFooters.isEmpty() ) {
01218 return 0;
01219 } else {
01220 return d->headerFooters.first();
01221 }
01222 }
01223
01224 HeaderFooterList Chart::headerFooters()
01225 {
01226 return d->headerFooters;
01227 }
01228
01229 void Chart::addLegend( Legend* legend )
01230 {
01231 if( ! legend ) return;
01232
01233
01234 d->legends.append( legend );
01235 legend->setParent( this );
01236
01237 TextAttributes textAttrs( legend->textAttributes() );
01238
01239 KDChart::Measure measure( textAttrs.fontSize() );
01240 measure.setRelativeMode( this, KDChartEnums::MeasureOrientationMinimum );
01241 measure.setValue( 20 );
01242 textAttrs.setFontSize( measure );
01243 legend->setTextAttributes( textAttrs );
01244
01245 textAttrs = legend->titleTextAttributes();
01246 measure.setRelativeMode( this, KDChartEnums::MeasureOrientationMinimum );
01247 measure.setValue( 24 );
01248 textAttrs.setFontSize( measure );
01249
01250 legend->setTitleTextAttributes( textAttrs );
01251
01252 legend->setReferenceArea( this );
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265 connect( legend, SIGNAL( destroyedLegend( Legend* ) ),
01266 d, SLOT( slotUnregisterDestroyedLegend( Legend* ) ) );
01267 connect( legend, SIGNAL( positionChanged( AbstractAreaWidget* ) ),
01268 d, SLOT( slotLayoutPlanes() ) );
01269 connect( legend, SIGNAL( propertiesChanged() ),
01270 this, SIGNAL( propertiesChanged() ) );
01271 legend->setVisible( true );
01272 d->slotRelayout();
01273 }
01274
01275
01276 void Chart::replaceLegend( Legend* legend, Legend* oldLegend_ )
01277 {
01278 if( legend && oldLegend_ != legend ){
01279 Legend* oldLegend = oldLegend_;
01280 if( d->legends.count() ){
01281 if( ! oldLegend ){
01282 oldLegend = d->legends.first();
01283 if( oldLegend == legend )
01284 return;
01285 }
01286 takeLegend( oldLegend );
01287 }
01288 delete oldLegend;
01289 addLegend( legend );
01290 }
01291 }
01292
01293 void Chart::takeLegend( Legend* legend )
01294 {
01295 const int idx = d->legends.indexOf( legend );
01296 if( idx != -1 ){
01297 d->legends.takeAt( idx );
01298 disconnect( legend, SIGNAL( destroyedLegend( Legend* ) ),
01299 d, SLOT( slotUnregisterDestroyedLegend( Legend* ) ) );
01300 disconnect( legend, SIGNAL( positionChanged( AbstractAreaWidget* ) ),
01301 d, SLOT( slotLayoutPlanes() ) );
01302 disconnect( legend, SIGNAL( propertiesChanged() ),
01303 this, SIGNAL( propertiesChanged() ) );
01304 legend->setParent( 0 );
01305 legend->setVisible( false );
01306 }
01307 d->slotRelayout();
01308
01309
01310
01311
01312
01313 emit propertiesChanged();
01314 }
01315
01316 Legend* Chart::legend()
01317 {
01318 if ( d->legends.isEmpty() )
01319 {
01320 return 0;
01321 } else {
01322 return d->legends.first();
01323 }
01324 }
01325
01326 LegendList Chart::legends()
01327 {
01328 return d->legends;
01329 }
01330
01331
01332 void Chart::mousePressEvent( QMouseEvent* event )
01333 {
01334 const QPoint pos = mapFromGlobal( event->globalPos() );
01335
01336 KDAB_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes )
01337 {
01338 if ( plane->geometry().contains( event->pos() ) )
01339 {
01340 if ( plane->diagrams().size() > 0 )
01341 {
01342 QMouseEvent ev( QEvent::MouseButtonPress, pos, event->globalPos(),
01343 event->button(), event->buttons(),
01344 event->modifiers() );
01345
01346 plane->mousePressEvent( &ev );
01347 d->mouseClickedPlanes.append( plane );
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
01518
01519
01520
01521
01522
01523 void Chart::mouseDoubleClickEvent( QMouseEvent* event )
01524 {
01525 const QPoint pos = mapFromGlobal( event->globalPos() );
01526
01527 KDAB_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes )
01528 {
01529 if ( plane->geometry().contains( event->pos() ) )
01530 {
01531 if ( plane->diagrams().size() > 0 )
01532 {
01533 QMouseEvent ev( QEvent::MouseButtonPress, pos, event->globalPos(),
01534 event->button(), event->buttons(),
01535 event->modifiers() );
01536 plane->mouseDoubleClickEvent( &ev );
01537 }
01538 }
01539 }
01540 }
01541
01542 void Chart::mouseMoveEvent( QMouseEvent* event )
01543 {
01544 QSet< AbstractCoordinatePlane* > eventReceivers = QSet< AbstractCoordinatePlane* >::fromList( d->mouseClickedPlanes );
01545
01546 KDAB_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes )
01547 {
01548 if( plane->geometry().contains( event->pos() ) )
01549 {
01550 if( plane->diagrams().size() > 0 )
01551 {
01552 eventReceivers.insert( plane );
01553 }
01554 }
01555 }
01556
01557 const QPoint pos = mapFromGlobal( event->globalPos() );
01558
01559 KDAB_FOREACH( AbstractCoordinatePlane* plane, eventReceivers )
01560 {
01561 QMouseEvent ev( QEvent::MouseMove, pos, event->globalPos(),
01562 event->button(), event->buttons(),
01563 event->modifiers() );
01564 plane->mouseMoveEvent( &ev );
01565 }
01566 }
01567
01568 void Chart::mouseReleaseEvent( QMouseEvent* event )
01569 {
01570 QSet< AbstractCoordinatePlane* > eventReceivers = QSet< AbstractCoordinatePlane* >::fromList( d->mouseClickedPlanes );
01571
01572 KDAB_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes )
01573 {
01574 if ( plane->geometry().contains( event->pos() ) )
01575 {
01576 if( plane->diagrams().size() > 0 )
01577 {
01578 eventReceivers.insert( plane );
01579 }
01580 }
01581 }
01582
01583 const QPoint pos = mapFromGlobal( event->globalPos() );
01584
01585 KDAB_FOREACH( AbstractCoordinatePlane* plane, eventReceivers )
01586 {
01587 QMouseEvent ev( QEvent::MouseButtonRelease, pos, event->globalPos(),
01588 event->button(), event->buttons(),
01589 event->modifiers() );
01590 plane->mouseReleaseEvent( &ev );
01591 }
01592
01593 d->mouseClickedPlanes.clear();
01594 }
01595
01596 bool Chart::event( QEvent* event )
01597 {
01598 switch( event->type() )
01599 {
01600 case QEvent::ToolTip:
01601 {
01602 const QHelpEvent* const helpEvent = static_cast< QHelpEvent* >( event );
01603 KDAB_FOREACH( const AbstractCoordinatePlane* const plane, d->coordinatePlanes )
01604 {
01605 for (int i = plane->diagrams().count() - 1; i >= 0; --i) {
01606 const QModelIndex index = plane->diagrams().at(i)->indexAt( helpEvent->pos() );
01607 const QVariant toolTip = index.data( Qt::ToolTipRole );
01608 if( toolTip.isValid() )
01609 {
01610 QPoint pos = mapFromGlobal(helpEvent->pos());
01611 QRect rect(pos-QPoint(1,1), QSize(3,3));
01612 QToolTip::showText( QCursor::pos(), toolTip.toString(), this, rect );
01613 return true;
01614 }
01615 }
01616 }
01617
01618 }
01619 default:
01620 return QWidget::event( event );
01621 }
01622 }