tdf160518 DOCX: import hyphenation-keep to fix layout

To fix layout interoperability, import DOCX compatSettings
allowHyphenationAtTrackBottom and useWord2013TrackBottomHyphenation
as hyphenation-keep setting "COLUMN", shifting last hyphenated
lines of pages and columns, like MSO does.

Follow-up to commit 9574a62add8e4901405e12117e75c86c2d2c2f21
"tdf#132599 cui offapi sw xmloff: implement hyphenate-keep".

Change-Id: Ib2a06efc22a4f30d8f8be8a752460b09d09e97a3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165798
Tested-by: Jenkins
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/editeng/source/items/paraitem.cxx b/editeng/source/items/paraitem.cxx
index 3e99813..4103fe2 100644
--- a/editeng/source/items/paraitem.cxx
+++ b/editeng/source/items/paraitem.cxx
@@ -616,7 +616,7 @@ bool    SvxHyphenZoneItem::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) con
bool SvxHyphenZoneItem::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId )
{
    nMemberId &= ~CONVERT_TWIPS;
    sal_Int16 nNewVal = 0;
    sal_Int32 nNewVal = 0; // sal_Int32 needs for MID_HYPHEN_KEEP

    if( nMemberId != MID_IS_HYPHEN && nMemberId != MID_HYPHEN_NO_CAPS &&
                nMemberId != MID_HYPHEN_NO_LAST_WORD )
diff --git a/sw/qa/extras/ooxmlexport/data/tdf160518_allowHyphenationAtTrackBottom.docx b/sw/qa/extras/ooxmlexport/data/tdf160518_allowHyphenationAtTrackBottom.docx
new file mode 100644
index 0000000..61e81cf
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf160518_allowHyphenationAtTrackBottom.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf160518_useWord2013TrackBottomHyphenation.docx b/sw/qa/extras/ooxmlexport/data/tdf160518_useWord2013TrackBottomHyphenation.docx
new file mode 100644
index 0000000..26acacc
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf160518_useWord2013TrackBottomHyphenation.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
index a045a03..c33275b 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
@@ -28,6 +28,8 @@
#include <com/sun/star/text/XTextGraphicObjectsSupplier.hpp>
#include <com/sun/star/text/XTextTable.hpp>
#include <com/sun/star/text/XTextTablesSupplier.hpp>
#include <com/sun/star/linguistic2/XHyphenator.hpp>
#include <editeng/unolingu.hxx>

#include <comphelper/sequenceashashmap.hxx>
#include <officecfg/Office/Common.hxx>
@@ -1424,6 +1426,68 @@ DECLARE_OOXMLEXPORT_TEST(testTdf159032, "tdf124795-5.docx")
    CPPUNIT_ASSERT_EQUAL(57, getPages());
}

DECLARE_OOXMLEXPORT_TEST(testTdf160518, "tdf160518_useWord2013TrackBottomHyphenation.docx")
{
    uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
    if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
        return;

    // TODO: fix export too
    if (isExported())
        return;
    // This was 2 (without shifting last hyphenated line of the page)
    CPPUNIT_ASSERT_EQUAL(3, getPages());
}

DECLARE_OOXMLEXPORT_TEST(testTdf160518_compatible, "tdf160518_allowHyphenationAtTrackBottom.docx")
{
    uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
    if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
        return;

    // TODO: fix export too
    if (isExported())
        return;
    // This is still 2
    CPPUNIT_ASSERT_EQUAL(2, getPages());
}

DECLARE_OOXMLEXPORT_TEST(testTdf160518_ODT, "tdf160518_useWord2013TrackBottomHyphenation.docx")
{
    uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
    if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
        return;

    // TODO: fix export too
    if (isExported())
        return;
    // This was 2 (without shifting last hyphenated line of the page)
    CPPUNIT_ASSERT_EQUAL(3, getPages());

    // check compatibility option in ODT export/import, too
    saveAndReload("writer8");

    CPPUNIT_ASSERT_EQUAL(3, getPages());
}

DECLARE_OOXMLEXPORT_TEST(testTdf160518_ODT_compatible, "tdf160518_allowHyphenationAtTrackBottom.docx")
{
    uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
    if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
        return;

    // TODO: fix export too
    if (isExported())
        return;
    // This is still 2
    CPPUNIT_ASSERT_EQUAL(2, getPages());

    // check compatibility option in ODT export/import, too
    saveAndReload("writer8");

    CPPUNIT_ASSERT_EQUAL(2, getPages());
}

