sw/inc/crsrsh.hxx                           |    2 
 sw/inc/doc.hxx                              |    4 
 sw/inc/editsh.hxx                           |    3 
 sw/inc/ndarr.hxx                            |   15 +
 sw/inc/ndtxt.hxx                            |    9 
 sw/qa/uitest/data/tdf164074.fodt            |  214 +++++++++++++++++++
 sw/qa/uitest/navigator/movechapterupdown.py |  305 ++++++++++++++++++++++++++++
 sw/source/core/crsr/crstrvl.cxx             |   31 ++
 sw/source/core/doc/docnum.cxx               |   64 +++++
 sw/source/core/docnode/ndnum.cxx            |   53 ++++
 sw/source/core/edit/ednumber.cxx            |    5 
 sw/source/core/txtnode/ndtxt.cxx            |   38 +++
 sw/source/uibase/utlui/content.cxx          |  104 +++++++++
 13 files changed, 826 insertions(+), 21 deletions(-)

New commits:
commit 32398232e925d18d2ac5a6d467b61e1a84a0df7c
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Wed Nov 27 16:52:10 2024 +0100
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Thu Nov 28 12:39:47 2024 +0100

    tdf#164074 sw inline heading: add up/down outline moving
    
    Move inline headings with their outline tree in
    Navigator, clicking on the Move Heading Up/Down icons.
    
    Instead of changing CompareSwOutlineNodes, which breaks
    the code at other places, add a new SwOutlineNodesInline
    and CompareSwOutlineNodesInline to sort inline headings
    (put in Inline Heading frames) with normal headings only
    for MoveOutlinePara and other part of Navigator's
    outline moving.
    
    Reordering chapters and sections using the Navigator was
    limited for normal (root) headings, but not for headings
    in text frames and tables.
    
    Recent implementation of inline headings use text frames
    with Inline Heading frame style, anchored as characters
    to their paragraphs. Now these inline headings are movable
    with the Navigator, with their outline tree, i.e. the paragraph
    where the inline heading anchored as character, the following
    paragraphs without inline heading, or the following subsections.
    
    Note: selecting the inline headings is possible by the Navigator
    content tree or or by clicking inside the text of the inline
    heading in the document.
    
    Note: according to the fix for tdf#143569, multiple headings
    in the same text frame or table are ordered alphabetically in
    the Navigator. This doesn't effect the inline headings, where
    there is only a single heading in an Inline Heading text frame.
    
    Follow-up to commit 7a35f3dc7419d833b8f47069c4df63e900ccb880
    "tdf#48459 sw inline heading: apply it on the selected words",
    commit d87cf67f8f3346a1e380383917a3a4552fd9248e
    "tdf#131728 sw inline heading: fix missing/broken DOCX export"
    and commit a1dcbd1d1ce6071d48bb5df26d7839aeb21b75a8
    "tdf48459 sw inline heading: add Inline Heading frame style".
    
    Change-Id: I7618aa1d4e1ddc20512d81c9a2babfa660053cbf
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177438
    Tested-by: Jenkins
    Reviewed-by: László Németh <nem...@numbertext.org>

diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx
index 2d7f279c8aa3..2fc9598401cc 100644
--- a/sw/inc/crsrsh.hxx
+++ b/sw/inc/crsrsh.hxx
@@ -663,7 +663,7 @@ public:
     // select the given range of OutlineNodes. Optionally including the 
children
     // the sal_uInt16s are the positions in OutlineNodes-Array (EditShell)
     void MakeOutlineSel(SwOutlineNodes::size_type nSttPos, 
SwOutlineNodes::size_type nEndPos,
-                         bool bWithChildren, bool bKillPams = true );
+        bool bWithChildren, bool bKillPams = true, SwOutlineNodesInline* 
pOutlNdsInline = nullptr);
 
     bool GotoNextOutline();
     bool GotoPrevOutline();
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index 7d0c2955721e..ca8da4e293e3 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -1050,7 +1050,9 @@ public:
     bool OutlineUpDown(const SwPaM& rPam, short nOffset, SwRootFrame const* 
pLayout = nullptr);
 
     /// Outline - move up / move down.
-    bool MoveOutlinePara( const SwPaM& rPam, SwOutlineNodes::difference_type 
nOffset);
+    bool MoveOutlinePara( const SwPaM& rPam,
+                    SwOutlineNodes::difference_type nOffset,
+                    SwOutlineNodesInline* pOutlNdsInline = nullptr);
 
     SW_DLLPUBLIC bool GotoOutline(SwPosition& rPos, const OUString& rName, 
SwRootFrame const* = nullptr) const;
 
diff --git a/sw/inc/editsh.hxx b/sw/inc/editsh.hxx
index 0e9d8064901b..5a16812e89da 100644
--- a/sw/inc/editsh.hxx
+++ b/sw/inc/editsh.hxx
@@ -498,7 +498,8 @@ public:
 
     bool OutlineUpDown( short nOffset = 1 );
 
-    bool MoveOutlinePara( SwOutlineNodes::difference_type nOffset );
+    bool MoveOutlinePara( SwOutlineNodes::difference_type nOffset,
+                        SwOutlineNodesInline* pOutlineNodesInline = nullptr );
 
     bool IsProtectedOutlinePara() const;
 
diff --git a/sw/inc/ndarr.hxx b/sw/inc/ndarr.hxx
index 7bcebeda22db..5c423e11378c 100644
--- a/sw/inc/ndarr.hxx
+++ b/sw/inc/ndarr.hxx
@@ -81,6 +81,21 @@ public:
     static constexpr auto npos = std::numeric_limits<size_type>::max();
 
     bool Seek_Entry(const SwNode* rP, size_type* pnPos) const;
+    static const SwNode* GetRootNode(const SwNode* pNode);
+};
+
+struct CompareSwOutlineNodesInline
+{
+    bool operator()(const SwNode* lhs, const SwNode* rhs) const;
+};
+
+class SwOutlineNodesInline : public o3tl::sorted_vector<SwNode*, 
CompareSwOutlineNodesInline>
+{
+public:
+    static constexpr auto npos = std::numeric_limits<size_type>::max();
+
+    bool Seek_Entry(const SwNode* rP, size_type* pnPos) const;
+    bool Seek_Entry_By_Anchor(const SwNode* rAnchor, size_type* pnPos) const;
 };
 
 struct SwTableToTextSave;
diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index 8c7e32662aa6..174a88e74c53 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -619,6 +619,8 @@ public:
     /**
        Returns outline level of this text node.
 
+       @param bInlineHeading     it can return the outline level of the inline 
heading
+
        If a text node has an outline number (i.e. it has an SwNodeNum
        and an outline numbering rule) the outline level is the level of
        this SwNodeNum.
@@ -627,7 +629,10 @@ public:
        attached the outline level is the outline level of the
        paragraph style.
 
-       Otherwise the text node has no outline level (NO_NUMBERING).
+       Otherwise the text node has no outline level (NO_NUMBERING),
+       except if bInlineHeading is true, and there is an inline heading
+       at the beginning of the paragraph anchored as character and
+       with a different outline level.
 
        NOTE: The outline level of text nodes is subject to change. The
        plan is to have an SwTextNode::nOutlineLevel member that is
@@ -636,7 +641,7 @@ public:
 
        @return outline level or NO_NUMBERING if there is no outline level
      */
