Fix QTextBoundaryFinder usage cases in QAccessible2

Make the implementation safer and closer to what
http://www.linuxfoundation.org/collaborate/workgroups/accessibility/ia2/ia2_implementation_guide#boundaries
requires us to do.

Change-Id: I00af4697e52a9b6e7f5d7b3f403b29126fa1517b
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Reviewed-by: Jan Arve Sæther <jan-arve.saether@digia.com>
This commit is contained in:
Konstantin Ritt 2012-10-06 02:53:44 +03:00 committed by The Qt Project
parent 539ef45689
commit 4717d36c91
4 changed files with 179 additions and 131 deletions

View File

@ -134,19 +134,184 @@ QT_BEGIN_NAMESPACE
*/
/*!
\fn QString QAccessibleTextInterface::textBeforeOffset (int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset) const
Returns the text item of type \a boundaryType that is close to offset \a offset
and sets \a startOffset and \a endOffset values to the start and end positions
of that item; returns an empty string if there is no such an item.
Sets \a startOffset and \a endOffset values to -1 on error.
*/
QString QAccessibleTextInterface::textBeforeOffset(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset) const
{
const QString txt = text(0, characterCount());
if (txt.isEmpty() || offset < 0 || offset > txt.length()) {
*startOffset = *endOffset = -1;
return QString();
}
if (offset == 0) {
*startOffset = *endOffset = offset;
return QString();
}
QTextBoundaryFinder::BoundaryType type;
switch (boundaryType) {
case QAccessible2::CharBoundary:
type = QTextBoundaryFinder::Grapheme;
break;
case QAccessible2::WordBoundary:
type = QTextBoundaryFinder::Word;
break;
case QAccessible2::SentenceBoundary:
type = QTextBoundaryFinder::Sentence;
break;
default:
// in any other case return the whole line
*startOffset = 0;
*endOffset = txt.length();
return txt;
}
// keep behavior in sync with QTextCursor::movePosition()!
QTextBoundaryFinder boundary(type, txt);
boundary.setPosition(offset);
do {
if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
break;
} while (boundary.toPreviousBoundary() > 0);
Q_ASSERT(boundary.position() >= 0);
*endOffset = boundary.position();
while (boundary.toPreviousBoundary() > 0) {
if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
break;
}
Q_ASSERT(boundary.position() >= 0);
*startOffset = boundary.position();
return txt.mid(*startOffset, *endOffset - *startOffset);
}
/*!
\fn QString QAccessibleTextInterface::textAfterOffset(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset) const
Returns the text item of type \a boundaryType that is right after offset \a offset
and sets \a startOffset and \a endOffset values to the start and end positions
of that item; returns an empty string if there is no such an item.
Sets \a startOffset and \a endOffset values to -1 on error.
*/
QString QAccessibleTextInterface::textAfterOffset(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset) const
{
const QString txt = text(0, characterCount());
if (txt.isEmpty() || offset < 0 || offset > txt.length()) {
*startOffset = *endOffset = -1;
return QString();
}
if (offset == txt.length()) {
*startOffset = *endOffset = offset;
return QString();
}
QTextBoundaryFinder::BoundaryType type;
switch (boundaryType) {
case QAccessible2::CharBoundary:
type = QTextBoundaryFinder::Grapheme;
break;
case QAccessible2::WordBoundary:
type = QTextBoundaryFinder::Word;
break;
case QAccessible2::SentenceBoundary:
type = QTextBoundaryFinder::Sentence;
break;
default:
// in any other case return the whole line
*startOffset = 0;
*endOffset = txt.length();
return txt;
}
// keep behavior in sync with QTextCursor::movePosition()!
QTextBoundaryFinder boundary(type, txt);
boundary.setPosition(offset);
while (boundary.toNextBoundary() < txt.length()) {
if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
break;
}
Q_ASSERT(boundary.position() <= txt.length());
*startOffset = boundary.position();
while (boundary.toNextBoundary() < txt.length()) {
if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
break;
}
Q_ASSERT(boundary.position() <= txt.length());
*endOffset = boundary.position();
return txt.mid(*startOffset, *endOffset - *startOffset);
}
/*!
\fn QString QAccessibleTextInterface::textAtOffset(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset) const
Returns the text item of type \a boundaryType at offset \a offset
and sets \a startOffset and \a endOffset values to the start and end positions
of that item; returns an empty string if there is no such an item.
Sets \a startOffset and \a endOffset values to -1 on error.
*/
QString QAccessibleTextInterface::textAtOffset(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset) const
{
const QString txt = text(0, characterCount());
if (txt.isEmpty() || offset < 0 || offset > txt.length()) {
*startOffset = *endOffset = -1;
return QString();
}
if (offset == txt.length()) {
*startOffset = *endOffset = offset;
return QString();
}
QTextBoundaryFinder::BoundaryType type;
switch (boundaryType) {
case QAccessible2::CharBoundary:
type = QTextBoundaryFinder::Grapheme;
break;
case QAccessible2::WordBoundary:
type = QTextBoundaryFinder::Word;
break;
case QAccessible2::SentenceBoundary:
type = QTextBoundaryFinder::Sentence;
break;
default:
// in any other case return the whole line
*startOffset = 0;
*endOffset = txt.length();
return txt;
}
// keep behavior in sync with QTextCursor::movePosition()!
QTextBoundaryFinder boundary(type, txt);
boundary.setPosition(offset);
do {
if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
break;
} while (boundary.toPreviousBoundary() > 0);
Q_ASSERT(boundary.position() >= 0);
*startOffset = boundary.position();
while (boundary.toNextBoundary() < txt.length()) {
if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
break;
}
Q_ASSERT(boundary.position() <= txt.length());
*endOffset = boundary.position();
return txt.mid(*startOffset, *endOffset - *startOffset);
}
/*!
\fn void QAccessibleTextInterface::removeSelection(int selectionIndex)
@ -512,117 +677,6 @@ const QString &QAccessibleActionInterface::toggleAction()
return accessibleActionStrings()->toggleAction;
}
/*!
\internal
*/
QString Q_GUI_EXPORT qTextBeforeOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset, const QString& text)
{
QTextBoundaryFinder::BoundaryType type;
switch (boundaryType) {
case QAccessible2::CharBoundary:
type = QTextBoundaryFinder::Grapheme;
break;
case QAccessible2::WordBoundary:
type = QTextBoundaryFinder::Word;
break;
case QAccessible2::SentenceBoundary:
type = QTextBoundaryFinder::Sentence;
break;
default:
// in any other case return the whole line
*startOffset = 0;
*endOffset = text.length();
return text;
}
QTextBoundaryFinder boundary(type, text);
boundary.setPosition(offset);
if (!boundary.isAtBoundary()) {
boundary.toPreviousBoundary();
}
boundary.toPreviousBoundary();
*startOffset = boundary.position();
boundary.toNextBoundary();
*endOffset = boundary.position();
return text.mid(*startOffset, *endOffset - *startOffset);
}
/*!
\internal
*/
QString Q_GUI_EXPORT qTextAfterOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset, const QString& text)
{
QTextBoundaryFinder::BoundaryType type;
switch (boundaryType) {
case QAccessible2::CharBoundary:
type = QTextBoundaryFinder::Grapheme;
break;
case QAccessible2::WordBoundary:
type = QTextBoundaryFinder::Word;
break;
case QAccessible2::SentenceBoundary:
type = QTextBoundaryFinder::Sentence;
break;
default:
// in any other case return the whole line
*startOffset = 0;
*endOffset = text.length();
return text;
}
QTextBoundaryFinder boundary(type, text);
boundary.setPosition(offset);
boundary.toNextBoundary();
*startOffset = boundary.position();
boundary.toNextBoundary();
*endOffset = boundary.position();
return text.mid(*startOffset, *endOffset - *startOffset);
}
/*!
\internal
*/
QString Q_GUI_EXPORT qTextAtOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset, const QString& text)
{
QTextBoundaryFinder::BoundaryType type;
switch (boundaryType) {
case QAccessible2::CharBoundary:
type = QTextBoundaryFinder::Grapheme;
break;
case QAccessible2::WordBoundary:
type = QTextBoundaryFinder::Word;
break;
case QAccessible2::SentenceBoundary:
type = QTextBoundaryFinder::Sentence;
break;
default:
// in any other case return the whole line
*startOffset = 0;
*endOffset = text.length();
return text;
}
QTextBoundaryFinder boundary(type, text);
boundary.setPosition(offset);
if (!boundary.isAtBoundary()) {
boundary.toPreviousBoundary();
}
*startOffset = boundary.position();
boundary.toNextBoundary();
*endOffset = boundary.position();
return text.mid(*startOffset, *endOffset - *startOffset);
}
QT_END_NAMESPACE
#endif // QT_NO_ACCESSIBILITY