CPPUNIT_TEST_FIXTURE(Test, testHyphenationAuto)
{
    loadAndReload("hyphenation.odt");
diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
index a84b4df..422d643 100644
--- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
+++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
@@ -1161,7 +1161,8 @@ void DomainMapperTableHandler::ApplyParagraphPropertiesFromTableStyle(TableParag
                    // The wording is confusing here. Normally, the paragraph style DOES override the table-style.
                    // But for these two special situations, do not override the table-style. So the default is false.
                    // If false, then "CompatOverride" the normal behaviour, and apply the table-style's value.
                    bCompatOverride &= !m_rDMapper_Impl.GetSettingsTable()->GetCompatSettingValue(u"overrideTableStyleFontSizeAndJustification");
                    bCompatOverride &= !m_rDMapper_Impl.GetSettingsTable()->
                        GetCompatSettingHasAndValue(u"overrideTableStyleFontSizeAndJustification").second;
                }

                // use table style when no paragraph style setting or a docDefault value is applied instead of it
diff --git a/writerfilter/source/dmapper/PropertyIds.cxx b/writerfilter/source/dmapper/PropertyIds.cxx
index b8b4efc0..316298a 100644
--- a/writerfilter/source/dmapper/PropertyIds.cxx
+++ b/writerfilter/source/dmapper/PropertyIds.cxx
@@ -102,6 +102,7 @@ namespace
        { PROP_PARA_IS_HYPHENATION, u"ParaIsHyphenation"},
        { PROP_PARA_HYPHENATION_NO_CAPS, u"ParaHyphenationNoCaps"},
        { PROP_PARA_HYPHENATION_ZONE, u"ParaHyphenationZone"},
        { PROP_PARA_HYPHENATION_KEEP, u"ParaHyphenationKeep"},
        { PROP_PARA_LINE_NUMBER_COUNT, u"ParaLineNumberCount"},
        { PROP_PARA_IS_HANGING_PUNCTUATION, u"ParaIsHangingPunctuation"},
        { PROP_PARA_LINE_SPACING, u"ParaLineSpacing"},
diff --git a/writerfilter/source/dmapper/PropertyIds.hxx b/writerfilter/source/dmapper/PropertyIds.hxx
index b39fcd2..8c0b07a 100644
--- a/writerfilter/source/dmapper/PropertyIds.hxx
+++ b/writerfilter/source/dmapper/PropertyIds.hxx
@@ -248,6 +248,7 @@ enum PropertyIds
        ,PROP_PARA_IS_HYPHENATION
        ,PROP_PARA_HYPHENATION_NO_CAPS
        ,PROP_PARA_HYPHENATION_ZONE
        ,PROP_PARA_HYPHENATION_KEEP
        ,PROP_PARA_KEEP_TOGETHER
        ,PROP_PARA_LAST_LINE_ADJUST
        ,PROP_PARA_LEFT_MARGIN
diff --git a/writerfilter/source/dmapper/SettingsTable.cxx b/writerfilter/source/dmapper/SettingsTable.cxx
index 14a7808..35683ca 100644
--- a/writerfilter/source/dmapper/SettingsTable.cxx
+++ b/writerfilter/source/dmapper/SettingsTable.cxx
@@ -26,6 +26,7 @@

#include <rtl/ustring.hxx>
#include <sfx2/zoomitem.hxx>
#include <com/sun/star/text/ParagraphHyphenationKeepType.hpp>
#include <com/sun/star/text/XDependentTextField.hpp>
#include <com/sun/star/text/XTextFieldsSupplier.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
@@ -699,10 +700,21 @@ void SettingsTable::ApplyProperties(uno::Reference<text::XTextDocument> const& x
        xPropertySet->setPropertyValue("ParaWidows", aAny);
        xPropertySet->setPropertyValue("ParaOrphans", aAny);
    }

    std::pair<bool, bool> aAllow = GetCompatSettingHasAndValue(u"allowHyphenationAtTrackBottom");
    std::pair<bool, bool> aUse = GetCompatSettingHasAndValue(u"useWord2013TrackBottomHyphenation");
    // if allowHyphenationAtTrackBottom is not true and useWord2013TrackBottomHyphenation is
    // not present or it is true, set ParaHyphenationKeep to COLUMN
    if ( !aAllow.second && ( !aUse.first || aUse.second ) )
    {
        uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY);
        xPropertySet->setPropertyValue("ParaHyphenationKeep", uno::Any(text::ParagraphHyphenationKeepType::COLUMN));
    }
}

bool SettingsTable::GetCompatSettingValue( std::u16string_view sCompatName ) const
std::pair<bool, bool> SettingsTable::GetCompatSettingHasAndValue( std::u16string_view sCompatName ) const
{
    bool bHas = false;
    bool bRet = false;
    for (const auto& rProp : m_pImpl->m_aCompatSettings)
    {
@@ -725,10 +737,11 @@ bool SettingsTable::GetCompatSettingValue( std::u16string_view sCompatName ) con
            aCurrentCompatSettings[2].Value >>= sVal;
            // if repeated, what happens?  Last one wins
            bRet = sVal.toBoolean();
            bHas = true;
        }
    }

    return bRet;
    return std::pair<bool, bool>(bHas, bRet);
}

//Keep this function in-sync with the one in sw/.../docxattributeoutput.cxx
diff --git a/writerfilter/source/dmapper/SettingsTable.hxx b/writerfilter/source/dmapper/SettingsTable.hxx
index f44338aa..f5ccb1b 100644
--- a/writerfilter/source/dmapper/SettingsTable.hxx
+++ b/writerfilter/source/dmapper/SettingsTable.hxx
@@ -91,7 +91,7 @@ public:

    void ApplyProperties(css::uno::Reference<css::text::XTextDocument> const& xDoc);

    bool GetCompatSettingValue(std::u16string_view sCompatName) const;
    std::pair<bool, bool> GetCompatSettingHasAndValue(std::u16string_view sCompatName) const;
    sal_Int32 GetWordCompatibilityMode() const;

    const OUString& GetCurrentDatabaseDataSource() const;