sw doc model xml dump: improve undo-redo coverage:

- show the undo manager's node array
- show SwUndoDelete
- show SwUndoSaveContent
- show SwHistory
- show SwHistoryHint
- show SwHistoryTextFlyCnt
- show SwUndoFlyBase
- show SwHistorySetFormat
- show SwUndoInserts

When an action + undo pair goes wrong, it's easier to see the state of
the undo stack after the action this way, then decide if the undo stack
is already bad, or the problem is with the undo implementation.

Change-Id: Ic509a233dce3c47db9697982eb7ea423f4706129
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96930
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
diff --git a/sw/inc/undobj.hxx b/sw/inc/undobj.hxx
index bd6748d..60d219bc 100644
--- a/sw/inc/undobj.hxx
+++ b/sw/inc/undobj.hxx
@@ -42,6 +42,7 @@ class SwRedlineData;
class SwRedlineSaveDatas;
enum class RedlineFlags;
enum class RndStdIds;
typedef struct _xmlTextWriter* xmlTextWriterPtr;

namespace sw {
    class UndoRedoContext;
@@ -191,7 +192,8 @@ protected:

public:
    SwUndoSaveContent();
    ~SwUndoSaveContent() COVERITY_NOEXCEPT_FALSE;
    virtual ~SwUndoSaveContent() COVERITY_NOEXCEPT_FALSE;
    virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
};

// Save a complete section in nodes-array.
@@ -274,6 +276,8 @@ public:
    static bool IsCreateUndoForNewFly(SwFormatAnchor const& rAnchor,
        sal_uLong const nStartNode, sal_uLong const nEndNode);
    std::vector<SwFrameFormat*> * GetFlysAnchoredAt() { return m_pFrameFormats.get(); }

    void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};

class SwUndoInsDoc final : public SwUndoInserts
@@ -307,6 +311,7 @@ protected:

public:
    virtual ~SwUndoFlyBase() override;
    void dumpAsXml(xmlTextWriterPtr pWriter) const override;

};

diff --git a/sw/source/core/inc/UndoDelete.hxx b/sw/source/core/inc/UndoDelete.hxx
index ce38a4d..6e38201 100644
--- a/sw/source/core/inc/UndoDelete.hxx
+++ b/sw/source/core/inc/UndoDelete.hxx
@@ -27,6 +27,7 @@

class SwRedlineSaveDatas;
class SwTextNode;
typedef struct _xmlTextWriter* xmlTextWriterPtr;

namespace sfx2 {
    class MetadatableUndo;
@@ -101,6 +102,7 @@ public:
    bool IsDelFullPara() const { return m_bDelFullPara; }

    void DisableMakeFrames() { m_bDisableMakeFrames = true; };
    void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};

#endif // INCLUDED_SW_SOURCE_CORE_INC_UNDODELETE_HXX
diff --git a/sw/source/core/inc/UndoManager.hxx b/sw/source/core/inc/UndoManager.hxx
index fda9c73..4113d54 100644
--- a/sw/source/core/inc/UndoManager.hxx
+++ b/sw/source/core/inc/UndoManager.hxx
@@ -86,6 +86,7 @@ public:
                                   bool bTryMerg = false) override;
    virtual bool Undo() override;
    virtual bool Redo() override;
    void dumpAsXml(xmlTextWriterPtr pWriter) const;

    SwUndo * RemoveLastUndo();
    SwUndo * GetLastUndo();
diff --git a/sw/source/core/inc/rolbck.hxx b/sw/source/core/inc/rolbck.hxx
index 1882a68..96a8eb5 100644
--- a/sw/source/core/inc/rolbck.hxx
+++ b/sw/source/core/inc/rolbck.hxx
@@ -54,6 +54,7 @@ class SwFormatChain;
class SwNode;
class SwCharFormat;
enum class SwFieldIds : sal_uInt16;
typedef struct _xmlTextWriter* xmlTextWriterPtr;

