[Libreoffice-commits] core.git: chart2/qa chart2/source compilerplugins/clang offapi/com oox/source sd/qa

Balazs Varga (via logerrit) logerrit at kemper.freedesktop.org
Thu Jan 30 09:44:02 UTC 2020


 chart2/qa/extras/chart2import.cxx                                  |   24 ++++++
 chart2/qa/extras/data/xlsx/testDataPointLabelCustomPos.xlsx        |binary
 chart2/source/controller/chartapiwrapper/LegendWrapper.cxx         |    2 
 chart2/source/controller/inc/PositionAndSizeHelper.hxx             |    2 
 chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx |   13 ++-
 chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx |   11 ++
 chart2/source/controller/main/ChartController_Position.cxx         |    2 
 chart2/source/controller/main/ChartController_Window.cxx           |    2 
 chart2/source/controller/main/PositionAndSizeHelper.cxx            |   30 +++++++
 chart2/source/model/main/DataPointProperties.cxx                   |    7 +
 chart2/source/model/main/DataPointProperties.hxx                   |    3 
 chart2/source/tools/DataSeriesHelper.cxx                           |    2 
 chart2/source/tools/ObjectIdentifier.cxx                           |    1 
 chart2/source/view/charttypes/VSeriesPlotter.cxx                   |   10 ++
 chart2/source/view/inc/VDataSeries.hxx                             |    4 +
 chart2/source/view/main/VDataSeries.cxx                            |   40 +++++++++-
 compilerplugins/clang/unusedenumconstants.writeonly.results        |    2 
 offapi/com/sun/star/chart/DataLabelPlacement.idl                   |    1 
 offapi/com/sun/star/chart2/DataPointProperties.idl                 |    7 +
 oox/source/drawingml/chart/seriesconverter.cxx                     |   31 +++++--
 oox/source/token/properties.txt                                    |    1 
 sd/qa/unit/import-tests.cxx                                        |    7 +
 22 files changed, 177 insertions(+), 25 deletions(-)

New commits:
commit 4223ff2be69f03e571464b0b09ad0d278918631b
Author:     Balazs Varga <balazs.varga991 at gmail.com>
AuthorDate: Wed Jan 15 16:31:35 2020 +0100
Commit:     László Németh <nemeth at numbertext.org>
CommitDate: Thu Jan 30 10:43:02 2020 +0100

    tdf#48436 Chart: add CustomLabelPosition UNO API property
    
    and CUSTOM DataLabelPlacement to support custom data label positions,
    and its initial implementation: only UI support with OOXML import
    (tdf#130030), yet.
    
    Change-Id: I01d986071d78ae3e2a5f43d5711e9f60b8410c21
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86859
    Tested-by: Jenkins
    Reviewed-by: László Németh <nemeth at numbertext.org>
    Tested-by: László Németh <nemeth at numbertext.org>

diff --git a/chart2/qa/extras/chart2import.cxx b/chart2/qa/extras/chart2import.cxx
index 223ca95b2b32..47b2e0354d51 100644
--- a/chart2/qa/extras/chart2import.cxx
+++ b/chart2/qa/extras/chart2import.cxx
@@ -12,6 +12,7 @@
 #include <com/sun/star/chart2/DataPointLabel.hpp>
 #include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
 #include <com/sun/star/chart2/DataPointCustomLabelFieldType.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
 #include <com/sun/star/chart/ErrorBarStyle.hpp>
 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
 #include <com/sun/star/chart2/XChartDocument.hpp>
@@ -151,6 +152,7 @@ public:
     void testTdf122765();
     void testTdf123206CustomLabelField();
     void testTdf125444PercentageCustomLabel();
+    void testDataPointLabelCustomPos();
 
     CPPUNIT_TEST_SUITE(Chart2ImportTest);
     CPPUNIT_TEST(Fdo60083);
@@ -251,6 +253,7 @@ public:
     CPPUNIT_TEST(testTdf122765);
     CPPUNIT_TEST(testTdf123206CustomLabelField);
     CPPUNIT_TEST(testTdf125444PercentageCustomLabel);
+    CPPUNIT_TEST(testDataPointLabelCustomPos);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -2348,6 +2351,27 @@ void Chart2ImportTest::testTdf125444PercentageCustomLabel()
     CPPUNIT_ASSERT_EQUAL(chart2::DataPointCustomLabelFieldType_PERCENTAGE, aLabelFields[2]->getFieldType());
 }
 
