diff options
author | Maxim Monastirsky <momonasmon@gmail.com> | 2023-06-15 11:16:18 +0300 |
---|---|---|
committer | Maxim Monastirsky <momonasmon@gmail.com> | 2023-06-16 00:48:44 +0200 |
commit | d934aeace6e7049db3959421538ae382cb97b1d1 (patch) | |
tree | b60b5ff3a1bbec87e2505d6f5ca2892ca489b6d8 | |
parent | cc483a88a03f9ee847f3cb5fac83fb5dd49d0ba1 (diff) |
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 <momonasmon@gmail.com>
-rw-r--r-- | editeng/source/editeng/impedit.hxx | 4 | ||||
-rw-r--r-- | editeng/source/editeng/impedit2.cxx | 2 | ||||
-rw-r--r-- | editeng/source/editeng/impedit5.cxx | 2 | ||||
-rw-r--r-- | include/svl/style.hxx | 2 | ||||
-rw-r--r-- | svl/source/items/style.cxx | 2 | ||||
-rw-r--r-- | sw/inc/docstyle.hxx | 4 | ||||
-rw-r--r-- | sw/inc/docufld.hxx | 1 | ||||
-rw-r--r-- | sw/source/core/fields/docufld.cxx | 6 | ||||
-rw-r--r-- | sw/source/uibase/app/docstyle.cxx | 191 | ||||
-rw-r--r-- | sw/source/uibase/docvw/AnnotationWin2.cxx | 5 | ||||
-rw-r--r-- | sw/source/uibase/docvw/PostItMgr.cxx | 14 |
11 files changed, 225 insertions, 8 deletions
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(); |