Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

KDChartLayoutItems.cpp

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

Generated on Thu May 10 11:06:25 2007 for KD Chart 2 by doxygen 1.3.6