+void Chart2ImportTest::testDataPointLabelCustomPos()
+{
+    load("/chart2/qa/extras/data/xlsx/", "testDataPointLabelCustomPos.xlsx");
+    uno::Reference< chart2::XChartDocument > xChartDoc = getChartDocFromSheet(0, mxComponent);
+    CPPUNIT_ASSERT(xChartDoc.is());
+    uno::Reference<chart2::XDataSeries> xDataSeries(getDataSeriesFromDoc(xChartDoc, 0));
+    CPPUNIT_ASSERT(xDataSeries.is());
+
+    uno::Reference<beans::XPropertySet> xPropertySet(xDataSeries->getDataPointByIndex(0), uno::UNO_SET_THROW);
+    CPPUNIT_ASSERT(xPropertySet.is());
+
+    chart2::RelativePosition aCustomLabelPosition;
+    xPropertySet->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition;
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(aCustomLabelPosition.Primary, -0.14621409921671025, 1e-7);
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(aCustomLabelPosition.Secondary, -5.2887961029923464E-2, 1e-7);
+
+    sal_Int32 aPlacement;
+    xPropertySet->getPropertyValue("LabelPlacement") >>= aPlacement;
+    CPPUNIT_ASSERT_EQUAL(chart::DataLabelPlacement::OUTSIDE, aPlacement);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(Chart2ImportTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/chart2/qa/extras/data/xlsx/testDataPointLabelCustomPos.xlsx b/chart2/qa/extras/data/xlsx/testDataPointLabelCustomPos.xlsx
new file mode 100644
index 000000000000..69f89ec0e4c2
Binary files /dev/null and b/chart2/qa/extras/data/xlsx/testDataPointLabelCustomPos.xlsx differ
diff --git a/chart2/source/controller/chartapiwrapper/LegendWrapper.cxx b/chart2/source/controller/chartapiwrapper/LegendWrapper.cxx
index e4059c6d4b74..4dce225ba570 100644
--- a/chart2/source/controller/chartapiwrapper/LegendWrapper.cxx
+++ b/chart2/source/controller/chartapiwrapper/LegendWrapper.cxx
@@ -309,7 +309,7 @@ void SAL_CALL LegendWrapper::setSize( const awt::Size& aSize )
         awt::Rectangle aNewPositionAndSize(aPos.X,aPos.Y,aSize.Width,aSize.Height);
 
         PositionAndSizeHelper::moveObject( OBJECTTYPE_LEGEND
-                , xProp, aNewPositionAndSize, aPageRectangle );
+                , xProp, aNewPositionAndSize, awt::Rectangle(), aPageRectangle );
     }
 }
 
diff --git a/chart2/source/controller/inc/PositionAndSizeHelper.hxx b/chart2/source/controller/inc/PositionAndSizeHelper.hxx
index f65b333c3407..964eebfb03cc 100644
--- a/chart2/source/controller/inc/PositionAndSizeHelper.hxx
+++ b/chart2/source/controller/inc/PositionAndSizeHelper.hxx
@@ -34,11 +34,13 @@ public:
     static bool moveObject( ObjectType eObjectType
             , const css::uno::Reference< css::beans::XPropertySet >& xObjectProp
             , const css::awt::Rectangle& rNewPositionAndSize
+            , const css::awt::Rectangle& rOldPositionAndSize
             , const css::awt::Rectangle& rPageRectangle );
 
     static bool moveObject( const OUString& rObjectCID
             , const css::uno::Reference< css::frame::XModel >& xChartModel
             , const css::awt::Rectangle& rNewPositionAndSize
+            , const css::awt::Rectangle& rOldPositionAndSize
             , const css::awt::Rectangle& rPageRectangle );
 };
 
diff --git a/chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx b/chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx
index 43721c24502a..aab6be665814 100644
--- a/chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx
+++ b/chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx
@@ -31,9 +31,11 @@
 #include <ChartTypeHelper.hxx>
 #include <unonames.hxx>
 
+#include <com/sun/star/chart/DataLabelPlacement.hpp>
 #include <com/sun/star/chart2/AxisType.hpp>
 #include <com/sun/star/chart2/DataPointLabel.hpp>
 #include <com/sun/star/chart2/Symbol.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
 
 #include <svx/xflclit.hxx>