-    int GetAttrOutlineLevel() const;
+    int GetAttrOutlineLevel(bool bInlineHeading = false) const;
 
     /**
        Sets the out line level *at* a text node.
diff --git a/sw/qa/uitest/data/tdf164074.fodt b/sw/qa/uitest/data/tdf164074.fodt
new file mode 100644
index 000000000000..be9f064d77c0
--- /dev/null
+++ b/sw/qa/uitest/data/tdf164074.fodt
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; xmlns:c
 alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"
 xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:officeooo="http://openoffice.org/2009/office"; 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:
 meta:1.0" 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:font-face-decls>
+  <style:font-face style:name="Liberation Sans" 
svg:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" 
style:font-pitch="variable"/>
+  <style:font-face style:name="Liberation Serif" 
svg:font-family="&apos;Liberation Serif&apos;" 
style:font-family-generic="roman" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+  <style:default-style style:family="graphic">
+   <style:graphic-properties svg:stroke-color="#3465a4" 
draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" 
draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" 
draw:start-line-spacing-vertical="0.283cm" 
draw:end-line-spacing-horizontal="0.283cm" 
draw:end-line-spacing-vertical="0.283cm" style:writing-mode="lr-tb" 
style:flow-with-text="false"/>
+   <style:paragraph-properties style:text-autospace="ideograph-alpha" 
style:line-break="strict" loext:tab-stop-distance="0cm" 
style:font-independent-line-spacing="false">
+    <style:tab-stops/>
+   </style:paragraph-properties>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" 
fo:language="en" fo:country="US" style:letter-kerning="true"/>
+  </style:default-style>
+  <style:default-style style:family="paragraph">
+   <style:paragraph-properties fo:orphans="2" fo:widows="2" 
fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" 
loext:hyphenation-keep-type="column" style:text-autospace="ideograph-alpha" 
style:punctuation-wrap="hanging" style:line-break="strict" 
style:tab-stop-distance="1.251cm" style:writing-mode="page"/>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" 
fo:language="en" fo:country="US" style:letter-kerning="true" 
fo:hyphenate="false" fo:hyphenation-remain-char-count="2" 
fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" 
loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" 
loext:hyphenation-zone="no-limit"/>
+  </style:default-style>
+  <style:style style:name="Standard" style:family="paragraph" 
style:class="text"/>
+  <style:style style:name="Heading" style:family="paragraph" 
style:parent-style-name="Standard" style:next-style-name="Text_20_body" 
style:class="chapter">
+   <style:paragraph-properties fo:margin-top="0.423cm" 
fo:margin-bottom="0.212cm" style:contextual-spacing="false" 
fo:keep-with-next="always"/>
+   <style:text-properties style:font-name="Liberation Sans" 
fo:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" 
style:font-pitch="variable" fo:font-size="14pt"/>
+  </style:style>
+  <style:style style:name="Text_20_body" style:display-name="Text body" 
style:family="paragraph" style:parent-style-name="Standard" style:class="text">
+   <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.247cm" 
style:contextual-spacing="false" fo:line-height="115%"/>
+  </style:style>
+  <style:style style:name="Caption" style:family="paragraph" 
style:parent-style-name="Standard" style:class="extra">
+   <style:paragraph-properties fo:margin-top="0.212cm" 
fo:margin-bottom="0.212cm" style:contextual-spacing="false" 
text:number-lines="false" text:line-number="0"/>
+   <style:text-properties fo:font-size="12pt" fo:font-style="italic"/>
+  </style:style>
+  <style:style style:name="Index" style:family="paragraph" 
style:parent-style-name="Standard" style:class="index">
+   <style:paragraph-properties text:number-lines="false" text:line-number="0"/>
+   <style:text-properties/>
+  </style:style>
+  <style:style style:name="Heading_20_1" style:display-name="Heading 1" 
style:family="paragraph" style:parent-style-name="Heading" 
style:next-style-name="Text_20_body" style:default-outline-level="1" 
style:class="chapter" style:master-page-name="">
+   <style:paragraph-properties fo:margin-top="0.423cm" 
fo:margin-bottom="0.212cm" style:contextual-spacing="false" 
style:page-number="auto" fo:break-before="page"/>
+   <style:text-properties fo:font-size="18pt" fo:font-weight="bold"/>
+  </style:style>
+  <style:style style:name="Heading_20_2" style:display-name="Heading 2" 
style:family="paragraph" style:parent-style-name="Heading" 
style:next-style-name="Text_20_body" style:default-outline-level="2" 
style:class="chapter">
+   <style:paragraph-properties fo:margin-top="0.353cm" 
fo:margin-bottom="0.212cm" style:contextual-spacing="false"/>
+   <style:text-properties fo:font-size="16pt" fo:font-weight="bold"/>
+  </style:style>
+  <style:style style:name="Heading_20_3" style:display-name="Heading 3" 
style:family="paragraph" style:parent-style-name="Heading" 
style:next-style-name="Text_20_body" style:default-outline-level="3" 
style:class="chapter">
+   <style:paragraph-properties fo:margin-top="0.247cm" 
fo:margin-bottom="0.212cm" style:contextual-spacing="false"/>
+   <style:text-properties fo:font-size="14pt" fo:font-weight="bold"/>
+  </style:style>
+  <style:style style:name="Heading_20_4" style:display-name="Heading 4" 
style:family="paragraph" style:parent-style-name="Heading" 
style:next-style-name="Text_20_body" style:default-outline-level="4" 
style:class="chapter">
+   <style:paragraph-properties fo:margin-top="0.212cm" 
fo:margin-bottom="0.212cm" style:contextual-spacing="false"/>
+   <style:text-properties fo:font-size="13pt" fo:font-style="normal" 
fo:font-weight="bold"/>
+  </style:style>
+  <style:style style:name="Frame_20_contents" style:display-name="Frame 
contents" style:family="paragraph" style:parent-style-name="Standard" 
style:class="extra"/>
+  <style:style style:name="Heading_20_5" style:display-name="Heading 5" 
style:family="paragraph" style:parent-style-name="Heading" 
style:next-style-name="Text_20_body" style:default-outline-level="5" 
style:class="chapter">
+   <style:paragraph-properties fo:margin-top="0.212cm" 
fo:margin-bottom="0.106cm" style:contextual-spacing="false"/>
+   <style:text-properties fo:font-size="12pt" fo:font-style="italic" 
fo:font-weight="bold"/>
+  </style:style>
+  <style:style style:name="Frame" style:family="graphic">
+   <style:graphic-properties text:anchor-type="paragraph" svg:x="0cm" 
svg:y="0cm" fo:margin-left="0.201cm" fo:margin-right="0.201cm" 
fo:margin-top="0.201cm" fo:margin-bottom="0.201cm" style:wrap="parallel" 
style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" 
style:vertical-pos="top" style:vertical-rel="paragraph-content" 
style:horizontal-pos="center" style:horizontal-rel="paragraph-content" 
fo:background-color="transparent" draw:fill="none" draw:fill-color="#729fcf" 
fo:padding="0.15cm" fo:border="0.06pt solid #000000"/>
+  </style:style>
+  <style:style style:name="Inline_20_Heading" style:display-name="Inline 
Heading" style:family="graphic">
+   <style:graphic-properties fo:min-width="0.041cm" fo:min-height="0.041cm" 
text:anchor-type="as-char" svg:y="0cm" fo:margin-left="0cm" 
fo:margin-right="0cm" style:vertical-pos="middle" style:vertical-rel="text" 
fo:background-color="transparent" draw:fill="none" draw:fill-color="#729fcf"/>
+  </style:style>
+  <text:linenumbering-configuration text:number-lines="false" 
text:offset="0.499cm" style:num-format="1" text:number-position="left" 
text:increment="5"/>
+ </office:styles>
+ <office:automatic-styles>
+  <style:style style:name="P1" style:family="paragraph" 
style:parent-style-name="Heading_20_1">
+   <style:text-properties officeooo:rsid="00155f68" 
officeooo:paragraph-rsid="00155f68"/>
+  </style:style>
+  <style:style style:name="P2" style:family="paragraph" 
style:parent-style-name="Text_20_body">
+   <style:text-properties officeooo:rsid="00155f68" 
officeooo:paragraph-rsid="00155f68"/>
+  </style:style>
+  <style:style style:name="P3" style:family="paragraph" 
style:parent-style-name="Heading_20_4">
+   <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" 
style:contextual-spacing="false"/>
+  </style:style>
+  <style:style style:name="P4" style:family="paragraph" 
style:parent-style-name="Heading_20_5">
+   <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" 
style:contextual-spacing="false"/>
+  </style:style>
+  <style:style style:name="P5" style:family="paragraph" 
style:parent-style-name="Text_20_body">
+   <style:text-properties officeooo:rsid="00155f68" 
officeooo:paragraph-rsid="00163552"/>
+  </style:style>
+  <style:style style:name="P6" style:family="paragraph" 
style:parent-style-name="Heading_20_3">
+   <style:text-properties officeooo:paragraph-rsid="00163552"/>
+  </style:style>
+  <style:style style:name="P7" style:family="paragraph" 
style:parent-style-name="Heading_20_2">
+   <style:text-properties officeooo:paragraph-rsid="00155f68"/>
+  </style:style>
+  <style:style style:name="P8" style:family="paragraph" 
style:parent-style-name="Heading_20_3">
+   <style:text-properties officeooo:paragraph-rsid="00155f68"/>
+  </style:style>
+  <style:style style:name="P9" style:family="paragraph" 
style:parent-style-name="Text_20_body">
+   <style:text-properties officeooo:paragraph-rsid="00163552"/>
+  </style:style>
+  <style:style style:name="T1" style:family="text">
+   <style:text-properties officeooo:rsid="00155f68"/>
+  </style:style>
+  <style:style style:name="fr1" style:family="graphic" 
style:parent-style-name="Inline_20_Heading">
+   <style:graphic-properties style:vertical-pos="middle" 
style:vertical-rel="text" style:horizontal-pos="from-left" 
style:horizontal-rel="paragraph-content"/>
+  </style:style>
+  <style:page-layout style:name="pm1">
+   <style:page-layout-properties fo:page-width="21.001cm" 
fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" 
fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" 
fo:margin-right="2cm" style:writing-mode="lr-tb" 
style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" 
style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" 
style:layout-grid-mode="none" style:layout-grid-ruby-below="false" 
style:layout-grid-print="false" style:layout-grid-display="false" 
style:footnote-max-height="0cm" loext:margin-gutter="0cm">
+    <style:footnote-sep style:width="0.018cm" 
style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" 
style:line-style="solid" style:adjustment="left" style:rel-width="25%" 
style:color="#000000"/>
+   </style:page-layout-properties>
+   <style:header-style/>
+   <style:footer-style/>
+  </style:page-layout>
+  <style:style style:name="dp1" style:family="drawing-page">
+   <style:drawing-page-properties draw:background-size="full"/>
+  </style:style>
+ </office:automatic-styles>
+ <office:master-styles>
+  <style:master-page style:name="Standard" style:page-layout-name="pm1" 
draw:style-name="dp1"/>
+ </office:master-styles>
+ <office:body>
+  <office:text text:use-soft-page-breaks="true">
+   <text:h text:style-name="P1" text:outline-level="1">1. H1</text:h>
+   <text:h text:style-name="Heading_20_2" text:outline-level="2">1.1. 
H<text:span text:style-name="T1">2</text:span></text:h>
+   <text:h text:style-name="Heading_20_3" text:outline-level="3">1.1.1. 
H3</text:h>
+   <text:p text:style-name="P2"><draw:frame draw:style-name="fr1" 
draw:name="Frame1" text:anchor-type="as-char" draw:z-index="0">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P3" text:outline-level="4">1.1.1.1. 
Lorem</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>ipsum dolor sit amet, consectetur adipiscing 
elit.</text:p>
+   <text:p text:style-name="P2"><draw:frame draw:style-name="fr1" 
draw:name="Frame3" text:anchor-type="as-char" draw:z-index="1">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">1.1.1.1.1. 
Vestibulum</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>consequat mi quis pretium semper.</text:p>
+   <text:p text:style-name="P2"><draw:frame draw:style-name="fr1" 
draw:name="Frame2" text:anchor-type="as-char" draw:z-index="2">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">1.1.1.1.2. 
Integer</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>sodales tincidunt tristique.</text:p>
+   <text:p text:style-name="P2"><draw:frame draw:style-name="fr1" 
draw:name="Frame4" text:anchor-type="as-char" draw:z-index="3">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P3" text:outline-level="4">1.1.1.2. 
Aliquam</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>velit massa, laoreet vel leo nec, volutpat facilisis 
eros.</text:p>
+   <text:p text:style-name="P5"><draw:frame draw:style-name="fr1" 
draw:name="Frame5" text:anchor-type="as-char" draw:z-index="4">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">1.1.1.2.1. 
Donec</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>consequat arcu ut diam tempor luctus.</text:p>
+   <text:p text:style-name="P5"><draw:frame draw:style-name="fr1" 
draw:name="Frame11" text:anchor-type="as-char" draw:z-index="5">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">1.1.1.2.2. 
Praesent</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>vitae lacus vel leo sodales pharetra a a 
nibh.</text:p>
+   <text:h text:style-name="P6" text:outline-level="3">1.1.2. H3</text:h>
+   <text:p text:style-name="P5"><draw:frame draw:style-name="fr1" 
draw:name="Frame14" text:anchor-type="as-char" draw:z-index="6">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P3" text:outline-level="4">1.1.2.1. 
Lorem</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>ipsum dolor sit amet, consectetur adipiscing 
elit.</text:p>
+   <text:p text:style-name="P5"><draw:frame draw:style-name="fr1" 
draw:name="Frame15" text:anchor-type="as-char" draw:z-index="7">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">1.1.2.1.1. 
Vestibulum</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>consequat mi quis pretium semper.</text:p>
+   <text:p text:style-name="P5"><draw:frame draw:style-name="fr1" 
draw:name="Frame16" text:anchor-type="as-char" draw:z-index="8">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">1.1.2.1.2. 
Integer</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>sodales tincidunt tristique.</text:p>
+   <text:p text:style-name="P5"><draw:frame draw:style-name="fr1" 
draw:name="Frame17" text:anchor-type="as-char" draw:z-index="9">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P3" text:outline-level="4">1.1.2.2. 
Aliquam</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>velit massa, laoreet vel leo nec, volutpat facilisis 
eros.</text:p>
+   <text:p text:style-name="P5"><draw:frame draw:style-name="fr1" 
draw:name="Frame18" text:anchor-type="as-char" draw:z-index="10">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">1.1.2.2.1. 
Donec</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>consequat arcu ut diam tempor luctus.</text:p>
+   <text:p text:style-name="P5"><draw:frame draw:style-name="fr1" 
draw:name="Frame13" text:anchor-type="as-char" draw:z-index="11">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">1.1.2.2.2. 
Praesent</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>vitae lacus vel leo sodales pharetra a a 
nibh.</text:p>
+   <text:h text:style-name="P1" text:outline-level="1">2. H1</text:h>
+   <text:h text:style-name="P7" text:outline-level="2">2.1. H<text:span 
text:style-name="T1">2</text:span></text:h>
+   <text:h text:style-name="P8" text:outline-level="3">2.1.1. H3</text:h>
+   <text:p text:style-name="P2"><draw:frame draw:style-name="fr1" 
draw:name="Frame6" text:anchor-type="as-char" draw:z-index="12">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P3" text:outline-level="4">2.1.1.1. 
Lorem</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>ipsum dolor sit amet, consectetur adipiscing 
elit.</text:p>
+   <text:p text:style-name="P2"><draw:frame draw:style-name="fr1" 
draw:name="Frame7" text:anchor-type="as-char" draw:z-index="13">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">2.1.1.1.1. 
Vestibulum</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>consequat mi quis pretium semper.</text:p>
+   <text:p text:style-name="P2"><draw:frame draw:style-name="fr1" 
draw:name="Frame8" text:anchor-type="as-char" draw:z-index="14">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">2.1.1.1.2. 
Integer</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>sodales tincidunt tristique.</text:p>
+   <text:p text:style-name="P2"><draw:frame draw:style-name="fr1" 
draw:name="Frame9" text:anchor-type="as-char" draw:z-index="15">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P3" text:outline-level="4">2.1.1.2. 
Aliquam</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>velit massa, laoreet vel leo nec, volutpat facilisis 
eros.</text:p>
+   <text:p text:style-name="P5"><draw:frame draw:style-name="fr1" 
draw:name="Frame10" text:anchor-type="as-char" draw:z-index="16">
+     <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+      <text:h text:style-name="P4" text:outline-level="5">2.1.1.2.1. 
Donec</text:h>
+     </draw:text-box>
+    </draw:frame><text:s/>consequat arcu ut diam tempor luctus.</text:p>
+   <text:p text:style-name="P9"><text:span text:style-name="T1"><draw:frame 
draw:style-name="fr1" draw:name="Frame12" text:anchor-type="as-char" 
draw:z-index="17">
+      <draw:text-box fo:min-height="0.041cm" fo:min-width="0.041cm">
+       <text:h text:style-name="P4" text:outline-level="5">2.1.1.2.2. 
Praesent</text:h>
+      </draw:text-box>
+     </draw:frame></text:span><text:span text:style-name="T1"><text:s/>vitae 
lacus vel leo sodales pharetra a a nibh.</text:span></text:p>
+  </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/uitest/navigator/movechapterupdown.py 
b/sw/qa/uitest/navigator/movechapterupdown.py
index d90400ef89b8..c6b6589f7093 100644
--- a/sw/qa/uitest/navigator/movechapterupdown.py
+++ b/sw/qa/uitest/navigator/movechapterupdown.py
@@ -501,4 +501,309 @@ class movechapterupdown(UITestCase):
 
             self.xUITest.executeCommand('.uno:Sidebar')
 
+    def test_tdf164074(self):
+
+        with self.ui_test.load_file(get_url_for_data_file('tdf164074.fodt')):
+            xWriterDoc = self.xUITest.getTopFocusWindow()
+            xWriterEdit = xWriterDoc.getChild('writer_edit')
+
+            self.xUITest.executeCommand('.uno:Sidebar')
+            xWriterEdit.executeAction('SIDEBAR', mkPropertyValues({'PANEL': 
'SwNavigatorPanel'}))
+
+            # wait until the navigator panel is available
+            xNavigatorPanel = 
self.ui_test.wait_until_child_is_available('NavigatorPanel')
+
+            # See the `m_aUpdateTimer.SetTimeout(200)` (to "avoid flickering 
of buttons")
+            # in the SwChildWinWrapper ctor in 
sw/source/uibase/fldui/fldwrap.cxx, where that
+            # m_aUpdateTimer is started by SwChildWinWrapper::ReInitDlg 
triggered from the
+            # xInsert click above.
+            xToolkit = 
self.xContext.ServiceManager.createInstance('com.sun.star.awt.Toolkit')
+            xToolkit.waitUntilAllIdlesDispatched()
+
+            # Given the document chapter structure:
+                # 1. One H1
+                #   1.1. one_A (H2)
+                #   1.2. one_B (H2)
+                # 2. Two (H1)
+                #     A heading of level 3
+                #   2.1. Two_A (H2)
+                #   2.1. Two_B (H2)
+                # 3. Three (H1)
+                #   3.1. Three_A (H2)
+                #   3.2. Three_B (H2)
+
+            xNavigatorPanelContentTree = 
xNavigatorPanel.getChild("contenttree")
+
+            xNavigatorPanelContentTreeHeadings = 
xNavigatorPanelContentTree.getChild('0')
+            xNavigatorPanelContentTreeHeadings.executeAction("EXPAND", tuple())
+
+            #
+            # test a level 1 chapter move up then move down
+            #
+
+            # Double click on the "2. Two (H1)" entry to select and set focus
+            xHeadingsChild1 = xNavigatorPanelContentTreeHeadings.getChild('1')
+            self.assertEqual(get_state_as_dict(xHeadingsChild1)["Text"], "2. 
H1")
+            xHeadingsChild1.executeAction("DOUBLECLICK", tuple())
+
+            
self.ui_test.wait_until_property_is_updated(xNavigatorPanelContentTree, 
"SelectEntryText", "2. H1")
+
+            # Click on the 'Move chapter up' button in the Navigator tool box
+            xNavigatorPanel = xWriterEdit.getChild("NavigatorPanel")
+            xToolBar = 
xNavigatorPanel.getChild("HeadingsContentFunctionButtonsToolbar")
+            xToolBar.executeAction("CLICK", mkPropertyValues({"POS": "2"}))
+
+            # Expected chapter order:
+                # 2. H1
+                #   2.1. H2
+                #     2.1.1. H3
+                #       2.1.1.1. Lorem
+                #         2.1.1.1.1. Vestibulum
+                #         2.1.1.1.2. Integer
+                #       2.1.1.2. Aliquam
+
+            xNavigatorPanelContentTreeHeadings = 
xNavigatorPanelContentTree.getChild('0')
+
+            xHeadingsChild0 = xNavigatorPanelContentTreeHeadings.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0)["Text"], "2. 
H1")
+            xHeadingsChild0Child0 = xHeadingsChild0.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0Child0)["Text"], 
"2.1. H2")
+            xHeadingsChild0Child0Child0 = xHeadingsChild0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0)["Text"], 
"2.1.1. H3")
+            xHeadingsChild0Child0Child0Child0 = 
xHeadingsChild0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0)["Text"], 
"2.1.1.1. Lorem")
+            xHeadingsChild0Child0Child0Child0Child0 = 
xHeadingsChild0Child0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child0)["Text"],
 "2.1.1.1.1. Vestibulum")
+            xHeadingsChild0Child0Child0Child0Child1 = 
xHeadingsChild0Child0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child1)["Text"],
 "2.1.1.1.2. Integer")
+            xHeadingsChild0Child0Child0Child1 = 
xHeadingsChild0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1)["Text"], 
"2.1.1.2. Aliquam")
+
+            # Click on the 'Move chapter down' button in the Navigator tool box
+            xNavigatorPanel = xWriterEdit.getChild("NavigatorPanel")
+            xToolBar = 
xNavigatorPanel.getChild("HeadingsContentFunctionButtonsToolbar")
+            xToolBar.executeAction("CLICK", mkPropertyValues({"POS": "3"}))
+
+            # Expected chapter order is the original order
+            xNavigatorPanelContentTreeHeadings = 
xNavigatorPanelContentTree.getChild('0')
+
+            xHeadingsChild0 = xNavigatorPanelContentTreeHeadings.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0)["Text"], "1. 
H1")
+            xHeadingsChild0Child0 = xHeadingsChild0.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0Child0)["Text"], 
"1.1. H2")
+            xHeadingsChild0Child0Child0 = xHeadingsChild0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0)["Text"], 
"1.1.1. H3")
+            xHeadingsChild0Child0Child0Child0 = 
xHeadingsChild0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0)["Text"], 
"1.1.1.1. Lorem")
+            xHeadingsChild0Child0Child0Child0Child0 = 
xHeadingsChild0Child0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child0)["Text"],
 "1.1.1.1.1. Vestibulum")
+            xHeadingsChild0Child0Child0Child0Child1 = 
xHeadingsChild0Child0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child1)["Text"],
 "1.1.1.1.2. Integer")
+            xHeadingsChild0Child0Child0Child1 = 
xHeadingsChild0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1)["Text"], 
"1.1.1.2. Aliquam")
+
+            #
+            # test moving a sub chapter out of and then back into its parent
+            #
+
+            # Double click on the "1.1.2. (H3)" entry to select and set focus
+            xHeadingsChild0 = xNavigatorPanelContentTreeHeadings.getChild('0')
+            xHeadingsChild0Child0 = xHeadingsChild0.getChild('0')
+            xHeadingsChild0Child0Child1 = xHeadingsChild0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child1)["Text"], 
"1.1.2. H3")
+            xHeadingsChild0Child0Child1.executeAction("DOUBLECLICK", tuple())
+
+            
self.ui_test.wait_until_property_is_updated(xNavigatorPanelContentTree, 
"SelectEntryText", "1.1.2. H3")
+
+            # Click on the 'Move chapter up' button in the Navigator tool box
+            xNavigatorPanel = xWriterEdit.getChild("NavigatorPanel")
+            xToolBar = 
xNavigatorPanel.getChild("HeadingsContentFunctionButtonsToolbar")
+            xToolBar.executeAction("CLICK", mkPropertyValues({"POS": "2"}))
+
+            # Expected chapter order:
+                # 1. H1
+                #   1.1. H2
+                #     1.1.2. H3 <----
+                #       1.1.2.1. Lorem
+                #         1.1.2.1.1. Vestibulum
+                #         1.1.2.1.2. Integer
+                #       1.1.2.2. Aliquam
+                #       1.1.2.2.1. Donec
+                #       1.1.2.2.2. Praesent
+                #     1.1.1. H3
+
+            xNavigatorPanelContentTreeHeadings = 
xNavigatorPanelContentTree.getChild('0')
+
+            xHeadingsChild0 = xNavigatorPanelContentTreeHeadings.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0)["Text"], "1. 
H1")
+            xHeadingsChild0Child0 = xHeadingsChild0.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0Child0)["Text"], 
"1.1. H2")
+            xHeadingsChild0Child0Child0 = xHeadingsChild0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0)["Text"], 
"1.1.2. H3")
+            xHeadingsChild0Child0Child0Child0 = 
xHeadingsChild0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0)["Text"], 
"1.1.2.1. Lorem")
+            xHeadingsChild0Child0Child0Child0Child0 = 
xHeadingsChild0Child0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child0)["Text"],
 "1.1.2.1.1. Vestibulum")
+            xHeadingsChild0Child0Child0Child0Child1 = 
xHeadingsChild0Child0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child1)["Text"],
 "1.1.2.1.2. Integer")
+            xHeadingsChild0Child0Child0Child1 = 
xHeadingsChild0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1)["Text"], 
"1.1.2.2. Aliquam")
+            xHeadingsChild0Child0Child0Child1Child0 = 
xHeadingsChild0Child0Child0Child1.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1Child0)["Text"],
 "1.1.2.2.1. Donec")
+            xHeadingsChild0Child0Child0Child1Child1 = 
xHeadingsChild0Child0Child0Child1.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1Child1)["Text"],
 "1.1.2.2.2. Praesent")
+            xHeadingsChild0Child0Child1 = xHeadingsChild0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child1)["Text"], 
"1.1.1. H3")
+
+            # Click on the 'Move chapter down' button in the Navigator tool box
+            xNavigatorPanel = xWriterEdit.getChild("NavigatorPanel")
+            xToolBar = 
xNavigatorPanel.getChild("HeadingsContentFunctionButtonsToolbar")
+            xToolBar.executeAction("CLICK", mkPropertyValues({"POS": "3"}))
+
+            # Expected chapter order is the original order
+                # 1. H1
+                #   1.1. H2
+                #     1.1.1. H3
+                #       1.1.1.1. Lorem
+                #         1.1.1.1.1. Vestibulum
+                #         1.1.1.1.2. Integer
+                #       1.1.1.2. Aliquam
+                #       1.1.1.2.1. Donec
+                #       1.1.1.2.2. Praesent
+                #     1.1.2. H3
+
+            xNavigatorPanelContentTreeHeadings = 
xNavigatorPanelContentTree.getChild('0')
+
+            xHeadingsChild0 = xNavigatorPanelContentTreeHeadings.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0)["Text"], "1. 
H1")
+            xHeadingsChild0Child0 = xHeadingsChild0.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0Child0)["Text"], 
"1.1. H2")
+            xHeadingsChild0Child0Child0 = xHeadingsChild0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0)["Text"], 
"1.1.1. H3")
+            xHeadingsChild0Child0Child0Child0 = 
xHeadingsChild0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0)["Text"], 
"1.1.1.1. Lorem")
+            xHeadingsChild0Child0Child0Child0Child0 = 
xHeadingsChild0Child0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child0)["Text"],
 "1.1.1.1.1. Vestibulum")
+            xHeadingsChild0Child0Child0Child0Child1 = 
xHeadingsChild0Child0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child1)["Text"],
 "1.1.1.1.2. Integer")
+            xHeadingsChild0Child0Child0Child1 = 
xHeadingsChild0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1)["Text"], 
"1.1.1.2. Aliquam")
+            xHeadingsChild0Child0Child0Child1Child0 = 
xHeadingsChild0Child0Child0Child1.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1Child0)["Text"],
 "1.1.1.2.1. Donec")
+            xHeadingsChild0Child0Child0Child1Child1 = 
xHeadingsChild0Child0Child0Child1.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1Child1)["Text"],
 "1.1.1.2.2. Praesent")
+            xHeadingsChild0Child0Child1 = xHeadingsChild0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child1)["Text"], 
"1.1.2. H3")
+
+            #
+            # test moving a sub chapter out of and then back into its parent
+            #
+
+            # Double click on the "1.1.2. (H3)" entry to select and set focus
+            xHeadingsChild0 = xNavigatorPanelContentTreeHeadings.getChild('0')
+            xHeadingsChild0Child0 = xHeadingsChild0.getChild('0')
+            xHeadingsChild0Child0Child0 = xHeadingsChild0Child0.getChild('0')
+            xHeadingsChild0Child0Child0Child1 = 
xHeadingsChild0Child0Child0.getChild('1')
+
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1)["Text"], 
"1.1.1.2. Aliquam")
+            xHeadingsChild0Child0Child0Child1.executeAction("DOUBLECLICK", 
tuple())
+
+            
self.ui_test.wait_until_property_is_updated(xNavigatorPanelContentTree, 
"SelectEntryText", "1.1.1.2. Aliquam")
+
+            # Click on the 'Move chapter up' button in the Navigator tool box
+            xNavigatorPanel = xWriterEdit.getChild("NavigatorPanel")
+            xToolBar = 
xNavigatorPanel.getChild("HeadingsContentFunctionButtonsToolbar")
+            xToolBar.executeAction("CLICK", mkPropertyValues({"POS": "2"}))
+
+            # Expected chapter order:
+                # 1. H1
+                #   1.1. H2
+                #     1.1.1. H3
+                #       1.1.1.2. Aliquam <---
+                #       1.1.1.2.1. Donec
+                #       1.1.1.2.2. Praesent
+                #       1.1.1.1. Lorem
+                #         1.1.1.1.1. Vestibulum
+                #         1.1.1.1.2. Integer
+                #     1.1.2. H3
+
+            xNavigatorPanelContentTreeHeadings = 
xNavigatorPanelContentTree.getChild('0')
+
+            xHeadingsChild0 = xNavigatorPanelContentTreeHeadings.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0)["Text"], "1. 
H1")
+            xHeadingsChild0Child0 = xHeadingsChild0.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0Child0)["Text"], 
"1.1. H2")
+            xHeadingsChild0Child0Child0 = xHeadingsChild0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0)["Text"], 
"1.1.1. H3")
+            xHeadingsChild0Child0Child0Child0 = 
xHeadingsChild0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0)["Text"], 
"1.1.1.2. Aliquam")
+            xHeadingsChild0Child0Child0Child0Child0 = 
xHeadingsChild0Child0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child0)["Text"],
 "1.1.1.2.1. Donec")
+            xHeadingsChild0Child0Child0Child0Child1 = 
xHeadingsChild0Child0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child1)["Text"],
 "1.1.1.2.2. Praesent")
+            xHeadingsChild0Child0Child0Child1 = 
xHeadingsChild0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1)["Text"], 
"1.1.1.1. Lorem")
+            xHeadingsChild0Child0Child0Child1Child0 = 
xHeadingsChild0Child0Child0Child1.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1Child0)["Text"],
 "1.1.1.1.1. Vestibulum")
+            xHeadingsChild0Child0Child0Child1Child1 = 
xHeadingsChild0Child0Child0Child1.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1Child1)["Text"],
 "1.1.1.1.2. Integer")
+            xHeadingsChild0Child0Child1 = xHeadingsChild0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child1)["Text"], 
"1.1.2. H3")
+
+            # Double click on the "1.1.1.2. Aliquam" entry to select and set 
focus
+            # FIXME: restore focus to avoid this
+            xHeadingsChild0 = xNavigatorPanelContentTreeHeadings.getChild('0')
+            xHeadingsChild0Child0 = xHeadingsChild0.getChild('0')
+            xHeadingsChild0Child0Child0 = xHeadingsChild0Child0.getChild('0')
+            xHeadingsChild0Child0Child0Child0 = 
xHeadingsChild0Child0Child0.getChild('0')
+
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0)["Text"], 
"1.1.1.2. Aliquam")
+            xHeadingsChild0Child0Child0Child0.executeAction("DOUBLECLICK", 
tuple())
+
+            
self.ui_test.wait_until_property_is_updated(xNavigatorPanelContentTree, 
"SelectEntryText", "1.1.1.2. Aliquam")
+
+            # Click on the 'Move chapter down' button in the Navigator tool box
+            xNavigatorPanel = xWriterEdit.getChild("NavigatorPanel")
+            xToolBar = 
xNavigatorPanel.getChild("HeadingsContentFunctionButtonsToolbar")
+            xToolBar.executeAction("CLICK", mkPropertyValues({"POS": "3"}))
+
+            # Expected chapter order is the original order
+                # 1. H1
+                #   1.1. H2
+                #     1.1.1. H3
+                #       1.1.1.1. Lorem
+                #         1.1.1.1.1. Vestibulum
+                #         1.1.1.1.2. Integer
+                #       1.1.1.2. Aliquam
+                #       1.1.1.2.1. Donec
+                #       1.1.1.2.2. Praesent
+                #     1.1.2. H3
+
+            xNavigatorPanelContentTreeHeadings = 
xNavigatorPanelContentTree.getChild('0')
+
+            xHeadingsChild0 = xNavigatorPanelContentTreeHeadings.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0)["Text"], "1. 
H1")
+            xHeadingsChild0Child0 = xHeadingsChild0.getChild('0')
+            self.assertEqual(get_state_as_dict(xHeadingsChild0Child0)["Text"], 
"1.1. H2")
+            xHeadingsChild0Child0Child0 = xHeadingsChild0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0)["Text"], 
"1.1.1. H3")
+            xHeadingsChild0Child0Child0Child0 = 
xHeadingsChild0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0)["Text"], 
"1.1.1.1. Lorem")
+            xHeadingsChild0Child0Child0Child0Child0 = 
xHeadingsChild0Child0Child0Child0.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child0)["Text"],
 "1.1.1.1.1. Vestibulum")
+            xHeadingsChild0Child0Child0Child0Child1 = 
xHeadingsChild0Child0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child0Child1)["Text"],
 "1.1.1.1.2. Integer")
+            xHeadingsChild0Child0Child0Child1 = 
xHeadingsChild0Child0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1)["Text"], 
"1.1.1.2. Aliquam")
+            xHeadingsChild0Child0Child0Child1Child0 = 
xHeadingsChild0Child0Child0Child1.getChild('0')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1Child0)["Text"],
 "1.1.1.2.1. Donec")
+            xHeadingsChild0Child0Child0Child1Child1 = 
xHeadingsChild0Child0Child0Child1.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child0Child1Child1)["Text"],
 "1.1.1.2.2. Praesent")
+            xHeadingsChild0Child0Child1 = xHeadingsChild0Child0.getChild('1')
+            
self.assertEqual(get_state_as_dict(xHeadingsChild0Child0Child1)["Text"], 
"1.1.2. H3")
+
+            self.xUITest.executeCommand('.uno:Sidebar')
+
+
+
 # vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index f2e4d72ac7cf..ca2c9c371222 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -1364,8 +1364,9 @@ SwOutlineNodes::size_type 
SwCursorShell::GetOutlinePos(sal_uInt8 nLevel, SwPaM*
 }
 
 void SwCursorShell::MakeOutlineSel(SwOutlineNodes::size_type nSttPos, 
SwOutlineNodes::size_type nEndPos,
-                                  bool bWithChildren , bool bKillPams)
+                                  bool bWithChildren , bool bKillPams, 
SwOutlineNodesInline* pOutlNdsInline)
 {
+    SwOutlineNodesInline::size_type nEndPosInline = SwOutlineNodesInline::npos;
     const SwNodes& rNds = GetDoc()->GetNodes();
     const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds();
     if( rOutlNds.empty() )
@@ -1383,7 +1384,7 @@ void 
SwCursorShell::MakeOutlineSel(SwOutlineNodes::size_type nSttPos, SwOutlineN
     SwNode* pSttNd = rOutlNds[ nSttPos ];
     SwNode* pEndNd = rOutlNds[ nEndPos ];
 
-    if( bWithChildren )
+    if( bWithChildren && !pOutlNdsInline )
     {
         const int nLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel()-1;
         for( ++nEndPos; nEndPos < rOutlNds.size(); ++nEndPos )
@@ -1394,11 +1395,33 @@ void 
SwCursorShell::MakeOutlineSel(SwOutlineNodes::size_type nSttPos, SwOutlineN
                 break; // EndPos is now on the next one
         }
     }
+    // headings in flys
+    else if( bWithChildren && pOutlNdsInline )
+    {
+        const int nLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel() - 1;
+        pSttNd = const_cast<SwNode*>(SwOutlineNodes::GetRootNode(pSttNd));
+
+        pOutlNdsInline->Seek_Entry( pEndNd, &nEndPosInline );
+
+        for( ++nEndPosInline; nEndPosInline < pOutlNdsInline->size(); 
++nEndPosInline )
+        {
+            pEndNd = (*pOutlNdsInline)[ nEndPosInline ];
+            const int nNxtLevel = 
pEndNd->GetTextNode()->GetAttrOutlineLevel()-1;
+            if( nNxtLevel <= nLevel )
+                break; // EndPos is now on the next one
+        }
+        // set anchor node of the fly node
+        if ( nEndPosInline < pOutlNdsInline->size() )
+            pEndNd = const_cast<SwNode*>(SwOutlineNodes::GetRootNode(pEndNd));
+    }
     // if without children then set onto next one
-    else if( ++nEndPos < rOutlNds.size() )
+    else if( !pOutlNdsInline && ++nEndPos < rOutlNds.size() )
         pEndNd = rOutlNds[ nEndPos ];
+    else if( pOutlNdsInline && ++nEndPosInline < pOutlNdsInline->size() )
+        pEndNd = 
const_cast<SwNode*>(SwOutlineNodes::GetRootNode((*pOutlNdsInline)[nEndPosInline]));
 
-    if( nEndPos == rOutlNds.size() ) // no end found
+    if( ( pOutlNdsInline && nEndPosInline == pOutlNdsInline->size() ) ||
+        ( !pOutlNdsInline && nEndPos == rOutlNds.size() ) ) // no end found
         pEndNd = &rNds.GetEndOfContent();
 
     if( bKillPams )
diff --git a/sw/source/core/doc/docnum.cxx b/sw/source/core/doc/docnum.cxx
index ed1a6ab64335..81bc47a8ab47 100644
--- a/sw/source/core/doc/docnum.cxx
+++ b/sw/source/core/doc/docnum.cxx
@@ -53,6 +53,7 @@
 #include <o3tl/string_view.hxx>
 #include <osl/diagnose.h>
 #include <tools/datetimeutils.hxx>
+//#include <fmtanchr.hxx>
 
 #include <map>
 #include <stdlib.h>
@@ -445,7 +446,8 @@ bool SwDoc::OutlineUpDown(const SwPaM& rPam, short nOffset,
 }
 
 // Move up/down
-bool SwDoc::MoveOutlinePara( const SwPaM& rPam, 
SwOutlineNodes::difference_type nOffset )
+bool SwDoc::MoveOutlinePara( const SwPaM& rPam,
+                SwOutlineNodes::difference_type nOffset, SwOutlineNodesInline* 
pOutlineNodesInline )
 {
     // Do not move to special sections in the nodes array
     const SwPosition& rStt = *rPam.Start(),
@@ -458,15 +460,20 @@ bool SwDoc::MoveOutlinePara( const SwPaM& rPam, 
SwOutlineNodes::difference_type
     }
 
     SwOutlineNodes::size_type nCurrentPos = 0;
+    SwOutlineNodesInline::size_type nCurrentPosInline = 0;
     SwNodeIndex aSttRg( rStt.GetNode() ), aEndRg( rEnd.GetNode() );
 
     int nOutLineLevel = MAXLEVEL;
     SwNode* pSrch = &aSttRg.GetNode();
 
     if( pSrch->IsTextNode())
-        nOutLineLevel = 
static_cast<sal_uInt8>(pSrch->GetTextNode()->GetAttrOutlineLevel()-1);
+        nOutLineLevel = static_cast<sal_uInt8>(
+                        
pSrch->GetTextNode()->GetAttrOutlineLevel(/*bInlineHeading=*/true)-1);
+
     SwNode* pEndSrch = &aEndRg.GetNode();
