tdf#141634 Special end of para split for folded outline node
After split place the cursor on a new blank line after the folded
content and at the same level as the split outline node.
Change-Id: I4073a1c0047ab8479993d8e605cc038896cd4630
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123747
Tested-by: Jenkins
Reviewed-by: Jim Raykowski <raykowj@gmail.com>
diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx
index 215cdf2..e74ac03b 100644
--- a/sw/source/uibase/wrtsh/wrtsh1.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh1.cxx
@@ -105,6 +105,10 @@
#include <frmtool.hxx>
#include <viewopt.hxx>
#include <IDocumentUndoRedo.hxx>
#include <UndoInsert.hxx>
#include <UndoCore.hxx>
using namespace sw::mark;
using namespace com::sun::star;
namespace {
@@ -994,15 +998,121 @@ void SwWrtShell::InsertFootnote(const OUString &rStr, bool bEndNote, bool bEdit
m_aNavigationMgr.addEntry(aPos);
}
// tdf#141634
static bool lcl_FoldedOutlineNodeEndOfParaSplit(SwWrtShell *pThis)
{
SwTextNode* pTextNode = pThis->GetCursor()->GetNode().GetTextNode();
if (pTextNode && pTextNode->IsOutline())
{
bool bVisible = true;
pTextNode->GetAttrOutlineContentVisible(bVisible);
if (!bVisible)
{
const SwNodes& rNodes = pThis->GetNodes();
const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
SwOutlineNodes::size_type nPos;
(void) rOutlineNodes.Seek_Entry(pTextNode, &nPos);
SwNode* pSttNd = rOutlineNodes[nPos];
// determine end node of folded outline content
SwNode* pEndNd = &rNodes.GetEndOfContent();
if (rOutlineNodes.size() > nPos + 1)
pEndNd = rOutlineNodes[nPos + 1];
if (pThis->GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
{
// get the next outline node after the folded outline content (iPos)
// it is the next outline node with the same level or less
int nLevel = pSttNd->GetTextNode()->GetAttrOutlineLevel();
SwOutlineNodes::size_type iPos = nPos;
while (++iPos < rOutlineNodes.size() &&
rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() > nLevel);
// get the correct end node
// the outline node may be in frames, headers, footers special section of doc model
SwNode* pStartOfSectionNodeSttNd = pSttNd->StartOfSectionNode();
while (pStartOfSectionNodeSttNd->StartOfSectionNode()
!= pStartOfSectionNodeSttNd->StartOfSectionNode()->StartOfSectionNode())
{
pStartOfSectionNodeSttNd = pStartOfSectionNodeSttNd->StartOfSectionNode();
}
pEndNd = pStartOfSectionNodeSttNd->EndOfSectionNode();
if (iPos < rOutlineNodes.size())
{
SwNode* pStartOfSectionNode = rOutlineNodes[iPos]->StartOfSectionNode();
while (pStartOfSectionNode->StartOfSectionNode()
!= pStartOfSectionNode->StartOfSectionNode()->StartOfSectionNode())
{
pStartOfSectionNode = pStartOfSectionNode->StartOfSectionNode();
}
if (pStartOfSectionNodeSttNd == pStartOfSectionNode)
pEndNd = rOutlineNodes[iPos];
}
}
// table, text box, header, footer
if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
{
// insert before section end node
if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex())
{
SwNodeIndex aIdx(*pSttNd->EndOfSectionNode());
while (aIdx.GetNode().IsEndNode())
--aIdx;
++aIdx;
pEndNd = &aIdx.GetNode();
}
}
// if pSttNd isn't in table but pEndNd is then insert after table
else if (pEndNd->GetTableBox())
{
pEndNd = pEndNd->FindTableNode();
SwNodeIndex aIdx(*pEndNd, -1);
// account for nested tables
while (aIdx.GetNode().GetTableBox())
{
pEndNd = aIdx.GetNode().FindTableNode();
aIdx.Assign(*pEndNd, -1);
}
aIdx.Assign(*pEndNd->EndOfSectionNode(), +1);
pEndNd = &aIdx.GetNode();
}
// end node determined
// now insert the new outline node
SwDoc* pDoc = pThis->GetDoc();
// insert at end of tablebox doesn't work correct without
MakeAllOutlineContentTemporarilyVisible a(pDoc);
SwTextNode* pNd = pDoc->GetNodes().MakeTextNode(*pEndNd, pTextNode->GetTextColl(), true);
(void) rOutlineNodes.Seek_Entry(pNd, &nPos);
pThis->GotoOutline(nPos);
if (pDoc->GetIDocumentUndoRedo().DoesUndo())
{
pDoc->GetIDocumentUndoRedo().ClearRedo();
pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsert>(*pNd));
pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoFormatColl>
(*pNd, pNd->GetTextColl(), true, true));
}
pThis->SetModified();
return true;
}
}
return false;
}
// SplitNode; also, because
// - of deleting selected content;
// - of reset of the Cursorstack if necessary.
void SwWrtShell::SplitNode( bool bAutoFormat )
{
if (!lcl_IsAllowed(this))
return;
ResetCursorStack();
if( !CanInsert() )
return;
@@ -1010,16 +1120,20 @@ void SwWrtShell::SplitNode( bool bAutoFormat )
SwActContext aActContext(this);
m_rView.GetEditWin().FlushInBuffer();
bool bHasSel = HasSelection();
if( bHasSel )
{
StartUndo( SwUndoId::INSERT );
DelRight();
}
StartUndo(SwUndoId::SPLITNODE);
SwFEShell::SplitNode( bAutoFormat );
if( bHasSel )
EndUndo( SwUndoId::INSERT );
bool bHasSel = HasSelection();
if (bHasSel)
DelRight();
bool bHandled = false;
if (GetViewOptions()->IsShowOutlineContentVisibilityButton() && IsEndPara())
bHandled = lcl_FoldedOutlineNodeEndOfParaSplit(this);
if (!bHandled)
SwFEShell::SplitNode( bAutoFormat );
EndUndo(SwUndoId::SPLITNODE);
}
// Turn on numbering