summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2014-10-02 17:02:10 +0100
committerCaolán McNamara <caolanm@redhat.com>2014-10-03 17:06:46 +0100
commit03a0f1147af703dc20574919213152a8599d2a8f (patch)
tree50f4d72039fecbd7e0fb8a83410440b655f4f192
parent4e678058267bb0749cc427b22d4583af72d86217 (diff)
Resolves:fdo#58277 don't double delete postits
In redline mode, if deleting the anchor point for a postit causes another one to get moved, i.e. deleting it and creating a replacement. Then update the the queue of postits to remove the old candidate and add the new candidate. This is complicated by the occasional anonymous SWFMTFLD_REMOVED event which just states that "something" got removed from the document (but not truly deleted), and I don't see any better way to handle it than to completely refill the pool of candidates and rely on the fix of commit 1f18b3b07832fee769e7a36c4f3503effde26f1e Date: Thu Oct 2 16:33:46 2014 +0100 Related: fdo#58277 only DelRight after a successful GotoField to skip the previously successful candidates which got moved into the redline backing area and so not loop forever Change-Id: I0b30111bc1f2527011e68d048ecd65fcf71416a5
-rw-r--r--sw/source/uibase/docvw/PostItMgr.cxx161
1 files changed, 141 insertions, 20 deletions
diff --git a/sw/source/uibase/docvw/PostItMgr.cxx b/sw/source/uibase/docvw/PostItMgr.cxx
index a75a70fdd38e..cbfc62c816bd 100644
--- a/sw/source/uibase/docvw/PostItMgr.cxx
+++ b/sw/source/uibase/docvw/PostItMgr.cxx
@@ -1186,30 +1186,154 @@ void SwPostItMgr::RemoveSidebarWin()
PreparePageContainer();
}
+class FilterFunctor : public std::unary_function<const SwFmtFld*, bool>
+{
+public:
+ virtual bool operator()(const SwFmtFld* pFld) const = 0;
+ virtual ~FilterFunctor() {}
+};
+
+class IsPostitField : public FilterFunctor
+{
+public:
+ bool operator()(const SwFmtFld* pFld) const SAL_OVERRIDE
+ {
+ return pFld->GetField()->GetTyp()->Which() == RES_POSTITFLD;
+ }
+};
+
+class IsPostitFieldWithAuthorOf : public FilterFunctor
+{
+ OUString m_sAuthor;
+public:
+ IsPostitFieldWithAuthorOf(const OUString &rAuthor)
+ : m_sAuthor(rAuthor)
+ {
+ }
+ bool operator()(const SwFmtFld* pFld) const SAL_OVERRIDE
+ {
+ if (pFld->GetField()->GetTyp()->Which() != RES_POSTITFLD)
+ return false;
+ return static_cast<const SwPostItField*>(pFld->GetField())->GetPar1() == m_sAuthor;
+ }
+};
+
+
+//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 pFld stating
+//rather unhelpfully that "something changed" so you may process the same
+//Fields more than once.
+class FieldDocWatchingStack : public SfxListener
+{
+ std::list<SwSidebarItem*>& l;
+ std::vector<const SwFmtFld*> v;
+ SwDocShell& m_rDocShell;
+ FilterFunctor& m_rFilter;
+
+ virtual void Notify(SfxBroadcaster&, const SfxHint& rHint) SAL_OVERRIDE
+ {
+ const SwFmtFldHint* pHint = dynamic_cast<const SwFmtFldHint*>(&rHint);
+ if (pHint)
+ {
+ bool bAllInvalidated = false;
+ if (pHint->Which() == SWFMTFLD_REMOVED)
+ {
+ const SwFmtFld* pFld = pHint->GetField();
+ bAllInvalidated = pFld == NULL;
+ if (!bAllInvalidated && m_rFilter(pFld))
+ {
+ EndListening(const_cast<SwFmtFld&>(*pFld));
+ v.erase(std::remove(v.begin(), v.end(), pFld), v.end());
+ }
+ }
+ else if (pHint->Which() == SWFMTFLD_INSERTED)
+ {
+ const SwFmtFld* pFld = pHint->GetField();
+ bAllInvalidated = pFld == NULL;
+ if (!bAllInvalidated && m_rFilter(pFld))
+ {
+ StartListening(const_cast<SwFmtFld&>(*pFld));
+ v.push_back(pFld);
+ }
+ }
+
+ if (bAllInvalidated)
+ FillVector();
+
+ return;
+ }
+ }
+
+public:
+ FieldDocWatchingStack(std::list<SwSidebarItem*>& in, SwDocShell &rDocShell, FilterFunctor& rFilter)
+ : l(in)
+ , m_rDocShell(rDocShell)
+ , m_rFilter(rFilter)
+ {
+ FillVector();
+ StartListening(m_rDocShell);
+ }
+ void FillVector()
+ {
+ EndListeningToAllFields();
+ v.clear();
+ v.reserve(l.size());
+ for(std::list<SwSidebarItem*>::iterator aI = l.begin(); aI != l.end(); ++aI)
+ {
+ SwSidebarItem* p = *aI;
+ const SwFmtFld& rFld = p->GetFmtFld();
+ if (!m_rFilter(&rFld))
+ continue;
+ StartListening(const_cast<SwFmtFld&>(rFld));
+ v.push_back(&rFld);
+ }
+ }
+ void EndListeningToAllFields()
+ {
+ for(std::vector<const SwFmtFld*>::iterator aI = v.begin(); aI != v.end(); ++aI)
+ {
+ const SwFmtFld* pFld = *aI;
+ EndListening(const_cast<SwFmtFld&>(*pFld));
+ }
+ }
+ ~FieldDocWatchingStack()
+ {
+ EndListeningToAllFields();
+ EndListening(m_rDocShell);
+ }
+ const SwFmtFld* pop()
+ {
+ if (v.empty())
+ return NULL;
+ const SwFmtFld* p = v.back();
+ EndListening(const_cast<SwFmtFld&>(*p));
+ v.pop_back();
+ return p;
+ }
+};
+
// copy to new vector, otherwise RemoveItem would operate and delete stuff on mvPostItFlds 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
-void SwPostItMgr::Delete(const OUString& aAuthor)
+void SwPostItMgr::Delete(const OUString& rAuthor)
{
mpWrtShell->StartAllAction();
- if ( HasActiveSidebarWin() && (GetActiveSidebarWin()->GetAuthor()==aAuthor) )
+ if (HasActiveSidebarWin() && (GetActiveSidebarWin()->GetAuthor() == rAuthor))
{
SetActiveSidebarWin(0);
}
SwRewriter aRewriter;
- aRewriter.AddRule(UndoArg1, SW_RESSTR(STR_DELETE_AUTHOR_NOTES) + aAuthor);
+ aRewriter.AddRule(UndoArg1, SW_RESSTR(STR_DELETE_AUTHOR_NOTES) + rAuthor);
mpWrtShell->StartUndo( UNDO_DELETE, &aRewriter );
- std::vector<const SwFmtFld*> aTmp;
- aTmp.reserve( mvPostItFlds.size() );
- for(std::list<SwSidebarItem*>::iterator pPostIt = mvPostItFlds.begin(); pPostIt!= mvPostItFlds.end() ; ++pPostIt)
- {
- if (((*pPostIt)->pPostIt->GetAuthor() == aAuthor) )
- aTmp.push_back( &(*pPostIt)->GetFmtFld() );
- }
- for(std::vector<const SwFmtFld*>::iterator i = aTmp.begin(); i != aTmp.end() ; ++i)
+ IsPostitFieldWithAuthorOf aFilter(rAuthor);
+ FieldDocWatchingStack aStack(mvPostItFlds, *mpView->GetDocShell(), aFilter);
+ while (const SwFmtFld* pFld = aStack.pop())
{
- if (mpWrtShell->GotoField(*(*i)))
+ if (mpWrtShell->GotoField(*pFld))
mpWrtShell->DelRight();
}
mpWrtShell->EndUndo();
@@ -1228,15 +1352,12 @@ void SwPostItMgr::Delete()
aRewriter.AddRule(UndoArg1, SW_RES(STR_DELETE_ALL_NOTES) );
mpWrtShell->StartUndo( UNDO_DELETE, &aRewriter );
- std::vector<const SwFmtFld*> aTmp;
- aTmp.reserve( mvPostItFlds.size() );
- for(std::list<SwSidebarItem*>::iterator pPostIt = mvPostItFlds.begin(); pPostIt!= mvPostItFlds.end() ; ++pPostIt)
- {
- aTmp.push_back( &(*pPostIt)->GetFmtFld() );
- }
- for(std::vector<const SwFmtFld*>::iterator i = aTmp.begin(); i != aTmp.end() ; ++i)
+ IsPostitField aFilter;
+ FieldDocWatchingStack aStack(mvPostItFlds, *mpView->GetDocShell(),
+ aFilter);
+ while (const SwFmtFld* pFld = aStack.pop())
{
- if (mpWrtShell->GotoField(*(*i)))
+ if (mpWrtShell->GotoField(*pFld))
mpWrtShell->DelRight();
}