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