sw/inc/crsrsh.hxx                                |   10 ++
 sw/inc/crstate.hxx                               |    4 -
 sw/qa/extras/uiwriter/data/tdf111969_field.fodt  |   10 ++
 sw/qa/extras/uiwriter/data/tdf111969_fieldB.fodt |   10 ++
 sw/qa/extras/uiwriter/uiwriter9.cxx              |   86 +++++++++++++++++++++++
 sw/source/core/crsr/crsrsh.cxx                   |    3 
 sw/source/uibase/docvw/edtwin.cxx                |    4 -
 7 files changed, 122 insertions(+), 5 deletions(-)

New commits:
commit e73dfbf860b977f3b862fb75a87a7ad726d9a4c7
Author:     Justin Luth <jl...@mail.com>
AuthorDate: Mon Dec 25 20:23:52 2023 -0500
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Jan 3 08:45:34 2024 +0100

    tdf#111969 sw: acknowledge field start/end for context menu
    
    This fixes the right-click menu building
    missing out on the edit/update field option about
    half-a-character too soon at the end.
    
    It also fixes itrcrsr adding field actions to the menu
    half-a-char too soon in the edge case of a 1-len portion.
    This edge case is not limited to fields - it fixes it
    for redlines (and hyperlinks if other bugs are fixed).
    
    make CppunitTest_sw_uiwriter9 CPPUNIT_TEST_NAME=testTdf111969
    
    Change-Id: I469ec75d18d4dce0bb62ebb63b661b60e35f9e1b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161295
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <jl...@mail.com>

diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx
index 20636648c794..db0667002ee2 100644
--- a/sw/inc/crsrsh.hxx
+++ b/sw/inc/crsrsh.hxx
@@ -401,7 +401,15 @@ public:
     //  return values:
     //      CRSR_POSCHG: when cursor was corrected from SPoint by the layout
     //      CRSR_POSOLD: when the cursor was not changed
-    int SetCursor( const Point &rPt, bool bOnlyText = false, bool bBlock = 
true );
+    /**
+     * @param bFieldInfo
+     * false: Over the last half of the character, place cursor behind it. 
This is used when
+     *        the cursor is actually being moved by the user to the closest 
valid point.
+     *  true: Place the cursor at the start of the character/field. This is 
used when setting
+     *        the cursor is done in order to get at the properties under the 
mouse pointer.
+     */
+    int SetCursor(const Point& rPt, bool bOnlyText = false, bool bBlock = true,
+                  bool bFieldInfo = false);
 
     /*
      * Notification that the visible area was changed. m_aVisArea is reset, 
then
diff --git a/sw/inc/crstate.hxx b/sw/inc/crstate.hxx
index acf13bfe45d7..018106514714 100644
--- a/sw/inc/crstate.hxx
+++ b/sw/inc/crstate.hxx
@@ -139,7 +139,7 @@ struct SwCursorMoveState
     sal_uInt8            m_nCursorBidiLevel;
     bool m_bStop;
     bool m_bRealHeight;           ///< should the real height be calculated?
-    bool m_bFieldInfo;            ///< should be fields recognized?
+    bool m_bFieldInfo;            ///< should fields be recognized? (get 
position of field start)
     bool m_bPosCorr;              ///< Point had to be corrected
     bool m_bFootnoteNoInfo;            ///< recognized footnote numbering
     bool m_bExactOnly;            /**< let GetModelPositionForViewPoint look 
for exact matches only,
@@ -151,7 +151,7 @@ struct SwCursorMoveState
     bool m_bNoScroll;             ///< No scrolling of undersized textframes
     bool m_bPosMatchesBounds;         /**< GetModelPositionForViewPoint should 
not return the next
                                        position if screen position is inside 
second
-                                       have of bound rect */
+                                       half of bound rect */
 
     bool m_bContentCheck;           // #i43742# Cursor position over content?
 
