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());