KDChartLayoutItems.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (C) 2001-2011 Klaralvdalens Datakonsult AB.  All rights reserved.
00003 **
00004 ** This file is part of the KD Chart library.
00005 **
00006 ** Licensees holding valid commercial KD Chart licenses may use this file in
00007 ** accordance with the KD Chart Commercial License Agreement provided with
00008 ** the Software.
00009 **
00010 **
00011 ** This file may be distributed and/or modified under the terms of the
00012 ** GNU General Public License version 2 and version 3 as published by the
00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
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 ** Contact info@kdab.com if any conditions of this licensing are not
00019 ** clear to you.
00020 **
00021 **********************************************************************/
00022 
00023 #include "KDChartLayoutItems.h"
00024 #include "KDTextDocument.h"
00025 #include "KDChartAbstractArea.h"
00026 #include "KDChartAbstractDiagram.h"
00027 #include "KDChartBackgroundAttributes.h"
00028 #include "KDChartFrameAttributes.h"
00029 #include "KDChartPaintContext.h"
00030 #include "KDChartPainterSaver_p.h"
00031 #include "KDChartPrintingParameters.h"
00032 #include <QTextCursor>
00033 #include <QTextBlockFormat>
00034 #include <QTextDocumentFragment>
00035 #include <QAbstractTextDocumentLayout>
00036 #include <QLayout>
00037 #include <QPainter>
00038 #include <QDebug>
00039 #include <QCoreApplication>
00040 #include <QApplication>
00041 #include <QStringList>
00042 #include <QStyle>
00043 
00044 #include <KDABLibFakes>
00045 
00046 #include <math.h>
00047 
00048 #define PI 3.141592653589793
00049 
00050 
00051 
00052 //#define DEBUG_ITEMS_PAINT
00053 
00062 void KDChart::AbstractLayoutItem::setParentWidget( QWidget* widget )
00063 {
00064     mParent = widget;
00065 }
00066 
00067 void KDChart::AbstractLayoutItem::paintAll( QPainter& painter )
00068 {
00069     paint( &painter );
00070 }
00071 
00075 void KDChart::AbstractLayoutItem::paintCtx( PaintContext* context )
00076 {
00077     if( context )
00078         paint( context->painter() );
00079 }
00080 
00084 void KDChart::AbstractLayoutItem::sizeHintChanged()const
00085 {
00086     // This is exactly like what QWidget::updateGeometry does.
00087 //  qDebug("KDChart::AbstractLayoutItem::sizeHintChanged() called");
00088     if( mParent ) {
00089         if ( mParent->layout() )
00090             mParent->layout()->invalidate();
00091         else
00092             QApplication::postEvent( mParent, new QEvent( QEvent::LayoutRequest ) );
00093     }
00094 }
00095 
00096 KDChart::TextBubbleLayoutItem::TextBubbleLayoutItem( const QString& text,
00097                                          const KDChart::TextAttributes& attributes,
00098                                          const QObject* area,
00099                                          KDChartEnums::MeasureOrientation orientation,
00100                                          Qt::Alignment alignment )
00101     : AbstractLayoutItem( alignment ),
00102       m_text( new TextLayoutItem( text, attributes, area, orientation, alignment ) )
00103 {
00104 }
00105 
00106 KDChart::TextBubbleLayoutItem::TextBubbleLayoutItem()
00107     : AbstractLayoutItem( Qt::AlignLeft ),
00108       m_text( new TextLayoutItem() )
00109 {
00110 }
00111 
00112 KDChart::TextBubbleLayoutItem::~TextBubbleLayoutItem()
00113 {
00114     delete m_text;
00115 }
00116 
00117 void KDChart::TextBubbleLayoutItem::setAutoReferenceArea( const QObject* area )
00118 {
00119     m_text->setAutoReferenceArea( area );
00120 }
00121 
00122 const QObject* KDChart::TextBubbleLayoutItem::autoReferenceArea() const
00123 {
00124     return m_text->autoReferenceArea();
00125 }
00126 
00127 void KDChart::TextBubbleLayoutItem::setText( const QString& text )
00128 {
00129     m_text->setText( text );
00130 }
00131 
00132 QString KDChart::TextBubbleLayoutItem::text() const
00133 {
00134     return m_text->text();
00135 }
00136 
00137 void KDChart::TextBubbleLayoutItem::setTextAttributes( const TextAttributes& a )
00138 {
00139     m_text->setTextAttributes( a );
00140 }
00141 
00142 KDChart::TextAttributes KDChart::TextBubbleLayoutItem::textAttributes() const
00143 {
00144     return m_text->textAttributes();
00145 }
00146 
00147 bool KDChart::TextBubbleLayoutItem::isEmpty() const
00148 {
00149     return m_text->isEmpty();
00150 }
00151 
00152 Qt::Orientations KDChart::TextBubbleLayoutItem::expandingDirections() const
00153 {
00154     return m_text->expandingDirections();
00155 }
00156 
00157 QSize KDChart::TextBubbleLayoutItem::maximumSize() const
00158 {
00159     const int border = borderWidth();
00160     return m_text->maximumSize() + QSize( 2 * border, 2 * border );
00161 }
00162 
00163 QSize KDChart::TextBubbleLayoutItem::minimumSize() const
00164 {
00165     const int border = borderWidth();
00166     return m_text->minimumSize() + QSize( 2 * border, 2 * border );
00167 }
00168 
00169 QSize KDChart::TextBubbleLayoutItem::sizeHint() const
00170 {
00171     const int border = borderWidth();
00172     return m_text->sizeHint() + QSize( 2 * border, 2 * border );
00173 }
00174 
00175 void KDChart::TextBubbleLayoutItem::setGeometry( const QRect& r )
00176 {
00177     const int border = borderWidth();
00178     m_text->setGeometry( r.adjusted( border, border, -border, -border ) );
00179 }
00180 
00181 QRect KDChart::TextBubbleLayoutItem::geometry() const
00182 {
00183     const int border = borderWidth();
00184     return m_text->geometry().adjusted( -border, -border, border, border );
00185 }
00186 
00187 void KDChart::TextBubbleLayoutItem::paint( QPainter* painter )
00188 {
00189     const QPen oldPen = painter->pen();
00190     const QBrush oldBrush = painter->brush();
00191     painter->setPen( Qt::black );
00192     painter->setBrush( QColor( 255, 255, 220 ) );
00193     painter->drawRoundRect( geometry(), 10 );
00194     painter->setPen( oldPen );
00195     painter->setBrush( oldBrush );
00196     m_text->paint( painter );
00197 }
00198 
00199 int KDChart::TextBubbleLayoutItem::borderWidth() const
00200 {
00201     return 1;
00202 }
00203 
00204 KDChart::TextLayoutItem::TextLayoutItem( const QString& text,
00205                                          const KDChart::TextAttributes& attributes,
00206                                          const QObject* area,
00207                                          KDChartEnums::MeasureOrientation orientation,
00208                                          Qt::Alignment alignment )
00209     : AbstractLayoutItem( alignment )
00210     , mText( text )
00211     , mTextAlignment( alignment )
00212     , mAttributes( attributes )
00213     , mAutoReferenceArea( area )
00214     , mAutoReferenceOrientation( orientation )
00215     , cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
00216     , cachedFontSize( 0.0 )
00217     , cachedFont( mAttributes.font() )
00218 {
00219 }
00220 
00221 KDChart::TextLayoutItem::TextLayoutItem()
00222     : AbstractLayoutItem( Qt::AlignLeft )
00223     , mText()
00224     , mTextAlignment( Qt::AlignLeft )
00225     , mAttributes()
00226     , mAutoReferenceArea( 0 )
00227     , mAutoReferenceOrientation( KDChartEnums::MeasureOrientationHorizontal )
00228     , cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
00229     , cachedFontSize( 0.0 )
00230     , cachedFont( mAttributes.font() )
00231 {
00232 
00233 }
00234 
00235 void KDChart::TextLayoutItem::setAutoReferenceArea( const QObject* area )
00236 {
00237     mAutoReferenceArea = area;
00238     cachedSizeHint = QSize();
00239     sizeHint();
00240 }
00241 
00242 const QObject* KDChart::TextLayoutItem::autoReferenceArea() const
00243 {
00244     return mAutoReferenceArea;
00245 }
00246 
00247 void KDChart::TextLayoutItem::setText(const QString & text)
00248 {
00249     mText = text;
00250     cachedSizeHint = QSize();
00251     sizeHint();
00252     if( mParent )
00253         mParent->update();
00254 }
00255 
00256 QString KDChart::TextLayoutItem::text() const
00257 {
00258     return mText;
00259 }
00260 
00261 void KDChart::TextLayoutItem::setTextAlignment( Qt::Alignment alignment)
00262 {
00263     if( mTextAlignment == alignment )
00264         return;
00265     mTextAlignment = alignment;
00266     if( mParent )
00267         mParent->update();
00268 }
00269 
00270 Qt::Alignment KDChart::TextLayoutItem::textAlignment() const
00271 {
00272     return mTextAlignment;
00273 }
00274 
00280 void KDChart::TextLayoutItem::setTextAttributes( const TextAttributes &a )
00281 {
00282     mAttributes = a;
00283     cachedFont = a.font();
00284     cachedSizeHint = QSize(); // invalidate size hint
00285     sizeHint();
00286     if( mParent )
00287         mParent->update();
00288 }
00289 
00295 KDChart::TextAttributes KDChart::TextLayoutItem::textAttributes() const
00296 {
00297     return mAttributes;
00298 }
00299 
00300 
00301 Qt::Orientations KDChart::TextLayoutItem::expandingDirections() const
00302 {
00303     return 0; // Grow neither vertically nor horizontally
00304 }
00305 
00306 QRect KDChart::TextLayoutItem::geometry() const
00307 {
00308     return mRect;
00309 }
00310 
00311 bool KDChart::TextLayoutItem::isEmpty() const
00312 {
00313     return false; // never empty, otherwise the layout item would not exist
00314 }
00315 
00316 QSize KDChart::TextLayoutItem::maximumSize() const
00317 {
00318     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00319 }
00320 
00321 QSize KDChart::TextLayoutItem::minimumSize() const
00322 {
00323     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00324 }
00325 
00326 void KDChart::TextLayoutItem::setGeometry( const QRect& r )
00327 {
00328     mRect = r;
00329 }
00330 
00331 QPointF rotatedPoint( const QPointF& pt, qreal rotation, const QPointF& center )
00332 {
00333     const qreal angle = PI * rotation / 180.0;
00334     const qreal cosAngle = cos( angle );
00335     const qreal sinAngle = -sin( angle );
00336     return QPointF(
00337             (cosAngle * ( pt.x() - center.x() ) + sinAngle * ( pt.y() - center.y() ) ),
00338             (cosAngle * ( pt.y() - center.y() ) - sinAngle * ( pt.x() - center.x() ) ) ) + center;
00339 }
00340 
00341 
00342 QRectF rotatedRect( const QRectF& oldRect, qreal angleInt, const QPointF& center )
00343 {
00344     const QRect rect( oldRect.translated( center ).toRect() );
00345     const qreal angle = PI * angleInt / 180.0;
00346     const qreal cosAngle = cos( angle );
00347     const qreal sinAngle = sin( angle );
00348     QMatrix rotationMatrix(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
00349     QPolygon rotPts;
00350     rotPts <<  rotationMatrix.map(rect.topLeft()) //QPoint(0,0)
00351             << rotationMatrix.map(rect.topRight())
00352             << rotationMatrix.map(rect.bottomRight())
00353             << rotationMatrix.map(rect.bottomLeft());
00354             //<< rotatedPoint(rect.topRight(), angleInt, center).toPoint()
00355             //<< rotatedPoint(rect.bottomRight(), angleInt, center).toPoint()
00356             //<< rotatedPoint(rect.bottomLeft(), angleInt, center).toPoint();
00357     return rotPts.boundingRect();
00358 /*
00359     const QPointF topLeft( rotatedPoint( oldRect.topLeft(), angle, center ) );
00360     const QPointF topRight( rotatedPoint( oldRect.topRight(), angle, center ) );
00361     const QPointF bottomLeft( rotatedPoint( oldRect.bottomLeft(), angle, center ) );
00362     const QPointF bottomRight( rotatedPoint( oldRect.bottomRight(), angle, center ) );
00363 
00364     const qreal x = qMin( qMin( topLeft.x(), topRight.x() ), qMin( bottomLeft.x(), topLeft.x() ) );
00365     const qreal y = qMin( qMin( topLeft.y(), topRight.y() ), qMin( bottomLeft.y(), topLeft.y() ) );
00366     const qreal width = qMax( qMax( topLeft.x(), topRight.x() ), qMax( bottomLeft.x(), topLeft.x() ) ) - x;
00367     const qreal height = qMax( qMax( topLeft.y(), topRight.y() ), qMax( bottomLeft.y(), topLeft.y() ) ) - y;
00368 
00369     return QRectF( x, y, width, height );
00370 */
00371 }
00372 
00373 /*
00374 QRectF rotatedRect( const QRectF& rect, qreal angle )
00375 {
00376     const QPointF topLeft(  rotatedPoint( rect.topLeft(),  angle ) );
00377     //const QPointF topRight( rotatedPoint( rect.topRight(), angle ) );
00378     //const QPointF bottomLeft(  rotatedPoint( rect.bottomLeft(),  angle ) );
00379 #if 1
00380     const QPointF bottomRight( rotatedPoint( rect.bottomRight(), angle ) );
00381     const QRectF result( topLeft, QSizeF( bottomRight.x() - topLeft.x(), bottomRight.y() - topLeft.y() ) );
00382 #else
00383     const QPointF siz( rotatedPoint( QPointF( rect.size().width(), rect.size().height() ), angle ) );
00384     const QRectF result(
00385             topLeft,
00386             QSizeF( siz.x(), //bottomRight.x() - topLeft.x(),
00387                     siz.y() ) ); //bottomRight.y() - topLeft.y() ) );
00388     //qDebug() << "angle" << angle << "\nbefore:" << rect << "\n after:" << result;
00389 #endif
00390     return result;
00391 }*/
00392 
00393 qreal KDChart::TextLayoutItem::fitFontSizeToGeometry() const
00394 {
00395     QFont f = realFont();
00396     const qreal origResult = f.pointSizeF();
00397     qreal result = origResult;
00398     const qreal minSize = mAttributes.minimalFontSize().value();
00399     const QSize mySize = geometry().size();
00400     if( mySize.isNull() )
00401         return result;
00402 
00403     const QString t = text();
00404     QFontMetrics fm( f );
00405     while( true )
00406     {
00407         const QSizeF textSize = rotatedRect( fm.boundingRect( t ), mAttributes.rotation() ).normalized().size();
00408 
00409         if( textSize.height() <= mySize.height() && textSize.width() <= mySize.width() )
00410             return result;
00411 
00412         result -= 0.5;
00413         if ( minSize > 0 && result < minSize )
00414             return result += 0.5;
00415         if( result <= 0.0 )
00416             return origResult;
00417         f.setPointSizeF( result );
00418         fm = QFontMetrics( f );
00419     }
00420 }
00421 
00422 qreal KDChart::TextLayoutItem::realFontSize() const
00423 {
00424     return mAttributes.calculatedFontSize( mAutoReferenceArea, mAutoReferenceOrientation );
00425 }
00426 
00427 
00428 bool KDChart::TextLayoutItem::realFontWasRecalculated() const
00429 {
00430     const qreal fntSiz = realFontSize();
00431     const bool bRecalcDone =
00432         ( ( ! cachedSizeHint.isValid() ) || ( cachedFontSize != fntSiz   ) );
00433 
00434     if( bRecalcDone && fntSiz > 0.0 ){
00435         cachedFontSize = fntSiz;
00436         cachedFont.setPointSizeF( fntSiz );
00437     }
00438     return bRecalcDone;
00439 }
00440 
00441 
00442 QFont KDChart::TextLayoutItem::realFont() const
00443 {
00444     realFontWasRecalculated(); // we can safely ignore the boolean return value
00445     return cachedFont;
00446 }
00447 
00448 QPolygon KDChart::TextLayoutItem::rotatedCorners() const
00449 {
00450     // the angle in rad
00451     const qreal angle = mAttributes.rotation() * PI / 180.0;
00452     QSize size = unrotatedSizeHint();
00453 
00454     // my P1 - P4 (the four points of the rotated area)
00455     QPointF P1( size.height() * sin( angle ), 0 );
00456     QPointF P2( size.height() * sin( angle ) + size.width() * cos( angle ), size.width() * sin( angle ) );
00457     QPointF P3( size.width() * cos( angle ), size.width() * sin( angle ) + size.height() * cos( angle ) );
00458     QPointF P4( 0, size.height() * cos( angle ) );
00459 
00460     QPolygon result;
00461     result << P1.toPoint() << P2.toPoint() << P3.toPoint() << P4.toPoint();
00462     return result;
00463 }
00464 
00465 bool KDChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPointF& myPos, const QPointF& otherPos ) const
00466 {
00467     return intersects( other, myPos.toPoint(), otherPos.toPoint() );
00468 }
00469 
00470 bool KDChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPoint& myPos, const QPoint& otherPos ) const
00471 {
00472     if ( mAttributes.rotation() != other.mAttributes.rotation() )
00473     {
00474         // that's the code for the common case: the rotation angles don't need to match here
00475         QPolygon myPolygon(          rotatedCorners() );
00476         QPolygon otherPolygon( other.rotatedCorners() );
00477 
00478         // move the polygons to their positions
00479         myPolygon.translate( myPos );
00480         otherPolygon.translate( otherPos );
00481 
00482         // create regions out of it
00483         QRegion myRegion( myPolygon );
00484         QRegion otherRegion( otherPolygon );
00485 
00486         // now the question - do they intersect or not?
00487         return ! myRegion.intersect( otherRegion ).isEmpty();
00488 
00489     } else {
00490         // and that's the code for the special case: the rotation angles match, which is less time consuming in calculation
00491         const qreal angle = mAttributes.rotation() * PI / 180.0;
00492         // both sizes
00493         const QSizeF mySize(          unrotatedSizeHint() );
00494         const QSizeF otherSize( other.unrotatedSizeHint() );
00495 
00496         // that's myP1 relative to myPos
00497         QPointF myP1( mySize.height() * sin( angle ), 0.0 );
00498         // that's otherP1 to myPos
00499         QPointF otherP1 = QPointF( otherSize.height() * sin( angle ), 0.0 ) + otherPos - myPos;
00500 
00501         // now rotate both points the negative angle around myPos
00502         myP1 = QPointF( myP1.x() * cos( -angle ), myP1.x() * sin( -angle ) );
00503         qreal r = sqrt( otherP1.x() * otherP1.x() + otherP1.y() * otherP1.y() );
00504         otherP1 = QPointF( r * cos( -angle ), r * sin( -angle ) );
00505 
00506         // finally we look, whether both rectangles intersect or even not
00507         const bool res = QRectF( myP1, mySize ).intersects( QRectF( otherP1, otherSize ) );
00508         //qDebug() << res << QRectF( myP1, mySize ) << QRectF( otherP1, otherSize );
00509         return res;
00510     }
00511 }
00512 
00513 QSize KDChart::TextLayoutItem::sizeHint() const
00514 {
00515     QPoint dummy;
00516     return sizeHintAndRotatedCorners(dummy,dummy,dummy,dummy);
00517 }
00518 
00519 QSize KDChart::TextLayoutItem::sizeHintAndRotatedCorners(
00520         QPoint& topLeftPt, QPoint& topRightPt, QPoint& bottomRightPt, QPoint& bottomLeftPt) const
00521 {
00522     if( realFontWasRecalculated() || mAttributes.rotation() )
00523     {
00524         const QSize newSizeHint( calcSizeHint( cachedFont,
00525                                                topLeftPt, topRightPt, bottomRightPt, bottomLeftPt ) );
00526         if( newSizeHint != cachedSizeHint ){
00527             cachedSizeHint = newSizeHint;
00528             sizeHintChanged();
00529         }
00530         cachedTopLeft     = topLeftPt;
00531         cachedTopRight    = topRightPt;
00532         cachedBottomRight = bottomRightPt;
00533         cachedBottomLeft  = bottomLeftPt;
00534     }else{
00535         topLeftPt     = cachedTopLeft;
00536         topRightPt    = cachedTopRight;
00537         bottomRightPt = cachedBottomRight;
00538         bottomLeftPt  = cachedBottomLeft;
00539     }
00540     //qDebug() << "-------- KDChart::TextLayoutItem::sizeHint() returns:"<<cachedSizeHint<<" ----------";
00541     return cachedSizeHint;
00542 }
00543 
00544 QSize KDChart::TextLayoutItem::sizeHintUnrotated() const
00545 {
00546     realFontWasRecalculated(); // make sure the cached font is updated if needed
00547     return unrotatedSizeHint( cachedFont );
00548 }
00549 
00550 
00551 // PENDING(kalle) Support auto shrink
00552 
00553 
00554 QSize KDChart::TextLayoutItem::unrotatedSizeHint( QFont fnt ) const
00555 {
00556     if ( fnt == QFont() )
00557         fnt = realFont(); // this *is* the chached font in most of the time
00558 
00559     const QFontMetricsF met( fnt, GlobalMeasureScaling::paintDevice() );
00560     QSize ret(0, 0);
00561     // note: boundingRect() does NOT take any newlines into account
00562     //       so we need to calculate the size by combining several
00563     //       rectangles: one per line.  This fixes bugz issue #3720.
00564     //       (khz, 2007 04 14)
00565     QStringList lines = mText.split(QString::fromAscii("\n"));
00566     for (int i = 0; i < lines.size(); ++i) {
00567         const QSize lSize = met.boundingRect(lines.at(i) ).toRect().size();
00568         ret.setWidth(qMax( ret.width(), lSize.width() ));
00569         ret.rheight() += lSize.height();
00570     }
00571 
00572     int frame = QApplication::style()->pixelMetric( QStyle::PM_ButtonMargin, 0, 0 );
00573     // fine-tuning for small font sizes: the frame must not be so big, if the font is tiny
00574     frame = qMin( frame, ret.height() * 2 / 3 );
00575     //qDebug() << "frame:"<< frame;
00576     ret += QSize( frame, frame );
00577     return ret;
00578     //const QFontMetricsF met( fnt, GlobalMeasureScaling::paintDevice() );
00579     //const int frame = QApplication::style()->pixelMetric( QStyle::PM_ButtonMargin, 0, 0 );
00580     //return
00581     //    met.boundingRect( mText ).size().toSize() + QSize( frame, frame );
00582 }
00583 
00584 
00585 QSize KDChart::TextLayoutItem::calcSizeHint(
00586         QFont fnt, QPoint& topLeftPt, QPoint& topRightPt, QPoint& bottomRightPt, QPoint& bottomLeftPt ) const
00587 {
00588     const QSize siz( unrotatedSizeHint( fnt ));
00589     //qDebug() << "-------- siz: "<<siz;
00590     if( ! mAttributes.rotation() ){
00591         topLeftPt     = QPoint(0,0);
00592         topRightPt    = QPoint(siz.width(),0);
00593         bottomRightPt = QPoint(siz.width(),siz.height());
00594         bottomLeftPt  = QPoint(0,siz.height());
00595         return siz;
00596     }
00597 
00598     const QRect rect(QPoint(0, 0), siz + QSize(4,4));
00599     const qreal angle = PI * mAttributes.rotation() / 180.0;
00600     const qreal cosAngle = cos( angle );
00601     const qreal sinAngle = sin( angle );
00602     QMatrix rotationMatrix(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
00603     QPolygon rotPts;
00604     rotPts << rotationMatrix.map(rect.topLeft())
00605            << rotationMatrix.map(rect.topRight())
00606            << rotationMatrix.map(rect.bottomRight())
00607            << rotationMatrix.map(rect.bottomLeft());
00608     QSize rotSiz( rotPts.boundingRect().size() );
00609     //qDebug() << "-------- KDChart::TextLayoutItem::calcSizeHint() returns:"<<rotSiz<<rotPts;
00610     topLeftPt     = rotPts[0];
00611     topRightPt    = rotPts[1];
00612     bottomRightPt = rotPts[2];
00613     bottomLeftPt  = rotPts[3];
00614     return rotSiz;
00615 }
00616 
00617 
00618 void KDChart::TextLayoutItem::paint( QPainter* painter )
00619 {
00620     // make sure, cached font is updated, if needed:
00621     // sizeHint();
00622 
00623     if( !mRect.isValid() )
00624         return;
00625 
00626     const PainterSaver painterSaver( painter );
00627     QFont f = realFont();
00628     if ( mAttributes.autoShrink() )
00629         f.setPointSizeF( fitFontSizeToGeometry() );
00630     painter->setFont( f );
00631     QRectF rect( geometry() );
00632 
00633 // #ifdef DEBUG_ITEMS_PAINT
00634 //     painter->setPen( Qt::black );
00635 //     painter->drawRect( rect );
00636 // #endif
00637     painter->translate( rect.center() );
00638     rect.moveTopLeft( QPointF( - rect.width() / 2, - rect.height() / 2 ) );
00639 #ifdef DEBUG_ITEMS_PAINT
00640     painter->setPen( Qt::blue );
00641     painter->drawRect( rect );
00642     painter->drawRect( QRect(QPoint((rect.topLeft().toPoint()  + rect.bottomLeft().toPoint())  / 2 - QPoint(2,2)), QSize(3,3)) );
00643     //painter->drawRect( QRect(QPoint((rect.topRight().toPoint() + rect.bottomRight().toPoint()) / 2 - QPoint(2,2)), QSize(3,3)) );
00644 #endif
00645     painter->rotate( mAttributes.rotation() );
00646     rect = rotatedRect( rect, mAttributes.rotation() );
00647 #ifdef DEBUG_ITEMS_PAINT
00648     painter->setPen( Qt::red );
00649     painter->drawRect( rect );
00650     painter->drawRect( QRect(QPoint((rect.topLeft().toPoint()  + rect.bottomLeft().toPoint())  / 2 - QPoint(2,2)), QSize(3,3)) );
00651     //painter->drawRect( QRect(QPoint((rect.topRight().toPoint() + rect.bottomRight().toPoint()) / 2 - QPoint(2,2)), QSize(3,3)) );
00652 #endif
00653     painter->setPen( PrintingParameters::scalePen( mAttributes.pen() ) );
00654     QFontMetrics fontMetrics( f );
00655     const int AHight = fontMetrics.boundingRect( QChar::fromAscii( 'A' ) ).height();
00656     const qreal AVCenter = fontMetrics.ascent() - AHight / 2.0;
00657     // Make sure that capital letters are vertically centered. This looks much
00658     // better than just centering the text's bounding rect.
00659     rect.translate( 0.0, rect.height() / 2.0 - AVCenter );
00660     //painter->drawText( rect, Qt::AlignHCenter | Qt::AlignTop, mText );
00661     painter->drawText( rect, mTextAlignment, mText );
00662 
00663 //    if (  calcSizeHint( realFont() ).width() > rect.width() )
00664 //        qDebug() << "rect.width()" << rect.width() << "text.width()" << calcSizeHint( realFont() ).width();
00665 //
00666 //    //painter->drawText( rect, Qt::AlignHCenter | Qt::AlignVCenter, mText );
00667 }
00668 
00669 KDChart::HorizontalLineLayoutItem::HorizontalLineLayoutItem()
00670     : AbstractLayoutItem( Qt::AlignCenter )
00671 {
00672 }
00673 
00674 Qt::Orientations KDChart::HorizontalLineLayoutItem::expandingDirections() const
00675 {
00676     return Qt::Vertical|Qt::Horizontal; // Grow both vertically, and horizontally
00677 }
00678 
00679 QRect KDChart::HorizontalLineLayoutItem::geometry() const
00680 {
00681     return mRect;
00682 }
00683 
00684 bool KDChart::HorizontalLineLayoutItem::isEmpty() const
00685 {
00686     return false; // never empty, otherwise the layout item would not exist
00687 }
00688 
00689 QSize KDChart::HorizontalLineLayoutItem::maximumSize() const
00690 {
00691     return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00692 }
00693 
00694 QSize KDChart::HorizontalLineLayoutItem::minimumSize() const
00695 {
00696     return QSize( 0, 0 );
00697 }
00698 
00699 void KDChart::HorizontalLineLayoutItem::setGeometry( const QRect& r )
00700 {
00701     mRect = r;
00702 }
00703 
00704 QSize KDChart::HorizontalLineLayoutItem::sizeHint() const
00705 {
00706     return QSize( -1, 3 ); // see qframe.cpp
00707 }
00708 
00709 
00710 void KDChart::HorizontalLineLayoutItem::paint( QPainter* painter )
00711 {
00712     if( !mRect.isValid() )
00713         return;
00714 
00715     painter->drawLine( QPointF( mRect.left(), mRect.center().y() ),
00716                        QPointF( mRect.right(), mRect.center().y() ) );
00717 }
00718 
00719 
00720 KDChart::VerticalLineLayoutItem::VerticalLineLayoutItem()
00721     : AbstractLayoutItem( Qt::AlignCenter )
00722 {
00723 }
00724 
00725 Qt::Orientations KDChart::VerticalLineLayoutItem::expandingDirections() const
00726 {
00727     return Qt::Vertical|Qt::Vertical; // Grow both vertically, and horizontally
00728 }
00729 
00730 QRect KDChart::VerticalLineLayoutItem::geometry() const
00731 {
00732     return mRect;
00733 }
00734 
00735 bool KDChart::VerticalLineLayoutItem::isEmpty() const
00736 {
00737     return false; // never empty, otherwise the layout item would not exist
00738 }
00739 
00740 QSize KDChart::VerticalLineLayoutItem::maximumSize() const
00741 {
00742     return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00743 }
00744 
00745 QSize KDChart::VerticalLineLayoutItem::minimumSize() const
00746 {
00747     return QSize( 0, 0 );
00748 }
00749 
00750 void KDChart::VerticalLineLayoutItem::setGeometry( const QRect& r )
00751 {
00752     mRect = r;
00753 }
00754 
00755 QSize KDChart::VerticalLineLayoutItem::sizeHint() const
00756 {
00757     return QSize( 3, -1 ); // see qframe.cpp
00758 }
00759 
00760 
00761 void KDChart::VerticalLineLayoutItem::paint( QPainter* painter )
00762 {
00763     if( !mRect.isValid() )
00764         return;
00765 
00766     painter->drawLine( QPointF( mRect.center().x(), mRect.top() ),
00767                        QPointF( mRect.center().x(), mRect.bottom() ) );
00768 }
00769 
00770 
00771 
00772 KDChart::MarkerLayoutItem::MarkerLayoutItem( KDChart::AbstractDiagram* diagram,
00773                                              const MarkerAttributes& marker,
00774                                              const QBrush& brush, const QPen& pen,
00775                                              Qt::Alignment alignment )
00776     : AbstractLayoutItem( alignment )
00777     , mDiagram( diagram )
00778     , mMarker( marker )
00779     , mBrush( brush )
00780     , mPen( pen )
00781 {
00782 }
00783 
00784 Qt::Orientations KDChart::MarkerLayoutItem::expandingDirections() const
00785 {
00786     return 0; // Grow neither vertically nor horizontally
00787 }
00788 
00789 QRect KDChart::MarkerLayoutItem::geometry() const
00790 {
00791     return mRect;
00792 }
00793 
00794 bool KDChart::MarkerLayoutItem::isEmpty() const
00795 {
00796     return false; // never empty, otherwise the layout item would not exist
00797 }
00798 
00799 QSize KDChart::MarkerLayoutItem::maximumSize() const
00800 {
00801     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00802 }
00803 
00804 QSize KDChart::MarkerLayoutItem::minimumSize() const
00805 {
00806     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00807 }
00808 
00809 void KDChart::MarkerLayoutItem::setGeometry( const QRect& r )
00810 {
00811     mRect = r;
00812 }
00813 
00814 QSize KDChart::MarkerLayoutItem::sizeHint() const
00815 {
00816     //qDebug() << "KDChart::MarkerLayoutItem::sizeHint() returns:"<<mMarker.markerSize().toSize();
00817     return mMarker.markerSize().toSize();
00818 }
00819 
00820 void KDChart::MarkerLayoutItem::paint( QPainter* painter )
00821 {
00822     paintIntoRect( painter, mRect, mDiagram, mMarker, mBrush, mPen );
00823 }
00824 
00825 void KDChart::MarkerLayoutItem::paintIntoRect(
00826         QPainter* painter,
00827         const QRect& rect,
00828         AbstractDiagram* diagram,
00829         const MarkerAttributes& marker,
00830         const QBrush& brush,
00831         const QPen& pen )
00832 {
00833     if( ! rect.isValid() )
00834         return;
00835 
00836     // The layout management may assign a larger rect than what we
00837     // wanted. We need to adjust the position.
00838     const QSize siz = marker.markerSize().toSize();
00839     QPointF pos = rect.topLeft();
00840     pos += QPointF( static_cast<qreal>(( rect.width()  - siz.width()) / 2.0 ),
00841                     static_cast<qreal>(( rect.height() - siz.height()) / 2.0 ) );
00842 
00843 #ifdef DEBUG_ITEMS_PAINT
00844     QPointF oldPos = pos;
00845 #endif
00846 
00847 // And finally, drawMarker() assumes the position to be the center
00848     // of the marker, adjust again.
00849     pos += QPointF( static_cast<qreal>( siz.width() ) / 2.0,
00850                     static_cast<qreal>( siz.height() )/ 2.0 );
00851 
00852     diagram->paintMarker( painter, marker, brush, pen, pos.toPoint(), siz );
00853 
00854 #ifdef DEBUG_ITEMS_PAINT
00855     const QPen oldPen( painter->pen() );
00856     painter->setPen( Qt::red );
00857     painter->drawRect( QRect(oldPos.toPoint(), siz) );
00858     painter->setPen( oldPen );
00859 #endif
00860 }
00861 
00862 
00863 KDChart::LineLayoutItem::LineLayoutItem( KDChart::AbstractDiagram* diagram,
00864                                          int length,
00865                                          const QPen& pen,
00866                                          Qt::Alignment alignment )
00867     : AbstractLayoutItem( alignment )
00868     , mDiagram( diagram )
00869     , mLength( length )
00870     , mPen( pen )
00871 {
00872     //have a mini pen width
00873     if ( pen.width() < 2 )
00874         mPen.setWidth( 2 );
00875 }
00876 
00877 Qt::Orientations KDChart::LineLayoutItem::expandingDirections() const
00878 {
00879     return 0; // Grow neither vertically nor horizontally
00880 }
00881 
00882 QRect KDChart::LineLayoutItem::geometry() const
00883 {
00884     return mRect;
00885 }
00886 
00887 bool KDChart::LineLayoutItem::isEmpty() const
00888 {
00889     return false; // never empty, otherwise the layout item would not exist
00890 }
00891 
00892 QSize KDChart::LineLayoutItem::maximumSize() const
00893 {
00894     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00895 }
00896 
00897 QSize KDChart::LineLayoutItem::minimumSize() const
00898 {
00899     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00900 }
00901 
00902 void KDChart::LineLayoutItem::setGeometry( const QRect& r )
00903 {
00904     mRect = r;
00905 }
00906 
00907 QSize KDChart::LineLayoutItem::sizeHint() const
00908 {
00909     return QSize( mLength, mPen.width()+2 );
00910 }
00911 
00912 void KDChart::LineLayoutItem::paint( QPainter* painter )
00913 {
00914     paintIntoRect( painter, mRect, mPen );
00915 }
00916 
00917 void KDChart::LineLayoutItem::paintIntoRect(
00918         QPainter* painter,
00919         const QRect& rect,
00920         const QPen& pen )
00921 {
00922     if( ! rect.isValid() )
00923         return;
00924 
00925     const QPen oldPen = painter->pen();
00926     painter->setPen( PrintingParameters::scalePen( pen ) );
00927     const qreal y = rect.center().y();
00928     painter->drawLine( QPointF( rect.left(), y ),
00929                        QPointF( rect.right(), y ) );
00930     painter->setPen( oldPen );
00931 }
00932 
00933 
00934 KDChart::LineWithMarkerLayoutItem::LineWithMarkerLayoutItem(
00935         KDChart::AbstractDiagram* diagram,
00936         int lineLength,
00937         const QPen& linePen,
00938         int markerOffs,
00939         const MarkerAttributes& marker,
00940         const QBrush& markerBrush,
00941         const QPen& markerPen,
00942         Qt::Alignment alignment )
00943     : AbstractLayoutItem( alignment )
00944     , mDiagram(     diagram )
00945     , mLineLength(  lineLength )
00946     , mLinePen(     linePen )
00947     , mMarkerOffs(  markerOffs )
00948     , mMarker(      marker )
00949     , mMarkerBrush( markerBrush )
00950     , mMarkerPen(   markerPen )
00951 {
00952 }
00953 
00954 Qt::Orientations KDChart::LineWithMarkerLayoutItem::expandingDirections() const
00955 {
00956     return 0; // Grow neither vertically nor horizontally
00957 }
00958 
00959 QRect KDChart::LineWithMarkerLayoutItem::geometry() const
00960 {
00961     return mRect;
00962 }
00963 
00964 bool KDChart::LineWithMarkerLayoutItem::isEmpty() const
00965 {
00966     return false; // never empty, otherwise the layout item would not exist
00967 }
00968 
00969 QSize KDChart::LineWithMarkerLayoutItem::maximumSize() const
00970 {
00971     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00972 }
00973 
00974 QSize KDChart::LineWithMarkerLayoutItem::minimumSize() const
00975 {
00976     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00977 }
00978 
00979 void KDChart::LineWithMarkerLayoutItem::setGeometry( const QRect& r )
00980 {
00981     mRect = r;
00982 }
00983 
00984 QSize KDChart::LineWithMarkerLayoutItem::sizeHint() const
00985 {
00986     const QSize sizeM = mMarker.markerSize().toSize();
00987     const QSize sizeL = QSize( mLineLength, mLinePen.width()+2 );
00988     return QSize( qMax(sizeM.width(),  sizeL.width()),
00989                   qMax(sizeM.height(), sizeL.height()) );
00990 }
00991 
00992 void KDChart::LineWithMarkerLayoutItem::paint( QPainter* painter )
00993 {
00994     // paint the line over the full width, into the vertical middle of the rect
00995     LineLayoutItem::paintIntoRect( painter, mRect, mLinePen );
00996 
00997     // paint the marker with the given offset from the left side of the line
00998     const QRect r(
00999             QPoint( mRect.x()+mMarkerOffs, mRect.y() ),
01000             QSize( mMarker.markerSize().toSize().width(), mRect.height() ) );
01001     MarkerLayoutItem::paintIntoRect(
01002             painter, r, mDiagram, mMarker, mMarkerBrush, mMarkerPen );
01003 }
01004 
01005 
01006 
01007 KDChart::AutoSpacerLayoutItem::AutoSpacerLayoutItem(
01008         bool layoutIsAtTopPosition, QHBoxLayout *rightLeftLayout,
01009         bool layoutIsAtLeftPosition, QVBoxLayout *topBottomLayout )
01010     : AbstractLayoutItem( Qt::AlignCenter )
01011     , mLayoutIsAtTopPosition(  layoutIsAtTopPosition )
01012     , mRightLeftLayout( rightLeftLayout )
01013     , mLayoutIsAtLeftPosition( layoutIsAtLeftPosition )
01014     , mTopBottomLayout( topBottomLayout )
01015 {
01016 }
01017 
01018 Qt::Orientations KDChart::AutoSpacerLayoutItem::expandingDirections() const
01019 {
01020     return 0; // Grow neither vertically nor horizontally
01021 }
01022 
01023 QRect KDChart::AutoSpacerLayoutItem::geometry() const
01024 {
01025     return mRect;
01026 }
01027 
01028 bool KDChart::AutoSpacerLayoutItem::isEmpty() const
01029 {
01030     return true; // never empty, otherwise the layout item would not exist
01031 }
01032 
01033 QSize KDChart::AutoSpacerLayoutItem::maximumSize() const
01034 {
01035     return sizeHint();
01036 }
01037 
01038 QSize KDChart::AutoSpacerLayoutItem::minimumSize() const
01039 {
01040     return sizeHint();
01041 }
01042 
01043 void KDChart::AutoSpacerLayoutItem::setGeometry( const QRect& r )
01044 {
01045     mRect = r;
01046 }
01047 
01048 
01049 static void updateCommonBrush( QBrush& commonBrush, bool& bStart, const KDChart::AbstractArea& area )
01050 {
01051     const KDChart::BackgroundAttributes ba( area.backgroundAttributes() );
01052     const bool hasSimpleBrush = (
01053             ! area.frameAttributes().isVisible() &&
01054             ba.isVisible() &&
01055             ba.pixmapMode() == KDChart::BackgroundAttributes::BackgroundPixmapModeNone &&
01056             ba.brush().gradient() == 0 );
01057     if( bStart ){
01058         bStart = false;
01059         commonBrush = hasSimpleBrush ? ba.brush() : QBrush();
01060     }else{
01061         if( ! hasSimpleBrush || ba.brush() != commonBrush )
01062         {
01063             commonBrush = QBrush();
01064         }
01065     }
01066 }
01067 
01068 QSize KDChart::AutoSpacerLayoutItem::sizeHint() const
01069 {
01070     QBrush commonBrush;
01071     bool bStart=true;
01072     // calculate the maximal overlap of the top/bottom axes:
01073     int topBottomOverlap = 0;
01074     if( mTopBottomLayout ){
01075         for (int i = 0; i < mTopBottomLayout->count(); ++i){
01076             AbstractArea* area = dynamic_cast<AbstractArea*>(mTopBottomLayout->itemAt(i));
01077             if( area ){
01078                 //qDebug() << "AutoSpacerLayoutItem testing" << area;
01079                 topBottomOverlap =
01080                     mLayoutIsAtLeftPosition
01081                     ? qMax( topBottomOverlap, area->rightOverlap() )
01082                     : qMax( topBottomOverlap, area->leftOverlap() );
01083                 updateCommonBrush( commonBrush, bStart, *area );
01084             }
01085         }
01086     }
01087     // calculate the maximal overlap of the left/right axes:
01088     int leftRightOverlap = 0;
01089     if( mRightLeftLayout ){
01090         for (int i = 0; i < mRightLeftLayout->count(); ++i){
01091             AbstractArea* area = dynamic_cast<AbstractArea*>(mRightLeftLayout->itemAt(i));
01092             if( area ){
01093                 //qDebug() << "AutoSpacerLayoutItem testing" << area;
01094                 leftRightOverlap =
01095                         mLayoutIsAtTopPosition
01096                         ? qMax( leftRightOverlap, area->bottomOverlap() )
01097                         : qMax( leftRightOverlap, area->topOverlap() );
01098                 updateCommonBrush( commonBrush, bStart, *area );
01099             }
01100         }
01101     }
01102     if( topBottomOverlap > 0 && leftRightOverlap > 0 )
01103         mCommonBrush = commonBrush;
01104     else
01105         mCommonBrush = QBrush();
01106     mCachedSize = QSize( topBottomOverlap, leftRightOverlap );
01107     //qDebug() << mCachedSize;
01108     return mCachedSize;
01109 }
01110 
01111 
01112 void KDChart::AutoSpacerLayoutItem::paint( QPainter* painter )
01113 {
01114     if( mParentLayout && mRect.isValid() && mCachedSize.isValid() &&
01115         mCommonBrush.style() != Qt::NoBrush )
01116     {
01117         QPoint p1( mRect.topLeft() );
01118         QPoint p2( mRect.bottomRight() );
01119         if( mLayoutIsAtLeftPosition )
01120             p1.rx() += mCachedSize.width() - mParentLayout->spacing();
01121         else
01122             p2.rx() -= mCachedSize.width() - mParentLayout->spacing();
01123         if( mLayoutIsAtTopPosition ){
01124             p1.ry() += mCachedSize.height() - mParentLayout->spacing() - 1;
01125             p2.ry() -= 1;
01126         }else
01127             p2.ry() -= mCachedSize.height() - mParentLayout->spacing() - 1;
01128         //qDebug() << mLayoutIsAtTopPosition << mLayoutIsAtLeftPosition;
01129         //qDebug() << mRect;
01130         //qDebug() << mParentLayout->margin();
01131         //qDebug() << QRect( p1, p2 );
01132         const QPoint oldBrushOrigin( painter->brushOrigin() );
01133         const QBrush oldBrush( painter->brush() );
01134         const QPen   oldPen(   painter->pen() );
01135         const QPointF newTopLeft( painter->deviceMatrix().map( p1 ) );
01136         painter->setBrushOrigin( newTopLeft );
01137         painter->setBrush( mCommonBrush );
01138         painter->setPen( Qt::NoPen );
01139         painter->drawRect( QRect( p1, p2 ) );
01140         painter->setBrushOrigin( oldBrushOrigin );
01141         painter->setBrush( oldBrush );
01142         painter->setPen( oldPen );
01143     }
01144     // debug code:
01145 #if 0
01146     //qDebug() << "KDChart::AutoSpacerLayoutItem::paint()";
01147     if( !mRect.isValid() )
01148         return;
01149 
01150     painter->drawRect( mRect );
01151     painter->drawLine( QPointF( mRect.x(), mRect.top() ),
01152                        QPointF( mRect.right(), mRect.bottom() ) );
01153     painter->drawLine( QPointF( mRect.right(), mRect.top() ),
01154                        QPointF( mRect.x(), mRect.bottom() ) );
01155 #endif
01156 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/