sw/qa/extras/layout/data/tdf116256.docx |binary
 sw/qa/extras/layout/layout2.cxx         |   44 +++++++++++++++
 sw/source/core/doc/textboxhelper.cxx    |   90 ++++++++++++++++++++++++++++----
 xmloff/qa/unit/draw.cxx                 |    2 
 4 files changed, 125 insertions(+), 11 deletions(-)

New commits:
commit 6e8ae79176be1c34cadc833c8e521be19455fade
Author:     Attila Bakos (NISZ) <bakos.attilakar...@nisz.hu>
AuthorDate: Thu Feb 17 16:00:01 2022 +0100
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Thu Mar 10 19:50:36 2022 +0100

    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 <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>

diff --git a/sw/qa/extras/layout/data/tdf116256.docx 
b/sw/qa/extras/layout/data/tdf116256.docx
new file mode 100644
index 000000000000..f067e04f0614
Binary files /dev/null and b/sw/qa/extras/layout/data/tdf116256.docx differ
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;
 

Reply via email to