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 +++++++++++++++++++++++-------
 5 files changed, 51 insertions(+), 13 deletions(-)

New commits:
commit 99055ae98ef1fe67b8db4a8c3167a8acaeaac02f
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Feb 2 20:10:24 2024 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Feb 5 16:28:26 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>

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 aa158b43b132..115e30b61368 100644
--- a/sw/qa/extras/odfimport/odfimport.cxx
+++ b/sw/qa/extras/odfimport/odfimport.cxx
@@ -1169,9 +1169,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());

Reply via email to