sw/qa/core/frmedt/frmedt.cxx | 28 ++++++++++++++++++++++++++++ sw/source/core/frmedt/feshview.cxx | 23 ++++++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-)
New commits: commit d19cbc040b0cc06a838858fdd27b4f3fc6865776 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon May 15 08:42:17 2023 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue May 16 11:07:35 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). (cherry picked from commit 61f3c796702f725f2c65b53b79ab7e190d39b6b8) Change-Id: Ifa0d2a245b97fc2ada247849e3f22579730a62e7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151824 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> 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 4af556edbef4..14b97a620cca 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 );