editeng/source/editeng/impedit.hxx | 4 editeng/source/editeng/impedit2.cxx | 2 editeng/source/editeng/impedit5.cxx | 2 editeng/source/uno/unoedprx.cxx | 14 + editeng/source/uno/unofored.cxx | 14 + editeng/source/uno/unoforou.cxx | 14 + editeng/source/uno/unotext.cxx | 54 ++++ include/editeng/unoedprx.hxx | 3 include/editeng/unoedsrc.hxx | 3 include/editeng/unofored.hxx | 3 include/editeng/unoforou.hxx | 5 include/editeng/unotext.hxx | 4 include/svl/style.hxx | 2 svl/source/items/style.cxx | 2 svx/source/accessibility/AccessibleEmptyEditSource.cxx | 3 svx/source/dialog/weldeditview.cxx | 20 + sw/inc/docstyle.hxx | 4 sw/inc/docufld.hxx | 1 sw/qa/extras/odfexport/odfexport2.cxx | 29 ++ sw/source/core/fields/docufld.cxx | 6 sw/source/core/fields/textapi.cxx | 61 +++-- sw/source/core/inc/textapi.hxx | 1 sw/source/uibase/app/docstyle.cxx | 191 ++++++++++++++++- sw/source/uibase/docvw/AnnotationWin2.cxx | 5 sw/source/uibase/docvw/PostItMgr.cxx | 14 + 25 files changed, 428 insertions(+), 33 deletions(-)
New commits: commit 6c4edf7f86912084371e15be7321e9c4764a9ca6 Author: Maxim Monastirsky <momonas...@gmail.com> AuthorDate: Thu Jun 15 11:36:43 2023 +0300 Commit: Maxim Monastirsky <momonas...@gmail.com> CommitDate: Fri Jun 16 00:48:56 2023 +0200 tdf#103064 sw,editeng: enable UNO API and ODF import/export Change-Id: Icf30e1f30fe6bf6a7d96d14b975954613cd68b70 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153157 Tested-by: Jenkins Reviewed-by: Maxim Monastirsky <momonas...@gmail.com> diff --git a/editeng/source/uno/unoedprx.cxx b/editeng/source/uno/unoedprx.cxx index 5bddd24fca7a..20d5df281bce 100644 --- a/editeng/source/uno/unoedprx.cxx +++ b/editeng/source/uno/unoedprx.cxx @@ -530,6 +530,20 @@ void SvxAccessibleTextAdapter::GetPortions( sal_Int32 nPara, std::vector<sal_Int mpTextForwarder->GetPortions( nPara, rList ); } +OUString SvxAccessibleTextAdapter::GetStyleSheet(sal_Int32 nPara) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetStyleSheet(nPara); +} + +void SvxAccessibleTextAdapter::SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + mpTextForwarder->SetStyleSheet(nPara, rStyleName); +} + SfxItemState SvxAccessibleTextAdapter::GetItemState( const ESelection& rSel, sal_uInt16 nWhich ) const { assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); diff --git a/editeng/source/uno/unofored.cxx b/editeng/source/uno/unofored.cxx index 5e1824ff5dca..66f4fde2bf78 100644 --- a/editeng/source/uno/unofored.cxx +++ b/editeng/source/uno/unofored.cxx @@ -124,6 +124,20 @@ void SvxEditEngineForwarder::GetPortions( sal_Int32 nPara, std::vector<sal_Int32 rEditEngine.GetPortions( nPara, rList ); } +OUString SvxEditEngineForwarder::GetStyleSheet(sal_Int32 nPara) const +{ + if (auto pStyle = rEditEngine.GetStyleSheet(nPara)) + return pStyle->GetName(); + return OUString(); +} + +void SvxEditEngineForwarder::SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) +{ + auto pStyleSheetPool = rEditEngine.GetStyleSheetPool(); + if (auto pStyle = pStyleSheetPool ? pStyleSheetPool->Find(rStyleName, SfxStyleFamily::Para) : nullptr) + rEditEngine.SetStyleSheet(nPara, static_cast<SfxStyleSheet*>(pStyle)); +} + void SvxEditEngineForwarder::QuickInsertText( const OUString& rText, const ESelection& rSel ) { rEditEngine.QuickInsertText( rText, rSel ); diff --git a/editeng/source/uno/unoforou.cxx b/editeng/source/uno/unoforou.cxx index f6d0fbb8eaea..8772ff9a77fa 100644 --- a/editeng/source/uno/unoforou.cxx +++ b/editeng/source/uno/unoforou.cxx @@ -186,6 +186,20 @@ void SvxOutlinerForwarder::GetPortions( sal_Int32 nPara, std::vector<sal_Int32>& const_cast<EditEngine&>(rOutliner.GetEditEngine()).GetPortions( nPara, rList ); } +OUString SvxOutlinerForwarder::GetStyleSheet(sal_Int32 nPara) const +{ + if (auto pStyle = rOutliner.GetStyleSheet(nPara)) + return pStyle->GetName(); + return OUString(); +} + +void SvxOutlinerForwarder::SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) +{ + auto pStyleSheetPool = rOutliner.GetStyleSheetPool(); + if (auto pStyle = pStyleSheetPool ? pStyleSheetPool->Find(rStyleName, SfxStyleFamily::Para) : nullptr) + rOutliner.SetStyleSheet(nPara, static_cast<SfxStyleSheet*>(pStyle)); +} + void SvxOutlinerForwarder::QuickInsertText( const OUString& rText, const ESelection& rSel ) { flushCache(); diff --git a/editeng/source/uno/unotext.cxx b/editeng/source/uno/unotext.cxx index 6f78a4a66878..eb18d69903c4 100644 --- a/editeng/source/uno/unotext.cxx +++ b/editeng/source/uno/unotext.cxx @@ -431,7 +431,30 @@ void SvxUnoTextRangeBase::_setPropertyValue( const OUString& PropertyName, const ESelection aSel( GetSelection() ); bool bParaAttrib = (pMap->nWID >= EE_PARA_START) && ( pMap->nWID <= EE_PARA_END ); - if( nPara == -1 && !bParaAttrib ) + if (pMap->nWID == WID_PARASTYLENAME) + { + OUString aStyle = aValue.get<OUString>(); + + sal_Int32 nEndPara; + + if( nPara == -1 ) + { + nPara = aSel.nStartPara; + nEndPara = aSel.nEndPara; + } + else + { + // only one paragraph + nEndPara = nPara; + } + + while( nPara <= nEndPara ) + { + pForwarder->SetStyleSheet(nPara, aStyle); + nPara++; + } + } + else if ( nPara == -1 && !bParaAttrib ) { SfxItemSet aOldSet( pForwarder->GetAttribs( aSel ) ); // we have a selection and no para attribute @@ -653,6 +676,12 @@ void SvxUnoTextRangeBase::getPropertyValue( const SfxItemPropertyMapEntry* pMap, } break; + case WID_PARASTYLENAME: + { + rAny <<= GetEditSource()->GetTextForwarder()->GetStyleSheet(maSelection.nStartPara); + } + break; + default: if(!GetPropertyValueHelper( *const_cast<SfxItemSet*>(&rSet), pMap, rAny, &maSelection, GetEditSource() )) rAny = SvxItemPropertySet::getPropertyValue(pMap, rSet, true, false ); @@ -780,6 +809,8 @@ void SvxUnoTextRangeBase::_setPropertyValues( const uno::Sequence< OUString >& a std::optional<SfxItemSet> pOldParaSet; std::optional<SfxItemSet> pNewParaSet; + std::optional<OUString> aStyleName; + for( ; nCount; nCount--, pPropertyNames++, pValues++ ) { const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry( *pPropertyNames ); @@ -788,7 +819,11 @@ void SvxUnoTextRangeBase::_setPropertyValues( const uno::Sequence< OUString >& a { bool bParaAttrib = (pMap->nWID >= EE_PARA_START) && ( pMap->nWID <= EE_PARA_END ); - if( (nPara == -1) && !bParaAttrib ) + if (pMap->nWID == WID_PARASTYLENAME) + { + aStyleName.emplace((*pValues).get<OUString>()); + } + else if( (nPara == -1) && !bParaAttrib ) { if( !pNewAttrSet ) { @@ -833,7 +868,7 @@ void SvxUnoTextRangeBase::_setPropertyValues( const uno::Sequence< OUString >& a bool bNeedsUpdate = false; - if( pNewParaSet ) + if( pNewParaSet || aStyleName ) { if( pNewParaSet->Count() ) { @@ -842,6 +877,8 @@ void SvxUnoTextRangeBase::_setPropertyValues( const uno::Sequence< OUString >& a SfxItemSet aSet( pForwarder->GetParaAttribs( nTempPara ) ); aSet.Put( *pNewParaSet ); pForwarder->SetParaAttribs( nTempPara, aSet ); + if (aStyleName) + pForwarder->SetStyleSheet(nTempPara, *aStyleName); nTempPara++; } bNeedsUpdate = true; @@ -984,6 +1021,7 @@ beans::PropertyState SvxUnoTextRangeBase::_getPropertyState(const SfxItemPropert case WID_NUMBERINGSTARTVALUE: case WID_PARAISNUMBERINGRESTART: + case WID_PARASTYLENAME: eItemState = SfxItemState::SET; bItemStateSet = true; break; @@ -1117,6 +1155,7 @@ bool SvxUnoTextRangeBase::_getOnePropertyStates(const SfxItemSet* pSet, const Sf case WID_NUMBERINGSTARTVALUE: case WID_PARAISNUMBERINGRESTART: + case WID_PARASTYLENAME: eItemState = SfxItemState::SET; bItemStateSet = true; break; @@ -2310,6 +2349,15 @@ void SvxDummyTextSource::GetPortions( sal_Int32, std::vector<sal_Int32>& ) const { } +OUString SvxDummyTextSource::GetStyleSheet(sal_Int32) const +{ + return OUString(); +} + +void SvxDummyTextSource::SetStyleSheet(sal_Int32, const OUString&) +{ +} + SfxItemState SvxDummyTextSource::GetItemState( const ESelection&, sal_uInt16 ) const { return SfxItemState::UNKNOWN; diff --git a/include/editeng/unoedprx.hxx b/include/editeng/unoedprx.hxx index 475cd158934b..22b6be0c91e3 100644 --- a/include/editeng/unoedprx.hxx +++ b/include/editeng/unoedprx.hxx @@ -46,6 +46,9 @@ public: sal_Int32 CalcEditEngineIndex( sal_Int32 nPara, sal_Int32 nLogicalIndex ); + virtual OUString GetStyleSheet(sal_Int32 nPara) const override; + virtual void SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) override; + virtual SfxItemState GetItemState( const ESelection& rSel, sal_uInt16 nWhich ) const override; virtual SfxItemState GetItemState( sal_Int32 nPara, sal_uInt16 nWhich ) const override; diff --git a/include/editeng/unoedsrc.hxx b/include/editeng/unoedsrc.hxx index 007633616b19..1537f00a743c 100644 --- a/include/editeng/unoedsrc.hxx +++ b/include/editeng/unoedsrc.hxx @@ -152,6 +152,9 @@ public: virtual void RemoveAttribs( const ESelection& rSelection ) = 0; virtual void GetPortions( sal_Int32 nPara, std::vector<sal_Int32>& rList ) const = 0; + virtual OUString GetStyleSheet(sal_Int32 nPara) const = 0; + virtual void SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) = 0; + virtual SfxItemState GetItemState( const ESelection& rSel, sal_uInt16 nWhich ) const = 0; virtual SfxItemState GetItemState( sal_Int32 nPara, sal_uInt16 nWhich ) const = 0; diff --git a/include/editeng/unofored.hxx b/include/editeng/unofored.hxx index 7429cb21e53f..323095f85f0b 100644 --- a/include/editeng/unofored.hxx +++ b/include/editeng/unofored.hxx @@ -44,6 +44,9 @@ public: virtual void RemoveAttribs( const ESelection& rSelection ) override; virtual void GetPortions( sal_Int32 nPara, std::vector<sal_Int32>& rList ) const override; + virtual OUString GetStyleSheet(sal_Int32 nPara) const override; + virtual void SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) override; + virtual SfxItemState GetItemState( const ESelection& rSel, sal_uInt16 nWhich ) const override; virtual SfxItemState GetItemState( sal_Int32 nPara, sal_uInt16 nWhich ) const override; diff --git a/include/editeng/unoforou.hxx b/include/editeng/unoforou.hxx index 4c8d17fd3ca0..646c44a39e8f 100644 --- a/include/editeng/unoforou.hxx +++ b/include/editeng/unoforou.hxx @@ -30,7 +30,7 @@ class Outliner; // SvxOutlinerForwarder - SvxTextForwarder for Outliner -class EDITENG_DLLPUBLIC SvxOutlinerForwarder final : public SvxTextForwarder +class EDITENG_DLLPUBLIC SvxOutlinerForwarder : public SvxTextForwarder { private: Outliner& rOutliner; @@ -63,6 +63,9 @@ public: virtual void RemoveAttribs( const ESelection& rSelection ) override; virtual void GetPortions( sal_Int32 nPara, std::vector<sal_Int32>& rList ) const override; + virtual OUString GetStyleSheet(sal_Int32 nPara) const override; + virtual void SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) override; + virtual SfxItemState GetItemState( const ESelection& rSel, sal_uInt16 nWhich ) const override; virtual SfxItemState GetItemState( sal_Int32 nPara, sal_uInt16 nWhich ) const override; diff --git a/include/editeng/unotext.hxx b/include/editeng/unotext.hxx index 84dc7d9fdb6f..de79cae965f2 100644 --- a/include/editeng/unotext.hxx +++ b/include/editeng/unotext.hxx @@ -64,6 +64,7 @@ struct SfxItemPropertyMapEntry; #define WID_PORTIONTYPE OWN_ATTR_VALUE_START+2 #define WID_NUMBERINGSTARTVALUE OWN_ATTR_VALUE_START+3 #define WID_PARAISNUMBERINGRESTART OWN_ATTR_VALUE_START+4 +#define WID_PARASTYLENAME OWN_ATTR_VALUE_START+5 #define SVX_UNOEDIT_NUMBERING_PROPERTY \ { UNO_NAME_NUMBERING_RULES, EE_PARA_NUMBULLET, cppu::UnoType<css::container::XIndexReplace>::get(), 0, 0 }, \ @@ -187,6 +188,9 @@ public: virtual void RemoveAttribs( const ESelection& rSelection ) override; virtual void GetPortions( sal_Int32 nPara, std::vector<sal_Int32>& rList ) const override; + virtual OUString GetStyleSheet(sal_Int32 nPara) const override; + virtual void SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) override; + SfxItemState GetItemState( const ESelection& rSel, sal_uInt16 nWhich ) const override; SfxItemState GetItemState( sal_Int32 nPara, sal_uInt16 nWhich ) const override; diff --git a/svx/source/accessibility/AccessibleEmptyEditSource.cxx b/svx/source/accessibility/AccessibleEmptyEditSource.cxx index 5f883a45986c..7ff9ec6610f7 100644 --- a/svx/source/accessibility/AccessibleEmptyEditSource.cxx +++ b/svx/source/accessibility/AccessibleEmptyEditSource.cxx @@ -103,6 +103,9 @@ namespace accessibility void RemoveAttribs( const ESelection& /*rSelection*/ ) override {} void GetPortions( sal_Int32 /*nPara*/, std::vector<sal_Int32>& /*rList*/ ) const override {} + OUString GetStyleSheet(sal_Int32 /*nPara*/) const override { return OUString(); } + void SetStyleSheet(sal_Int32 /*nPara*/, const OUString& /*rStyleName*/) override {} + SfxItemState GetItemState( const ESelection& /*rSel*/, sal_uInt16 /*nWhich*/ ) const override { return SfxItemState::UNKNOWN; } SfxItemState GetItemState( sal_Int32 /*nPara*/, sal_uInt16 /*nWhich*/ ) const override { return SfxItemState::UNKNOWN; } diff --git a/svx/source/dialog/weldeditview.cxx b/svx/source/dialog/weldeditview.cxx index e1e0d19617ff..886f01beebe1 100644 --- a/svx/source/dialog/weldeditview.cxx +++ b/svx/source/dialog/weldeditview.cxx @@ -371,6 +371,9 @@ public: virtual void RemoveAttribs(const ESelection& rSelection) override; virtual void GetPortions(sal_Int32 nPara, std::vector<sal_Int32>& rList) const override; + virtual OUString GetStyleSheet(sal_Int32 nPara) const override; + virtual void SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) override; + virtual SfxItemState GetItemState(const ESelection& rSel, sal_uInt16 nWhich) const override; virtual SfxItemState GetItemState(sal_Int32 nPara, sal_uInt16 nWhich) const override; @@ -1019,6 +1022,23 @@ void WeldTextForwarder::GetPortions(sal_Int32 nPara, std::vector<sal_Int32>& rLi pEditEngine->GetPortions(nPara, rList); } +OUString WeldTextForwarder::GetStyleSheet(sal_Int32 nPara) const +{ + EditEngine* pEditEngine = m_rEditAcc.GetEditEngine(); + if (auto pStyle = pEditEngine ? pEditEngine->GetStyleSheet(nPara) : nullptr) + return pStyle->GetName(); + return OUString(); +} + +void WeldTextForwarder::SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) +{ + EditEngine* pEditEngine = m_rEditAcc.GetEditEngine(); + auto pStyleSheetPool = pEditEngine ? pEditEngine->GetStyleSheetPool() : nullptr; + if (auto pStyle + = pStyleSheetPool ? pStyleSheetPool->Find(rStyleName, SfxStyleFamily::Para) : nullptr) + pEditEngine->SetStyleSheet(nPara, static_cast<SfxStyleSheet*>(pStyle)); +} + void WeldTextForwarder::QuickInsertText(const OUString& rText, const ESelection& rSel) { EditEngine* pEditEngine = m_rEditAcc.GetEditEngine(); diff --git a/sw/qa/extras/odfexport/odfexport2.cxx b/sw/qa/extras/odfexport/odfexport2.cxx index 46e192eaf3eb..0da6c7865c99 100644 --- a/sw/qa/extras/odfexport/odfexport2.cxx +++ b/sw/qa/extras/odfexport/odfexport2.cxx @@ -1071,6 +1071,35 @@ CPPUNIT_TEST_FIXTURE(Test, testParagraphMarkerMarkupRoundtrip) assertXPath(pXmlDoc, "/office:document-content/office:automatic-styles/style:style[@style:name='T2']/style:text-properties", "color", "#ff0000"); } +CPPUNIT_TEST_FIXTURE(Test, testCommentStyles) +{ + createSwDoc(); + + auto xFactory(mxComponent.queryThrow<lang::XMultiServiceFactory>()); + auto xComment(xFactory->createInstance("com.sun.star.text.textfield.Annotation").queryThrow<text::XTextContent>()); + auto xCommentText(getProperty<uno::Reference<text::XTextRange>>(xComment, "TextRange")); + xCommentText->setString("Hello World"); + xCommentText.queryThrow<beans::XPropertySet>()->setPropertyValue("ParaStyleName", uno::Any(OUString("Heading"))); + + xComment->attach(getParagraph(1)->getEnd()); + + saveAndReload("writer8"); + + auto xFields(mxComponent.queryThrow<text::XTextFieldsSupplier>()->getTextFields()->createEnumeration()); + xComment.set(xFields->nextElement().queryThrow<text::XTextContent>()); + CPPUNIT_ASSERT(xComment.queryThrow<lang::XServiceInfo>()->supportsService("com.sun.star.text.textfield.Annotation")); + + xCommentText.set(getProperty<uno::Reference<text::XTextRange>>(xComment, "TextRange")); + CPPUNIT_ASSERT_EQUAL(OUString("Heading"), getProperty<OUString>(xCommentText, "ParaStyleName")); + + auto xStyleFamilies(mxComponent.queryThrow<style::XStyleFamiliesSupplier>()->getStyleFamilies()); + auto xParaStyles(xStyleFamilies->getByName("ParagraphStyles")); + auto xStyle(xParaStyles.queryThrow<container::XNameAccess>()->getByName("Heading")); + CPPUNIT_ASSERT_EQUAL(getProperty<float>(xStyle, "CharHeight"), getProperty<float>(xCommentText, "CharHeight")); + CPPUNIT_ASSERT_EQUAL(beans::PropertyState_DEFAULT_VALUE, + xCommentText.queryThrow<beans::XPropertyState>()->getPropertyState("CharHeight")); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/fields/textapi.cxx b/sw/source/core/fields/textapi.cxx index eecaf14217f4..88520065c7e3 100644 --- a/sw/source/core/fields/textapi.cxx +++ b/sw/source/core/fields/textapi.cxx @@ -21,6 +21,9 @@ #include <doc.hxx> #include <IDocumentDrawModelAccess.hxx> #include <docsh.hxx> +#include <docstyle.hxx> +#include <SwStyleNameMapper.hxx> +#include <unoprnms.hxx> #include <editeng/eeitem.hxx> #include <editeng/editeng.hxx> #include <editeng/outlobj.hxx> @@ -44,6 +47,8 @@ static const SvxItemPropertySet* ImplGetSvxTextPortionPropertySet() SVX_UNOEDIT_FONT_PROPERTIES, SVX_UNOEDIT_OUTLINER_PROPERTIES, SVX_UNOEDIT_PARA_PROPERTIES, + {UNO_NAME_PARA_STYLE_NAME, WID_PARASTYLENAME, + cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0 }, {u"TextField", EE_FEATURE_FIELD, cppu::UnoType<text::XTextField>::get(), beans::PropertyAttribute::READONLY, 0 }, {u"TextPortionType", WID_PORTIONTYPE, @@ -79,6 +84,25 @@ struct SwTextAPIEditSource_Impl sal_Int32 mnRef; }; +namespace { + +class SwTextAPIForwarder : public SvxOutlinerForwarder +{ +public: + using SvxOutlinerForwarder::SvxOutlinerForwarder; + OUString GetStyleSheet(sal_Int32 nPara) const override + { + return SwStyleNameMapper::GetProgName(SvxOutlinerForwarder::GetStyleSheet(nPara), SwGetPoolIdFromName::TxtColl); + } + + void SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) override + { + SvxOutlinerForwarder::SetStyleSheet(nPara, SwStyleNameMapper::GetUIName(rStyleName, SwGetPoolIdFromName::TxtColl)); + } +}; + +} + SwTextAPIEditSource::SwTextAPIEditSource( const SwTextAPIEditSource& rSource ) : SvxEditSource( *this ) { @@ -119,22 +143,29 @@ void SwTextAPIEditSource::Dispose() m_pImpl->mpOutliner.reset(); } -SvxTextForwarder* SwTextAPIEditSource::GetTextForwarder() +void SwTextAPIEditSource::EnsureOutliner() { - if( !m_pImpl->mpPool ) - return nullptr; // mpPool == 0 can be used to flag this as disposed - if( !m_pImpl->mpOutliner ) { //init draw model first m_pImpl->mpDoc->getIDocumentDrawModelAccess().GetOrCreateDrawModel(); m_pImpl->mpOutliner.reset(new Outliner(m_pImpl->mpPool, OutlinerMode::TextObject)); + m_pImpl->mpOutliner->SetStyleSheetPool( + static_cast<SwDocStyleSheetPool*>(m_pImpl->mpDoc->GetDocShell()->GetStyleSheetPool())->GetEEStyleSheetPool()); m_pImpl->mpDoc->SetCalcFieldValueHdl(m_pImpl->mpOutliner.get()); } +} + +SvxTextForwarder* SwTextAPIEditSource::GetTextForwarder() +{ + if( !m_pImpl->mpPool ) + return nullptr; // mpPool == 0 can be used to flag this as disposed + + EnsureOutliner(); if( !m_pImpl->mpTextForwarder ) { - m_pImpl->mpTextForwarder.reset(new SvxOutlinerForwarder(*m_pImpl->mpOutliner, false)); + m_pImpl->mpTextForwarder.reset(new SwTextAPIForwarder(*m_pImpl->mpOutliner, false)); } return m_pImpl->mpTextForwarder.get(); @@ -144,14 +175,7 @@ void SwTextAPIEditSource::SetText( OutlinerParaObject const & rText ) { if ( m_pImpl->mpPool ) { - if( !m_pImpl->mpOutliner ) - { - //init draw model first - m_pImpl->mpDoc->getIDocumentDrawModelAccess().GetOrCreateDrawModel(); - m_pImpl->mpOutliner.reset(new Outliner(m_pImpl->mpPool, OutlinerMode::TextObject)); - m_pImpl->mpDoc->SetCalcFieldValueHdl(m_pImpl->mpOutliner.get()); - } - + EnsureOutliner(); m_pImpl->mpOutliner->SetText( rText ); } } @@ -161,15 +185,10 @@ void SwTextAPIEditSource::SetString( const OUString& rText ) if ( !m_pImpl->mpPool ) return; - if( !m_pImpl->mpOutliner ) - { - //init draw model first - m_pImpl->mpDoc->getIDocumentDrawModelAccess().GetOrCreateDrawModel(); - m_pImpl->mpOutliner.reset(new Outliner(m_pImpl->mpPool, OutlinerMode::TextObject)); - m_pImpl->mpDoc->SetCalcFieldValueHdl(m_pImpl->mpOutliner.get()); - } - else + if ( m_pImpl->mpOutliner ) m_pImpl->mpOutliner->Clear(); + + EnsureOutliner(); m_pImpl->mpOutliner->Insert( rText ); } diff --git a/sw/source/core/inc/textapi.hxx b/sw/source/core/inc/textapi.hxx index 48586b5fa561..ec0395cbbdc8 100644 --- a/sw/source/core/inc/textapi.hxx +++ b/sw/source/core/inc/textapi.hxx @@ -31,6 +31,7 @@ class SwTextAPIEditSource final : public SvxEditSource { SwTextAPIEditSource_Impl* m_pImpl; + void EnsureOutliner(); virtual std::unique_ptr<SvxEditSource> Clone() const override; virtual SvxTextForwarder* GetTextForwarder() override; virtual void UpdateData() override; commit d934aeace6e7049db3959421538ae382cb97b1d1 Author: Maxim Monastirsky <momonas...@gmail.com> AuthorDate: Thu Jun 15 11:16:18 2023 +0300 Commit: Maxim Monastirsky <momonas...@gmail.com> CommitDate: Fri Jun 16 00:48:44 2023 +0200 tdf#103064 sw,editeng: make para styles work inside comments - Style objects for comments are stored in a dedicated stylesheet pool, and constantly updated from the "real" styles using modification broadcasts. In theory, it should be possible to use same objects for both Writer core and EditEngine, as they use separate item ranges. But unfortunately SwDocStyleSheetPool isn't really a styles container, but just a wrapper around Writer's core styles, with a single mxStyleSheet member that is filled each time with data from different styles (while EditEngine expects different styles to be represented by different objects). - EditEngine switched to allow duplicate listeners for styles - one per paragraph. The use case is 2 paragraphs of the same style, and then one of them is switched to another style. In that case we still need to keep listening to the former style for the other paragraph. There is probably some opportunity for optimization, but it should be good enough for now. - Copying formatted text from document's body doesn't preserve style assignment for now. The editeng RTF import should be tweaked to not insert styles into our "special" stylesheet pool (or somehow forward them to Writer's core style handling) before we can enable this part. Change-Id: Ib67c5388f9cd078c73ec0d453017f815843161ed Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153156 Tested-by: Jenkins Reviewed-by: Maxim Monastirsky <momonas...@gmail.com> diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx index 6db82ab2392a..a5e2e3c89593 100644 --- a/editeng/source/editeng/impedit.hxx +++ b/editeng/source/editeng/impedit.hxx @@ -477,7 +477,7 @@ public: // ImpEditEngine -class ImpEditEngine : public SfxListener +class ImpEditEngine : public SfxListener, public svl::StyleSheetUser { friend class EditEngine; @@ -1014,6 +1014,8 @@ public: void UpdateParagraphsWithStyleSheet( SfxStyleSheet* pStyle ); void RemoveStyleFromParagraphs( SfxStyleSheet const * pStyle ); + bool isUsedByModel() const override { return true; } + OutputDevice* GetRefDevice() const { return pRefDev.get(); } void SetRefDevice( OutputDevice* pRefDef ); diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx index cc8b39154844..000c0b39a1f6 100644 --- a/editeng/source/editeng/impedit2.cxx +++ b/editeng/source/editeng/impedit2.cxx @@ -2925,6 +2925,8 @@ EditPaM ImpEditEngine::ImpInsertParaBreak( EditPaM& rPaM, bool bKeepEndingAttrib InsertUndo(std::make_unique<EditUndoSplitPara>(pEditEngine, aEditDoc.GetPos(rPaM.GetNode()), rPaM.GetIndex())); EditPaM aPaM( aEditDoc.InsertParaBreak( rPaM, bKeepEndingAttribs ) ); + if (auto pStyle = aPaM.GetNode()->GetStyleSheet()) + StartListening(*pStyle, DuplicateHandling::Allow); if ( GetStatus().DoOnlineSpelling() ) { diff --git a/editeng/source/editeng/impedit5.cxx b/editeng/source/editeng/impedit5.cxx index 8438f0be7632..afb1b424d907 100644 --- a/editeng/source/editeng/impedit5.cxx +++ b/editeng/source/editeng/impedit5.cxx @@ -86,7 +86,7 @@ void ImpEditEngine::SetStyleSheet( sal_Int32 nPara, SfxStyleSheet* pStyle ) EndListening( *pCurStyle ); pNode->SetStyleSheet( pStyle, aStatus.UseCharAttribs() ); if ( pStyle ) - StartListening(*pStyle, DuplicateHandling::Prevent); + StartListening(*pStyle, DuplicateHandling::Allow); if (pNode->GetWrongList()) pNode->GetWrongList()->ResetInvalidRange(0, pNode->Len()); diff --git a/include/svl/style.hxx b/include/svl/style.hxx index cb8498a2d118..257b1786eb57 100644 --- a/include/svl/style.hxx +++ b/include/svl/style.hxx @@ -272,7 +272,7 @@ public: SfxStyleSheetBase* First(SfxStyleFamily eFamily, SfxStyleSearchBits eMask = SfxStyleSearchBits::All); SfxStyleSheetBase* Next(); - virtual SfxStyleSheetBase* Find( const OUString&, SfxStyleFamily eFam, SfxStyleSearchBits n=SfxStyleSearchBits::All ) const; + virtual SfxStyleSheetBase* Find( const OUString&, SfxStyleFamily eFam, SfxStyleSearchBits n=SfxStyleSearchBits::All ); virtual bool SetParent(SfxStyleFamily eFam, const OUString &rStyle, diff --git a/svl/source/items/style.cxx b/svl/source/items/style.cxx index ff21cd91c804..e766dcb09f65 100644 --- a/svl/source/items/style.cxx +++ b/svl/source/items/style.cxx @@ -690,7 +690,7 @@ SfxStyleSheetBasePool& SfxStyleSheetBasePool::operator+=( const SfxStyleSheetBas SfxStyleSheetBase* SfxStyleSheetBasePool::Find(const OUString& rName, SfxStyleFamily eFamily, - SfxStyleSearchBits eMask) const + SfxStyleSearchBits eMask) { SfxStyleSheetIterator aIter(this, eFamily, eMask); return aIter.Find(rName); diff --git a/sw/inc/docstyle.hxx b/sw/inc/docstyle.hxx index e71fb73c9828..2d7bfdf3ff99 100644 --- a/sw/inc/docstyle.hxx +++ b/sw/inc/docstyle.hxx @@ -207,6 +207,7 @@ public: class SwDocStyleSheetPool final : public SfxStyleSheetBasePool { rtl::Reference< SwDocStyleSheet > mxStyleSheet; + rtl::Reference< SfxStyleSheetPool > mxEEStyleSheetPool; SwDoc& m_rDoc; bool m_bOrganizer : 1; ///< Organizer @@ -222,7 +223,7 @@ public: SfxStyleSearchBits nMask = SfxStyleSearchBits::All) override; virtual SfxStyleSheetBase* Find( const OUString&, SfxStyleFamily eFam, - SfxStyleSearchBits n=SfxStyleSearchBits::All ) const override; + SfxStyleSearchBits n=SfxStyleSearchBits::All ) override; virtual bool SetParent( SfxStyleFamily eFam, const OUString &rStyle, const OUString &rParent ) override; @@ -234,6 +235,7 @@ public: virtual std::unique_ptr<SfxStyleSheetIterator> CreateIterator( SfxStyleFamily, SfxStyleSearchBits nMask = SfxStyleSearchBits::All) override; SwDoc& GetDoc() const { return m_rDoc; } + SfxStyleSheetPool* GetEEStyleSheetPool() { return mxEEStyleSheetPool.get(); } void dispose(); diff --git a/sw/inc/docufld.hxx b/sw/inc/docufld.hxx index 89a5341222db..17e99a94225e 100644 --- a/sw/inc/docufld.hxx +++ b/sw/inc/docufld.hxx @@ -511,6 +511,7 @@ public: bool GetResolved() const; sal_Int32 GetNumberOfParagraphs() const; + void ChangeStyleSheetName(std::u16string_view rOldName, const SfxStyleSheetBase* pStyleSheet); virtual bool QueryValue( css::uno::Any& rVal, sal_uInt16 nWhich ) const override; virtual bool PutValue( const css::uno::Any& rVal, sal_uInt16 nWhich ) override; diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx index e604985e7d0f..97156636ef60 100644 --- a/sw/source/core/fields/docufld.cxx +++ b/sw/source/core/fields/docufld.cxx @@ -1846,6 +1846,12 @@ sal_Int32 SwPostItField::GetNumberOfParagraphs() const return mpText ? mpText->Count() : 1; } +void SwPostItField::ChangeStyleSheetName(std::u16string_view rOldName, const SfxStyleSheetBase* pStyleSheet) +{ + if (mpText && pStyleSheet) + mpText->ChangeStyleSheetName(pStyleSheet->GetFamily(), rOldName, pStyleSheet->GetName()); +} + void SwPostItField::SetPostItId(const sal_uInt32 nPostItId) { m_nPostItId = nPostItId == 0 ? s_nLastPostItId++ : nPostItId; diff --git a/sw/source/uibase/app/docstyle.cxx b/sw/source/uibase/app/docstyle.cxx index 0738b2ce6bd1..c869b10f7a5c 100644 --- a/sw/source/uibase/app/docstyle.cxx +++ b/sw/source/uibase/app/docstyle.cxx @@ -63,6 +63,9 @@ #include <SwRewriter.hxx> #include <hints.hxx> #include <frameformats.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/eeitem.hxx> #include <svx/xfillit0.hxx> #include <svx/xflftrit.hxx> #include <svx/drawitem.hxx> @@ -77,6 +80,179 @@ using namespace com::sun::star; namespace { +class EEStyleSheet : public SfxStyleSheet +{ +public: + using SfxStyleSheet::SfxStyleSheet; + bool IsUsed() const override + { + bool bResult = false; + ForAllListeners( + [&bResult] (SfxListener* pListener) + { + auto pUser(dynamic_cast<svl::StyleSheetUser*>(pListener)); + bResult = pUser && pUser->isUsedByModel(); + return bResult; + }); + return bResult; + } + void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override + { + if (rHint.GetId() == SfxHintId::DataChanged) + Broadcast(rHint); + else + SfxStyleSheet::Notify(rBC, rHint); + } + bool SetParent(const OUString& rName) override + { + if (SfxStyleSheet::SetParent(rName)) + { + auto pStyle = m_pPool->Find(rName, nFamily); + pSet->SetParent(pStyle ? &pStyle->GetItemSet() : nullptr); + Broadcast(SfxHint(SfxHintId::DataChanged)); + return true; + } + return false; + } +}; + +class EEStyleSheetPool : public SfxStyleSheetPool, public SfxListener +{ + SfxStyleSheetBasePool* m_pOwner; + +public: + explicit EEStyleSheetPool(SfxStyleSheetBasePool* pOwner) + : SfxStyleSheetPool(pOwner->GetPool()) + , m_pOwner(pOwner) + { + StartListening(*m_pOwner); + } + + using SfxStyleSheetPool::Create; + rtl::Reference<SfxStyleSheetBase> Create(const OUString& rName, SfxStyleFamily eFamily, + SfxStyleSearchBits nMask) override + { + return new EEStyleSheet(rName, *this, eFamily, nMask); + } + + void Notify(SfxBroadcaster&, const SfxHint& rHint) override + { + auto pHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint); + if (!pHint) + return; + + auto nId = pHint->GetId(); + auto pDocStyleSheet = pHint->GetStyleSheet(); + auto pExtendedHint = dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint); + const OUString aName = pExtendedHint ? pExtendedHint->GetOldName() : pDocStyleSheet->GetName(); + auto pStyleSheet = SfxStyleSheetPool::Find(aName, pDocStyleSheet->GetFamily()); + if (!pStyleSheet) + return; + + if (nId == SfxHintId::StyleSheetModified) + { + pStyleSheet->SetName(pDocStyleSheet->GetName()); + pStyleSheet->GetItemSet().ClearItem(); + EnsureStyleHierarchy(pDocStyleSheet->GetName(), pDocStyleSheet->GetFamily()); + } + else if (nId == SfxHintId::StyleSheetErased) + Remove(pStyleSheet); + } + + SfxStyleSheetBase* Find(const OUString& rName, SfxStyleFamily eFamily, + SfxStyleSearchBits = SfxStyleSearchBits::All) override + { + if (eFamily != SfxStyleFamily::All) + EnsureStyleHierarchy(rName, eFamily); + return SfxStyleSheetPool::Find(rName, eFamily); + } + + void EnsureStyleHierarchy(const OUString& rName, SfxStyleFamily eFamily) + { + auto pDocStyleSheet = m_pOwner->Find(rName, eFamily); + if (!pDocStyleSheet) + return; + + auto pStyleSheet = SfxStyleSheetPool::Find(rName, eFamily); + if (!pStyleSheet) + pStyleSheet = &Make(rName, eFamily); + + FillItemSet(pStyleSheet, pDocStyleSheet); + + // Remember now, as the next calls will invalidate pDocStyleSheet. + const OUString aParent = pDocStyleSheet->GetParent(); + const OUString aFollow = pDocStyleSheet->GetFollow(); + + if (pStyleSheet->GetParent() != aParent) + pStyleSheet->SetParent(aParent); + + if (pStyleSheet->GetFollow() != aFollow) + pStyleSheet->SetFollow(aFollow); + } + + void FillItemSet(SfxStyleSheetBase* pDestSheet, SfxStyleSheetBase* pSourceSheet) + { + auto& rItemSet = pDestSheet->GetItemSet(); + if (rItemSet.Count() > 0) + return; + + auto pCol = static_cast<SwDocStyleSheet*>(pSourceSheet)->GetCollection(); + if (!pCol->GetAttrSet().Count()) + return; + + const WhichRangesContainer aRanges(svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END, + RES_PARATR_BEGIN, RES_PARATR_END, + RES_FRMATR_BEGIN, RES_FRMATR_END>); + + for (const auto& range : aRanges) + { + std::optional<SvxLRSpaceItem> oLRSpaceItem; + + for (auto i = range.first; i < range.second; ++i) + { + const SfxPoolItem* pItem; + if (pCol->GetItemState(i, false, &pItem) != SfxItemState::SET) + continue; + + auto nSlotId = rPool.GetSlotId(i); + auto nNewWhich = rPool.GetSecondaryPool()->GetWhich(nSlotId); + if (nNewWhich != nSlotId) + rItemSet.Put(pItem->CloneSetWhich(nNewWhich)); + else if (i == RES_MARGIN_FIRSTLINE) + { + if (!oLRSpaceItem) + oLRSpaceItem.emplace(EE_PARA_LRSPACE); + auto pFirstLineItem = static_cast<const SvxFirstLineIndentItem*>(pItem); + (*oLRSpaceItem).SetTextFirstLineOffsetValue(pFirstLineItem->GetTextFirstLineOffset()); + (*oLRSpaceItem).SetAutoFirst(pFirstLineItem->IsAutoFirst()); + } + else if (i == RES_MARGIN_TEXTLEFT) + { + if (!oLRSpaceItem) + oLRSpaceItem.emplace(EE_PARA_LRSPACE); + (*oLRSpaceItem).SetTextLeft(static_cast<const SvxTextLeftMarginItem*>(pItem)->GetTextLeft()); + } + else if (i == RES_MARGIN_RIGHT) + { + if (!oLRSpaceItem) + oLRSpaceItem.emplace(EE_PARA_LRSPACE); + (*oLRSpaceItem).SetRight(static_cast<const SvxRightMarginItem*>(pItem)->GetRight()); + } + else if (i == RES_CHRATR_BACKGROUND) + { + auto pBrushItem = static_cast<const SvxBrushItem*>(pItem); + rItemSet.Put(SvxColorItem(pBrushItem->GetColor(), EE_CHAR_BKGCOLOR)); + } + } + + if (oLRSpaceItem) + rItemSet.Put(*oLRSpaceItem); + } + + static_cast<SfxStyleSheet*>(pDestSheet)->Broadcast(SfxHint(SfxHintId::DataChanged)); + } +}; + class SwImplShellAction { SwWrtShell* m_pSh; @@ -2291,7 +2467,16 @@ bool SwDocStyleSheet::IsUsed() const OSL_ENSURE(false, "unknown style family"); return false; } - return m_rDoc.IsUsed( *pMod ); + + if (m_rDoc.IsUsed(*pMod)) + return true; + + SfxStyleSheetIterator aIter(static_cast<SwDocStyleSheetPool*>(m_pPool)->GetEEStyleSheetPool(), nFamily); + auto pStyle = aIter.Find(GetName()); + if (pStyle && pStyle->IsUsed()) + return true; + + return false; } OUString SwDocStyleSheet::GetUsedBy() @@ -2434,6 +2619,7 @@ void SwDocStyleSheet::SetHelpId( const OUString& r, sal_uLong nId ) SwDocStyleSheetPool::SwDocStyleSheetPool( SwDoc& rDocument, bool bOrg ) : SfxStyleSheetBasePool(rDocument.GetAttrPool()) , mxStyleSheet(new SwDocStyleSheet(rDocument, *this)) + , mxEEStyleSheetPool(new EEStyleSheetPool(this)) , m_rDoc(rDocument) { m_bOrganizer = bOrg; @@ -2479,6 +2665,7 @@ std::unique_ptr<SfxStyleSheetIterator> SwDocStyleSheetPool::CreateIterator( SfxS void SwDocStyleSheetPool::dispose() { mxStyleSheet.clear(); + mxEEStyleSheetPool.clear(); } void SwDocStyleSheetPool::Remove( SfxStyleSheetBase* pStyle) @@ -2598,7 +2785,7 @@ bool SwDocStyleSheetPool::SetParent( SfxStyleFamily eFam, } SfxStyleSheetBase* SwDocStyleSheetPool::Find(const OUString& rName, - SfxStyleFamily eFam, SfxStyleSearchBits n) const + SfxStyleFamily eFam, SfxStyleSearchBits n) { SfxStyleSearchBits nSMask = n; if( SfxStyleFamily::Para == eFam && m_rDoc.getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE) ) diff --git a/sw/source/uibase/docvw/AnnotationWin2.cxx b/sw/source/uibase/docvw/AnnotationWin2.cxx index 2c4bc7ce3d5e..d531a62e1f57 100644 --- a/sw/source/uibase/docvw/AnnotationWin2.cxx +++ b/sw/source/uibase/docvw/AnnotationWin2.cxx @@ -67,6 +67,7 @@ #include <docsh.hxx> #include <wrtsh.hxx> #include <doc.hxx> +#include <docstyle.hxx> #include <docufld.hxx> #include <swmodule.hxx> @@ -321,6 +322,7 @@ void SwAnnotationWin::InitControls() SwDocShell* aShell = mrView.GetDocShell(); mpOutliner.reset(new Outliner(&aShell->GetPool(),OutlinerMode::TextObject)); + mpOutliner->SetStyleSheetPool(static_cast<SwDocStyleSheetPool*>(aShell->GetStyleSheetPool())->GetEEStyleSheetPool()); aShell->GetDoc()->SetCalcFieldValueHdl( mpOutliner.get() ); mpOutliner->SetUpdateLayout( true ); @@ -352,6 +354,9 @@ void SwAnnotationWin::InitControls() EEControlBits nCntrl = mpOutliner->GetControlWord(); // TODO: crash when AUTOCOMPLETE enabled nCntrl |= EEControlBits::MARKFIELDS | EEControlBits::PASTESPECIAL | EEControlBits::AUTOCORRECT | EEControlBits::USECHARATTRIBS; // | EEControlBits::AUTOCOMPLETE; + // Our stylesheet pool follows closely the core paragraph styles. + // We don't want the rtf import (during paste) to mess with that. + nCntrl &= ~EEControlBits::RTFSTYLESHEETS; if (SwWrtShell* pWrtShell = mrView.GetWrtShellPtr()) { diff --git a/sw/source/uibase/docvw/PostItMgr.cxx b/sw/source/uibase/docvw/PostItMgr.cxx index 68c1a00221f7..bd92adadbf03 100644 --- a/sw/source/uibase/docvw/PostItMgr.cxx +++ b/sw/source/uibase/docvw/PostItMgr.cxx @@ -45,6 +45,7 @@ #include <doc.hxx> #include <IDocumentSettingAccess.hxx> #include <IDocumentFieldsAccess.hxx> +#include <docstyle.hxx> #include <fldbas.hxx> #include <fmtfld.hxx> #include <docufld.hxx> @@ -223,6 +224,9 @@ SwPostItMgr::SwPostItMgr(SwView* pView) */ // we want to receive stuff like SfxHintId::DocChanged StartListening(*mpView->GetDocShell()); + // listen to stylesheet pool to update on stylesheet rename, + // as EditTextObject references styles by name. + StartListening(*static_cast<SwDocStyleSheetPool*>(mpView->GetDocShell()->GetStyleSheetPool())->GetEEStyleSheetPool()); if (!mvPostItFields.empty()) { mbWaitingForCalcRects = true; @@ -236,7 +240,7 @@ SwPostItMgr::~SwPostItMgr() Application::RemoveUserEvent( mnEventId ); // forget about all our Sidebar windows RemoveSidebarWin(); - EndListening( *mpView->GetDocShell() ); + EndListeningAll(); mPages.clear(); } @@ -469,6 +473,14 @@ void SwPostItMgr::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) } } } + else if ( const SfxStyleSheetModifiedHint * pStyleHint = dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint) ) + { + for (const auto& postItField : mvPostItFields) + { + auto pField = static_cast<SwPostItField*>(postItField->GetFormatField().GetField()); + pField->ChangeStyleSheetName(pStyleHint->GetOldName(), pStyleHint->GetStyleSheet()); + } + } else { SfxHintId nId = rHint.GetId();