editeng/qa/unit/core-test.cxx             |   35 ++++++++++++++++++++++++++++--
 editeng/source/editeng/impedit2.cxx       |    9 -------
 sw/qa/extras/odfimport/data/tdf123968.odt |binary
 sw/qa/extras/odfimport/odfimport.cxx      |   12 ++++++++++
 sw/source/core/fields/expfld.cxx          |   20 ++++++++++++-----
 sw/source/core/inc/unofield.hxx           |    2 -
 sw/source/core/unocore/unofield.cxx       |   30 +++++++++++++++++++------
 7 files changed, 85 insertions(+), 23 deletions(-)

New commits:
commit a2a85724b3260713b1938a934fd73211d6e1d99d
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Feb 2 20:10:24 2024 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Tue Feb 6 20:34:59 2024 +0100

    tdf#123968 sw: fix assert on importing ooo62823-1.sxw
    
    svl/source/items/itemset.cxx:662: const SfxPoolItem* 
implCreateItemEntry(SfxItemPool&, const SfxPoolItem*, bool): Assertion 
`pSource->Which() == nWhich && "ITEM: Clone of Item did NOT copy/set WhichID 
(!)"' failed.
    
    XMLVariableInputFieldImportContext::PrepareField() first sets "Input"
    and then "SubType" property.
    
    Apparently i missed that *both* of these are mutable in the API, and
    both together determine whether the field is a RES_TXTATR_INPUTFIELD or
    RES_TXTATR_FIELD.
    
    So call SwXTextField::TransmuteLeadToInputField() also when the
    "SubType" is set, and adapt it to toggling 2 different things.
    
    Hmm... actually this will change these fields to be inline editable
    after ODF import, which was the intention all along.
    
    It turns out that there is even a unit test testTdf123968 for this; it
    works in the usual case, but in this case the input field is in a
    header, so in styles.xml, and the styles.xml is imported before
    content.xml and does not contain the variable-decls element, so the
    variable field type has the GSE_EXPR subtype (default?), and setting the
    "Input" property doesn't transmute it.
    
    (regression from commit 742baabbe4d077e1ba913a7989300908f4637ac7)
    
    Change-Id: Ib5757cda32287e51651f05f5b19e82d7be0431e3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162941
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 99055ae98ef1fe67b8db4a8c3167a8acaeaac02f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163012
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/sw/qa/extras/odfimport/data/tdf123968.odt 
b/sw/qa/extras/odfimport/data/tdf123968.odt
index 1c081619ea30..cd1ec8a3859a 100644
Binary files a/sw/qa/extras/odfimport/data/tdf123968.odt and 
b/sw/qa/extras/odfimport/data/tdf123968.odt differ
diff --git a/sw/qa/extras/odfimport/odfimport.cxx 
b/sw/qa/extras/odfimport/odfimport.cxx
index 168de4fb6db7..70c6452e3d9f 100644
--- a/sw/qa/extras/odfimport/odfimport.cxx
+++ b/sw/qa/extras/odfimport/odfimport.cxx
@@ -1167,9 +1167,21 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf123968)
     SwTextNode& rStart = 
dynamic_cast<SwTextNode&>(pShellCursor->Start()->GetNode());
 
     // The field is now editable like any text, thus the field content "New 
value" shows up for the cursor.
+    // This field's variable is declared as string and used as string - 
typical.
     CPPUNIT_ASSERT_EQUAL(OUString("inputfield: " + 
OUStringChar(CH_TXT_ATR_INPUTFIELDSTART)
                                   + "New value" + 
OUStringChar(CH_TXT_ATR_INPUTFIELDEND)),
                          rStart.GetText());
+
+    // This field's variable is declared as float and used as string - not
+    // typical; this can easily happen if the input field is in a 
header/footer,
+    // because only content.xml contains the variable-decls, styles.xml is
+    // imported before content.xml, and apparently the default variable type is
+    // numeric.
+    SwTextNode& rEnd = 
dynamic_cast<SwTextNode&>(pShellCursor->End()->GetNode());
+    CPPUNIT_ASSERT_EQUAL(OUString("inputfield: " + 
OUStringChar(CH_TXT_ATR_INPUTFIELDSTART)
+                                  + "String input for num variable" + 
OUStringChar(CH_TXT_ATR_INPUTFIELDEND)),
+                         rEnd.GetText());
+
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testTdf133459)
diff --git a/sw/source/core/fields/expfld.cxx b/sw/source/core/fields/expfld.cxx
index 434f67672903..6ed4cdb7c125 100644
--- a/sw/source/core/fields/expfld.cxx
+++ b/sw/source/core/fields/expfld.cxx
@@ -881,10 +881,9 @@ std::unique_ptr<SwField> SwSetExpField::Copy() const
 
 void SwSetExpField::SetSubType(sal_uInt16 nSub)
 {
+    assert((nSub & 0xff) != 
(nsSwGetSetExpType::GSE_STRING|nsSwGetSetExpType::GSE_EXPR) && "SubType is 
illegal!");
     static_cast<SwSetExpFieldType*>(GetTyp())->SetType(nSub & 0xff);
     mnSubType = nSub & 0xff00;
-
-    OSL_ENSURE( (nSub & 0xff) != 3, "SubType is illegal!" );
 }
 
 sal_uInt16 SwSetExpField::GetSubType() const
@@ -1100,8 +1099,19 @@ bool SwSetExpField::PutValue( const uno::Any& rAny, 
sal_uInt16 nWhichId )
         break;
     case FIELD_PROP_SUBTYPE:
         nTmp32 = lcl_APIToSubType(rAny);
-        if(nTmp32 >= 0)
-            SetSubType(o3tl::narrowing<sal_uInt16>((GetSubType() & 0xff00) | 
nTmp32));
+        if (0 <= nTmp32 && nTmp32 != (GetSubType() & 0xff))
+        {
+            auto const subType(o3tl::narrowing<sal_uInt16>((GetSubType() & 
0xff00) | nTmp32));
+            if (((nTmp32 & nsSwGetSetExpType::GSE_STRING) != (GetSubType() & 
nsSwGetSetExpType::GSE_STRING))
+                && GetInputFlag())
+            {
+                SwXTextField::TransmuteLeadToInputField(*this, &subType);
+            }
+            else
+            {
+                SetSubType(subType);
+            }
+        }
         break;
     case FIELD_PROP_PAR3:
         rAny >>= maPText;
@@ -1120,7 +1130,7 @@ bool SwSetExpField::PutValue( const uno::Any& rAny, 
sal_uInt16 nWhichId )
                 if (static_cast<SwSetExpFieldType*>(GetTyp())->GetType()
                         & nsSwGetSetExpType::GSE_STRING)
                 {
-                    SwXTextField::TransmuteLeadToInputField(*this);
+                    SwXTextField::TransmuteLeadToInputField(*this, nullptr);
                 }
                 else
                 {
diff --git a/sw/source/core/inc/unofield.hxx b/sw/source/core/inc/unofield.hxx
index 55214020c038..313185a0001b 100644
--- a/sw/source/core/inc/unofield.hxx
+++ b/sw/source/core/inc/unofield.hxx
@@ -133,7 +133,7 @@ private:
 public:
     SwServiceType GetServiceId() const;
 
-    static void TransmuteLeadToInputField(SwSetExpField & rField);
+    static void TransmuteLeadToInputField(SwSetExpField & rField, sal_uInt16 
const*const pSubType);
 
     /// @return an SwXTextField, either an already existing one or a new one
     static rtl::Reference<SwXTextField>
diff --git a/sw/source/core/unocore/unofield.cxx 
b/sw/source/core/unocore/unofield.cxx
index d73c0b59b34e..b3452890e0d2 100644
--- a/sw/source/core/unocore/unofield.cxx
+++ b/sw/source/core/unocore/unofield.cxx
@@ -1238,20 +1238,34 @@ SwServiceType SwXTextField::GetServiceId() const
     it has to be disconnected first and at the end connected to the
     new instance!
  */
-void SwXTextField::TransmuteLeadToInputField(SwSetExpField & rField)
-{
-    assert(rField.GetFormatField()->Which() == (rField.GetInputFlag() ? 
RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD));
+void SwXTextField::TransmuteLeadToInputField(SwSetExpField & rField,
+        sal_uInt16 const*const pSubType)
+{
+#ifndef NDEBUG
+    auto const oldWhich(
+        (pSubType ? (rField.GetSubType() & nsSwGetSetExpType::GSE_STRING) != 0 
: rField.GetInputFlag())
+            ? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD);
+    auto const newWhich(oldWhich == RES_TXTATR_FIELD ? RES_TXTATR_INPUTFIELD : 
RES_TXTATR_FIELD);
+#endif
+    assert(rField.GetFormatField()->Which() == oldWhich);
     rtl::Reference<SwXTextField> const pXField(
         rField.GetFormatField()->GetXTextField());
     if (pXField)
         pXField->m_pImpl->SetFormatField(nullptr, nullptr);
     SwTextField *const pOldAttr(rField.GetFormatField()->GetTextField());
     SwSetExpField tempField(rField);
-    tempField.SetInputFlag(!rField.GetInputFlag());
+    if (pSubType)
+    {
+        tempField.SetSubType(*pSubType);
+    }
+    else
+    {
+        tempField.SetInputFlag(!rField.GetInputFlag());
+    }
     SwFormatField tempFormat(tempField);
     assert(tempFormat.GetField() != &rField);
     assert(tempFormat.GetField() != &tempField); // this copies it again?
-    assert(tempFormat.Which() == (static_cast<SwSetExpField 
const*>(tempFormat.GetField())->GetInputFlag() ? RES_TXTATR_INPUTFIELD : 
RES_TXTATR_FIELD));
+    assert(tempFormat.Which() == newWhich);
     SwTextNode & rNode(pOldAttr->GetTextNode());
     std::shared_ptr<SwPaM> pPamForTextField;
     IDocumentContentOperations & 
rIDCO(rNode.GetDoc().getIDocumentContentOperations());
@@ -1266,8 +1280,10 @@ void 
SwXTextField::TransmuteLeadToInputField(SwSetExpField & rField)
     SwTextField const* pNewAttr(rNode.GetFieldTextAttrAt(nStart, 
::sw::GetTextAttrMode::Default));
     assert(pNewAttr);
     SwFormatField const& rNewFormat(pNewAttr->GetFormatField());
-    assert(rNewFormat.Which() == (static_cast<SwSetExpField 
const*>(rNewFormat.GetField())->GetInputFlag() ? RES_TXTATR_INPUTFIELD : 
RES_TXTATR_FIELD));
-    assert(static_cast<SwSetExpField 
const*>(rNewFormat.GetField())->GetInputFlag() == 
(dynamic_cast<SwTextInputField const*>(pNewAttr) != nullptr));
+    assert(rNewFormat.Which() == newWhich);
+    assert((dynamic_cast<SwTextInputField const*>(pNewAttr) != nullptr)
+        == ((static_cast<SwSetExpField 
const*>(rNewFormat.GetField())->GetSubType() & nsSwGetSetExpType::GSE_STRING)
+            && static_cast<SwSetExpField 
const*>(rNewFormat.GetField())->GetInputFlag()));
     if (pXField)
     {
         
pXField->m_pImpl->SetFormatField(const_cast<SwFormatField*>(&rNewFormat), 
&rNode.GetDoc());
commit 536096309f78de9eabac38ffb9c04bff95ea7d91
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Feb 2 08:08:54 2024 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Tue Feb 6 20:34:46 2024 +0100

    tdf#159507 editeng: support pasting HTML fragments
    
    Commit ce53519f025158f8f64a4e8603c8c6e0dc35473a (cool#8023 editeng:
    support HTML paste, 2024-01-24) added support for pasting HTML files
    into Calc cells while editing, but this doesn't work when only a HTML
    fragment is provided, without headers and footers.
    
    The HTML code in ImpEditEngine::PasteText() was modeled after the
    HTML_SIMPLE case, which is some custom format from MSIE and that
    rejected the data in case the header didn't match, so the HTML case also
    required a HTML header in the above commit, but this doesn't work for
    HTML fragments.
    
    Fix the problem by just dropping the header check in
    ImpEditEngine::PasteText(), because that data already comes from the
    text/html slot of the clipboard, so there is already indication about
    the file format, even without the header. And without headers, it's
    almost impossible to recognize if the HTML fragment is a HTML one or
    not.
    
    Note that this is the HTML paste when a cell edit is active, the normal
    Calc HTML paste is a different codepath, in sc/.
    
    Change-Id: I4d37d80f947880fe22051c5fe84dc6bbc257e108
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162927
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 0503f6718f7686f3e2c93fc13af23e9fbfdace42)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162903
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/editeng/qa/unit/core-test.cxx b/editeng/qa/unit/core-test.cxx
index 348bb031d13c..8d2a6c11d4fc 100644
--- a/editeng/qa/unit/core-test.cxx
+++ b/editeng/qa/unit/core-test.cxx
@@ -83,6 +83,9 @@ public:
     /// Test Paste using HTML
     void testHTMLPaste();
 
+    /// Test Paste using an HTML fragment
+    void testHTMLFragmentPaste();
+
     /// Test Copy/Paste with selective selection over multiple paragraphs
     void testMultiParaSelCopyPaste();
 
@@ -130,6 +133,7 @@ public:
     CPPUNIT_TEST(testHyperlinkCopyPaste);
     CPPUNIT_TEST(testCopyPaste);
     CPPUNIT_TEST(testHTMLPaste);
+    CPPUNIT_TEST(testHTMLFragmentPaste);
     CPPUNIT_TEST(testMultiParaSelCopyPaste);
     CPPUNIT_TEST(testTabsCopyPaste);
     CPPUNIT_TEST(testHyperlinkSearch);
@@ -716,12 +720,19 @@ void Test::testCopyPaste()
 /// XTransferable implementation that provides simple HTML content.
 class TestHTMLTransferable : public 
cppu::WeakImplHelper<datatransfer::XTransferable>
 {
+    OString m_aHTML;
 public:
+    TestHTMLTransferable(const OString& rHTML);
     uno::Any SAL_CALL getTransferData(const datatransfer::DataFlavor& rFlavor) 
override;
     uno::Sequence<datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() 
override;
     sal_Bool SAL_CALL isDataFlavorSupported(const datatransfer::DataFlavor& 
rFlavor) override;
 };
 
+TestHTMLTransferable::TestHTMLTransferable(const OString& rHTML)
+    : m_aHTML(rHTML)
+{
+}
+
 uno::Any TestHTMLTransferable::getTransferData(const datatransfer::DataFlavor& 
rFlavor)
 {
     if (rFlavor.MimeType != "text/html")
@@ -731,7 +742,7 @@ uno::Any TestHTMLTransferable::getTransferData(const 
datatransfer::DataFlavor& r
 
     uno::Any aRet;
     SvMemoryStream aStream;
-    aStream.WriteOString("<!DOCTYPE html>
<html><body>test</body></html>");
+    aStream.WriteOString(m_aHTML);
     aRet <<= uno::Sequence<sal_Int8>(static_cast<const 
sal_Int8*>(aStream.GetData()), aStream.GetSize());
     return aRet;
 }
@@ -756,7 +767,8 @@ void Test::testHTMLPaste()
     // Given an empty editeng document:
     EditEngine aEditEngine(mpItemPool.get());
     EditDoc &rDoc = aEditEngine.GetEditDoc();
-    uno::Reference< datatransfer::XTransferable > xData(new 
TestHTMLTransferable);
+    OString aHTML("<!DOCTYPE html>
<html><body>test</body></html>"_ostr);
+    uno::Reference< datatransfer::XTransferable > xData(new 
TestHTMLTransferable(aHTML));
 
     // When trying to paste HTML:
     aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);
@@ -769,6 +781,25 @@ void Test::testHTMLPaste()
     CPPUNIT_ASSERT_EQUAL(OUString("test"), 
rDoc.GetParaAsString(static_cast<sal_Int32>(0)));
 }
 
+void Test::testHTMLFragmentPaste()
+{
+    // Given an empty editeng document:
+    EditEngine aEditEngine(mpItemPool.get());
+    EditDoc &rDoc = aEditEngine.GetEditDoc();
+    OString aHTML("a<b>b</b>c"_ostr);
+    uno::Reference< datatransfer::XTransferable > xData(new 
TestHTMLTransferable(aHTML));
+
+    // When trying to paste an HTML fragment:
+    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);
+
+    // Then make sure the text gets pasted:
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: abc
+    // - Actual  :
+    // i.e. a HTML fragment without a proper header was ignored on paste.
+    CPPUNIT_ASSERT_EQUAL(OUString("abc"), 
rDoc.GetParaAsString(static_cast<sal_Int32>(0)));
+}
+
 void Test::testMultiParaSelCopyPaste()
 {
     // Create EditEngine's instance
diff --git a/editeng/source/editeng/impedit2.cxx 
b/editeng/source/editeng/impedit2.cxx
index 7a5897196715..40f111b72e73 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -3978,14 +3978,7 @@ EditSelection ImpEditEngine::PasteText( uno::Reference< 
datatransfer::XTransfera
                     uno::Sequence<sal_Int8> aSeq;
                     aData >>= aSeq;
                     SvMemoryStream aHtmlStream(aSeq.getArray(), 
aSeq.getLength(), StreamMode::READ);
-                    static constexpr OUString aExpectedPrefix = u"<!DOCTYPE 
html>"_ustr;
-                    OUString aActualPrefix;
-                    aHtmlStream.ReadByteStringLine(aActualPrefix, 
RTL_TEXTENCODING_UTF8,
-                                                   
aExpectedPrefix.getLength());
-                    if (aActualPrefix == aExpectedPrefix)
-                    {
-                        aNewSelection = Read(aHtmlStream, rBaseURL, 
EETextFormat::Html, rPaM);
-                    }
+                    aNewSelection = Read(aHtmlStream, rBaseURL, 
EETextFormat::Html, rPaM);
                     bDone = true;
                 }
                 catch (const css::uno::Exception&)

Reply via email to