enum HISTORY_HINT {
    HSTRY_SETFMTHNT,
@@ -85,6 +86,7 @@ public:
    virtual void SetInDoc( SwDoc* pDoc, bool bTmpSet ) = 0;
    HISTORY_HINT Which() const                     { return m_eWhichId; }
    virtual OUString GetDescription() const;
    virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
};

class SwHistorySetFormat : public SwHistoryHint
@@ -98,6 +100,7 @@ public:
    virtual void SetInDoc( SwDoc* pDoc, bool bTmpSet ) override;
    virtual OUString GetDescription() const override;

    void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};

class SwHistoryResetFormat : public SwHistoryHint
@@ -234,6 +237,7 @@ public:
    virtual void SetInDoc( SwDoc* pDoc, bool bTmpSet ) override;
    SwUndoDelLayFormat* GetUDelLFormat() { return m_pUndo.get(); }

    void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};

class SwHistoryBookmark : public SwHistoryHint
@@ -400,6 +404,8 @@ public:
        const bool bCopyFields );

    void CopyFormatAttr( const SfxItemSet& rSet, sal_uLong nNodeIdx );

    void dumpAsXml(xmlTextWriterPtr pWriter) const;
};

class SwRegHistory : public SwClient
diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index ae9311d..976b38c 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -577,7 +577,12 @@ void SwFormatContent::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatContent"));
    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("startNode"), BAD_CAST(OString::number(m_pStartNode->GetNode().GetIndex()).getStr()));
    if (m_pStartNode)
    {
        xmlTextWriterWriteAttribute(
            pWriter, BAD_CAST("startNode"),
            BAD_CAST(OString::number(m_pStartNode->GetNode().GetIndex()).getStr()));
    }
    xmlTextWriterEndElement(pWriter);
}

diff --git a/sw/source/core/undo/docundo.cxx b/sw/source/core/undo/docundo.cxx
index 61629e0..ce41625 100644
--- a/sw/source/core/undo/docundo.cxx
+++ b/sw/source/core/undo/docundo.cxx
@@ -19,6 +19,8 @@

#include <UndoManager.hxx>

#include <libxml/xmlwriter.h>

#include <doc.hxx>
#include <docsh.hxx>
#include <view.hxx>
@@ -651,6 +653,18 @@ bool UndoManager::Redo()
    }
}

void UndoManager::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    xmlTextWriterStartElement(pWriter, BAD_CAST("swUndoManager"));
    SdrUndoManager::dumpAsXml(pWriter);

    xmlTextWriterStartElement(pWriter, BAD_CAST("m_xUndoNodes"));
    m_xUndoNodes->dumpAsXml(pWriter);
    xmlTextWriterEndElement(pWriter);

    xmlTextWriterEndElement(pWriter);
}

void UndoManager::EmptyActionsChanged()
{
    if (m_pDocShell)
diff --git a/sw/source/core/undo/rolbck.cxx b/sw/source/core/undo/rolbck.cxx
index 2de4c62..8806f4f 100644
--- a/sw/source/core/undo/rolbck.cxx
+++ b/sw/source/core/undo/rolbck.cxx
@@ -18,6 +18,9 @@
 */

#include <rolbck.hxx>

#include <libxml/xmlwriter.h>

#include <svl/itemiter.hxx>
#include <editeng/formatbreakitem.hxx>
#include <hints.hxx>
@@ -61,6 +64,16 @@ OUString SwHistoryHint::GetDescription() const
    return OUString();
}

void SwHistoryHint::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    xmlTextWriterStartElement(pWriter, BAD_CAST("SwHistoryHint"));
    xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("symbol"), BAD_CAST(typeid(*this).name()));
    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_eWhichId"),
                                BAD_CAST(OString::number(m_eWhichId).getStr()));
    xmlTextWriterEndElement(pWriter);
}

