tdf#116163: Limit label height in chart if needed

Change-Id: Ia84fd0c3b76886bc6124dc3b59035465aa31b020
Reviewed-on: https://gerrit.libreoffice.org/50700
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Szymon Kłos <szymon.klos@collabora.com>
diff --git a/chart2/qa/extras/chart2export.cxx b/chart2/qa/extras/chart2export.cxx
index 9f5efb1..d0ab36e 100644
--- a/chart2/qa/extras/chart2export.cxx
+++ b/chart2/qa/extras/chart2export.cxx
@@ -107,6 +107,7 @@ public:
    void testCustomDataLabel();
    void testCustomDataLabelMultipleSeries();
    void testNumberFormatExportPPTX();
    void testTdf116163();

    CPPUNIT_TEST_SUITE(Chart2ExportTest);
    CPPUNIT_TEST(testErrorBarXLSX);
@@ -176,6 +177,7 @@ public:
    CPPUNIT_TEST(testCustomDataLabel);
    CPPUNIT_TEST(testCustomDataLabelMultipleSeries);
    CPPUNIT_TEST(testNumberFormatExportPPTX);
    CPPUNIT_TEST(testTdf116163);
    CPPUNIT_TEST_SUITE_END();

protected:
@@ -1743,6 +1745,15 @@ void Chart2ExportTest::testNumberFormatExportPPTX()
    assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:barChart/c:ser/c:dLbls/c:numFmt", "sourceLinked", "0");
}

void Chart2ExportTest::testTdf116163()
{
    load("/chart2/qa/extras/data/pptx/", "tdf116163.pptx");
    xmlDocPtr pXmlDoc = parseExport("ppt/charts/chart", "Impress MS PowerPoint 2007 XML");
    CPPUNIT_ASSERT(pXmlDoc);

    assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:catAx/c:txPr/a:bodyPr", "rot", "-5400000");
}

CPPUNIT_TEST_SUITE_REGISTRATION(Chart2ExportTest);

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/chart2/qa/extras/data/pptx/tdf116163.pptx b/chart2/qa/extras/data/pptx/tdf116163.pptx
new file mode 100644
index 0000000..5fbee83
--- /dev/null
+++ b/chart2/qa/extras/data/pptx/tdf116163.pptx
Binary files differ
diff --git a/chart2/source/view/axes/VAxisProperties.hxx b/chart2/source/view/axes/VAxisProperties.hxx
index 20f648d..9a10c94 100644
--- a/chart2/source/view/axes/VAxisProperties.hxx
+++ b/chart2/source/view/axes/VAxisProperties.hxx
@@ -137,6 +137,8 @@ struct AxisProperties final
    css::uno::Reference<css::chart2::data::XTextualDataSequence> m_xAxisTextProvider; //for categories or series names
    //<- category axes

    bool                                m_bLimitSpaceForLabels;

    //methods:

    AxisProperties( const css::uno::Reference< css::chart2::XAxis >& xAxisModel
diff --git a/chart2/source/view/axes/VCartesianAxis.cxx b/chart2/source/view/axes/VCartesianAxis.cxx
index 9dab35c..dd5593c 100644
--- a/chart2/source/view/axes/VCartesianAxis.cxx
+++ b/chart2/source/view/axes/VCartesianAxis.cxx
@@ -74,6 +74,53 @@ VCartesianAxis::~VCartesianAxis()
    m_pPosHelper = nullptr;
}

void lcl_ResizeTextShapeToFitAvailableSpace( Reference< drawing::XShape >& xShape2DText,
                                             const AxisLabelProperties& rAxisLabelProperties,
                                             const OUString& rLabel,
                                             const tNameSequence& rPropNames,
                                             const tAnySequence& rPropValues )
{
    uno::Reference< text::XTextRange > xTextRange( xShape2DText, uno::UNO_QUERY );

    if( !xTextRange.is() )
        return;

    const sal_Int32 nFullHeight = rAxisLabelProperties.m_aFontReferenceSize.Height;

    if( !nFullHeight || !rLabel.getLength() )
        return;

    sal_Int32 nMaxLabelsHeight = nFullHeight - rAxisLabelProperties.m_aMaximumSpaceForLabels.Height - rAxisLabelProperties.m_aMaximumSpaceForLabels.Y;
    const sal_Int32 nAvgCharWidth = xShape2DText->getSize().Width / rLabel.getLength();
    const sal_Int32 nTextSize = AbstractShapeFactory::getSizeAfterRotation( xShape2DText,
                                            rAxisLabelProperties.fRotationAngleDegree ).Height;

    if( !nAvgCharWidth )
        return;

    const OUString sDots = "...";
    const sal_Int32 nCharsToRemove = ( nTextSize - nMaxLabelsHeight ) / nAvgCharWidth + 1;
    sal_Int32 nNewLen = rLabel.getLength() - nCharsToRemove - sDots.getLength();
    // Prevent from showing only dots
    if (nNewLen < 0)
        nNewLen = ( rLabel.getLength() >= sDots.getLength() ) ? sDots.getLength() : rLabel.getLength();

    bool bCrop = nCharsToRemove > 0;
    if( bCrop )
    {
        OUString aNewLabel = rLabel.copy( 0, nNewLen );
        if( nNewLen > sDots.getLength() )
            aNewLabel += sDots;
        xTextRange->setString( aNewLabel );

        uno::Reference< beans::XPropertySet > xProp( xTextRange, uno::UNO_QUERY );
        if( xProp.is() )
        {
            PropertyMapper::setMultiProperties( rPropNames, rPropValues, xProp );
        }
    }
}

