Fix QTextBoundaryFinder usage cases in QAccessible2
authorKonstantin Ritt <ritt.ks@gmail.com>
Fri, 5 Oct 2012 23:53:44 +0000 (02:53 +0300)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Sat, 13 Oct 2012 01:17:39 +0000 (03:17 +0200)
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>
src/gui/accessible/qaccessible2.cpp
src/gui/accessible/qaccessible2.h
src/plugins/accessible/widgets/simplewidgets.cpp
tests/auto/other/qaccessibility/tst_qaccessibility.cpp

index e3402ef..7f871f9 100644 (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
index ee0215e..c1e7b8b 100644 (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
index 2015929..bb90061 100644 (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)
index 1b789b2..0166d59 100644 (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(" "));