chart2/source/view/axes/VAxisBase.cxx | 4 chart2/source/view/axes/VAxisBase.hxx | 2 chart2/source/view/axes/VAxisProperties.cxx | 9 chart2/source/view/axes/VAxisProperties.hxx | 4 chart2/source/view/axes/VCartesianAxis.cxx | 300 +++++++++++++++++++++------- chart2/source/view/axes/VCartesianAxis.hxx | 36 ++- 6 files changed, 277 insertions(+), 78 deletions(-)
New commits: commit 6a71d5bd7722b30b5cb268487da706c7a6e0c05b Author: Kohei Yoshida <[email protected]> Date: Thu Oct 23 13:35:54 2014 -0400 Modify the tick iterator strategy to use fewer ticks. To pre-determine the size of the largest text label object, auto-staggering strategy etc. In theory (if I read the code correctly) we could achieve the same thing by using only 3 ticks rather than 5. Change-Id: Iee51588061e482c724ee4fb666c51c2a6b636e8c diff --git a/chart2/source/view/axes/VCartesianAxis.cxx b/chart2/source/view/axes/VCartesianAxis.cxx index 7ff0f99..1209664 100644 --- a/chart2/source/view/axes/VCartesianAxis.cxx +++ b/chart2/source/view/axes/VCartesianAxis.cxx @@ -407,9 +407,10 @@ void getAxisLabelProperties( } /** - * Iterate through only the first 2 and last 2 tick info items, and the tick - * that has the longest text (in terms of character length) in case it's not - * in the first or last 2 items. + * Iterate through only 3 ticks including the one that has the longest text + * length. When the first tick has the longest text, it iterates through + * the first 3 ticks. Otherwise it iterates through 3 ticks such that the + * 2nd tick is the one with the longest text. */ class MaxLabelTickIter : public TickIter { @@ -431,21 +432,27 @@ MaxLabelTickIter::MaxLabelTickIter( m_rTickInfoVector(rTickInfoVector), m_nCurrentIndex(0) { assert(!rTickInfoVector.empty()); // should be checked by the caller. + assert(nLongestLabelIndex < rTickInfoVector.size()); size_t nMaxIndex = m_rTickInfoVector.size()-1; if (nLongestLabelIndex >= nMaxIndex-1) nLongestLabelIndex = 0; - m_aValidIndices.push_back(0); - if( nMaxIndex>=1 ) - m_aValidIndices.push_back(1); - if( nLongestLabelIndex>1 ) + if (nLongestLabelIndex > 0) + m_aValidIndices.push_back(nLongestLabelIndex-1); + + m_aValidIndices.push_back(nLongestLabelIndex); + + while (m_aValidIndices.size() < 3) + { + ++nLongestLabelIndex; + if (nLongestLabelIndex > nMaxIndex) + break; + m_aValidIndices.push_back(nLongestLabelIndex); - if( nMaxIndex > 2 ) - m_aValidIndices.push_back(nMaxIndex-1); - if( nMaxIndex > 1 ) - m_aValidIndices.push_back(nMaxIndex); + } } + MaxLabelTickIter::~MaxLabelTickIter() { } @@ -624,6 +631,9 @@ TickIter* VCartesianAxis::createMaximumLabelTickIterator( sal_Int32 nTextLevel ) if( !m_aAllTickInfos.empty() ) { size_t nLongestLabelIndex = m_bUseTextLabels ? getIndexOfLongestLabel(m_aTextLabels) : 0; + if (nLongestLabelIndex >= m_aAllTickInfos[0].size()) + return NULL; + return new MaxLabelTickIter( m_aAllTickInfos[0], nLongestLabelIndex ); } } commit af7aedbceb694a1193e34eafcb94db632ff089d7 Author: Kohei Yoshida <[email protected]> Date: Thu Oct 23 12:43:30 2014 -0400 Let's use size_t for the index. This removes unnecessary static_cast's and check for negative values which, from what I've read from the code, never happens. Change-Id: I9d9e1de5b091df335dd3b7eeb34e4e8f98de0fbd diff --git a/chart2/source/view/axes/VAxisBase.cxx b/chart2/source/view/axes/VAxisBase.cxx index c391382..f97655f 100644 --- a/chart2/source/view/axes/VAxisBase.cxx +++ b/chart2/source/view/axes/VAxisBase.cxx @@ -187,7 +187,7 @@ bool VAxisBase::prepareShapeCreation() return true; } -sal_Int32 VAxisBase::getIndexOfLongestLabel( const uno::Sequence< OUString >& rLabels ) +size_t VAxisBase::getIndexOfLongestLabel( const uno::Sequence<OUString>& rLabels ) { sal_Int32 nRet = 0; sal_Int32 nLength = 0; @@ -201,6 +201,8 @@ sal_Int32 VAxisBase::getIndexOfLongestLabel( const uno::Sequence< OUString >& rL nRet = nN; } } + + assert(nRet >= 0); return nRet; } diff --git a/chart2/source/view/axes/VAxisBase.hxx b/chart2/source/view/axes/VAxisBase.hxx index d43ef58..ab0e4093 100644 --- a/chart2/source/view/axes/VAxisBase.hxx +++ b/chart2/source/view/axes/VAxisBase.hxx @@ -65,7 +65,7 @@ public: void setExrtaLinePositionAtOtherAxis( double fCrossingAt ); protected: //methods - sal_Int32 getIndexOfLongestLabel( const ::com::sun::star::uno::Sequence< OUString >& rLabels ); + size_t getIndexOfLongestLabel( const css::uno::Sequence<OUString>& rLabels ); void removeTextShapesFromTicks(); void updateUnscaledValuesAtTicks( TickIter& rIter ); diff --git a/chart2/source/view/axes/VCartesianAxis.cxx b/chart2/source/view/axes/VCartesianAxis.cxx index fbc5335..7ff0f99 100644 --- a/chart2/source/view/axes/VCartesianAxis.cxx +++ b/chart2/source/view/axes/VCartesianAxis.cxx @@ -414,8 +414,7 @@ void getAxisLabelProperties( class MaxLabelTickIter : public TickIter { public: - MaxLabelTickIter( TickInfoArrayType& rTickInfoVector - , sal_Int32 nLongestLabelIndex ); + MaxLabelTickIter( TickInfoArrayType& rTickInfoVector, size_t nLongestLabelIndex ); virtual ~MaxLabelTickIter(); virtual TickInfo* firstInfo() SAL_OVERRIDE; @@ -423,21 +422,21 @@ public: private: TickInfoArrayType& m_rTickInfoVector; - ::std::vector< sal_Int32 > m_aValidIndices; - sal_Int32 m_nCurrentIndex; + std::vector<size_t> m_aValidIndices; + size_t m_nCurrentIndex; }; -MaxLabelTickIter::MaxLabelTickIter( TickInfoArrayType& rTickInfoVector - , sal_Int32 nLongestLabelIndex ) - : m_rTickInfoVector(rTickInfoVector) - , m_nCurrentIndex(0) +MaxLabelTickIter::MaxLabelTickIter( + TickInfoArrayType& rTickInfoVector, size_t nLongestLabelIndex ) : + m_rTickInfoVector(rTickInfoVector), m_nCurrentIndex(0) { - sal_Int32 nMaxIndex = m_rTickInfoVector.size()-1; - if( nLongestLabelIndex<0 || nLongestLabelIndex>=nMaxIndex-1 ) + assert(!rTickInfoVector.empty()); // should be checked by the caller. + + size_t nMaxIndex = m_rTickInfoVector.size()-1; + if (nLongestLabelIndex >= nMaxIndex-1) nLongestLabelIndex = 0; - if( nMaxIndex>=0 ) - m_aValidIndices.push_back(0); + m_aValidIndices.push_back(0); if( nMaxIndex>=1 ) m_aValidIndices.push_back(1); if( nLongestLabelIndex>1 ) @@ -454,7 +453,7 @@ MaxLabelTickIter::~MaxLabelTickIter() TickInfo* MaxLabelTickIter::firstInfo() { m_nCurrentIndex = 0; - if( m_nCurrentIndex < static_cast<sal_Int32>(m_aValidIndices.size()) ) + if (m_nCurrentIndex < m_aValidIndices.size()) return &m_rTickInfoVector[m_aValidIndices[m_nCurrentIndex]]; return 0; } @@ -462,7 +461,7 @@ TickInfo* MaxLabelTickIter::firstInfo() TickInfo* MaxLabelTickIter::nextInfo() { m_nCurrentIndex++; - if( m_nCurrentIndex>=0 && m_nCurrentIndex<static_cast<sal_Int32>(m_aValidIndices.size()) ) + if (m_nCurrentIndex < m_aValidIndices.size()) return &m_rTickInfoVector[m_aValidIndices[m_nCurrentIndex]]; return 0; } @@ -624,7 +623,7 @@ TickIter* VCartesianAxis::createMaximumLabelTickIterator( sal_Int32 nTextLevel ) { if( !m_aAllTickInfos.empty() ) { - sal_Int32 nLongestLabelIndex = m_bUseTextLabels ? this->getIndexOfLongestLabel( m_aTextLabels ) : 0; + size_t nLongestLabelIndex = m_bUseTextLabels ? getIndexOfLongestLabel(m_aTextLabels) : 0; return new MaxLabelTickIter( m_aAllTickInfos[0], nLongestLabelIndex ); } } commit 19e33a3ad865e5fbe12dbaca90199f4d6441cc97 Author: Kohei Yoshida <[email protected]> Date: Wed Oct 22 11:50:41 2014 -0400 Some code sharing. Change-Id: If80c4b0ceec5e0afd55d12ebe7511fb4f40b4797 diff --git a/chart2/source/view/axes/VAxisProperties.cxx b/chart2/source/view/axes/VAxisProperties.cxx index 3b5502f..3db365d 100644 --- a/chart2/source/view/axes/VAxisProperties.cxx +++ b/chart2/source/view/axes/VAxisProperties.cxx @@ -412,6 +412,13 @@ bool AxisLabelProperties::isStaggered() const return ( STAGGER_ODD == eStaggering || STAGGER_EVEN == eStaggering ); } +void AxisLabelProperties::autoRotate45() +{ + fRotationAngleDegree = 45; + bLineBreakAllowed = false; + eStaggering = SIDE_BY_SIDE; +} + } //namespace chart /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VAxisProperties.hxx b/chart2/source/view/axes/VAxisProperties.hxx index b658925..1eadf70 100644 --- a/chart2/source/view/axes/VAxisProperties.hxx +++ b/chart2/source/view/axes/VAxisProperties.hxx @@ -82,6 +82,8 @@ struct AxisLabelProperties SAL_FINAL ::com::sun::star::chart2::XAxis >& xAxisModel ); bool isStaggered() const; + + void autoRotate45(); }; struct AxisLabelAlignment diff --git a/chart2/source/view/axes/VCartesianAxis.cxx b/chart2/source/view/axes/VCartesianAxis.cxx index d43e32f..fbc5335 100644 --- a/chart2/source/view/axes/VCartesianAxis.cxx +++ b/chart2/source/view/axes/VCartesianAxis.cxx @@ -365,6 +365,47 @@ bool lcl_hasWordBreak( const Reference<drawing::XShape>& xShape ) return false; } +OUString getTextLabelString( + const FixedNumberFormatter& rFixedNumberFormatter, const uno::Sequence<OUString>* pCategories, + const TickInfo* pTickInfo, bool bComplexCat, sal_Int32& rExtraColor, bool& rHasExtraColor ) +{ + if (pCategories) + { + // This is a normal category axis. Get the label string from the + // label string array. + sal_Int32 nIndex = static_cast<sal_Int32>(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0 + if( nIndex>=0 && nIndex<pCategories->getLength() ) + return (*pCategories)[nIndex]; + + return OUString(); + } + else if (bComplexCat) + { + // This is a complex category axis. The label is stored in the tick. + return pTickInfo->aText; + } + + // This is a numeric axis. Format the original tick value per number format. + return rFixedNumberFormatter.getFormattedString(pTickInfo->getUnscaledTickValue(), rExtraColor, rHasExtraColor); +} + +void getAxisLabelProperties( + tNameSequence& rPropNames, tAnySequence& rPropValues, const AxisProperties& rAxisProp, + const AxisLabelProperties& rAxisLabelProp, + sal_Int32 nLimitedSpaceForText, bool bLimitedHeight ) +{ + Reference<beans::XPropertySet> xProps(rAxisProp.m_xAxisModel, uno::UNO_QUERY); + + PropertyMapper::getTextLabelMultiPropertyLists( + xProps, rPropNames, rPropValues, false, nLimitedSpaceForText, bLimitedHeight); + + LabelPositionHelper::doDynamicFontResize( + rPropValues, rPropNames, xProps, rAxisLabelProp.m_aFontReferenceSize); + + LabelPositionHelper::changeTextAdjustment( + rPropValues, rPropNames, rAxisProp.maLabelAlignment.meAlignment); +} + /** * Iterate through only the first 2 and last 2 tick info items, and the tick * that has the longest text (in terms of character length) in case it's not @@ -644,17 +685,12 @@ bool VCartesianAxis::createTextShapes( const TickInfo* pPREPreviousVisibleTickInfo = NULL; const TickInfo* pLastVisibleNeighbourTickInfo = NULL; + bool bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY()); + //prepare properties for multipropertyset-interface of shape tNameSequence aPropNames; tAnySequence aPropValues; - - bool bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY()); - Reference< beans::XPropertySet > xProps( m_aAxisProperties.m_xAxisModel, uno::UNO_QUERY ); - PropertyMapper::getTextLabelMultiPropertyLists( xProps, aPropNames, aPropValues, false - , nLimitedSpaceForText, bLimitedHeight ); - LabelPositionHelper::doDynamicFontResize( aPropValues, aPropNames, xProps - , m_aAxisLabelProperties.m_aFontReferenceSize ); - LabelPositionHelper::changeTextAdjustment( aPropValues, aPropNames, m_aAxisProperties.maLabelAlignment.meAlignment ); + getAxisLabelProperties(aPropNames, aPropValues, m_aAxisProperties, rAxisLabelProperties, nLimitedSpaceForText, bLimitedHeight); uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,"CharColor"); sal_Int32 nColor = Color( COL_AUTO ).GetColor(); @@ -725,25 +761,9 @@ bool VCartesianAxis::createTextShapes( bool bHasExtraColor=false; sal_Int32 nExtraColor=0; - OUString aLabel; - if(pCategories) - { - // This is a normal category axis. Get the label string from the - // label string array. - sal_Int32 nIndex = static_cast<sal_Int32>(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0 - if( nIndex>=0 && nIndex<pCategories->getLength() ) - aLabel = (*pCategories)[nIndex]; - } - else if( m_aAxisProperties.m_bComplexCategories ) - { - // This is a complex category axis. The label is stored in the tick. - aLabel = pTickInfo->aText; - } - else - { - // This is a numeric axis. Format the original tick value per number format. - aLabel = aFixedNumberFormatter.getFormattedString( pTickInfo->getUnscaledTickValue(), nExtraColor, bHasExtraColor ); - } + OUString aLabel = getTextLabelString( + aFixedNumberFormatter, pCategories, pTickInfo, isComplexCategoryAxis(), + nExtraColor, bHasExtraColor); if(pColorAny) *pColorAny = uno::makeAny(bHasExtraColor?nExtraColor:nColor); @@ -810,10 +830,7 @@ bool VCartesianAxis::createTextShapes( // Try auto-rotating the labels at 45 degrees and // start over. This rotation angle will be stored for // all future text shape creation runs. - - rAxisLabelProperties.fRotationAngleDegree = 45; - rAxisLabelProperties.bLineBreakAllowed = false; - rAxisLabelProperties.eStaggering = SIDE_BY_SIDE; + rAxisLabelProperties.autoRotate45(); m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree; // Store it for future runs. removeTextShapesFromTicks(); return false; @@ -862,17 +879,12 @@ bool VCartesianAxis::createTextShapesSimple( const TickInfo* pPreviousVisibleTickInfo = NULL; const TickInfo* pLastVisibleNeighbourTickInfo = NULL; + bool bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY()); + //prepare properties for multipropertyset-interface of shape tNameSequence aPropNames; tAnySequence aPropValues; - - bool bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY()); - Reference< beans::XPropertySet > xProps( m_aAxisProperties.m_xAxisModel, uno::UNO_QUERY ); - PropertyMapper::getTextLabelMultiPropertyLists( xProps, aPropNames, aPropValues, false - , -1, bLimitedHeight ); - LabelPositionHelper::doDynamicFontResize( aPropValues, aPropNames, xProps - , m_aAxisLabelProperties.m_aFontReferenceSize ); - LabelPositionHelper::changeTextAdjustment( aPropValues, aPropNames, m_aAxisProperties.maLabelAlignment.meAlignment ); + getAxisLabelProperties(aPropNames, aPropValues, m_aAxisProperties, rAxisLabelProperties, -1, bLimitedHeight); uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,"CharColor"); sal_Int32 nColor = Color( COL_AUTO ).GetColor(); @@ -921,25 +933,9 @@ bool VCartesianAxis::createTextShapesSimple( bool bHasExtraColor=false; sal_Int32 nExtraColor=0; - OUString aLabel; - if(pCategories) - { - // This is a normal category axis. Get the label string from the - // label string array. - sal_Int32 nIndex = static_cast<sal_Int32>(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0 - if( nIndex>=0 && nIndex<pCategories->getLength() ) - aLabel = (*pCategories)[nIndex]; - } - else if( m_aAxisProperties.m_bComplexCategories ) - { - // This is a complex category axis. The label is stored in the tick. - aLabel = pTickInfo->aText; - } - else - { - // This is a numeric axis. Format the original tick value per number format. - aLabel = aFixedNumberFormatter.getFormattedString( pTickInfo->getUnscaledTickValue(), nExtraColor, bHasExtraColor ); - } + OUString aLabel = getTextLabelString( + aFixedNumberFormatter, pCategories, pTickInfo, isComplexCategoryAxis(), + nExtraColor, bHasExtraColor); if(pColorAny) *pColorAny = uno::makeAny(bHasExtraColor?nExtraColor:nColor); @@ -975,10 +971,7 @@ bool VCartesianAxis::createTextShapesSimple( // Try auto-rotating the labels at 45 degrees and // start over. This rotation angle will be stored for // all future text shape creation runs. - - rAxisLabelProperties.fRotationAngleDegree = 45; - rAxisLabelProperties.bLineBreakAllowed = false; - rAxisLabelProperties.eStaggering = SIDE_BY_SIDE; + rAxisLabelProperties.autoRotate45(); m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree; // Store it for future runs. removeTextShapesFromTicks(); return false; commit b6601a01b4202ff21bc621fd1fd1da11ede0f06a Author: Kohei Yoshida <[email protected]> Date: Wed Oct 22 10:51:44 2014 -0400 Create a variant of createTextShapes for simpler use cases. So that we can do more aggressive optimization without breaking the other cases. Change-Id: I5d4ceb2a3b7f041f752a570827815236e9de58db diff --git a/chart2/source/view/axes/VAxisProperties.cxx b/chart2/source/view/axes/VAxisProperties.cxx index 9b449d5..3b5502f 100644 --- a/chart2/source/view/axes/VAxisProperties.cxx +++ b/chart2/source/view/axes/VAxisProperties.cxx @@ -407,7 +407,7 @@ void AxisLabelProperties::init( const uno::Reference< XAxis >& xAxisModel ) } } -bool AxisLabelProperties::getIsStaggered() const +bool AxisLabelProperties::isStaggered() const { return ( STAGGER_ODD == eStaggering || STAGGER_EVEN == eStaggering ); } diff --git a/chart2/source/view/axes/VAxisProperties.hxx b/chart2/source/view/axes/VAxisProperties.hxx index 7495c21..b658925 100644 --- a/chart2/source/view/axes/VAxisProperties.hxx +++ b/chart2/source/view/axes/VAxisProperties.hxx @@ -81,7 +81,7 @@ struct AxisLabelProperties SAL_FINAL void init( const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XAxis >& xAxisModel ); - bool getIsStaggered() const; + bool isStaggered() const; }; struct AxisLabelAlignment diff --git a/chart2/source/view/axes/VCartesianAxis.cxx b/chart2/source/view/axes/VCartesianAxis.cxx index d095af5..d43e32f 100644 --- a/chart2/source/view/axes/VCartesianAxis.cxx +++ b/chart2/source/view/axes/VCartesianAxis.cxx @@ -600,20 +600,25 @@ sal_Int32 VCartesianAxis::getTextLevelCount() const } bool VCartesianAxis::createTextShapes( - const Reference< drawing::XShapes >& xTarget - , TickIter& rTickIter - , AxisLabelProperties& rAxisLabelProperties - , TickFactory2D* pTickFactory - , sal_Int32 nScreenDistanceBetweenTicks ) + const Reference<drawing::XShapes>& xTarget, TickIter& rTickIter, + AxisLabelProperties& rAxisLabelProperties, TickFactory2D* pTickFactory, + sal_Int32 nScreenDistanceBetweenTicks ) { + const bool bIsHorizontalAxis = pTickFactory->isHorizontalAxis(); + const bool bIsVerticalAxis = pTickFactory->isVerticalAxis(); + + if (!isBreakOfLabelsAllowed(rAxisLabelProperties, bIsHorizontalAxis) && + !isAutoStaggeringOfLabelsAllowed(rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis) && + !rAxisLabelProperties.isStaggered()) + return createTextShapesSimple(xTarget, rTickIter, rAxisLabelProperties, pTickFactory); + FixedNumberFormatter aFixedNumberFormatter( m_xNumberFormatsSupplier, rAxisLabelProperties.nNumberFormatKey ); - const bool bIsHorizontalAxis = pTickFactory->isHorizontalAxis(); - const bool bIsVerticalAxis = pTickFactory->isVerticalAxis(); - bool bIsStaggered = rAxisLabelProperties.getIsStaggered(); + bool bIsStaggered = rAxisLabelProperties.isStaggered(); B2DVector aTextToTickDistance = pTickFactory->getDistanceAxisTickToText(m_aAxisProperties, true); sal_Int32 nLimitedSpaceForText = -1; + if( isBreakOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis ) ) { nLimitedSpaceForText = nScreenDistanceBetweenTicks; @@ -837,6 +842,169 @@ bool VCartesianAxis::createTextShapes( return true; } +bool VCartesianAxis::createTextShapesSimple( + const Reference<drawing::XShapes>& xTarget, TickIter& rTickIter, + AxisLabelProperties& rAxisLabelProperties, TickFactory2D* pTickFactory ) +{ + FixedNumberFormatter aFixedNumberFormatter( + m_xNumberFormatsSupplier, rAxisLabelProperties.nNumberFormatKey ); + + const bool bIsHorizontalAxis = pTickFactory->isHorizontalAxis(); + const bool bIsVerticalAxis = pTickFactory->isVerticalAxis(); + B2DVector aTextToTickDistance = pTickFactory->getDistanceAxisTickToText(m_aAxisProperties, true); + + // Stores an array of text label strings in case of a normal + // (non-complex) category axis. + const uno::Sequence<OUString>* pCategories = NULL; + if( m_bUseTextLabels && !m_aAxisProperties.m_bComplexCategories ) + pCategories = &m_aTextLabels; + + const TickInfo* pPreviousVisibleTickInfo = NULL; + const TickInfo* pLastVisibleNeighbourTickInfo = NULL; + + //prepare properties for multipropertyset-interface of shape + tNameSequence aPropNames; + tAnySequence aPropValues; + + bool bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY()); + Reference< beans::XPropertySet > xProps( m_aAxisProperties.m_xAxisModel, uno::UNO_QUERY ); + PropertyMapper::getTextLabelMultiPropertyLists( xProps, aPropNames, aPropValues, false + , -1, bLimitedHeight ); + LabelPositionHelper::doDynamicFontResize( aPropValues, aPropNames, xProps + , m_aAxisLabelProperties.m_aFontReferenceSize ); + LabelPositionHelper::changeTextAdjustment( aPropValues, aPropNames, m_aAxisProperties.maLabelAlignment.meAlignment ); + + uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,"CharColor"); + sal_Int32 nColor = Color( COL_AUTO ).GetColor(); + if(pColorAny) + *pColorAny >>= nColor; + + uno::Any* pLimitedSpaceAny = PropertyMapper::getValuePointerForLimitedSpace(aPropValues,aPropNames,bLimitedHeight); + + sal_Int32 nTick = 0; + for( TickInfo* pTickInfo = rTickIter.firstInfo() + ; pTickInfo + ; pTickInfo = rTickIter.nextInfo(), nTick++ ) + { + pLastVisibleNeighbourTickInfo = pPreviousVisibleTickInfo; + + //don't create labels which does not fit into the rhythm + if( nTick%rAxisLabelProperties.nRhythm != 0 ) + continue; + + //don't create labels for invisible ticks + if( !pTickInfo->bPaintIt ) + continue; + + if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed ) + { + // Overlapping is not allowed. If the label overlaps with its + // neighbering label, try increasing the tick interval (or rhythm + // as it's called) and start over. + + if( lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape + , rAxisLabelProperties.fRotationAngleDegree + , pTickInfo->aTickScreenPosition + , bIsHorizontalAxis, bIsVerticalAxis ) ) + { + // This tick overlaps with its neighbor. Increment the visible + // tick intervals (if that's allowed) and start over. + + if( rAxisLabelProperties.bRhythmIsFix ) + continue; + rAxisLabelProperties.nRhythm++; + removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget ); + return false; + } + } + + bool bHasExtraColor=false; + sal_Int32 nExtraColor=0; + + OUString aLabel; + if(pCategories) + { + // This is a normal category axis. Get the label string from the + // label string array. + sal_Int32 nIndex = static_cast<sal_Int32>(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0 + if( nIndex>=0 && nIndex<pCategories->getLength() ) + aLabel = (*pCategories)[nIndex]; + } + else if( m_aAxisProperties.m_bComplexCategories ) + { + // This is a complex category axis. The label is stored in the tick. + aLabel = pTickInfo->aText; + } + else + { + // This is a numeric axis. Format the original tick value per number format. + aLabel = aFixedNumberFormatter.getFormattedString( pTickInfo->getUnscaledTickValue(), nExtraColor, bHasExtraColor ); + } + + if(pColorAny) + *pColorAny = uno::makeAny(bHasExtraColor?nExtraColor:nColor); + if(pLimitedSpaceAny) + *pLimitedSpaceAny = uno::makeAny(sal_Int32(-1*pTickInfo->nFactorForLimitedTextWidth)); + + B2DVector aTickScreenPos2D = pTickInfo->aTickScreenPosition; + aTickScreenPos2D += aTextToTickDistance; + awt::Point aAnchorScreenPosition2D( + static_cast<sal_Int32>(aTickScreenPos2D.getX()) + ,static_cast<sal_Int32>(aTickScreenPos2D.getY())); + + //create single label + if(!pTickInfo->xTextShape.is()) + pTickInfo->xTextShape = createSingleLabel( m_xShapeFactory, xTarget + , aAnchorScreenPosition2D, aLabel + , rAxisLabelProperties, m_aAxisProperties + , aPropNames, aPropValues ); + if(!pTickInfo->xTextShape.is()) + continue; + + recordMaximumTextSize( pTickInfo->xTextShape, rAxisLabelProperties.fRotationAngleDegree ); + + //if NO OVERLAP -> remove overlapping shapes + if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed ) + { + // Check if the label still overlaps with its neighber. + if( doesOverlap( pLastVisibleNeighbourTickInfo->xTextShape, pTickInfo->xTextShape, rAxisLabelProperties.fRotationAngleDegree ) ) + { + // It overlaps. + if( !rAxisLabelProperties.bOverlapAllowed && ::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) ) + { + // Try auto-rotating the labels at 45 degrees and + // start over. This rotation angle will be stored for + // all future text shape creation runs. + + rAxisLabelProperties.fRotationAngleDegree = 45; + rAxisLabelProperties.bLineBreakAllowed = false; + rAxisLabelProperties.eStaggering = SIDE_BY_SIDE; + m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree; // Store it for future runs. + removeTextShapesFromTicks(); + return false; + } + + if( rAxisLabelProperties.bRhythmIsFix ) + { + // Tick interval is fixed. We have no choice but to + // remove this label. + xTarget->remove(pTickInfo->xTextShape); + pTickInfo->xTextShape = NULL; + continue; + } + + // Try incrementing the tick interval and start over. + rAxisLabelProperties.nRhythm++; + removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget ); + return false; + } + } + + pPreviousVisibleTickInfo = pTickInfo; + } + return true; +} + drawing::PointSequenceSequence lcl_makePointSequence( B2DVector& rStart, B2DVector& rEnd ) { drawing::PointSequenceSequence aPoints(1); @@ -1377,7 +1545,7 @@ void VCartesianAxis::doStaggeringOfLabels( const AxisLabelProperties& rAxisLabel } } } - else if( rAxisLabelProperties.getIsStaggered() ) + else if (rAxisLabelProperties.isStaggered()) { if( !m_aAllTickInfos.empty() ) { diff --git a/chart2/source/view/axes/VCartesianAxis.hxx b/chart2/source/view/axes/VCartesianAxis.hxx index 3b9886d..839d5e8 100644 --- a/chart2/source/view/axes/VCartesianAxis.hxx +++ b/chart2/source/view/axes/VCartesianAxis.hxx @@ -117,12 +117,20 @@ private: //methods * have changed during the call, and the caller needs to call this * method once again to get the text shapes created. */ - bool createTextShapes( const ::com::sun::star::uno::Reference< - ::com::sun::star::drawing::XShapes >& xTarget - , TickIter& rTickIter - , AxisLabelProperties& rAxisLabelProperties - , TickFactory2D* pTickFactory - , sal_Int32 nScreenDistanceBetweenTicks ); + bool createTextShapes( + const css::uno::Reference<css::drawing::XShapes >& xTarget, + TickIter& rTickIter, AxisLabelProperties& rAxisLabelProperties, + TickFactory2D* pTickFactory, sal_Int32 nScreenDistanceBetweenTicks ); + + /** + * Variant of createTextShapes where none of auto-staggering and + * link-breaking are allowed in case of overlaps. Overlaps of text shapes + * are to be resolved only by adjusting the label tick interval. + */ + bool createTextShapesSimple( + const css::uno::Reference<css::drawing::XShapes >& xTarget, + TickIter& rTickIter, AxisLabelProperties& rAxisLabelProperties, + TickFactory2D* pTickFactory ); void createTickMarkLineShapes( TickInfoArrayType& rTickInfos, const TickmarkProperties& rTickmarkProperties, TickFactory2D& rTickFactory2D, bool bOnlyAtLabels ); commit 0bf0c8af7e22ee2745ca32d8c0291ebc687893bd Author: Kohei Yoshida <[email protected]> Date: Wed Oct 22 10:25:42 2014 -0400 These methods can be private rather than protected. Change-Id: I56f1296f5a2df67ae9386ae9f30761aee0fde7f3 diff --git a/chart2/source/view/axes/VCartesianAxis.hxx b/chart2/source/view/axes/VCartesianAxis.hxx index 8abe4eb..3b9886d 100644 --- a/chart2/source/view/axes/VCartesianAxis.hxx +++ b/chart2/source/view/axes/VCartesianAxis.hxx @@ -100,7 +100,7 @@ public: ::basegfx::B2DVector aScreenPos; }; -protected: //methods +private: //methods /** * Go through all tick label positions and decide which labels to display * based on the text shape geometry, overlap setting, tick interval, commit 15a501b6e05fb2490b69a98a4c0782f09dd326d2 Author: Kohei Yoshida <[email protected]> Date: Wed Oct 22 09:56:01 2014 -0400 More method descriptions. I'm starting to "get" this axis label layout code. Change-Id: I797a92698cb81a1b9325f81b5275cb033cb7c342 diff --git a/chart2/source/view/axes/VCartesianAxis.hxx b/chart2/source/view/axes/VCartesianAxis.hxx index 2492bb0..8abe4eb 100644 --- a/chart2/source/view/axes/VCartesianAxis.hxx +++ b/chart2/source/view/axes/VCartesianAxis.hxx @@ -131,14 +131,24 @@ protected: //methods /** * Shift the screen positions of the tick labels according to the stagger - * settings. Stagger setting is finalized during the createTextShapes + * settings. Final stagger setting is decided during the createTextShapes * call, but this method does the physical shifting of the label - * positions. + * positions based on the final stagger setting. */ void doStaggeringOfLabels( const AxisLabelProperties& rAxisLabelProperties , TickFactory2D* pTickFactory2D ); + + /** + * @return true if we can try to stagger labels in order to avoid + * overlaps, otherwise false. + */ bool isAutoStaggeringOfLabelsAllowed( const AxisLabelProperties& rAxisLabelProperties, bool bIsHorizontalAxis, bool bIsVerticalAxis ) const; + + /** + * @return true if we can break a single line label text into multiple + * lines for better fitting, otherwise false. + */ bool isBreakOfLabelsAllowed( const AxisLabelProperties& rAxisLabelProperties, bool bIsHorizontalAxis ) const; ::basegfx::B2DVector getScreenPosition( double fLogicX, double fLogicY, double fLogicZ ) const; _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
