3a45029a6b
Was this way since commitedf11d28fa
Author Vladimir Glazounov <vg@openoffice.org> Date Thu Apr 24 16:27:52 2003 +0000 INTEGRATION: CWS uaa02 (1.3.44); FILE MERGED Surfaced after commitb1148c31ed
Author Noel Grandin <noel.grandin@collabora.co.uk> Date Wed Apr 27 16:47:53 2022 +0200 use more string_view in comphelper where the pointers were changed to iterators, which are checked in debug builds, failing an assertion. Change-Id: I87fce562aef8f50b94fb52ad6c2a79d2e84d6424 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133934 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
800 lines
27 KiB
C++
800 lines
27 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-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/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <comphelper/accessibletexthelper.hxx>
|
|
#include <com/sun/star/accessibility/AccessibleTextType.hpp>
|
|
#include <com/sun/star/i18n/BreakIterator.hpp>
|
|
#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
|
|
#include <com/sun/star/i18n/CharacterClassification.hpp>
|
|
#include <com/sun/star/i18n/WordType.hpp>
|
|
#include <com/sun/star/i18n/KCharacterType.hpp>
|
|
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <com/sun/star/accessibility/TextSegment.hpp>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
namespace comphelper
|
|
{
|
|
|
|
|
|
using namespace ::com::sun::star;
|
|
using namespace ::com::sun::star::uno;
|
|
using namespace ::com::sun::star::lang;
|
|
using namespace ::com::sun::star::beans;
|
|
using namespace ::com::sun::star::accessibility;
|
|
|
|
|
|
// OCommonAccessibleText
|
|
|
|
|
|
OCommonAccessibleText::OCommonAccessibleText()
|
|
{
|
|
}
|
|
|
|
|
|
OCommonAccessibleText::~OCommonAccessibleText()
|
|
{
|
|
}
|
|
|
|
|
|
Reference < i18n::XBreakIterator > const & OCommonAccessibleText::implGetBreakIterator()
|
|
{
|
|
if ( !m_xBreakIter.is() )
|
|
{
|
|
Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
|
|
m_xBreakIter = i18n::BreakIterator::create(xContext);
|
|
}
|
|
|
|
return m_xBreakIter;
|
|
}
|
|
|
|
|
|
Reference < i18n::XCharacterClassification > const & OCommonAccessibleText::implGetCharacterClassification()
|
|
{
|
|
if ( !m_xCharClass.is() )
|
|
{
|
|
m_xCharClass = i18n::CharacterClassification::create( ::comphelper::getProcessComponentContext() );
|
|
}
|
|
|
|
return m_xCharClass;
|
|
}
|
|
|
|
|
|
bool OCommonAccessibleText::implIsValidBoundary( i18n::Boundary const & rBoundary, sal_Int32 nLength )
|
|
{
|
|
return ( rBoundary.startPos >= 0 ) && ( rBoundary.startPos < nLength ) && ( rBoundary.endPos >= 0 ) && ( rBoundary.endPos <= nLength );
|
|
}
|
|
|
|
|
|
bool OCommonAccessibleText::implIsValidIndex( sal_Int32 nIndex, sal_Int32 nLength )
|
|
{
|
|
return ( nIndex >= 0 ) && ( nIndex < nLength );
|
|
}
|
|
|
|
|
|
bool OCommonAccessibleText::implIsValidRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex, sal_Int32 nLength )
|
|
{
|
|
return ( nStartIndex >= 0 ) && ( nStartIndex <= nLength ) && ( nEndIndex >= 0 ) && ( nEndIndex <= nLength );
|
|
}
|
|
|
|
|
|
void OCommonAccessibleText::implGetGlyphBoundary( const OUString& rText, i18n::Boundary& rBoundary, sal_Int32 nIndex )
|
|
{
|
|
if ( implIsValidIndex( nIndex, rText.getLength() ) )
|
|
{
|
|
Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator();
|
|
if ( xBreakIter.is() )
|
|
{
|
|
sal_Int32 nCount = 1;
|
|
sal_Int32 nDone;
|
|
sal_Int32 nStartIndex = xBreakIter->previousCharacters( rText, nIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone );
|
|
if ( nDone != 0 )
|
|
nStartIndex = xBreakIter->nextCharacters( rText, nStartIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone );
|
|
sal_Int32 nEndIndex = xBreakIter->nextCharacters( rText, nStartIndex, implGetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nDone );
|
|
if ( nDone != 0 )
|
|
{
|
|
rBoundary.startPos = nStartIndex;
|
|
rBoundary.endPos = nEndIndex;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rBoundary.startPos = nIndex;
|
|
rBoundary.endPos = nIndex;
|
|
}
|
|
}
|
|
|
|
|
|
bool OCommonAccessibleText::implGetWordBoundary( const OUString& rText, i18n::Boundary& rBoundary, sal_Int32 nIndex )
|
|
{
|
|
bool bWord = false;
|
|
|
|
if ( implIsValidIndex( nIndex, rText.getLength() ) )
|
|
{
|
|
Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator();
|
|
if ( xBreakIter.is() )
|
|
{
|
|
rBoundary = xBreakIter->getWordBoundary( rText, nIndex, implGetLocale(), i18n::WordType::ANY_WORD, true );
|
|
|
|
// it's a word, if the first character is an alpha-numeric character
|
|
Reference< i18n::XCharacterClassification > xCharClass = implGetCharacterClassification();
|
|
if ( xCharClass.is() )
|
|
{
|
|
sal_Int32 nType = xCharClass->getCharacterType( rText, rBoundary.startPos, implGetLocale() );
|
|
if ( ( nType & ( i18n::KCharacterType::LETTER | i18n::KCharacterType::DIGIT ) ) != 0 )
|
|
bWord = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rBoundary.startPos = nIndex;
|
|
rBoundary.endPos = nIndex;
|
|
}
|
|
|
|
return bWord;
|
|
}
|
|
|
|
|
|
void OCommonAccessibleText::implGetSentenceBoundary( const OUString& rText, i18n::Boundary& rBoundary, sal_Int32 nIndex )
|
|
{
|
|
if ( implIsValidIndex( nIndex, rText.getLength() ) )
|
|
{
|
|
Locale aLocale = implGetLocale();
|
|
Reference < i18n::XBreakIterator > xBreakIter = implGetBreakIterator();
|
|
if ( xBreakIter.is() )
|
|
{
|
|
rBoundary.endPos = xBreakIter->endOfSentence( rText, nIndex, aLocale );
|
|
rBoundary.startPos = xBreakIter->beginOfSentence( rText, rBoundary.endPos, aLocale );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rBoundary.startPos = nIndex;
|
|
rBoundary.endPos = nIndex;
|
|
}
|
|
}
|
|
|
|
|
|
void OCommonAccessibleText::implGetParagraphBoundary( const OUString& rText, i18n::Boundary& rBoundary, sal_Int32 nIndex )
|
|
{
|
|
if ( implIsValidIndex( nIndex, rText.getLength() ) )
|
|
{
|
|
rBoundary.startPos = 0;
|
|
rBoundary.endPos = rText.getLength();
|
|
|
|
sal_Int32 nFound = rText.lastIndexOf( '\n', nIndex );
|
|
if ( nFound != -1 )
|
|
rBoundary.startPos = nFound + 1;
|
|
|
|
nFound = rText.indexOf( '\n', nIndex );
|
|
if ( nFound != -1 )
|
|
rBoundary.endPos = nFound + 1;
|
|
}
|
|
else
|
|
{
|
|
rBoundary.startPos = nIndex;
|
|
rBoundary.endPos = nIndex;
|
|
}
|
|
}
|
|
|
|
|
|
void OCommonAccessibleText::implGetLineBoundary( const OUString& rText, i18n::Boundary& rBoundary, sal_Int32 nIndex )
|
|
{
|
|
sal_Int32 nLength = rText.getLength();
|
|
|
|
if ( implIsValidIndex( nIndex, nLength ) || nIndex == nLength )
|
|
{
|
|
rBoundary.startPos = 0;
|
|
rBoundary.endPos = nLength;
|
|
}
|
|
else
|
|
{
|
|
rBoundary.startPos = nIndex;
|
|
rBoundary.endPos = nIndex;
|
|
}
|
|
}
|
|
|
|
|
|
sal_Unicode OCommonAccessibleText::implGetCharacter( std::u16string_view rText, sal_Int32 nIndex )
|
|
{
|
|
if ( !implIsValidIndex( nIndex, rText.size() ) )
|
|
throw IndexOutOfBoundsException();
|
|
|
|
return rText[nIndex];
|
|
}
|
|
|
|
OUString OCommonAccessibleText::getSelectedText()
|
|
{
|
|
OUString sText;
|
|
sal_Int32 nStartIndex;
|
|
sal_Int32 nEndIndex;
|
|
|
|
implGetSelection( nStartIndex, nEndIndex );
|
|
|
|
try
|
|
{
|
|
sText = implGetTextRange( implGetText(), nStartIndex, nEndIndex );
|
|
}
|
|
catch ( IndexOutOfBoundsException& )
|
|
{
|
|
}
|
|
|
|
return sText;
|
|
}
|
|
|
|
|
|
sal_Int32 OCommonAccessibleText::getSelectionStart()
|
|
{
|
|
sal_Int32 nStartIndex;
|
|
sal_Int32 nEndIndex;
|
|
|
|
implGetSelection( nStartIndex, nEndIndex );
|
|
|
|
return nStartIndex;
|
|
}
|
|
|
|
|
|
sal_Int32 OCommonAccessibleText::getSelectionEnd()
|
|
{
|
|
sal_Int32 nStartIndex;
|
|
sal_Int32 nEndIndex;
|
|
|
|
implGetSelection( nStartIndex, nEndIndex );
|
|
|
|
return nEndIndex;
|
|
}
|
|
|
|
|
|
OUString OCommonAccessibleText::implGetTextRange( std::u16string_view rText, sal_Int32 nStartIndex, sal_Int32 nEndIndex )
|
|
{
|
|
|
|
if ( !implIsValidRange( nStartIndex, nEndIndex, rText.size() ) )
|
|
throw IndexOutOfBoundsException();
|
|
|
|
sal_Int32 nMinIndex = std::min( nStartIndex, nEndIndex );
|
|
sal_Int32 nMaxIndex = std::max( nStartIndex, nEndIndex );
|
|
|
|
return OUString(rText.substr( nMinIndex, nMaxIndex - nMinIndex ));
|
|
}
|
|
|
|
TextSegment OCommonAccessibleText::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType )
|
|
{
|
|
OUString sText( implGetText() );
|
|
sal_Int32 nLength = sText.getLength();
|
|
|
|
if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength )
|
|
throw IndexOutOfBoundsException();
|
|
|
|
i18n::Boundary aBoundary;
|
|
TextSegment aResult;
|
|
aResult.SegmentStart = -1;
|
|
aResult.SegmentEnd = -1;
|
|
|
|
switch ( aTextType )
|
|
{
|
|
case AccessibleTextType::CHARACTER:
|
|
{
|
|
if ( implIsValidIndex( nIndex, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( nIndex, 1 );
|
|
aResult.SegmentStart = nIndex;
|
|
aResult.SegmentEnd = nIndex+1;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::GLYPH:
|
|
{
|
|
// get glyph at index
|
|
implGetGlyphBoundary( sText, aBoundary, nIndex );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::WORD:
|
|
{
|
|
// get word at index
|
|
bool bWord = implGetWordBoundary( sText, aBoundary, nIndex );
|
|
if ( bWord && implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::SENTENCE:
|
|
{
|
|
// get sentence at index
|
|
implGetSentenceBoundary( sText, aBoundary, nIndex );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::PARAGRAPH:
|
|
{
|
|
// get paragraph at index
|
|
implGetParagraphBoundary( sText, aBoundary, nIndex );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::LINE:
|
|
{
|
|
// get line at index
|
|
implGetLineBoundary( sText, aBoundary, nIndex );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::ATTRIBUTE_RUN:
|
|
{
|
|
// TODO: implGetAttributeRunBoundary() (incompatible!)
|
|
|
|
aResult.SegmentText = sText;
|
|
aResult.SegmentStart = 0;
|
|
aResult.SegmentEnd = nLength;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
// unknown text type
|
|
}
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
|
|
TextSegment OCommonAccessibleText::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType )
|
|
{
|
|
OUString sText( implGetText() );
|
|
sal_Int32 nLength = sText.getLength();
|
|
|
|
if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength )
|
|
throw IndexOutOfBoundsException();
|
|
|
|
i18n::Boundary aBoundary;
|
|
TextSegment aResult;
|
|
aResult.SegmentStart = -1;
|
|
aResult.SegmentEnd = -1;
|
|
|
|
switch ( aTextType )
|
|
{
|
|
case AccessibleTextType::CHARACTER:
|
|
{
|
|
if ( implIsValidIndex( nIndex - 1, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( nIndex - 1, 1 );
|
|
aResult.SegmentStart = nIndex-1;
|
|
aResult.SegmentEnd = nIndex;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::GLYPH:
|
|
{
|
|
// get glyph at index
|
|
implGetGlyphBoundary( sText, aBoundary, nIndex );
|
|
// get previous glyph
|
|
if ( aBoundary.startPos > 0 )
|
|
{
|
|
implGetGlyphBoundary( sText, aBoundary, aBoundary.startPos - 1 );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::WORD:
|
|
{
|
|
// get word at index
|
|
implGetWordBoundary( sText, aBoundary, nIndex );
|
|
// get previous word
|
|
bool bWord = false;
|
|
while ( !bWord && aBoundary.startPos > 0 )
|
|
bWord = implGetWordBoundary( sText, aBoundary, aBoundary.startPos - 1 );
|
|
if ( bWord && implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::SENTENCE:
|
|
{
|
|
// get sentence at index
|
|
implGetSentenceBoundary( sText, aBoundary, nIndex );
|
|
// get previous sentence
|
|
if ( aBoundary.startPos > 0 )
|
|
{
|
|
implGetSentenceBoundary( sText, aBoundary, aBoundary.startPos - 1 );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::PARAGRAPH:
|
|
{
|
|
// get paragraph at index
|
|
implGetParagraphBoundary( sText, aBoundary, nIndex );
|
|
// get previous paragraph
|
|
if ( aBoundary.startPos > 0 )
|
|
{
|
|
implGetParagraphBoundary( sText, aBoundary, aBoundary.startPos - 1 );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::LINE:
|
|
{
|
|
// get line at index
|
|
implGetLineBoundary( sText, aBoundary, nIndex );
|
|
// get previous line
|
|
if ( aBoundary.startPos > 0 )
|
|
{
|
|
implGetLineBoundary( sText, aBoundary, aBoundary.startPos - 1 );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::ATTRIBUTE_RUN:
|
|
{
|
|
// TODO: implGetAttributeRunBoundary() (incompatible!)
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
// unknown text type
|
|
}
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
|
|
TextSegment OCommonAccessibleText::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType )
|
|
{
|
|
OUString sText( implGetText() );
|
|
sal_Int32 nLength = sText.getLength();
|
|
|
|
if ( !implIsValidIndex( nIndex, nLength ) && nIndex != nLength )
|
|
throw IndexOutOfBoundsException();
|
|
|
|
i18n::Boundary aBoundary;
|
|
TextSegment aResult;
|
|
aResult.SegmentStart = -1;
|
|
aResult.SegmentEnd = -1;
|
|
|
|
switch ( aTextType )
|
|
{
|
|
case AccessibleTextType::CHARACTER:
|
|
{
|
|
if ( implIsValidIndex( nIndex + 1, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( nIndex + 1, 1 );
|
|
aResult.SegmentStart = nIndex+1;
|
|
aResult.SegmentEnd = nIndex+2;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::GLYPH:
|
|
{
|
|
// get glyph at index
|
|
implGetGlyphBoundary( sText, aBoundary, nIndex );
|
|
// get next glyph
|
|
if ( aBoundary.endPos < nLength )
|
|
{
|
|
implGetGlyphBoundary( sText, aBoundary, aBoundary.endPos );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::WORD:
|
|
{
|
|
// get word at index
|
|
implGetWordBoundary( sText, aBoundary, nIndex );
|
|
// get next word
|
|
bool bWord = false;
|
|
while ( !bWord && aBoundary.endPos < nLength )
|
|
bWord = implGetWordBoundary( sText, aBoundary, aBoundary.endPos );
|
|
if ( bWord && implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::SENTENCE:
|
|
{
|
|
// get sentence at index
|
|
implGetSentenceBoundary( sText, aBoundary, nIndex );
|
|
// get next sentence
|
|
sal_Int32 nEnd = aBoundary.endPos;
|
|
sal_Int32 nI = aBoundary.endPos;
|
|
bool bFound = false;
|
|
while ( !bFound && ++nI < nLength )
|
|
{
|
|
implGetSentenceBoundary( sText, aBoundary, nI );
|
|
bFound = ( aBoundary.endPos > nEnd );
|
|
}
|
|
if ( bFound && implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::PARAGRAPH:
|
|
{
|
|
// get paragraph at index
|
|
implGetParagraphBoundary( sText, aBoundary, nIndex );
|
|
// get next paragraph
|
|
if ( aBoundary.endPos < nLength )
|
|
{
|
|
implGetParagraphBoundary( sText, aBoundary, aBoundary.endPos );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::LINE:
|
|
{
|
|
// get line at index
|
|
implGetLineBoundary( sText, aBoundary, nIndex );
|
|
// get next line
|
|
if ( aBoundary.endPos < nLength )
|
|
{
|
|
implGetLineBoundary( sText, aBoundary, aBoundary.endPos );
|
|
if ( implIsValidBoundary( aBoundary, nLength ) )
|
|
{
|
|
aResult.SegmentText = sText.copy( aBoundary.startPos, aBoundary.endPos - aBoundary.startPos );
|
|
aResult.SegmentStart = aBoundary.startPos;
|
|
aResult.SegmentEnd = aBoundary.endPos;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case AccessibleTextType::ATTRIBUTE_RUN:
|
|
{
|
|
// TODO: implGetAttributeRunBoundary() (incompatible!)
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
// unknown text type
|
|
}
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
|
|
bool OCommonAccessibleText::implInitTextChangedEvent(
|
|
std::u16string_view rOldString,
|
|
std::u16string_view rNewString,
|
|
css::uno::Any& rDeleted,
|
|
css::uno::Any& rInserted) // throw()
|
|
{
|
|
size_t nLenOld = rOldString.size();
|
|
size_t nLenNew = rNewString.size();
|
|
|
|
// equal
|
|
if ((0 == nLenOld) && (0 == nLenNew))
|
|
return false;
|
|
|
|
TextSegment aDeletedText;
|
|
TextSegment aInsertedText;
|
|
|
|
aDeletedText.SegmentStart = -1;
|
|
aDeletedText.SegmentEnd = -1;
|
|
aInsertedText.SegmentStart = -1;
|
|
aInsertedText.SegmentEnd = -1;
|
|
|
|
// insert only
|
|
if ((0 == nLenOld) && (nLenNew > 0))
|
|
{
|
|
aInsertedText.SegmentStart = 0;
|
|
aInsertedText.SegmentEnd = nLenNew;
|
|
aInsertedText.SegmentText = rNewString.substr( aInsertedText.SegmentStart, aInsertedText.SegmentEnd - aInsertedText.SegmentStart );
|
|
|
|
rInserted <<= aInsertedText;
|
|
return true;
|
|
}
|
|
|
|
// delete only
|
|
if ((nLenOld > 0) && (0 == nLenNew))
|
|
{
|
|
aDeletedText.SegmentStart = 0;
|
|
aDeletedText.SegmentEnd = nLenOld;
|
|
aDeletedText.SegmentText = rOldString.substr( aDeletedText.SegmentStart, aDeletedText.SegmentEnd - aDeletedText.SegmentStart );
|
|
|
|
rDeleted <<= aDeletedText;
|
|
return true;
|
|
}
|
|
|
|
auto pFirstDiffOld = rOldString.begin();
|
|
auto pLastDiffOld = rOldString.end();
|
|
auto pFirstDiffNew = rNewString.begin();
|
|
auto pLastDiffNew = rNewString.end();
|
|
|
|
// find first difference
|
|
while ((pFirstDiffOld < pLastDiffOld) && (pFirstDiffNew < pLastDiffNew)
|
|
&& (*pFirstDiffOld == *pFirstDiffNew))
|
|
{
|
|
pFirstDiffOld++;
|
|
pFirstDiffNew++;
|
|
}
|
|
|
|
// equality test
|
|
if (pFirstDiffOld == pLastDiffOld && pFirstDiffNew == pLastDiffNew)
|
|
return false;
|
|
|
|
// find last difference
|
|
while ( ( pLastDiffOld > pFirstDiffOld) &&
|
|
( pLastDiffNew > pFirstDiffNew) &&
|
|
(pLastDiffOld[-1] == pLastDiffNew[-1]))
|
|
{
|
|
pLastDiffOld--;
|
|
pLastDiffNew--;
|
|
}
|
|
|
|
if (pFirstDiffOld < pLastDiffOld)
|
|
{
|
|
aDeletedText.SegmentStart = pFirstDiffOld - rOldString.begin();
|
|
aDeletedText.SegmentEnd = pLastDiffOld - rOldString.begin();
|
|
aDeletedText.SegmentText = rOldString.substr( aDeletedText.SegmentStart, aDeletedText.SegmentEnd - aDeletedText.SegmentStart );
|
|
|
|
rDeleted <<= aDeletedText;
|
|
}
|
|
|
|
if (pFirstDiffNew < pLastDiffNew)
|
|
{
|
|
aInsertedText.SegmentStart = pFirstDiffNew - rNewString.begin();
|
|
aInsertedText.SegmentEnd = pLastDiffNew - rNewString.begin();
|
|
aInsertedText.SegmentText = rNewString.substr( aInsertedText.SegmentStart, aInsertedText.SegmentEnd - aInsertedText.SegmentStart );
|
|
|
|
rInserted <<= aInsertedText;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
// OAccessibleTextHelper
|
|
|
|
|
|
OAccessibleTextHelper::OAccessibleTextHelper( )
|
|
{
|
|
}
|
|
|
|
|
|
// XInterface
|
|
|
|
|
|
IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleTextHelper, OAccessibleExtendedComponentHelper, OAccessibleTextHelper_Base )
|
|
|
|
|
|
// XTypeProvider
|
|
|
|
|
|
IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleTextHelper, OAccessibleExtendedComponentHelper, OAccessibleTextHelper_Base )
|
|
|
|
|
|
// XAccessibleText
|
|
|
|
|
|
OUString OAccessibleTextHelper::getSelectedText()
|
|
{
|
|
OExternalLockGuard aGuard( this );
|
|
|
|
return OCommonAccessibleText::getSelectedText();
|
|
}
|
|
|
|
|
|
sal_Int32 OAccessibleTextHelper::getSelectionStart()
|
|
{
|
|
OExternalLockGuard aGuard( this );
|
|
|
|
return OCommonAccessibleText::getSelectionStart();
|
|
}
|
|
|
|
|
|
sal_Int32 OAccessibleTextHelper::getSelectionEnd()
|
|
{
|
|
OExternalLockGuard aGuard( this );
|
|
|
|
return OCommonAccessibleText::getSelectionEnd();
|
|
}
|
|
|
|
|
|
TextSegment OAccessibleTextHelper::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType )
|
|
{
|
|
OExternalLockGuard aGuard( this );
|
|
|
|
return OCommonAccessibleText::getTextAtIndex( nIndex, aTextType );
|
|
}
|
|
|
|
|
|
TextSegment OAccessibleTextHelper::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType )
|
|
{
|
|
OExternalLockGuard aGuard( this );
|
|
|
|
return OCommonAccessibleText::getTextBeforeIndex( nIndex, aTextType );
|
|
}
|
|
|
|
|
|
TextSegment OAccessibleTextHelper::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType )
|
|
{
|
|
OExternalLockGuard aGuard( this );
|
|
|
|
return OCommonAccessibleText::getTextBehindIndex( nIndex, aTextType );
|
|
}
|
|
|
|
|
|
} // namespace comphelper
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|