From 4223ff2be69f03e571464b0b09ad0d278918631b Mon Sep 17 00:00:00 2001 From: Balazs Varga Date: Wed, 15 Jan 2020 16:31:35 +0100 Subject: tdf#48436 Chart: add CustomLabelPosition UNO API property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Tested-by: László Németh --- chart2/qa/extras/chart2import.cxx | 24 +++++++++++++ .../data/xlsx/testDataPointLabelCustomPos.xlsx | Bin 0 -> 15069 bytes .../controller/chartapiwrapper/LegendWrapper.cxx | 2 +- .../controller/inc/PositionAndSizeHelper.hxx | 2 ++ .../itemsetwrapper/DataPointItemConverter.cxx | 13 +++++-- .../itemsetwrapper/TextLabelItemConverter.cxx | 11 ++++-- .../controller/main/ChartController_Position.cxx | 2 +- .../controller/main/ChartController_Window.cxx | 2 ++ .../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 +++++++++++++++++++-- .../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(-) create mode 100644 chart2/qa/extras/data/xlsx/testDataPointLabelCustomPos.xlsx 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 #include #include +#include #include #include #include @@ -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 xDataSeries(getDataSeriesFromDoc(xChartDoc, 0)); + CPPUNIT_ASSERT(xDataSeries.is()); + + uno::Reference 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 #include +#include #include #include #include +#include #include #include @@ -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 #include +#include #include #include #include +#include #include using namespace com::sun::star; @@ -370,6 +372,7 @@ bool TextLabelItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxIte { sal_Int32 nNew = static_cast(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 #include #include +#include #include #include #include @@ -410,6 +411,12 @@ void DataPointProperties::AddPropertiesToVector( cppu::UnoType>>::get(), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::MAYBEDEFAULT); + + rOutProperties.emplace_back( "CustomLabelPosition", + PROP_DATAPOINT_LABEL_CUSTOM_POS, + cppu::UnoType::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 #include #include +#include #include #include @@ -107,6 +108,9 @@ public: sal_Int32 nPointIndex, const css::uno::Reference& 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 getPropertiesOfPoint( sal_Int32 index ) const; css::uno::Reference 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 #include +#include #include #include #include #include #include +#include #include #include @@ -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(aCustomLabelPosition.Primary * m_aReferenceSize.Width) + aTextShapePos.X; + aPos.Y = static_cast(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 #include #include +#include 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 #include +#include #include #include #include @@ -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( 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(); } -- cgit