summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2023-12-01 08:40:40 +0100
committerMiklos Vajna <vmiklos@collabora.com>2023-12-01 10:21:11 +0100
commitf461853b11439c4e485a79174d34735395e5bf52 (patch)
tree763d88b076d48a7b60fcd13b14575fdc73b3250c
parent44ee19c99bfb3bf0f550d9656e87bca3e20e5ca0 (diff)
sw floattable: fix finding the nearest text in split flys on mouse click
Clicking on the right of the floating table on the page 1 resulted in a cursor position on page 2 instead of a position inside the floating table on page 1. What happens is that the anchor text frame on page 1 is wide enough to contain the mouse click position, but then "before the first character of the paragraph" is on page 2, so a page 1 click results in a page 2 cursor position, which is unexpected. Fix the problem by first ignoring which dummy anchor frames (all non-last ones) in SwLayoutFrame, so SwLayoutFrame::GetModelPositionForViewPoint() in SwPageFrame::GetModelPositionForViewPoint() fails for the perfect match case, and then later looking for split flys explicitly, so the corrected case finds the split fly on the page. I imagine this is not only useful for mouse clicks, but it's also good for everything else that uses GetModelPositionForViewPoint(), e.g. keyboard page-down. Change-Id: I761b211c1b5468d9d8996c59a32ac9be5b83a777 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160194 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--sw/CppunitTest_sw_core_layout.mk1
-rw-r--r--sw/qa/core/layout/data/floattable-model-position-for-view-point-correction.docxbin0 -> 12696 bytes
-rw-r--r--sw/qa/core/layout/trvlfrm.cxx56
-rw-r--r--sw/source/core/layout/trvlfrm.cxx25
4 files changed, 81 insertions, 1 deletions
diff --git a/sw/CppunitTest_sw_core_layout.mk b/sw/CppunitTest_sw_core_layout.mk
index b77cf51e2799..5eb874400d53 100644
--- a/sw/CppunitTest_sw_core_layout.mk
+++ b/sw/CppunitTest_sw_core_layout.mk
@@ -23,6 +23,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,sw_core_layout, \
sw/qa/core/layout/paintfrm \
sw/qa/core/layout/sortedobjs \
sw/qa/core/layout/tabfrm \
+ sw/qa/core/layout/trvlfrm \
))
$(eval $(call gb_CppunitTest_use_libraries,sw_core_layout, \
diff --git a/sw/qa/core/layout/data/floattable-model-position-for-view-point-correction.docx b/sw/qa/core/layout/data/floattable-model-position-for-view-point-correction.docx
new file mode 100644
index 000000000000..1de36c6e0c1f
--- /dev/null
+++ b/sw/qa/core/layout/data/floattable-model-position-for-view-point-correction.docx
Binary files differ
diff --git a/sw/qa/core/layout/trvlfrm.cxx b/sw/qa/core/layout/trvlfrm.cxx
new file mode 100644
index 000000000000..dc8ba54f4feb
--- /dev/null
+++ b/sw/qa/core/layout/trvlfrm.cxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <wrtsh.hxx>
+#include <docsh.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <rootfrm.hxx>
+#include <node.hxx>
+
+namespace
+{
+/// Covers sw/source/core/layout/trvlfrm.cxx fixes.
+class Test : public SwModelTestBase
+{
+public:
+ Test()
+ : SwModelTestBase("/sw/qa/core/layout/data/")
+ {
+ }
+};
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyModelPositionForViewPointCorrection)
+{
+ // Given a 2 page floating table, 40% width, positioned on the left of the page:
+ createSwDoc("floattable-model-position-for-view-point-correction.docx");
+
+ // When clicking on the right side of the table:
+ SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+ SwDoc* pDoc = getSwDocShell()->GetDoc();
+ SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+ SwFrame* pPage = pLayout->GetLower();
+ SwFrame* pBody = pPage->GetLower();
+ const SwRect& rBodyRect = pBody->getFrameArea();
+ // 1 line below the top center of the body frame.
+ Point aDocPos(rBodyRect.Left() + rBodyRect.Width() / 2, rBodyRect.Top() + 220);
+ bool bOnlyText = false;
+ pWrtShell->CallSetCursor(&aDocPos, bOnlyText);
+
+ // Then make sure the cursor gets inside the table, and doesn't go to the anchor on page 2:
+ SwCursor& rCursor = pWrtShell->GetCurrentShellCursor();
+ SwTableNode* pTableNode = rCursor.GetPointNode().FindTableNode();
+ // Without the accompanying fix in place, this test would have failed, the cursor was in the
+ // anchor text node, not inside the split fly.
+ CPPUNIT_ASSERT(pTableNode);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx
index d79ffab813aa..5f8e3aa995a3 100644
--- a/sw/source/core/layout/trvlfrm.cxx
+++ b/sw/source/core/layout/trvlfrm.cxx
@@ -51,6 +51,7 @@
#include "../text/itrpaint.hxx"
#include <ndtxt.hxx>
#include <undobj.hxx>
+#include <flyfrms.hxx>
#include <swselectionlist.hxx>
#include <comphelper/lok.hxx>
@@ -166,8 +167,17 @@ bool SwLayoutFrame::GetModelPositionForViewPoint( SwPosition *pPos, Point &rPoin
pFrame->UnionFrame() :
pFrame->GetPaintArea() );
+ auto pTextFrame = pFrame->DynCastTextFrame();
+ bool bSplitFly = false;
+ if (pTextFrame && pTextFrame->HasNonLastSplitFlyDrawObj())
+ {
+ // Don't consider a non-last anchor of the split fly, so the view point can be corrected
+ // to go to the nearest fly, instead of the last anchor on a later page.
+ bSplitFly = true;
+ }
+
if ( aPaintRect.Contains( rPoint ) &&
- ( bContentCheck || pFrame->GetModelPositionForViewPoint( pPos, rPoint, pCMS ) ) )
+ ( bContentCheck || pFrame->GetModelPositionForViewPoint( pPos, rPoint, pCMS ) ) && !bSplitFly )
bRet = true;
else
pFrame = pFrame->GetNext();
@@ -218,6 +228,19 @@ bool SwPageFrame::GetModelPositionForViewPoint( SwPosition *pPos, Point &rPoint,
}
const SwContentFrame *pCnt = GetContentPos( aPoint, false, false, pCMS, false );
+
+ auto pTextFrame = pCnt ? pCnt->DynCastTextFrame() : nullptr;
+ if (pTextFrame)
+ {
+ SwFlyAtContentFrame* pFly = pTextFrame->HasNonLastSplitFlyDrawObj();
+ if (pFly)
+ {
+ // No exact match, looking for a nearest doc model position. Consider our fly
+ // frame.
+ pCnt = pFly->GetContentPos( aPoint, false, false, pCMS, false );
+ }
+ }
+
// GetContentPos may have modified pCMS
if ( pCMS && pCMS->m_bStop )
return false;