sc/qa/unit/subsequent_export_test3.cxx |   11 ++++++++++-
 sc/source/filter/excel/xehelper.cxx    |    5 +++++
 sc/source/filter/excel/xestring.cxx    |   13 +++++++------
 sc/source/filter/excel/xetable.cxx     |   12 ++++++++----
 sc/source/filter/inc/xestring.hxx      |   10 ++++++++--
 5 files changed, 38 insertions(+), 13 deletions(-)

New commits:
commit 424329bb0b71fdb46b56be5638d5304dbef9e718
Author:     Justin Luth <justin.l...@collabora.com>
AuthorDate: Thu Oct 3 14:03:55 2024 -0400
Commit:     Justin Luth <jl...@mail.com>
CommitDate: Sat Oct 19 17:30:10 2024 +0200

    tdf#158460 xls/x export: don't force wrap-text for imported single-line
    
    Starting in LO 24.2, we started displaying imported XLS/X files
    that had contents-with-newlines on a single line
    if the cell did not have the wrap-text property - just like buggy Excel.
    
    So, now we need to round-trip that without setting wrap-text,
    so that we can continue to exhibit buggy behaviour
    (instead of fixing the document so that the newlines aren't ignored).
    
    A previous attempt to do this was reverted (for many reasons),
    significantly because it failed to handle the situation
    where a user entered new newline content (without forcing wrap-text).
    So in LO the new content DISPLAYS on multiple lines,
    but after a round-trip it was all squashed together.
    
    So it is important to keep the traditional behaviour of forcing wrap-text,
    and ONLY avoiding it when round-tripping imported content.
    It also preserves ODS -> XLS/X conversions.
    
    I also took the opportunity to rename mbWrapped.
    
    make CppunitTest_sc_subsequent_export_test3 \
        CPPUNIT_TEST_NAME=testPreserveTextWhitespace2XLSX
    
    Change-Id: Ia35b0679946b51626fabd4043779c1b43cc1ae37
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174436
    Reviewed-by: Justin Luth <jl...@mail.com>
    Tested-by: Jenkins

diff --git a/sc/qa/unit/subsequent_export_test3.cxx 
b/sc/qa/unit/subsequent_export_test3.cxx
index 5070b5ebe7af..959b73e21d33 100644
--- a/sc/qa/unit/subsequent_export_test3.cxx
+++ b/sc/qa/unit/subsequent_export_test3.cxx
@@ -26,6 +26,7 @@
 #include <unotools/useroptions.hxx>
 #include <sfx2/docfile.hxx>
 #include <tools/datetime.hxx>
+#include <tools/UnitConversion.hxx>
 
 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
 #include <com/sun/star/awt/XBitmap.hpp>
@@ -1423,11 +1424,19 @@ CPPUNIT_TEST_FIXTURE(ScExportTest3, 
testPreserveTextWhitespace2XLSX)
 {
     createScDoc("xlsx/preserve_space.xlsx");
 
-    save(u"Calc Office Open XML"_ustr);
+    saveAndReload(u"Calc Office Open XML"_ustr);
     xmlDocUniquePtr pDoc = parseExport(u"xl/sharedStrings.xml"_ustr);
     CPPUNIT_ASSERT(pDoc);
     assertXPath(pDoc, "/x:sst/x:si[1]/x:t", "space", u"preserve");
     assertXPath(pDoc, "/x:sst/x:si[2]/x:t", "space", u"preserve");
+
+    // tdf#158460: ensure B1 is NOT set to wrap text, so Excel keeps 
displaying as single line
+    SCTAB nTab = 0;
+    SCROW nRow = 0;
+    CPPUNIT_ASSERT(!getScDoc()->GetAttr(1, nRow, nTab, 
ATTR_LINEBREAK)->GetValue());
+    // Without the fix, this wrapped to two lines high (841). It should be 1 
line high (529).
+    int nHeight = convertTwipToMm100(getScDoc()->GetRowHeight(nRow, nTab, 
false));
+    CPPUNIT_ASSERT_LESS(600, nHeight);
 }
 
 CPPUNIT_TEST_FIXTURE(ScExportTest3, testHiddenShapeXLS)
diff --git a/sc/source/filter/excel/xehelper.cxx 
b/sc/source/filter/excel/xehelper.cxx
index 0b3835527576..f910aa4aaad5 100644
--- a/sc/source/filter/excel/xehelper.cxx
+++ b/sc/source/filter/excel/xehelper.cxx
@@ -531,6 +531,11 @@ XclExpStringRef lclCreateFormattedString(
             XclExpStringHelper::AppendChar( *xString, rRoot, '
' );
     }
 
+    if (xString->HasNewline() && nParaCount == 1)
+    {
+        // Found buggy Excel behaviour: although the content has newlines, it 
has not been wrapped.
+        xString->SetSingleLineForMultipleParagraphs(true);
+    }
     return xString;
 }
 
diff --git a/sc/source/filter/excel/xestring.cxx 
b/sc/source/filter/excel/xestring.cxx
index 295f37709594..5715227cf127 100644
--- a/sc/source/filter/excel/xestring.cxx
+++ b/sc/source/filter/excel/xestring.cxx
@@ -205,7 +205,7 @@ bool XclExpString::IsEqual( const XclExpString& rCmp ) const
         (mnLen          == rCmp.mnLen)          &&
         (mbIsBiff8      == rCmp.mbIsBiff8)      &&
         (mbIsUnicode    == rCmp.mbIsUnicode)    &&
-        (mbWrapped      == rCmp.mbWrapped)      &&
+        (mbHasNewline   == rCmp.mbHasNewline)   &&
         (
             ( mbIsBiff8 && (maUniBuffer  == rCmp.maUniBuffer)) ||
             (!mbIsBiff8 && (maCharBuffer == rCmp.maCharBuffer))
@@ -471,8 +471,8 @@ void XclExpString::CharsToBuffer( const sal_Unicode* 
pcSource, sal_Int32 nBegin,
         if( *aIt & 0xFF00 )
             mbIsUnicode = true;
     }
-    if( !mbWrapped )
-        mbWrapped = ::std::find( aBeg, aEnd, EXC_LF ) != aEnd;
+    if (!mbHasNewline)
+        mbHasNewline = std::find(aBeg, aEnd, EXC_LF) != aEnd;
 }
 
 void XclExpString::CharsToBuffer( const char* pcSource, sal_Int32 nBegin, 
sal_Int32 nLen )
@@ -485,8 +485,8 @@ void XclExpString::CharsToBuffer( const char* pcSource, 
sal_Int32 nBegin, sal_In
     for( ScfUInt8Vec::iterator aIt = aBeg; aIt != aEnd; ++aIt, ++pcSrcChar )
         *aIt = static_cast< sal_uInt8 >( *pcSrcChar );
     mbIsUnicode = false;
-    if( !mbWrapped )
-        mbWrapped = ::std::find( aBeg, aEnd, EXC_LF_C ) != aEnd;
+    if (!mbHasNewline)
+        mbHasNewline = std::find(aBeg, aEnd, EXC_LF_C) != aEnd;
 }
 
 void XclExpString::Init( sal_Int32 nCurrLen, XclStrFlags nFlags, sal_uInt16 
nMaxLen, bool bBiff8 )
@@ -496,7 +496,8 @@ void XclExpString::Init( sal_Int32 nCurrLen, XclStrFlags 
nFlags, sal_uInt16 nMax
     mb8BitLen = bool( nFlags & XclStrFlags::EightBitLength );
     mbSmartFlags = bBiff8 && ( nFlags & XclStrFlags::SmartFlags );
     mbSkipFormats = bool( nFlags & XclStrFlags::SeparateFormats );
-    mbWrapped = false;
+    mbHasNewline = false;
+    mbSingleLineForMultipleParagraphs = false;
     mbSkipHeader = bool( nFlags & XclStrFlags::NoHeader );
     mnMaxLen = nMaxLen;
     SetStrLen( nCurrLen );
diff --git a/sc/source/filter/excel/xetable.cxx 
b/sc/source/filter/excel/xetable.cxx
index a5cddfc86ff1..a466bfa7ca81 100644
--- a/sc/source/filter/excel/xetable.cxx
+++ b/sc/source/filter/excel/xetable.cxx
@@ -722,7 +722,7 @@ XclExpLabelCell::XclExpLabelCell(
 
 bool XclExpLabelCell::IsMultiLineText() const
 {
-    return mbLineBreak || mxText->IsWrapped();
+    return mbLineBreak || mxText->HasNewline();
 }
 
 void XclExpLabelCell::Init( const XclExpRoot& rRoot,
@@ -744,9 +744,13 @@ void XclExpLabelCell::Init( const XclExpRoot& rRoot,
     // create cell format
     if( GetXFId() == EXC_XFID_NOTFOUND )
     {
-       OSL_ENSURE( nXclFont != EXC_FONT_NOTFOUND, "XclExpLabelCell::Init - 
leading font not found" );
-       bool bForceLineBreak = mxText->IsWrapped();
-       SetXFId( rRoot.GetXFBuffer().InsertWithFont( pPattern, 
ApiScriptType::WEAK, nXclFont, bForceLineBreak ) );
+        OSL_ENSURE(nXclFont != EXC_FONT_NOTFOUND, "XclExpLabelCell::Init - 
leading font not found");
+
+        // Buggy Excel behaviour - newlines are ignored unless wrap-text is 
enabled,
+        // so always force text-wrapping (unless it was imported that way and 
not modified).
+        bool bForceLineBreak = mxText->HasNewline() && 
!mxText->IsSingleLineForMultipleParagraphs();
+        SetXFId(rRoot.GetXFBuffer().InsertWithFont(
+            pPattern, ApiScriptType::WEAK, nXclFont, bForceLineBreak));
     }
 
     // get auto-wrap attribute from cell format
diff --git a/sc/source/filter/inc/xestring.hxx 
b/sc/source/filter/inc/xestring.hxx
index a61e563f01b9..0b62d1a98bfb 100644
--- a/sc/source/filter/inc/xestring.hxx
+++ b/sc/source/filter/inc/xestring.hxx
@@ -119,7 +119,12 @@ public:
     /** Returns true, if the string is empty. */
     bool         IsEmpty() const { return mnLen == 0; }
     /** Returns true, if the string contains line breaks. */
-    bool         IsWrapped() const { return mbWrapped; }
+    bool         HasNewline() const { return mbHasNewline; }
+
+    /** Returns true, if multiple paragraphs are displayed without any 
wrapping **/
+    bool IsSingleLineForMultipleParagraphs() const { return 
mbSingleLineForMultipleParagraphs; }
+    void SetSingleLineForMultipleParagraphs(bool bSet) { 
mbSingleLineForMultipleParagraphs = bSet; }
+
     /** Returns true, if this string is equal to the passed string. */
     bool                IsEqual( const XclExpString& rCmp ) const;
     /** Returns true, if this string is less than the passed string. */
@@ -236,7 +241,8 @@ private:
     bool                mb8BitLen;      /// true = write 8-bit string length; 
false = 16-bit.
     bool                mbSmartFlags;   /// true = omit flags on empty string; 
false = always write flags.
     bool                mbSkipFormats;  /// true = skip formats on export; 
false = write complete formatted string.
-    bool                mbWrapped;      /// true = text contains several 
paragraphs.
+    bool                mbHasNewline;   /// true = text contains several 
paragraphs.
+    bool                mbSingleLineForMultipleParagraphs; /// true = several 
paragraphs displayed all on one line
     bool                mbSkipHeader;   /// true = skip length and flags when 
writing string bytes.
 };
 

Reply via email to