# KDChartLayoutItems.cpp

Go to the documentation of this file.

    00001 /****************************************************************************
    00002  ** Copyright (C) 2007 Klar�vdalens Datakonsult AB.  All rights reserved.
    00003  **
    00004  ** This file is part of the KD Chart library.
    00005  **
    00006  ** This file may be distributed and/or modified under the terms of the
    00007  ** GNU General Public License version 2 as published by the Free Software
    00008  ** Foundation and appearing in the file LICENSE.GPL included in the
    00009  ** packaging of this file.
    00010  **
    00011  ** Licensees holding valid commercial KD Chart licenses may use this file in
    00012  ** accordance with the KD Chart Commercial License Agreement provided with
    00013  ** the Software.
    00014  **
    00015  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
    00016  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    00017  **
    00018  ** See http://www.kdab.net/kdchart for
    00019  **   information about KDChart Commercial License Agreements.
    00020  **
    00021  ** Contact info@kdab.net if any conditions of this
    00022  ** licensing are not clear to you.
    00023  **
    00024  **********************************************************************/
    00025
    00026 #include "KDChartLayoutItems.h"
    00027 #include "KDTextDocument.h"
    00028 #include "KDChartAbstractArea.h"
    00029 #include "KDChartAbstractDiagram.h"
    00030 #include "KDChartBackgroundAttributes.h"
    00031 #include "KDChartFrameAttributes.h"
    00032 #include "KDChartPaintContext.h"
    00033 #include "KDChartPainterSaver_p.h"
    00034 #include <QTextCursor>
    00035 #include <QTextBlockFormat>
    00036 #include <QTextDocumentFragment>
    00037 #include <QAbstractTextDocumentLayout>
    00038 #include <QLayout>
    00039 #include <QPainter>
    00040 #include <QDebug>
    00041 #include <QCoreApplication>
    00042 #include <QApplication>
    00043 #include <QStringList>
    00044 #include <QStyle>
    00045
    00046 #include <KDABLibFakes>
    00047
    00048 #include <math.h>
    00049
    00050 #define PI 3.141592653589793
    00051
    00052
    00053
    00054 //#define DEBUG_ITEMS_PAINT
    00055
    00064 void KDChart::AbstractLayoutItem::setParentWidget( QWidget* widget )
    00065 {
    00066     mParent = widget;
    00067 }
    00068
    00069 void KDChart::AbstractLayoutItem::paintAll( QPainter& painter )
    00070 {
    00071     paint( &painter );
    00072 }
    00073
    00077 void KDChart::AbstractLayoutItem::paintCtx( PaintContext* context )
    00078 {
    00079     if( context )
    00080         paint( context->painter() );
    00081 }
    00082
    00086 void KDChart::AbstractLayoutItem::sizeHintChanged()const
    00087 {
    00088     // This is exactly like what QWidget::updateGeometry does.
    00089 //  qDebug("KDChart::AbstractLayoutItem::sizeHintChanged() called");
    00090     if( mParent ) {
    00091         if ( mParent->layout() )
    00092             mParent->layout()->invalidate();
    00093         else
    00094             QApplication::postEvent( mParent, new QEvent( QEvent::LayoutRequest ) );
    00095     }
    00096 }
    00097
    00098
    00099 KDChart::TextLayoutItem::TextLayoutItem( const QString& text,
    00100                                          const KDChart::TextAttributes& attributes,
    00101                                          const QObject* area,
    00102                                          KDChartEnums::MeasureOrientation orientation,
    00103                                          Qt::Alignment alignment )
    00104     : AbstractLayoutItem( alignment )
    00105     , mText( text )
    00106     , mAttributes( attributes )
    00107     , mAutoReferenceArea( area )
    00108     , mAutoReferenceOrientation( orientation )
    00109     , cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
    00110     , cachedFontSize( 0.0 )
    00111     , cachedFont( mAttributes.font() )
    00112 {
    00113 }
    00114
    00115 KDChart::TextLayoutItem::TextLayoutItem()
    00116     : AbstractLayoutItem( Qt::AlignLeft )
    00117     , mText()
    00118     , mAttributes()
    00119     , mAutoReferenceArea( 0 )
    00120     , mAutoReferenceOrientation( KDChartEnums::MeasureOrientationHorizontal )
    00121     , cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
    00122     , cachedFontSize( 0.0 )
    00123     , cachedFont( mAttributes.font() )
    00124 {
    00125
    00126 }
    00127
    00128 void KDChart::TextLayoutItem::setAutoReferenceArea( const QObject* area )
    00129 {
    00130     mAutoReferenceArea = area;
    00131     cachedSizeHint = QSize();
    00132     sizeHint();
    00133 }
    00134
    00135 const QObject* KDChart::TextLayoutItem::autoReferenceArea() const
    00136 {
    00137     return mAutoReferenceArea;
    00138 }
    00139
    00140 void KDChart::TextLayoutItem::setText(const QString & text)
    00141 {
    00142     mText = text;
    00143     cachedSizeHint = QSize();
    00144     sizeHint();
    00145     if( mParent )
    00146         mParent->update();
    00147 }
    00148
    00149 QString KDChart::TextLayoutItem::text() const
    00150 {
    00151     return mText;
    00152 }
    00153
    00159 void KDChart::TextLayoutItem::setTextAttributes( const TextAttributes &a )
    00160 {
    00161     mAttributes = a;
    00162     cachedSizeHint = QSize(); // invalidate size hint
    00163     sizeHint();
    00164     if( mParent )
    00165         mParent->update();
    00166 }
    00167
    00173 KDChart::TextAttributes KDChart::TextLayoutItem::textAttributes() const
    00174 {
    00175     return mAttributes;
    00176 }
    00177
    00178
    00179 Qt::Orientations KDChart::TextLayoutItem::expandingDirections() const
    00180 {
    00181     return 0; // Grow neither vertically nor horizontally
    00182 }
    00183
    00184 QRect KDChart::TextLayoutItem::geometry() const
    00185 {
    00186     return mRect;
    00187 }
    00188
    00189 bool KDChart::TextLayoutItem::isEmpty() const
    00190 {
    00191     return false; // never empty, otherwise the layout item would not exist
    00192 }
    00193
    00194 QSize KDChart::TextLayoutItem::maximumSize() const
    00195 {
    00196     return sizeHint(); // PENDING(kalle) Review, quite inflexible
    00197 }
    00198
    00199 QSize KDChart::TextLayoutItem::minimumSize() const
    00200 {
    00201     return sizeHint(); // PENDING(kalle) Review, quite inflexible
    00202 }
    00203
    00204 void KDChart::TextLayoutItem::setGeometry( const QRect& r )
    00205 {
    00206     mRect = r;
    00207 }
    00208
    00209
    00210 qreal KDChart::TextLayoutItem::realFontSize() const
    00211 {
    00212     return mAttributes.calculatedFontSize( mAutoReferenceArea, mAutoReferenceOrientation );
    00213 }
    00214
    00215
    00216 bool KDChart::TextLayoutItem::realFontWasRecalculated() const
    00217 {
    00218     const qreal fntSiz = realFontSize();
    00219     const bool bRecalcDone =
    00220         ( ( ! cachedSizeHint.isValid() ) || ( cachedFontSize != fntSiz   ) );
    00221
    00222     if( bRecalcDone && fntSiz > 0.0 ){
    00223         cachedFontSize = fntSiz;
    00224         cachedFont.setPointSizeF( fntSiz );
    00225     }
    00226     return bRecalcDone;
    00227 }
    00228
    00229
    00230 QFont KDChart::TextLayoutItem::realFont() const
    00231 {
    00232     realFontWasRecalculated(); // we can safely ignore the boolean return value
    00233     return cachedFont;
    00234 }
    00235
    00236 QPolygon KDChart::TextLayoutItem::rotatedCorners() const
    00237 {
    00238     // the angle in rad
    00239     const qreal angle = mAttributes.rotation() * PI / 180.0;
    00240     QSize size = unrotatedSizeHint();
    00241
    00242     // my P1 - P4 (the four points of the rotated area)
    00243     QPointF P1( size.height() * sin( angle ), 0 );
    00244     QPointF P2( size.height() * sin( angle ) + size.width() * cos( angle ), size.width() * sin( angle ) );
    00245     QPointF P3( size.width() * cos( angle ), size.width() * sin( angle ) + size.height() * cos( angle ) );
    00246     QPointF P4( 0, size.height() * cos( angle ) );
    00247
    00248     QPolygon result;
    00249     result << P1.toPoint() << P2.toPoint() << P3.toPoint() << P4.toPoint();
    00250     return result;
    00251 }
    00252
    00253 bool KDChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPointF& myPos, const QPointF& otherPos ) const
    00254 {
    00255     return intersects( other, myPos.toPoint(), otherPos.toPoint() );
    00256 }
    00257
    00258 bool KDChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPoint& myPos, const QPoint& otherPos ) const
    00259 {
    00260     if ( mAttributes.rotation() != other.mAttributes.rotation() )
    00261     {
    00262         // that's the code for the common case: the rotation angles don't need to match here
    00263         QPolygon myPolygon(          rotatedCorners() );
    00264         QPolygon otherPolygon( other.rotatedCorners() );
    00265
    00266         // move the polygons to their positions
    00267         myPolygon.translate( myPos );
    00268         otherPolygon.translate( otherPos );
    00269
    00270         // create regions out of it
    00271         QRegion myRegion( myPolygon );
    00272         QRegion otherRegion( otherPolygon );
    00273
    00274         // now the question - do they intersect or not?
    00275         return ! myRegion.intersect( otherRegion ).isEmpty();
    00276
    00277     } else {
    00278         // and that's the code for the special case: the rotation angles match, which is less time consuming in calculation
    00279         const qreal angle = mAttributes.rotation() * PI / 180.0;
    00280         // both sizes
    00281         const QSizeF mySize(          unrotatedSizeHint() );
    00282         const QSizeF otherSize( other.unrotatedSizeHint() );
    00283
    00284         // that's myP1 relative to myPos
    00285         QPointF myP1( mySize.height() * sin( angle ), 0.0 );
    00286         // that's otherP1 to myPos
    00287         QPointF otherP1 = QPointF( otherSize.height() * sin( angle ), 0.0 ) + otherPos - myPos;
    00288
    00289         // now rotate both points the negative angle around myPos
    00290         myP1 = QPointF( myP1.x() * cos( -angle ), myP1.x() * sin( -angle ) );
    00291         qreal r = sqrt( otherP1.x() * otherP1.x() + otherP1.y() * otherP1.y() );
    00292         otherP1 = QPointF( r * cos( -angle ), r * sin( -angle ) );
    00293
    00294         // finally we look, whether both rectangles intersect or even not
    00295         return QRectF( myP1, mySize ).intersects( QRectF( otherP1, otherSize ) );
    00296     }
    00297 }
    00298
    00299 QSize KDChart::TextLayoutItem::sizeHint() const
    00300 {
    00301     if( realFontWasRecalculated() )
    00302     {
    00303         const QSize newSizeHint( calcSizeHint( cachedFont ) );
    00304         if( newSizeHint != cachedSizeHint ){
    00305             cachedSizeHint = newSizeHint;
    00306             sizeHintChanged();
    00307         }
    00308     }
    00309     //qDebug() << "-------- KDChart::TextLayoutItem::sizeHint() returns:"<<cachedSizeHint<<" ----------";
    00310     return cachedSizeHint;
    00311 }
    00312
    00313
    00314 // PENDING(kalle) Support auto shrink
    00315
    00316
    00317 QSize KDChart::TextLayoutItem::unrotatedSizeHint( QFont fnt ) const
    00318 {
    00319     if ( fnt == QFont() )
    00320         fnt = cachedFont;
    00321
    00322     const QFontMetricsF met( fnt, GlobalMeasureScaling::paintDevice() );
    00323     QSize ret(0, 0);
    00324     // note: boundingRect() does NOT take any newlines into account
    00325     //       so we need to calculate the size by combining several
    00326     //       rectangles: one per line.  This fixes bugz issue #3720.
    00327     //       (khz, 2007 04 14)
    00328     QStringList lines = mText.split(QString::fromAscii("\n"));
    00329     for (int i = 0; i < lines.size(); ++i){
    00330         const QSize lSize = met.boundingRect(lines.at(i) ).toRect().size();
    00331         ret.setWidth(qMax( ret.width(), lSize.width() ));
    00332         ret.rheight() += lSize.height();
    00333     }
    00334
    00335     int frame = QApplication::style()->pixelMetric( QStyle::PM_ButtonMargin, 0, 0 );
    00336     // fine-tuning for small font sizes: the frame must not be so big, if the font is tiny
    00337     frame = qMin( frame, ret.height() * 2 / 3 );
    00338     //qDebug() << "frame:"<< frame;
    00339     ret += QSize( frame, frame );
    00340     return ret;
    00341     //const QFontMetricsF met( fnt, GlobalMeasureScaling::paintDevice() );
    00342     //const int frame = QApplication::style()->pixelMetric( QStyle::PM_ButtonMargin, 0, 0 );
    00343     //return
    00344     //    met.boundingRect( mText ).size().toSize() + QSize( frame, frame );
    00345 }
    00346
    00347
    00348 QSize KDChart::TextLayoutItem::calcSizeHint( QFont fnt ) const
    00349 {
    00350     QSize ret = unrotatedSizeHint( fnt );
    00351     //qDebug() << "-------- "<<ret.width();
    00352     const qreal angle = PI * mAttributes.rotation() / 180.0;
    00353     const qreal cosAngle = cos( angle );
    00354     const qreal sinAngle = sin( angle );
    00355     QSize rotated( qAbs(static_cast<int>( cosAngle * ret.width()  + sinAngle * ret.height() )),
    00356                    qAbs(static_cast<int>( cosAngle * ret.height() + sinAngle * ret.width()  )) );
    00357     //qDebug() << "-------- KDChart::TextLayoutItem::calcSizeHint() returns:"<<rotated<<" ----------";
    00358     return rotated;
    00359 }
    00360
    00361 static QPointF rotatedPoint( const QPointF& pt, qreal rotation )
    00362 {
    00363     const qreal angle = PI * rotation / 180.0;
    00364     const qreal cosAngle = cos( angle );
    00365     const qreal sinAngle = sin( angle );
    00366     return QPointF(
    00367             (cosAngle * pt.x() + sinAngle * pt.y() ),
    00368             (cosAngle * pt.y() + sinAngle * pt.x() ) );
    00369 }
    00370
    00371 static QRectF rotatedRect( const QRectF& rect, qreal angle )
    00372 {
    00373     const QPointF topLeft(  rotatedPoint( rect.topLeft(),  angle ) );
    00374     //const QPointF topRight( rotatedPoint( rect.topRight(), angle ) );
    00375     //const QPointF bottomLeft(  rotatedPoint( rect.bottomLeft(),  angle ) );
    00376     //const QPointF bottomRight( rotatedPoint( rect.bottomRight(), angle ) );
    00377     const QPointF siz( rotatedPoint( QPointF( rect.size().width(), rect.size().height() ), angle ) );
    00378     const QRectF result(
    00379             topLeft,
    00380             QSizeF( siz.x(), //bottomRight.x() - topLeft.x(),
    00381                     siz.y() ) ); //bottomRight.y() - topLeft.y() ) );
    00382     //qDebug() << "angle" << angle << "\nbefore:" << rect << "\n after:" << result;
    00383     return result;
    00384 }
    00385
    00386 void KDChart::TextLayoutItem::paint( QPainter* painter )
    00387 {
    00388     // make sure, cached font is updated, if needed:
    00389     // sizeHint();
    00390
    00391     if( !mRect.isValid() )
    00392         return;
    00393
    00394     PainterSaver painterSaver( painter );
    00395     painter->setFont( cachedFont );
    00396     QRectF rect( geometry() );
    00397
    00398 // #ifdef DEBUG_ITEMS_PAINT
    00399 //     painter->setPen( Qt::black );
    00400 //     painter->drawRect( rect );
    00401 // #endif
    00402     painter->translate( rect.center() );
    00403     rect.moveTopLeft( QPointF( - rect.width() / 2, - rect.height() / 2 ) );
    00404 #ifdef DEBUG_ITEMS_PAINT
    00405     painter->setPen( Qt::blue );
    00406     painter->drawRect( rect );
    00407 #endif
    00408     painter->rotate( mAttributes.rotation() );
    00409     rect = rotatedRect( rect, mAttributes.rotation() );
    00410 #ifdef DEBUG_ITEMS_PAINT
    00411     painter->setPen( Qt::red );
    00412     painter->drawRect( rect );
    00413 #endif
    00414     painter->setPen( mAttributes.pen() );
    00415     painter->drawText( rect, Qt::AlignHCenter | Qt::AlignVCenter, mText );
    00416 //    if (  calcSizeHint( cachedFont ).width() > rect.width() )
    00417 //        qDebug() << "rect.width()" << rect.width() << "text.width()" << calcSizeHint( cachedFont ).width();
    00418 //
    00419 //    //painter->drawText( rect, Qt::AlignHCenter | Qt::AlignVCenter, mText );
    00420 }
    00421
    00422 KDChart::HorizontalLineLayoutItem::HorizontalLineLayoutItem()
    00423     : AbstractLayoutItem( Qt::AlignCenter )
    00424 {
    00425 }
    00426
    00427 Qt::Orientations KDChart::HorizontalLineLayoutItem::expandingDirections() const
    00428 {
    00429     return Qt::Vertical|Qt::Horizontal; // Grow both vertically, and horizontally
    00430 }
    00431
    00432 QRect KDChart::HorizontalLineLayoutItem::geometry() const
    00433 {
    00434     return mRect;
    00435 }
    00436
    00437 bool KDChart::HorizontalLineLayoutItem::isEmpty() const
    00438 {
    00439     return false; // never empty, otherwise the layout item would not exist
    00440 }
    00441
    00442 QSize KDChart::HorizontalLineLayoutItem::maximumSize() const
    00443 {
    00444     return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
    00445 }
    00446
    00447 QSize KDChart::HorizontalLineLayoutItem::minimumSize() const
    00448 {
    00449     return QSize( 0, 0 );
    00450 }
    00451
    00452 void KDChart::HorizontalLineLayoutItem::setGeometry( const QRect& r )
    00453 {
    00454     mRect = r;
    00455 }
    00456
    00457 QSize KDChart::HorizontalLineLayoutItem::sizeHint() const
    00458 {
    00459     return QSize( -1, 3 ); // see qframe.cpp
    00460 }
    00461
    00462
    00463 void KDChart::HorizontalLineLayoutItem::paint( QPainter* painter )
    00464 {
    00465     if( !mRect.isValid() )
    00466         return;
    00467
    00468     painter->drawLine( QPointF( mRect.left(), mRect.center().y() ),
    00469                        QPointF( mRect.right(), mRect.center().y() ) );
    00470 }
    00471
    00472
    00473 KDChart::VerticalLineLayoutItem::VerticalLineLayoutItem()
    00474     : AbstractLayoutItem( Qt::AlignCenter )
    00475 {
    00476 }
    00477
    00478 Qt::Orientations KDChart::VerticalLineLayoutItem::expandingDirections() const
    00479 {
    00480     return Qt::Vertical|Qt::Vertical; // Grow both vertically, and horizontally
    00481 }
    00482
    00483 QRect KDChart::VerticalLineLayoutItem::geometry() const
    00484 {
    00485     return mRect;
    00486 }
    00487
    00488 bool KDChart::VerticalLineLayoutItem::isEmpty() const
    00489 {
    00490     return false; // never empty, otherwise the layout item would not exist
    00491 }
    00492
    00493 QSize KDChart::VerticalLineLayoutItem::maximumSize() const
    00494 {
    00495     return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
    00496 }
    00497
    00498 QSize KDChart::VerticalLineLayoutItem::minimumSize() const
    00499 {
    00500     return QSize( 0, 0 );
    00501 }
    00502
    00503 void KDChart::VerticalLineLayoutItem::setGeometry( const QRect& r )
    00504 {
    00505     mRect = r;
    00506 }
    00507
    00508 QSize KDChart::VerticalLineLayoutItem::sizeHint() const
    00509 {
    00510     return QSize( 3, -1 ); // see qframe.cpp
    00511 }
    00512
    00513
    00514 void KDChart::VerticalLineLayoutItem::paint( QPainter* painter )
    00515 {
    00516     if( !mRect.isValid() )
    00517         return;
    00518
    00519     painter->drawLine( QPointF( mRect.center().x(), mRect.top() ),
    00520                        QPointF( mRect.center().x(), mRect.bottom() ) );
    00521 }
    00522
    00523
    00524
    00525 KDChart::MarkerLayoutItem::MarkerLayoutItem( KDChart::AbstractDiagram* diagram,
    00526                                              const MarkerAttributes& marker,
    00527                                              const QBrush& brush, const QPen& pen,
    00528                                              Qt::Alignment alignment )
    00529     : AbstractLayoutItem( alignment )
    00530     , mDiagram( diagram )
    00531     , mMarker( marker )
    00532     , mBrush( brush )
    00533     , mPen( pen )
    00534 {
    00535 }
    00536
    00537 Qt::Orientations KDChart::MarkerLayoutItem::expandingDirections() const
    00538 {
    00539     return 0; // Grow neither vertically nor horizontally
    00540 }
    00541
    00542 QRect KDChart::MarkerLayoutItem::geometry() const
    00543 {
    00544     return mRect;
    00545 }
    00546
    00547 bool KDChart::MarkerLayoutItem::isEmpty() const
    00548 {
    00549     return false; // never empty, otherwise the layout item would not exist
    00550 }
    00551
    00552 QSize KDChart::MarkerLayoutItem::maximumSize() const
    00553 {
    00554     return sizeHint(); // PENDING(kalle) Review, quite inflexible
    00555 }
    00556
    00557 QSize KDChart::MarkerLayoutItem::minimumSize() const
    00558 {
    00559     return sizeHint(); // PENDING(kalle) Review, quite inflexible
    00560 }
    00561
    00562 void KDChart::MarkerLayoutItem::setGeometry( const QRect& r )
    00563 {
    00564     mRect = r;
    00565 }
    00566
    00567 QSize KDChart::MarkerLayoutItem::sizeHint() const
    00568 {
    00569     //qDebug() << "KDChart::MarkerLayoutItem::sizeHint() returns:"<<mMarker.markerSize().toSize();
    00570     return mMarker.markerSize().toSize();
    00571 }
    00572
    00573 void KDChart::MarkerLayoutItem::paint( QPainter* painter )
    00574 {
    00575     paintIntoRect( painter, mRect, mDiagram, mMarker, mBrush, mPen );
    00576 }
    00577
    00578 void KDChart::MarkerLayoutItem::paintIntoRect(
    00579         QPainter* painter,
    00580         const QRect& rect,
    00581         AbstractDiagram* diagram,
    00582         const MarkerAttributes& marker,
    00583         const QBrush& brush,
    00584         const QPen& pen )
    00585 {
    00586     if( ! rect.isValid() )
    00587         return;
    00588
    00589     // The layout management may assign a larger rect than what we
    00590     // wanted. We need to adjust the position.
    00591     const QSize siz = marker.markerSize().toSize();
    00592     QPointF pos = rect.topLeft();
    00593     pos += QPointF( static_cast<qreal>(( rect.width()  - siz.width()) / 2.0 ),
    00594                     static_cast<qreal>(( rect.height() - siz.height()) / 2.0 ) );
    00595
    00596 #ifdef DEBUG_ITEMS_PAINT
    00597     QPointF oldPos = pos;
    00598 #endif
    00599
    00600 // And finally, drawMarker() assumes the position to be the center
    00601     // of the marker, adjust again.
    00602     pos += QPointF( static_cast<qreal>( siz.width() ) / 2.0,
    00603                     static_cast<qreal>( siz.height() )/ 2.0 );
    00604
    00605     diagram->paintMarker( painter, marker, brush, pen, pos.toPoint(), siz );
    00606
    00607 #ifdef DEBUG_ITEMS_PAINT
    00608     const QPen oldPen( painter->pen() );
    00609     painter->setPen( Qt::red );
    00610     painter->drawRect( QRect(oldPos.toPoint(), siz) );
    00611     painter->setPen( oldPen );
    00612 #endif
    00613 }
    00614
    00615
    00616 KDChart::LineLayoutItem::LineLayoutItem( KDChart::AbstractDiagram* diagram,
    00617                                          int length,
    00618                                          const QPen& pen,
    00619                                          Qt::Alignment alignment )
    00620     : AbstractLayoutItem( alignment )
    00621     , mDiagram( diagram )
    00622     , mLength( length )
    00623     , mPen( pen )
    00624 {
    00625     //have a mini pen width
    00626     if ( pen.width() < 2 )
    00627         mPen.setWidth( 2 );
    00628 }
    00629
    00630 Qt::Orientations KDChart::LineLayoutItem::expandingDirections() const
    00631 {
    00632     return 0; // Grow neither vertically nor horizontally
    00633 }
    00634
    00635 QRect KDChart::LineLayoutItem::geometry() const
    00636 {
    00637     return mRect;
    00638 }
    00639
    00640 bool KDChart::LineLayoutItem::isEmpty() const
    00641 {
    00642     return false; // never empty, otherwise the layout item would not exist
    00643 }
    00644
    00645 QSize KDChart::LineLayoutItem::maximumSize() const
    00646 {
    00647     return sizeHint(); // PENDING(kalle) Review, quite inflexible
    00648 }
    00649
    00650 QSize KDChart::LineLayoutItem::minimumSize() const
    00651 {
    00652     return sizeHint(); // PENDING(kalle) Review, quite inflexible
    00653 }
    00654
    00655 void KDChart::LineLayoutItem::setGeometry( const QRect& r )
    00656 {
    00657     mRect = r;
    00658 }
    00659
    00660 QSize KDChart::LineLayoutItem::sizeHint() const
    00661 {
    00662     return QSize( mLength, mPen.width()+2 );
    00663 }
    00664
    00665 void KDChart::LineLayoutItem::paint( QPainter* painter )
    00666 {
    00667     paintIntoRect( painter, mRect, mPen );
    00668 }
    00669
    00670 void KDChart::LineLayoutItem::paintIntoRect(
    00671         QPainter* painter,
    00672         const QRect& rect,
    00673         const QPen& pen )
    00674 {
    00675     if( ! rect.isValid() )
    00676         return;
    00677
    00678     const QPen oldPen = painter->pen();
    00679     painter->setPen( pen );
    00680     const qreal y = rect.center().y();
    00681     painter->drawLine( QPointF( rect.left(), y ),
    00682                        QPointF( rect.right(), y ) );
    00683     painter->setPen( oldPen );
    00684 }
    00685
    00686
    00687 KDChart::LineWithMarkerLayoutItem::LineWithMarkerLayoutItem(
    00688         KDChart::AbstractDiagram* diagram,
    00689         int lineLength,
    00690         const QPen& linePen,
    00691         int markerOffs,
    00692         const MarkerAttributes& marker,
    00693         const QBrush& markerBrush,
    00694         const QPen& markerPen,
    00695         Qt::Alignment alignment )
    00696     : AbstractLayoutItem( alignment )
    00697     , mDiagram(     diagram )
    00698     , mLineLength(  lineLength )
    00699     , mLinePen(     linePen )
    00700     , mMarkerOffs(  markerOffs )
    00701     , mMarker(      marker )
    00702     , mMarkerBrush( markerBrush )
    00703     , mMarkerPen(   markerPen )
    00704 {
    00705 }
    00706
    00707 Qt::Orientations KDChart::LineWithMarkerLayoutItem::expandingDirections() const
    00708 {
    00709     return 0; // Grow neither vertically nor horizontally
    00710 }
    00711
    00712 QRect KDChart::LineWithMarkerLayoutItem::geometry() const
    00713 {
    00714     return mRect;
    00715 }
    00716
    00717 bool KDChart::LineWithMarkerLayoutItem::isEmpty() const
    00718 {
    00719     return false; // never empty, otherwise the layout item would not exist
    00720 }
    00721
    00722 QSize KDChart::LineWithMarkerLayoutItem::maximumSize() const
    00723 {
    00724     return sizeHint(); // PENDING(kalle) Review, quite inflexible
    00725 }
    00726
    00727 QSize KDChart::LineWithMarkerLayoutItem::minimumSize() const
    00728 {
    00729     return sizeHint(); // PENDING(kalle) Review, quite inflexible
    00730 }
    00731
    00732 void KDChart::LineWithMarkerLayoutItem::setGeometry( const QRect& r )
    00733 {
    00734     mRect = r;
    00735 }
    00736
    00737 QSize KDChart::LineWithMarkerLayoutItem::sizeHint() const
    00738 {
    00739     const QSize sizeM = mMarker.markerSize().toSize();
    00740     const QSize sizeL = QSize( mLineLength, mLinePen.width()+2 );
    00741     return QSize( qMax(sizeM.width(),  sizeL.width()),
    00742                   qMax(sizeM.height(), sizeL.height()) );
    00743 }
    00744
    00745 void KDChart::LineWithMarkerLayoutItem::paint( QPainter* painter )
    00746 {
    00747     // paint the line over the full width, into the vertical middle of the rect
    00748     LineLayoutItem::paintIntoRect( painter, mRect, mLinePen );
    00749
    00750     // paint the marker with the given offset from the left side of the line
    00751     const QRect r(
    00752             QPoint( mRect.x()+mMarkerOffs, mRect.y() ),
    00753             QSize( mMarker.markerSize().toSize().width(), mRect.height() ) );
    00754     MarkerLayoutItem::paintIntoRect(
    00755             painter, r, mDiagram, mMarker, mMarkerBrush, mMarkerPen );
    00756 }
    00757
    00758
    00759
    00760 KDChart::AutoSpacerLayoutItem::AutoSpacerLayoutItem(
    00761         bool layoutIsAtTopPosition, QHBoxLayout *rightLeftLayout,
    00762         bool layoutIsAtLeftPosition, QVBoxLayout *topBottomLayout )
    00763     : AbstractLayoutItem( Qt::AlignCenter )
    00764     , mLayoutIsAtTopPosition(  layoutIsAtTopPosition )
    00765     , mRightLeftLayout( rightLeftLayout )
    00766     , mLayoutIsAtLeftPosition( layoutIsAtLeftPosition )
    00767     , mTopBottomLayout( topBottomLayout )
    00768 {
    00769 }
    00770
    00771 Qt::Orientations KDChart::AutoSpacerLayoutItem::expandingDirections() const
    00772 {
    00773     return 0; // Grow neither vertically nor horizontally
    00774 }
    00775
    00776 QRect KDChart::AutoSpacerLayoutItem::geometry() const
    00777 {
    00778     return mRect;
    00779 }
    00780
    00781 bool KDChart::AutoSpacerLayoutItem::isEmpty() const
    00782 {
    00783     return true; // never empty, otherwise the layout item would not exist
    00784 }
    00785
    00786 QSize KDChart::AutoSpacerLayoutItem::maximumSize() const
    00787 {
    00788     return sizeHint();
    00789 }
    00790
    00791 QSize KDChart::AutoSpacerLayoutItem::minimumSize() const
    00792 {
    00793     return sizeHint();
    00794 }
    00795
    00796 void KDChart::AutoSpacerLayoutItem::setGeometry( const QRect& r )
    00797 {
    00798     mRect = r;
    00799 }
    00800
    00801
    00802 static void updateCommonBrush( QBrush& commonBrush, bool& bStart, const KDChart::AbstractArea& area )
    00803 {
    00804     const KDChart::BackgroundAttributes ba( area.backgroundAttributes() );
    00805     const bool hasSimpleBrush = (
    00806             ! area.frameAttributes().isVisible() &&
    00807             ba.isVisible() &&
    00808             ba.pixmapMode() == KDChart::BackgroundAttributes::BackgroundPixmapModeNone &&
    00809             ba.brush().gradient() == 0 );
    00810     if( bStart ){
    00811         bStart = false;
    00812         commonBrush = hasSimpleBrush ? ba.brush() : QBrush();
    00813     }else{
    00814         if( ! hasSimpleBrush || ba.brush() != commonBrush )
    00815         {
    00816             commonBrush = QBrush();
    00817         }
    00818     }
    00819 }
    00820
    00821 QSize KDChart::AutoSpacerLayoutItem::sizeHint() const
    00822 {
    00823     QBrush commonBrush;
    00824     bool bStart=true;
    00825     // calculate the maximal overlap of the top/bottom axes:
    00826     int topBottomOverlap = 0;
    00827     if( mTopBottomLayout ){
    00828         for (int i = 0; i < mTopBottomLayout->count(); ++i){
    00829             AbstractArea* area = dynamic_cast<AbstractArea*>(mTopBottomLayout->itemAt(i));
    00830             if( area ){
    00831                 //qDebug() << "AutoSpacerLayoutItem testing" << area;
    00832                 topBottomOverlap =
    00833                     mLayoutIsAtLeftPosition
    00834                     ? qMax( topBottomOverlap, area->rightOverlap() )
    00835                     : qMax( topBottomOverlap, area->leftOverlap() );
    00836                 updateCommonBrush( commonBrush, bStart, *area );
    00837             }
    00838         }
    00839     }
    00840     // calculate the maximal overlap of the left/right axes:
    00841     int leftRightOverlap = 0;
    00842     if( mRightLeftLayout ){
    00843         for (int i = 0; i < mRightLeftLayout->count(); ++i){
    00844             AbstractArea* area = dynamic_cast<AbstractArea*>(mRightLeftLayout->itemAt(i));
    00845             if( area ){
    00846                 //qDebug() << "AutoSpacerLayoutItem testing" << area;
    00847                 leftRightOverlap =
    00848                         mLayoutIsAtTopPosition
    00849                         ? qMax( leftRightOverlap, area->bottomOverlap() )
    00850                         : qMax( leftRightOverlap, area->topOverlap() );
    00851                 updateCommonBrush( commonBrush, bStart, *area );
    00852             }
    00853         }
    00854     }
    00855     if( topBottomOverlap > 0 && leftRightOverlap > 0 )
    00856         mCommonBrush = commonBrush;
    00857     else
    00858         mCommonBrush = QBrush();
    00859     mCachedSize = QSize( topBottomOverlap, leftRightOverlap );
    00860     //qDebug() << mCachedSize;
    00861     return mCachedSize;
    00862 }
    00863
    00864
    00865 void KDChart::AutoSpacerLayoutItem::paint( QPainter* painter )
    00866 {
    00867     if( mParentLayout && mRect.isValid() && mCachedSize.isValid() &&
    00868         mCommonBrush.style() != Qt::NoBrush )
    00869     {
    00870         QPoint p1( mRect.topLeft() );
    00871         QPoint p2( mRect.bottomRight() );
    00872         if( mLayoutIsAtLeftPosition )
    00873             p1.rx() += mCachedSize.width() - mParentLayout->spacing();
    00874         else
    00875             p2.rx() -= mCachedSize.width() - mParentLayout->spacing();
    00876         if( mLayoutIsAtTopPosition ){
    00877             p1.ry() += mCachedSize.height() - mParentLayout->spacing() - 1;
    00878             p2.ry() -= 1;
    00879         }else
    00880             p2.ry() -= mCachedSize.height() - mParentLayout->spacing() - 1;
    00881         //qDebug() << mLayoutIsAtTopPosition << mLayoutIsAtLeftPosition;
    00882         //qDebug() << mRect;
    00883         //qDebug() << mParentLayout->margin();
    00884         //qDebug() << QRect( p1, p2 );
    00885         const QPoint oldBrushOrigin( painter->brushOrigin() );
    00886         const QBrush oldBrush( painter->brush() );
    00887         const QPen   oldPen(   painter->pen() );
    00888         const QPointF newTopLeft( painter->deviceMatrix().map( p1 ) );
    00889         painter->setBrushOrigin( newTopLeft );
    00890         painter->setBrush( mCommonBrush );
    00891         painter->setPen( Qt::NoPen );
    00892         painter->drawRect( QRect( p1, p2 ) );
    00893         painter->setBrushOrigin( oldBrushOrigin );
    00894         painter->setBrush( oldBrush );
    00895         painter->setPen( oldPen );
    00896     }
    00897     // debug code:
    00898 #if 0
    00899     //qDebug() << "KDChart::AutoSpacerLayoutItem::paint()";
    00900     if( !mRect.isValid() )
    00901         return;
    00902
    00903     painter->drawRect( mRect );
    00904     painter->drawLine( QPointF( mRect.x(), mRect.top() ),
    00905                        QPointF( mRect.right(), mRect.bottom() ) );
    00906     painter->drawLine( QPointF( mRect.right(), mRect.top() ),
    00907                        QPointF( mRect.x(), mRect.bottom() ) );
    00908 #endif
    00909 }