9 #include "KChartLayoutItems.h"
11 #include "KTextDocument.h"
12 #include "KChartAbstractArea.h"
13 #include "KChartAbstractDiagram.h"
14 #include "KChartBackgroundAttributes.h"
15 #include "KChartFrameAttributes.h"
16 #include "KChartPaintContext.h"
17 #include "KChartPainterSaver_p.h"
18 #include "KChartPrintingParameters.h"
19 #include "KChartMath_p.h"
21 #include <QTextCursor>
22 #include <QTextBlockFormat>
23 #include <QTextDocumentFragment>
24 #include <QAbstractTextDocumentLayout>
27 #include <QCoreApplication>
28 #include <QApplication>
29 #include <QStringList>
48 paint( context->painter() );
56 if ( mParent->layout() )
57 mParent->layout()->invalidate();
63 KChart::TextBubbleLayoutItem::TextBubbleLayoutItem(
const QString& text,
69 m_text( new
TextLayoutItem( text, attributes, area, orientation, alignment ) )
73 KChart::TextBubbleLayoutItem::TextBubbleLayoutItem()
74 : AbstractLayoutItem(
Qt::AlignLeft ),
75 m_text( new TextLayoutItem() )
79 KChart::TextBubbleLayoutItem::~TextBubbleLayoutItem()
84 void KChart::TextBubbleLayoutItem::setAutoReferenceArea(
const QObject* area )
86 m_text->setAutoReferenceArea( area );
89 const QObject* KChart::TextBubbleLayoutItem::autoReferenceArea()
const
91 return m_text->autoReferenceArea();
94 void KChart::TextBubbleLayoutItem::setText(
const QString& text )
96 m_text->setText( text );
99 QString KChart::TextBubbleLayoutItem::text()
const
101 return m_text->text();
104 void KChart::TextBubbleLayoutItem::setTextAttributes(
const TextAttributes& a )
106 m_text->setTextAttributes( a );
111 return m_text->textAttributes();
114 bool KChart::TextBubbleLayoutItem::isEmpty()
const
116 return m_text->isEmpty();
121 return m_text->expandingDirections();
124 QSize KChart::TextBubbleLayoutItem::maximumSize()
const
126 const int border = borderWidth();
127 return m_text->maximumSize() +
QSize( 2 * border, 2 * border );
130 QSize KChart::TextBubbleLayoutItem::minimumSize()
const
132 const int border = borderWidth();
133 return m_text->minimumSize() +
QSize( 2 * border, 2 * border );
136 QSize KChart::TextBubbleLayoutItem::sizeHint()
const
138 const int border = borderWidth();
139 return m_text->sizeHint() +
QSize( 2 * border, 2 * border );
142 void KChart::TextBubbleLayoutItem::setGeometry(
const QRect& r )
144 const int border = borderWidth();
145 m_text->setGeometry( r.
adjusted( border, border, -border, -border ) );
148 QRect KChart::TextBubbleLayoutItem::geometry()
const
150 const int border = borderWidth();
151 return m_text->geometry().adjusted( -border, -border, border, border );
154 void KChart::TextBubbleLayoutItem::paint(
QPainter* painter )
156 const QPen oldPen = painter->
pen();
161 painter->
setPen( oldPen );
163 m_text->paint( painter );
166 int KChart::TextBubbleLayoutItem::borderWidth()
const
171 KChart::TextLayoutItem::TextLayoutItem(
const QString& text,
176 : AbstractLayoutItem( alignment )
178 , mTextAlignment( alignment )
179 , mAttributes( attributes )
180 , mAutoReferenceArea( area )
181 , mAutoReferenceOrientation( orientation )
183 , cachedFontSize( 0.0 )
184 , cachedFont( mAttributes.font() )
188 KChart::TextLayoutItem::TextLayoutItem()
193 , mAutoReferenceArea( nullptr )
194 , mAutoReferenceOrientation(
KChartEnums::MeasureOrientationHorizontal )
196 , cachedFontSize( 0.0 )
197 , cachedFont( mAttributes.font() )
202 void KChart::TextLayoutItem::setAutoReferenceArea(
const QObject* area )
204 mAutoReferenceArea = area;
205 cachedSizeHint =
QSize();
209 const QObject* KChart::TextLayoutItem::autoReferenceArea()
const
211 return mAutoReferenceArea;
214 void KChart::TextLayoutItem::setText(
const QString & text)
217 cachedSizeHint =
QSize();
223 QString KChart::TextLayoutItem::text()
const
228 void KChart::TextLayoutItem::setTextAlignment(
Qt::Alignment alignment)
230 if ( mTextAlignment == alignment )
232 mTextAlignment = alignment;
239 return mTextAlignment;
245 cachedFont = a.
font();
246 cachedSizeHint =
QSize();
289 QRectF rotatedRect(
const QRectF& rect, qreal rotation )
299 qreal KChart::TextLayoutItem::fitFontSizeToGeometry()
const
301 QFont f = realFont();
303 qreal result = origResult;
304 const qreal minSize = mAttributes.minimalFontSize().value();
305 const QSize mySize = geometry().size();
312 const QSizeF textSize = rotatedRect( fm.boundingRect( mText ), mAttributes.rotation() ).
normalized().
size();
319 if ( minSize > 0 && result < minSize ) {
321 }
else if ( result <= 0.0 ) {
329 qreal KChart::TextLayoutItem::realFontSize()
const
331 return mAttributes.calculatedFontSize( mAutoReferenceArea, mAutoReferenceOrientation );
334 bool KChart::TextLayoutItem::maybeUpdateRealFont()
const
336 const qreal fntSiz = realFontSize();
337 const bool doUpdate = !cachedSizeHint.isValid() || cachedFontSize != fntSiz;
339 if ( doUpdate && fntSiz > 0.0 ) {
340 cachedFontSize = fntSiz;
341 cachedFont.setPointSizeF( fntSiz );
346 QFont KChart::TextLayoutItem::realFont()
const
348 maybeUpdateRealFont();
352 QPolygon KChart::TextLayoutItem::boundingPolygon()
const
355 return mCachedBoundingPolygon;
358 bool KChart::TextLayoutItem::intersects(
const TextLayoutItem& other,
const QPointF& myPos,
const QPointF& otherPos )
const
363 bool KChart::TextLayoutItem::intersects(
const TextLayoutItem& other,
const QPoint& myPos,
const QPoint& otherPos )
const
365 QRegion myRegion( boundingPolygon().translated( myPos - otherPos ) );
366 QRegion otherRegion( other.boundingPolygon() );
368 return myRegion.intersects( otherRegion );
374 if ( maybeUpdateRealFont() || mAttributes.rotation() || !cachedSizeHint.isValid() ) {
375 const QSize newSizeHint( calcSizeHint( cachedFont ) );
376 Q_ASSERT( newSizeHint.
isValid() );
377 if ( newSizeHint != cachedSizeHint ) {
378 cachedSizeHint = newSizeHint;
382 return cachedSizeHint;
385 QSize KChart::TextLayoutItem::sizeHintUnrotated()
const
387 maybeUpdateRealFont();
388 return unrotatedSizeHint( cachedFont );
395 QSize KChart::TextLayoutItem::unrotatedTextSize(
QFont fnt )
const
397 if ( fnt ==
QFont() ) {
402 QRect veryLarge( 0, 0, 100000, 100000 );
407 int KChart::TextLayoutItem::marginWidth()
const
409 return marginWidth( unrotatedTextSize() );
412 int KChart::TextLayoutItem::marginWidth(
const QSize& textSize )
const
416 textSize.
height() * 2 / 3 );
419 QSize KChart::TextLayoutItem::unrotatedSizeHint(
const QFont& fnt )
const
421 QSize ret = unrotatedTextSize( fnt );
422 const int margin = marginWidth( ret );
423 ret +=
QSize( margin, margin );
427 QSize KChart::TextLayoutItem::calcSizeHint(
const QFont& font )
const
429 const QSize size = unrotatedSizeHint( font );
431 if ( !mAttributes.rotation() ) {
432 mCachedBoundingPolygon.resize( 4 );
435 mCachedBoundingPolygon[ 0 ] = topLeft;
436 mCachedBoundingPolygon[ 1 ] = topLeft +
QPoint( size.
width(), 0 );
438 mCachedBoundingPolygon[ 3 ] = topLeft +
QPoint( 0, size.
height() );
442 const QRect rect( topLeft, size );
444 t.
rotate( mAttributes.rotation() );
450 void KChart::TextLayoutItem::paint(
QPainter* painter )
452 if ( !mRect.isValid() ) {
455 const PainterSaver painterSaver( painter );
456 QFont f = realFont();
457 if ( mAttributes.autoShrink() ) {
462 QSize innerSize = unrotatedTextSize();
466 painter->
rotate( mAttributes.rotation() );
467 #ifdef DEBUG_ITEMS_PAINT
472 painter->
setPen( PrintingParameters::scalePen( mAttributes.pen() ) );
480 paintcontext.clip = rect;
483 painter->
drawText( rect, mTextAlignment, mText );
487 KChart::HorizontalLineLayoutItem::HorizontalLineLayoutItem()
492 Qt::Orientations KChart::HorizontalLineLayoutItem::expandingDirections()
const
497 QRect KChart::HorizontalLineLayoutItem::geometry()
const
502 bool KChart::HorizontalLineLayoutItem::isEmpty()
const
507 QSize KChart::HorizontalLineLayoutItem::maximumSize()
const
509 return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
512 QSize KChart::HorizontalLineLayoutItem::minimumSize()
const
514 return QSize( 0, 0 );
517 void KChart::HorizontalLineLayoutItem::setGeometry(
const QRect& r )
522 QSize KChart::HorizontalLineLayoutItem::sizeHint()
const
524 return QSize( -1, 3 );
528 void KChart::HorizontalLineLayoutItem::paint(
QPainter* painter )
530 if ( !mRect.isValid() )
534 QPointF( mRect.right(), mRect.center().y() ) );
538 KChart::VerticalLineLayoutItem::VerticalLineLayoutItem()
543 Qt::Orientations KChart::VerticalLineLayoutItem::expandingDirections()
const
548 QRect KChart::VerticalLineLayoutItem::geometry()
const
553 bool KChart::VerticalLineLayoutItem::isEmpty()
const
558 QSize KChart::VerticalLineLayoutItem::maximumSize()
const
560 return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
563 QSize KChart::VerticalLineLayoutItem::minimumSize()
const
565 return QSize( 0, 0 );
568 void KChart::VerticalLineLayoutItem::setGeometry(
const QRect& r )
573 QSize KChart::VerticalLineLayoutItem::sizeHint()
const
575 return QSize( 3, -1 );
579 void KChart::VerticalLineLayoutItem::paint(
QPainter* painter )
581 if ( !mRect.isValid() )
585 QPointF( mRect.center().x(), mRect.bottom() ) );
591 const MarkerAttributes& marker,
594 : AbstractLayoutItem( alignment )
595 , mDiagram( diagram )
607 QRect KChart::MarkerLayoutItem::geometry()
const
612 bool KChart::MarkerLayoutItem::isEmpty()
const
617 QSize KChart::MarkerLayoutItem::maximumSize()
const
622 QSize KChart::MarkerLayoutItem::minimumSize()
const
627 void KChart::MarkerLayoutItem::setGeometry(
const QRect& r )
632 QSize KChart::MarkerLayoutItem::sizeHint()
const
635 return mMarker.markerSize().toSize();
638 void KChart::MarkerLayoutItem::paint(
QPainter* painter )
640 paintIntoRect( painter, mRect, mDiagram, mMarker, mBrush, mPen );
643 void KChart::MarkerLayoutItem::paintIntoRect(
646 AbstractDiagram* diagram,
647 const MarkerAttributes& marker,
656 const QSize siz = marker.markerSize().toSize();
659 static_cast<qreal
>(( rect.
height() - siz.
height()) / 2.0 ) );
661 #ifdef DEBUG_ITEMS_PAINT
667 pos +=
QPointF(
static_cast<qreal
>( siz.
width() ) / 2.0,
668 static_cast<qreal
>( siz.
height() )/ 2.0 );
670 diagram->paintMarker( painter, marker, brush, pen, pos.
toPoint(), siz );
672 #ifdef DEBUG_ITEMS_PAINT
673 const QPen oldPen( painter->
pen() );
676 painter->
setPen( oldPen );
686 : AbstractLayoutItem( alignment )
687 , mDiagram( diagram )
690 , mLegendLineSymbolAlignment(legendLineSymbolAlignment)
693 if ( pen.
width() < 2 )
702 QRect KChart::LineLayoutItem::geometry()
const
707 bool KChart::LineLayoutItem::isEmpty()
const
712 QSize KChart::LineLayoutItem::maximumSize()
const
717 QSize KChart::LineLayoutItem::minimumSize()
const
722 void KChart::LineLayoutItem::setGeometry(
const QRect& r )
727 QSize KChart::LineLayoutItem::sizeHint()
const
729 return QSize( mLength, mPen.width() + 2 );
733 void KChart::LineLayoutItem::setLegendLineSymbolAlignment(
Qt::Alignment legendLineSymbolAlignment)
735 if (mLegendLineSymbolAlignment == legendLineSymbolAlignment)
738 mLegendLineSymbolAlignment = legendLineSymbolAlignment;
741 Qt::Alignment KChart::LineLayoutItem::legendLineSymbolAlignment()
const
743 return mLegendLineSymbolAlignment;
746 void KChart::LineLayoutItem::paint(
QPainter* painter )
748 paintIntoRect( painter, mRect, mPen, mLegendLineSymbolAlignment );
751 void KChart::LineLayoutItem::paintIntoRect(
760 const QPen oldPen = painter->
pen();
761 painter->
setPen( PrintingParameters::scalePen( pen ) );
772 painter->
setPen( oldPen );
776 KChart::LineWithMarkerLayoutItem::LineWithMarkerLayoutItem(
781 const MarkerAttributes& marker,
782 const QBrush& markerBrush,
783 const QPen& markerPen,
785 : AbstractLayoutItem( alignment )
786 , mDiagram( diagram )
787 , mLineLength( lineLength )
788 , mLinePen( linePen )
789 , mMarkerOffs( markerOffs )
791 , mMarkerBrush( markerBrush )
792 , mMarkerPen( markerPen )
796 Qt::Orientations KChart::LineWithMarkerLayoutItem::expandingDirections()
const
801 QRect KChart::LineWithMarkerLayoutItem::geometry()
const
806 bool KChart::LineWithMarkerLayoutItem::isEmpty()
const
811 QSize KChart::LineWithMarkerLayoutItem::maximumSize()
const
816 QSize KChart::LineWithMarkerLayoutItem::minimumSize()
const
821 void KChart::LineWithMarkerLayoutItem::setGeometry(
const QRect& r )
826 QSize KChart::LineWithMarkerLayoutItem::sizeHint()
const
828 const QSize lineSize( mLineLength, mLinePen.width() + 2 );
829 return lineSize.expandedTo( mMarker.markerSize().toSize() );
832 void KChart::LineWithMarkerLayoutItem::paint(
QPainter* painter )
835 LineLayoutItem::paintIntoRect( painter, mRect, mLinePen,
Qt::AlignCenter );
839 QPoint( mRect.x()+mMarkerOffs, mRect.y() ),
840 QSize( mMarker.markerSize().toSize().width(), mRect.height() ) );
841 MarkerLayoutItem::paintIntoRect(
842 painter, r, mDiagram, mMarker, mMarkerBrush, mMarkerPen );
845 KChart::AutoSpacerLayoutItem::AutoSpacerLayoutItem(
846 bool layoutIsAtTopPosition,
QHBoxLayout *rightLeftLayout,
847 bool layoutIsAtLeftPosition,
QVBoxLayout *topBottomLayout )
849 , mLayoutIsAtTopPosition( layoutIsAtTopPosition )
850 , mRightLeftLayout( rightLeftLayout )
851 , mLayoutIsAtLeftPosition( layoutIsAtLeftPosition )
852 , mTopBottomLayout( topBottomLayout )
861 QRect KChart::AutoSpacerLayoutItem::geometry()
const
866 bool KChart::AutoSpacerLayoutItem::isEmpty()
const
871 QSize KChart::AutoSpacerLayoutItem::maximumSize()
const
876 QSize KChart::AutoSpacerLayoutItem::minimumSize()
const
881 void KChart::AutoSpacerLayoutItem::setGeometry(
const QRect& r )
890 const bool hasSimpleBrush = (
891 ! area.frameAttributes().isVisible() &&
893 ba.pixmapMode() == KChart::BackgroundAttributes::BackgroundPixmapModeNone &&
894 ba.brush().gradient() == nullptr );
897 commonBrush = hasSimpleBrush ? ba.brush() :
QBrush();
899 if ( ! hasSimpleBrush || ba.brush() != commonBrush )
906 QSize KChart::AutoSpacerLayoutItem::sizeHint()
const
911 int topBottomOverlap = 0;
912 if ( mTopBottomLayout ) {
913 for (
int i = 0; i < mTopBottomLayout->count(); ++i) {
914 AbstractArea* area =
dynamic_cast<AbstractArea*
>(mTopBottomLayout->itemAt(i));
917 topBottomOverlap = qMax( topBottomOverlap,
918 mLayoutIsAtLeftPosition ? area->rightOverlap()
919 : area->leftOverlap() );
920 updateCommonBrush( commonBrush, bStart, *area );
925 int leftRightOverlap = 0;
926 if ( mRightLeftLayout ) {
927 for (
int i = 0; i < mRightLeftLayout->count(); ++i) {
928 AbstractArea* area =
dynamic_cast<AbstractArea*
>(mRightLeftLayout->itemAt(i));
931 leftRightOverlap = qMax( leftRightOverlap,
932 mLayoutIsAtTopPosition ? area->bottomOverlap()
933 : area->topOverlap() );
934 updateCommonBrush( commonBrush, bStart, *area );
938 if ( topBottomOverlap > 0 && leftRightOverlap > 0 )
939 mCommonBrush = commonBrush;
942 mCachedSize =
QSize( topBottomOverlap, leftRightOverlap );
948 void KChart::AutoSpacerLayoutItem::paint(
QPainter* painter )
950 if ( mParentLayout && mRect.isValid() && mCachedSize.isValid() &&
953 QPoint p1( mRect.topLeft() );
954 QPoint p2( mRect.bottomRight() );
955 if ( mLayoutIsAtLeftPosition )
956 p1.rx() += mCachedSize.width() - mParentLayout->spacing();
958 p2.rx() -= mCachedSize.width() - mParentLayout->spacing();
959 if ( mLayoutIsAtTopPosition ) {
960 p1.ry() += mCachedSize.height() - mParentLayout->spacing() - 1;
963 p2.ry() -= mCachedSize.height() - mParentLayout->spacing() - 1;
970 const QPen oldPen( painter->
pen() );
978 painter->
setPen( oldPen );
983 if ( !mRect.isValid() )