KD Chart 2  [rev.2.5]
KDChartLayoutItems.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 ** Copyright (C) 2001-2012 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 
00049 //#define DEBUG_ITEMS_PAINT
00050 
00059 void KDChart::AbstractLayoutItem::setParentWidget( QWidget* widget )
00060 {
00061     mParent = widget;
00062 }
00063 
00064 void KDChart::AbstractLayoutItem::paintAll( QPainter& painter )
00065 {
00066     paint( &painter );
00067 }
00068 
00072 void KDChart::AbstractLayoutItem::paintCtx( PaintContext* context )
00073 {
00074     if( context )
00075         paint( context->painter() );
00076 }
00077 
00081 void KDChart::AbstractLayoutItem::sizeHintChanged() const
00082 {
00083     // This is exactly like what QWidget::updateGeometry does.
00084 //  qDebug("KDChart::AbstractLayoutItem::sizeHintChanged() called");
00085     if( mParent ) {
00086         if ( mParent->layout() )
00087             mParent->layout()->invalidate();
00088         else
00089             QApplication::postEvent( mParent, new QEvent( QEvent::LayoutRequest ) );
00090     }
00091 }
00092 
00093 KDChart::TextBubbleLayoutItem::TextBubbleLayoutItem( const QString& text,
00094                                          const KDChart::TextAttributes& attributes,
00095                                          const QObject* area,
00096                                          KDChartEnums::MeasureOrientation orientation,
00097                                          Qt::Alignment alignment )
00098     : AbstractLayoutItem( alignment ),
00099       m_text( new TextLayoutItem( text, attributes, area, orientation, alignment ) )
00100 {
00101 }
00102 
00103 KDChart::TextBubbleLayoutItem::TextBubbleLayoutItem()
00104     : AbstractLayoutItem( Qt::AlignLeft ),
00105       m_text( new TextLayoutItem() )
00106 {
00107 }
00108 
00109 KDChart::TextBubbleLayoutItem::~TextBubbleLayoutItem()
00110 {
00111     delete m_text;
00112 }
00113 
00114 void KDChart::TextBubbleLayoutItem::setAutoReferenceArea( const QObject* area )
00115 {
00116     m_text->setAutoReferenceArea( area );
00117 }
00118 
00119 const QObject* KDChart::TextBubbleLayoutItem::autoReferenceArea() const
00120 {
00121     return m_text->autoReferenceArea();
00122 }
00123 
00124 void KDChart::TextBubbleLayoutItem::setText( const QString& text )
00125 {
00126     m_text->setText( text );
00127 }
00128 
00129 QString KDChart::TextBubbleLayoutItem::text() const
00130 {
00131     return m_text->text();
00132 }
00133 
00134 void KDChart::TextBubbleLayoutItem::setTextAttributes( const TextAttributes& a )
00135 {
00136     m_text->setTextAttributes( a );
00137 }
00138 
00139 KDChart::TextAttributes KDChart::TextBubbleLayoutItem::textAttributes() const
00140 {
00141     return m_text->textAttributes();
00142 }
00143 
00144 bool KDChart::TextBubbleLayoutItem::isEmpty() const
00145 {
00146     return m_text->isEmpty();
00147 }
00148 
00149 Qt::Orientations KDChart::TextBubbleLayoutItem::expandingDirections() const
00150 {
00151     return m_text->expandingDirections();
00152 }
00153 
00154 QSize KDChart::TextBubbleLayoutItem::maximumSize() const
00155 {
00156     const int border = borderWidth();
00157     return m_text->maximumSize() + QSize( 2 * border, 2 * border );
00158 }
00159 
00160 QSize KDChart::TextBubbleLayoutItem::minimumSize() const
00161 {
00162     const int border = borderWidth();
00163     return m_text->minimumSize() + QSize( 2 * border, 2 * border );
00164 }
00165 
00166 QSize KDChart::TextBubbleLayoutItem::sizeHint() const
00167 {
00168     const int border = borderWidth();
00169     return m_text->sizeHint() + QSize( 2 * border, 2 * border );
00170 }
00171 
00172 void KDChart::TextBubbleLayoutItem::setGeometry( const QRect& r )
00173 {
00174     const int border = borderWidth();
00175     m_text->setGeometry( r.adjusted( border, border, -border, -border ) );
00176 }
00177 
00178 QRect KDChart::TextBubbleLayoutItem::geometry() const
00179 {
00180     const int border = borderWidth();
00181     return m_text->geometry().adjusted( -border, -border, border, border );
00182 }
00183 
00184 void KDChart::TextBubbleLayoutItem::paint( QPainter* painter )
00185 {
00186     const QPen oldPen = painter->pen();
00187     const QBrush oldBrush = painter->brush();
00188     painter->setPen( Qt::black );
00189     painter->setBrush( QColor( 255, 255, 220 ) );
00190     painter->drawRoundRect( geometry(), 10 );
00191     painter->setPen( oldPen );
00192     painter->setBrush( oldBrush );
00193     m_text->paint( painter );
00194 }
00195 
00196 int KDChart::TextBubbleLayoutItem::borderWidth() const
00197 {
00198     return 1;
00199 }
00200 
00201 KDChart::TextLayoutItem::TextLayoutItem( const QString& text,
00202                                          const KDChart::TextAttributes& attributes,
00203                                          const QObject* area,
00204                                          KDChartEnums::MeasureOrientation orientation,
00205                                          Qt::Alignment alignment )
00206     : AbstractLayoutItem( alignment )
00207     , mText( text )
00208     , mTextAlignment( alignment )
00209     , mAttributes( attributes )
00210     , mAutoReferenceArea( area )
00211     , mAutoReferenceOrientation( orientation )
00212     , cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
00213     , cachedFontSize( 0.0 )
00214     , cachedFont( mAttributes.font() )
00215 {
00216 }
00217 
00218 KDChart::TextLayoutItem::TextLayoutItem()
00219     : AbstractLayoutItem( Qt::AlignLeft )
00220     , mText()
00221     , mTextAlignment( Qt::AlignLeft )
00222     , mAttributes()
00223     , mAutoReferenceArea( 0 )
00224     , mAutoReferenceOrientation( KDChartEnums::MeasureOrientationHorizontal )
00225     , cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
00226     , cachedFontSize( 0.0 )
00227     , cachedFont( mAttributes.font() )
00228 {
00229 
00230 }
00231 
00232 void KDChart::TextLayoutItem::setAutoReferenceArea( const QObject* area )
00233 {
00234     mAutoReferenceArea = area;
00235     cachedSizeHint = QSize();
00236     sizeHint();
00237 }
00238 
00239 const QObject* KDChart::TextLayoutItem::autoReferenceArea() const
00240 {
00241     return mAutoReferenceArea;
00242 }
00243 
00244 void KDChart::TextLayoutItem::setText(const QString & text)
00245 {
00246     mText = text;
00247     cachedSizeHint = QSize();
00248     sizeHint();
00249     if( mParent )
00250         mParent->update();
00251 }
00252 
00253 QString KDChart::TextLayoutItem::text() const
00254 {
00255     return mText;
00256 }
00257 
00258 void KDChart::TextLayoutItem::setTextAlignment( Qt::Alignment alignment)
00259 {
00260     if( mTextAlignment == alignment )
00261         return;
00262     mTextAlignment = alignment;
00263     if( mParent )
00264         mParent->update();
00265 }
00266 
00267 Qt::Alignment KDChart::TextLayoutItem::textAlignment() const
00268 {
00269     return mTextAlignment;
00270 }
00271 
00277 void KDChart::TextLayoutItem::setTextAttributes( const TextAttributes &a )
00278 {
00279     mAttributes = a;
00280     cachedFont = a.font();
00281     cachedSizeHint = QSize(); // invalidate size hint
00282     sizeHint();
00283     if( mParent )
00284         mParent->update();
00285 }
00286 
00292 KDChart::TextAttributes KDChart::TextLayoutItem::textAttributes() const
00293 {
00294     return mAttributes;
00295 }
00296 
00297 
00298 Qt::Orientations KDChart::TextLayoutItem::expandingDirections() const
00299 {
00300     return 0; // Grow neither vertically nor horizontally
00301 }
00302 
00303 QRect KDChart::TextLayoutItem::geometry() const
00304 {
00305     return mRect;
00306 }
00307 
00308 bool KDChart::TextLayoutItem::isEmpty() const
00309 {
00310     return false; // never empty, otherwise the layout item would not exist
00311 }
00312 
00313 QSize KDChart::TextLayoutItem::maximumSize() const
00314 {
00315     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00316 }
00317 
00318 QSize KDChart::TextLayoutItem::minimumSize() const
00319 {
00320     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00321 }
00322 
00323 void KDChart::TextLayoutItem::setGeometry( const QRect& r )
00324 {
00325     mRect = r;
00326 }
00327 
00328 // returns the bounding box of rect rotated around its center
00329 QRectF rotatedRect( const QRectF& rect, qreal rotation )
00330 {
00331     QTransform t;
00332     QPointF center = rect.center();
00333     t.translate( center.x(), center.y() );
00334     t.rotate( rotation );
00335     t.translate( -center.x(), -center.y() );
00336     return t.mapRect( rect );
00337 }
00338 
00339 qreal KDChart::TextLayoutItem::fitFontSizeToGeometry() const
00340 {
00341     QFont f = realFont();
00342     const qreal origResult = f.pointSizeF();
00343     qreal result = origResult;
00344     const qreal minSize = mAttributes.minimalFontSize().value();
00345     const QSize mySize = geometry().size();
00346     if ( mySize.isNull() ) {
00347         return result;
00348     }
00349 
00350     QFontMetrics fm( f );
00351     while ( true ) {
00352         const QSizeF textSize = rotatedRect( fm.boundingRect( mText ), mAttributes.rotation() ).normalized().size();
00353 
00354         if ( textSize.height() <= mySize.height() && textSize.width() <= mySize.width() ){
00355             return result;
00356         }
00357 
00358         result -= 0.5;
00359         if ( minSize > 0 && result < minSize ) {
00360             return result + 0.5;
00361         } else if ( result <= 0.0 ) {
00362             return origResult;
00363         }
00364         f.setPointSizeF( result );
00365         fm = QFontMetrics( f );
00366     }
00367 }
00368 
00369 qreal KDChart::TextLayoutItem::realFontSize() const
00370 {
00371     return mAttributes.calculatedFontSize( mAutoReferenceArea, mAutoReferenceOrientation );
00372 }
00373 
00374 bool KDChart::TextLayoutItem::maybeUpdateRealFont() const
00375 {
00376     const qreal fntSiz = realFontSize();
00377     const bool doUpdate = !cachedSizeHint.isValid() || cachedFontSize != fntSiz;
00378 
00379     if ( doUpdate && fntSiz > 0.0 ) {
00380         cachedFontSize = fntSiz;
00381         cachedFont.setPointSizeF( fntSiz );
00382     }
00383     return doUpdate; // "didUpdate" by now
00384 }
00385 
00386 QFont KDChart::TextLayoutItem::realFont() const
00387 {
00388     maybeUpdateRealFont();
00389     return cachedFont;
00390 }
00391 
00392 QPolygon KDChart::TextLayoutItem::boundingPolygon() const
00393 {
00394     // should probably call sizeHint() here, but that one is expensive (see TODO there)
00395     return mCachedBoundingPolygon;
00396 }
00397 
00398 bool KDChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPointF& myPos, const QPointF& otherPos ) const
00399 {
00400     return intersects( other, myPos.toPoint(), otherPos.toPoint() );
00401 }
00402 
00403 bool KDChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPoint& myPos, const QPoint& otherPos ) const
00404 {
00405     if ( mAttributes.rotation() != other.mAttributes.rotation() )
00406     {
00407         // that's the code for the common case: the rotation angles don't need to match here
00408         QPolygon myPolygon = boundingPolygon().translated( myPos );
00409         QPolygon otherPolygon = other.boundingPolygon().translated( otherPos );
00410 
00411         // create regions out of it
00412         QRegion myRegion( myPolygon );
00413         QRegion otherRegion( otherPolygon );
00414 
00415         // now the question - do they intersect or not?
00416         return ! myRegion.intersect( otherRegion ).isEmpty();
00417 
00418     } else {
00419         // the rotation angles match so we can use a faster algorithm
00420         const qreal angle = DEGTORAD( mAttributes.rotation() );
00421         // both sizes
00422         const QSizeF mySize( unrotatedSizeHint() );
00423         const QSizeF otherSize( other.unrotatedSizeHint() );
00424 
00425         // that's myP1 relative to myPos
00426         QPointF myP1( mySize.height() * sin( angle ), 0.0 );
00427         // that's otherP1 to myPos
00428         QPointF otherP1 = QPointF( otherSize.height() * sin( angle ), 0.0 ) + otherPos - myPos;
00429 
00430         // now rotate both points the negative angle around myPos
00431         myP1 = QPointF( myP1.x() * cos( -angle ), myP1.x() * sin( -angle ) );
00432         qreal r = sqrt( otherP1.x() * otherP1.x() + otherP1.y() * otherP1.y() );
00433         if ( myP1.x() == otherP1.x() ) { // vertical
00434             otherP1 = QPointF( r * sin( -angle ), r * cos( -angle ) );
00435         } else if ( myP1.y() == otherP1.y() ) { // horizontal
00436             otherP1 = QPointF( r * cos( -angle ), r * sin( -angle ) );
00437         }
00438 
00439         return QRectF( myP1, mySize ).intersects( QRectF( otherP1, otherSize ) );
00440     }
00441 }
00442 
00443 QSize KDChart::TextLayoutItem::sizeHint() const
00444 {
00445     // ### we only really need to recalculate the size hint when mAttributes.rotation has *changed*
00446     if ( maybeUpdateRealFont() || mAttributes.rotation() || !cachedSizeHint.isValid() ) {
00447         const QSize newSizeHint( calcSizeHint( cachedFont ) );
00448         Q_ASSERT( newSizeHint.isValid() );
00449         if ( newSizeHint != cachedSizeHint ) {
00450             cachedSizeHint = newSizeHint;
00451             sizeHintChanged();
00452         }
00453     }
00454     return cachedSizeHint;
00455 }
00456 
00457 QSize KDChart::TextLayoutItem::sizeHintUnrotated() const
00458 {
00459     maybeUpdateRealFont(); // make sure the cached font is up to date
00460     return unrotatedSizeHint( cachedFont );
00461 }
00462 
00463 
00464 // PENDING(kalle) Support auto shrink
00465 
00466 
00467 QSize KDChart::TextLayoutItem::unrotatedTextSize( QFont fnt ) const
00468 {
00469     if ( fnt == QFont() ) {
00470         fnt = realFont(); // this is the cached font in most cases
00471     }
00472 
00473     const QFontMetricsF fm( fnt, GlobalMeasureScaling::paintDevice() );
00474     QRect veryLarge( 0, 0, 100000, 100000 );
00475     // this overload of boundingRect() interprets \n as line breaks, not as regular characters.
00476     return fm.boundingRect( veryLarge, Qt::AlignLeft | Qt::AlignTop, mText ).size().toSize();
00477 }
00478 
00479 int KDChart::TextLayoutItem::marginWidth() const
00480 {
00481     return marginWidth( unrotatedTextSize() );
00482 }
00483 
00484 int KDChart::TextLayoutItem::marginWidth( const QSize& textSize ) const
00485 {
00486     return qMin ( QApplication::style()->pixelMetric( QStyle::PM_ButtonMargin, 0, 0 ),
00487                   // decrease frame size if the text is small
00488                   textSize.height() * 2 / 3 );
00489 }
00490 
00491 QSize KDChart::TextLayoutItem::unrotatedSizeHint( const QFont& fnt ) const
00492 {
00493     QSize ret = unrotatedTextSize( fnt );
00494     const int margin = marginWidth( ret );
00495     ret += QSize( margin, margin );
00496     return ret;
00497 }
00498 
00499 QSize KDChart::TextLayoutItem::calcSizeHint( const QFont& font ) const
00500 {
00501     const QSize size = unrotatedSizeHint( font );
00502     QPoint topLeft( -size.width() * 0.5, -size.height() * 0.5 );
00503     if ( !mAttributes.rotation() ) {
00504         mCachedBoundingPolygon.resize( 4 );
00505         // using the same winding order as returned by QPolygon QTransform::mapToPolygon(const QRect&),
00506         // which is: 0-1: top edge, 1-2: right edge, 2-3: bottom edge, 3-0: left edge (of input rect)
00507         mCachedBoundingPolygon[ 0 ] = topLeft;
00508         mCachedBoundingPolygon[ 1 ] = topLeft + QPoint( size.width(), 0 ); // top right
00509         mCachedBoundingPolygon[ 2 ] = topLeft + QPoint( size.width(), size.height() ); // bottom right
00510         mCachedBoundingPolygon[ 3 ] = topLeft + QPoint( 0, size.height() ); // bottom left
00511         return size;
00512     }
00513 
00514     const QRect rect( topLeft, size );
00515     QTransform t;
00516     t.rotate( mAttributes.rotation() );
00517     mCachedBoundingPolygon = t.mapToPolygon( rect );
00518 
00519     return mCachedBoundingPolygon.boundingRect().size();
00520 }
00521 
00522 void KDChart::TextLayoutItem::paint( QPainter* painter )
00523 {
00524     if ( !mRect.isValid() ) {
00525         return;
00526     }
00527     const PainterSaver painterSaver( painter );
00528     QFont f = realFont();
00529     if ( mAttributes.autoShrink() ) {
00530         f.setPointSizeF( fitFontSizeToGeometry() );
00531     }
00532     painter->setFont( f );
00533 
00534     QSize innerSize = unrotatedTextSize();
00535     QRectF rect = QRectF( QPointF( 0, 0 ), innerSize );
00536     rect.translate( -rect.center() );
00537     painter->translate( mRect.center() );
00538     painter->rotate( mAttributes.rotation() );
00539 #ifdef DEBUG_ITEMS_PAINT
00540     painter->setPen( Qt::red );
00541     painter->drawRect( rect );
00542 #endif
00543 
00544     painter->setPen( PrintingParameters::scalePen( mAttributes.pen() ) );
00545     QTextDocument* document = mAttributes.textDocument();
00546     if ( document ) {
00547         document->setPageSize( rect.size() );
00548         document->setHtml( mText );
00549         QAbstractTextDocumentLayout::PaintContext paintcontext;
00550         // ### this doesn't work for rotated painting because clip does not translate the painting
00551         // TODO translate the painting either using a QTransform or one of QPainter's transform stages
00552         paintcontext.clip = rect;
00553         document->documentLayout()->draw( painter, paintcontext );
00554     } else {
00555         painter->drawText( rect, mTextAlignment, mText );
00556     }
00557 }
00558 
00559 KDChart::HorizontalLineLayoutItem::HorizontalLineLayoutItem()
00560     : AbstractLayoutItem( Qt::AlignCenter )
00561 {
00562 }
00563 
00564 Qt::Orientations KDChart::HorizontalLineLayoutItem::expandingDirections() const
00565 {
00566     return Qt::Vertical|Qt::Horizontal; // Grow both vertically, and horizontally
00567 }
00568 
00569 QRect KDChart::HorizontalLineLayoutItem::geometry() const
00570 {
00571     return mRect;
00572 }
00573 
00574 bool KDChart::HorizontalLineLayoutItem::isEmpty() const
00575 {
00576     return false; // never empty, otherwise the layout item would not exist
00577 }
00578 
00579 QSize KDChart::HorizontalLineLayoutItem::maximumSize() const
00580 {
00581     return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00582 }
00583 
00584 QSize KDChart::HorizontalLineLayoutItem::minimumSize() const
00585 {
00586     return QSize( 0, 0 );
00587 }
00588 
00589 void KDChart::HorizontalLineLayoutItem::setGeometry( const QRect& r )
00590 {
00591     mRect = r;
00592 }
00593 
00594 QSize KDChart::HorizontalLineLayoutItem::sizeHint() const
00595 {
00596     return QSize( -1, 3 ); // see qframe.cpp
00597 }
00598 
00599 
00600 void KDChart::HorizontalLineLayoutItem::paint( QPainter* painter )
00601 {
00602     if( !mRect.isValid() )
00603         return;
00604 
00605     painter->drawLine( QPointF( mRect.left(), mRect.center().y() ),
00606                        QPointF( mRect.right(), mRect.center().y() ) );
00607 }
00608 
00609 
00610 KDChart::VerticalLineLayoutItem::VerticalLineLayoutItem()
00611     : AbstractLayoutItem( Qt::AlignCenter )
00612 {
00613 }
00614 
00615 Qt::Orientations KDChart::VerticalLineLayoutItem::expandingDirections() const
00616 {
00617     return Qt::Vertical|Qt::Vertical; // Grow both vertically, and horizontally
00618 }
00619 
00620 QRect KDChart::VerticalLineLayoutItem::geometry() const
00621 {
00622     return mRect;
00623 }
00624 
00625 bool KDChart::VerticalLineLayoutItem::isEmpty() const
00626 {
00627     return false; // never empty, otherwise the layout item would not exist
00628 }
00629 
00630 QSize KDChart::VerticalLineLayoutItem::maximumSize() const
00631 {
00632     return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00633 }
00634 
00635 QSize KDChart::VerticalLineLayoutItem::minimumSize() const
00636 {
00637     return QSize( 0, 0 );
00638 }
00639 
00640 void KDChart::VerticalLineLayoutItem::setGeometry( const QRect& r )
00641 {
00642     mRect = r;
00643 }
00644 
00645 QSize KDChart::VerticalLineLayoutItem::sizeHint() const
00646 {
00647     return QSize( 3, -1 ); // see qframe.cpp
00648 }
00649 
00650 
00651 void KDChart::VerticalLineLayoutItem::paint( QPainter* painter )
00652 {
00653     if( !mRect.isValid() )
00654         return;
00655 
00656     painter->drawLine( QPointF( mRect.center().x(), mRect.top() ),
00657                        QPointF( mRect.center().x(), mRect.bottom() ) );
00658 }
00659 
00660 
00661 
00662 KDChart::MarkerLayoutItem::MarkerLayoutItem( KDChart::AbstractDiagram* diagram,
00663                                              const MarkerAttributes& marker,
00664                                              const QBrush& brush, const QPen& pen,
00665                                              Qt::Alignment alignment )
00666     : AbstractLayoutItem( alignment )
00667     , mDiagram( diagram )
00668     , mMarker( marker )
00669     , mBrush( brush )
00670     , mPen( pen )
00671 {
00672 }
00673 
00674 Qt::Orientations KDChart::MarkerLayoutItem::expandingDirections() const
00675 {
00676     return 0; // Grow neither vertically nor horizontally
00677 }
00678 
00679 QRect KDChart::MarkerLayoutItem::geometry() const
00680 {
00681     return mRect;
00682 }
00683 
00684 bool KDChart::MarkerLayoutItem::isEmpty() const
00685 {
00686     return false; // never empty, otherwise the layout item would not exist
00687 }
00688 
00689 QSize KDChart::MarkerLayoutItem::maximumSize() const
00690 {
00691     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00692 }
00693 
00694 QSize KDChart::MarkerLayoutItem::minimumSize() const
00695 {
00696     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00697 }
00698 
00699 void KDChart::MarkerLayoutItem::setGeometry( const QRect& r )
00700 {
00701     mRect = r;
00702 }
00703 
00704 QSize KDChart::MarkerLayoutItem::sizeHint() const
00705 {
00706     //qDebug() << "KDChart::MarkerLayoutItem::sizeHint() returns:"<<mMarker.markerSize().toSize();
00707     return mMarker.markerSize().toSize();
00708 }
00709 
00710 void KDChart::MarkerLayoutItem::paint( QPainter* painter )
00711 {
00712     paintIntoRect( painter, mRect, mDiagram, mMarker, mBrush, mPen );
00713 }
00714 
00715 void KDChart::MarkerLayoutItem::paintIntoRect(
00716         QPainter* painter,
00717         const QRect& rect,
00718         AbstractDiagram* diagram,
00719         const MarkerAttributes& marker,
00720         const QBrush& brush,
00721         const QPen& pen )
00722 {
00723     if( ! rect.isValid() )
00724         return;
00725 
00726     // The layout management may assign a larger rect than what we
00727     // wanted. We need to adjust the position.
00728     const QSize siz = marker.markerSize().toSize();
00729     QPointF pos = rect.topLeft();
00730     pos += QPointF( static_cast<qreal>(( rect.width()  - siz.width()) / 2.0 ),
00731                     static_cast<qreal>(( rect.height() - siz.height()) / 2.0 ) );
00732 
00733 #ifdef DEBUG_ITEMS_PAINT
00734     QPointF oldPos = pos;
00735 #endif
00736 
00737 // And finally, drawMarker() assumes the position to be the center
00738     // of the marker, adjust again.
00739     pos += QPointF( static_cast<qreal>( siz.width() ) / 2.0,
00740                     static_cast<qreal>( siz.height() )/ 2.0 );
00741 
00742     diagram->paintMarker( painter, marker, brush, pen, pos.toPoint(), siz );
00743 
00744 #ifdef DEBUG_ITEMS_PAINT
00745     const QPen oldPen( painter->pen() );
00746     painter->setPen( Qt::red );
00747     painter->drawRect( QRect(oldPos.toPoint(), siz) );
00748     painter->setPen( oldPen );
00749 #endif
00750 }
00751 
00752 
00753 KDChart::LineLayoutItem::LineLayoutItem( KDChart::AbstractDiagram* diagram,
00754                                          int length,
00755                                          const QPen& pen,
00756                                          Qt::Alignment legendLineSymbolAlignment,
00757                                          Qt::Alignment alignment )
00758     : AbstractLayoutItem( alignment )
00759     , mDiagram( diagram )
00760     , mLength( length )
00761     , mPen( pen )
00762     , mLegendLineSymbolAlignment(legendLineSymbolAlignment)
00763 {
00764     //have a mini pen width
00765     if ( pen.width() < 2 )
00766         mPen.setWidth( 2 );
00767 }
00768 
00769 Qt::Orientations KDChart::LineLayoutItem::expandingDirections() const
00770 {
00771     return 0; // Grow neither vertically nor horizontally
00772 }
00773 
00774 QRect KDChart::LineLayoutItem::geometry() const
00775 {
00776     return mRect;
00777 }
00778 
00779 bool KDChart::LineLayoutItem::isEmpty() const
00780 {
00781     return false; // never empty, otherwise the layout item would not exist
00782 }
00783 
00784 QSize KDChart::LineLayoutItem::maximumSize() const
00785 {
00786     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00787 }
00788 
00789 QSize KDChart::LineLayoutItem::minimumSize() const
00790 {
00791     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00792 }
00793 
00794 void KDChart::LineLayoutItem::setGeometry( const QRect& r )
00795 {
00796     mRect = r;
00797 }
00798 
00799 QSize KDChart::LineLayoutItem::sizeHint() const
00800 {
00801     return QSize( mLength, mPen.width()+2 );
00802 }
00803 
00804 
00805 void KDChart::LineLayoutItem::setLegendLineSymbolAlignment(Qt::Alignment legendLineSymbolAlignment)
00806 {
00807     if(mLegendLineSymbolAlignment == legendLineSymbolAlignment)
00808         return;
00809 
00810     mLegendLineSymbolAlignment = legendLineSymbolAlignment;
00811 }
00812 
00813 Qt::Alignment KDChart::LineLayoutItem::legendLineSymbolAlignment() const
00814 {
00815     return mLegendLineSymbolAlignment;
00816 }
00817 
00818 void KDChart::LineLayoutItem::paint( QPainter* painter )
00819 {
00820     paintIntoRect( painter, mRect, mPen, mLegendLineSymbolAlignment );
00821 }
00822 
00823 void KDChart::LineLayoutItem::paintIntoRect(
00824         QPainter* painter,
00825         const QRect& rect,
00826         const QPen& pen,
00827         Qt::Alignment lineAlignment)
00828 {
00829     if( ! rect.isValid() )
00830         return;
00831 
00832     const QPen oldPen = painter->pen();
00833     painter->setPen( PrintingParameters::scalePen( pen ) );
00834     qreal y = 0;
00835     if(lineAlignment == Qt::AlignTop)
00836         y = rect.top();
00837     else if(lineAlignment == Qt::AlignBottom)
00838         y = rect.bottom();
00839     else
00840         y = rect.center().y();
00841 
00842     painter->drawLine( QPointF( rect.left(), y ),
00843                        QPointF( rect.right(), y ) );
00844     painter->setPen( oldPen );
00845 }
00846 
00847 
00848 KDChart::LineWithMarkerLayoutItem::LineWithMarkerLayoutItem(
00849         KDChart::AbstractDiagram* diagram,
00850         int lineLength,
00851         const QPen& linePen,
00852         int markerOffs,
00853         const MarkerAttributes& marker,
00854         const QBrush& markerBrush,
00855         const QPen& markerPen,
00856         Qt::Alignment alignment )
00857     : AbstractLayoutItem( alignment )
00858     , mDiagram( diagram )
00859     , mLineLength( lineLength )
00860     , mLinePen( linePen )
00861     , mMarkerOffs( markerOffs )
00862     , mMarker( marker )
00863     , mMarkerBrush( markerBrush )
00864     , mMarkerPen( markerPen )
00865 {
00866 }
00867 
00868 Qt::Orientations KDChart::LineWithMarkerLayoutItem::expandingDirections() const
00869 {
00870     return 0; // Grow neither vertically nor horizontally
00871 }
00872 
00873 QRect KDChart::LineWithMarkerLayoutItem::geometry() const
00874 {
00875     return mRect;
00876 }
00877 
00878 bool KDChart::LineWithMarkerLayoutItem::isEmpty() const
00879 {
00880     return false; // never empty, otherwise the layout item would not exist
00881 }
00882 
00883 QSize KDChart::LineWithMarkerLayoutItem::maximumSize() const
00884 {
00885     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00886 }
00887 
00888 QSize KDChart::LineWithMarkerLayoutItem::minimumSize() const
00889 {
00890     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00891 }
00892 
00893 void KDChart::LineWithMarkerLayoutItem::setGeometry( const QRect& r )
00894 {
00895     mRect = r;
00896 }
00897 
00898 QSize KDChart::LineWithMarkerLayoutItem::sizeHint() const
00899 {
00900     const QSize sizeM = mMarker.markerSize().toSize();
00901     const QSize sizeL = QSize( mLineLength, mLinePen.width()+2 );
00902     return QSize( qMax(sizeM.width(),  sizeL.width()),
00903                   qMax(sizeM.height(), sizeL.height()) );
00904 }
00905 
00906 void KDChart::LineWithMarkerLayoutItem::paint( QPainter* painter )
00907 {
00908     // paint the line over the full width, into the vertical middle of the rect
00909     LineLayoutItem::paintIntoRect( painter, mRect, mLinePen, Qt::AlignCenter );
00910 
00911     // paint the marker with the given offset from the left side of the line
00912     const QRect r(
00913             QPoint( mRect.x()+mMarkerOffs, mRect.y() ),
00914             QSize( mMarker.markerSize().toSize().width(), mRect.height() ) );
00915     MarkerLayoutItem::paintIntoRect(
00916             painter, r, mDiagram, mMarker, mMarkerBrush, mMarkerPen );
00917 }
00918 
00919 KDChart::AutoSpacerLayoutItem::AutoSpacerLayoutItem(
00920         bool layoutIsAtTopPosition, QHBoxLayout *rightLeftLayout,
00921         bool layoutIsAtLeftPosition, QVBoxLayout *topBottomLayout )
00922     : AbstractLayoutItem( Qt::AlignCenter )
00923     , mLayoutIsAtTopPosition( layoutIsAtTopPosition )
00924     , mRightLeftLayout( rightLeftLayout )
00925     , mLayoutIsAtLeftPosition( layoutIsAtLeftPosition )
00926     , mTopBottomLayout( topBottomLayout )
00927 {
00928 }
00929 
00930 Qt::Orientations KDChart::AutoSpacerLayoutItem::expandingDirections() const
00931 {
00932     return 0; // Grow neither vertically nor horizontally
00933 }
00934 
00935 QRect KDChart::AutoSpacerLayoutItem::geometry() const
00936 {
00937     return mRect;
00938 }
00939 
00940 bool KDChart::AutoSpacerLayoutItem::isEmpty() const
00941 {
00942     return true; // never empty, otherwise the layout item would not exist
00943 }
00944 
00945 QSize KDChart::AutoSpacerLayoutItem::maximumSize() const
00946 {
00947     return sizeHint();
00948 }
00949 
00950 QSize KDChart::AutoSpacerLayoutItem::minimumSize() const
00951 {
00952     return sizeHint();
00953 }
00954 
00955 void KDChart::AutoSpacerLayoutItem::setGeometry( const QRect& r )
00956 {
00957     mRect = r;
00958 }
00959 
00960 
00961 static void updateCommonBrush( QBrush& commonBrush, bool& bStart, const KDChart::AbstractArea& area )
00962 {
00963     const KDChart::BackgroundAttributes ba( area.backgroundAttributes() );
00964     const bool hasSimpleBrush = (
00965             ! area.frameAttributes().isVisible() &&
00966             ba.isVisible() &&
00967             ba.pixmapMode() == KDChart::BackgroundAttributes::BackgroundPixmapModeNone &&
00968             ba.brush().gradient() == 0 );
00969     if( bStart ){
00970         bStart = false;
00971         commonBrush = hasSimpleBrush ? ba.brush() : QBrush();
00972     }else{
00973         if( ! hasSimpleBrush || ba.brush() != commonBrush )
00974         {
00975             commonBrush = QBrush();
00976         }
00977     }
00978 }
00979 
00980 QSize KDChart::AutoSpacerLayoutItem::sizeHint() const
00981 {
00982     QBrush commonBrush;
00983     bool bStart=true;
00984     // calculate the maximal overlap of the top/bottom axes:
00985     int topBottomOverlap = 0;
00986     if( mTopBottomLayout ){
00987         for (int i = 0; i < mTopBottomLayout->count(); ++i){
00988             AbstractArea* area = dynamic_cast<AbstractArea*>(mTopBottomLayout->itemAt(i));
00989             if( area ){
00990                 //qDebug() << "AutoSpacerLayoutItem testing" << area;
00991                 topBottomOverlap = qMax( topBottomOverlap,
00992                                          mLayoutIsAtLeftPosition ? area->rightOverlap()
00993                                                                  : area->leftOverlap() );
00994                 updateCommonBrush( commonBrush, bStart, *area );
00995             }
00996         }
00997     }
00998     // calculate the maximal overlap of the left/right axes:
00999     int leftRightOverlap = 0;
01000     if( mRightLeftLayout ){
01001         for (int i = 0; i < mRightLeftLayout->count(); ++i){
01002             AbstractArea* area = dynamic_cast<AbstractArea*>(mRightLeftLayout->itemAt(i));
01003             if( area ){
01004                 //qDebug() << "AutoSpacerLayoutItem testing" << area;
01005                 leftRightOverlap = qMax( leftRightOverlap,
01006                                          mLayoutIsAtTopPosition ? area->bottomOverlap()
01007                                                                 : area->topOverlap() );
01008                 updateCommonBrush( commonBrush, bStart, *area );
01009             }
01010         }
01011     }
01012     if( topBottomOverlap > 0 && leftRightOverlap > 0 )
01013         mCommonBrush = commonBrush;
01014     else
01015         mCommonBrush = QBrush();
01016     mCachedSize = QSize( topBottomOverlap, leftRightOverlap );
01017     //qDebug() << mCachedSize;
01018     return mCachedSize;
01019 }
01020 
01021 
01022 void KDChart::AutoSpacerLayoutItem::paint( QPainter* painter )
01023 {
01024     if( mParentLayout && mRect.isValid() && mCachedSize.isValid() &&
01025         mCommonBrush.style() != Qt::NoBrush )
01026     {
01027         QPoint p1( mRect.topLeft() );
01028         QPoint p2( mRect.bottomRight() );
01029         if( mLayoutIsAtLeftPosition )
01030             p1.rx() += mCachedSize.width() - mParentLayout->spacing();
01031         else
01032             p2.rx() -= mCachedSize.width() - mParentLayout->spacing();
01033         if( mLayoutIsAtTopPosition ){
01034             p1.ry() += mCachedSize.height() - mParentLayout->spacing() - 1;
01035             p2.ry() -= 1;
01036         }else
01037             p2.ry() -= mCachedSize.height() - mParentLayout->spacing() - 1;
01038         //qDebug() << mLayoutIsAtTopPosition << mLayoutIsAtLeftPosition;
01039         //qDebug() << mRect;
01040         //qDebug() << mParentLayout->margin();
01041         //qDebug() << QRect( p1, p2 );
01042         const QPoint oldBrushOrigin( painter->brushOrigin() );
01043         const QBrush oldBrush( painter->brush() );
01044         const QPen   oldPen( painter->pen() );
01045         const QPointF newTopLeft( painter->deviceMatrix().map( p1 ) );
01046         painter->setBrushOrigin( newTopLeft );
01047         painter->setBrush( mCommonBrush );
01048         painter->setPen( Qt::NoPen );
01049         painter->drawRect( QRect( p1, p2 ) );
01050         painter->setBrushOrigin( oldBrushOrigin );
01051         painter->setBrush( oldBrush );
01052         painter->setPen( oldPen );
01053     }
01054     // debug code:
01055 #if 0
01056     //qDebug() << "KDChart::AutoSpacerLayoutItem::paint()";
01057     if( !mRect.isValid() )
01058         return;
01059 
01060     painter->drawRect( mRect );
01061     painter->drawLine( QPointF( mRect.topLeft(), mRect.bottomRight() ) );
01062     painter->drawLine( QPointF( mRect.topRight(), mRect.bottomLeft() ) );
01063 #endif
01064 }
 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/