@@ -409,6 +411,7 @@ bool DataPointItemConverter::ApplySpecialItem(
             {
                 sal_Int32 nNew = static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue();
                 sal_Int32 nOld =0;
+                RelativePosition aCustomLabelPosition;
                 if( !(GetPropertySet()->getPropertyValue( "LabelPlacement" ) >>= nOld) )
                 {
                     if( m_aAvailableLabelPlacements.hasElements() )
@@ -424,9 +427,10 @@ bool DataPointItemConverter::ApplySpecialItem(
                         bChanged = true;
                     }
                 }
-                else if( nOld!=nNew )
+                else if( nOld!=nNew || (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition) )
                 {
-                    GetPropertySet()->setPropertyValue( "LabelPlacement" , uno::Any( nNew ));
+                    GetPropertySet()->setPropertyValue("LabelPlacement", uno::Any(nNew));
+                    GetPropertySet()->setPropertyValue("CustomLabelPosition", uno::Any());
                     bChanged = true;
                 }
             }
@@ -641,7 +645,10 @@ void DataPointItemConverter::FillSpecialItem(
             try
             {
                 sal_Int32 nPlacement=0;
-                if( GetPropertySet()->getPropertyValue( "LabelPlacement" ) >>= nPlacement )
+                RelativePosition aCustomLabelPosition;
+                if( !m_bOverwriteLabelsForAttributedDataPointsAlso && (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition) )
+                    rOutItemSet.Put(SfxInt32Item(nWhichId, css::chart::DataLabelPlacement::CUSTOM));
+                else if( GetPropertySet()->getPropertyValue( "LabelPlacement" ) >>= nPlacement )
                     rOutItemSet.Put( SfxInt32Item( nWhichId, nPlacement ));
                 else if( m_aAvailableLabelPlacements.hasElements() )
                     rOutItemSet.Put( SfxInt32Item( nWhichId, m_aAvailableLabelPlacements[0] ));
diff --git a/chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx b/chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx
index 70dc31a46b92..f5c9d8a0ce4d 100644
--- a/chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx
+++ b/chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx
@@ -37,9 +37,11 @@
 #include <tools/diagnose_ex.h>
 #include <vcl/graph.hxx>
 
+#include <com/sun/star/chart/DataLabelPlacement.hpp>
 #include <com/sun/star/chart2/AxisType.hpp>
 #include <com/sun/star/chart2/DataPointLabel.hpp>
 #include <com/sun/star/chart2/Symbol.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
 #include <memory>
 
 using namespace com::sun::star;
@@ -370,6 +372,7 @@ bool TextLabelItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxIte
             {
                 sal_Int32 nNew = static_cast<const SfxInt32Item&>(rItemSet.Get(nWhichId)).GetValue();
                 sal_Int32 nOld = 0;
+                RelativePosition aCustomLabelPosition;
                 if (!(GetPropertySet()->getPropertyValue("LabelPlacement") >>= nOld))
                 {
                     if (maAvailableLabelPlacements.hasElements())
@@ -385,9 +388,10 @@ bool TextLabelItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxIte
                         bChanged = true;
                     }
                 }
-                else if (nOld != nNew)
+                else if (nOld != nNew || (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition))
                 {
                     GetPropertySet()->setPropertyValue("LabelPlacement", uno::Any(nNew));
+                    GetPropertySet()->setPropertyValue("CustomLabelPosition", uno::Any());
                     bChanged = true;
                 }
             }
@@ -591,7 +595,10 @@ void TextLabelItemConverter::FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet& r
             try
             {
                 sal_Int32 nPlacement = 0;
-                if (GetPropertySet()->getPropertyValue("LabelPlacement") >>= nPlacement)
+                RelativePosition aCustomLabelPosition;
+                if (!mbDataSeries && (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition))
+                    rOutItemSet.Put(SfxInt32Item(nWhichId, css::chart::DataLabelPlacement::CUSTOM));
+                else if (GetPropertySet()->getPropertyValue("LabelPlacement") >>= nPlacement)
                     rOutItemSet.Put(SfxInt32Item(nWhichId, nPlacement));
                 else if (maAvailableLabelPlacements.hasElements())
                     rOutItemSet.Put(SfxInt32Item(nWhichId, maAvailableLabelPlacements[0]));
diff --git a/chart2/source/controller/main/ChartController_Position.cxx b/chart2/source/controller/main/ChartController_Position.cxx
index 184c37e108ed..32c4bd78522e 100644
--- a/chart2/source/controller/main/ChartController_Position.cxx
+++ b/chart2/source/controller/main/ChartController_Position.cxx
@@ -194,7 +194,7 @@ void ChartController::executeDispatch_PositionAndSize(const ::css::uno::Sequence
             }
 
             bool bMoved = PositionAndSizeHelper::moveObject( m_aSelection.getSelectedCID(), getModel()
-                        , aObjectRect, aPageRect );
+                        , aObjectRect, awt::Rectangle(), aPageRect );
             if( bMoved || bChanged )
                 aUndoGuard.commit();
         }
diff --git a/chart2/source/controller/main/ChartController_Window.cxx b/chart2/source/controller/main/ChartController_Window.cxx
index 9266e61005c7..c7b753dda1dc 100644
--- a/chart2/source/controller/main/ChartController_Window.cxx
+++ b/chart2/source/controller/main/ChartController_Window.cxx
@@ -836,6 +836,7 @@ void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt )
                     if( pObj )
                     {
                         tools::Rectangle aObjectRect = pObj->GetSnapRect();
+                        tools::Rectangle aOldObjectRect = pObj->GetLastBoundRect();
                         awt::Size aPageSize( ChartModelHelper::getPageSize( getModel() ) );
                         tools::Rectangle aPageRect( 0,0,aPageSize.Width,aPageSize.Height );
 
@@ -868,6 +869,7 @@ void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt )
                         bool bMoved = PositionAndSizeHelper::moveObject( m_aSelection.getSelectedCID()
                                         , getModel()
                                         , awt::Rectangle(aObjectRect.getX(),aObjectRect.getY(),aObjectRect.getWidth(),aObjectRect.getHeight())
+                                        , awt::Rectangle(aOldObjectRect.getX(), aOldObjectRect.getY(), 0, 0)
                                         , awt::Rectangle(aPageRect.getX(),aPageRect.getY(),aPageRect.getWidth(),aPageRect.getHeight()) );
 
                         if( bMoved || bChanged )
