tdf#159565 prerequisite: make hidden sections have zero-height frames

As mentioned in commit bb733957dd (tdf#114973
sw: enable SelectAll with hidden para at start/end, 2023-01-27), the hidden
sections didn't have frames. That prevented correct handling of the case
when such a frame was in the beginning of the document.

This change re-implements the hidden section to use 0-height frames, like
hidden paragraphs, as a pre-requisite for a follow-up change.

Some layout breakages noticed while working on this are unit-tested now.

This change needed to handle the case when the first section is hidden, and
then goes a page break with page style. In this case, the page style must
apply to the very first page of the document. Implementing this now, when
the frame that defines the page style is not the first in the document, I
accidentally fixed also the previously broken case when the first paragraph
was hidden. Now the page style defined in the second paragraph's page break
will apply correctly.

This change makes hidden sections break outer section's frames. This means
that when text borders are shown, there will be an artifact in the place of
the hidden sections (a horizontal line breaking outer frame). I suppose
it's not a problem, actually helping to see the layout better, so in line
with the "show text borders" helper functionality. If this proves to be
problematic, this can be handled specially in a follow-up.

Change-Id: I14ebf0559b463186aba28902cd10c5cc978ba456
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163151
Tested-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
This commit is contained in:
Mike Kaganski 2024-02-09 11:56:19 +06:00
parent 3a0807b08f
commit 0c96119895
27 changed files with 362 additions and 163 deletions

View file

@ -267,7 +267,7 @@ private:
SAL_DLLPRIVATE bool LRMargin( bool, bool bAPI = false );
SAL_DLLPRIVATE bool IsAtLRMargin( bool, bool bAPI = false ) const;
SAL_DLLPRIVATE bool isInHiddenTextFrame(SwShellCursor* pShellCursor);
SAL_DLLPRIVATE bool isInHiddenFrame(SwShellCursor* pShellCursor);
SAL_DLLPRIVATE bool GoStartWordImpl();
SAL_DLLPRIVATE bool GoEndWordImpl();

View file

@ -590,7 +590,7 @@ public:
const SwSection& GetSection() const { return *m_pSection; }
SwSection& GetSection() { return *m_pSection; }
SwFrame *MakeFrame( SwFrame* );
SwFrame* MakeFrame(SwFrame* pSib, bool bHidden);
/** Creates the frms for the SectionNode (i.e. the SectionFrames).
On default the frames are created until the end of the range.

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
<office:styles>
<style:style style:name="Standard" style:family="paragraph" style:class="text">
<style:paragraph-properties fo:margin-top="1in" fo:margin-bottom="0" style:contextual-spacing="false" fo:line-height="12pt"/>
</style:style>
</office:styles>
<office:body>
<office:text>
<text:section text:name="Hidden" text:display="none"/>
<text:section text:name="Shown"/>
</office:text>
</office:body>
</office:document>

View file

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
<office:automatic-styles>
<style:style style:name="P1" style:family="paragraph" style:master-page-name="Landscape">
<style:paragraph-properties style:page-number="1"/>
</style:style>
<style:style style:name="P2" style:family="paragraph" style:master-page-name="Landscape">
<style:paragraph-properties style:page-number="1"/>
<style:text-properties text:display="none"/>
</style:style>
</office:automatic-styles>
<office:body>
<office:text>
<text:p>First line</text:p>
<text:section text:name="Hidden" text:display="none">
<text:p text:style-name="P1"/>
</text:section>
<text:section text:name="Shown">
<text:p>Before break (still first page)</text:p>
</text:section>
<text:section text:name="HiddenText">
<text:p text:style-name="P2"/>
</text:section>
<text:p>After break</text:p>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p/>
<text:p>Should be together with next</text:p>
<text:section text:name="Hidden2" text:display="none">
<text:p text:style-name="P2"/>
</text:section>
<text:p>Should be together with previous</text:p>
</office:text>
</office:body>
</office:document>

View file

@ -97,15 +97,25 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf119875)
{
createSwDoc("tdf119875.odt");
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
sal_Int32 nFirstTop
= getXPath(pXmlDoc, "/root/page[2]/body/section[1]/infos/bounds"_ostr, "top"_ostr)
.toInt32();
sal_Int32 nSecondTop
= getXPath(pXmlDoc, "/root/page[2]/body/section[2]/infos/bounds"_ostr, "top"_ostr)
.toInt32();
// The first section had the same top value as the second one, so they
// overlapped.
CPPUNIT_ASSERT_LESS(nSecondTop, nFirstTop);
assertXPath(pXmlDoc, "//page[2]/body/section[1]"_ostr, "formatName"_ostr, u"S10"_ustr);
assertXPath(pXmlDoc, "//page[2]/body/section[2]"_ostr, "formatName"_ostr, u"S11"_ustr);
assertXPath(pXmlDoc, "//page[2]/body/section[3]"_ostr, "formatName"_ostr, u"S13"_ustr);
assertXPath(pXmlDoc, "//page[2]/body/section[4]"_ostr, "formatName"_ostr, u"S14"_ustr);
// Sections "S10" and "S13" are hidden -> their frames are zero-height
assertXPath(pXmlDoc, "//page[2]/body/section[1]/infos/bounds"_ostr, "height"_ostr, u"0"_ustr);
assertXPath(pXmlDoc, "//page[2]/body/section[3]/infos/bounds"_ostr, "height"_ostr, u"0"_ustr);
OUString S10Top = getXPath(pXmlDoc, "//page[2]/body/section[1]/infos/bounds"_ostr, "top"_ostr);
OUString S11Top = getXPath(pXmlDoc, "//page[2]/body/section[2]/infos/bounds"_ostr, "top"_ostr);
OUString S13Top = getXPath(pXmlDoc, "//page[2]/body/section[3]/infos/bounds"_ostr, "top"_ostr);
OUString S14Top = getXPath(pXmlDoc, "//page[2]/body/section[4]/infos/bounds"_ostr, "top"_ostr);
CPPUNIT_ASSERT_EQUAL(S10Top, S11Top);
CPPUNIT_ASSERT_EQUAL(S13Top, S14Top);
// Section "S11" had the same top value as section "S14", so they overlapped.
CPPUNIT_ASSERT_LESS(S14Top.toInt32(), S11Top.toInt32());
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf137523)
@ -2339,6 +2349,46 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf159259)
CPPUNIT_ASSERT_EQUAL(paraHeight, flyHeight);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testLargeTopParaMarginAfterHiddenSection)
{
// Given a large top margin in Standard paragraph style, and the first section hidden
createSwDoc("largeTopMarginAndHiddenFirstSection.fodt");
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
// Make sure there is only one page and two sections, first hidden (zero-height)
assertXPath(pXmlDoc, "//page"_ostr, 1);
assertXPath(pXmlDoc, "//page/body/section"_ostr, 2);
assertXPath(pXmlDoc, "//page/body/section[1]/infos/bounds"_ostr, "height"_ostr, u"0"_ustr);
// Check that the top margin (1 in = 1440 twip) is added to line height (12 pt = 240 twip)
assertXPath(pXmlDoc, "//page/body/section[2]/infos/bounds"_ostr, "height"_ostr, u"1680"_ustr);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testPageBreakInHiddenSection)
{
// Given a paragraph with page-break-before with page style and page number
createSwDoc("pageBreakInHiddenSection.fodt");
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
assertXPath(pXmlDoc, "//page"_ostr, 4);
assertXPath(pXmlDoc, "//section"_ostr, 4);
assertXPath(pXmlDoc, "//page[1]/body/txt"_ostr, 1);
// The page break inside the hidden section is ignored (otherwise, there would be one section
// on the first page)
assertXPath(pXmlDoc, "//page[1]/body/section"_ostr, 2);
// The first section is hidden
assertXPath(pXmlDoc, "//page[1]/body/section[1]/infos/bounds"_ostr, "height"_ostr, u"0"_ustr);
// Page 2 is empty even page (generated by the next page's section with page-break-before)
assertXPath(pXmlDoc, "//page[2]/body"_ostr, 0);
// The section on page 3 is not hidden, only text in it is, therefore its page break works
assertXPath(pXmlDoc, "//page[3]/body/section"_ostr, 1);
assertXPath(pXmlDoc, "//page[3]/body/section/infos/bounds"_ostr, "height"_ostr, u"0"_ustr);
// The section on page 4 is hidden, thus page break in it is ignored (no further pages, where
// the section would be moved to otherwise)
assertXPath(pXmlDoc, "//page[4]/body/section"_ostr, 1);
assertXPath(pXmlDoc, "//page[4]/body/section/infos/bounds"_ostr, "height"_ostr, u"0"_ustr);
}
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
<office:automatic-styles>
<style:style style:name="P1" style:family="paragraph" style:master-page-name="Landscape">
<style:paragraph-properties style:page-number="auto" fo:break-before="page"/>
</style:style>
</office:automatic-styles>
<office:body>
<office:text>
<text:section text:name="Section 1" text:display="none"/>
<text:section text:name="Section 2">
<text:p text:style-name="P1">A paragraph with a page-break-before</text:p>
</text:section>
<text:section text:name="Section 3" text:display="none"/>
<text:section text:name="Section 4">
<text:p>Lorem</text:p>
</text:section>
</office:text>
</office:body>
</office:document>

View file

@ -235,6 +235,22 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf135083)
CPPUNIT_ASSERT(!getProperty<OUString>(xLastPara, u"ListId"_ustr).isEmpty());
}
CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testHiddenSectionsAroundPageBreak)
{
createSwDoc("hiddenSectionsAroundPageBreak.fodt");
CPPUNIT_ASSERT_EQUAL(1, getPages());
auto xModel(mxComponent.queryThrow<frame::XModel>());
auto xTextViewCursorSupplier(
xModel->getCurrentController().queryThrow<text::XTextViewCursorSupplier>());
auto xCursor(xTextViewCursorSupplier->getViewCursor().queryThrow<text::XPageCursor>());
// Make sure that the page style is set correctly
xCursor->jumpToFirstPage();
CPPUNIT_ASSERT_EQUAL(u"Landscape"_ustr, getProperty<OUString>(xCursor, "PageStyleName"));
}
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();

View file

@ -944,14 +944,14 @@ bool SwCursorShell::MovePage( SwWhichPage fnWhichPage, SwPosPage fnPosPage )
return bRet;
}
bool SwCursorShell::isInHiddenTextFrame(SwShellCursor* pShellCursor)
bool SwCursorShell::isInHiddenFrame(SwShellCursor* pShellCursor)
{
SwContentNode *pCNode = pShellCursor->GetPointContentNode();
std::pair<Point, bool> tmp(pShellCursor->GetPtPos(), false);
SwContentFrame *const pFrame = pCNode
? pCNode->getLayoutFrame(GetLayout(), pShellCursor->GetPoint(), &tmp)
: nullptr;
return !pFrame || (pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsHiddenNow());
return !pFrame || pFrame->IsHiddenNow();
}
// sw_redlinehide: this should work for all cases: GoCurrPara, GoNextPara, GoPrevPara
@ -992,7 +992,7 @@ bool SwCursorShell::MovePara(SwWhichPara fnWhichPara, SwMoveFnCollection const &
//which is what SwCursorShell::UpdateCursorPos will reset
//the position to if we pass it a position in an
//invisible hidden paragraph field
while (isInHiddenTextFrame(pTmpCursor)
while (isInHiddenFrame(pTmpCursor)
|| !IsAtStartOrEndOfFrame(this, pTmpCursor, fnPosPara))
{
if (!pTmpCursor->MovePara(fnWhichPara, fnPosPara))
@ -1799,7 +1799,7 @@ void SwCursorShell::UpdateCursorPos()
SwShellCursor* pShellCursor = getShellCursor( true );
Size aOldSz( GetDocSize() );
if (isInHiddenTextFrame(pShellCursor) && !ExtendedSelectedAll())
if (isInHiddenFrame(pShellCursor) && !ExtendedSelectedAll())
{
SwCursorMoveState aTmpState(CursorMoveState::SetOnlyText);
aTmpState.m_bSetInReadOnly = IsReadOnlyAvailable();
@ -1808,14 +1808,14 @@ void SwCursorShell::UpdateCursorPos()
pShellCursor->DeleteMark();
// kde45196-1.html: try to get to a non-hidden paragraph, there must
// be one in the document body
while (isInHiddenTextFrame(pShellCursor))
while (isInHiddenFrame(pShellCursor))
{
if (!pShellCursor->MovePara(GoNextPara, fnParaStart))
{
break;
}
}
while (isInHiddenTextFrame(pShellCursor))
while (isInHiddenFrame(pShellCursor))
{
if (!pShellCursor->MovePara(GoPrevPara, fnParaStart))
{

View file

@ -1060,7 +1060,7 @@ SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const &
(
nullptr == pFrame ||
( !bInReadOnly && pFrame->IsProtected() ) ||
(pFrame->IsTextFrame() && static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow())
pFrame->IsHiddenNow()
) ||
( !bInReadOnly && pNd->FindSectionNode() &&
pNd->FindSectionNode()->GetSection().IsProtect()
@ -1101,8 +1101,7 @@ SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const &
SwContentFrame const*const pFrame(pNd->getLayoutFrame(pLayout));
if (nullptr == pFrame ||
( !bInReadOnly && pFrame->IsProtected() ) ||
( pFrame->IsTextFrame() &&
static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow()))
pFrame->IsHiddenNow())
{
pNd = nullptr;
continue;

View file

@ -553,7 +553,7 @@ uno::Any SwDoc::Spell( SwPaM& rPaM,
{
nCurrNd = pNd->EndOfSectionIndex();
}
else if( !static_cast<SwTextFrame*>(pContentFrame)->IsHiddenNow() )
else if( !pContentFrame->IsHiddenNow() )
{
if( pPageCnt && *pPageCnt && pPageSt )
{
@ -766,7 +766,7 @@ static bool lcl_HyphenateNode( SwNode* pNd, void* pArgs )
// sw_redlinehide: this will be called once per node for merged nodes;
// the fully deleted ones won't have frames so are skipped.
SwContentFrame* pContentFrame = pNode->getLayoutFrame( pNode->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() );
if( pContentFrame && !static_cast<SwTextFrame*>(pContentFrame)->IsHiddenNow() )
if( pContentFrame && !pContentFrame->IsHiddenNow() )
{
sal_uInt16 *pPageSt = pHyphArgs->GetPageSt();
sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt();

View file

@ -1022,9 +1022,9 @@ SwSectionNode::~SwSectionNode()
}
}
SwFrame *SwSectionNode::MakeFrame( SwFrame *pSib )
SwFrame* SwSectionNode::MakeFrame(SwFrame* pSib, bool bHidden)
{
m_pSection->m_Data.SetHiddenFlag(false);
m_pSection->m_Data.SetHiddenFlag(bHidden);
return new SwSectionFrame( *m_pSection, pSib );
}

View file

@ -1963,7 +1963,7 @@ SwContentNode* SwNodes::GoNextSection( SwNodeIndex * pIdx,
if (SwNodeType::Section == pNd->GetNodeType())
{
const SwSection& rSect = static_cast<const SwSectionNode*>(pNd)->GetSection();
if( (bSkipHidden && rSect.IsHiddenFlag()) ||
if( (bSkipHidden && rSect.CalcHiddenFlag()) ||
(bSkipProtect && rSect.IsProtectFlag()) )
// than skip the section
aTmp = *pNd->EndOfSectionNode();
@ -1974,7 +1974,7 @@ SwContentNode* SwNodes::GoNextSection( SwNodeIndex * pIdx,
{
const SwSection& rSect = static_cast<SwSectionNode*>(pNd->
m_pStartOfSection)->GetSection();
if( (bSkipHidden && rSect.IsHiddenFlag()) ||
if( (bSkipHidden && rSect.CalcHiddenFlag()) ||
(bSkipProtect && rSect.IsProtectFlag()) )
// than skip the section
aTmp = *pNd->EndOfSectionNode();
@ -1985,7 +1985,7 @@ SwContentNode* SwNodes::GoNextSection( SwNodeIndex * pIdx,
const SwSectionNode* pSectNd;
if( ( bSkipHidden || bSkipProtect ) &&
nullptr != (pSectNd = pNd->FindSectionNode() ) &&
( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) ||
( ( bSkipHidden && pSectNd->GetSection().CalcHiddenFlag() ) ||
( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) )
{
aTmp = *pSectNd->EndOfSectionNode();

View file

@ -299,14 +299,11 @@ void SwSection::ImplSetHiddenFlag(bool const bTmpHidden, bool const bCondition)
// Tell all Children that they are hidden
const sw::SectionHidden aHint;
pFormat->CallSwClientNotify(aHint);
// Delete all Frames
pFormat->DelFrames();
}
}
else if (m_Data.IsHiddenFlag()) // show Nodes again
{
// Show all Frames (Child Sections are accounted for by MakeFrames)
// Show all Frames
// Only if the Parent Section is not restricting us!
SwSection* pParentSect = pFormat->GetParentSection();
if( !pParentSect || !pParentSect->IsHiddenFlag() )
@ -314,8 +311,6 @@ void SwSection::ImplSetHiddenFlag(bool const bTmpHidden, bool const bCondition)
// Tell all Children that the Parent is not hidden anymore
const sw::SectionHidden aHint(false);
pFormat->CallSwClientNotify(aHint);
pFormat->MakeFrames();
}
}
}

View file

@ -796,7 +796,7 @@ void SwEditShell::SetNumberingRestart()
if( nullptr != pContentFrame )
{
// skip hidden frames - ignore protection!
if( !static_cast<SwTextFrame*>(pContentFrame)->IsHiddenNow() )
if( !pContentFrame->IsHiddenNow() )
{
// if the node is numbered and the starting value of the numbering equals the
// start value of the numbering rule then set this value as hard starting value

View file

@ -894,6 +894,8 @@ public:
// Fly in ... and footnotes
bool IsProtected() const;
virtual bool IsHiddenNow() const;
bool IsColLocked() const { return mbColLocked; }
virtual bool IsDeleteForbidden() const { return mnForbidDelete > 0; }

View file

@ -88,6 +88,8 @@ public:
virtual void Cut() override;
virtual void Paste( SwFrame* pParent, SwFrame* pSibling = nullptr ) override;
virtual bool IsHiddenNow() const override;
inline const SwSectionFrame *GetFollow() const;
inline SwSectionFrame *GetFollow();
SwSectionFrame* FindMaster() const;

View file

@ -558,7 +558,7 @@ public:
#endif
/// Hidden
bool IsHiddenNow() const; // bHidden && pOut == pPrt
virtual bool IsHiddenNow() const override; // bHidden && pOut == pPrt
void HideHidden(); // Remove appendage if Hidden
void HideFootnotes(TextFrameIndex nStart, TextFrameIndex nEnd);

View file

@ -177,7 +177,7 @@ bool SwContentFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool & )
if ( nMoveAnyway < 3 )
{
if ( nSpace )
if (nSpace || IsHiddenNow())
{
// Do not notify footnotes which are stuck to the paragraph:
// This would require extremely confusing code, taking into
@ -209,7 +209,7 @@ bool SwContentFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool & )
}
// Check for space left in new upper
return nSpace != 0;
return nSpace != 0 || IsHiddenNow();
}
}
return false;
@ -532,7 +532,7 @@ static SwFrame* lcl_NotHiddenPrev( SwFrame* pFrame )
do
{
pRet = lcl_Prev( pRet );
} while ( pRet && pRet->IsTextFrame() && static_cast<SwTextFrame*>(pRet)->IsHiddenNow() );
} while ( pRet && pRet->IsHiddenNow() );
return pRet;
}
@ -1083,9 +1083,8 @@ void SwContentFrame::MakePrtArea( const SwBorderAttrs &rAttrs )
setFramePrintAreaValid(true);
SwRectFnSet aRectFnSet(this);
const bool bTextFrame = IsTextFrame();
SwTwips nUpper = 0;
if ( bTextFrame && static_cast<SwTextFrame*>(this)->IsHiddenNow() )
if (IsTextFrame() && IsHiddenNow())
{
if ( static_cast<SwTextFrame*>(this)->HasFollow() )
static_cast<SwTextFrame*>(this)->JoinFrame();
@ -1715,7 +1714,7 @@ void SwContentFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
const bool bMoveFwdInvalid = nullptr != GetIndNext();
const bool bNxtNew =
( 0 == aRectFnSet.GetHeight(pNxt->getFramePrintArea()) ) &&
(!pNxt->IsTextFrame() ||!static_cast<SwTextFrame*>(pNxt)->IsHiddenNow());
!pNxt->IsHiddenNow();
pNxt->Calc(getRootFrame()->GetCurrShell()->GetOut());
@ -2217,7 +2216,7 @@ bool SwContentFrame::WouldFit_( SwTwips nSpace,
pTmpPrev = nullptr;
else
{
if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsHiddenNow() )
if (pFrame->IsHiddenNow())
pTmpPrev = lcl_NotHiddenPrev( pFrame );
else
pTmpPrev = pFrame;

View file

@ -1015,7 +1015,7 @@ SwFrame *SwFrame::FindNext_()
(!bFootnote || pSct->IsInFootnote() ) )
return pSct;
}
return pRet;
return pRet == this ? nullptr : pRet;
}
// #i27138# - add parameter <_bInSameFootnote>
@ -1401,11 +1401,7 @@ void SwFrame::InvalidateNextPrtArea()
SwFrame* pNextFrame = FindNext();
// skip empty section frames and hidden text frames
{
while ( pNextFrame &&
( ( pNextFrame->IsSctFrame() &&
!static_cast<SwSectionFrame*>(pNextFrame)->GetSection() ) ||
( pNextFrame->IsTextFrame() &&
static_cast<SwTextFrame*>(pNextFrame)->IsHiddenNow() ) ) )
while (pNextFrame && pNextFrame->IsHiddenNow())
{
pNextFrame = pNextFrame->FindNext();
}

View file

@ -1271,8 +1271,7 @@ bool SwFlowFrame::IsPageBreak( bool bAct ) const
// Determine predecessor
const SwFrame *pPrev = m_rThis.FindPrev();
while ( pPrev && ( !pPrev->IsInDocBody() ||
( pPrev->IsTextFrame() && static_cast<const SwTextFrame*>(pPrev)->IsHiddenNow() ) ) )
while (pPrev && (!pPrev->IsInDocBody() || pPrev->IsHiddenNow()))
pPrev = pPrev->FindPrev();
if ( pPrev )
@ -1333,7 +1332,7 @@ bool SwFlowFrame::IsColBreak( bool bAct ) const
// Determine predecessor
const SwFrame *pPrev = m_rThis.FindPrev();
while( pPrev && ( ( !pPrev->IsInDocBody() && !m_rThis.IsInFly() && !m_rThis.FindFooterOrHeader() ) ||
( pPrev->IsTextFrame() && static_cast<const SwTextFrame*>(pPrev)->IsHiddenNow() ) ) )
pPrev->IsHiddenNow() ) )
pPrev = pPrev->FindPrev();
if ( pPrev )
@ -1364,6 +1363,14 @@ bool SwFlowFrame::IsColBreak( bool bAct ) const
return false;
}
// Skip hidden paragraphs and empty sections on the same level
static const SwFrame* skipHiddenSiblingFrames_(const SwFrame* pFrame)
{
while (pFrame && pFrame->IsHiddenNow())
pFrame = pFrame->GetPrev();
return pFrame;
}
bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const
{
if( m_rThis.IsInSct() )
@ -1379,7 +1386,7 @@ bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const
return !pTmp->GetPrev() || IsPageBreak(true);
if( pTmp->IsColumnFrame() && pTmp->GetPrev() )
return IsColBreak( true );
if( pTmp->IsSctFrame() && ( !bSct || pTmp->GetPrev() ) )
if (pTmp->IsSctFrame() && (!bSct || skipHiddenSiblingFrames_(pTmp->GetPrev())))
return false;
pTmp = pTmp->GetUpper();
}
@ -1401,6 +1408,31 @@ bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const
return pTmp && !pTmp->GetPrev();
}
// Skip hidden paragraphs and empty sections
static const SwFrame* skipHiddenFrames_(const SwFrame* pFrame)
{
do
{
pFrame = skipHiddenSiblingFrames_(pFrame);
if (!pFrame || !pFrame->IsSctFrame())
return pFrame;
// Special case: found previous frame is a section
// Search for the last content in the section
auto pSectFrame = static_cast<const SwSectionFrame*>(pFrame);
pFrame = pSectFrame->FindLastContent();
// If the last content is in a table _inside_ the section,
// take the table herself.
// Correction: Check directly, if table is inside table, instead of indirectly
// by checking, if section isn't inside a table
if (pFrame && pFrame->IsInTab())
{
const SwTabFrame* pTableFrame = pFrame->FindTabFrame();
if (pSectFrame->IsAnLower(pTableFrame))
return pTableFrame;
}
} while (true);
}
/** helper method to determine previous frame for calculation of the
upper space
@ -1408,73 +1440,21 @@ bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const
*/
const SwFrame* SwFlowFrame::GetPrevFrameForUpperSpaceCalc_( const SwFrame* _pProposedPrevFrame ) const
{
const SwFrame* pPrevFrame = _pProposedPrevFrame
? _pProposedPrevFrame
: m_rThis.GetPrev();
// Skip hidden paragraphs and empty sections
while ( pPrevFrame &&
( ( pPrevFrame->IsTextFrame() &&
static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) ||
( pPrevFrame->IsSctFrame() &&
!static_cast<const SwSectionFrame*>(pPrevFrame)->GetSection() ) ) )
{
pPrevFrame = pPrevFrame->GetPrev();
}
const SwFrame* pPrevFrame
= skipHiddenFrames_(_pProposedPrevFrame ? _pProposedPrevFrame : m_rThis.GetPrev());
if (pPrevFrame || !m_rThis.IsInFootnote()
|| !(m_rThis.IsSctFrame() || !m_rThis.IsInSct() || !m_rThis.FindSctFrame()->IsInFootnote()))
return pPrevFrame;
// Special case: no direct previous frame is found but frame is in footnote
// Search for a previous frame in previous footnote,
// if frame isn't in a section, which is also in the footnote
if ( !pPrevFrame && m_rThis.IsInFootnote() &&
( m_rThis.IsSctFrame() ||
!m_rThis.IsInSct() || !m_rThis.FindSctFrame()->IsInFootnote() ) )
{
const SwFootnoteFrame* pPrevFootnoteFrame =
static_cast<const SwFootnoteFrame*>(m_rThis.FindFootnoteFrame()->GetPrev());
if ( pPrevFootnoteFrame )
{
pPrevFrame = pPrevFootnoteFrame->GetLastLower();
const SwFootnoteFrame* pPrevFootnoteFrame =
static_cast<const SwFootnoteFrame*>(m_rThis.FindFootnoteFrame()->GetPrev());
if ( pPrevFootnoteFrame )
return skipHiddenFrames_(pPrevFootnoteFrame->GetLastLower());
// Skip hidden paragraphs and empty sections
while ( pPrevFrame &&
( ( pPrevFrame->IsTextFrame() &&
static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) ||
( pPrevFrame->IsSctFrame() &&
!static_cast<const SwSectionFrame*>(pPrevFrame)->GetSection() ) ) )
{
pPrevFrame = pPrevFrame->GetPrev();
}
}
}
// Special case: found previous frame is a section
// Search for the last content in the section
if( pPrevFrame && pPrevFrame->IsSctFrame() )
{
const SwSectionFrame* pPrevSectFrame =
static_cast<const SwSectionFrame*>(pPrevFrame);
pPrevFrame = pPrevSectFrame->FindLastContent();
// If the last content is in a table _inside_ the section,
// take the table herself.
// Correction: Check directly, if table is inside table, instead of indirectly
// by checking, if section isn't inside a table
if ( pPrevFrame && pPrevFrame->IsInTab() )
{
const SwTabFrame* pTableFrame = pPrevFrame->FindTabFrame();
if ( pPrevSectFrame->IsAnLower( pTableFrame ) )
{
pPrevFrame = pTableFrame;
}
}
// Correction: skip hidden text frames
while ( pPrevFrame &&
pPrevFrame->IsTextFrame() &&
static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() )
{
pPrevFrame = pPrevFrame->GetPrev();
}
}
return pPrevFrame;
return nullptr;
}
// This should be renamed to something like lcl_UseULSpacing
@ -1912,6 +1892,8 @@ SwTwips SwFlowFrame::CalcAddLowerSpaceAsLastInTableCell(
/// Moves the Frame forward if it seems necessary regarding the current conditions and attributes.
bool SwFlowFrame::CheckMoveFwd( bool& rbMakePage, bool bKeep, bool bIgnoreMyOwnKeepValue )
{
if (m_rThis.IsHiddenNow())
return false;
const SwFrame* pNxt = m_rThis.GetIndNext();
if ( bKeep && //!bMovedBwd &&
@ -2299,7 +2281,8 @@ bool SwFlowFrame::MoveBwd( bool &rbReformat )
)
pNewUpper = m_rThis.GetLeaf( MAKEPAGE_FTN, false );
}
else if ( IsPageBreak( true ) ) // Do we have to respect a PageBreak?
// Do we have to respect a PageBreak?
else if (IsPageBreak(true) && (!m_rThis.IsInSct() || !m_rThis.FindSctFrame()->IsHiddenNow()))
{
// If the previous page doesn't have a Frame in the body,
// flowing back makes sense despite the PageBreak (otherwise,
@ -2366,7 +2349,7 @@ bool SwFlowFrame::MoveBwd( bool &rbReformat )
}
}
}
else if ( IsColBreak( true ) )
else if (IsColBreak(true))
{
// If the previous column doesn't contain a ContentFrame, flowing back
// makes sense despite the ColumnBreak, as otherwise we'd get

View file

@ -844,11 +844,7 @@ void SwContentNotify::ImplDestroy()
SwFrame* pPrevFrame = pCnt->FindPrev();
// skip empty section frames and hidden text frames
{
while ( pPrevFrame &&
( ( pPrevFrame->IsSctFrame() &&
!static_cast<SwSectionFrame*>(pPrevFrame)->GetSection() ) ||
( pPrevFrame->IsTextFrame() &&
static_cast<SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) ) )
while (pPrevFrame && pPrevFrame->IsHiddenNow())
{
pPrevFrame = pPrevFrame->FindPrev();
}
@ -1608,7 +1604,7 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
pFrame = pNode->IsTextNode()
? sw::MakeTextFrame(*pNode->GetTextNode(), pLay, eMode)
: pNode->MakeFrame(pLay);
if( pPageMaker )
if (pPageMaker && !pLay->IsHiddenNow())
pPageMaker->CheckInsert( nIndex );
pFrame->InsertBehind( pLay, pPrv );
@ -1766,15 +1762,11 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
continue; // skip it
}
SwSectionNode *pNode = static_cast<SwSectionNode*>(pNd);
if( pNode->GetSection().CalcHiddenFlag() )
// is hidden, skip the area
nIndex = pNode->EndOfSectionIndex();
else
{
if (pActualSection)
pActualSection->SetLastPos(pPrv);
pFrame = pNode->MakeFrame( pLay );
pFrame = pNode->MakeFrame(pLay, pNode->GetSection().CalcHiddenFlag());
pActualSection.reset( new SwActualSection( pActualSection.release(),
static_cast<SwSectionFrame*>(pFrame), pNode ) );
if ( pActualSection->GetUpper() )
@ -1945,7 +1937,8 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
}
else
{
pFrame = pActualSection->GetSectionNode()->MakeFrame( pLay );
pFrame = pActualSection->GetSectionNode()->MakeFrame(
pLay, pActualSection->GetSectionNode()->GetSection().IsHiddenFlag());
pFrame->InsertBehind( pLay, pPrv );
static_cast<SwSectionFrame*>(pFrame)->Init();
@ -2523,8 +2516,7 @@ void SwBorderAttrs::CalcJoinedWithPrev( const SwFrame& _rFrame,
// one as previous frame.
const SwFrame* pPrevFrame = _pPrevFrame ? _pPrevFrame : _rFrame.GetPrev();
// OD 2004-02-13 #i25029# - skip hidden text frames.
while ( pPrevFrame && pPrevFrame->IsTextFrame() &&
static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() )
while (pPrevFrame && pPrevFrame->IsHiddenNow())
{
pPrevFrame = pPrevFrame->GetPrev();
}
@ -2555,8 +2547,7 @@ void SwBorderAttrs::CalcJoinedWithNext( const SwFrame& _rFrame ) const
// corresponding attribute set is set at current text frame.
// OD 2004-02-13 #i25029# - get next frame, but skip hidden text frames.
const SwFrame* pNextFrame = _rFrame.GetNext();
while ( pNextFrame && pNextFrame->IsTextFrame() &&
static_cast<const SwTextFrame*>(pNextFrame)->IsHiddenNow() )
while (pNextFrame && pNextFrame->IsHiddenNow())
{
pNextFrame = pNextFrame->GetNext();
}

View file

@ -2983,13 +2983,9 @@ SwContentFrame* SwFootnoteFrame::FindLastContent()
while ( pTmpLastLower && pTmpLastLower->GetNext() )
{
pTmpLastLower = pTmpLastLower->GetNext();
if ( ( pTmpLastLower->IsTextFrame() &&
!static_cast<SwTextFrame*>(pTmpLastLower)->IsHiddenNow() ) ||
( pTmpLastLower->IsSctFrame() &&
static_cast<SwSectionFrame*>(pTmpLastLower)->GetSection() &&
static_cast<SwSectionFrame*>(pTmpLastLower)->ContainsContent() ) ||
( pTmpLastLower->IsTabFrame() &&
static_cast<SwTabFrame*>(pTmpLastLower)->ContainsContent() ) )
if (!pTmpLastLower->IsHiddenNow()
&& (!pTmpLastLower->IsLayoutFrame()
|| static_cast<SwLayoutFrame*>(pTmpLastLower)->ContainsContent()))
{
pLastLowerOfFootnote = pTmpLastLower;
}

View file

@ -789,7 +789,10 @@ SwPageDesc *SwPageFrame::FindPageDesc()
return pRet;
}
SwFrame *pFlow = FindFirstBodyContent();
SwContentFrame* pFirstContent = FindFirstBodyContent();
while (pFirstContent && pFirstContent->IsHiddenNow())
pFirstContent = pFirstContent->GetNextContentFrame();
SwFrame* pFlow = pFirstContent;
if ( pFlow && pFlow->IsInTab() )
pFlow = pFlow->FindTabFrame();

View file

@ -189,6 +189,13 @@ SwSectionFrame::~SwSectionFrame()
{
}
//virtual
bool SwSectionFrame::IsHiddenNow() const
{
const auto* pSection = GetSection();
return !pSection || pSection->CalcHiddenFlag();
}
void SwSectionFrame::DelEmpty( bool bRemove )
{
if( IsColLocked() )
@ -1371,6 +1378,20 @@ void SwSectionFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderA
SwRectFnSet aRectFnSet(this);
if (GetSection()->CalcHiddenFlag())
{
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight(aFrm, 0);
}
{
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
aRectFnSet.SetHeight(aPrt, 0);
}
setFrameAreaSizeValid(true);
setFramePrintAreaValid(true);
}
if ( !isFramePrintAreaValid() )
{
PROTOCOL( this, PROT::PrintArea, DbgAction::NONE, nullptr )
@ -2182,6 +2203,11 @@ bool SwSectionFrame::Growable() const
SwTwips SwSectionFrame::Grow_( SwTwips nDist, bool bTst )
{
if (GetSection()->CalcHiddenFlag())
{
return 0;
}
if ( !IsColLocked() && !HasFixSize() )
{
SwRectFnSet aRectFnSet(this);
@ -2646,6 +2672,17 @@ void SwSectionFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
return;
SwSectionFrame::MoveContentAndDelete(this, pHint->IsSaveContent());
}
else if (rHint.GetId() == SfxHintId::SwSectionHidden)
{
InvalidateAll();
InvalidateObjs(false);
for (SwFrame* pLowerFrame = Lower(); pLowerFrame; pLowerFrame = pLowerFrame->GetNext())
{
pLowerFrame->InvalidateAll();
pLowerFrame->InvalidateObjs(false);
}
}
else
SwFrame::SwClientNotify(rMod, rHint);
}

View file

@ -1454,6 +1454,8 @@ namespace
auto IsAllHiddenSection(SwSectionFrame const& rSection) -> bool
{
if (rSection.IsHiddenNow())
return true;
for (SwFrame const* pFrame = rSection.Lower(); pFrame; pFrame = pFrame->GetNext())
{
if (pFrame->IsColumnFrame())
@ -1474,7 +1476,7 @@ namespace
}
else if (pFrame->IsTextFrame())
{
if (!static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow())
if (!pFrame->IsHiddenNow())
{
return false;
}
@ -1509,7 +1511,7 @@ namespace
}
else if (pFrame->IsTextFrame())
{
if (!static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow())
if (!pFrame->IsHiddenNow())
{
return false;
}

View file

@ -52,6 +52,7 @@
#include <ndtxt.hxx>
#include <undobj.hxx>
#include <flyfrms.hxx>
#include <sectfrm.hxx>
#include <swselectionlist.hxx>
#include <comphelper/lok.hxx>
@ -816,8 +817,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart,
//If I'm in the DocumentBody, I want to stay there.
if ( pStart->IsInDocBody() )
{
while ( pCnt && (!pCnt->IsInDocBody() ||
(pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow())))
while (pCnt && (!pCnt->IsInDocBody() || pCnt->IsHiddenNow()))
{
pCnt = (*fnNxtPrv)( pCnt );
pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
@ -828,8 +828,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart,
//case of necessity.
else if ( pStart->IsInFootnote() )
{
while ( pCnt && (!pCnt->IsInFootnote() ||
(pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow())))
while (pCnt && (!pCnt->IsInFootnote() || pCnt->IsHiddenNow()))
{
pCnt = (*fnNxtPrv)( pCnt );
pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
@ -839,7 +838,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart,
//In Flys we can go ahead blindly as long as we find a Content.
else if ( pStart->IsInFly() )
{
if ( pCnt && pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow() )
if (pCnt && pCnt->IsHiddenNow())
{
pCnt = (*fnNxtPrv)( pCnt );
pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
@ -863,7 +862,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart,
}
if ( !bSame )
pCnt = nullptr;
else if (pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow()) // i73332
else if (pCnt->IsHiddenNow()) // i73332
{
pCnt = (*fnNxtPrv)( pCnt );
pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
@ -946,8 +945,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart,
}
}
} while ( !bEnd ||
(pCnt && pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow()));
} while (!bEnd || (pCnt && pCnt->IsHiddenNow()));
if (pCnt == nullptr)
{
@ -1234,7 +1232,7 @@ const SwContentFrame *SwLayoutFrame::GetContentPos( Point& rPoint,
if ( pComp != pContent )
continue;
if ( !pContent->IsTextFrame() || !static_cast<const SwTextFrame*>(pContent)->IsHiddenNow() )
if (!pContent->IsHiddenNow())
{
SwRect aContentFrame( pContent->UnionFrame() );
if ( aContentFrame.Contains( rPoint ) )
@ -1718,6 +1716,15 @@ bool SwFrame::IsProtected() const
return false;
}
// virtual
bool SwFrame::IsHiddenNow() const
{
if (const auto* pSectFrame = FindSctFrame())
return pSectFrame->IsHiddenNow();
return false;
}
/** @return the physical page number */
sal_uInt16 SwFrame::GetPhyPageNum() const
{

View file

@ -1484,6 +1484,9 @@ bool SwTextFrame::IsHiddenNow() const
return true;
}
if (SwContentFrame::IsHiddenNow())
return true;
bool bHiddenCharsHidePara(false);
bool bHiddenParaField(false);
if (m_pMergedPara)
@ -1553,22 +1556,14 @@ bool SwTextFrame::IsHiddenNow() const
// be visible - check this for the 1st body paragraph
if (IsInDocBody() && FindPrevCnt() == nullptr)
{
bool isAllHidden(true);
for (SwContentFrame const* pNext = FindNextCnt(true);
pNext != nullptr; pNext = pNext->FindNextCnt(true))
{
if (!pNext->IsTextFrame()
|| !static_cast<SwTextFrame const*>(pNext)->IsHiddenNow())
{
isAllHidden = false;
break;
}
}
if (isAllHidden)
{
SAL_INFO("sw.core", "unhiding one body paragraph");
return false;
if (!pNext->IsHiddenNow())
return true;
}
SAL_INFO("sw.core", "unhiding one body paragraph");
return false;
}
return true;
}