-    if( !GetNodes().GetOutLineNds().Seek_Entry( pSrch, &nCurrentPos ) )
+
+    auto aOutlineNodes = GetNodes().GetOutLineNds();
+    if( !pOutlineNodesInline && !GetNodes().GetOutLineNds().Seek_Entry( pSrch, 
&nCurrentPos ) )
     {
         if( !nCurrentPos )
             return false; // Promoting or demoting before the first outline => 
no.
@@ -477,24 +484,63 @@ bool SwDoc::MoveOutlinePara( const SwPaM& rPam, 
SwOutlineNodes::difference_type
         else
             aSttRg = *GetNodes().GetEndOfContent().StartOfSectionNode();
     }
+    else if ( pOutlineNodesInline )
+    {
+        if ( !pOutlineNodesInline->Seek_Entry_By_Anchor(pSrch, 
&nCurrentPosInline) )
+        {
+            if( !nCurrentPosInline )
+                return false; // Promoting or demoting before the first 
outline => no.
+            if( --nCurrentPosInline )
+            {
+                aSttRg = *SwOutlineNodes::GetRootNode((*pOutlineNodesInline)[ 
nCurrentPosInline ]);
+            }
+            else if( 0 > nOffset )
+                return false; // Promoting at the top of document?!
+            else
+                aSttRg = *GetNodes().GetEndOfContent().StartOfSectionNode();
+        }
+    }
     SwOutlineNodes::size_type nTmpPos = 0;
+    SwOutlineNodesInline::size_type nTmpPosInline = 0;
     // If the given range ends at an outlined text node we have to decide if 
it has to be a part of
     // the moving range or not. Normally it will be a sub outline of our 
chapter
     // and has to be moved, too. But if the chapter ends with a table(or a 
section end),
     // the next text node will be chosen and this could be the next outline of 
