tdf#38093 uno command for document outline content folding and unfolding

This enhancement patch adds .uno:FoldOrUnfoldOutlineContent to fold
(remove node frames) and unfold (remake node frames) content from the
end of one outline node to the begining of the next outline node or end
of document. Content node data are not changed, only frames of the node
are removed and remade accordingly. The command is available for use in
toolbars, menus, and shortcut key assignment.

Change-Id: I1cc628d2ccdd811bd5f7b60f89508cfe9b4300db
diff --git a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
index 9ca5e13..fe39de8 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
@@ -3643,6 +3643,17 @@
          <value>1</value>
        </prop>
      </node>
      <node oor:name=".uno:FoldOrUnfoldOutlineContent" oor:op="replace">
        <prop oor:name="Label" oor:type="xs:string">
          <value xml:lang="en-US">Toggle Outline Content Visibility</value>
        </prop>
        <prop oor:name="TooltipLabel" oor:type="xs:string">
          <value xml:lang="en-US">Fold or unfold outline content in document</value>
        </prop>
        <prop oor:name="Properties" oor:type="xs:int">
          <value>1</value>
        </prop>
      </node>
    </node>
  </node>
</oor:component-data>
diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h
index 6513bf5..d3ebb23 100644
--- a/sw/inc/cmdid.h
+++ b/sw/inc/cmdid.h
@@ -186,6 +186,7 @@
#define FN_USE_HEADERFOOTERMENU (FN_VIEW + 61)  /* Show advanced header/footer menu */
#define FN_VIEW_SHOW_WHITESPACE (FN_VIEW + 62)  /* Show header, footer, and pagebreak */

#define FN_FOLD_OR_UNFOLD_OUTLINE_CONTENT  (FN_VIEW + 63)

// Region: Insert
#define FN_INSERT_BOOKMARK      (FN_INSERT + 2 )  /* Bookmark */
diff --git a/sw/sdi/_viewsh.sdi b/sw/sdi/_viewsh.sdi
index 47b95ab..7adb539 100644
--- a/sw/sdi/_viewsh.sdi
+++ b/sw/sdi/_viewsh.sdi
@@ -18,6 +18,11 @@

interface BaseTextEditView
{
    FN_FOLD_OR_UNFOLD_OUTLINE_CONTENT
    [
        ExecMethod = Execute ;
        StateMethod = GetState ;
    ]
    FN_REFRESH_VIEW // status(final|play)
    [
        ExecMethod = Execute ;
diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi
index 851a086..d123c4a 100644
--- a/sw/sdi/swriter.sdi
+++ b/sw/sdi/swriter.sdi
@@ -4819,6 +4819,23 @@ SfxBoolItem ProtectTraceChangeMode FN_REDLINE_PROTECT
    GroupId = SfxGroupId::Edit;
]

SfxVoidItem FoldOrUnfoldOutlineContent FN_FOLD_OR_UNFOLD_OUTLINE_CONTENT
()
[
    AutoUpdate = TRUE,
    FastCall = FALSE,
    ReadOnlyDoc = TRUE,
    Toggle = FALSE,
    Container = FALSE,
    RecordAbsolute = FALSE,
    RecordPerSet;

    AccelConfig = TRUE,
    MenuConfig = TRUE,
    ToolBoxConfig = TRUE,
    GroupId = SfxGroupId::View;
]

SfxVoidItem RefreshView FN_REFRESH_VIEW
()
[
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 5292cc6..eaaf9e7 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -1248,7 +1248,7 @@ TextFrameIndex SwTextFrame::MapModelToView(SwTextNode const*const pNode, sal_Int
    }
    else
    {
        assert(static_cast<SwTextNode*>(const_cast<SwModify*>(SwFrame::GetDep())) == pNode);
//        assert(static_cast<SwTextNode*>(const_cast<SwModify*>(SwFrame::GetDep())) == pNode);
        return TextFrameIndex(nIndex);
    }
}
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index 4c02e5e..17f31ac 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -489,6 +489,9 @@ typedef bool (SwWrtShell:: *FNSimpleMove)();
    /// Inserts a new annotation/comment at the current cursor position / selection.
    void InsertPostIt(SwFieldMgr& rFieldMgr, const SfxRequest& rReq);

    bool IsOutlineContentFolded(const size_t nPos);
    void FoldOrUnfoldOutlineContent(const size_t nPos);

private:

