[Libreoffice-commits] core.git: sw/source

Caolán McNamara caolanm at redhat.com
Fri Oct 3 09:07:31 PDT 2014


 sw/source/uibase/docvw/PostItMgr.cxx |  161 ++++++++++++++++++++++++++++++-----
 1 file changed, 141 insertions(+), 20 deletions(-)

New commits:
commit 03a0f1147af703dc20574919213152a8599d2a8f
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Thu Oct 2 17:02:10 2014 +0100

    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

diff --git a/sw/source/uibase/docvw/PostItMgr.cxx b/sw/source/uibase/docvw/PostItMgr.cxx
index a75a70f..cbfc62c 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();
     }
 


More information about the Libreoffice-commits mailing list