tdf#104816 sw: if non-section content, let all sections hide.

If all of the document is contained inside of sections, then at
least one section must be visible or writer crashes. The 2012
fix seemed to assume that all content would be in a section,
and thus required at least one section be visible.

Instead, check for non-section content at the start and end of the
document, and for gaps between sections, and count those
as "virtual", visible sections, which would allow all real sections
to be marked as hidden.

The example document HiddenSection.odt in tdf#55814 is a really
nice test document. With this patch, that test now works
even if you remove the last non-section paragraph.

Even nicer is finding that a (very unclear) "did you fix me?"
unit test entry gives a unit test for patch.

Change-Id: I6cac5e6df8dff7fbb78828ae2521a1b02e305a27
Reviewed-on: https://gerrit.libreoffice.org/66128
Reviewed-by: Justin Luth <justin_luth@sil.org>
Tested-by: Jenkins
Tested-by: Serge Krot (CIB) <Serge.Krot@cib.de>
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
diff --git a/sw/qa/python/var_fields.py b/sw/qa/python/var_fields.py
index e7c7fbb..e793aaa 100644
--- a/sw/qa/python/var_fields.py
+++ b/sw/qa/python/var_fields.py
@@ -132,10 +132,7 @@
        read_content = xSection.getPropertyValue("Condition")

        # 21. check
        # expected:
        # self.assertEqual("foo EQ 1", readContent)
        # reality:
        self.assertEqual("0", read_content)
        self.assertEqual("foo EQ 1", read_content)

if __name__ == '__main__':
    unittest.main()
diff --git a/sw/source/core/doc/DocumentFieldsManager.cxx b/sw/source/core/doc/DocumentFieldsManager.cxx
index 53bc3e2..e122e69 100644
--- a/sw/source/core/doc/DocumentFieldsManager.cxx
+++ b/sw/source/core/doc/DocumentFieldsManager.cxx
@@ -993,19 +993,36 @@
    bool bCanFill = pMgr->FillCalcWithMergeData( m_rDoc.GetNumberFormatter(), nLang, aCalc );
#endif

    // Make sure we don't hide all sections, which would lead to a crash. First, count how many of them do we have.
    // Make sure we don't hide all content, which would lead to a crash. First, count how many visible sections we have.
    int nShownSections = 0;
    sal_uLong nContentStart = m_rDoc.GetNodes().GetEndOfContent().StartOfSectionIndex() + 1;
    sal_uLong nContentEnd = m_rDoc.GetNodes().GetEndOfContent().GetIndex();
    SwSectionFormats& rSectFormats = m_rDoc.GetSections();
    for( SwSectionFormats::size_type n = 0; n<rSectFormats.size(); ++n )
    {
        SwSectionFormats& rSectFormats = m_rDoc.GetSections();
        for( SwSectionFormats::size_type n = 0; n<rSectFormats.size(); ++n )
        {
            SwSectionFormat* pSectFormat = rSectFormats[ n ];
            SwSection* pSect = pSectFormat->GetSection();
        SwSectionFormat& rSectFormat = *rSectFormats[ n ];
        SwSectionNode* pSectionNode = rSectFormat.GetSectionNode();
        SwSection* pSect = rSectFormat.GetSection();

            // count only visible sections
            if ( pSect && !pSect->CalcHiddenFlag())
                nShownSections++;
        // Usually some of the content is not in a section: count that as a virtual section, so that all real sections can be hidden.
        // Only look for section gaps at the lowest level, ignoring sub-sections.
        if ( pSectionNode && !rSectFormat.GetParent() )
        {
            SwNodeIndex aNextIdx( *pSectionNode->EndOfSectionNode(), 1 );
            if ( n == 0 && pSectionNode->GetIndex() != nContentStart )
                nShownSections++;  //document does not start with a section
            if ( n == rSectFormats.size() - 1 )
            {
                if ( aNextIdx.GetIndex() != nContentEnd )
                    nShownSections++;  //document does not end in a section
            }
            else if ( !aNextIdx.GetNode().IsSectionNode() )
                    nShownSections++; //section is not immediately followed by another section
        }

        // count only visible sections
        if ( pSect && !pSect->CalcHiddenFlag())
            nShownSections++;
    }

    IDocumentRedlineAccess const& rIDRA(m_rDoc.getIDocumentRedlineAccess());
@@ -1027,15 +1044,9 @@
                    // This section will be hidden, but it wasn't before
                    if (nShownSections == 1)
                    {
                        // Is the last node part of a section?
                        SwPaM aPam(m_rDoc.GetNodes());
                        aPam.Move(fnMoveForward, GoInDoc);
                        if (aPam.Start()->nNode.GetNode().StartOfSectionNode()->IsSectionNode())
                        {
                            // This would be the last section, so set its condition to false, and avoid hiding it.
                            pSect->SetCondition("0");
                            bHide = false;
                        }
                        // This would be the last section, so set its condition to false, and avoid hiding it.
                        pSect->SetCondition("0");
                        bHide = false;
                    }
                    nShownSections--;
                }