SwHistorySetFormat::SwHistorySetFormat( const SfxPoolItem* pFormatHt, sal_uLong nNd )
    :  SwHistoryHint( HSTRY_SETFMTHNT )
    ,  m_pAttr( pFormatHt->Clone() )
@@ -133,6 +146,21 @@ OUString SwHistorySetFormat::GetDescription() const
    return aResult;
}

void SwHistorySetFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    xmlTextWriterStartElement(pWriter, BAD_CAST("SwHistorySetFormat"));
    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nNodeIndex"),
                                BAD_CAST(OString::number(m_nNodeIndex).getStr()));
    SwHistoryHint::dumpAsXml(pWriter);

    if (m_pAttr)
    {
        m_pAttr->dumpAsXml(pWriter);
    }

    xmlTextWriterEndElement(pWriter);
}

void SwHistorySetFormat::SetInDoc( SwDoc* pDoc, bool bTmpSet )
{
    SwNode * pNode = pDoc->GetNodes()[ m_nNodeIndex ];
@@ -553,6 +581,19 @@ void SwHistoryTextFlyCnt::SetInDoc( SwDoc* pDoc, bool )
    m_pUndo->UndoImpl(context);
}

void SwHistoryTextFlyCnt::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    xmlTextWriterStartElement(pWriter, BAD_CAST("SwHistoryTextFlyCnt"));
    SwHistoryHint::dumpAsXml(pWriter);

    if (m_pUndo)
    {
        m_pUndo->dumpAsXml(pWriter);
    }

    xmlTextWriterEndElement(pWriter);
}

SwHistoryBookmark::SwHistoryBookmark(
    const ::sw::mark::IMark& rBkmk,
    bool bSavePos,
@@ -1241,6 +1282,21 @@ void SwHistory::CopyFormatAttr(
    }
}

void SwHistory::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    xmlTextWriterStartElement(pWriter, BAD_CAST("SwHistory"));
    xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);

    xmlTextWriterStartElement(pWriter, BAD_CAST("m_SwpHstry"));
    for (const auto& pHistory : m_SwpHstry)
    {
        pHistory->dumpAsXml(pWriter);
    }
    xmlTextWriterEndElement(pWriter);

    xmlTextWriterEndElement(pWriter);
}

void SwHistory::CopyAttr(
    SwpHints const * pHts,
    const sal_uLong nNodeIdx,
diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx
index d225d1e..cc00137 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -18,6 +18,9 @@
 */

#include <UndoDelete.hxx>

#include <libxml/xmlwriter.h>

#include <hintids.hxx>
#include <rtl/ustrbuf.hxx>
#include <unotools/charclass.hxx>
@@ -1313,4 +1316,13 @@ void SwUndoDelete::SetTableName(const OUString & rName)
    m_sTableName = rName;
}

void SwUndoDelete::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    xmlTextWriterStartElement(pWriter, BAD_CAST("SwUndoDelete"));
    xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
    SwUndo::dumpAsXml(pWriter);
    SwUndoSaveContent::dumpAsXml(pWriter);
    xmlTextWriterEndElement(pWriter);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index aca9012..b2609a2 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -17,6 +17,8 @@
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <libxml/xmlwriter.h>

#include <IShellCursorSupplier.hxx>
#include <txtftn.hxx>
#include <fmtanchr.hxx>
@@ -702,6 +704,19 @@ SwUndoSaveContent::~SwUndoSaveContent() COVERITY_NOEXCEPT_FALSE
{
}

void SwUndoSaveContent::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    xmlTextWriterStartElement(pWriter, BAD_CAST("SwUndoSaveContent"));
    xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);

    if (m_pHistory)
    {
        m_pHistory->dumpAsXml(pWriter);
    }

    xmlTextWriterEndElement(pWriter);
}

