offapi/com/sun/star/accessibility/XAccessibleTextSelection.idl |    2 
 sw/source/core/access/accpara.cxx                              |    2 
 sw/source/core/access/accpara.hxx                              |    2 
 vcl/qt5/QtAccessibleWidget.cxx                                 |   38 
++++++++--
 vcl/unx/gtk3/a11y/atktext.cxx                                  |   10 +-
 winaccessibility/source/UAccCOM/AccTextBase.cxx                |    2 
 6 files changed, 44 insertions(+), 12 deletions(-)

New commits:
commit d540577625ab140930f8467822aec70ede817ed5
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Thu Aug 14 11:42:47 2025 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Thu Aug 14 15:44:04 2025 +0200

    tdf#167930 qt a11y: Implement QtAccessibleWidget::{add,remove}Selection
    
    Add initial implementation for these methods, but only
    supporting a single selection, similar to what the gtk3
    implementation currently does.
    
    This makes the scenario described for gtk3 in
    
        Change-Id: Ieca9dff66eef366bf2a3845e5fdb53b3bfa70df9
        Author: Michael Weghorn <m.wegh...@posteo.de>
        Date:   Thu Aug 14 11:19:14 2025 +0200
    
            tdf#167930 gtk3 a11y: Keep caret pos when removing selection
    
    also work when using the qt6 VCL plugin on Linux.
    
    Change-Id: I93694cb2b81ef95fc25c678eaae73fd0dc00a141
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189580
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins

diff --git a/vcl/qt5/QtAccessibleWidget.cxx b/vcl/qt5/QtAccessibleWidget.cxx
index 54cc047d5df6..911ea85776e7 100644
--- a/vcl/qt5/QtAccessibleWidget.cxx
+++ b/vcl/qt5/QtAccessibleWidget.cxx
@@ -993,9 +993,24 @@ QVariant 
QtAccessibleWidget::attributeValue(QAccessible::Attribute eAttribute) c
 #endif
 
 // QAccessibleTextInterface
-void QtAccessibleWidget::addSelection(int /* startOffset */, int /* endOffset 
*/)
+void QtAccessibleWidget::addSelection(int startOffset, int endOffset)
 {
-    SAL_INFO("vcl.qt", "Unsupported QAccessibleTextInterface::addSelection");
+    // only single selection supported currently
+    if (selectionCount() > 0)
+        return;
+
+    Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
+    if (!xText.is())
+        return;
+
+    const sal_Int32 nTextLength = xText->getCharacterCount();
+    if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || 
endOffset > nTextLength)
+    {
+        SAL_WARN("vcl.qt", "QtAccessibleWidget::addSelection called with 
invalid offset.");
+        return;
+    }
+
+    xText->setSelection(startOffset, endOffset);
 }
 
 // Text attributes are returned in format specified in IAccessible2 spec, 
since that
@@ -1089,9 +1104,24 @@ int QtAccessibleWidget::offsetAtPoint(const QPoint& 
rPoint) const
     return xText->getIndexAtPoint(aPoint);
 }
 
