sw/inc/crsrsh.hxx                       |    2 -
 sw/qa/uitest/data/tdf150037.docx        |binary
 sw/qa/uitest/data/tdf150037.odt         |binary
 sw/qa/uitest/writer_tests8/tdf150037.py |   44 ++++++++++++++++++++++++++++++++
 sw/source/core/crsr/crbm.cxx            |    9 ++++--
 sw/source/core/inc/swfont.hxx           |    2 +
 sw/source/core/txtnode/fntcache.cxx     |    9 ++++--
 sw/source/uibase/docvw/edtwin.cxx       |    6 +++-
 sw/source/uibase/inc/edtwin.hxx         |    2 +
 sw/source/uibase/inc/wrtsh.hxx          |    2 -
 sw/source/uibase/uitest/uiobject.cxx    |   37 ++++++++++++++++++++++++++
 sw/source/uibase/wrtsh/wrtsh3.cxx       |    4 +-
 12 files changed, 106 insertions(+), 11 deletions(-)

New commits:
commit 96323a10d3a55d212c350886e2a1344c0cd2ba95
Author:     Oliver Specht <[email protected]>
AuthorDate: Wed Dec 20 07:15:53 2023 +0100
Commit:     Thorsten Behrens <[email protected]>
CommitDate: Wed Jan 17 22:24:25 2024 +0100

    tdf#150037 Writer: text fieldmark behaviour changed
    
    A mouse click selects the fieldmark to be able to overwrite the field
    with the next text input. Additionally the EN SPACE (0x2002) character
    is visualized by the DEGREE symbol when 'View/Formatting Marks' is
    active.
    
    Word's FORMTEXT ist usually filled with EN SPACE.
    
    Change-Id: I82446473d31bc5ea101bd1b94a50a855351d88b7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161044
    Tested-by: Jenkins
    Reviewed-by: Thorsten Behrens <[email protected]>

diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx
index db0667002ee2..5823a49a1599 100644
--- a/sw/inc/crsrsh.hxx
+++ b/sw/inc/crsrsh.hxx
@@ -593,7 +593,7 @@ public:
     ::sw::mark::IFieldmark* GetCurrentFieldmark();
     sw::mark::IFieldmark* GetFieldmarkAfter(bool bLoop);
     sw::mark::IFieldmark* GetFieldmarkBefore(bool bLoop);
-    bool GotoFieldmark( const ::sw::mark::IFieldmark* const pMark );
+    bool GotoFieldmark( const ::sw::mark::IFieldmark* const pMark, bool 
completeSelection = false );
 
     // update Cursr, i.e. reset it into content should only be called when the
     // cursor was set to a random position e.g. when deleting frames