// This is needed when deleting content. For REDO all contents will be moved
// into the UndoNodesArray. These methods always create a new node to insert
// content. As a result, the attributes will not be expanded.
diff --git a/sw/source/core/undo/undobj1.cxx b/sw/source/core/undo/undobj1.cxx
index 51ba206..b9757d2 100644
--- a/sw/source/core/undo/undobj1.cxx
+++ b/sw/source/core/undo/undobj1.cxx
@@ -17,6 +17,8 @@
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <libxml/xmlwriter.h>

#include <svl/itemiter.hxx>
#include <svx/svdundo.hxx>
#include <hintids.hxx>
@@ -60,6 +62,28 @@ SwUndoFlyBase::~SwUndoFlyBase()
    }
}

void SwUndoFlyBase::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    xmlTextWriterStartElement(pWriter, BAD_CAST("SwUndoFlyBase"));
    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nNodePagePos"),
                                BAD_CAST(OString::number(m_nNodePagePos).getStr()));
    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nContentPos"),
                                BAD_CAST(OString::number(m_nContentPos).getStr()));
    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nRndId"),
                                BAD_CAST(OString::number(static_cast<int>(m_nRndId)).getStr()));
    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_bDelFormat"),
                                BAD_CAST(OString::boolean(m_bDelFormat).getStr()));

    SwUndo::dumpAsXml(pWriter);

    if (m_pFrameFormat)
    {
        m_pFrameFormat->dumpAsXml(pWriter);
    }

    xmlTextWriterEndElement(pWriter);
}

void SwUndoFlyBase::InsFly(::sw::UndoRedoContext & rContext, bool bShowSelFrame)
{
    SwDoc *const pDoc = & rContext.GetDoc();
diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx
index 6e08fb5..dc5303c 100644
--- a/sw/source/core/undo/unins.cxx
+++ b/sw/source/core/undo/unins.cxx
@@ -490,9 +490,6 @@ class SwUndoReplace::Impl

public:
    Impl(SwPaM const& rPam, OUString const& rIns, bool const bRegExp);
    virtual ~Impl()
    {
    }

    void UndoImpl( ::sw::UndoRedoContext & );
    void RedoImpl( ::sw::UndoRedoContext & );
diff --git a/sw/source/core/undo/untblk.cxx b/sw/source/core/undo/untblk.cxx
index 2a4b489..6df02f3 100644
--- a/sw/source/core/undo/untblk.cxx
+++ b/sw/source/core/undo/untblk.cxx
@@ -17,6 +17,8 @@
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <libxml/xmlwriter.h>

#include <fmtanchr.hxx>
#include <frmfmt.hxx>
#include <doc.hxx>
@@ -178,6 +180,39 @@ bool SwUndoInserts::IsCreateUndoForNewFly(SwFormatAnchor const& rAnchor,
            || nEndNode == pAnchorPos->nNode.GetIndex());
}

void SwUndoInserts::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    xmlTextWriterStartElement(pWriter, BAD_CAST("SwUndoInserts"));
    xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
    xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s",
                                      BAD_CAST(typeid(*this).name()));

    SwUndo::dumpAsXml(pWriter);
    SwUndoSaveContent::dumpAsXml(pWriter);

    if (m_pFrameFormats)
    {
        xmlTextWriterStartElement(pWriter, BAD_CAST("m_pFrameFormats"));
        for (const auto& pFormat : *m_pFrameFormats)
        {
            pFormat->dumpAsXml(pWriter);
        }
        xmlTextWriterEndElement(pWriter);
    }

    if (!m_FlyUndos.empty())
    {
        xmlTextWriterStartElement(pWriter, BAD_CAST("m_FlyUndos"));
        for (const auto& pFly : m_FlyUndos)
        {
            pFly->dumpAsXml(pWriter);
        }
        xmlTextWriterEndElement(pWriter);
    }

    xmlTextWriterEndElement(pWriter);
}

SwUndoInserts::~SwUndoInserts()
{
    if (m_pUndoNodeIndex) // delete also the section from UndoNodes array