diff --git a/chart2/source/controller/main/PositionAndSizeHelper.cxx b/chart2/source/controller/main/PositionAndSizeHelper.cxx
index d9100c839a14..c1e0e14441bd 100644
--- a/chart2/source/controller/main/PositionAndSizeHelper.cxx
+++ b/chart2/source/controller/main/PositionAndSizeHelper.cxx
@@ -36,6 +36,7 @@ using namespace ::com::sun::star::chart2;
 bool PositionAndSizeHelper::moveObject( ObjectType eObjectType
                 , const uno::Reference< beans::XPropertySet >& xObjectProp
                 , const awt::Rectangle& rNewPositionAndSize
+                , const awt::Rectangle& rOldPositionAndSize
                 , const awt::Rectangle& rPageRectangle
                 )
 {
@@ -59,6 +60,32 @@ bool PositionAndSizeHelper::moveObject( ObjectType eObjectType
         aRelativePosition.Secondary = (double(aPos.Y())+double(aObjectRect.getHeight())/2.0)/double(aPageRect.getHeight());
         xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) );
     }
+    else if( eObjectType == OBJECTTYPE_DATA_LABEL )
+    {
+        RelativePosition aAbsolutePosition;
+        RelativePosition aCustomLabelPosition;
+        aAbsolutePosition.Primary = double(rOldPositionAndSize.X) / double(aPageRect.getWidth());
+        aAbsolutePosition.Secondary = double(rOldPositionAndSize.Y) / double(aPageRect.getHeight());
+
+        if( xObjectProp->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition )
+        {
+            aAbsolutePosition.Primary -= aCustomLabelPosition.Primary;
+            aAbsolutePosition.Secondary -= aCustomLabelPosition.Secondary;
+        }
+
+        //the anchor point at the data label object is top/left
+        Point aPos = aObjectRect.TopLeft();
+        double fRotation = 0.0;
+        xObjectProp->getPropertyValue("TextRotation") >>= fRotation;
+        if( fRotation == 90.0 )
+            aPos = aObjectRect.BottomLeft();
+        else if( fRotation == 270.0 )
+            aPos = aObjectRect.TopRight();
+
+        aCustomLabelPosition.Primary = double(aPos.X()) / double(aPageRect.getWidth()) - aAbsolutePosition.Primary;
+        aCustomLabelPosition.Secondary = double(aPos.Y()) / double(aPageRect.getHeight()) - aAbsolutePosition.Secondary;
+        xObjectProp->setPropertyValue("CustomLabelPosition", uno::Any(aCustomLabelPosition));
+    }
     else if( eObjectType==OBJECTTYPE_DATA_CURVE_EQUATION )
     {
         //@todo decide whether x is primary or secondary
@@ -128,6 +155,7 @@ bool PositionAndSizeHelper::moveObject( ObjectType eObjectType
 bool PositionAndSizeHelper::moveObject( const OUString& rObjectCID
                 , const uno::Reference< frame::XModel >& xChartModel
                 , const awt::Rectangle& rNewPositionAndSize
+                , const awt::Rectangle& rOldPositionAndSize
                 , const awt::Rectangle& rPageRectangle
                 )
 {
@@ -143,7 +171,7 @@ bool PositionAndSizeHelper::moveObject( const OUString& rObjectCID
         if(!xObjectProp.is())
             return false;
     }
-    return moveObject( eObjectType, xObjectProp, aNewPositionAndSize, rPageRectangle );
+    return moveObject( eObjectType, xObjectProp, aNewPositionAndSize, rOldPositionAndSize, rPageRectangle );
 }
 
 } //namespace chart
diff --git a/chart2/source/model/main/DataPointProperties.cxx b/chart2/source/model/main/DataPointProperties.cxx
index 1cb709d0559c..114fb4355069 100644
--- a/chart2/source/model/main/DataPointProperties.cxx
+++ b/chart2/source/model/main/DataPointProperties.cxx
@@ -28,6 +28,7 @@
 #include <com/sun/star/drawing/LineDash.hpp>
 #include <com/sun/star/drawing/BitmapMode.hpp>
 #include <com/sun/star/drawing/RectanglePoint.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
 #include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
 #include <com/sun/star/chart2/DataPointLabel.hpp>
@@ -410,6 +411,12 @@ void DataPointProperties::AddPropertiesToVector(
                   cppu::UnoType<uno::Sequence<uno::Reference<chart2::XDataPointCustomLabelField>>>::get(),
                   beans::PropertyAttribute::BOUND
                   | beans::PropertyAttribute::MAYBEDEFAULT);
+
+    rOutProperties.emplace_back( "CustomLabelPosition",
+                  PROP_DATAPOINT_LABEL_CUSTOM_POS,
+                  cppu::UnoType<chart2::RelativePosition>::get(),
+                  beans::PropertyAttribute::BOUND
+                  | beans::PropertyAttribute::MAYBEVOID );
 }
 
 void DataPointProperties::AddDefaultsToMap(
diff --git a/chart2/source/model/main/DataPointProperties.hxx b/chart2/source/model/main/DataPointProperties.hxx
index 51f1d81a71b7..d591f13625f3 100644
--- a/chart2/source/model/main/DataPointProperties.hxx
+++ b/chart2/source/model/main/DataPointProperties.hxx
@@ -82,7 +82,8 @@ namespace DataPointProperties
         PROP_DATAPOINT_LABEL_BORDER_DASH,
         PROP_DATAPOINT_LABEL_BORDER_DASH_NAME,
         PROP_DATAPOINT_LABEL_BORDER_TRANS,
-        PROP_DATAPOINT_CUSTOM_LABEL_FIELDS
+        PROP_DATAPOINT_CUSTOM_LABEL_FIELDS,
+        PROP_DATAPOINT_LABEL_CUSTOM_POS
 
         // additionally some properties from ::chart::LineProperties
     };
diff --git a/chart2/source/tools/DataSeriesHelper.cxx b/chart2/source/tools/DataSeriesHelper.cxx
index 4b4c954b5e0e..d2b0b27e04fb 100644
--- a/chart2/source/tools/DataSeriesHelper.cxx
+++ b/chart2/source/tools/DataSeriesHelper.cxx
@@ -600,6 +600,8 @@ void setPropertyAlsoToAllAttributedDataPoints( const Reference< chart2::XDataSer
             if(!xPointProp.is())
                 continue;
             xPointProp->setPropertyValue( rPropertyName, rPropertyValue );
+            if( rPropertyName == "LabelPlacement" )
+                xPointProp->setPropertyValue("CustomLabelPosition", uno::Any());
         }
     }
 }
diff --git a/chart2/source/tools/ObjectIdentifier.cxx b/chart2/source/tools/ObjectIdentifier.cxx
index 7b47967f1f9a..3c2c45a19e74 100644
--- a/chart2/source/tools/ObjectIdentifier.cxx
+++ b/chart2/source/tools/ObjectIdentifier.cxx
@@ -796,6 +796,7 @@ bool ObjectIdentifier::isDragableObject( const OUString& rClassifiedIdentifier )
         case OBJECTTYPE_TITLE:
         case OBJECTTYPE_LEGEND:
         case OBJECTTYPE_DIAGRAM:
+        case OBJECTTYPE_DATA_LABEL:
         case OBJECTTYPE_DATA_CURVE_EQUATION:
         //case OBJECTTYPE_DIAGRAM_WALL:
             bReturn = true;
diff --git a/chart2/source/view/charttypes/VSeriesPlotter.cxx b/chart2/source/view/charttypes/VSeriesPlotter.cxx
index f7e828425246..b6382943b418 100644
--- a/chart2/source/view/charttypes/VSeriesPlotter.cxx
+++ b/chart2/source/view/charttypes/VSeriesPlotter.cxx
@@ -707,7 +707,6 @@ uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Re
 
         // in case text is rotated, the transformation property of the text
         // shape is modified.
-        const awt::Point aUnrotatedTextPos( xTextShape->getPosition() );
         if( fRotationDegrees != 0.0 )
         {
             const double fDegreesPi( -basegfx::deg2rad(fRotationDegrees) );
@@ -717,8 +716,17 @@ uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Re
             LabelPositionHelper::correctPositionForRotation( xTextShape, eAlignment, fRotationDegrees, true /*bRotateAroundCenter*/ );
         }
 
+        awt::Point aTextShapePos(xTextShape->getPosition());
+        if( rDataSeries.isLabelCustomPos(nPointIndex) )
+        {
+            awt::Point aRelPos = rDataSeries.getLabelPosition(aTextShapePos, nPointIndex);
+            if( aRelPos.X != -1 )
+                xTextShape->setPosition(aRelPos);
+        }
+
         // in case legend symbol has to be displayed, text shape position is
         // slightly changed.
+        const awt::Point aUnrotatedTextPos(xTextShape->getPosition());
         if( xSymbol.is() )
         {
             const awt::Point aOldTextPos( xTextShape->getPosition() );
diff --git a/chart2/source/view/inc/VDataSeries.hxx b/chart2/source/view/inc/VDataSeries.hxx
index b65ea66f1009..853b6757077b 100644
--- a/chart2/source/view/inc/VDataSeries.hxx
+++ b/chart2/source/view/inc/VDataSeries.hxx
@@ -24,6 +24,7 @@
 #include <com/sun/star/chart2/StackingDirection.hpp>
 #include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
 #include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/awt/Point.hpp>
 
 #include <memory>
 #include <map>
@@ -107,6 +108,9 @@ public:
         sal_Int32 nPointIndex, const css::uno::Reference<css::chart2::XChartType>& xChartType,
         bool bSwapXAndY ) const;
 
+    css::awt::Point getLabelPosition( css::awt::Point aTextShapePos, sal_Int32 nPointIndex ) const;
+    bool isLabelCustomPos( sal_Int32 nPointIndex ) const;
+
     css::uno::Reference<css::beans::XPropertySet> getPropertiesOfPoint( sal_Int32 index ) const;
 
     css::uno::Reference<css::beans::XPropertySet> getPropertiesOfSeries() const;
diff --git a/chart2/source/view/main/VDataSeries.cxx b/chart2/source/view/main/VDataSeries.cxx
index 867eb56dee11..33bf9bee481d 100644
--- a/chart2/source/view/main/VDataSeries.cxx
+++ b/chart2/source/view/main/VDataSeries.cxx
@@ -26,11 +26,13 @@
 #include <RegressionCurveHelper.hxx>
 #include <unonames.hxx>
 
+#include <com/sun/star/chart/DataLabelPlacement.hpp>
 #include <com/sun/star/chart/MissingValueTreatment.hpp>
 #include <com/sun/star/chart2/DataPointLabel.hpp>
 #include <com/sun/star/chart2/Symbol.hpp>
 #include <com/sun/star/chart2/XDataSeries.hpp>
 #include <com/sun/star/chart2/XRegressionCurveCalculator.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
 
 #include <rtl/math.hxx>
 #include <osl/diagnose.h>
@@ -603,8 +605,6 @@ sal_Int32 VDataSeries::getLabelPlacement( sal_Int32 nPointIndex, const uno::Refe
         if( xPointProps.is() )
             xPointProps->getPropertyValue("LabelPlacement") >>= nLabelPlacement;
 
-        //ensure that the set label placement is supported by this charttype
-
         uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements(
                 xChartType, bSwapXAndY, m_xDataSeries ) );
 
@@ -628,6 +628,42 @@ sal_Int32 VDataSeries::getLabelPlacement( sal_Int32 nPointIndex, const uno::Refe
     return nLabelPlacement;
 }
 