diff --git a/sw/qa/uitest/data/tdf150037.docx b/sw/qa/uitest/data/tdf150037.docx
new file mode 100755
index 000000000000..4fcb18efd724
Binary files /dev/null and b/sw/qa/uitest/data/tdf150037.docx differ
diff --git a/sw/qa/uitest/data/tdf150037.odt b/sw/qa/uitest/data/tdf150037.odt
new file mode 100755
index 000000000000..15d75a694b0a
Binary files /dev/null and b/sw/qa/uitest/data/tdf150037.odt differ
diff --git a/sw/qa/uitest/writer_tests8/tdf150037.py 
b/sw/qa/uitest/writer_tests8/tdf150037.py
new file mode 100644
index 000000000000..39ea5eda7dec
--- /dev/null
+++ b/sw/qa/uitest/writer_tests8/tdf150037.py
@@ -0,0 +1,44 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-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/.
+#
+from uitest.framework import UITestCase
+from uitest.uihelper.common import get_url_for_data_file
+from libreoffice.uno.propertyvalue import mkPropertyValues
+from com.sun.star.text.TextContentAnchorType import AT_PAGE, AT_PARAGRAPH
+
+class tdf150037(UITestCase):
+
+    def test_tdf150037(self):
+
+        with self.ui_test.load_file(get_url_for_data_file("tdf150037.docx")) 
as document:
+
+            xWriterDoc = self.xUITest.getTopFocusWindow()
+            xWriterEdit = xWriterDoc.getChild("writer_edit")
+
+            xWriterEdit.executeAction("CLICK", mkPropertyValues({"START_POS": 
"14", "END_POS": "14"}))
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"TEXT": 
"Replacement"}))
+            xWriterEdit.executeAction("SELECT", mkPropertyValues({"START_POS": 
"0", "END_POS": "22"}))
+            windowState = xWriterEdit.getState();
+            self.assertEqual(windowState[14].Value, "Fieldmark: Replacement")
+
+    def test_tdf150037_protected(self):
+
+        with self.ui_test.load_file(get_url_for_data_file("tdf150037.odt")) as 
document:
+
+            xWriterDoc = self.xUITest.getTopFocusWindow()
+            xWriterEdit = xWriterDoc.getChild("writer_edit")
+
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": 
"DOWN"}))
+            xWriterEdit.executeAction("CLICK", mkPropertyValues({"START_POS": 
"14", "END_POS": "14"}))
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"TEXT": 
"Replacement"}))
+            xWriterEdit.executeAction("SELECT", mkPropertyValues({"START_POS": 
"0", "END_POS": "23"}))
+            windowState = xWriterEdit.getState();
+            self.assertEqual(windowState[14].Value, "Fieldmark: Replacement")
+
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/core/crsr/crbm.cxx b/sw/source/core/crsr/crbm.cxx
index e296bd50e8fe..fbc2ab28e1da 100644
--- a/sw/source/core/crsr/crbm.cxx
+++ b/sw/source/core/crsr/crbm.cxx
@@ -302,15 +302,18 @@ sw::mark::IFieldmark* 
SwCursorShell::GetFieldmarkBefore(bool bLoop)
     return getIDocumentMarkAccess()->getFieldmarkBefore(pos, bLoop);
 }
 