the same level.
     // The criteria has to be the outline level: sub level => incorporate, 
same/higher level => no.
-    if( GetNodes().GetOutLineNds().Seek_Entry( pEndSrch, &nTmpPos ) )
+    if( !pOutlineNodesInline && GetNodes().GetOutLineNds().Seek_Entry( 
pEndSrch, &nTmpPos ) )
     {
         if( !pEndSrch->IsTextNode() || pEndSrch == pSrch ||
             nOutLineLevel < pEndSrch->GetTextNode()->GetAttrOutlineLevel()-1 )
             ++nTmpPos; // For sub outlines only!
     }
+    else if ( pOutlineNodesInline )
+    {
+        if ( pOutlineNodesInline->Seek_Entry_By_Anchor(pEndSrch, 
&nTmpPosInline) && (
+            !pEndSrch->IsTextNode() || pEndSrch == pSrch || nOutLineLevel <
+                
pEndSrch->GetTextNode()->GetAttrOutlineLevel(/*bInlineHeading=*/true)-1 ) )
+        {
+            ++nTmpPosInline;
+        }
+    }
 
-    aEndRg = nTmpPos < GetNodes().GetOutLineNds().size()
+    if ( !pOutlineNodesInline )
+    {
+        aEndRg = nTmpPos < GetNodes().GetOutLineNds().size()
                     ? *GetNodes().GetOutLineNds()[ nTmpPos ]
                     : GetNodes().GetEndOfContent();
+    }
+    else
+    {
+        aEndRg = nTmpPosInline < pOutlineNodesInline->size()
+                    ? *SwOutlineNodes::GetRootNode((*pOutlineNodesInline)[ 
nTmpPosInline ])
+                    : GetNodes().GetEndOfContent();
+    }
+
     if( nOffset >= 0 )
