chart2/qa/extras/chart2export3.cxx | 70 +++++++- chart2/qa/extras/data/xlsx/tdf39052.xlsx |binary chart2/source/controller/chartapiwrapper/TitleWrapper.cxx | 65 +++++++- chart2/source/controller/dialogs/TitleDialogData.cxx | 2 chart2/source/controller/inc/ChartController.hxx | 5 chart2/source/controller/inc/SelectionHelper.hxx | 1 chart2/source/controller/main/ChartController.cxx | 6 chart2/source/controller/main/ChartController_TextEdit.cxx | 83 ++++++++-- chart2/source/controller/main/ChartController_Tools.cxx | 11 + chart2/source/controller/main/ChartController_Window.cxx | 10 - chart2/source/controller/main/ControllerCommandDispatch.cxx | 6 chart2/source/controller/main/SelectionHelper.cxx | 5 chart2/source/controller/sidebar/ChartElementsPanel.cxx | 3 chart2/source/inc/TitleHelper.hxx | 6 chart2/source/tools/TitleHelper.cxx | 97 ++++++++---- chart2/source/view/main/PropertyMapper.cxx | 3 chart2/source/view/main/ShapeFactory.cxx | 74 ++++++--- chart2/uiconfig/menubar/menubar.xml | 1 chart2/uiconfig/toolbar/toolbar.xml | 1 editeng/source/editeng/editobj.cxx | 14 + editeng/source/editeng/editobj2.hxx | 2 editeng/source/outliner/overflowingtxt.cxx | 2 include/editeng/editobj.hxx | 4 include/oox/export/chartexport.hxx | 4 oox/inc/drawingml/textcharacterproperties.hxx | 8 oox/source/drawingml/chart/titleconverter.cxx | 11 + oox/source/drawingml/textcharacterpropertiescontext.cxx | 3 oox/source/export/chartexport.cxx | 81 +++++++--- oox/source/export/drawingml.cxx | 3 sc/source/filter/xcl97/xcl97rec.cxx | 3 sc/source/ui/Accessibility/AccessiblePageHeader.cxx | 2 sc/source/ui/view/viewfunc.cxx | 2 sd/source/filter/ppt/pptinanimations.cxx | 2 svx/source/svdraw/svdotxat.cxx | 19 +- svx/source/table/cell.cxx | 2 sw/source/uibase/docvw/AnnotationWin.cxx | 2 xmloff/source/chart/SchXMLAxisContext.cxx | 1 xmloff/source/chart/SchXMLChartContext.cxx | 2 xmloff/source/chart/SchXMLExport.cxx | 3 39 files changed, 492 insertions(+), 127 deletions(-)
New commits: commit 170fdbae18fdaf1ce0259b51f80566dc54f5a683 Author: Balazs Varga <[email protected]> AuthorDate: Fri Mar 29 23:00:50 2024 +0100 Commit: Balazs Varga <[email protected]> CommitDate: Wed Apr 3 11:09:23 2024 +0200 Related: tdf#39052 - chart ooxml: export formatted chart titles texts properly to ooxml. Also adding "FormattedStrings" property for title objects to simplify the working of character formattings in editable chart shapes. TODO: odf import/export cherry-pick from commit: 55e9a27afd2d6a13cf76b39641bf121c3ec4b45c Change-Id: Ie27b4dee72c24fa6a2a4e2a7db8da7fa50eb8937 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165583 Tested-by: Jenkins Tested-by: Gabor Kelemen <[email protected]> Reviewed-by: Balazs Varga <[email protected]> diff --git a/chart2/qa/extras/chart2export3.cxx b/chart2/qa/extras/chart2export3.cxx index 845e6c98c6a6..b81c99218cba 100644 --- a/chart2/qa/extras/chart2export3.cxx +++ b/chart2/qa/extras/chart2export3.cxx @@ -455,12 +455,13 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testChartMainWithSubTitle) xmlDocUniquePtr pXmlDoc = parseExport("xl/charts/chart1.xml"); CPPUNIT_ASSERT(pXmlDoc); // test properties of title - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr", "sz", "1300"); - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr", "b", "0"); - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr", "i", "1"); - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:pPr/a:defRPr/a:solidFill/a:srgbClr", "val", "f10d0c"); - assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:rPr/a:latin", "typeface", "Arial"); - assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p/a:r/a:t", "It is a Maintitle It is a Subtitle"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:pPr/a:defRPr", "sz", "1300"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:pPr/a:defRPr", "b", "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:pPr/a:defRPr", "i", "1"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:pPr/a:defRPr/a:solidFill/a:srgbClr", "val", "f10d0c"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r/a:rPr/a:latin", "typeface", "Arial"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r/a:t", "It is a Maintitle"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r/a:t", "It is a Subtitle"); assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:spPr/a:solidFill/a:srgbClr", "val", "81d41a"); } @@ -741,6 +742,63 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testTdf148142) CPPUNIT_ASSERT(!aScaleData2.ShiftedCategoryPosition); } +CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testFormattedChartTitles) +{ + loadFromFile(u"xlsx/tdf39052.xlsx"); + save("Calc Office Open XML"); + xmlDocUniquePtr pXmlDoc = parseExport("xl/charts/chart1.xml"); + CPPUNIT_ASSERT(pXmlDoc); + + // Check run level properties [1] - first paragraph + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[1]/a:rPr", "b", "1"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[1]/a:rPr", "sz", "1400"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[1]/a:rPr/a:solidFill/a:srgbClr", "val", "ff0000"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[1]/a:rPr/a:latin", "typeface", "Aptos Narrow"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[1]/a:t", "This"); + // Check run level properties [2] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[2]/a:rPr", "b", "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[2]/a:rPr", "sz", "1400"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[2]/a:rPr/a:solidFill/a:srgbClr", "val", "595959"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[2]/a:t", " is"); + // Check run level properties [3] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[3]/a:rPr", "b", "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[3]/a:rPr", "sz", "1400"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[3]/a:rPr", "baseline", "30000"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[3]/a:t", "3"); + // Check run level properties [4] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[4]/a:rPr", "b", "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[4]/a:rPr", "sz", "1400"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[4]/a:t", " a "); + // Check run level properties [5] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr", "b", "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr", "i", "1"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr", "sz", "2000"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr", "u", "sng"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr/a:solidFill/a:srgbClr", "val", "4ea72e"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:rPr/a:uFillTx", 1); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[5]/a:t", "custom"); + // Check run level properties [6] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[6]/a:rPr", "b", "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[6]/a:rPr", "sz", "1400"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[1]/a:r[6]/a:t", " erte1"); + // Check run level properties [1] - second paragraph + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[1]/a:rPr", "b", "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[1]/a:rPr", "sz", "1400"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[1]/a:rPr/a:solidFill/a:srgbClr", "val", "595959"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[1]/a:rPr/a:latin", "typeface", "Aptos Narrow"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[1]/a:t", "2dfgd ch"); + // Check run level properties [2] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[2]/a:rPr", "b", "1"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[2]/a:t", "ar"); + // Check run level properties [3] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[3]/a:rPr", "b", "0");; + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[3]/a:t", "t "); + // Check run level properties [4] + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[4]/a:rPr", "b", "0"); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[4]/a:rPr", "strike", "sngStrike"); + assertXPathContent(pXmlDoc, "/c:chartSpace/c:chart/c:title/c:tx/c:rich/a:p[2]/a:r[4]/a:t", "title"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/qa/extras/data/xlsx/tdf39052.xlsx b/chart2/qa/extras/data/xlsx/tdf39052.xlsx new file mode 100644 index 000000000000..5b0285bab292 Binary files /dev/null and b/chart2/qa/extras/data/xlsx/tdf39052.xlsx differ diff --git a/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx b/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx index 75d6c9e98f1f..6036869947e8 100644 --- a/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx +++ b/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx @@ -104,6 +104,63 @@ Any WrappedTitleStringProperty::getPropertyDefault( const Reference< beans::XPro return uno::Any( OUString() );//default title is an empty String } +namespace { + + class WrappedTitleFormStringsProperty : public WrappedProperty + { + public: + explicit WrappedTitleFormStringsProperty(); + + virtual void setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + + protected: + Reference< uno::XComponentContext > m_xContext; + }; + +} + +WrappedTitleFormStringsProperty::WrappedTitleFormStringsProperty() + : ::chart::WrappedProperty( "FormattedStrings", OUString() ) +{ +} + +void WrappedTitleFormStringsProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Title* pTitle = dynamic_cast<Title*>(xInnerPropertySet.get()); + if (pTitle) + { + Sequence< Reference< chart2::XFormattedString >> xFormattedStrings; + rOuterValue >>= xFormattedStrings; + TitleHelper::setFormattedString(pTitle, xFormattedStrings); + } +} +Any WrappedTitleFormStringsProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet(getPropertyDefault(Reference< beans::XPropertyState >(xInnerPropertySet, uno::UNO_QUERY))); + Reference< chart2::XTitle > xTitle(xInnerPropertySet, uno::UNO_QUERY); + if (xTitle.is()) + { + const Sequence< Reference< chart2::XFormattedString > > aStrings(xTitle->getText()); + + OUStringBuffer aBuf; + for (Reference< chart2::XFormattedString > const& formattedStr : aStrings) + { + aBuf.append(formattedStr->getString()); + } + if (!aBuf.makeStringAndClear().isEmpty()) + { + aRet <<= aStrings; + } + } + return aRet; +} +Any WrappedTitleFormStringsProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return uno::Any(Sequence< Reference< chart2::XFormattedString > >()); //default title is an empty Sequence of XFormattedStrings +} + namespace { class WrappedStackedTextProperty : public WrappedProperty @@ -127,6 +184,7 @@ namespace enum { PROP_TITLE_STRING, + PROP_TITLE_FORMATTED_STRINGS, PROP_TITLE_TEXT_ROTATION, PROP_TITLE_TEXT_STACKED }; @@ -139,7 +197,11 @@ void lcl_AddPropertiesToVector( cppu::UnoType<OUString>::get(), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::MAYBEVOID ); - + rOutProperties.emplace_back( "FormattedStrings", + PROP_TITLE_FORMATTED_STRINGS, + cppu::UnoType< Sequence< Reference< chart2::XFormattedString >>>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); rOutProperties.emplace_back( "TextRotation", PROP_TITLE_TEXT_ROTATION, cppu::UnoType<sal_Int32>::get(), @@ -468,6 +530,7 @@ std::vector< std::unique_ptr<WrappedProperty> > TitleWrapper::createWrappedPrope std::vector< std::unique_ptr<WrappedProperty> > aWrappedProperties; aWrappedProperties.emplace_back( new WrappedTitleStringProperty( m_spChart2ModelContact->m_xContext ) ); + aWrappedProperties.emplace_back( new WrappedTitleFormStringsProperty() ); aWrappedProperties.emplace_back( new WrappedTextRotationProperty( true ) ); aWrappedProperties.emplace_back( new WrappedStackedTextProperty() ); WrappedCharacterHeightProperty::addWrappedProperties( aWrappedProperties, this ); diff --git a/chart2/source/controller/main/ChartController_TextEdit.cxx b/chart2/source/controller/main/ChartController_TextEdit.cxx index d43549fcb81e..3b808af4522b 100644 --- a/chart2/source/controller/main/ChartController_TextEdit.cxx +++ b/chart2/source/controller/main/ChartController_TextEdit.cxx @@ -125,17 +125,10 @@ bool ChartController::EndTextEdit() if(!pTextObject) return false; - SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner(); OutlinerParaObject* pParaObj = pTextObject->GetOutlinerParaObject(); - if( !pParaObj || !pOutliner ) + if( !pParaObj ) return true; - pOutliner->SetText( *pParaObj ); - - OUString aString = pOutliner->GetText( - pOutliner->GetParagraph( 0 ), - pOutliner->GetParagraphCount() ); - OUString aObjectCID = m_aSelection.getSelectedCID(); if ( !aObjectCID.isEmpty() ) { @@ -149,26 +142,7 @@ bool ChartController::EndTextEdit() GetFormattedTitle(pParaObj->GetTextObject(), pTextObject->getUnoShape()); Title* pTitle = dynamic_cast<Title*>(xPropSet.get()); - if (pTitle && aNewFormattedTitle.hasElements()) - { - bool bStacked = false; - if (xPropSet.is()) - xPropSet->getPropertyValue("StackCharacters") >>= bStacked; - - if (bStacked) - { - for (uno::Reference< chart2::XFormattedString >const& formattedStr : aNewFormattedTitle) - { - formattedStr->setString(TitleHelper::getUnstackedStr(formattedStr->getString())); - } - } - - pTitle->setText(aNewFormattedTitle); - } - else - { - TitleHelper::setCompleteString(aString, pTitle, m_xCC); - } + TitleHelper::setFormattedString(pTitle, aNewFormattedTitle); OSL_ENSURE(m_pTextActionUndoGuard, "ChartController::EndTextEdit: no TextUndoGuard!"); if (m_pTextActionUndoGuard) diff --git a/chart2/source/inc/TitleHelper.hxx b/chart2/source/inc/TitleHelper.hxx index a0940d7b4166..ba14ac36fdfb 100644 --- a/chart2/source/inc/TitleHelper.hxx +++ b/chart2/source/inc/TitleHelper.hxx @@ -78,6 +78,8 @@ public: static OUString getCompleteString( const rtl::Reference< ::chart::Title >& xTitle ); static OUString getUnstackedStr( const OUString& rNewText ); + static void setFormattedString( const rtl::Reference< ::chart::Title >& xTitle, + const css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >& aNewFormattedTitle ); static void setCompleteString( const OUString& rNewText , const rtl::Reference< ::chart::Title >& xTitle , const css::uno::Reference< css::uno::XComponentContext > & xContext diff --git a/chart2/source/tools/TitleHelper.cxx b/chart2/source/tools/TitleHelper.cxx index a3831d332c30..5700d6e00449 100644 --- a/chart2/source/tools/TitleHelper.cxx +++ b/chart2/source/tools/TitleHelper.cxx @@ -329,32 +329,47 @@ OUString TitleHelper::getUnstackedStr(const OUString& rNewText) return aUnstackedStr.makeStringAndClear(); } +void TitleHelper::setFormattedString( const rtl::Reference< Title >& xTitle, + const css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >& aNewFormattedTitle ) +{ + if (!xTitle.is() || !aNewFormattedTitle.hasElements()) + return; + + bool bStacked = false; + xTitle->getPropertyValue("StackCharacters") >>= bStacked; + + if (bStacked) + { + for (uno::Reference< chart2::XFormattedString >const& formattedStr : aNewFormattedTitle) + { + formattedStr->setString(TitleHelper::getUnstackedStr(formattedStr->getString())); + } + } + + xTitle->setText(aNewFormattedTitle); +} + void TitleHelper::setCompleteString( const OUString& rNewText , const rtl::Reference< Title >& xTitle , const uno::Reference< uno::XComponentContext > & xContext , const float * pDefaultCharHeight /* = 0 */ , bool bDialogTitle /*= false*/ ) { - if(!xTitle.is()) + if (!xTitle.is()) return; - OUString aNewText = rNewText; - bool bStacked = false; if( xTitle.is() ) xTitle->getPropertyValue( "StackCharacters" ) >>= bStacked; - uno::Sequence< uno::Reference< XFormattedString > > aOldStringList = xTitle->getText(); + OUString aNewText = rNewText; if( bStacked ) { aNewText = getUnstackedStr(rNewText); - for (uno::Reference< XFormattedString >const & formattedStr : aOldStringList) - { - formattedStr->setString(getUnstackedStr(formattedStr->getString())); - } } uno::Sequence< uno::Reference< XFormattedString > > aNewStringList; + uno::Sequence< uno::Reference< XFormattedString > > aOldStringList = xTitle->getText(); if( aOldStringList.hasElements()) { const OUString aFullString = getCompleteString(xTitle); diff --git a/include/oox/export/chartexport.hxx b/include/oox/export/chartexport.hxx index 6a40254f6491..4108aec96806 100644 --- a/include/oox/export/chartexport.hxx +++ b/include/oox/export/chartexport.hxx @@ -25,6 +25,7 @@ #include <com/sun/star/uno/Reference.hxx> #include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/chart2/FormattedString.hpp> #include <oox/dllapi.h> #include <oox/export/drawingml.hxx> #include <oox/export/shapes.hxx> @@ -176,7 +177,8 @@ private: void exportLegend( const css::uno::Reference< css::chart::XChartDocument >& rChartDoc ); void exportTitle( const css::uno::Reference< css::drawing::XShape >& xShape, - const OUString* pSubText = nullptr ); + const css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >& xFormattedSubTitle = + css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >() ); void exportPlotArea( const css::uno::Reference< css::chart::XChartDocument >& rChartDoc ); void exportAdditionalShapes( const css::uno::Reference<css::chart::XChartDocument >& rChartDoc ); diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx index c9db6f8cc431..1837b67cffed 100644 --- a/oox/source/export/chartexport.cxx +++ b/oox/source/export/chartexport.cxx @@ -1129,7 +1129,6 @@ void ChartExport::exportChart( const Reference< css::chart::XChartDocument >& xC // get Properties of ChartDocument bool bHasMainTitle = false; - OUString aSubTitle; bool bHasLegend = false; Reference< beans::XPropertySet > xDocPropSet( xChartDoc, uno::UNO_QUERY ); if( xDocPropSet.is()) @@ -1147,12 +1146,13 @@ void ChartExport::exportChart( const Reference< css::chart::XChartDocument >& xC } } // if( xDocPropSet.is()) + Sequence< uno::Reference< chart2::XFormattedString > > xFormattedSubTitle; Reference< beans::XPropertySet > xPropSubTitle( xChartDoc->getSubTitle(), UNO_QUERY ); if( xPropSubTitle.is()) { try { - xPropSubTitle->getPropertyValue("String") >>= aSubTitle; + xPropSubTitle->getPropertyValue("FormattedStrings") >>= xFormattedSubTitle; } catch( beans::UnknownPropertyException & ) { @@ -1166,12 +1166,12 @@ void ChartExport::exportChart( const Reference< css::chart::XChartDocument >& xC // titles if( bHasMainTitle ) { - exportTitle( xChartDoc->getTitle(), !aSubTitle.isEmpty() ? &aSubTitle : nullptr ); + exportTitle( xChartDoc->getTitle(), xFormattedSubTitle); pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "0"); } - else if( !aSubTitle.isEmpty() ) + else if( xFormattedSubTitle.hasElements() ) { - exportTitle( xChartDoc->getSubTitle(), nullptr ); + exportTitle( xChartDoc->getSubTitle() ); pFS->singleElement(FSNS(XML_c, XML_autoTitleDeleted), XML_val, "0"); } else @@ -1440,20 +1440,40 @@ void ChartExport::exportLegend( const Reference< css::chart::XChartDocument >& x pFS->endElement( FSNS( XML_c, XML_legend ) ); } -void ChartExport::exportTitle( const Reference< XShape >& xShape, const OUString* pSubText) +void ChartExport::exportTitle( const Reference< XShape >& xShape, + const css::uno::Sequence< uno::Reference< css::chart2::XFormattedString > >& xFormattedSubTitle ) { - OUString sText; + Sequence< uno::Reference< chart2::XFormattedString > > xFormattedTitle; Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); if( xPropSet.is()) { - xPropSet->getPropertyValue("String") >>= sText; + xPropSet->getPropertyValue("FormattedStrings") >>= xFormattedTitle; } // tdf#101322: add subtitle to title - if( pSubText ) - sText = sText.isEmpty() ? *pSubText : sText + " " + *pSubText; + if (xFormattedSubTitle.hasElements()) + { + if (!xFormattedTitle.hasElements()) + { + xFormattedTitle = xFormattedSubTitle; + } + else + { + sal_uInt32 nLength = xFormattedTitle.size(); + const OUString aLastString = xFormattedTitle.getArray()[nLength - 1]->getString(); + xFormattedTitle.getArray()[nLength - 1]->setString(aLastString + OUStringChar(' ')); + for (const uno::Reference<chart2::XFormattedString>& rxFS : xFormattedSubTitle) + { + if (!rxFS->getString().isEmpty()) + { + xFormattedTitle.realloc(nLength + 1); + xFormattedTitle.getArray()[nLength++] = rxFS; + } + } + } + } - if( sText.isEmpty() ) + if (!xFormattedTitle.hasElements()) return; FSHelperPtr pFS = GetFS(); @@ -1477,7 +1497,6 @@ void ChartExport::exportTitle( const Reference< XShape >& xShape, const OUString XML_rot, oox::drawingml::calcRotationValue(nRotation) ); // TODO: lstStyle pFS->singleElement(FSNS(XML_a, XML_lstStyle)); - // FIXME: handle multiple paragraphs to parse aText pFS->startElement(FSNS(XML_a, XML_p)); pFS->startElement(FSNS(XML_a, XML_pPr)); @@ -1488,13 +1507,37 @@ void ChartExport::exportTitle( const Reference< XShape >& xShape, const OUString pFS->endElement( FSNS( XML_a, XML_pPr ) ); - pFS->startElement(FSNS(XML_a, XML_r)); - bDummy = false; - WriteRunProperties( xPropSet, false, XML_rPr, true, bDummy, nDummy ); - pFS->startElement(FSNS(XML_a, XML_t)); - pFS->writeEscaped( sText ); - pFS->endElement( FSNS( XML_a, XML_t ) ); - pFS->endElement( FSNS( XML_a, XML_r ) ); + for (const uno::Reference<chart2::XFormattedString>& rxFS : xFormattedTitle) + { + pFS->startElement(FSNS(XML_a, XML_r)); + bDummy = false; + Reference< beans::XPropertySet > xRunPropSet(rxFS, uno::UNO_QUERY); + WriteRunProperties(xRunPropSet, false, XML_rPr, true, bDummy, nDummy); + pFS->startElement(FSNS(XML_a, XML_t)); + + // the linebreak should always be at the end of the XFormattedString text + bool bNextPara = rxFS->getString().endsWith(u" "); + if (!bNextPara) + pFS->writeEscaped(rxFS->getString()); + else + { + sal_Int32 nEnd = rxFS->getString().lastIndexOf(' '); + pFS->writeEscaped(rxFS->getString().replaceAt(nEnd, 1, u"")); + } + pFS->endElement(FSNS(XML_a, XML_t)); + pFS->endElement(FSNS(XML_a, XML_r)); + + if (bNextPara) + { + pFS->endElement(FSNS(XML_a, XML_p)); + + pFS->startElement(FSNS(XML_a, XML_p)); + pFS->startElement(FSNS(XML_a, XML_pPr)); + bDummy = false; + WriteRunProperties(xPropSet, false, XML_defRPr, true, bDummy, nDummy); + pFS->endElement(FSNS(XML_a, XML_pPr)); + } + } pFS->endElement( FSNS( XML_a, XML_p ) ); diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index e021354a4f0a..296bf5011354 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -2407,6 +2407,9 @@ void DrawingML::WriteRunProperties( const Reference< XPropertySet >& rRun, bool { switch ( *o3tl::doAccess<sal_Int16>(mAny) ) { + case awt::FontUnderline::NONE : + underline = "none"; + break; case awt::FontUnderline::SINGLE : underline = "sng"; break; diff --git a/xmloff/source/chart/SchXMLAxisContext.cxx b/xmloff/source/chart/SchXMLAxisContext.cxx index ae55da90f8b5..fd106f72fa69 100644 --- a/xmloff/source/chart/SchXMLAxisContext.cxx +++ b/xmloff/source/chart/SchXMLAxisContext.cxx @@ -565,6 +565,7 @@ void SchXMLAxisContext::SetAxisTitle() { try { + // TODO: ODF import for formatted chart titles xTitleProp->setPropertyValue("String", uno::Any(m_aCurrentAxis.aTitle) ); } catch( beans::UnknownPropertyException & ) diff --git a/xmloff/source/chart/SchXMLChartContext.cxx b/xmloff/source/chart/SchXMLChartContext.cxx index 7a8ac46c40a9..6d1350add627 100644 --- a/xmloff/source/chart/SchXMLChartContext.cxx +++ b/xmloff/source/chart/SchXMLChartContext.cxx @@ -727,6 +727,7 @@ void SchXMLChartContext::endFastElement(sal_Int32 ) { try { + // TODO: ODF import for formatted chart titles xTitleProp->setPropertyValue("String", uno::Any(maMainTitle) ); } catch(const beans::UnknownPropertyException&) @@ -742,6 +743,7 @@ void SchXMLChartContext::endFastElement(sal_Int32 ) { try { + // TODO: ODF import for formatted chart titles xTitleProp->setPropertyValue("String", uno::Any(maSubTitle) ); } catch(const beans::UnknownPropertyException&) diff --git a/xmloff/source/chart/SchXMLExport.cxx b/xmloff/source/chart/SchXMLExport.cxx index e07fb6a77693..e1eb8f21a164 100644 --- a/xmloff/source/chart/SchXMLExport.cxx +++ b/xmloff/source/chart/SchXMLExport.cxx @@ -1336,6 +1336,7 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); if( xPropSet.is()) { + // TODO: ODF export for formatted chart titles Any aAny( xPropSet->getPropertyValue( "String" )); OUString aText; aAny >>= aText; @@ -1377,6 +1378,7 @@ void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); if( xPropSet.is()) { + // TODO: ODF import for formatted chart titles Any aAny( xPropSet->getPropertyValue( "String" )); OUString aText; aAny >>= aText; @@ -2256,6 +2258,7 @@ void SchXMLExportHelper_Impl::exportAxisTitle( const Reference< beans::XProperty std::vector<XMLPropertyState> aPropertyStates = mxExpPropMapper->Filter(mrExport, rTitleProps); if( bExportContent ) { + // TODO: ODF import for formatted chart titles OUString aText; Any aAny( rTitleProps->getPropertyValue( "String" )); aAny >>= aText; commit f4eaa12e2bd6018f13904dd977b92de60851621c Author: Balazs Varga <[email protected]> AuthorDate: Thu Mar 28 17:55:30 2024 +0100 Commit: Balazs Varga <[email protected]> CommitDate: Wed Apr 3 10:38:07 2024 +0200 tdf#39052 - Chart: make characters formatable in editable chart textshapes Editable textshapes include main chart title, sub chart title, axis titles. In chart2 the chart2::XFormattedString and chart2::XFormattedString2 store the formatted characters from textshapes, so we need to set all the character properties from the EditTextObject and need to add them to to the XFormattedString array with all the related texts which are formatted individually. For formatting of the characters the .uno:FontDialog command can be used, which can be called from the chart menubar, toolbar and with right click on the text when we are in edit mode in the textshape. (Note: in the next patch the OOXML export will be fixed.) cherry-pick from commit: 4f994cec388377cc5c2bddb804bd92eb4cd7dc8d Change-Id: I5750a5fe694b384dc6b28e2ef03ac1f2b03957db Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165501 Tested-by: Jenkins Tested-by: Gabor Kelemen <[email protected]> Reviewed-by: Balazs Varga <[email protected]> diff --git a/chart2/source/controller/dialogs/TitleDialogData.cxx b/chart2/source/controller/dialogs/TitleDialogData.cxx index f110b3d520bd..e711ad151e75 100644 --- a/chart2/source/controller/dialogs/TitleDialogData.cxx +++ b/chart2/source/controller/dialogs/TitleDialogData.cxx @@ -100,7 +100,7 @@ bool TitleDialogData::writeDifferenceToModel( TitleHelper::getTitle( static_cast< TitleHelper::eTitleType >( nN ), xChartModel ) ); if(xTitle.is()) { - TitleHelper::setCompleteString( aTextList[nN], xTitle, xContext ); + TitleHelper::setCompleteString( aTextList[nN], xTitle, xContext, nullptr, true ); bChanged = true; } } diff --git a/chart2/source/controller/inc/ChartController.hxx b/chart2/source/controller/inc/ChartController.hxx index 63fb4d4fc302..8535bcc8c0d0 100644 --- a/chart2/source/controller/inc/ChartController.hxx +++ b/chart2/source/controller/inc/ChartController.hxx @@ -330,6 +330,7 @@ public: void setDrawMode( ChartDrawMode eMode ) { m_eDrawMode = eMode; } bool isShapeContext() const; + bool IsTextEdit() const; ViewElementListProvider getViewElementListProvider(); DrawModelWrapper* GetDrawModelWrapper(); @@ -491,6 +492,8 @@ private: void executeDispatch_MoveSeries( bool bForward ); bool EndTextEdit(); + css::uno::Sequence< css::uno::Reference<css::chart2::XFormattedString >> GetFormattedTitle( + const EditTextObject& aEdit, const css::uno::Reference< css::drawing::XShape >& xShape ); void executeDispatch_View3D(); void executeDispatch_PositionAndSize( const ::css::uno::Sequence< ::css::beans::PropertyValue >* pArgs = nullptr ); @@ -521,7 +524,7 @@ private: const css::uno::Sequence< css::beans::PropertyValue >& rArgs ); DECL_LINK( DoubleClickWaitingHdl, Timer*, void ); - void execute_DoubleClick( const Point* pMousePixel ); + void execute_DoubleClick( const Point* pMousePixel, bool &bEditText ); void startDoubleClickWaiting(); void stopDoubleClickWaiting(); diff --git a/chart2/source/controller/inc/SelectionHelper.hxx b/chart2/source/controller/inc/SelectionHelper.hxx index ff0e95eee27a..119640bd4300 100644 --- a/chart2/source/controller/inc/SelectionHelper.hxx +++ b/chart2/source/controller/inc/SelectionHelper.hxx @@ -39,6 +39,7 @@ public: //methods bool isResizeableObjectSelected() const; bool isRotateableObjectSelected( const rtl::Reference<::chart::ChartModel>& xChartModel ) const; + bool isTitleObjectSelected() const; bool isDragableObjectSelected() const; bool isAdditionalShapeSelected() const; diff --git a/chart2/source/controller/main/ChartController.cxx b/chart2/source/controller/main/ChartController.cxx index 3f94410d22b0..e105885e04ad 100644 --- a/chart2/source/controller/main/ChartController.cxx +++ b/chart2/source/controller/main/ChartController.cxx @@ -1259,7 +1259,9 @@ void SAL_CALL ChartController::dispatch( this->executeDispatch_PositionAndSize(); } } - else if( lcl_isFormatObjectCommand(aCommand) ) + else if ( aCommand == "FontDialog" ) + this->impl_ShapeControllerDispatch(rURL, rArgs); + else if (lcl_isFormatObjectCommand(aCommand)) this->executeDispatch_FormatObject(rURL.Path); //more format else if( aCommand == "DiagramType" ) @@ -1655,7 +1657,7 @@ const o3tl::sorted_vector< OUString >& ChartController::impl_getAvailableCommand "InsertMenuDataTable", "InsertDataTable", "DeleteDataTable", //format objects - "FormatSelection", "TransformDialog", + "FormatSelection", "FontDialog", "TransformDialog", "DiagramType", "View3D", "Forward", "Backward", "MainTitle", "SubTitle", diff --git a/chart2/source/controller/main/ChartController_TextEdit.cxx b/chart2/source/controller/main/ChartController_TextEdit.cxx index fbc8df4ed6b0..d43549fcb81e 100644 --- a/chart2/source/controller/main/ChartController_TextEdit.cxx +++ b/chart2/source/controller/main/ChartController_TextEdit.cxx @@ -30,6 +30,7 @@ #include <TitleHelper.hxx> #include <ObjectIdentifier.hxx> #include <ControllerLockGuard.hxx> +#include <comphelper/diagnose_ex.hxx> #if !ENABLE_WASM_STRIP_ACCESSIBILITY #include <AccessibleTextHelper.hxx> #endif @@ -42,10 +43,10 @@ #include <svx/svxids.hrc> #include <editeng/editids.hrc> #include <vcl/svapp.hxx> -#include <com/sun/star/beans/XPropertySet.hpp> -#include <com/sun/star/chart2/XTitle.hpp> +#include <com/sun/star/chart2/FormattedString.hpp> #include <svl/stritem.hxx> #include <editeng/fontitem.hxx> +#include <editeng/section.hxx> #include <memory> namespace chart @@ -144,8 +145,30 @@ bool ChartController::EndTextEdit() // lock controllers till end of block ControllerLockGuardUNO aCLGuard( getChartModel() ); + uno::Sequence< uno::Reference< chart2::XFormattedString > > aNewFormattedTitle = + GetFormattedTitle(pParaObj->GetTextObject(), pTextObject->getUnoShape()); + Title* pTitle = dynamic_cast<Title*>(xPropSet.get()); - TitleHelper::setCompleteString( aString, pTitle, m_xCC ); + if (pTitle && aNewFormattedTitle.hasElements()) + { + bool bStacked = false; + if (xPropSet.is()) + xPropSet->getPropertyValue("StackCharacters") >>= bStacked; + + if (bStacked) + { + for (uno::Reference< chart2::XFormattedString >const& formattedStr : aNewFormattedTitle) + { + formattedStr->setString(TitleHelper::getUnstackedStr(formattedStr->getString())); + } + } + + pTitle->setText(aNewFormattedTitle); + } + else + { + TitleHelper::setCompleteString(aString, pTitle, m_xCC); + } OSL_ENSURE(m_pTextActionUndoGuard, "ChartController::EndTextEdit: no TextUndoGuard!"); if (m_pTextActionUndoGuard) @@ -155,6 +178,70 @@ bool ChartController::EndTextEdit() return true; } +uno::Sequence< uno::Reference< chart2::XFormattedString > > ChartController::GetFormattedTitle( + const EditTextObject& aEdit, const uno::Reference< drawing::XShape >& xShape ) +{ + std::vector < uno::Reference< chart2::XFormattedString > > aNewStrings; + if (!xShape.is()) + return comphelper::containerToSequence(aNewStrings); + + uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY); + if (!xText.is()) + return comphelper::containerToSequence(aNewStrings); + + uno::Reference< text::XTextCursor > xSelectionCursor(xText->createTextCursor()); + if (!xSelectionCursor.is()) + return comphelper::containerToSequence(aNewStrings); + + xSelectionCursor->gotoStart(false); + + std::vector<editeng::Section> aSecAttrs; + aEdit.GetAllSections(aSecAttrs); + + for (editeng::Section const& rSection : aSecAttrs) + { + if (!xSelectionCursor->isCollapsed()) + xSelectionCursor->collapseToEnd(); + + xSelectionCursor->goRight(rSection.mnEnd - rSection.mnStart, true); + + OUString aNewString = xSelectionCursor->getString(); + + bool bNextPara = (aEdit.GetParagraphCount() > 1 && rSection.mnParagraph != aEdit.GetParagraphCount() - 1 && + aEdit.GetTextLen(rSection.mnParagraph) <= rSection.mnEnd); + + uno::Reference< chart2::XFormattedString2 > xFmtStr = chart2::FormattedString::create(m_xCC); + if (bNextPara) + aNewString = aNewString + OUStringChar(' '); + xFmtStr->setString(aNewString); + aNewStrings.emplace_back(xFmtStr); + + uno::Reference< beans::XPropertySetInfo > xInfo = xFmtStr->getPropertySetInfo(); + uno::Reference< beans::XPropertySet > xSelectionProp(xSelectionCursor, uno::UNO_QUERY); + try + { + for (const beans::Property& rProp : xSelectionProp->getPropertySetInfo()->getProperties()) + { + if (xInfo.is() && xInfo->hasPropertyByName(rProp.Name)) + { + const uno::Any aValue = xSelectionProp->getPropertyValue(rProp.Name); + xFmtStr->setPropertyValue(rProp.Name, aValue); + } + } + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + aNewStrings.clear(); + } + + if (bNextPara) + xSelectionCursor->goRight(1, false); // next paragraph + } + + return comphelper::containerToSequence(aNewStrings); +} + void ChartController::executeDispatch_InsertSpecialCharacter() { SolarMutexGuard aGuard; diff --git a/chart2/source/controller/main/ChartController_Tools.cxx b/chart2/source/controller/main/ChartController_Tools.cxx index da166261328f..ae9f3f4f47f4 100644 --- a/chart2/source/controller/main/ChartController_Tools.cxx +++ b/chart2/source/controller/main/ChartController_Tools.cxx @@ -320,8 +320,8 @@ void ChartController::executeDispatch_Paste() if( m_pDrawViewWrapper ) { OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); - if( pOutlinerView )//in case of edit mode insert into edited string - pOutlinerView->InsertText( aString ); + if (pOutlinerView)//in case of edit mode insert the formatted string + pOutlinerView->PasteSpecial(); else { impl_PasteStringAsTextShape( aString, awt::Point( 0, 0 ) ); @@ -589,6 +589,13 @@ bool ChartController::isShapeContext() const ( m_pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::Text ) ); } +bool ChartController::IsTextEdit() const +{ + // only Title objects are editable textshapes + return m_aSelection.isTitleObjectSelected() && + m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit(); +} + void ChartController::impl_ClearSelection() { if( m_aSelection.hasSelection()) diff --git a/chart2/source/controller/main/ChartController_Window.cxx b/chart2/source/controller/main/ChartController_Window.cxx index 1bdb1f2ed48a..4530c4b3e7a1 100644 --- a/chart2/source/controller/main/ChartController_Window.cxx +++ b/chart2/source/controller/main/ChartController_Window.cxx @@ -745,6 +745,7 @@ void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt ) bool bMouseUpWithoutMouseDown = !m_bWaitingForMouseUp; m_bWaitingForMouseUp = false; bool bNotifySelectionChange = false; + bool bEditText = false; { SolarMutexGuard aGuard; @@ -921,7 +922,7 @@ void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt ) if( isDoubleClick(rMEvt) && !bMouseUpWithoutMouseDown /*#i106966#*/ ) { Point aMousePixel = rMEvt.GetPosPixel(); - execute_DoubleClick( &aMousePixel ); + execute_DoubleClick( &aMousePixel, bEditText ); } if( m_aSelection.isSelectionDifferentFromBeforeMouseDown() ) @@ -930,18 +931,17 @@ void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt ) impl_SetMousePointer( rMEvt ); - if(bNotifySelectionChange) + if(bNotifySelectionChange || bEditText) impl_notifySelectionChangeListeners(); } -void ChartController::execute_DoubleClick( const Point* pMousePixel ) +void ChartController::execute_DoubleClick( const Point* pMousePixel, bool &bEditText ) { const SfxViewShell* pViewShell = SfxViewShell::Current(); bool isMobilePhone = pViewShell && pViewShell->isLOKMobilePhone(); if (isMobilePhone) return; - bool bEditText = false; if ( m_aSelection.hasSelection() ) { OUString aCID( m_aSelection.getSelectedCID() ); @@ -1036,6 +1036,8 @@ void ChartController::execute_Command( const CommandEvent& rCEvt ) OUString aFormatCommand( lcl_getFormatCommandForObjectCID( m_aSelection.getSelectedCID() ) ); lcl_insertMenuCommand( xPopupMenu, nUniqueId++, aFormatCommand ); + if (eObjectType == OBJECTTYPE_TITLE && m_pDrawViewWrapper->IsTextEdit()) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FontDialog" ); //some commands for dataseries and points: diff --git a/chart2/source/controller/main/ControllerCommandDispatch.cxx b/chart2/source/controller/main/ControllerCommandDispatch.cxx index 98468a138c3f..9c9c0a898965 100644 --- a/chart2/source/controller/main/ControllerCommandDispatch.cxx +++ b/chart2/source/controller/main/ControllerCommandDispatch.cxx @@ -533,6 +533,7 @@ void ControllerCommandDispatch::updateCommandAvailability() // read-only bool bIsWritable = bModelStateIsValid && (! m_apModelState->bIsReadOnly); bool bShapeContext = m_xChartController.is() && m_xChartController->isShapeContext(); + bool bIsTextEdit = m_xChartController.is() && m_xChartController->IsTextEdit(); bool bEnableDataTableDialog = false; bool bCanCreateDataProvider = false; @@ -599,9 +600,10 @@ void ControllerCommandDispatch::updateCommandAvailability() // format objects bool bFormatObjectAvailable = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsFormateableObjectSelected; - m_aCommandAvailability[ ".uno:FormatSelection" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatSelection" ] = bFormatObjectAvailable && !bIsTextEdit; + m_aCommandAvailability[ ".uno:FontDialog" ] = bFormatObjectAvailable && bIsTextEdit; m_aCommandAvailability[ ".uno:FormatAxis" ] = bFormatObjectAvailable; - m_aCommandAvailability[ ".uno:FormatTitle" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatTitle" ] = bFormatObjectAvailable && !bIsTextEdit; m_aCommandAvailability[ ".uno:FormatDataSeries" ] = bFormatObjectAvailable; m_aCommandAvailability[ ".uno:FormatDataPoint" ] = bFormatObjectAvailable; m_aCommandAvailability[ ".uno:FormatDataLabels" ] = bFormatObjectAvailable; diff --git a/chart2/source/controller/main/SelectionHelper.cxx b/chart2/source/controller/main/SelectionHelper.cxx index 11fc5d9faee7..8e7e1a1f7700 100644 --- a/chart2/source/controller/main/SelectionHelper.cxx +++ b/chart2/source/controller/main/SelectionHelper.cxx @@ -314,6 +314,11 @@ bool Selection::isDragableObjectSelected() const return m_aSelectedOID.isDragableObject(); } +bool Selection::isTitleObjectSelected() const +{ + return m_aSelectedOID.getObjectType() == OBJECTTYPE_TITLE; +} + bool Selection::isAdditionalShapeSelected() const { return m_aSelectedOID.isAdditionalShape(); diff --git a/chart2/source/controller/sidebar/ChartElementsPanel.cxx b/chart2/source/controller/sidebar/ChartElementsPanel.cxx index 4f856355ba9c..3325b1d9e274 100644 --- a/chart2/source/controller/sidebar/ChartElementsPanel.cxx +++ b/chart2/source/controller/sidebar/ChartElementsPanel.cxx @@ -636,7 +636,8 @@ IMPL_LINK(ChartElementsPanel, EditHdl, weld::Entry&, rEdit, void) // set it OUString aText(rEdit.get_text()); - TitleHelper::setCompleteString(aText, TitleHelper::getTitle(aTitleType, mxModel), comphelper::getProcessComponentContext()); + TitleHelper::setCompleteString(aText, TitleHelper::getTitle(aTitleType, mxModel), + comphelper::getProcessComponentContext(), nullptr, true); } IMPL_LINK_NOARG(ChartElementsPanel, LegendPosHdl, weld::ComboBox&, void) diff --git a/chart2/source/inc/TitleHelper.hxx b/chart2/source/inc/TitleHelper.hxx index ac9f9618799b..a0940d7b4166 100644 --- a/chart2/source/inc/TitleHelper.hxx +++ b/chart2/source/inc/TitleHelper.hxx @@ -77,10 +77,12 @@ public: , const rtl::Reference< ::chart::ChartModel >& xModel ); static OUString getCompleteString( const rtl::Reference< ::chart::Title >& xTitle ); + static OUString getUnstackedStr( const OUString& rNewText ); static void setCompleteString( const OUString& rNewText , const rtl::Reference< ::chart::Title >& xTitle , const css::uno::Reference< css::uno::XComponentContext > & xContext - , const float * pDefaultCharHeight = nullptr ); + , const float * pDefaultCharHeight = nullptr + , bool bDialogTitle = false ); static bool getTitleType( eTitleType& rType , const rtl::Reference< ::chart::Title >& xTitle diff --git a/chart2/source/tools/TitleHelper.cxx b/chart2/source/tools/TitleHelper.cxx index 992f5cdf6196..a3831d332c30 100644 --- a/chart2/source/tools/TitleHelper.cxx +++ b/chart2/source/tools/TitleHelper.cxx @@ -305,12 +305,36 @@ OUString TitleHelper::getCompleteString( const rtl::Reference< Title >& xTitle ) return aRet.makeStringAndClear(); } +OUString TitleHelper::getUnstackedStr(const OUString& rNewText) +{ + //#i99841# remove linebreaks that were added for vertical stacking + OUStringBuffer aUnstackedStr; + OUStringBuffer aSource(rNewText); + + bool bBreakIgnored = false; + sal_Int32 nLen = rNewText.getLength(); + for (sal_Int32 nPos = 0; nPos < nLen; ++nPos) + { + sal_Unicode aChar = aSource[nPos]; + if (aChar != ' ') + { + aUnstackedStr.append(aChar); + bBreakIgnored = false; + } + else if (aChar == ' ' && bBreakIgnored) + aUnstackedStr.append(aChar); + else + bBreakIgnored = true; + } + return aUnstackedStr.makeStringAndClear(); +} + void TitleHelper::setCompleteString( const OUString& rNewText , const rtl::Reference< Title >& xTitle , const uno::Reference< uno::XComponentContext > & xContext - , const float * pDefaultCharHeight /* = 0 */ ) + , const float * pDefaultCharHeight /* = 0 */ + , bool bDialogTitle /*= false*/ ) { - //the format of the first old text portion will be maintained if there is any if(!xTitle.is()) return; @@ -320,37 +344,35 @@ void TitleHelper::setCompleteString( const OUString& rNewText if( xTitle.is() ) xTitle->getPropertyValue( "StackCharacters" ) >>= bStacked; + uno::Sequence< uno::Reference< XFormattedString > > aOldStringList = xTitle->getText(); if( bStacked ) { - //#i99841# remove linebreaks that were added for vertical stacking - OUStringBuffer aUnstackedStr; - OUStringBuffer aSource(rNewText); - - bool bBreakIgnored = false; - sal_Int32 nLen = rNewText.getLength(); - for( sal_Int32 nPos = 0; nPos < nLen; ++nPos ) + aNewText = getUnstackedStr(rNewText); + for (uno::Reference< XFormattedString >const & formattedStr : aOldStringList) { - sal_Unicode aChar = aSource[nPos]; - if( aChar != ' ' ) - { - aUnstackedStr.append( aChar ); - bBreakIgnored = false; - } - else if( aChar == ' ' && bBreakIgnored ) - aUnstackedStr.append( aChar ); - else - bBreakIgnored = true; + formattedStr->setString(getUnstackedStr(formattedStr->getString())); } - aNewText = aUnstackedStr.makeStringAndClear(); } uno::Sequence< uno::Reference< XFormattedString > > aNewStringList; - - uno::Sequence< uno::Reference< XFormattedString > > aOldStringList = xTitle->getText(); - if( aOldStringList.hasElements() ) + if( aOldStringList.hasElements()) { - aNewStringList = { aOldStringList[0] }; - aNewStringList[0]->setString( aNewText ); + const OUString aFullString = getCompleteString(xTitle); + if (bDialogTitle && aNewText.equals(getUnstackedStr(aFullString))) + { + // If the new title setted from a dialog window to a new string + // the first old text portion will be maintained if its a new string, + // otherwise we use the original one. + aNewStringList = aOldStringList; + } + else + { + // If the new title setted from a dialog to a new string the first + // old text portion will be maintained if there was any. Also in case of ODF + // import which still not support non-uniform formatted titles + aNewStringList = { aOldStringList[0] }; + aNewStringList[0]->setString(aNewText); + } } else { diff --git a/chart2/uiconfig/menubar/menubar.xml b/chart2/uiconfig/menubar/menubar.xml index 58c84d6cbc33..e295d77a3943 100644 --- a/chart2/uiconfig/menubar/menubar.xml +++ b/chart2/uiconfig/menubar/menubar.xml @@ -120,6 +120,7 @@ <menu:menuitem menu:id=".uno:View3D"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:FormatSelection" menu:style="text"/> + <menu:menuitem menu:id=".uno:FontDialog" menu:style="text"/> <menu:menuitem menu:id=".uno:TransformDialog" menu:style="text"/> <menu:menu menu:id=".uno:ArrangeRow"> <menu:menupopup> diff --git a/chart2/uiconfig/toolbar/toolbar.xml b/chart2/uiconfig/toolbar/toolbar.xml index 809174ba206d..21105871c095 100644 --- a/chart2/uiconfig/toolbar/toolbar.xml +++ b/chart2/uiconfig/toolbar/toolbar.xml @@ -20,6 +20,7 @@ <toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink"> <toolbar:toolbaritem xlink:href=".uno:ChartElementSelector"/> <toolbar:toolbaritem xlink:href=".uno:FormatSelection"/> + <toolbar:toolbaritem xlink:href=".uno:FontDialog"/> <toolbar:toolbarseparator/> <toolbar:toolbaritem xlink:href=".uno:DiagramType"/> <toolbar:toolbaritem xlink:href=".uno:DiagramArea"/> commit a0d5fea9c3324af467b6f7728f1dfb7bfe4e5452 Author: Noel Grandin <[email protected]> AuthorDate: Wed Mar 6 09:43:28 2024 +0200 Commit: Balazs Varga <[email protected]> CommitDate: Wed Apr 3 10:18:25 2024 +0200 tdf#158773 reduce cost of ContentInfo::GetText The specific path that is showing up on the perf profile is SdrTextObj::HasText -> EditTextObjectImpl::GetText -> ContentInfo::GetText Reduce the cost by 10% there by adding a method to check if we have text, and avoid the cost of constructing an OUString from an svl::SharedString. Also make use of the new method in places. Change-Id: Ibc2e0f61c4a2a6c33eea7f2cce09d692d82fd2b2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164449 Tested-by: Noel Grandin <[email protected]> Reviewed-by: Noel Grandin <[email protected]> diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx index d0ec8632f134..a508e197f266 100644 --- a/editeng/source/editeng/editobj.cxx +++ b/editeng/source/editeng/editobj.cxx @@ -138,6 +138,12 @@ OUString ContentInfo::GetText() const return OUString(p); } +sal_Int32 ContentInfo::GetTextLen() const +{ + const rtl_uString* p = maText.getData(); + return p->length; +} + void ContentInfo::SetText( const OUString& rStr ) { maText = svl::SharedString(rStr.pData, nullptr); @@ -410,6 +416,14 @@ OUString EditTextObjectImpl::GetText(sal_Int32 nPara) const return maContents[nPara]->GetText(); } +sal_Int32 EditTextObjectImpl::GetTextLen(sal_Int32 nPara ) const +{ + if (nPara < 0 || o3tl::make_unsigned(nPara) >= maContents.size()) + return 0; + + return maContents[nPara]->GetTextLen(); +} + void EditTextObjectImpl::ClearPortionInfo() { mpPortionInfo.reset(); diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx index 86c81e23f94e..81151448ee11 100644 --- a/editeng/source/editeng/editobj2.hxx +++ b/editeng/source/editeng/editobj2.hxx @@ -142,6 +142,7 @@ public: const svl::SharedString& GetSharedString() const { return maText;} OUString GetText() const; void SetText( const OUString& rStr ); + sal_Int32 GetTextLen() const; void dumpAsXml(xmlTextWriterPtr pWriter) const; @@ -228,6 +229,7 @@ public: virtual sal_Int32 GetParagraphCount() const override; virtual OUString GetText(sal_Int32 nParagraph) const override; + virtual sal_Int32 GetTextLen(sal_Int32 nParagraph) const override; virtual void ClearPortionInfo() override; diff --git a/editeng/source/outliner/overflowingtxt.cxx b/editeng/source/outliner/overflowingtxt.cxx index 42316fa1fa34..5943d7be6c54 100644 --- a/editeng/source/outliner/overflowingtxt.cxx +++ b/editeng/source/outliner/overflowingtxt.cxx @@ -45,7 +45,7 @@ std::optional<OutlinerParaObject> TextChainingUtils::JuxtaposeParaObject( // Special case: if only empty text remove it at the end bool bOnlyOneEmptyPara = !pNextPObj || (pOutl->GetParagraphCount() == 1 && - pNextPObj->GetTextObject().GetText(0).isEmpty()); + !pNextPObj->GetTextObject().HasText(0)); EditEngine &rEditEngine = const_cast<EditEngine &>(pOutl->GetEditEngine()); diff --git a/include/editeng/editobj.hxx b/include/editeng/editobj.hxx index 5badaf8e8a2a..b78b1a918b27 100644 --- a/include/editeng/editobj.hxx +++ b/include/editeng/editobj.hxx @@ -87,6 +87,10 @@ public: virtual OUString GetText(sal_Int32 nPara) const = 0; + virtual sal_Int32 GetTextLen(sal_Int32 nPara) const = 0; + + bool HasText(sal_Int32 nPara) const { return GetTextLen(nPara) > 0; } + virtual void ClearPortionInfo() = 0; virtual bool HasOnlineSpellErrors() const = 0; diff --git a/sc/source/filter/xcl97/xcl97rec.cxx b/sc/source/filter/xcl97/xcl97rec.cxx index f9031449bf70..3c054416d9b9 100644 --- a/sc/source/filter/xcl97/xcl97rec.cxx +++ b/sc/source/filter/xcl97/xcl97rec.cxx @@ -921,8 +921,7 @@ XclTxo::XclTxo( const XclExpRoot& rRoot, const EditTextObject& rEditObj, SdrObje // Excel has one alignment per NoteObject while Calc supports // one alignment per paragraph - use the first paragraph // alignment (if set) as our overall alignment. - OUString aParaText( rEditObj.GetText( 0 ) ); - if( !aParaText.isEmpty() ) + if( rEditObj.HasText( 0 ) ) { const SfxItemSet& aSet( rEditObj.GetParaAttribs( 0)); if( const SvxAdjustItem* pItem = aSet.GetItemIfSet( EE_PARA_JUST ) ) diff --git a/sc/source/ui/Accessibility/AccessiblePageHeader.cxx b/sc/source/ui/Accessibility/AccessiblePageHeader.cxx index 075f72b0c349..2c72bf64318c 100644 --- a/sc/source/ui/Accessibility/AccessiblePageHeader.cxx +++ b/sc/source/ui/Accessibility/AccessiblePageHeader.cxx @@ -348,7 +348,7 @@ bool ScAccessiblePageHeader::IsDefunc( sal_Int64 nParentStates ) void ScAccessiblePageHeader::AddChild(const EditTextObject* pArea, sal_uInt32 nIndex, SvxAdjust eAdjust) { - if (pArea && (!pArea->GetText(0).isEmpty() || (pArea->GetParagraphCount() > 1))) + if (pArea && ((pArea->GetParagraphCount() > 1) || pArea->HasText(0))) { if (maAreas[nIndex].is()) { diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx index a5c17784fbf9..38a0e02534ff 100644 --- a/sc/source/ui/view/viewfunc.cxx +++ b/sc/source/ui/view/viewfunc.cxx @@ -832,7 +832,7 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, pDocSh->UpdateOle(GetViewData()); bool bIsEmpty = rData.GetParagraphCount() == 0 - || (rData.GetParagraphCount() == 1 && rData.GetText(0).isEmpty()); + || (rData.GetParagraphCount() == 1 && !rData.HasText(0)); const OUString aType(bIsEmpty ? u"delete-content" : u"cell-change"); HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, rMark, nCol, nRow, aType); diff --git a/sd/source/filter/ppt/pptinanimations.cxx b/sd/source/filter/ppt/pptinanimations.cxx index 07a36e0eec98..9de191f2d068 100644 --- a/sd/source/filter/ppt/pptinanimations.cxx +++ b/sd/source/filter/ppt/pptinanimations.cxx @@ -2523,7 +2523,7 @@ void AnimationImporter::importTargetElementContainer( const Atom* pAtom, Any& rT while( (nPara < nParaCount) && (begin > 0) ) { - sal_Int32 nParaLength = rEditTextObject.GetText( nPara ).getLength() + 1; + sal_Int32 nParaLength = rEditTextObject.GetTextLen( nPara ) + 1; begin -= nParaLength; end -= nParaLength; nPara++; diff --git a/svx/source/svdraw/svdotxat.cxx b/svx/source/svdraw/svdotxat.cxx index 35a467327dc9..1158deb8c160 100644 --- a/svx/source/svdraw/svdotxat.cxx +++ b/svx/source/svdraw/svdotxat.cxx @@ -424,17 +424,16 @@ bool SdrTextObj::HasText() const OutlinerParaObject* pOPO = GetOutlinerParaObject(); - bool bHasText = false; - if( pOPO ) - { - const EditTextObject& rETO = pOPO->GetTextObject(); - sal_Int32 nParaCount = rETO.GetParagraphCount(); - - if( nParaCount > 0 ) - bHasText = (nParaCount > 1) || (!rETO.GetText( 0 ).isEmpty()); - } + if( !pOPO ) + return false; - return bHasText; + const EditTextObject& rETO = pOPO->GetTextObject(); + sal_Int32 nParaCount = rETO.GetParagraphCount(); + if( nParaCount == 0 ) + return false; + if( nParaCount > 1 ) + return true; + return rETO.HasText( 0 ); } void SdrTextObj::AppendFamilyToStyleName(OUString& styleName, SfxStyleFamily family) diff --git a/svx/source/table/cell.cxx b/svx/source/table/cell.cxx index bbef530c3dd1..74a8b822f539 100644 --- a/svx/source/table/cell.cxx +++ b/svx/source/table/cell.cxx @@ -562,7 +562,7 @@ bool Cell::hasText() const { if( rTextObj.GetParagraphCount() == 1 ) { - if( rTextObj.GetText(0).isEmpty() ) + if( !rTextObj.HasText(0) ) return false; } return true; diff --git a/sw/source/uibase/docvw/AnnotationWin.cxx b/sw/source/uibase/docvw/AnnotationWin.cxx index 3d350048055b..8bb2fcec68aa 100644 --- a/sw/source/uibase/docvw/AnnotationWin.cxx +++ b/sw/source/uibase/docvw/AnnotationWin.cxx @@ -441,7 +441,7 @@ void SwAnnotationWin::InitAnswer(OutlinerParaObject const & rText) // insert old, selected text or "..." // TODO: iterate over all paragraphs, not only first one to find out if it is empty - if (!rText.GetTextObject().GetText(0).isEmpty()) + if (rText.GetTextObject().HasText(0)) GetOutlinerView()->GetEditView().InsertText(rText.GetTextObject()); else GetOutlinerView()->InsertText("..."); commit b3463ecc332145333b3411897e66111207322da6 Author: Balazs Varga <[email protected]> AuthorDate: Thu Mar 28 17:17:47 2024 +0100 Commit: Balazs Varga <[email protected]> CommitDate: Wed Apr 3 10:04:56 2024 +0200 tdf#78027 - Fix Chart OOXML Import with non-uniform formatted titles Character formats are disappeared from Chart Title textobjects if they were formatted non-uniform. In this patch only the OOXML import and the chartview part will be fixed which make it visible after the import. (Note: next patch will contain the chart controller part where the characters can be formatted during title editing). cherry-picked from commit: f31a8ff9ea15ad81aeac265fce6eafe6342a68b7 Change-Id: I4fb5c3d80b7889935d198e70fb49e2c68108b235 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165500 Tested-by: Jenkins Tested-by: Gabor Kelemen <[email protected]> Reviewed-by: Balazs Varga <[email protected]> diff --git a/chart2/source/view/main/PropertyMapper.cxx b/chart2/source/view/main/PropertyMapper.cxx index 2700769f595c..2b2934c47efd 100644 --- a/chart2/source/view/main/PropertyMapper.cxx +++ b/chart2/source/view/main/PropertyMapper.cxx @@ -268,7 +268,8 @@ const tPropertyNameMap& PropertyMapper::getPropertyNameMapForCharacterProperties {"CharColor", "CharColor"}, {"CharContoured", "CharContoured"}, {"CharEmphasis", "CharEmphasis"},//the service style::CharacterProperties describes a property called 'CharEmphasize' which is nowhere implemented - + {"CharEscapement", "CharEscapement"}, + {"CharEscapementHeight", "CharEscapementHeight"}, {"CharFontFamily", "CharFontFamily"}, {"CharFontFamilyAsian", "CharFontFamilyAsian"}, {"CharFontFamilyComplex", "CharFontFamilyComplex"}, diff --git a/chart2/source/view/main/ShapeFactory.cxx b/chart2/source/view/main/ShapeFactory.cxx index f9efceb676a5..1384372cda33 100644 --- a/chart2/source/view/main/ShapeFactory.cxx +++ b/chart2/source/view/main/ShapeFactory.cxx @@ -2177,7 +2177,8 @@ rtl::Reference<SvxShapeText> //set text and text properties uno::Reference< text::XTextCursor > xTextCursor( xShape->createTextCursor() ); - if( !xTextCursor.is() ) + uno::Reference< text::XTextCursor > xSelectionCursor( xShape->createTextCursor() ); + if( !xTextCursor.is() || !xSelectionCursor.is() ) return xShape; tPropertyNameValueMap aValueMap; @@ -2226,18 +2227,32 @@ rtl::Reference<SvxShapeText> //if the characters should be stacked we use only the first character properties for code simplicity if( xFormattedString.hasElements() ) { - OUString aLabel; - for( const auto & i : std::as_const(xFormattedString) ) - aLabel += i->getString(); - aLabel = ShapeFactory::getStackedString( aLabel, bStackCharacters ); - - xTextCursor->gotoEnd(false); - xShape->insertString( xTextCursor, aLabel, false ); - xTextCursor->gotoEnd(true); - uno::Reference< beans::XPropertySet > xSourceProps( xFormattedString[0], uno::UNO_QUERY ); - - PropertyMapper::setMappedProperties( *xShape, xSourceProps - , PropertyMapper::getPropertyNameMapForCharacterProperties() ); + size_t nLBreaks = xFormattedString.size() - 1; + uno::Reference< beans::XPropertySet > xSelectionProp(xSelectionCursor, uno::UNO_QUERY); + for (const uno::Reference<chart2::XFormattedString>& rxFS : xFormattedString) + { + if (!rxFS->getString().isEmpty()) + { + xTextCursor->gotoEnd(false); + xSelectionCursor->gotoEnd(false); + OUString aLabel = ShapeFactory::getStackedString(rxFS->getString(), bStackCharacters); + if (nLBreaks-- > 0) + aLabel += OUStringChar(' '); + xShape->insertString(xTextCursor, aLabel, false); + xSelectionCursor->gotoEnd(true); // select current paragraph + uno::Reference< beans::XPropertySet > xSourceProps(rxFS, uno::UNO_QUERY); + if (xFormattedString.size() > 1 && xSelectionProp.is()) + { + PropertyMapper::setMappedProperties(xSelectionProp, xSourceProps, + PropertyMapper::getPropertyNameMapForTextShapeProperties()); + } + else + { + PropertyMapper::setMappedProperties(*xShape, xSourceProps, + PropertyMapper::getPropertyNameMapForTextShapeProperties()); + } + } + } // adapt font size according to page size awt::Size aOldRefSize; @@ -2249,23 +2264,34 @@ rtl::Reference<SvxShapeText> } else { - for( const uno::Reference< chart2::XFormattedString >& rxFS : std::as_const(xFormattedString) ) + uno::Reference< beans::XPropertySet > xSelectionProp(xSelectionCursor, uno::UNO_QUERY); + for (const uno::Reference<chart2::XFormattedString>& rxFS : xFormattedString) { - xTextCursor->gotoEnd(false); - xShape->insertString( xTextCursor, rxFS->getString(), false ); - xTextCursor->gotoEnd(true); + if (!rxFS->getString().isEmpty()) + { + xTextCursor->gotoEnd(false); + xSelectionCursor->gotoEnd(false); + xShape->insertString(xTextCursor, rxFS->getString(), false); + xSelectionCursor->gotoEnd(true); // select current paragraph + uno::Reference< beans::XPropertySet > xSourceProps(rxFS, uno::UNO_QUERY); + if (xFormattedString.size() > 1 && xSelectionProp.is()) + { + PropertyMapper::setMappedProperties(xSelectionProp, xSourceProps, + PropertyMapper::getPropertyNameMapForTextShapeProperties()); + } + else + { + PropertyMapper::setMappedProperties(*xShape, xSourceProps, + PropertyMapper::getPropertyNameMapForTextShapeProperties()); + } + } } - awt::Size aOldRefSize; - bool bHasRefPageSize = - ( xTextProperties->getPropertyValue( "ReferencePageSize") >>= aOldRefSize ); if( xFormattedString.hasElements() ) { - uno::Reference< beans::XPropertySet > xSourceProps( xFormattedString[0], uno::UNO_QUERY ); - PropertyMapper::setMappedProperties( *xShape, xSourceProps, PropertyMapper::getPropertyNameMapForCharacterProperties() ); - // adapt font size according to page size - if( bHasRefPageSize ) + awt::Size aOldRefSize; + if( xTextProperties->getPropertyValue("ReferencePageSize") >>= aOldRefSize ) { RelativeSizeHelper::adaptFontSizes( *xShape, aOldRefSize, rSize ); } diff --git a/oox/inc/drawingml/textcharacterproperties.hxx b/oox/inc/drawingml/textcharacterproperties.hxx index 40842585d10a..9750407b817c 100644 --- a/oox/inc/drawingml/textcharacterproperties.hxx +++ b/oox/inc/drawingml/textcharacterproperties.hxx @@ -64,6 +64,12 @@ struct TextCharacterProperties /// Set if there was a property set that alters run visually during import bool mbHasVisualRunProperties; + /// Set if there was an empty paragraph property set during import + /// <a:pPr><a:defRPr/></a:pPr> + /// In that case we use the default paragraph properties from the + /// <c:txPr><a:p><a:pPr><a:defRPr>...</a:defRPr> + bool mbHasEmptyParaProperties; + std::vector<css::beans::PropertyValue> maTextEffectsProperties; /** Overwrites all members that are explicitly set in rSourceProps. */ @@ -84,7 +90,7 @@ struct TextCharacterProperties PropertySet& rPropSet, const ::oox::core::XmlFilterBase& rFilter ) const; - TextCharacterProperties() : mbHasVisualRunProperties(false) {} + TextCharacterProperties() : mbHasVisualRunProperties(false), mbHasEmptyParaProperties(false) {} }; diff --git a/oox/source/drawingml/chart/titleconverter.cxx b/oox/source/drawingml/chart/titleconverter.cxx index 91684393c627..e09108f6a171 100644 --- a/oox/source/drawingml/chart/titleconverter.cxx +++ b/oox/source/drawingml/chart/titleconverter.cxx @@ -90,7 +90,16 @@ Sequence< Reference< XFormattedString > > TextConverter::createStringSequence( bool bAddNewLine = ((aRIt + 1 == aREnd) && (aPIt + 1 != aPEnd)) || rTextRun.isLineBreak(); Reference< XFormattedString > xFmtStr = appendFormattedString( aStringVec, rTextRun.getText(), bAddNewLine ); PropertySet aPropSet( xFmtStr ); - TextCharacterProperties aRunProps( rParaProps ); + TextCharacterProperties aRunProps; + if (rParaProps.mbHasEmptyParaProperties && rxTextProp.is() && rxTextProp->hasParagraphProperties()) + { + const TextParagraphVector rDefTextParas = rxTextProp->getParagraphs(); + TextParagraphVector::const_iterator aDefPIt = rDefTextParas.begin(); + const TextParagraph& rDefTextPara = **aDefPIt; + aRunProps = rDefTextPara.getProperties().getTextCharacterProperties(); + } + else + aRunProps = rParaProps; aRunProps.assignUsed( rTextRun.getTextCharacterProperties() ); getFormatter().convertTextFormatting( aPropSet, aRunProps, eObjType ); } diff --git a/oox/source/drawingml/textcharacterpropertiescontext.cxx b/oox/source/drawingml/textcharacterpropertiescontext.cxx index fb4390e4c7a7..4935e8a75a68 100644 --- a/oox/source/drawingml/textcharacterpropertiescontext.cxx +++ b/oox/source/drawingml/textcharacterpropertiescontext.cxx @@ -50,6 +50,9 @@ TextCharacterPropertiesContext::TextCharacterPropertiesContext( int nVisualTokenAmount = sax_fastparser::castToFastAttributeList( rAttribs.getFastAttributeList() ).getFastAttributeTokens().size(); + if (nVisualTokenAmount == 0) + mrTextCharacterProperties.mbHasEmptyParaProperties = true; + if ( rAttribs.hasAttribute( XML_lang ) ) { mrTextCharacterProperties.moLang = rAttribs.getString( XML_lang );