-bool SwCursorShell::GotoFieldmark(::sw::mark::IFieldmark const * const pMark)
+bool SwCursorShell::GotoFieldmark(::sw::mark::IFieldmark const * const pMark, 
bool completeSelection)
 {
     if(pMark==nullptr) return false;
 
     // watch Cursor-Moves
     CursorStateHelper aCursorSt(*this);
     aCursorSt.SetCursorToMark(pMark);
-    aCursorSt.m_pCursor->GetPoint()->AdjustContent(+1);
-    aCursorSt.m_pCursor->GetMark()->AdjustContent(-1);
+    if (!completeSelection || aCursorSt.m_pCursor->HasReadonlySel(false, 
false))
+    {
+        aCursorSt.m_pCursor->GetPoint()->AdjustContent(+1);
+        aCursorSt.m_pCursor->GetMark()->AdjustContent(-1);
+    }
 
     if(aCursorSt.RollbackIfIllegal()) return false;
 
diff --git a/sw/source/core/inc/swfont.hxx b/sw/source/core/inc/swfont.hxx
index 86f44fb3eb64..a8c3320d1cb8 100644
--- a/sw/source/core/inc/swfont.hxx
+++ b/sw/source/core/inc/swfont.hxx
@@ -47,6 +47,8 @@ const sal_Unicode CH_BULLET = 0xB7;     // centered dot
 const sal_Unicode CH_FULL_BLANK = 0x3000;
 const sal_Unicode CH_NB_SPACE = 0xA0;
 const sal_Unicode CH_SIX_PER_EM = 0x2006; // six-per-em space
+const sal_Unicode CH_EN_SPACE = 0x2002;
+const sal_Unicode CH_DEGREE =  0xb0;
 
 Degree10 UnMapDirection( Degree10 nDir, const bool bVertFormat, const bool 
bVertFormatLRBT );
 
diff --git a/sw/source/core/txtnode/fntcache.cxx 
b/sw/source/core/txtnode/fntcache.cxx
index 4e9f2a1c1dc7..6b613f4d91ca 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -1321,7 +1321,9 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
             aBulletOverlay = rInf.GetText().copy( nCopyStart, nCopyLen );
 
             for( sal_Int32 i = 0; i < aBulletOverlay.getLength(); ++i )
-                if( CH_BLANK == aBulletOverlay[ i ] )
+            {
+                const sal_Unicode replaceChar = aBulletOverlay[ i ];
+                if( CH_BLANK == replaceChar || CH_EN_SPACE == replaceChar )
                 {
                     /* fdo#72488 Hack: try to see if the space is zero width
                      * and don't bother with inserting a bullet in this case.
@@ -1329,17 +1331,18 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                     if ((i + nCopyStart + 1 >= sal_Int32(rInf.GetLen())) ||
                         aKernArray[i + nCopyStart] != aKernArray[ i + 
nCopyStart + 1])
                     {
-                        aBulletOverlay = aBulletOverlay.replaceAt(i, 1, 
rtl::OUStringChar(CH_BULLET));
+                        aBulletOverlay = aBulletOverlay.replaceAt(i, 1, 
rtl::OUStringChar(CH_BLANK == replaceChar ? CH_BULLET : CH_DEGREE));
                     }
                     else
                     {
-                        aBulletOverlay = aBulletOverlay.replaceAt(i, 1, 
rtl::OUStringChar(CH_BLANK));
+                        aBulletOverlay = aBulletOverlay.replaceAt(i, 1, 
rtl::OUStringChar(replaceChar));
                     }
                 }
                 else
                 {
                     aBulletOverlay = aBulletOverlay.replaceAt(i, 1, 
rtl::OUStringChar(CH_BLANK));
                 }
+            }
         }
 
         TextFrameIndex nCnt(rInf.GetText().getLength());
diff --git a/sw/source/uibase/docvw/edtwin.cxx 
b/sw/source/uibase/docvw/edtwin.cxx
index f01cf9256c74..e36699b74def 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -4897,7 +4897,7 @@ void SwEditWin::MouseButtonUp(const MouseEvent& rMEvt)
             }
             else
             {
-                SwContentAtPos aFieldAtPos ( IsAttrAtPos::Field );
+                SwContentAtPos aFieldAtPos ( IsAttrAtPos::Field | 
IsAttrAtPos::FormControl );
                 if ( !rSh.IsInSelect() && rSh.TestCurrPam( aDocPt ) &&
                      !rSh.GetContentAtPos( aDocPt, aFieldAtPos ) )
                 {
@@ -5024,6 +5024,10 @@ void SwEditWin::MouseButtonUp(const MouseEvent& rMEvt)
                                         rCheckboxFm.Invalidate();
                                         rSh.InvalidateWindows( 
SwRect(m_rView.GetVisArea()) );
                                     }
+                                    else if ( fieldBM->GetFieldname( ) == 
ODF_FORMTEXT )
+                                    {
+                                        rSh.GotoFieldmark( 
aContentAtPos.aFnd.pFieldmark, true );
+                                    }
                                 }
                             }
                             else if ( IsAttrAtPos::InetAttr == 
aContentAtPos.eContentAtPos )
diff --git a/sw/source/uibase/inc/edtwin.hxx b/sw/source/uibase/inc/edtwin.hxx
index 714e6bcc3be0..8978762ac3d3 100644
--- a/sw/source/uibase/inc/edtwin.hxx
+++ b/sw/source/uibase/inc/edtwin.hxx
@@ -59,6 +59,8 @@ class SwTextFrame;
 class SW_DLLPUBLIC SwEditWin final : public vcl::DocWindow,
                 public DropTargetHelper, public DragSourceHelper
 {
+    friend class SwEditWinUIObject;
+
     static  QuickHelpData* s_pQuickHlpData;
 
     static  tools::Long    s_nDDStartPosX;
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index 741c28c8a648..44a17f96a6ad 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -426,7 +426,7 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
     bool GoNextBookmark(); // true when there still was one
     bool GoPrevBookmark();
 
-    bool GotoFieldmark(::sw::mark::IFieldmark const * const pMark);
+    bool GotoFieldmark(::sw::mark::IFieldmark const * const pMark, bool 
completeSelection = false);
 
     bool GotoField( const SwFormatField& rField );
 
diff --git a/sw/source/uibase/uitest/uiobject.cxx 
b/sw/source/uibase/uitest/uiobject.cxx
index 097769e3704f..eed92644ef16 100644
--- a/sw/source/uibase/uitest/uiobject.cxx
+++ b/sw/source/uibase/uitest/uiobject.cxx
@@ -14,6 +14,7 @@
 #include <wrtsh.hxx>
 #include <ndtxt.hxx>
 #include <viewopt.hxx>
+#include <vcl/event.hxx>
 #include <sfx2/sidebar/Sidebar.hxx>
 #include <sfx2/viewfrm.hxx>
 
@@ -134,6 +135,42 @@ void SwEditWinUIObject::execute(const OUString& rAction,
             ::sfx2::sidebar::Sidebar::ShowPanel(aVal, 
pViewFrm->GetFrame().GetFrameInterface());
         }
     }
+    else if (rAction == "CLICK")
+    {
+        if (rParameters.find("START_POS") != rParameters.end())
+        {
+            auto itr = rParameters.find("START_POS");
+            OUString aStartPos = itr->second;
+            TextFrameIndex const nStartPos(aStartPos.toInt32());
+
+            itr = rParameters.find("END_POS");
+            assert(itr != rParameters.end());
+            OUString aEndPos = itr->second;
+            TextFrameIndex const nEndPos(aEndPos.toInt32());
+
+            auto & shell = getWrtShell(mxEditWin);
+            if (shell.GetCursor_()->GetPoint()->GetNode().GetTextNode())
+            {
+                shell.Push();
+                shell.MovePara(GoCurrPara, fnParaEnd);
+                TextFrameIndex const len(shell.GetCursorPointAsViewIndex());
+                shell.Pop(SwCursorShell::PopMode::DeleteCurrent);
+                SAL_WARN_IF(
+                    sal_Int32(nStartPos) < 0 || nStartPos > len || 
sal_Int32(nEndPos) < 0 || nEndPos > len, "sw.ui",
+                    "SELECT START/END_POS " << sal_Int32(nStartPos) << ".." << 
sal_Int32(nEndPos) << " outside 0.." << sal_Int32(len));
+                shell.SelectTextView(
+                    std::clamp(nStartPos, TextFrameIndex(0), len), 
std::clamp(nEndPos, TextFrameIndex(0), len));
+                Point point = shell.GetCharRect().Center();
+                MouseEvent mouseEvent(mxEditWin->LogicToPixel(point), 1, 
MouseEventModifiers::NONE, MOUSE_LEFT);
+                mxEditWin->MouseButtonDown(mouseEvent);
+                mxEditWin->MouseButtonUp(mouseEvent);
+            }
+            else
+            {
+                SAL_WARN("sw.ui", "CLICK without SwTextNode");
+            }
+        }
+    }
     else
         WindowUIObject::execute(rAction, rParameters);
 }
diff --git a/sw/source/uibase/wrtsh/wrtsh3.cxx 
b/sw/source/uibase/wrtsh/wrtsh3.cxx
index 0907794d7c2c..6920def5a3e7 100644
--- a/sw/source/uibase/wrtsh/wrtsh3.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh3.cxx
@@ -221,10 +221,10 @@ bool SwWrtShell::GotoContentControl(const 
SwFormatContentControl& rContentContro
     return bRet;
 }
 
-bool SwWrtShell::GotoFieldmark(::sw::mark::IFieldmark const * const pMark)
+bool SwWrtShell::GotoFieldmark(::sw::mark::IFieldmark const * const pMark, 
bool completeSelection)
 {
     (this->*m_fnKillSel)( nullptr, false );
-    bool bRet = SwCursorShell::GotoFieldmark(pMark);
+    bool bRet = SwCursorShell::GotoFieldmark(pMark, completeSelection);
     if( bRet && IsSelFrameMode() )
     {
         UnSelectFrame();

Reply via email to