+awt::Point VDataSeries::getLabelPosition( awt::Point aTextShapePos, sal_Int32 nPointIndex ) const
+{
+    awt::Point aPos(-1, -1);
+    try
+    {
+        RelativePosition aCustomLabelPosition;
+        uno::Reference< beans::XPropertySet > xPointProps(getPropertiesOfPoint(nPointIndex));
+        if( xPointProps.is() && (xPointProps->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition))
+        {
+            aPos.X = static_cast<sal_Int32>(aCustomLabelPosition.Primary * m_aReferenceSize.Width) + aTextShapePos.X;
+            aPos.Y = static_cast<sal_Int32>(aCustomLabelPosition.Secondary * m_aReferenceSize.Height) + aTextShapePos.Y;
+        }
+    }
+    catch (const uno::Exception&) {}
+
+    return aPos;
+}
+
+bool VDataSeries::isLabelCustomPos(sal_Int32 nPointIndex) const
+{
+    bool bCustom = false;
+    RelativePosition aCustomLabelPosition;
+    try
+    {
+        if( isAttributedDataPoint(nPointIndex) )
+        {
+            uno::Reference< beans::XPropertySet > xPointProps(m_xDataSeries->getDataPointByIndex(nPointIndex));
+            if( xPointProps.is() && (xPointProps->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition) )
+                bCustom = true;
+        }
+    }
+    catch (const uno::Exception&) {}
+
+    return bCustom;
+}
+
 double VDataSeries::getMinimumofAllDifferentYValues( sal_Int32 index ) const
 {
     double fMin=0.0;
diff --git a/compilerplugins/clang/unusedenumconstants.writeonly.results b/compilerplugins/clang/unusedenumconstants.writeonly.results
index ff3da7eee610..313ef966c1a7 100644
--- a/compilerplugins/clang/unusedenumconstants.writeonly.results
+++ b/compilerplugins/clang/unusedenumconstants.writeonly.results
@@ -728,6 +728,8 @@ chart2/source/model/main/DataPointProperties.hxx:84
     enum chart::DataPointProperties::(anonymous at /media/disk2/libo4/chart2/source/model/main/DataPointProperties.hxx:36:5) PROP_DATAPOINT_LABEL_BORDER_TRANS
 chart2/source/model/main/DataPointProperties.hxx:85
     enum chart::DataPointProperties::(anonymous at /media/disk2/libo4/chart2/source/model/main/DataPointProperties.hxx:36:5) PROP_DATAPOINT_CUSTOM_LABEL_FIELDS
+chart2/source/model/main/DataPointProperties.hxx:86
+    enum chart::DataPointProperties::(anonymous at /media/disk2/libo4/chart2/source/model/main/DataPointProperties.hxx:36:5) PROP_DATAPOINT_LABEL_CUSTOM_POS
 chart2/source/model/main/DataSeriesProperties.hxx:37
     enum chart::DataSeriesProperties::(anonymous at /media/disk2/libo4/chart2/source/model/main/DataSeriesProperties.hxx:34:5) PROP_DATASERIES_STACKING_DIRECTION
 chart2/source/model/main/DataSeriesProperties.hxx:38
diff --git a/offapi/com/sun/star/chart/DataLabelPlacement.idl b/offapi/com/sun/star/chart/DataLabelPlacement.idl
index ca1cf02d6a25..fbdc19fcce8f 100644
--- a/offapi/com/sun/star/chart/DataLabelPlacement.idl
+++ b/offapi/com/sun/star/chart/DataLabelPlacement.idl
@@ -41,6 +41,7 @@ published constants DataLabelPlacement
     const long INSIDE = 10;
     const long OUTSIDE = 11;
     const long NEAR_ORIGIN = 12;
+    const long CUSTOM = 13;
 };
 
 
diff --git a/offapi/com/sun/star/chart2/DataPointProperties.idl b/offapi/com/sun/star/chart2/DataPointProperties.idl
index e2230a5f7630..a8725651c00a 100644
--- a/offapi/com/sun/star/chart2/DataPointProperties.idl
+++ b/offapi/com/sun/star/chart2/DataPointProperties.idl
@@ -32,6 +32,7 @@
 #include <com/sun/star/chart2/DataPointLabel.idl>
 #include <com/sun/star/chart2/Symbol.idl>
 #include <com/sun/star/chart2/XFormattedString2.idl>
+#include <com/sun/star/chart2/RelativePosition.idl>
 
 module com
 {
@@ -327,6 +328,12 @@ service DataPointProperties
     /** A value between 0 and 100 indicating the percentage how round an edge should be.
     */
     [optional, maybevoid, property] short             PercentDiagonal;
+
+    /** Custom position on the page associated to the CUSTOM label placement.
+
+        @since LibreOffice 6.5
+    */
+    [optional, maybevoid, property] ::com::sun::star::chart2::RelativePosition CustomLabelPosition;
 };
 
 } ; // chart2
diff --git a/oox/source/drawingml/chart/seriesconverter.cxx b/oox/source/drawingml/chart/seriesconverter.cxx
index 62f78a28e383..d47d897c5a91 100644
--- a/oox/source/drawingml/chart/seriesconverter.cxx
+++ b/oox/source/drawingml/chart/seriesconverter.cxx
@@ -20,6 +20,7 @@
 #include <drawingml/chart/seriesconverter.hxx>
 
 #include <com/sun/star/chart/DataLabelPlacement.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
 #include <com/sun/star/chart/ErrorBarStyle.hpp>
 #include <com/sun/star/chart2/DataPointLabel.hpp>
 #include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
