tdf#137802 tdf#84691 sw: sync anchoring of textbox with UNO
It was possible to anchor the textbox both to page and
paragraph, resulting crash during file saving.
Change-Id: I0c95a13c0d8d58cd7cc1fa86de1b80bf088ba782
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/105046
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/qa/extras/uiwriter/data3/AtPageTextBoxCrash.odt b/sw/qa/extras/uiwriter/data3/AtPageTextBoxCrash.odt
new file mode 100644
index 0000000..20e58df
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data3/AtPageTextBoxCrash.odt
Binary files differ
diff --git a/sw/qa/extras/uiwriter/uiwriter3.cxx b/sw/qa/extras/uiwriter/uiwriter3.cxx
index 09cad81..841b034 100644
--- a/sw/qa/extras/uiwriter/uiwriter3.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter3.cxx
@@ -1856,6 +1856,45 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf127652)
CPPUNIT_ASSERT_EQUAL_MESSAGE("We are on the wrong page!", assertPage, currentPage);
}
CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, AtPageTextBoxCrash)
{
// Load sample file
load(DATA_DIRECTORY, "AtPageTextBoxCrash.odt");
SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
CPPUNIT_ASSERT(pTextDoc);
// Get the Writer-Shell for later use
SwWrtShell* pWrtSh = pTextDoc->GetDocShell()->GetWrtShell();
CPPUNIT_ASSERT(pWrtSh);
// Get the format of the shape
const SwFrameFormats& rFrmFormats = *pWrtSh->GetDoc()->GetSpzFrameFormats();
CPPUNIT_ASSERT(rFrmFormats.size() >= size_t(o3tl::make_unsigned(1)));
auto pShape = rFrmFormats.front();
CPPUNIT_ASSERT(pShape);
// Add a textbox to the shape
SwTextBoxHelper::create(pShape);
auto pTxBxFrm = SwTextBoxHelper::getOtherTextBoxFormat(getShape(1));
CPPUNIT_ASSERT(pTxBxFrm);
// Change its anchor to page
uno::Reference<beans::XPropertySet> xShpProps(getShape(1), uno::UNO_QUERY_THROW);
xShpProps->setPropertyValue(
"AnchorType", uno::makeAny(text::TextContentAnchorType::TextContentAnchorType_AT_PAGE));
// The page anchored objects must not have content anchor
// unless this will lead to crash later, for example on
// removing the paragraph where it is achored to...
CPPUNIT_ASSERT_EQUAL(RndStdIds::FLY_AT_PAGE, pTxBxFrm->GetAnchor().GetAnchorId());
CPPUNIT_ASSERT(!pTxBxFrm->GetAnchor().GetContentAnchor());
// Remove the paragraph where the textframe should be anchored
// before. Now with the patch it must not crash...
auto xPara = getParagraph(1);
xPara->getText()->setString(OUString());
}
CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf135661)
{
load(DATA_DIRECTORY, "tdf135661.odt");
diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx
index 82a1c9b..b62269f 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -130,6 +130,8 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape)
uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
syncProperty(pShape, RES_FOLLOW_TEXT_FLOW, MID_FOLLOW_TEXT_FLOW,
xShapePropertySet->getPropertyValue(UNO_NAME_IS_FOLLOWING_TEXT_FLOW));
syncProperty(pShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE,
xShapePropertySet->getPropertyValue(UNO_NAME_ANCHOR_TYPE));
syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_ORIENT,
xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT));
syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_RELATION,
@@ -160,15 +162,10 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape)
return;
SfxItemSet aTxFrmSet(pFormat->GetDoc()->GetAttrPool(), aFrameFormatSetRange);
SwFormatAnchor aNewAnch = pFormat->GetAnchor();
if (pShape->GetAnchor().GetContentAnchor())
aNewAnch.SetAnchor(pShape->GetAnchor().GetContentAnchor());
if (pShape->GetAnchor().GetPageNum() > 0)
aNewAnch.SetPageNum(pShape->GetAnchor().GetPageNum());
aNewAnch.SetType(pShape->GetAnchor().GetAnchorId());
aTxFrmSet.Put(aNewAnch);
if (rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR
|| rAnch.GetAnchorId() == RndStdIds::FLY_AT_PARA)
aTxFrmSet.Put(rAnch);
SwFormatVertOrient aVOri(pFormat->GetVertOrient());
SwFormatHoriOrient aHOri(pFormat->GetHoriOrient());
@@ -626,17 +623,38 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_u
switch (nMemberID)
{
case MID_ANCHOR_ANCHORTYPE:
{
uno::Reference<beans::XPropertySet> const xPropertySet(
SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat),
uno::UNO_QUERY);
// Surround (Wrap) has to be THROUGH always:
xPropertySet->setPropertyValue(UNO_NAME_SURROUND,
uno::makeAny(text::WrapTextMode_THROUGH));
// Use At_Char anchor instead of As_Char anchoring:
if (aValue.get<text::TextContentAnchorType>()
== text::TextContentAnchorType_AS_CHARACTER)
== text::TextContentAnchorType::TextContentAnchorType_AS_CHARACTER)
{
uno::Reference<beans::XPropertySet> const xPropertySet(
SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat),
uno::UNO_QUERY);
xPropertySet->setPropertyValue(UNO_NAME_SURROUND,
uno::makeAny(text::WrapTextMode_THROUGH));
return;
xPropertySet->setPropertyValue(
UNO_NAME_ANCHOR_TYPE,
uno::makeAny(
text::TextContentAnchorType::TextContentAnchorType_AT_CHARACTER));
}
break;
else // Otherwise copy the anchor type of the shape
{
xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
}
// After anchoring the position must be set as well:
if (aValue.get<text::TextContentAnchorType>()
== text::TextContentAnchorType::TextContentAnchorType_AT_PAGE)
{
xPropertySet->setPropertyValue(
UNO_NAME_ANCHOR_PAGE_NO,
uno::makeAny(pShape->GetAnchor().GetPageNum()));
}
return;
}
break;
}
break;
case FN_TEXT_RANGE: