Made QQuickTextInput follow input direction changes
authorPekka Vuorela <pekka.ta.vuorela@nokia.com>
Mon, 9 Jan 2012 11:41:36 +0000 (13:41 +0200)
committerQt by Nokia <qt-info@nokia.com>
Tue, 17 Jan 2012 12:15:30 +0000 (13:15 +0100)
Cursor of empty field should align based on input method
direction. Now input method allowed to change direction
on run time.

Also earlier cursor wasn't properly drawn on correct alignment
at all.

Change-Id: I4601f10e6b5dde09591bd484b05f001add6c1573
Reviewed-by: Andrew den Exter <andrew.den-exter@nokia.com>
Reviewed-by: Joona Petrell <joona.t.petrell@nokia.com>
src/quick/items/qquicktextinput.cpp
src/quick/items/qquicktextinput_p.h
src/quick/items/qquicktextinput_p_p.h
tests/auto/qtquick2/qquicktextinput/tst_qquicktextinput.cpp
tests/auto/shared/platforminputcontext.h

index e569581..309d039 100644 (file)
@@ -2316,6 +2316,12 @@ void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
         if (!hasFocus) {
             d->commitPreedit();
             d->deselect();
+            disconnect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
+                       this, SLOT(q_updateAlignment()));
+        } else {
+            q_updateAlignment();
+            connect(qApp->inputPanel(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
+                    this, SLOT(q_updateAlignment()));
         }
     }
     QQuickItem::itemChange(change, value);
@@ -2444,6 +2450,15 @@ void QQuickTextInput::q_canPasteChanged()
 
 }
 
+void QQuickTextInput::q_updateAlignment()
+{
+    Q_D(QQuickTextInput);
+    if (d->determineHorizontalAlignment()) {
+        d->updateLayout();
+        updateCursorRectangle();
+    }
+}
+
 // ### these should come from QStyleHints
 const int textCursorWidth = 1;
 const bool fullWidthSelection = true;
@@ -2510,7 +2525,7 @@ void QQuickTextInputPrivate::updateLayout()
         return;
 
     QTextOption option = m_textLayout.textOption();
-    option.setTextDirection(m_layoutDirection);
+    option.setTextDirection(layoutDirection());
     option.setFlags(QTextOption::IncludeTrailingSpaces);
     option.setWrapMode(QTextOption::WrapMode(wrapMode));
     option.setAlignment(Qt::Alignment(q->effectiveHAlign()));
@@ -2984,6 +2999,7 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
 
     Q_UNUSED(update)
     bool notifyInputPanel = m_textDirty || m_selDirty;
+    bool alignmentChanged = false;
 
     if (m_textDirty) {
         // do validation
@@ -3026,18 +3042,21 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
         if (m_textDirty) {
             m_textDirty = false;
             m_preeditDirty = false;
-            determineHorizontalAlignment();
+            alignmentChanged = determineHorizontalAlignment();
             emit q->textChanged();
         }
 
-        updateDisplayText();
+        updateDisplayText(alignmentChanged);
 
         if (m_validInput != wasValidInput)
             emit q->acceptableInputChanged();
     }
     if (m_preeditDirty) {
         m_preeditDirty = false;
-        determineHorizontalAlignment();
+        if (determineHorizontalAlignment()) {
+            alignmentChanged = true;
+            updateLayout();
+        }
     }
 
     if (m_selDirty) {
@@ -3049,7 +3068,9 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
     if (notifyInputPanel)
         q->updateMicroFocus();
     emitUndoRedoChanged();
-    emitCursorPositionChanged();
+
+    if (!emitCursorPositionChanged() && alignmentChanged)
+        q->updateCursorRectangle();
 
     return true;
 }
@@ -3683,7 +3704,7 @@ void QQuickTextInputPrivate::emitUndoRedoChanged()
     If the current cursor position differs from the last emitted cursor
     position, emits cursorPositionChanged().
 */
-void QQuickTextInputPrivate::emitCursorPositionChanged()
+bool QQuickTextInputPrivate::emitCursorPositionChanged()
 {
     Q_Q(QQuickTextInput);
     if (m_cursor != m_lastCursorPos) {
@@ -3710,7 +3731,10 @@ void QQuickTextInputPrivate::emitCursorPositionChanged()
 #ifndef QT_NO_ACCESSIBILITY
         QAccessible::updateAccessibility(q, 0, QAccessible::TextCaretMoved);
 #endif
+
+        return true;
     }
+    return false;
 }
 
 
index 535b1af..7b80ed0 100644 (file)
@@ -323,6 +323,7 @@ private Q_SLOTS:
     void createCursor();
     void updateCursorRectangle();
     void q_canPasteChanged();
+    void q_updateAlignment();
 
 private:
     Q_DECLARE_PRIVATE(QQuickTextInput)
index 3f28c4a..44ea777 100644 (file)
@@ -424,7 +424,7 @@ private:
     void internalRedo();
     void emitUndoRedoChanged();
 
-    void emitCursorPositionChanged();
+    bool emitCursorPositionChanged();
 
     bool finishChange(int validateFromState = -1, bool update = false, bool edited = true);
 
index e97756f..8cc35f3 100644 (file)
@@ -1219,6 +1219,10 @@ void tst_qquicktextinput::horizontalAlignment()
 
 void tst_qquicktextinput::horizontalAlignment_RightToLeft()
 {
+    PlatformInputContext platformInputContext;
+    QInputPanelPrivate *inputPanelPrivate = QInputPanelPrivate::get(qApp->inputPanel());
+    inputPanelPrivate->testContext = &platformInputContext;
+
     QQuickView canvas(testFileUrl("horizontalAlignment_RightToLeft.qml"));
     QQuickTextInput *textInput = canvas.rootObject()->findChild<QQuickTextInput*>("text");
     QVERIFY(textInput != 0);
@@ -1314,26 +1318,42 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft()
     // empty text with implicit alignment follows the system locale-based
     // keyboard input direction from QInputPanel::inputDirection()
     textInput->setText("");
-    QCOMPARE(textInput->hAlign(), qApp->inputPanel()->inputDirection() == Qt::LeftToRight ?
-                                  QQuickTextInput::AlignLeft : QQuickTextInput::AlignRight);
-    if (qApp->inputPanel()->inputDirection() == Qt::LeftToRight) {
-        QCOMPARE(textInputPrivate->boundingRect.left() - textInputPrivate->hscroll, qreal(0));
-    } else {
-        QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1);
-        QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1);
-    }
-    textInput->setHAlign(QQuickTextInput::AlignRight);
+    platformInputContext.setInputDirection(Qt::LeftToRight);
+    QVERIFY(qApp->inputPanel()->inputDirection() == Qt::LeftToRight);
+    QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignLeft);
+    QCOMPARE(textInputPrivate->boundingRect.left() - textInputPrivate->hscroll, qreal(0));
+
+    QSignalSpy cursorRectangleSpy(textInput, SIGNAL(cursorRectangleChanged()));
+    platformInputContext.setInputDirection(Qt::RightToLeft);
+    QVERIFY(qApp->inputPanel()->inputDirection() == Qt::RightToLeft);
+    QCOMPARE(cursorRectangleSpy.count(), 1);
+    QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
+    QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1);
+    QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1);
+
+    // set input direction while having content
+    platformInputContext.setInputDirection(Qt::LeftToRight);
+    textInput->setText("a");
+    platformInputContext.setInputDirection(Qt::RightToLeft);
+    QTest::keyClick(&canvas, Qt::Key_Backspace);
+    QVERIFY(textInput->text().isEmpty());
+    QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
+    QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1);
+    QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1);
+
+    // input direction changed while not having focus
+    platformInputContext.setInputDirection(Qt::LeftToRight);
+    textInput->setFocus(false);
+    platformInputContext.setInputDirection(Qt::RightToLeft);
+    textInput->setFocus(true);
     QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
     QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1);
     QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1);
 
-    QString componentStr = "import QtQuick 2.0\nTextInput {}";
-    QDeclarativeComponent textComponent(&engine);
-    textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
-    QQuickTextInput *textObject = qobject_cast<QQuickTextInput*>(textComponent.create());
-    QCOMPARE(textObject->hAlign(), qApp->inputPanel()->inputDirection() == Qt::LeftToRight ?
-                                  QQuickTextInput::AlignLeft : QQuickTextInput::AlignRight);
-    delete textObject;
+    textInput->setHAlign(QQuickTextInput::AlignRight);
+    QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
+    QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll >= textInput->width() - 1);
+    QVERIFY(textInputPrivate->boundingRect.right() - textInputPrivate->hscroll <= textInput->width() + 1);
 }
 
 void tst_qquicktextinput::verticalAlignment()
index db50837..0c23db4 100644 (file)
@@ -48,7 +48,7 @@ public:
     PlatformInputContext()
         : m_visible(false), m_action(QInputPanel::Click), m_cursorPosition(0),
           m_invokeActionCallCount(0), m_showInputPanelCallCount(0), m_hideInputPanelCallCount(0),
-          m_updateCallCount(0)
+          m_updateCallCount(0), m_direction(Qt::LeftToRight)
     {
     }
 
@@ -77,6 +77,25 @@ public:
         m_updateCallCount++;
     }
 
+    virtual QLocale locale() const
+    {
+        if (m_direction == Qt::RightToLeft)
+            return QLocale(QLocale::Arabic);
+        else
+            return QLocale(QLocale::English);
+    }
+
+    virtual Qt::LayoutDirection inputDirection() const
+    {
+        return m_direction;
+    }
+
+    void setInputDirection(Qt::LayoutDirection direction) {
+        m_direction = direction;
+        emitLocaleChanged();
+        emitInputDirectionChanged(inputDirection());
+    }
+
     void clear() {
         m_cursorPosition = 0;
         m_invokeActionCallCount = 0;
@@ -93,4 +112,5 @@ public:
     int m_showInputPanelCallCount;
     int m_hideInputPanelCallCount;
     int m_updateCallCount;
+    Qt::LayoutDirection m_direction;
 };