View File

@ -83,12 +83,12 @@ public:
// text
virtual QString text(int startOffset, int endOffset) const = 0;
virtual QString textBeforeOffset (int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset) const = 0;
virtual QString textBeforeOffset(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset) const;
virtual QString textAfterOffset(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset) const = 0;
int *startOffset, int *endOffset) const;
virtual QString textAtOffset(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset) const = 0;
int *startOffset, int *endOffset) const;
virtual int characterCount() const = 0;
// character <-> geometry

View File

@ -72,13 +72,6 @@ extern QList<QWidget*> childWidgets(const QWidget *widget, bool includeTopLevel
QString Q_GUI_EXPORT qt_accStripAmp(const QString &text);
QString Q_GUI_EXPORT qt_accHotKey(const QString &text);
QString Q_GUI_EXPORT qTextBeforeOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset, const QString& text);
QString Q_GUI_EXPORT qTextAtOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset, const QString& text);
QString Q_GUI_EXPORT qTextAfterOffsetFromString(int offset, QAccessible2::BoundaryType boundaryType,
int *startOffset, int *endOffset, const QString& text);
/*!
\class QAccessibleButton
\brief The QAccessibleButton class implements the QAccessibleInterface for button type widgets.
@ -725,7 +718,7 @@ QString QAccessibleLineEdit::textBeforeOffset(int offset, BoundaryType boundaryT
*startOffset = *endOffset = -1;
return QString();
}
return qTextBeforeOffsetFromString(offset, boundaryType, startOffset, endOffset, lineEdit()->text());
return QAccessibleTextInterface::textBeforeOffset(offset, boundaryType, startOffset, endOffset);
}
QString QAccessibleLineEdit::textAfterOffset(int offset, BoundaryType boundaryType,
@ -735,7 +728,7 @@ QString QAccessibleLineEdit::textAfterOffset(int offset, BoundaryType boundaryTy
*startOffset = *endOffset = -1;
return QString();
}
return qTextAfterOffsetFromString(offset, boundaryType, startOffset, endOffset, lineEdit()->text());
return QAccessibleTextInterface::textAfterOffset(offset, boundaryType, startOffset, endOffset);
}
QString QAccessibleLineEdit::textAtOffset(int offset, BoundaryType boundaryType,
@ -745,7 +738,7 @@ QString QAccessibleLineEdit::textAtOffset(int offset, BoundaryType boundaryType,
*startOffset = *endOffset = -1;
return QString();
}
return qTextAtOffsetFromString(offset, boundaryType, startOffset, endOffset, lineEdit()->text());
return QAccessibleTextInterface::textAtOffset(offset, boundaryType, startOffset, endOffset);
}
void QAccessibleLineEdit::removeSelection(int selectionIndex)

View File

@ -1885,6 +1885,7 @@ void tst_QAccessibility::lineEditTest()
QCOMPARE(textIface->textAtOffset(8, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1(" "));
QCOMPARE(textIface->textAtOffset(25, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("advice"));
QCOMPARE(textIface->textAtOffset(92, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1("oneself"));
QCOMPARE(textIface->textAtOffset(101, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1(". --"));
QCOMPARE(textIface->textBeforeOffset(5, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1(" "));
QCOMPARE(textIface->textAfterOffset(5, QAccessible2::WordBoundary,&start,&end), QString::fromLatin1(" "));