diff options
author | Attila Bakos (NISZ) <bakos.attilakaroly@nisz.hu> | 2022-02-17 16:00:01 +0100 |
---|---|---|
committer | László Németh <nemeth@numbertext.org> | 2022-03-10 19:50:36 +0100 |
commit | 6e8ae79176be1c34cadc833c8e521be19455fade (patch) | |
tree | 88860206400f18a3c3f12edea44ba03526f15d7c | |
parent | 64dcedcf7c073d1819794d68a33651b14877e1b5 (diff) |
tdf#116256 sw: fix textbox position in floating table
in case of it has to follow the text flow.
Change-Id: Ic4f195c2efcc465276faa9a95362933dafa65bee
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130077
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
-rw-r--r-- | sw/qa/extras/layout/data/tdf116256.docx | bin | 0 -> 21136 bytes | |||
-rw-r--r-- | sw/qa/extras/layout/layout2.cxx | 44 | ||||
-rw-r--r-- | sw/source/core/doc/textboxhelper.cxx | 90 | ||||
-rw-r--r-- | xmloff/qa/unit/draw.cxx | 2 |
4 files changed, 125 insertions, 11 deletions
diff --git a/sw/qa/extras/layout/data/tdf116256.docx b/sw/qa/extras/layout/data/tdf116256.docx Binary files differnew file mode 100644 index 000000000000..f067e04f0614 --- /dev/null +++ b/sw/qa/extras/layout/data/tdf116256.docx diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx index 38451465bab0..7c8914b814d7 100644 --- a/sw/qa/extras/layout/layout2.cxx +++ b/sw/qa/extras/layout/layout2.cxx @@ -11,6 +11,7 @@ #include <com/sun/star/text/XTextFrame.hpp> #include <com/sun/star/linguistic2/XHyphenator.hpp> +#include <com/sun/star/table/XTable.hpp> #include <comphelper/scopeguard.hxx> #include <comphelper/propertysequence.hxx> @@ -988,6 +989,49 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf69648) } } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf116256) +{ + // Open bugdoc + createSwDoc(DATA_DIRECTORY, "tdf116256.docx"); + CPPUNIT_ASSERT(mxComponent); + + // Get the textbox + uno::Reference<beans::XPropertySet> xTextBox(getShape(2), uno::UNO_QUERY_THROW); + + // Ensure that is a real textbox, and follows the text flow + CPPUNIT_ASSERT(xTextBox->getPropertyValue("TextBox").get<bool>()); + CPPUNIT_ASSERT(xTextBox->getPropertyValue("IsFollowingTextFlow").get<bool>()); + + // Parse the layout + auto pLayout = parseLayoutDump(); + // Get the position of the shape + const auto nTextBoxShapeLeft = getXPath(pLayout, + "/root/page/body/txt/anchored/fly/tab/row[1]/cell/txt/" + "anchored/SwAnchoredDrawObject/bounds", + "left") + .toInt64(); + const auto nTextBoxShapeTop = getXPath(pLayout, + "/root/page/body/txt/anchored/fly/tab/row[1]/cell/txt/" + "anchored/SwAnchoredDrawObject/bounds", + "top") + .toInt64(); + // Get the position of the textframe too. + const auto nTextBoxFrameLeft + = getXPath(pLayout, + "/root/page/body/txt/anchored/fly/tab/row[1]/cell/txt/anchored/fly/infos/bounds", + "left") + .toInt64(); + const auto nTextBoxFrameTop + = getXPath(pLayout, + "/root/page/body/txt/anchored/fly/tab/row[1]/cell/txt/anchored/fly/infos/bounds", + "top") + .toInt64(); + + // Without the fix in place these were less than they supposed to. + CPPUNIT_ASSERT_GREATEREQUAL(nTextBoxShapeLeft, nTextBoxFrameLeft); + CPPUNIT_ASSERT_GREATEREQUAL(nTextBoxShapeTop, nTextBoxFrameTop); +} + CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf138194) { SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "xaxis-labelbreak.docx"); diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx index 6657a5244305..21da16f5f2d8 100644 --- a/sw/source/core/doc/textboxhelper.cxx +++ b/sw/source/core/doc/textboxhelper.cxx @@ -26,9 +26,11 @@ #include <unoprnms.hxx> #include <mvsave.hxx> #include <fmtsrnd.hxx> +#include <fmtfollowtextflow.hxx> #include <frmfmt.hxx> #include <frameformats.hxx> #include <dflyobj.hxx> +#include <swtable.hxx> #include <editeng/unoprnms.hxx> #include <editeng/memberids.h> @@ -1069,6 +1071,9 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& return; const bool bInlineAnchored = rShape.GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR; + const bool bLayoutInCell + = rShape.GetFollowTextFlow().GetValue() && rShape.GetAnchor().GetContentAnchor() + && rShape.GetAnchor().GetContentAnchor()->nNode.GetNode().FindTableNode(); SfxItemSet aTextBoxSet(pFormat->GetDoc()->GetAttrPool(), aFrameFormatSetRange); SfxItemIter aIter(rSet); @@ -1085,7 +1090,7 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& = mapAnchorType(rShape.GetAnchor().GetAnchorId()); syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType), pObj); - if (bInlineAnchored) + if (bInlineAnchored || bLayoutInCell) return; SwFormatVertOrient aOrient(pItem->StaticWhichCast(RES_VERT_ORIENT)); @@ -1115,7 +1120,7 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& = mapAnchorType(rShape.GetAnchor().GetAnchorId()); syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType), pObj); - if (bInlineAnchored) + if (bInlineAnchored || bLayoutInCell) return; SwFormatHoriOrient aOrient(pItem->StaticWhichCast(RES_HORI_ORIENT)); @@ -1324,24 +1329,37 @@ bool SwTextBoxHelper::changeAnchor(SwFrameFormat* pShape, SdrObject* pObj) bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pObj) { + bool bSuccess = false; + // Set the position of the textboxes according to the position of its shape-pair const bool bIsGroupObj = (pObj != pShape->FindRealSdrObject()) && pObj; if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj)) { + // Do not create undo entry for the positioning ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo()); + + // Special treatment for AS_CHAR textboxes: if (pShape->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR) { + // Get the text area of the shape tools::Rectangle aRect( getTextRectangle(pObj ? pObj : pShape->FindRealSdrObject(), false)); + // Get the left spacing of the text area of the shape auto nLeftSpace = pShape->GetLRSpace().GetLeft(); + // Set the textbox position at the X-axis: SwFormatHoriOrient aNewHOri(pFormat->GetHoriOrient()); aNewHOri.SetPos(aRect.Left() + nLeftSpace + (bIsGroupObj ? pObj->GetRelativePos().getX() : 0)); SwFormatVertOrient aNewVOri(pFormat->GetVertOrient()); + // Special handling of group textboxes if (bIsGroupObj) { + // There are the following cases: + // case 1: The textbox should be in that position where the shape is. + // case 2: The shape has negative offset so that have to be subtracted + // case 3: The shape and its parent shape also has negative offset, so subtract aNewVOri.SetPos( ((pObj->GetRelativePos().getY()) > 0 ? (pShape->GetVertOrient().GetPos() > 0 @@ -1354,16 +1372,19 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pOb } else { + // Simple textboxes: vertical position equals to the vertical offset of the shape aNewVOri.SetPos( ((pShape->GetVertOrient().GetPos()) > 0 ? pShape->GetVertOrient().GetPos() : 0) + aRect.Top()); } + // Special cases when the shape is aligned to the line if (pShape->GetVertOrient().GetVertOrient() != text::VertOrientation::NONE) { aNewVOri.SetVertOrient(text::VertOrientation::NONE); switch (pShape->GetVertOrient().GetVertOrient()) { + // Top aligned shape case text::VertOrientation::TOP: case text::VertOrientation::CHAR_TOP: case text::VertOrientation::LINE_TOP: @@ -1371,6 +1392,7 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pOb aNewVOri.SetPos(aNewVOri.GetPos() - pShape->GetFrameSize().GetHeight()); break; } + // Bottom aligned shape case text::VertOrientation::BOTTOM: case text::VertOrientation::CHAR_BOTTOM: case text::VertOrientation::LINE_BOTTOM: @@ -1378,6 +1400,7 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pOb aNewVOri.SetPos(aNewVOri.GetPos() + pShape->GetFrameSize().GetHeight()); break; } + // Center aligned shape case text::VertOrientation::CENTER: case text::VertOrientation::CHAR_CENTER: case text::VertOrientation::LINE_CENTER: @@ -1391,14 +1414,20 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pOb } } - pFormat->SetFormatAttr(aNewHOri); - pFormat->SetFormatAttr(aNewVOri); + bSuccess = pFormat->SetFormatAttr(aNewHOri); + bSuccess &= pFormat->SetFormatAttr(aNewVOri); } + // Other cases when the shape has different anchor from AS_CHAR else { + // Text area of the shape tools::Rectangle aRect( getTextRectangle(pObj ? pObj : pShape->FindRealSdrObject(), false)); + // X Offset of the shape spacing + auto nLeftSpace = pShape->GetLRSpace().GetLeft(); + + // Set the same position as the (child) shape has SwFormatHoriOrient aNewHOri(pShape->GetHoriOrient()); aNewHOri.SetPos( (bIsGroupObj && pObj ? pObj->GetRelativePos().getX() : aNewHOri.GetPos()) @@ -1408,10 +1437,12 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pOb (bIsGroupObj && pObj ? pObj->GetRelativePos().getY() : aNewVOri.GetPos()) + aRect.Top()); + // Get the distance of the child shape inside its parent const auto& nInshapePos = pObj ? pObj->GetRelativePos() - pShape->FindRealSdrObject()->GetRelativePos() : Point(); + // Special case: the shape has relative position from the page if (pShape->GetHoriOrient().GetRelationOrient() == text::RelOrientation::PAGE_FRAME && pShape->GetAnchor().GetAnchorId() != RndStdIds::FLY_AT_PAGE) { @@ -1428,10 +1459,49 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pOb + aRect.Top()); } - pFormat->SetFormatAttr(aNewHOri); - pFormat->SetFormatAttr(aNewVOri); + // Other special case: shape is inside a table or floating table following the text flow + if (pShape->GetFollowTextFlow().GetValue() && pShape->GetAnchor().GetContentAnchor() + && pShape->GetAnchor().GetContentAnchor()->nNode.GetNode().FindTableNode()) + { + // Table position + Point nTableOffset; + // Floating table + if (auto pFly = pShape->GetAnchor() + .GetContentAnchor() + ->nNode.GetNode() + .FindTableNode() + ->FindFlyStartNode()) + { + if (auto pFlyFormat = pFly->GetFlyFormat()) + { + nTableOffset.setX(pFlyFormat->GetHoriOrient().GetPos()); + nTableOffset.setY(pFlyFormat->GetVertOrient().GetPos()); + } + } + else + // Normal table + { + auto pTableNode + = pShape->GetAnchor().GetContentAnchor()->nNode.GetNode().FindTableNode(); + if (auto pTableFormat = pTableNode->GetTable().GetFrameFormat()) + { + nTableOffset.setX(pTableFormat->GetHoriOrient().GetPos()); + nTableOffset.setY(pTableFormat->GetVertOrient().GetPos()); + } + } + + // Add the table positions to the textbox. + aNewHOri.SetPos(aNewHOri.GetPos() + nTableOffset.getX() + nLeftSpace); + if (pShape->GetVertOrient().GetRelationOrient() == text::RelOrientation::PAGE_FRAME + || pShape->GetVertOrient().GetRelationOrient() + == text::RelOrientation::PAGE_PRINT_AREA) + aNewVOri.SetPos(aNewVOri.GetPos() + nTableOffset.getY()); + } + + bSuccess = pFormat->SetFormatAttr(aNewHOri); + bSuccess &= pFormat->SetFormatAttr(aNewVOri); } - return true; + return bSuccess; } return false; @@ -1469,7 +1539,7 @@ bool SwTextBoxHelper::DoTextBoxZOrderCorrection(SwFrameFormat* pShape, const Sdr SdrObject* pFrmObj = pTextBox->FindRealSdrObject(); if (!pFrmObj) { - // During doc-loading there is no ready SdrObj for z-ordering, so create one here and cache it. + // During loading there is no ready SdrObj for z-ordering, so create and cache it here pFrmObj = SwXTextFrame::GetOrCreateSdrObject(*dynamic_cast<SwFlyFrameFormat*>(pTextBox)); } @@ -1480,9 +1550,9 @@ bool SwTextBoxHelper::DoTextBoxZOrderCorrection(SwFrameFormat* pShape, const Sdr = pShape->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel(); if (pDrawModel) { - // Not really sure this will work all page, but it seems it will. + // Not really sure this will work on all pages, but it seems it will. auto pPage = pDrawModel->GetPage(0); - // Recalc all Zorders + // Recalc all Z-orders pPage->RecalcObjOrdNums(); // Here is a counter avoiding running to in infinity: sal_uInt16 nIterator = 0; diff --git a/xmloff/qa/unit/draw.cxx b/xmloff/qa/unit/draw.cxx index 9185bfb63157..ac0801dce72b 100644 --- a/xmloff/qa/unit/draw.cxx +++ b/xmloff/qa/unit/draw.cxx @@ -109,7 +109,7 @@ CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTextBoxLoss) // Make sure that the shape is still a textbox. uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY); uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage(); - uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(1), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); bool bTextBox = false; xShape->getPropertyValue("TextBox") >>= bTextBox; |