Reference< drawing::XShape > createSingleLabel(
            const Reference< lang::XMultiServiceFactory>& xShapeFactory
          , const Reference< drawing::XShapes >& xTarget
@@ -96,6 +143,9 @@ Reference< drawing::XShape > createSingleLabel(
    Reference< drawing::XShape > xShape2DText = AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)
                    ->createText( xTarget, aLabel, rPropNames, rPropValues, aATransformation );

    if( rAxisProperties.m_bLimitSpaceForLabels )
        lcl_ResizeTextShapeToFitAvailableSpace(xShape2DText, rAxisLabelProperties, aLabel, rPropNames, rPropValues);

    LabelPositionHelper::correctPositionForRotation( xShape2DText
        , rAxisProperties.maLabelAlignment.meAlignment, rAxisLabelProperties.fRotationAngleDegree, rAxisProperties.m_bComplexCategories );

diff --git a/chart2/source/view/axes/VCartesianCoordinateSystem.cxx b/chart2/source/view/axes/VCartesianCoordinateSystem.cxx
index dbfbe9c..f60a38c 100644
--- a/chart2/source/view/axes/VCartesianCoordinateSystem.cxx
+++ b/chart2/source/view/axes/VCartesianCoordinateSystem.cxx
@@ -93,6 +93,7 @@ void VCartesianCoordinateSystem::createVAxisList(
              const uno::Reference<chart2::XChartDocument> & xChartDoc
            , const awt::Size& rFontReferenceSize
            , const awt::Rectangle& rMaximumSpaceForLabels
            , bool bLimitSpaceForLabels
            )
{
    // note: using xChartDoc itself as XNumberFormatsSupplier would cause
@@ -125,6 +126,7 @@ void VCartesianCoordinateSystem::createVAxisList(
            aAxisProperties.m_nDimensionIndex = nDimensionIndex;
            aAxisProperties.m_bSwapXAndY = bSwapXAndY;
            aAxisProperties.m_bIsMainAxis = (nAxisIndex==0);
            aAxisProperties.m_bLimitSpaceForLabels = bLimitSpaceForLabels;
            Reference< XAxis > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, m_xCooSysModel ) );
            if( xCrossingMainAxis.is() )
            {
diff --git a/chart2/source/view/axes/VCartesianCoordinateSystem.hxx b/chart2/source/view/axes/VCartesianCoordinateSystem.hxx
index c61768f..e959dbc 100644
--- a/chart2/source/view/axes/VCartesianCoordinateSystem.hxx
+++ b/chart2/source/view/axes/VCartesianCoordinateSystem.hxx
@@ -34,7 +34,8 @@ public:
    virtual void createVAxisList(
            const css::uno::Reference< css::chart2::XChartDocument> &ChartDoc
            , const css::awt::Size& rFontReferenceSize
            , const css::awt::Rectangle& rMaximumSpaceForLabels ) override;
            , const css::awt::Rectangle& rMaximumSpaceForLabels
            , bool bLimitSpaceForLabels ) override;

    virtual void initVAxisInList() override;
    virtual void updateScalesAndIncrementsOnAxes() override;
diff --git a/chart2/source/view/axes/VCoordinateSystem.cxx b/chart2/source/view/axes/VCoordinateSystem.cxx
index 0f103c5..063697c 100644
--- a/chart2/source/view/axes/VCoordinateSystem.cxx
+++ b/chart2/source/view/axes/VCoordinateSystem.cxx
@@ -339,6 +339,7 @@ void VCoordinateSystem::createVAxisList(
              const uno::Reference<chart2::XChartDocument> & /* xChartDoc */
            , const awt::Size& /* rFontReferenceSize */
            , const awt::Rectangle& /* rMaximumSpaceForLabels */
            , bool /* bLimitSpaceForLabels */
            )
{
}
diff --git a/chart2/source/view/axes/VPolarCoordinateSystem.cxx b/chart2/source/view/axes/VPolarCoordinateSystem.cxx
index 823e591..cc6b3cb2 100644
--- a/chart2/source/view/axes/VPolarCoordinateSystem.cxx
+++ b/chart2/source/view/axes/VPolarCoordinateSystem.cxx
@@ -65,6 +65,7 @@ void VPolarCoordinateSystem::createVAxisList(
              const uno::Reference<chart2::XChartDocument> & xChartDoc
            , const awt::Size& rFontReferenceSize
            , const awt::Rectangle& rMaximumSpaceForLabels
            , bool //bLimitSpaceForLabels
            )
{
    // note: using xChartDoc itself as XNumberFormatsSupplier would cause
diff --git a/chart2/source/view/axes/VPolarCoordinateSystem.hxx b/chart2/source/view/axes/VPolarCoordinateSystem.hxx
index e7941484..4976672 100644
--- a/chart2/source/view/axes/VPolarCoordinateSystem.hxx
+++ b/chart2/source/view/axes/VPolarCoordinateSystem.hxx
@@ -38,7 +38,8 @@ public:
    virtual void createVAxisList(
            const css::uno::Reference< css::chart2::XChartDocument> & xChartDoc
            , const css::awt::Size& rFontReferenceSize
            , const css::awt::Rectangle& rMaximumSpaceForLabels ) override;
            , const css::awt::Rectangle& rMaximumSpaceForLabels
            , bool bLimitSpaceForLabels ) override;

    virtual void initVAxisInList() override;
    virtual void updateScalesAndIncrementsOnAxes() override;
diff --git a/chart2/source/view/inc/VCoordinateSystem.hxx b/chart2/source/view/inc/VCoordinateSystem.hxx
index 6b115d3..7a4a711 100644
--- a/chart2/source/view/inc/VCoordinateSystem.hxx
+++ b/chart2/source/view/inc/VCoordinateSystem.hxx
@@ -111,7 +111,8 @@ public:
    virtual void createVAxisList(
            const css::uno::Reference< css::chart2::XChartDocument> & xChartDoc
            , const css::awt::Size& rFontReferenceSize
            , const css::awt::Rectangle& rMaximumSpaceForLabels );
            , const css::awt::Rectangle& rMaximumSpaceForLabels
            , bool bLimitSpaceForLabels );

    virtual void initVAxisInList();
    virtual void updateScalesAndIncrementsOnAxes();
diff --git a/chart2/source/view/main/ChartView.cxx b/chart2/source/view/main/ChartView.cxx
index e0cd2c6..a743c60a 100644
--- a/chart2/source/view/main/ChartView.cxx
+++ b/chart2/source/view/main/ChartView.cxx
@@ -1587,7 +1587,7 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D
            pVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos );
        }

        pVCooSys->createVAxisList(xChartDoc, rPageSize, rParam.maRemainingSpace);
        pVCooSys->createVAxisList(xChartDoc, rPageSize, rParam.maRemainingSpace, rParam.mbUseFixedInnerSize);
    }

    // - prepare list of all axis and how they are used
diff --git a/include/oox/export/chartexport.hxx b/include/oox/export/chartexport.hxx
index 0c59b1b..04ef384 100644
--- a/include/oox/export/chartexport.hxx
+++ b/include/oox/export/chartexport.hxx
@@ -175,7 +175,7 @@ private:
    void exportSeriesValues(
        const css::uno::Reference< css::chart2::data::XDataSequence >& xValueSeq, sal_Int32 nValueType = XML_val );
    void exportShapeProps( const css::uno::Reference< css::beans::XPropertySet >& xPropSet );
    void exportTextProps(const css::uno::Reference< css::beans::XPropertySet >& xPropSet);
    void exportTextProps(const css::uno::Reference< css::beans::XPropertySet >& xPropSet, bool bAxis = false);
    void exportDataPoints(
        const css::uno::Reference< css::beans::XPropertySet >& xSeriesProperties,
        sal_Int32 nSeriesLength, sal_Int32 eChartType );
diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx
index 81ed22c..424d479 100644
--- a/oox/source/export/chartexport.cxx
+++ b/oox/source/export/chartexport.cxx
@@ -2325,11 +2325,25 @@ void ChartExport::exportShapeProps( const Reference< XPropertySet >& xPropSet )
    pFS->endElement( FSNS( XML_c, XML_spPr ) );
}

void ChartExport::exportTextProps(const Reference<XPropertySet>& xPropSet)
void ChartExport::exportTextProps(const Reference<XPropertySet>& xPropSet, bool bAxis)
{
    FSHelperPtr pFS = GetFS();
    pFS->startElement(FSNS(XML_c, XML_txPr), FSEND);
    pFS->singleElement( FSNS( XML_a, XML_bodyPr ), FSEND );

    sal_Int32 nRotation = 0;
    if (bAxis)
    {
        double fTextRotation = 0;
        uno::Any aAny = xPropSet->getPropertyValue("TextRotation");
        if (aAny.hasValue() && (aAny >>= fTextRotation))
            nRotation = fTextRotation * -600.0;
    }

    if (nRotation)
        pFS->singleElement(FSNS(XML_a, XML_bodyPr), XML_rot, I32S(nRotation), FSEND);
    else
        pFS->singleElement(FSNS(XML_a, XML_bodyPr), FSEND);

    pFS->singleElement( FSNS( XML_a, XML_lstStyle ), FSEND );

    pFS->startElement(FSNS(XML_a, XML_p), FSEND);
@@ -2736,7 +2750,7 @@ void ChartExport::_exportAxis(
    // shape properties
    exportShapeProps( xAxisProp );

    exportTextProps(xAxisProp);
    exportTextProps(xAxisProp, true);

    pFS->singleElement( FSNS( XML_c, XML_crossAx ),
            XML_val, I32S( rAxisIdPair.nCrossAx ),