-void QtAccessibleWidget::removeSelection(int /* selectionIndex */)
+void QtAccessibleWidget::removeSelection(int selectionIndex)
 {
-    SAL_INFO("vcl.qt", "Unsupported 
QAccessibleTextInterface::removeSelection");
+    if (selectionIndex < 0 || selectionIndex >= selectionCount())
+    {
+        SAL_WARN("vcl.qt", "QtAccessibleWidget::removeSelection called with 
invalid index");
+        return;
+    }
+
+    Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY);
+    if (!xText.is())
+        return;
+
+    // only single selection supported at the moment (s.a. seleciontCount();
+    // code below needs adjustment if that changes
+    assert(selectionIndex == 0);
+
+    const sal_Int32 nCaretPos = xText->getCaretPosition();
+    xText->setSelection(nCaretPos, nCaretPos);
 }
 
 void QtAccessibleWidget::scrollToSubstring(int startIndex, int endIndex)
commit 315c94c91adc6a9e79a78b304e8d2b95e2f45b80
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Thu Aug 14 11:19:14 2025 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Thu Aug 14 15:43:58 2025 +0200

    tdf#167930 gtk3 a11y: Keep caret pos when removing selection
    
    Don't always use an index of 0 for the start and end index
    of the new empty selection, but use the current caret position
    instead.
    
    This prevents the cursor from jumping to the beginning of
    a paragraph when removing a selection via the AT-SPI Text
    interface as decribed in tdf#167930:
    
    Example using Accerciser's IPython console with a sample
    Writer paragraph with text "abcdefghijk", with "efgh"
    initially selected.
    
    Previously (unexpected line marked with arrow):
    
        In [64]: text = acc.queryText()
        In [65]: text.caretOffset
        Out[65]: 8
        In [66]: text.getNSelections()
        Out[66]: 1
        In [67]: selection = text.getSelection(0)
        In [68]: selection[0]
        Out[68]: 4
        In [69]: selection[1]
        Out[69]: 8
        In [70]: text.removeSelection(0)
        Out[70]: True
        In [71]: text.caretOffset
    ->  Out[71]: 0
        In [72]: text.getNSelections()
        Out[72]: 0
    
    With this commit in place, the caret offset remains
    unchanged:
    
        In [74]: text = acc.queryText()
        In [75]: text.caretOffset
        Out[75]: 8
        In [76]: text.getNSelections()
        Out[76]: 1
        In [77]: selection = text.getSelection(0)
        In [78]: selection[0]
        Out[78]: 4
        In [79]: selection[1]
        Out[79]: 8
        In [80]: text.removeSelection(0)
        Out[80]: True
        In [81]: text.caretOffset
    ->  Out[81]: 8
        In [82]: text.getNSelections()
        Out[82]: 0
    
    There is also an XAccessibleTextSelection UNO interface
    that SwAccessibleParagraph implements that looks like
    it should be useful to implement the methods to
    add/remove/count selections, but it didn't work as
    expected in a quick test, so the implementation inside
    Writer would likely need to be fixed first if going
    that route.
    
    Change-Id: Ieca9dff66eef366bf2a3845e5fdb53b3bfa70df9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189579
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>

diff --git a/vcl/unx/gtk3/a11y/atktext.cxx b/vcl/unx/gtk3/a11y/atktext.cxx
index b140232055d3..54973d739e0c 100644
--- a/vcl/unx/gtk3/a11y/atktext.cxx
+++ b/vcl/unx/gtk3/a11y/atktext.cxx
@@ -793,10 +793,12 @@ text_wrapper_remove_selection (AtkText *text,
     g_return_val_if_fail( selection_num == 0, FALSE );
 
     try {
-        css::uno::Reference<css::accessibility::XAccessibleText> pText
-            = getText( text );
-        if( pText.is() )
-            return pText->setSelection( 0, 0 ); // ?
+        css::uno::Reference<css::accessibility::XAccessibleText> xText = 
getText(text);
+        if (!xText.is())
+            return false;
+
+        const sal_Int32 nCaretPos = xText->getCaretPosition();
+        return xText->setSelection(nCaretPos, nCaretPos);
     }
     catch(const uno::Exception&) {
         g_warning( "Exception in setSelection()" );
commit 3a2b113201fe2dede20286ad2cb3b45f266af976
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Thu Aug 14 10:00:40 2025 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Thu Aug 14 15:43:52 2025 +0200

    [API CHANGE] a11y: Drop XAccessibleTextSelection::addSelection param
    
    Neither the corresponding AT-SPI "AddSelection" Text
    iface method [1] used on Linux nor the IAccessibleText::addSelection
    method [2] of the IAccessible2 API used on Windows has
    any such parameter to specify what selection index the
    newly added selection should have.
    
    The only implementation of the method in
    SwAccessibleParagraph::addSelection was also simply
    ignoring it.
    
    Therefore, drop that unnecessary and unused parameter
    altogether.
    
    [1] 
https://gitlab.gnome.org/GNOME/at-spi2-core/-/blob/93fc318e12b6bfc84aa160ce539a97b59189d8c3/xml/Text.xml#L108-112
    [2] 
https://accessibility.linuxfoundation.org/a11yspecs/ia2/docs/html/interface_i_accessible_text.html#a646c0dff62feb76075e3890f059a86b6
    
    Change-Id: I42fcea029139255b7b327c6e375e37ffb9039bc6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189578
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins

diff --git a/offapi/com/sun/star/accessibility/XAccessibleTextSelection.idl 
b/offapi/com/sun/star/accessibility/XAccessibleTextSelection.idl
index 18f6ce999934..f9c84c054fa4 100644
--- a/offapi/com/sun/star/accessibility/XAccessibleTextSelection.idl
+++ b/offapi/com/sun/star/accessibility/XAccessibleTextSelection.idl
@@ -29,7 +29,7 @@ interface XAccessibleTextSelection : 
::com::sun::star::uno::XInterface
 
     long getSeletedPositionEnd ([in] long nSelectedPortionIndex) raises 
(::com::sun::star::lang::IndexOutOfBoundsException);
 
-    long addSelection( [in] long selectionIndex, [in]long startOffset, [in] 
long endOffset) raises (::com::sun::star::lang::IndexOutOfBoundsException);
+    long addSelection([in] long startOffset, [in] long endOffset) raises 
(::com::sun::star::lang::IndexOutOfBoundsException);
 
     boolean removeSelection( [in] long selectionIndex ) raises 
(::com::sun::star::lang::IndexOutOfBoundsException);
 };
diff --git a/sw/source/core/access/accpara.cxx 
b/sw/source/core/access/accpara.cxx
index b5f56036a88f..c54350dd3126 100644
--- a/sw/source/core/access/accpara.cxx
+++ b/sw/source/core/access/accpara.cxx
@@ -2880,7 +2880,7 @@ sal_Bool SAL_CALL SwAccessibleParagraph::removeSelection( 
sal_Int32 selectionInd
     return true;
 }
 
-sal_Int32 SAL_CALL SwAccessibleParagraph::addSelection( sal_Int32, sal_Int32 
startOffset, sal_Int32 endOffset)
+sal_Int32 SAL_CALL SwAccessibleParagraph::addSelection(sal_Int32 startOffset, 
sal_Int32 endOffset)
 {
     SolarMutexGuard aGuard;
 
diff --git a/sw/source/core/access/accpara.hxx 
b/sw/source/core/access/accpara.hxx
index 035504fbc1e3..268f2d2f01cd 100644
--- a/sw/source/core/access/accpara.hxx
+++ b/sw/source/core/access/accpara.hxx
@@ -328,7 +328,7 @@ public:
     virtual sal_Int32 SAL_CALL getSeletedPositionStart( sal_Int32 
nSelectedPortionIndex ) override;
     virtual sal_Int32 SAL_CALL getSeletedPositionEnd( sal_Int32 
nSelectedPortionIndex ) override;
     virtual sal_Bool SAL_CALL removeSelection( sal_Int32 selectionIndex ) 
override;
-    virtual sal_Int32 SAL_CALL  addSelection( sal_Int32 selectionIndex, 
sal_Int32 startOffset, sal_Int32 endOffset) override;
+    virtual sal_Int32 SAL_CALL addSelection(sal_Int32 startOffset, sal_Int32 
endOffset) override;
     // XAccessibleExtendedAttributes
     virtual OUString SAL_CALL getExtendedAttributes() override;
     sal_Int32 GetRealHeadingLevel();
diff --git a/winaccessibility/source/UAccCOM/AccTextBase.cxx 
b/winaccessibility/source/UAccCOM/AccTextBase.cxx
index 784e6cdd6430..0971b698c281 100644
--- a/winaccessibility/source/UAccCOM/AccTextBase.cxx
+++ b/winaccessibility/source/UAccCOM/AccTextBase.cxx
@@ -105,7 +105,7 @@ COM_DECLSPEC_NOTHROW STDMETHODIMP 
CAccTextBase::get_addSelection(long startOffse
 
     if( pRExtension.is() )
     {
-        pRExtension->addSelection(0, startOffset, endOffset);
+        pRExtension->addSelection(startOffset, endOffset);
         return S_OK;
     }
     else

Reply via email to