diff options
author | Pranam Lashkari <lpranam@collabora.com> | 2024-10-30 05:11:49 +0530 |
---|---|---|
committer | Pranam Lashkari <lpranam@collabora.com> | 2024-10-30 18:02:01 +0100 |
commit | 86422743e6a4fa67de3b0049bd4ea40e1aca17ad (patch) | |
tree | d636a6ca8e25823ed3a9a81ef0b7d9f283783711 /sw/source/uibase | |
parent | 1f4009e98caf9ea878b89ae1d93934540a91e753 (diff) |
sw: redline changes may try to set broadcast on non PostIt fields
broadcast was set from sw::UpdateFramesForRemoveDeleteRedline
which triggered SwPostItMgr::Notify
in that case SwFormatFieldHintWhich::INSERTED may have pField which maybe different from SwPostIt
fixed regression from 0b7a9c231f66b5c2659ab3aa6a0f3c7991b9e721
problem:(in LOK)
with tracked changed on delete a merge field
then reject the changes
LOK will crash
Change-Id: Ic1fafa1408d7a238133f5b3d18bf948d539aa991
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175808
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
Diffstat (limited to 'sw/source/uibase')
-rw-r--r-- | sw/source/uibase/docvw/PostItMgr.cxx | 337 |
1 files changed, 168 insertions, 169 deletions
diff --git a/sw/source/uibase/docvw/PostItMgr.cxx b/sw/source/uibase/docvw/PostItMgr.cxx index 8e67e94ef3f1..21a498e8dd56 100644 --- a/sw/source/uibase/docvw/PostItMgr.cxx +++ b/sw/source/uibase/docvw/PostItMgr.cxx @@ -194,6 +194,171 @@ namespace { } } + class FilterFunctor + { + public: + virtual bool operator()(const SwFormatField* pField) const = 0; + virtual ~FilterFunctor() {} + }; + + class IsPostitField : public FilterFunctor + { + public: + bool operator()(const SwFormatField* pField) const override + { + return pField->GetField()->GetTyp()->Which() == SwFieldIds::Postit; + } + }; + + class IsPostitFieldWithAuthorOf : public FilterFunctor + { + OUString m_sAuthor; + public: + explicit IsPostitFieldWithAuthorOf(OUString aAuthor) + : m_sAuthor(std::move(aAuthor)) + { + } + bool operator()(const SwFormatField* pField) const override + { + if (pField->GetField()->GetTyp()->Which() != SwFieldIds::Postit) + return false; + return static_cast<const SwPostItField*>(pField->GetField())->GetPar1() == m_sAuthor; + } + }; + + class IsPostitFieldWithPostitId : public FilterFunctor + { + sal_uInt32 m_nPostItId; + public: + explicit IsPostitFieldWithPostitId(sal_uInt32 nPostItId) + : m_nPostItId(nPostItId) + {} + + bool operator()(const SwFormatField* pField) const override + { + if (pField->GetField()->GetTyp()->Which() != SwFieldIds::Postit) + return false; + return static_cast<const SwPostItField*>(pField->GetField())->GetPostItId() == m_nPostItId; + } + }; + + class IsFieldNotDeleted : public FilterFunctor + { + private: + IDocumentRedlineAccess const& m_rIDRA; + FilterFunctor const& m_rNext; + + public: + IsFieldNotDeleted(IDocumentRedlineAccess const& rIDRA, + const FilterFunctor & rNext) + : m_rIDRA(rIDRA) + , m_rNext(rNext) + { + } + bool operator()(const SwFormatField* pField) const override + { + if (!m_rNext(pField)) + return false; + if (!pField->GetTextField()) + return false; + return !sw::IsFieldDeletedInModel(m_rIDRA, *pField->GetTextField()); + } + }; + + //Manages the passed in vector by automatically removing entries if they are deleted + //and automatically adding entries if they appear in the document and match the + //functor. + // + //This will completely refill in the case of a "anonymous" NULL pField stating + //rather unhelpfully that "something changed" so you may process the same + //Fields more than once. + class FieldDocWatchingStack : public SfxListener + { + std::vector<std::unique_ptr<SwSidebarItem>>& m_aSidebarItems; + std::vector<const SwFormatField*> m_aFormatFields; + SwDocShell& m_rDocShell; + FilterFunctor& m_rFilter; + + virtual void Notify(SfxBroadcaster&, const SfxHint& rHint) override + { + const SwFormatFieldHint* pHint = dynamic_cast<const SwFormatFieldHint*>(&rHint); + if (!pHint) + return; + + bool bAllInvalidated = false; + if (pHint->Which() == SwFormatFieldHintWhich::REMOVED) + { + const SwFormatField* pField = pHint->GetField(); + bAllInvalidated = pField == nullptr; + if (!bAllInvalidated && m_rFilter(pField)) + { + EndListening(const_cast<SwFormatField&>(*pField)); + std::erase(m_aFormatFields, pField); + } + } + else if (pHint->Which() == SwFormatFieldHintWhich::INSERTED) + { + const SwFormatField* pField = pHint->GetField(); + bAllInvalidated = pField == nullptr; + if (!bAllInvalidated && m_rFilter(pField)) + { + StartListening(const_cast<SwFormatField&>(*pField)); + m_aFormatFields.push_back(pField); + } + } + + if (bAllInvalidated) + FillVector(); + + return; + } + + public: + FieldDocWatchingStack(std::vector<std::unique_ptr<SwSidebarItem>>& in, SwDocShell &rDocShell, FilterFunctor& rFilter) + : m_aSidebarItems(in) + , m_rDocShell(rDocShell) + , m_rFilter(rFilter) + { + FillVector(); + StartListening(m_rDocShell); + } + void FillVector() + { + EndListeningToAllFields(); + m_aFormatFields.clear(); + m_aFormatFields.reserve(m_aSidebarItems.size()); + for (auto const& p : m_aSidebarItems) + { + const SwFormatField& rField = p->GetFormatField(); + if (!m_rFilter(&rField)) + continue; + StartListening(const_cast<SwFormatField&>(rField)); + m_aFormatFields.push_back(&rField); + } + } + void EndListeningToAllFields() + { + for (auto const& pField : m_aFormatFields) + { + EndListening(const_cast<SwFormatField&>(*pField)); + } + } + virtual ~FieldDocWatchingStack() override + { + EndListeningToAllFields(); + EndListening(m_rDocShell); + } + const SwFormatField* pop() + { + if (m_aFormatFields.empty()) + return nullptr; + const SwFormatField* p = m_aFormatFields.back(); + EndListening(const_cast<SwFormatField&>(*p)); + m_aFormatFields.pop_back(); + return p; + } + }; + } // anonymous namespace SwPostItMgr::SwPostItMgr(SwView* pView) @@ -317,6 +482,9 @@ SwSidebarItem* SwPostItMgr::InsertItem(SfxBroadcaster* pItem, bool bCheckExisten SwSidebarItem* pAnnotationItem = nullptr; if (auto pSwFormatField = dynamic_cast< SwFormatField *>( pItem )) { + IsPostitField isPostitField; + if (!isPostitField(pSwFormatField)) + return nullptr; mvPostItFields.push_back(std::make_unique<SwAnnotationItem>(*pSwFormatField, bFocus)); pAnnotationItem = mvPostItFields.back().get(); } @@ -1387,175 +1555,6 @@ void SwPostItMgr::RemoveSidebarWin() PreparePageContainer(); } -namespace { - -class FilterFunctor -{ -public: - virtual bool operator()(const SwFormatField* pField) const = 0; - virtual ~FilterFunctor() {} -}; - -class IsPostitField : public FilterFunctor -{ -public: - bool operator()(const SwFormatField* pField) const override - { - return pField->GetField()->GetTyp()->Which() == SwFieldIds::Postit; - } -}; - -class IsPostitFieldWithAuthorOf : public FilterFunctor -{ - OUString m_sAuthor; -public: - explicit IsPostitFieldWithAuthorOf(OUString aAuthor) - : m_sAuthor(std::move(aAuthor)) - { - } - bool operator()(const SwFormatField* pField) const override - { - if (pField->GetField()->GetTyp()->Which() != SwFieldIds::Postit) - return false; - return static_cast<const SwPostItField*>(pField->GetField())->GetPar1() == m_sAuthor; - } -}; - -class IsPostitFieldWithPostitId : public FilterFunctor -{ - sal_uInt32 m_nPostItId; -public: - explicit IsPostitFieldWithPostitId(sal_uInt32 nPostItId) - : m_nPostItId(nPostItId) - {} - - bool operator()(const SwFormatField* pField) const override - { - if (pField->GetField()->GetTyp()->Which() != SwFieldIds::Postit) - return false; - return static_cast<const SwPostItField*>(pField->GetField())->GetPostItId() == m_nPostItId; - } -}; - -class IsFieldNotDeleted : public FilterFunctor -{ -private: - IDocumentRedlineAccess const& m_rIDRA; - FilterFunctor const& m_rNext; - -public: - IsFieldNotDeleted(IDocumentRedlineAccess const& rIDRA, - const FilterFunctor & rNext) - : m_rIDRA(rIDRA) - , m_rNext(rNext) - { - } - bool operator()(const SwFormatField* pField) const override - { - if (!m_rNext(pField)) - return false; - if (!pField->GetTextField()) - return false; - return !sw::IsFieldDeletedInModel(m_rIDRA, *pField->GetTextField()); - } -}; - -//Manages the passed in vector by automatically removing entries if they are deleted -//and automatically adding entries if they appear in the document and match the -//functor. -// -//This will completely refill in the case of a "anonymous" NULL pField stating -//rather unhelpfully that "something changed" so you may process the same -//Fields more than once. -class FieldDocWatchingStack : public SfxListener -{ - std::vector<std::unique_ptr<SwSidebarItem>>& m_aSidebarItems; - std::vector<const SwFormatField*> m_aFormatFields; - SwDocShell& m_rDocShell; - FilterFunctor& m_rFilter; - - virtual void Notify(SfxBroadcaster&, const SfxHint& rHint) override - { - const SwFormatFieldHint* pHint = dynamic_cast<const SwFormatFieldHint*>(&rHint); - if (!pHint) - return; - - bool bAllInvalidated = false; - if (pHint->Which() == SwFormatFieldHintWhich::REMOVED) - { - const SwFormatField* pField = pHint->GetField(); - bAllInvalidated = pField == nullptr; - if (!bAllInvalidated && m_rFilter(pField)) - { - EndListening(const_cast<SwFormatField&>(*pField)); - std::erase(m_aFormatFields, pField); - } - } - else if (pHint->Which() == SwFormatFieldHintWhich::INSERTED) - { - const SwFormatField* pField = pHint->GetField(); - bAllInvalidated = pField == nullptr; - if (!bAllInvalidated && m_rFilter(pField)) - { - StartListening(const_cast<SwFormatField&>(*pField)); - m_aFormatFields.push_back(pField); - } - } - - if (bAllInvalidated) - FillVector(); - - return; - } - -public: - FieldDocWatchingStack(std::vector<std::unique_ptr<SwSidebarItem>>& in, SwDocShell &rDocShell, FilterFunctor& rFilter) - : m_aSidebarItems(in) - , m_rDocShell(rDocShell) - , m_rFilter(rFilter) - { - FillVector(); - StartListening(m_rDocShell); - } - void FillVector() - { - EndListeningToAllFields(); - m_aFormatFields.clear(); - m_aFormatFields.reserve(m_aSidebarItems.size()); - for (auto const& p : m_aSidebarItems) - { - const SwFormatField& rField = p->GetFormatField(); - if (!m_rFilter(&rField)) - continue; - StartListening(const_cast<SwFormatField&>(rField)); - m_aFormatFields.push_back(&rField); - } - } - void EndListeningToAllFields() - { - for (auto const& pField : m_aFormatFields) - { - EndListening(const_cast<SwFormatField&>(*pField)); - } - } - virtual ~FieldDocWatchingStack() override - { - EndListeningToAllFields(); - EndListening(m_rDocShell); - } - const SwFormatField* pop() - { - if (m_aFormatFields.empty()) - return nullptr; - const SwFormatField* p = m_aFormatFields.back(); - EndListening(const_cast<SwFormatField&>(*p)); - m_aFormatFields.pop_back(); - return p; - } -}; - -} - // copy to new vector, otherwise RemoveItem would operate and delete stuff on mvPostItFields as well // RemoveItem will clean up the core field and visible postit if necessary // we cannot just delete everything as before, as postits could move into change tracking |