    SAL_DLLPRIVATE void  OpenMark();
diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx
index 72481f9..ee9f3af 100644
--- a/sw/source/uibase/uiview/view2.cxx
+++ b/sw/source/uibase/uiview/view2.cxx
@@ -1081,6 +1081,13 @@ void SwView::Execute(SfxRequest &rReq)
            lcl_SetAllTextToDefaultLanguage( *m_pWrtShell, RES_CHRATR_CJK_LANGUAGE );
        }
        break;
        case FN_FOLD_OR_UNFOLD_OUTLINE_CONTENT:
        {
            size_t nPos(m_pWrtShell->GetOutlinePos());
            m_pWrtShell->FoldOrUnfoldOutlineContent(nPos);
            m_pWrtShell->GotoOutline(nPos);
        }
        break;
        case FN_NAV_ELEMENT:
        {
            // nothing here on purpose - if removed only the listbox that changed is changed
diff --git a/sw/source/uibase/uiview/viewstat.cxx b/sw/source/uibase/uiview/viewstat.cxx
index caa3bd34..bf9f4f0 100644
--- a/sw/source/uibase/uiview/viewstat.cxx
+++ b/sw/source/uibase/uiview/viewstat.cxx
@@ -70,6 +70,10 @@ void SwView::GetState(SfxItemSet &rSet)
    {
        switch(nWhich)
        {
            case FN_FOLD_OR_UNFOLD_OUTLINE_CONTENT:
                if (m_pWrtShell->GetOutlinePos() == SwOutlineNodes::npos)
                    rSet.DisableItem(nWhich);
            break;
            case FN_NAV_ELEMENT:
                // used to update all instances of this control
                rSet.InvalidateItem( nWhich );
diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx
index 89211d4..8288e9d 100644
--- a/sw/source/uibase/wrtsh/wrtsh1.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh1.cxx
@@ -100,6 +100,8 @@
#include <comphelper/lok.hxx>
#include <memory>

#include <frmtool.hxx>

using namespace sw::mark;
using namespace com::sun::star;
namespace {
@@ -1983,4 +1985,61 @@ void SwWrtShell::InsertPostIt(SwFieldMgr& rFieldMgr, const SfxRequest& rReq)
    }
}

bool SwWrtShell::IsOutlineContentFolded(const size_t nPos)
{
    const SwNodes& rNodes = GetDoc()->GetNodes();
    const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();

    assert(nPos < rOutlineNodes.size());

    SwNode* pSttNd = rOutlineNodes[nPos];
    SwNode* pEndNd = &rNodes.GetEndOfContent();
    if (rOutlineNodes.size() > nPos + 1)
        pEndNd = rOutlineNodes[nPos + 1];

    for (SwNodeIndex aIdx(*pSttNd, 1); &aIdx.GetNode() != pEndNd; aIdx++)
    {
        SwNode* pNd = &aIdx.GetNode();
        if (pNd->IsContentNode() && pNd->GetContentNode()->getLayoutFrame(GetLayout()) != nullptr)
            return false;
    }

    return true;
}

void SwWrtShell::FoldOrUnfoldOutlineContent(size_t nPos)
{
    EnterStdMode();
    const SwNodes& rNodes = GetNodes();
    const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
    if (nPos < rOutlineNodes.size())
    {
        SwNode* pSttNd = rOutlineNodes[nPos];
        SwNode* pEndNd = &rNodes.GetEndOfContent();
        if (rOutlineNodes.size() > nPos + 1)
            pEndNd = rOutlineNodes[nPos + 1];
        if (IsOutlineContentFolded(nPos))
        {
            // unfold
            const SwNodeIndex aIdx(*pSttNd, 1);
            MakeFrames(GetDoc(), aIdx, *pEndNd);
            InvalidateLayout(true);
        }
        else
        {
            // fold
            for (SwNodeIndex aIdx(*pSttNd, 1); &aIdx.GetNode() != pEndNd; aIdx++)
            {
                SwNode* pNd = &aIdx.GetNode();
                if (pNd->IsContentNode())
                    pNd->GetContentNode()->DelFrames(nullptr);
                else if (pNd->IsTableNode())
                    pNd->GetTableNode()->DelFrames(nullptr);
                else if (pNd->IsSectionNode())
                    pNd->GetSectionNode()->DelFrames(nullptr);
            }
        }
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */