include/LibreOfficeKit/LibreOfficeKitEnums.h | 2 sfx2/source/view/viewsh.cxx | 74 ++++++++++++++++++++++++--- sw/source/core/access/accpara.cxx | 14 +++++ sw/source/core/unocore/unomapproperties.hxx | 1 4 files changed, 85 insertions(+), 6 deletions(-)
New commits: commit 038903d2e066de9525a3baffdd232484ef44ff51 Author: Marco Cecchetti <marco.cecche...@collabora.com> AuthorDate: Sun Sep 3 18:47:30 2023 +0200 Commit: Marco Cecchetti <marco.cecche...@collabora.com> CommitDate: Mon Sep 11 14:41:04 2023 +0200 lok: a11y: send list item prefix length to client Implemented getListPrefixSize function which relies on UNO_NAME_NUMBERING_LEVEL, UNO_NAME_NUMBERING character attributes. The former provides the list item level, the latter is a boolean that says if a prefix (bullet/number) is present or not for the list item. It has been needed to modify SwAccessibleParagraph::_getSupplementalAttributesImpl so that it returns such properties for list item only and not for simple paragraph too. In fact for a simple paragraph the default value for the level property was returned which is 0 exactly the same value for top list item. Change-Id: Ia651af4d4b2372eed42c90b0752e16fd47a4fdec Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156816 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Gökay ŞATIR <gokaysa...@collabora.com> diff --git a/include/LibreOfficeKit/LibreOfficeKitEnums.h b/include/LibreOfficeKit/LibreOfficeKitEnums.h index b5c5d5c44d97..ce093ff7a276 100644 --- a/include/LibreOfficeKit/LibreOfficeKitEnums.h +++ b/include/LibreOfficeKit/LibreOfficeKitEnums.h @@ -932,9 +932,11 @@ typedef enum * "position": N * "start": N1 * "end": N2 + * "listPrefixLength": L * } * where N is the position of the text cursor inside the focused paragraph, * and [N1,N2] is the range of the text selection inside the focused paragraph. + * In case the paragraph is a list item, L is the length of the bullet/number prefix. */ LOK_CALLBACK_A11Y_FOCUS_CHANGED = 62, diff --git a/sfx2/source/view/viewsh.cxx b/sfx2/source/view/viewsh.cxx index 6e2d392e3846..5c8d2bc6cf65 100644 --- a/sfx2/source/view/viewsh.cxx +++ b/sfx2/source/view/viewsh.cxx @@ -67,6 +67,7 @@ #include <com/sun/star/awt/FontSlant.hpp> #include <comphelper/diagnose_ex.hxx> +#include <editeng/unoprnms.hxx> #include <tools/urlobj.hxx> #include <unotools/tempfile.hxx> #include <svtools/soerr.hxx> @@ -405,6 +406,42 @@ void aboutEvent(std::string msg, const accessibility::AccessibleEventObject& aEv } } +sal_Int32 getListPrefixSize(const uno::Reference<css::accessibility::XAccessibleText>& xAccText) +{ + if (!xAccText.is()) + return 0; + + OUString sText = xAccText->getText(); + sal_Int32 nLength = sText.getLength(); + if (nLength <= 0) + return 0; + + css::uno::Sequence< css::beans::PropertyValue > aRunAttributeList; + css::uno::Sequence< OUString > aRequestedAttributes = {UNO_NAME_NUMBERING_LEVEL, UNO_NAME_NUMBERING}; + aRunAttributeList = xAccText->getCharacterAttributes(0, aRequestedAttributes); + + sal_Int16 nLevel = -1; + bool bIsCounted = false; + for (const auto& attribute: aRunAttributeList) + { + if (attribute.Name.isEmpty()) + continue; + if (attribute.Name == UNO_NAME_NUMBERING_LEVEL) + attribute.Value >>= nLevel; + else if (attribute.Name == UNO_NAME_NUMBERING) + attribute.Value >>= bIsCounted; + } + if (nLevel < 0 || !bIsCounted) + return 0; + + css::accessibility::TextSegment aTextSegment = + xAccText->getTextAtIndex(0, css::accessibility::AccessibleTextType::ATTRIBUTE_RUN); + + SAL_INFO("lok.a11y", "getListPrefixSize: prefix: " << aTextSegment.SegmentText << ", level: " << nLevel); + + return aTextSegment.SegmentEnd; +} + void aboutTextFormatting(std::string msg, const uno::Reference<css::accessibility::XAccessibleText>& xAccText) { if (!xAccText.is()) @@ -479,6 +516,22 @@ void aboutTextFormatting(std::string msg, const uno::Reference<css::accessibilit attribute.Value >>= nValue; sValue = OUString::number(nValue); } + else if (attribute.Name == UNO_NAME_NUMBERING_LEVEL) + { + sal_Int16 nValue(-1); + attribute.Value >>= nValue; + sValue = OUString::number(nValue); + } + else if (attribute.Name == UNO_NAME_NUMBERING) + { + bool bValue(false); + attribute.Value >>= bValue; + sValue = OUString::boolean(bValue); + } + else if (attribute.Name == UNO_NAME_NUMBERING_RULES) + { + attribute.Value >>= sValue; + } if (!sValue.isEmpty()) { @@ -498,12 +551,14 @@ void aboutTextFormatting(std::string msg, const uno::Reference<css::accessibilit } void aboutParagraph(std::string msg, const OUString& rsParagraphContent, sal_Int32 nCaretPosition, - sal_Int32 nSelectionStart, sal_Int32 nSelectionEnd, bool force = false) + sal_Int32 nSelectionStart, sal_Int32 nSelectionEnd, sal_Int32 nlistPrefixLength, + bool force = false) { SAL_INFO("lok.a11y", msg << ": " << "\n text content: \"" << rsParagraphContent << "\"" << "\n caret pos: " << nCaretPosition << "\n selection: start: " << nSelectionStart << ", end: " << nSelectionEnd + << "\n list prefix length: " << nlistPrefixLength << "\n force: " << force ); } @@ -518,7 +573,8 @@ void aboutParagraph(std::string msg, const uno::Reference<css::accessibility::XA sal_Int32 nCaretPosition = xAccText->getCaretPosition(); sal_Int32 nSelectionStart = xAccText->getSelectionStart(); sal_Int32 nSelectionEnd = xAccText->getSelectionEnd(); - aboutParagraph(msg, sText, nCaretPosition, nSelectionStart, nSelectionEnd, force); + sal_Int32 nlistPrefixLength = getListPrefixSize(xAccText); + aboutParagraph(msg, sText, nCaretPosition, nSelectionStart, nSelectionEnd, nlistPrefixLength, force); } void aboutFocusedCellChanged(sal_Int32 nOutCount, const std::vector<TableSizeType>& aInList, @@ -554,6 +610,7 @@ class LOKDocumentFocusListener : sal_Int32 m_nCaretPosition; sal_Int32 m_nSelectionStart; sal_Int32 m_nSelectionEnd; + sal_Int32 m_nListPrefixLength; uno::Reference<accessibility::XAccessibleTable> m_xLastTable; OUString m_sSelectedText; bool m_bIsEditingCell; @@ -618,7 +675,6 @@ public: void notifyFocusedParagraphChanged(bool force = false); void notifyCaretChanged(); void notifyTextSelectionChanged(); - void notifyTablePositionChanged(); void notifyFocusedCellChanged(sal_Int32 nOutCount, const std::vector<TableSizeType>& aInList, sal_Int32 nRow, sal_Int32 nCol, sal_Int32 nRowSpan, sal_Int32 nColSpan); OUString getFocusedParagraph() const; @@ -638,6 +694,7 @@ LOKDocumentFocusListener::LOKDocumentFocusListener(const SfxViewShell* pViewShel , m_nCaretPosition(0) , m_nSelectionStart(0) , m_nSelectionEnd(0) + , m_nListPrefixLength(0) , m_bIsEditingCell(false) { } @@ -649,6 +706,8 @@ void LOKDocumentFocusListener::paragraphPropertiesToTree(boost::property_tree::p aPayloadTree.put("position", m_nCaretPosition); aPayloadTree.put("start", bLeftToRight ? m_nSelectionStart : m_nSelectionEnd); aPayloadTree.put("end", bLeftToRight ? m_nSelectionEnd : m_nSelectionStart); + if (m_nListPrefixLength > 0) + aPayloadTree.put("listPrefixLength", m_nListPrefixLength); if (force) aPayloadTree.put("force", 1); } @@ -666,7 +725,8 @@ OUString LOKDocumentFocusListener::getFocusedParagraph() const { aboutView("LOKDocumentFocusListener::getFocusedParagraph", this, m_pViewShell); aboutParagraph("LOKDocumentFocusListener::getFocusedParagraph", - m_sFocusedParagraph, m_nCaretPosition, m_nSelectionStart, m_nSelectionEnd); + m_sFocusedParagraph, m_nCaretPosition, + m_nSelectionStart, m_nSelectionEnd, m_nListPrefixLength); std::string aPayload; paragraphPropertiesToJson(aPayload); @@ -699,7 +759,7 @@ int LOKDocumentFocusListener::getCaretPosition() const // is skipped until the composition is over. // On the contrary the composition would be aborted, making dictation not possible. // Anyway when the text change has been performed by another view we are in due -// to upadate the clipboard content even if the user is in the middle of a composition. +// to update the clipboard content even if the user is in the middle of a composition. void LOKDocumentFocusListener::notifyFocusedParagraphChanged(bool force) { aboutView("LOKDocumentFocusListener::notifyFocusedParagraphChanged", this, m_pViewShell); @@ -708,7 +768,8 @@ void LOKDocumentFocusListener::notifyFocusedParagraphChanged(bool force) if (m_pViewShell) { aboutParagraph("LOKDocumentFocusListener::notifyFocusedParagraphChanged", - m_sFocusedParagraph, m_nCaretPosition, m_nSelectionStart, m_nSelectionEnd, force); + m_sFocusedParagraph, m_nCaretPosition, + m_nSelectionStart, m_nSelectionEnd, m_nListPrefixLength, force); m_pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_A11Y_FOCUS_CHANGED, aPayload.c_str()); } @@ -824,6 +885,7 @@ bool LOKDocumentFocusListener::updateParagraphInfo(const uno::Reference<css::acc m_nCaretPosition = nCaretPosition; m_nSelectionStart = xAccText->getSelectionStart(); m_nSelectionEnd = xAccText->getSelectionEnd(); + m_nListPrefixLength = getListPrefixSize(xAccText); // In case only caret position or text selection are different we can rely on specific events. if (m_sFocusedParagraph != sText) diff --git a/sw/source/core/access/accpara.cxx b/sw/source/core/access/accpara.cxx index 8761e379b1e7..7ca30145b1d6 100644 --- a/sw/source/core/access/accpara.cxx +++ b/sw/source/core/access/accpara.cxx @@ -910,6 +910,7 @@ static uno::Sequence< OUString > const & getSupplementalAttributeNames() { // sorted list of strings UNO_NAME_NUMBERING_LEVEL, + UNO_NAME_NUMBERING, UNO_NAME_NUMBERING_RULES, UNO_NAME_PARA_ADJUST, UNO_NAME_PARA_BOTTOM_MARGIN, @@ -1357,6 +1358,9 @@ uno::Sequence<PropertyValue> SwAccessibleParagraph::getCharacterAttributes( tAccParaPropValMap aRunAttrSeq; _getRunAttributesImpl( nIndex, aNames, aRunAttrSeq ); + // this allows to request one or more supplemental attributes, only + bSupplementalMode = bSupplementalMode || aDefAttrSeq.empty() || aRunAttrSeq.empty(); + // merge default and run attributes std::vector< PropertyValue > aValues( aDefAttrSeq.size() ); sal_Int32 i = 0; @@ -1761,6 +1765,7 @@ void SwAccessibleParagraph::_getSupplementalAttributesImpl( if ( pTextNode->HasBullet() || pTextNode->HasNumber() ) { aSet.Put( pTextNode->GetAttr(RES_PARATR_LIST_LEVEL) ); + aSet.Put( pTextNode->GetAttr(RES_PARATR_LIST_ISCOUNTED) ); } aSet.Put( pTextNode->SwContentNode::GetAttr(RES_UL_SPACE) ); aSet.Put( pTextNode->SwContentNode::GetAttr(RES_LR_SPACE) ); @@ -1772,6 +1777,15 @@ void SwAccessibleParagraph::_getSupplementalAttributesImpl( aSwMapProvider.GetPropertyMapEntries( PROPERTY_MAP_ACCESSIBILITY_TEXT_ATTRIBUTE ) ); for (const auto & rEntry : pPropMap) { + // For a paragraph, list level property is not set but when queried the returned default + // value is 0, exactly the same value of top level list item; that prevents using + // list level property for discerning simple paragraph from list item; + // the following check allows not to return the list level property at all + // when we are dealing with a simple paragraph + if ((rEntry.nWID == RES_PARATR_LIST_LEVEL || rEntry.nWID == RES_PARATR_LIST_ISCOUNTED) && + !aSet.HasItem( rEntry.nWID )) + continue; + const SfxPoolItem* pItem = aSet.GetItem( rEntry.nWID ); if ( pItem ) { diff --git a/sw/source/core/unocore/unomapproperties.hxx b/sw/source/core/unocore/unomapproperties.hxx index 2dd06a11ee9c..1ba7ebb5fe3d 100644 --- a/sw/source/core/unocore/unomapproperties.hxx +++ b/sw/source/core/unocore/unomapproperties.hxx @@ -532,6 +532,7 @@ { UNO_NAME_CHAR_UNDERLINE_COMPLEX_COLOR, RES_CHRATR_UNDERLINE, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_TL_COMPLEX_COLOR}, \ { UNO_NAME_CHAR_WEIGHT, RES_CHRATR_WEIGHT , cppu::UnoType<float>::get(), PropertyAttribute::MAYBEVOID, MID_WEIGHT}, \ { UNO_NAME_NUMBERING_LEVEL, RES_PARATR_LIST_LEVEL,cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0}, \ + { UNO_NAME_NUMBERING, RES_PARATR_LIST_ISCOUNTED, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0}, \ { UNO_NAME_CHAR_UNDERLINE, RES_CHRATR_UNDERLINE , cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_TL_STYLE}, \ { UNO_NAME_NUMBERING_RULES, RES_PARATR_NUMRULE,cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, CONVERT_TWIPS}, \ { UNO_NAME_PARA_ADJUST, RES_PARATR_ADJUST, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_PARA_ADJUST}, \