sw/qa/core/frmedt/frmedt.cxx       |   28 ++++++++++++++++++++++++++++
 sw/source/core/frmedt/feshview.cxx |   23 ++++++++++++++++++++---
 2 files changed, 48 insertions(+), 3 deletions(-)

New commits:
commit 61f3c796702f725f2c65b53b79ab7e190d39b6b8
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon May 15 08:42:17 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon May 15 09:41:32 2023 +0200

    sw floattable: fix UI / property dialog for shape containing table
    
    The bugdoc contains a shape, containing a table (fly + draw format
    pair). Trying to open the shape properties (position & size) dialog in a
    debug build crashes.
    
    We hit an assertion failure in SwTextFrame::MapModelToView(), because
    the model position does not belong to the text node of the text frame.
    This happens because SwFEShell::CalcBoundRect() uses GetCurrFrame(),
    that normally points to the anchor frame for draw formats, but pointed
    to a text frame inside the table (inside the shape) instead in the
    problematic case.
    
    Fix the problem by improving SwFEShell::SelectObj(), so in case it
    selects a draw format instead of a fly format, then we don't use
    SwCursorShell::SetCursor() (which works with a coordinate, and will find
    the in-shape text nodes) but instead use SwCursorShell::SetSelection()
    to explicitly set the cursor to the anchor position.
    
    This went wrong in commit 7596e26fd259ce5445212949403e7cd32303b2bd (Add
    SwTextBoxHelper::findShapes, 2014-06-24).
    
    Change-Id: Ifa0d2a245b97fc2ada247849e3f22579730a62e7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151757
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/qa/core/frmedt/frmedt.cxx b/sw/qa/core/frmedt/frmedt.cxx
index 6d6c3735724a..18474ad33bf0 100644
--- a/sw/qa/core/frmedt/frmedt.cxx
+++ b/sw/qa/core/frmedt/frmedt.cxx
@@ -140,6 +140,34 @@ CPPUNIT_TEST_FIXTURE(SwCoreFrmedtTest, 
testPasteFlyInTextBox)
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), 
pDoc->GetSpzFrameFormats()->GetFormatCount());
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreFrmedtTest, testTextBoxSelectCursorPos)
+{
+    // Given a document with a fly+draw format pair (textbox):
+    createSwDoc("paste-fly-in-textbox.docx");
+
+    // When selecting the fly format:
+    SwDoc* pDoc = getSwDoc();
+    SdrPage* pPage = 
pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
+    SdrObject* pFlyObject = pPage->GetObj(1);
+    SwDrawContact* pFlyContact = 
static_cast<SwDrawContact*>(pFlyObject->GetUserCall());
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(RES_FLYFRMFMT), 
pFlyContact->GetFormat()->Which());
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    pWrtShell->SelectObj(Point(), 0, pFlyObject);
+
+    // Then make sure the cursor is the anchor of the draw format:
+    SdrObject* pDrawObject = pPage->GetObj(0);
+    SwDrawContact* pDrawContact = 
static_cast<SwDrawContact*>(pDrawObject->GetUserCall());
+    SwFrameFormat* pDrawFormat = pDrawContact->GetFormat();
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(RES_DRAWFRMFMT), 
pDrawFormat->Which());
+    SwNodeOffset nAnchor = 
pDrawFormat->GetAnchor().GetContentAnchor()->GetNode().GetIndex();
+    SwNodeOffset nCursor = 
pWrtShell->GetCurrentShellCursor().GetPointNode().GetIndex();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 15 (anchor of draw format)
+    // - Actual  : 6 (in-fly-format position)
+    // i.e. the cursor had a broken position after trying to select the fly 
format.
+    CPPUNIT_ASSERT_EQUAL(nAnchor, nCursor);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/frmedt/feshview.cxx 
b/sw/source/core/frmedt/feshview.cxx
index ef9497b53f38..9183580a0d80 100644
--- a/sw/source/core/frmedt/feshview.cxx
+++ b/sw/source/core/frmedt/feshview.cxx
@@ -151,7 +151,7 @@ SwFlyFrame *GetFlyFromMarked( const SdrMarkList *pLst, 
SwViewShell *pSh )
     return nullptr;
 }
 
-static void lcl_GrabCursor( SwFEShell* pSh, SwFlyFrame* pOldSelFly)
+static void lcl_GrabCursor( SwFEShell* pSh, SwFlyFrame* pOldSelFly, 
SwFrameFormat* pNewDrawFormat = nullptr)
 {
     const SwFrameFormat *pFlyFormat = pSh->SelFlyGrabCursor();
     if( pFlyFormat && !pSh->ActionPend() &&
@@ -171,7 +171,21 @@ static void lcl_GrabCursor( SwFEShell* pSh, SwFlyFrame* 
pOldSelFly)
         // --> assure consistent cursor
         pSh->KillPams();
         pSh->ClearMark();
-        pSh->SetCursor( 
pSh->Imp()->GetDrawView()->GetAllMarkedRect().TopLeft(), true);
+        if (pNewDrawFormat)
+        {
+            // If we selected a draw shape format, move the cursor to its 
anchor position.
+            // SetCursor() may pick something inside, which is not wanted: 
code later assumes that
+            // the cursor is at the anchor point if a shape is selected.
+            const SwPosition* pContentAnchor = 
pNewDrawFormat->GetAnchor().GetContentAnchor();
+            if (pContentAnchor)
+            {
+                pSh->SetSelection(SwPaM(*pContentAnchor));
+            }
+        }
+        else
+        {
+            pSh->SetCursor( 
pSh->Imp()->GetDrawView()->GetAllMarkedRect().TopLeft(), true);
+        }
     }
 }
 
@@ -306,6 +320,7 @@ bool SwFEShell::SelectObj( const Point& rPt, sal_uInt8 
nFlag, SdrObject *pObj )
             pSelFly->SelectionHasChanged(this);
     }
 
+    SwFrameFormat* pNewDrawFormat = nullptr;
     if (!(nFlag & SW_ALLOW_TEXTBOX))
     {
         // If the fly frame is a textbox of a shape, then select the shape 
instead.
@@ -324,6 +339,8 @@ bool SwFEShell::SelectObj( const Point& rPt, sal_uInt8 
nFlag, SdrObject *pObj )
                 SdrObject* pShape = pShapeFormat->FindSdrObject();
                 pDView->UnmarkAll();
                 pDView->MarkObj(pShape, Imp()->GetPageView(), bAddSelect, 
bEnterGroup);
+                // Remember that this frame format was marked for selection.
+                pNewDrawFormat = pShapeFormat;
                 break;
             }
         }
@@ -331,7 +348,7 @@ bool SwFEShell::SelectObj( const Point& rPt, sal_uInt8 
nFlag, SdrObject *pObj )
 
     if ( bRet )
     {
-        ::lcl_GrabCursor(this, pOldSelFly);
+        ::lcl_GrabCursor(this, pOldSelFly, pNewDrawFormat);
         if ( GetCntType() & CNT_GRF )
         {
             const SwFlyFrame *pTmp = GetFlyFromMarked( &rMrkList, this );

Reply via email to