diff --git a/sw/qa/extras/uiwriter/data/tdf111969_field.fodt 
b/sw/qa/extras/uiwriter/data/tdf111969_field.fodt
new file mode 100644
index 000000000000..4048fa03c42b
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/tdf111969_field.fodt
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document  
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+  <office:text>
+   <text:p>–<text:time text:time-value="1899-12-30T12:34:56" 
text:fixed="true"/>–</text:p>
+  </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/uiwriter/data/tdf111969_fieldB.fodt 
b/sw/qa/extras/uiwriter/data/tdf111969_fieldB.fodt
new file mode 100644
index 000000000000..18de3f586a94
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/tdf111969_fieldB.fodt
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document  
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+  <office:text>
+   <text:p>––<text:time text:time-value="1899-12-30T12:34:56" 
text:fixed="true"/>––</text:p>
+  </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx 
b/sw/qa/extras/uiwriter/uiwriter9.cxx
index c12be545512d..8febc2f2145e 100644
--- a/sw/qa/extras/uiwriter/uiwriter9.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter9.cxx
@@ -68,6 +68,92 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf158785)
     CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos);
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf111969)
+{
+    // given a document with a field surrounded by N-dashes (–date–)
+    createSwDoc("tdf111969_field.fodt");
+    SwDoc& rDoc = *getSwDoc();
+    SwWrtShell* pWrtShell = rDoc.GetDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+
+    // go to the end of the field
+    pWrtShell->SttEndDoc(/*bStart=*/false);
+    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
+    // get last point that will be part of the field (current position 1pt 
wide).
+    Point aLogicL(pWrtShell->GetCharRect().Center());
+    Point aLogicR(aLogicL);
+
+    // sanity check - we really are at the right edge of the field
+    aLogicR.AdjustX(1);
+    SwContentAtPos aContentAtPos(IsAttrAtPos::Field);
+    pWrtShell->GetContentAtPos(aLogicR, aContentAtPos);
+    CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos);
+    aLogicL.AdjustX(-1);
+    aContentAtPos = IsAttrAtPos::Field;
+    pWrtShell->GetContentAtPos(aLogicL, aContentAtPos);
+    CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::Field, aContentAtPos.eContentAtPos);
+
+    // the test: simulate a right-click of a mouse which sets the cursor and 
then acts on that pos.
+    pWrtShell->SwCursorShell::SetCursor(aLogicL, false, /*Block=*/false, 
/*FieldInfo=*/true);
+    CPPUNIT_ASSERT(pWrtShell->GetCurField(true));
+
+    /*
+     * An edge case at the start of a field - don't start the field menu on 
the first N-dash
+     */
+    // go to the start of the field
+    pWrtShell->SttEndDoc(/*bStart=*/true);
+    pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
+    // get first point that will be part of the field (current position 1pt 
wide).
+    aLogicL = pWrtShell->GetCharRect().Center();
+    aLogicR = aLogicL;
+
+    // sanity check - we really are at the left edge of the field
+    aLogicR.AdjustX(1);
+    aContentAtPos = IsAttrAtPos::Field;
+    pWrtShell->GetContentAtPos(aLogicR, aContentAtPos);
+    CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::Field, aContentAtPos.eContentAtPos);
+    aLogicL.AdjustX(-1);
+    aContentAtPos = IsAttrAtPos::Field;
+    pWrtShell->GetContentAtPos(aLogicL, aContentAtPos);
+    CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos);
+
+    // the test: simulate a right-click of a mouse (at the end-edge of the 
N-dash)
+    // which sets the cursor and then acts on that pos.
+    pWrtShell->SwCursorShell::SetCursor(aLogicL, false, /*Block=*/false, 
/*FieldInfo=*/true);
+    CPPUNIT_ASSERT(!pWrtShell->GetCurField(true));
+}
+
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf111969B)
+{
+    // given a document with a field surrounded by two N-dashes (––date––)
+    createSwDoc("tdf111969_fieldB.fodt");
+    SwDoc& rDoc = *getSwDoc();
+    SwWrtShell* pWrtShell = rDoc.GetDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+
+    // go to the start of the field
+    pWrtShell->SttEndDoc(/*bStart=*/true);
+    pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 2, 
/*bBasicCall=*/false);
+    // get first point that will be part of the field (current position 1pt 
wide).
+    Point aLogicL(pWrtShell->GetCharRect().Center());
+    Point aLogicR(aLogicL);
+
+    // sanity check - we really are at the left edge of the field
+    aLogicR.AdjustX(1);
+    SwContentAtPos aContentAtPos(IsAttrAtPos::Field);
+    pWrtShell->GetContentAtPos(aLogicR, aContentAtPos);
+    CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::Field, aContentAtPos.eContentAtPos);
+    aLogicL.AdjustX(-1);
+    aContentAtPos = IsAttrAtPos::Field;
+    pWrtShell->GetContentAtPos(aLogicL, aContentAtPos);
+    CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos);
+
+    // the test: simulate a right-click of a mouse (at the end-edge of the 
second N-dash)
+    // which sets the cursor and then acts on that pos.
+    pWrtShell->SwCursorShell::SetCursor(aLogicL, false, /*Block=*/false, 
/*FieldInfo=*/true);
+    //CPPUNIT_ASSERT(!pWrtShell->GetCurField(true));
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx
index 449b074194bc..ed9f47dc81c5 100644
--- a/sw/source/core/crsr/crsrsh.cxx
+++ b/sw/source/core/crsr/crsrsh.cxx
@@ -1045,7 +1045,7 @@ bool SwCursorShell::IsInHeaderFooter( bool* pbInHeader ) 
const
     return nullptr != pFrame;
 }
 
-int SwCursorShell::SetCursor( const Point &rLPt, bool bOnlyText, bool bBlock )
+int SwCursorShell::SetCursor(const Point& rLPt, bool bOnlyText, bool bBlock, 
bool bFieldInfo)
 {
     CurrShell aCurr( this );
 
@@ -1056,6 +1056,7 @@ int SwCursorShell::SetCursor( const Point &rLPt, bool 
bOnlyText, bool bBlock )
     SwCursorMoveState aTmpState( IsTableMode() ? CursorMoveState::TableSel :
                                     bOnlyText ?  CursorMoveState::SetOnlyText 
: CursorMoveState::NONE );
     aTmpState.m_bSetInReadOnly = IsReadOnlyAvailable();
+    aTmpState.m_bFieldInfo = bFieldInfo; // always set cursor at field-start 
if point is over field
 
     SwTextNode const*const pTextNd = sw::GetParaPropsNode(*GetLayout(), 
pCursor->GetPoint()->GetNode());
 
diff --git a/sw/source/uibase/docvw/edtwin.cxx 
b/sw/source/uibase/docvw/edtwin.cxx
index 4d9750a98602..e89614319903 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -6160,7 +6160,9 @@ void SwEditWin::SelectMenuPosition(SwWrtShell& rSh, const 
Point& rMousePos )
         // create only temporary move context because otherwise
         // the query against the content form doesn't work!!!
         SwMvContext aMvContext( &rSh );
-        rSh.CallSetCursor(&aDocPos, false);
+        if (rSh.HasSelection())
+            rSh.ResetSelect(&aDocPos, false);
+        rSh.SwCursorShell::SetCursor(aDocPos, false, /*Block=*/false, 
/*FieldInfo=*/true);
     }
     if( !bOverURLGrf )
     {

Reply via email to