accessibility/inc/standard/vclxaccessibleedit.hxx | 3 + accessibility/source/helper/acc_factory.cxx | 7 ++ accessibility/source/standard/vclxaccessibleedit.cxx | 52 ++++++++++------- include/toolkit/awt/vclxwindows.hxx | 57 +++++++++++++++++++ include/toolkit/helper/accessiblefactory.hxx | 6 ++ toolkit/inc/awt/vclxwindows.hxx | 55 ------------------ toolkit/source/awt/vclxwindows.cxx | 5 + toolkit/source/helper/accessibilityclient.cxx | 5 + 8 files changed, 115 insertions(+), 75 deletions(-)
New commits: commit a766f7555c55c73e2dfd167e66f1bf32c75de6df Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Fri Sep 1 10:59:31 2023 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Fri Sep 1 16:13:31 2023 +0200 tdf#104833 a11y: Use VCLXAccessibleEdit for VCLXMultiLineEdit Instead of the generic `VCLXAccessibleComponent`, use `VCLXAccessibleEdit` as a11y class for `VCLXMultiLineEdit` (the component interface class for MultiLineEdit) as well, not just for `VCLXEdit`. With the preparatory changes from Change-Id I8218db61feb07605f6ea5309f26eebd38312458a tdf#104833 a11y: Don't use VCLXEdit in VCLXAccessibleEdit in place, it behaves as expected when interacting with the multi line edit from the sample dialog in attachment 189287 in tdf#104833 using Accerciser and the qt6 or gtk3 VCL plugin (and the text can also be edited when removing the readonly flag from the control) or the update dialog (which uses UNO controls, `UnoControlEditModel` for the panes that were not announced, s. extensions/source/update/check/updatehdl.cxx ). In particular, the a11y text interface is supported by the multi line edit on the a11y layer, which makes Orca with the gtk3 VCL plugin announce the text content when the control gets focused. NVDA on Windows still announces "Checking..." instead of using the actual text that would be retrievable via the IAccessibleText interface now. This is probably because "Checking..." is the (outdated) accessible name, as can be seen by interacting with the object in NVDA's Python console: >>> focus.name 'Checking...' >>> txt = focus.IAccessibleTextObject >>> txt.text(0, txt.nCharacters) 'LibreOfficeDev 24.2 is up to date.' For both, gtk3 and qt6, the a11y object does have the new text as a11y name as well, as can be verified in Accerciser: In [10]: acc.name Out[10]: 'LibreOfficeDev 24.2 is up to date.' In [11]: txt = acc.queryText() In [12]: txt.getTextAtOffset(0,3) Out[12]: ('LibreOfficeDev 24.2 is up to date.', 0, 34) Change-Id: Id80e191cdd5342b3215fdb9d2ad3847470366337 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156402 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/accessibility/source/helper/acc_factory.cxx b/accessibility/source/helper/acc_factory.cxx index fb0468fe6d65..4dcc63e4ab12 100644 --- a/accessibility/source/helper/acc_factory.cxx +++ b/accessibility/source/helper/acc_factory.cxx @@ -102,6 +102,8 @@ public: createAccessibleContext( VCLXScrollBar* _pXWindow ) override; virtual css::uno::Reference< css::accessibility::XAccessibleContext > createAccessibleContext( VCLXEdit* _pXWindow ) override; + virtual css::uno::Reference< css::accessibility::XAccessibleContext > + createAccessibleContext( VCLXMultiLineEdit* _pXWindow ) override; virtual css::uno::Reference< css::accessibility::XAccessibleContext > createAccessibleContext( VCLXComboBox* _pXWindow ) override; virtual css::uno::Reference< css::accessibility::XAccessibleContext > @@ -280,6 +282,11 @@ Reference< XAccessibleContext > AccessibleFactory::createAccessibleContext( VCLX return new VCLXAccessibleEdit( _pXWindow ); } +Reference< XAccessibleContext > AccessibleFactory::createAccessibleContext( VCLXMultiLineEdit* _pXWindow ) +{ + return new VCLXAccessibleEdit( _pXWindow ); +} + Reference< XAccessibleContext > AccessibleFactory::createAccessibleContext( VCLXComboBox* _pXWindow ) { bool bIsDropDownBox = false; diff --git a/include/toolkit/awt/vclxwindows.hxx b/include/toolkit/awt/vclxwindows.hxx index 3a86cdecdfef..b6d333374a3f 100644 --- a/include/toolkit/awt/vclxwindows.hxx +++ b/include/toolkit/awt/vclxwindows.hxx @@ -461,6 +461,9 @@ public: static void ImplGetPropertyIds( std::vector< sal_uInt16 > &aIds ); virtual void GetPropertyIds( std::vector< sal_uInt16 > &aIds ) override { return ImplGetPropertyIds( aIds ); } + +protected: + virtual css::uno::Reference<css::accessibility::XAccessibleContext> CreateAccessibleContext() override; }; // class VCLXSpinField diff --git a/include/toolkit/helper/accessiblefactory.hxx b/include/toolkit/helper/accessiblefactory.hxx index bd7ae90976d4..6c0532ce9edb 100644 --- a/include/toolkit/helper/accessiblefactory.hxx +++ b/include/toolkit/helper/accessiblefactory.hxx @@ -37,6 +37,7 @@ class VCLXFixedText; class VCLXScrollBar; class VCLXEdit; class VCLXComboBox; +class VCLXMultiLineEdit; class VCLXToolBox; class VCLXHeaderBar; class VCLXWindow; @@ -102,6 +103,11 @@ namespace toolkit virtual css::uno::Reference< css::accessibility::XAccessibleContext > createAccessibleContext( VCLXEdit* _pXWindow ) = 0; + /** creates an accessible context for a multiline edit window + */ + virtual css::uno::Reference< css::accessibility::XAccessibleContext > + createAccessibleContext( VCLXMultiLineEdit* _pXWindow ) = 0; + /** creates an accessible context for a combo box window */ virtual css::uno::Reference< css::accessibility::XAccessibleContext > diff --git a/toolkit/source/awt/vclxwindows.cxx b/toolkit/source/awt/vclxwindows.cxx index ef378f228895..8c6652ca8548 100644 --- a/toolkit/source/awt/vclxwindows.cxx +++ b/toolkit/source/awt/vclxwindows.cxx @@ -7869,4 +7869,9 @@ void VCLXMultiLineEdit::ImplGetPropertyIds( std::vector< sal_uInt16 > &rIds ) VCLXWindow::ImplGetPropertyIds( rIds, true ); } +css::uno::Reference<css::accessibility::XAccessibleContext> VCLXMultiLineEdit::CreateAccessibleContext() +{ + return getAccessibleFactory().createAccessibleContext(this); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/toolkit/source/helper/accessibilityclient.cxx b/toolkit/source/helper/accessibilityclient.cxx index 773bc9bfbd06..1926b004d15e 100644 --- a/toolkit/source/helper/accessibilityclient.cxx +++ b/toolkit/source/helper/accessibilityclient.cxx @@ -107,6 +107,11 @@ namespace toolkit { return nullptr; } + css::uno::Reference< css::accessibility::XAccessibleContext > + createAccessibleContext( VCLXMultiLineEdit* /*_pXWindow*/ ) override + { + return nullptr; + } css::uno::Reference< css::accessibility::XAccessibleContext > createAccessibleContext( VCLXComboBox* /*_pXWindow*/ ) override { commit 847df831b1c46a257fd371c6a193387cc9c06c4b Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Fri Sep 1 10:51:23 2023 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Fri Sep 1 16:13:25 2023 +0200 tdf#104833 Move VCLXMultiLineEdit to public toolkit header This is in preparation of having the a11y factory create a proper accessible context for it. Change-Id: If60efa84263c2d68eb57daa3aae4834a060529c3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156401 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/include/toolkit/awt/vclxwindows.hxx b/include/toolkit/awt/vclxwindows.hxx index bffddf6fd63e..3a86cdecdfef 100644 --- a/include/toolkit/awt/vclxwindows.hxx +++ b/include/toolkit/awt/vclxwindows.hxx @@ -21,6 +21,7 @@ #include <toolkit/dllapi.h> +#include <com/sun/star/awt/XTextArea.hpp> #include <com/sun/star/awt/XTextComponent.hpp> #include <com/sun/star/awt/XListBox.hpp> #include <com/sun/star/awt/XNumericField.hpp> @@ -41,6 +42,7 @@ #include <svl/numuno.hxx> #include <toolkit/awt/vclxwindow.hxx> #include <toolkit/helper/listenermultiplexer.hxx> +#include <tools/lineend.hxx> #include <vcl/image.hxx> @@ -408,6 +410,58 @@ public: virtual void GetPropertyIds( std::vector< sal_uInt16 > &aIds ) override { return ImplGetPropertyIds( aIds ); } }; +class VCLXMultiLineEdit final : public cppu::ImplInheritanceHelper< + VCLXWindow, + css::awt::XTextComponent, + css::awt::XTextArea, + css::awt::XTextLayoutConstrains> +{ +private: + TextListenerMultiplexer maTextListeners; + LineEnd meLineEndType; + + void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) override; + +public: + VCLXMultiLineEdit(); + virtual ~VCLXMultiLineEdit() override; + + // css::awt::XTextComponent + void SAL_CALL addTextListener( const css::uno::Reference< css::awt::XTextListener >& l ) override; + void SAL_CALL removeTextListener( const css::uno::Reference< css::awt::XTextListener >& l ) override; + void SAL_CALL setText( const OUString& aText ) override; + void SAL_CALL insertText( const css::awt::Selection& Sel, const OUString& Text ) override; + OUString SAL_CALL getText( ) override; + OUString SAL_CALL getSelectedText( ) override; + void SAL_CALL setSelection( const css::awt::Selection& aSelection ) override; + css::awt::Selection SAL_CALL getSelection( ) override; + sal_Bool SAL_CALL isEditable( ) override; + void SAL_CALL setEditable( sal_Bool bEditable ) override; + void SAL_CALL setMaxTextLen( sal_Int16 nLen ) override; + sal_Int16 SAL_CALL getMaxTextLen( ) override; + + //XTextArea + OUString SAL_CALL getTextLines( ) override; + + // css::awt::XLayoutConstrains + css::awt::Size SAL_CALL getMinimumSize( ) override; + css::awt::Size SAL_CALL getPreferredSize( ) override; + css::awt::Size SAL_CALL calcAdjustedSize( const css::awt::Size& aNewSize ) override; + + // css::awt::XTextLayoutConstrains + css::awt::Size SAL_CALL getMinimumSize( sal_Int16 nCols, sal_Int16 nLines ) override; + void SAL_CALL getColumnsAndLines( sal_Int16& nCols, sal_Int16& nLines ) override; + + // css::awt::XVclWindowPeer + void SAL_CALL setProperty( const OUString& PropertyName, const css::uno::Any& Value ) override; + css::uno::Any SAL_CALL getProperty( const OUString& PropertyName ) override; + + // css::awt::XWindow + void SAL_CALL setFocus( ) override; + + static void ImplGetPropertyIds( std::vector< sal_uInt16 > &aIds ); + virtual void GetPropertyIds( std::vector< sal_uInt16 > &aIds ) override { return ImplGetPropertyIds( aIds ); } +}; // class VCLXSpinField class VCLXSpinField : public cppu::ImplInheritanceHelper<VCLXEdit, css::awt::XSpinField> diff --git a/toolkit/inc/awt/vclxwindows.hxx b/toolkit/inc/awt/vclxwindows.hxx index ce96248494ea..22367ddcc08b 100644 --- a/toolkit/inc/awt/vclxwindows.hxx +++ b/toolkit/inc/awt/vclxwindows.hxx @@ -28,7 +28,6 @@ #include <com/sun/star/awt/XPatternField.hpp> #include <com/sun/star/awt/XProgressBar.hpp> #include <com/sun/star/awt/XSimpleTabController.hpp> -#include <com/sun/star/awt/XTextArea.hpp> #include <com/sun/star/awt/XTimeField.hpp> #include <com/sun/star/awt/grid/XGridControl.hpp> #include <com/sun/star/awt/grid/XGridRowSelection.hpp> @@ -40,7 +39,6 @@ #include <com/sun/star/util/Date.hpp> #include <cppuhelper/implbase.hxx> -#include <tools/lineend.hxx> #include <awt/vclxtopwindow.hxx> #include <toolkit/awt/vclxwindows.hxx> @@ -203,59 +201,6 @@ public: virtual void GetPropertyIds( std::vector< sal_uInt16 > &aIds ) override { return ImplGetPropertyIds( aIds ); } }; -class VCLXMultiLineEdit final : public cppu::ImplInheritanceHelper< - VCLXWindow, - css::awt::XTextComponent, - css::awt::XTextArea, - css::awt::XTextLayoutConstrains> -{ -private: - TextListenerMultiplexer maTextListeners; - LineEnd meLineEndType; - - void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) override; - -public: - VCLXMultiLineEdit(); - virtual ~VCLXMultiLineEdit() override; - - // css::awt::XTextComponent - void SAL_CALL addTextListener( const css::uno::Reference< css::awt::XTextListener >& l ) override; - void SAL_CALL removeTextListener( const css::uno::Reference< css::awt::XTextListener >& l ) override; - void SAL_CALL setText( const OUString& aText ) override; - void SAL_CALL insertText( const css::awt::Selection& Sel, const OUString& Text ) override; - OUString SAL_CALL getText( ) override; - OUString SAL_CALL getSelectedText( ) override; - void SAL_CALL setSelection( const css::awt::Selection& aSelection ) override; - css::awt::Selection SAL_CALL getSelection( ) override; - sal_Bool SAL_CALL isEditable( ) override; - void SAL_CALL setEditable( sal_Bool bEditable ) override; - void SAL_CALL setMaxTextLen( sal_Int16 nLen ) override; - sal_Int16 SAL_CALL getMaxTextLen( ) override; - - //XTextArea - OUString SAL_CALL getTextLines( ) override; - - // css::awt::XLayoutConstrains - css::awt::Size SAL_CALL getMinimumSize( ) override; - css::awt::Size SAL_CALL getPreferredSize( ) override; - css::awt::Size SAL_CALL calcAdjustedSize( const css::awt::Size& aNewSize ) override; - - // css::awt::XTextLayoutConstrains - css::awt::Size SAL_CALL getMinimumSize( sal_Int16 nCols, sal_Int16 nLines ) override; - void SAL_CALL getColumnsAndLines( sal_Int16& nCols, sal_Int16& nLines ) override; - - // css::awt::XVclWindowPeer - void SAL_CALL setProperty( const OUString& PropertyName, const css::uno::Any& Value ) override; - css::uno::Any SAL_CALL getProperty( const OUString& PropertyName ) override; - - // css::awt::XWindow - void SAL_CALL setFocus( ) override; - - static void ImplGetPropertyIds( std::vector< sal_uInt16 > &aIds ); - virtual void GetPropertyIds( std::vector< sal_uInt16 > &aIds ) override { return ImplGetPropertyIds( aIds ); } -}; - // class VCLXProgressBar class VCLXProgressBar final : public cppu::ImplInheritanceHelper<VCLXWindow, css::awt::XProgressBar> { commit 9a559df3fe2f623ac4eace30cdfeabb3a747c0e9 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Fri Sep 1 10:48:52 2023 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Fri Sep 1 16:13:19 2023 +0200 tdf#104833 a11y: Don't use VCLXEdit in VCLXAccessibleEdit Don't rely on the `VCLXWindow` of the control being a `VCLXEdit`, but use the `Edit` control directly, as is already done in other methods of this class. This is in preparation of using `VCLXAccessibleEdit` as the a11y class for `MultiLineEdit` as well, which derives from `Edit`, but its component interface class, `VCLXMultiLineEdit` does not derive from `VCLXEdit`. Already add reporting of the `AccessibleStateType::MULTI_LINE` state instead of `AccessibleStateType::SINGLE_LINE` to `VCLXAccessibleTextComponent::FillAccessibleStateSet` if the window type is `WindowType::MULTILINEEDIT`. Add a small helper function, `VCLXAccessibleEdit::isEditable` to use instead of `VCLXEdit::isEditable`, which does the same. Interacting with the single line edit from the sample dialog in attachment 189287 in tdf#104833 in Accerciser still behaves as expected (and the text can still be edited when removing the readonly flag from the control). Change-Id: I8218db61feb07605f6ea5309f26eebd38312458a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156400 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/accessibility/inc/standard/vclxaccessibleedit.hxx b/accessibility/inc/standard/vclxaccessibleedit.hxx index e10e8cecd6ff..b3b6a239b9d7 100644 --- a/accessibility/inc/standard/vclxaccessibleedit.hxx +++ b/accessibility/inc/standard/vclxaccessibleedit.hxx @@ -96,6 +96,9 @@ public: virtual sal_Bool SAL_CALL replaceText( sal_Int32 nStartIndex, sal_Int32 nEndIndex, const OUString& sReplacement ) override; virtual sal_Bool SAL_CALL setAttributes( sal_Int32 nStartIndex, sal_Int32 nEndIndex, const css::uno::Sequence< css::beans::PropertyValue >& aAttributeSet ) override; virtual sal_Bool SAL_CALL setText( const OUString& sText ) override; + +private: + bool isEditable(); }; diff --git a/accessibility/source/standard/vclxaccessibleedit.cxx b/accessibility/source/standard/vclxaccessibleedit.cxx index 96a8d6986cf8..81a1a73c5cae 100644 --- a/accessibility/source/standard/vclxaccessibleedit.cxx +++ b/accessibility/source/standard/vclxaccessibleedit.cxx @@ -108,12 +108,17 @@ void VCLXAccessibleEdit::FillAccessibleStateSet( sal_Int64& rStateSet ) { VCLXAccessibleTextComponent::FillAccessibleStateSet( rStateSet ); - VCLXEdit* pVCLXEdit = static_cast< VCLXEdit* >( GetVCLXWindow() ); - if ( pVCLXEdit ) + VCLXWindow* pVCLXWindow = GetVCLXWindow(); + if (pVCLXWindow) { rStateSet |= AccessibleStateType::FOCUSABLE; - rStateSet |= AccessibleStateType::SINGLE_LINE; - if ( pVCLXEdit->isEditable() ) + + if (GetWindow() && GetWindow()->GetType() == WindowType::MULTILINEEDIT) + rStateSet |= AccessibleStateType::MULTI_LINE; + else + rStateSet |= AccessibleStateType::SINGLE_LINE; + + if (isEditable()) rStateSet |= AccessibleStateType::EDITABLE; } } @@ -148,13 +153,13 @@ OUString VCLXAccessibleEdit::implGetText() void VCLXAccessibleEdit::implGetSelection( sal_Int32& nStartIndex, sal_Int32& nEndIndex ) { - awt::Selection aSelection; - VCLXEdit* pVCLXEdit = static_cast< VCLXEdit* >( GetVCLXWindow() ); - if ( pVCLXEdit ) - aSelection = pVCLXEdit->getSelection(); + Selection aSelection; + VclPtr<Edit> pEdit = GetAs<Edit>(); + if (pEdit) + aSelection = pEdit->GetSelection(); - nStartIndex = aSelection.Min; - nEndIndex = aSelection.Max; + nStartIndex = aSelection.Min(); + nEndIndex = aSelection.Max(); } @@ -415,11 +420,10 @@ sal_Bool VCLXAccessibleEdit::setSelection( sal_Int32 nStartIndex, sal_Int32 nEnd if ( !implIsValidRange( nStartIndex, nEndIndex, sText.getLength() ) ) throw IndexOutOfBoundsException(); - VCLXEdit* pVCLXEdit = static_cast< VCLXEdit* >( GetVCLXWindow() ); VclPtr< Edit > pEdit = GetAs< Edit >(); - if ( pVCLXEdit && pEdit && pEdit->IsEnabled() ) + if (pEdit && pEdit->IsEnabled()) { - pVCLXEdit->setSelection( awt::Selection( nStartIndex, nEndIndex ) ); + pEdit->SetSelection(Selection(nStartIndex, nEndIndex)); bReturn = true; } @@ -551,10 +555,12 @@ sal_Bool VCLXAccessibleEdit::replaceText( sal_Int32 nStartIndex, sal_Int32 nEndI sal_Int32 nMinIndex = std::min( nStartIndex, nEndIndex ); sal_Int32 nMaxIndex = std::max( nStartIndex, nEndIndex ); - VCLXEdit* pVCLXEdit = static_cast< VCLXEdit* >( GetVCLXWindow() ); - if ( pVCLXEdit && pVCLXEdit->isEditable() ) + + if (isEditable()) { - pVCLXEdit->setText( sText.replaceAt( nMinIndex, nMaxIndex - nMinIndex, sReplacement ) ); + VclPtr<Edit> pEdit = GetAs<Edit>(); + assert(pEdit); + pEdit->SetText(sText.replaceAt(nMinIndex, nMaxIndex - nMinIndex, sReplacement)); sal_Int32 nIndex = nMinIndex + sReplacement.getLength(); setSelection( nIndex, nIndex ); bReturn = true; @@ -581,17 +587,23 @@ sal_Bool VCLXAccessibleEdit::setText( const OUString& sText ) bool bReturn = false; - VCLXEdit* pVCLXEdit = static_cast< VCLXEdit* >( GetVCLXWindow() ); - if ( pVCLXEdit && pVCLXEdit->isEditable() ) + if (isEditable()) { - pVCLXEdit->setText( sText ); + VclPtr<Edit> pEdit = GetAs<Edit>(); + assert(pEdit); + pEdit->SetText(sText); sal_Int32 nSize = sText.getLength(); - pVCLXEdit->setSelection( awt::Selection( nSize, nSize ) ); + pEdit->SetSelection(Selection(nSize, nSize) ); bReturn = true; } return bReturn; } +bool VCLXAccessibleEdit::isEditable() +{ + VclPtr<Edit> pEdit = GetAs<Edit>(); + return pEdit && !pEdit->IsReadOnly() && pEdit->IsEnabled(); +} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */