tdf#121659 DOCX import: fix lost column break at shapes

The column break was moved into the neighboring shape during
the first import, and eliminated during the second import,
losing the 2-column text layout. As a workaround, split the
paragraph moving the column break into a new paragraph.

Based on the patch written by Justin Luth.

Co-authored-by: Justin Luth and Tibor Nagy (NISZ)

Change-Id: Id4042a92b09aa55952bc0ea02319d5e588f77d3b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114904
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/qa/extras/ooxmlexport/data/tdf121659_loseColumnBrNextToShape.docx b/sw/qa/extras/ooxmlexport/data/tdf121659_loseColumnBrNextToShape.docx
new file mode 100644
index 0000000..1fda142
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf121659_loseColumnBrNextToShape.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
index c50a75c..f0450f7 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
@@ -10,6 +10,7 @@
#include <swmodeltestbase.hxx>

#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/style/BreakType.hpp>
#include <com/sun/star/style/LineSpacing.hpp>
#include <com/sun/star/text/WritingMode.hpp>
#include <com/sun/star/text/WritingMode2.hpp>
@@ -107,6 +108,19 @@ DECLARE_OOXMLEXPORT_TEST(testTdf140182_extraPagebreak, "tdf140182_extraPagebreak
    CPPUNIT_ASSERT_EQUAL(2, getPages());
}

DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf121659_loseColumnBrNextToShape, "tdf121659_loseColumnBrNextToShape.docx")
{
    // The third paragraph contains a manual column break and a shape.
    // The column break was moved into the shape during the first import
    // (messing also the shape position), and eliminated during the second import,
    // losing the 2-column text layout. As a workaround, split the paragraph
    // moving the column break into the fourth paragraph instead of losing it.
    reload("Office Open XML Text", "tdf121659_loseColumnBrNextToShape.docx");
    bool bBreakOnPara3 = getProperty<style::BreakType>(getParagraph(3), "BreakType") == style::BreakType_COLUMN_BEFORE;
    bool bBreakOnPara4 = getProperty<style::BreakType>(getParagraph(4), "BreakType") == style::BreakType_COLUMN_BEFORE;
    CPPUNIT_ASSERT(bBreakOnPara3 || bBreakOnPara4);
}

DECLARE_OOXMLEXPORT_TEST(testTdf95848, "tdf95848.docx")
{
    OUString listId;
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index fa6018f..fd341dd 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -109,8 +109,9 @@ DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xCon
    LoggedTable("DomainMapper"),
    LoggedStream("DomainMapper"),
    m_pImpl(new DomainMapper_Impl(*this, xContext, xModel, eDocumentType, rMediaDesc)),
    mbIsSplitPara(false)
    ,mbHasControls(false)
    mbIsSplitPara(false),
    mbHasControls(false),
    mbWasShapeInPara(false)
{
    // #i24363# tab stops relative to indent
    m_pImpl->SetDocumentSettingsProperty(
@@ -3094,18 +3095,21 @@ void DomainMapper::lcl_startParagraphGroup()
            const OUString& sDefaultParaStyle = m_pImpl->GetDefaultParaStyleName();
            m_pImpl->GetTopContext()->Insert( PROP_PARA_STYLE_NAME, uno::makeAny( sDefaultParaStyle ) );
            m_pImpl->SetCurrentParaStyleName( sDefaultParaStyle );

            if (m_pImpl->isBreakDeferred(PAGE_BREAK))
                m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::makeAny(style::BreakType_PAGE_BEFORE));
            else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
                m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::makeAny(style::BreakType_COLUMN_BEFORE));
            mbWasShapeInPara = false;
        }
        if (m_pImpl->isBreakDeferred(PAGE_BREAK))
            m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::makeAny(style::BreakType_PAGE_BEFORE));
        else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
            m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::makeAny(style::BreakType_COLUMN_BEFORE));

        if (m_pImpl->isParaSdtEndDeferred())
            m_pImpl->GetTopContext()->Insert(PROP_PARA_SDT_END_BEFORE, uno::makeAny(true), true, PARA_GRAB_BAG);
    }
    m_pImpl->SetIsFirstRun(true);
    m_pImpl->SetIsOutsideAParagraph(false);
    m_pImpl->clearDeferredBreaks();
    if (!m_pImpl->IsInShape())
        m_pImpl->clearDeferredBreaks();
    m_pImpl->setParaSdtEndDeferred(false);
}

@@ -3159,7 +3163,7 @@ void DomainMapper::lcl_startShape(uno::Reference<drawing::XShape> const& xShape)
    }

    m_pImpl->SetIsFirstParagraphInShape(true);

    mbWasShapeInPara = true;
}

void DomainMapper::lcl_endShape( )
@@ -3636,8 +3640,9 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
                }
                else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
                {
                    if (m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun())
                    if (m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun() || mbWasShapeInPara)
                    {
                        mbWasShapeInPara = false;
                        mbIsSplitPara = true;
                        finishParagraph();
                        lcl_startParagraphGroup();
diff --git a/writerfilter/source/dmapper/DomainMapper.hxx b/writerfilter/source/dmapper/DomainMapper.hxx
index 94b9146..086e7f6 100644
--- a/writerfilter/source/dmapper/DomainMapper.hxx
+++ b/writerfilter/source/dmapper/DomainMapper.hxx
@@ -176,6 +176,7 @@ private:
    static sal_Unicode getFillCharFromValue(const sal_Int32 nIntValue);
    bool mbIsSplitPara;
    bool mbHasControls;
    bool mbWasShapeInPara;
    std::unique_ptr< GraphicZOrderHelper > zOrderHelper;
    std::unique_ptr<GraphicNamingHelper> m_pGraphicNamingHelper;
    OUString m_sGlossaryEntryName;