@@ -273,22 +274,32 @@ void DataLabelConverter::convertFromModel( const Reference< XDataSeries >& rxDat
         lclConvertLabelFormatting( aPropSet, getFormatter(), mrModel, rTypeGroup, false, bMSO2007Doc );
         const TypeGroupInfo& rTypeInfo = rTypeGroup.getTypeInfo();
         bool bIsPie = rTypeInfo.meTypeCategory == TYPECATEGORY_PIE;
-        if( mrModel.mxLayout && !mrModel.mxLayout->mbAutoLayout && !bIsPie )
+
+        if( mrModel.mxLayout && !mrModel.mxLayout->mbAutoLayout )
         {
-            // bnc#694340 - nasty hack - chart2 cannot individually
-            // place data labels, let's try to find a useful
-            // compromise instead
-            namespace csscd = ::com::sun::star::chart::DataLabelPlacement;
-            const sal_Int32 aPositionsLookupTable[] =
+            if( rTypeInfo.meTypeCategory == TYPECATEGORY_BAR )
+            {
+                // It is only works for BAR Chart, yet!!!
+                RelativePosition aPos(mrModel.mxLayout->mfX, mrModel.mxLayout->mfY, css::drawing::Alignment_TOP_LEFT);
+                aPropSet.setProperty(PROP_CustomLabelPosition, aPos);
+            }
+            else if( !bIsPie )
+            {
+                // bnc#694340 - nasty hack - chart2 cannot individually
+                // place data labels, let's try to find a useful
+                // compromise instead
+                namespace csscd = ::com::sun::star::chart::DataLabelPlacement;
+                const sal_Int32 aPositionsLookupTable[] =
                 {
                     csscd::TOP_LEFT,    csscd::TOP,    csscd::TOP_RIGHT,
                     csscd::LEFT,        csscd::CENTER, csscd::RIGHT,
                     csscd::BOTTOM_LEFT, csscd::BOTTOM, csscd::BOTTOM_RIGHT
                 };
-            const int simplifiedX = lclGetPositionX(mrModel.mxLayout->mfX);
-            const int simplifiedY = lclGetPositionY(mrModel.mxLayout->mfY);
-            aPropSet.setProperty( PROP_LabelPlacement,
-                                  aPositionsLookupTable[ simplifiedX+1 + 3*(simplifiedY+1) ] );
+                const int simplifiedX = lclGetPositionX(mrModel.mxLayout->mfX);
+                const int simplifiedY = lclGetPositionY(mrModel.mxLayout->mfY);
+                aPropSet.setProperty(PROP_LabelPlacement,
+                    aPositionsLookupTable[simplifiedX + 1 + 3 * (simplifiedY + 1)]);
+            }
         }
 
         if (mrModel.mxShapeProp)
diff --git a/oox/source/token/properties.txt b/oox/source/token/properties.txt
index b7a76058d688..de9cd886643a 100644
--- a/oox/source/token/properties.txt
+++ b/oox/source/token/properties.txt
@@ -113,6 +113,7 @@ CursorPositionX
 CursorPositionY
 CurveName
 CurveStyle
+CustomLabelPosition
 CustomShapeGeometry
 D3DSceneAmbientColor
 D3DSceneLightColor2
diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index 61c74879a6db..9eff839c2865 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -2614,24 +2614,25 @@ void SdImportTest::testTdf114821()
     uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() );
     CPPUNIT_ASSERT_EQUAL_MESSAGE( "Invalid Series count", static_cast<sal_Int32>( 1 ), aSeriesSeq.getLength() );
 
+    // These Labels have custom position, so the exported LabelPlacement (reference point) by MSO is OUTSIDE/OUTEND
     // Check the first label
     const css::uno::Reference< css::beans::XPropertySet >& rPropSet0( aSeriesSeq[0]->getDataPointByIndex( 0 ) );
     CPPUNIT_ASSERT( rPropSet0.is() );
     sal_Int32 aPlacement;
     rPropSet0->getPropertyValue( "LabelPlacement" ) >>= aPlacement;
-    CPPUNIT_ASSERT_EQUAL( css::chart::DataLabelPlacement::TOP, aPlacement );
+    CPPUNIT_ASSERT_EQUAL( css::chart::DataLabelPlacement::OUTSIDE, aPlacement );
 
     // Check the second label
     const css::uno::Reference< css::beans::XPropertySet >& rPropSet1( aSeriesSeq[0]->getDataPointByIndex( 1 ) );
     CPPUNIT_ASSERT( rPropSet1.is() );
     rPropSet1->getPropertyValue( "LabelPlacement" ) >>= aPlacement;
-    CPPUNIT_ASSERT_EQUAL( css::chart::DataLabelPlacement::CENTER, aPlacement );
+    CPPUNIT_ASSERT_EQUAL( css::chart::DataLabelPlacement::OUTSIDE, aPlacement );
 
     // Check the third label
     const css::uno::Reference< css::beans::XPropertySet >& rPropSet2( aSeriesSeq[0]->getDataPointByIndex( 2 ) );
     CPPUNIT_ASSERT( rPropSet2.is() );
     rPropSet2->getPropertyValue( "LabelPlacement") >>= aPlacement;
-    CPPUNIT_ASSERT_EQUAL( css::chart::DataLabelPlacement::TOP, aPlacement );
+    CPPUNIT_ASSERT_EQUAL( css::chart::DataLabelPlacement::OUTSIDE, aPlacement );
 
     xDocShRef->DoClose();
 }


More information about the Libreoffice-commits mailing list