+    {
         nCurrentPos = nTmpPos;
+        nCurrentPosInline = nTmpPosInline;
+    }
     if( aEndRg == aSttRg )
     {
         OSL_FAIL( "Moving outlines: Surprising selection" );
@@ -531,7 +577,13 @@ bool SwDoc::MoveOutlinePara( const SwPaM& rPam, 
SwOutlineNodes::difference_type
     ++aEndRg;
 
     // calculation of the new position
-    if( nOffset < 0 && nCurrentPos < o3tl::make_unsigned(-nOffset) )
+    if( pOutlineNodesInline && nOffset < 0 && nCurrentPosInline < 
o3tl::make_unsigned(-nOffset) )
+        pNd = GetNodes().GetEndOfContent().StartOfSectionNode();
+    else if( pOutlineNodesInline && nCurrentPosInline + nOffset >= 
pOutlineNodesInline->size() )
+        pNd = &GetNodes().GetEndOfContent();
+    else if ( pOutlineNodesInline )
+        pNd = SwOutlineNodes::GetRootNode((*pOutlineNodesInline)[ 
nCurrentPosInline + nOffset ]);
+    else if( nOffset < 0 && nCurrentPos < o3tl::make_unsigned(-nOffset) )
         pNd = GetNodes().GetEndOfContent().StartOfSectionNode();
     else if( nCurrentPos + nOffset >= GetNodes().GetOutLineNds().size() )
         pNd = &GetNodes().GetEndOfContent();
diff --git a/sw/source/core/docnode/ndnum.cxx b/sw/source/core/docnode/ndnum.cxx
index 58b4cbff6488..89e8cc186311 100644
--- a/sw/source/core/docnode/ndnum.cxx
+++ b/sw/source/core/docnode/ndnum.cxx
@@ -23,6 +23,28 @@
 #include <ndtxt.hxx>
 #include <fldbas.hxx>
 #include <osl/diagnose.h>
+#include <flyfrm.hxx>
+#include <fmtanchr.hxx>
+#include <poolfmt.hxx>
+
+static const SwNode* getNodeOrAnchorNode(const SwNode* pNode)
+{
+    // if pNode is an inline heading in an Inline Heading
+    // text frame, return its anchor node instead of pNode
+    if (const auto pFlyFormat = pNode->GetFlyFormat())
+    {
+        SwFormatAnchor const*const pAnchor = &pFlyFormat->GetAnchor();
+        SwNode const*const pAnchorNode = pAnchor->GetAnchorNode();
+        const SwFormat* pParent = pFlyFormat->DerivedFrom();
+        if ( pAnchorNode && pParent &&
+                RndStdIds::FLY_AS_CHAR == pAnchor->GetAnchorId() &&
+                pParent->GetPoolFormatId() == RES_POOLFRM_INLINE_HEADING )
+        {
+            return pAnchorNode;
+        }
+    }
+    return pNode;
+}
 
 bool CompareSwOutlineNodes::operator()(const SwNode* lhs, const SwNode* rhs) 
const
 {
@@ -36,6 +58,37 @@ bool SwOutlineNodes::Seek_Entry(const SwNode* rP, size_type* 
pnPos) const
     return it != end() && rP->GetIndex() == (*it)->GetIndex();
 }
 
+const SwNode* SwOutlineNodes::GetRootNode(const SwNode* pNode)
+{
+    return getNodeOrAnchorNode(pNode);
+}
+
+bool CompareSwOutlineNodesInline::operator()(const SwNode* lhs, const SwNode* 
rhs) const
+{
+    return getNodeOrAnchorNode(lhs)->GetIndex() < 
getNodeOrAnchorNode(rhs)->GetIndex();
+}
+
+bool SwOutlineNodesInline::Seek_Entry(const SwNode* rP, size_type* pnPos) const
+{
+    const_iterator it = lower_bound(rP);
+    *pnPos = it - begin();
+    return it != end() && getNodeOrAnchorNode(rP)->GetIndex() == 
getNodeOrAnchorNode(*it)->GetIndex();
+}
+
+bool SwOutlineNodesInline::Seek_Entry_By_Anchor(const SwNode* rAnchor, 
SwOutlineNodesInline::size_type* pnPos) const
+{
+    SwOutlineNodes::size_type nPos;
+    for( nPos = 0; nPos < size(); ++nPos )
+    {
+       if (getNodeOrAnchorNode(operator[](nPos))->GetIndex() >= 
rAnchor->GetIndex())
+       {
+           break;
+       }
+    }
+    *pnPos = nPos;
+    return nPos < size() && getNodeOrAnchorNode(operator[](nPos)) == rAnchor;
+}
+
 void SwNodes::UpdateOutlineNode(SwNode & rNd)
 {
     assert(IsDocNodes()); // no point in m_pOutlineNodes for undo nodes
diff --git a/sw/source/core/edit/ednumber.cxx b/sw/source/core/edit/ednumber.cxx
index 6a60cd47dd40..c626c2d9bab0 100644
--- a/sw/source/core/edit/ednumber.cxx
+++ b/sw/source/core/edit/ednumber.cxx
@@ -540,10 +540,11 @@ bool SwEditShell::OutlineUpDown( short nOffset )
     return bRet;
 }
 
-bool SwEditShell::MoveOutlinePara( SwOutlineNodes::difference_type nOffset )
+bool SwEditShell::MoveOutlinePara( SwOutlineNodes::difference_type nOffset,
+                SwOutlineNodesInline* pOutlineNodesInline )
 {
     StartAllAction();
-    bool bRet = GetDoc()->MoveOutlinePara( *GetCursor(), nOffset );
+    bool bRet = GetDoc()->MoveOutlinePara( *GetCursor(), nOffset, 
pOutlineNodesInline );
     EndAllAction();
     return bRet;
 }
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index f9cc2b4f82af..356645f6c9d6 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -86,6 +86,8 @@
 #include <svl/itemiter.hxx>
 #include <undobj.hxx>
 #include <formatflysplit.hxx>
+#include <fmtcntnt.hxx>
+#include <poolfmt.hxx>
 
 using namespace ::com::sun::star;
 
@@ -4186,9 +4188,41 @@ void SwTextNode::UpdateOutlineState()
     m_bLastOutlineState = IsOutline();
 }
 
-int SwTextNode::GetAttrOutlineLevel() const
+int SwTextNode::GetAttrOutlineLevel(bool bInlineHeading) const
 {
-    return GetAttr(RES_PARATR_OUTLINELEVEL).GetValue();
+    sal_uInt16 nLevel = GetAttr(RES_PARATR_OUTLINELEVEL).GetValue();
+    // not outline node, so if bIblineHeading = true, look for the
+    // outline level of the inline heading (i.e the outline node in
+    // an Inline Heading frame, which frame anchored as character to this node)
+    if ( !nLevel && bInlineHeading && HasHints() )
+    {
+        // are we in a fly
+        for ( size_t j = m_pSwpHints->Count(); j; )
+        {
+            SwTextAttr* const pHt = m_pSwpHints->Get( --j );
+            if ( RES_TXTATR_FLYCNT == pHt->Which() )
+            {
+                SwFrameFormat* pFrameFormat = 
pHt->GetFlyCnt().GetFrameFormat();
+                const SwFormat* pParent = pFrameFormat->DerivedFrom();
+                SwFormatAnchor const& rAnchor(pFrameFormat->GetAnchor());
+                bool bInlineHeadingFrame = pParent &&
+                        pParent->GetPoolFormatId() == 
RES_POOLFRM_INLINE_HEADING &&
+                        RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId();
+                const SwNodeIndex* pNdIdx = bInlineHeadingFrame
+                                             ? 
pFrameFormat->GetContent().GetContentIdx()
+                                             : nullptr;
+                const SwNodes* pNodesArray = (pNdIdx != nullptr)
+                                             ? &(pNdIdx->GetNodes())
+                                             : nullptr;
+                const SwTextNode *pTextNode = (pNodesArray != nullptr)
+                                        ? (*pNodesArray)[pNdIdx->GetIndex() + 
1]->GetTextNode()
+                                        : nullptr;
+                if ( pTextNode )
+                    return pTextNode->GetAttrOutlineLevel();
+            }
+        }
+    }
+    return nLevel;
 }
 
 void SwTextNode::SetAttrOutlineLevel(int nLevel)
diff --git a/sw/source/uibase/utlui/content.cxx 
b/sw/source/uibase/utlui/content.cxx
index adddc658fba6..35e281debd83 100644
--- a/sw/source/uibase/utlui/content.cxx
+++ b/sw/source/uibase/utlui/content.cxx
@@ -3958,6 +3958,7 @@ void SwContentTree::ExecCommand(std::u16string_view rCmd, 
bool bOutlineWithChild
     // get first regular document content node outline node position in 
outline nodes array
     SwOutlineNodes::size_type nFirstRegularDocContentOutlineNodePos = 
SwOutlineNodes::npos;
     SwNodeOffset nEndOfExtrasIndex = rNodes.GetEndOfExtras().GetIndex();
+    sal_Int32 nHasInlineHeading = 0;
     for (SwOutlineNodes::size_type nPos = 0; nPos < nOutlineNdsSize; nPos++)
     {
         if (rOutlineNodes[nPos]->GetIndex() > nEndOfExtrasIndex)
@@ -3965,6 +3966,8 @@ void SwContentTree::ExecCommand(std::u16string_view rCmd, 
bool bOutlineWithChild
             nFirstRegularDocContentOutlineNodePos = nPos;
             break;
         }
+        if ( bUpDown && rOutlineNodes[nPos] != 
SwOutlineNodes::GetRootNode(rOutlineNodes[nPos]) )
+            ++nHasInlineHeading;
     }
 
     for (auto const& pCurrentEntry : selected)
@@ -3977,7 +3980,20 @@ void SwContentTree::ExecCommand(std::u16string_view 
rCmd, bool bOutlineWithChild
                 (bUpDown && (!pShell->IsOutlineMovable(nActPos) ||
                  nFirstRegularDocContentOutlineNodePos == 
SwOutlineNodes::npos)))
         {
-            continue;
+            // except inline headings, i.e. Inline Heading frames with
+            // single outlines, and achored as characters, which headings
+            // are movable with their anchor node, if they are
+            // 1) not in other frames or 2) not in tables and 3) not protected
+            const SwNode* pRootNode = nHasInlineHeading > 0
+                    ? SwOutlineNodes::GetRootNode(rOutlineNodes[nActPos])
+                    : nullptr;
+            if ( !pRootNode || pRootNode == rOutlineNodes[nActPos] ||
+                 pRootNode != SwOutlineNodes::GetRootNode(pRootNode) || // 
frame in frame
+                 pRootNode->FindTableNode() || // frame in table
+                 pRootNode->IsProtect() ) // write protection
+            {
+               continue;
+            }
         }
 
         if (!bStartedAction)
@@ -3990,7 +4006,91 @@ void SwContentTree::ExecCommand(std::u16string_view 
rCmd, bool bOutlineWithChild
         pShell->GotoOutline( nActPos); // If text selection != box selection
         pShell->Push();
 
-        if (bUpDown)
+        if (nHasInlineHeading && bUpDown)
+        {
+            SwOutlineNodesInline aOutlineNodesInline;
+            // sort inline headings correctly
+            for (SwNode* pNode : rOutlineNodes)
+                aOutlineNodesInline.insert(pNode);
+            const SwOutlineNodes::size_type nOutlineNdsSizeInline = 
aOutlineNodesInline.size();
+
+            // move outline position up/down (outline position promote/demote)
+            SwOutlineNodes::difference_type nDir = bUp ? -1 : 1;
+            SwOutlineNodesInline::size_type nActPosInline;
+            aOutlineNodesInline.Seek_Entry(rOutlineNodes[nActPos], 
&nActPosInline);
+            if ( (nDir == -1 && nActPosInline > 0) ||
+                            (nDir == 1 && nActPosInline < 
nOutlineNdsSizeInline - 1) )
+            {
+                // make outline selection for use by MoveOutlinePara
+                pShell->MakeOutlineSel(nActPos, nActPos, bOutlineWithChildren, 
true, &aOutlineNodesInline);
+
+                int nActPosOutlineLevel =
+                        
rOutlineNodes[nActPos]->GetTextNode()->GetAttrOutlineLevel();
+                // search for sorted position
+                SwOutlineNodesInline::size_type nPos;
+                
aOutlineNodesInline.Seek_Entry_By_Anchor(SwOutlineNodes::GetRootNode(rOutlineNodes[nActPos]),
 &nPos);
+                if (!bUp)
+                {
+                    // move down
+                    int nPosOutlineLevel = -1;
+                    while (++nPos < nOutlineNdsSizeInline)
+                    {
+                        nPosOutlineLevel = 
aOutlineNodesInline[nPos]->GetTextNode()->GetAttrOutlineLevel();
+
+                        // discontinue if moving out of parent or equal level 
is found
+                        if (nPosOutlineLevel <= nActPosOutlineLevel)
+                        {
+                            break;
+                        }
+                        // count the children of the node when they are not 
included in the move
+                        if (!bOutlineWithChildren)
+                            nDir++;
+                    }
+                    if (nPosOutlineLevel >= nActPosOutlineLevel)
+                    {
+                        // move past children
+                        while (++nPos < nOutlineNdsSizeInline)
+                        {
+                            nPosOutlineLevel = 
aOutlineNodesInline[nPos]->GetTextNode()->GetAttrOutlineLevel();
+                            // discontinue if moving out of parent or equal 
level is found
+                            if (nPosOutlineLevel <= nActPosOutlineLevel)
+                                break;
+                            nDir++;
+                        }
+                    }
+                }
+                else
+                {
+                    // move up
+                    while (nPos && --nPos >= 
nFirstRegularDocContentOutlineNodePos - nHasInlineHeading)
+                    {
+                        int nPosOutlineLevel =
+                                
aOutlineNodesInline[nPos]->GetTextNode()->GetAttrOutlineLevel();
+                        // discontinue if equal level is found
+                        if (nPosOutlineLevel == nActPosOutlineLevel)
+                        {
+                            break;
+                        }
+                        // discontinue if moving out of parent
+                        if (nPosOutlineLevel < nActPosOutlineLevel)
+                        {
+                            // Required for expected chapter placement when 
the chapter being moved
+                            // up has an outline level less than the outline 
level of chapters it
+                            // is being moved above and then encounters a 
chapter with an outline
+                            // level that is greater before reaching a chapter 
with the same
+                            // outline level as itself.
+                            if (nDir < -1)
+                                nDir++;
+                            break;
+                        }
+                        nDir--;
+                    }
+                }
+                pShell->MoveOutlinePara(nDir, &aOutlineNodesInline);
+            }
+            pShell->ClearMark();
+        }
+        else if (bUpDown)
         {
             // move outline position up/down (outline position promote/demote)
             SwOutlineNodes::difference_type nDir = bUp ? -1 : 1;

Reply via email to