diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 20c35f42f2d5cb1121e164ec3721ffd604f4ff88..cd49377822392b3cda62536d68684411cb47fa75 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -158,6 +158,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
     qmlRegisterType<QQuickScale>(uri,major,minor,"Scale");
     qmlRegisterType<QQuickText>(uri,major,minor,"Text");
     qmlRegisterType<QQuickTextEdit>(uri,major,minor,"TextEdit");
+    qmlRegisterType<QQuickTextEdit,1>(uri,2,1,"TextEdit");
     qmlRegisterType<QQuickTextInput>(uri,major,minor,"TextInput");
     qmlRegisterType<QQuickViewSection>(uri,major,minor,"ViewSection");
 
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index dabbc96614f1100e466af1a0c9c8578af170f548..e30b9cb3fdd429d262841c90b8b9c3dbe034fa84 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -1238,6 +1238,44 @@ void QQuickTextEdit::componentComplete()
     if (d->cursorComponent && isCursorVisible())
         QQuickTextUtil::createCursor(d);
 }
+
+/*!
+    \qmlproperty bool QtQuick2::TextEdit::selectByKeyboard
+    \since QtQuick 2.1
+
+    Defaults to true when the editor is editable, and false
+    when read-only.
+
+    If true, the user can use the keyboard to select text
+    even if the editor is read-only. If false, the user
+    cannot use the keyboard to select text even if the
+    editor is editable.
+
+    \sa readOnly
+*/
+bool QQuickTextEdit::selectByKeyboard() const
+{
+    Q_D(const QQuickTextEdit);
+    if (d->selectByKeyboardSet)
+        return d->selectByKeyboard;
+    return !isReadOnly();
+}
+
+void QQuickTextEdit::setSelectByKeyboard(bool on)
+{
+    Q_D(QQuickTextEdit);
+    bool was = selectByKeyboard();
+    d->selectByKeyboardSet = true;
+    if (was != on) {
+        d->selectByKeyboard = on;
+        if (on)
+            d->control->setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByKeyboard);
+        else
+            d->control->setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByKeyboard);
+        emit selectByKeyboardChanged(on);
+    }
+}
+
 /*!
     \qmlproperty bool QtQuick2::TextEdit::selectByMouse
 
@@ -1316,8 +1354,12 @@ void QQuickTextEdit::setReadOnly(bool r)
     Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
     if (d->selectByMouse)
         flags = flags | Qt::TextSelectableByMouse;
+    if (d->selectByKeyboardSet && d->selectByKeyboard)
+        flags = flags | Qt::TextSelectableByKeyboard;
+    else if (!d->selectByKeyboardSet && !r)
+        flags = flags | Qt::TextSelectableByKeyboard;
     if (!r)
-        flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
+        flags = flags | Qt::TextEditable;
     d->control->setTextInteractionFlags(flags);
     if (!r)
         d->control->moveCursor(QTextCursor::End);
@@ -1327,6 +1369,8 @@ void QQuickTextEdit::setReadOnly(bool r)
 #endif
     q_canPasteChanged();
     emit readOnlyChanged(r);
+    if (!d->selectByKeyboardSet)
+        emit selectByKeyboardChanged(!r);
 }
 
 bool QQuickTextEdit::isReadOnly() const
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index 255c8ac6709f29b8d3275ee423470f547e2901fa..8a2d9b1e9254c96325156b7ab3e2af77a7c82f67 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -90,6 +90,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem
 #ifndef QT_NO_IM
     Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints NOTIFY inputMethodHintsChanged)
 #endif
+    Q_PROPERTY(bool selectByKeyboard READ selectByKeyboard WRITE setSelectByKeyboard NOTIFY selectByKeyboardChanged REVISION 1)
     Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged)
     Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged)
     Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged)
@@ -201,6 +202,9 @@ public:
     void setInputMethodHints(Qt::InputMethodHints hints);
 #endif
 
+    bool selectByKeyboard() const;
+    void setSelectByKeyboard(bool);
+
     bool selectByMouse() const;
     void setSelectByMouse(bool);
 
@@ -274,6 +278,7 @@ Q_SIGNALS:
     void activeFocusOnPressChanged(bool activeFocusOnPressed);
     void persistentSelectionChanged(bool isPersistentSelection);
     void textMarginChanged(qreal textMargin);
+    Q_REVISION(1) void selectByKeyboardChanged(bool selectByKeyboard);
     void selectByMouseChanged(bool selectByMouse);
     void mouseSelectionModeChanged(SelectionMode mode);
     void linkActivated(const QString &link);
diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h
index f65af3d2d30a48bcc9dd50c96a759474d8268e3d..dd0f76f8d93e7fae5745f7136b87fafcf1cbf145 100644
--- a/src/quick/items/qquicktextedit_p_p.h
+++ b/src/quick/items/qquicktextedit_p_p.h
@@ -87,7 +87,7 @@ public:
         , documentDirty(true), dirty(false), richText(false), cursorVisible(false), cursorPending(false)
         , focusOnPress(true), persistentSelection(false), requireImplicitWidth(false)
         , selectByMouse(false), canPaste(false), canPasteValid(false), hAlignImplicit(true)
-        , textCached(true), inLayout(false)
+        , textCached(true), inLayout(false), selectByKeyboard(false), selectByKeyboardSet(false)
     {
     }
 
@@ -168,6 +168,8 @@ public:
     bool hAlignImplicit:1;
     bool textCached:1;
     bool inLayout:1;
+    bool selectByKeyboard:1;
+    bool selectByKeyboardSet:1;
 };
 
 QT_END_NAMESPACE
diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
index 4c4a04b29314fd568ae8625f3d9f003989983d63..b9041fb7195a1618d87364dec3f2dfc3b48c2e81 100644
--- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
@@ -134,6 +134,9 @@ private slots:
     void dragMouseSelection();
     void mouseSelectionMode_accessors();
     void selectByMouse();
+    void selectByKeyboard();
+    void keyboardSelection_data();
+    void keyboardSelection();
     void renderType();
     void inputMethodHints();
 
@@ -2063,6 +2066,127 @@ void tst_qquicktextedit::selectByMouse()
     QCOMPARE(spy.at(1).at(0).toBool(), false);
 }
 
+void tst_qquicktextedit::selectByKeyboard()
+{
+    QQmlComponent oldComponent(&engine);
+    oldComponent.setData("import QtQuick 2.0\n TextEdit { selectByKeyboard: true }", QUrl());
+    QVERIFY(!oldComponent.create());
+
+    QQmlComponent component(&engine);
+    component.setData("import QtQuick 2.1\n TextEdit { }", QUrl());
+    QScopedPointer<QObject> object(component.create());
+    QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(object.data());
+    QVERIFY(edit);
+
+    QSignalSpy spy(edit, SIGNAL(selectByKeyboardChanged(bool)));
+
+    QCOMPARE(edit->isReadOnly(), false);
+    QCOMPARE(edit->selectByKeyboard(), true);
+
+    edit->setReadOnly(true);
+    QCOMPARE(edit->selectByKeyboard(), false);
+    QCOMPARE(spy.count(), 1);
+    QCOMPARE(spy.at(0).at(0).toBool(), false);
+
+    edit->setSelectByKeyboard(true);
+    QCOMPARE(edit->selectByKeyboard(), true);
+    QCOMPARE(spy.count(), 2);
+    QCOMPARE(spy.at(1).at(0).toBool(), true);
+
+    edit->setReadOnly(false);
+    QCOMPARE(edit->selectByKeyboard(), true);
+    QCOMPARE(spy.count(), 2);
+
+    edit->setSelectByKeyboard(false);
+    QCOMPARE(edit->selectByKeyboard(), false);
+    QCOMPARE(spy.count(), 3);
+    QCOMPARE(spy.at(2).at(0).toBool(), false);
+}
+
+Q_DECLARE_METATYPE(QKeySequence::StandardKey)
+
+void tst_qquicktextedit::keyboardSelection_data()
+{
+    QTest::addColumn<QString>("text");
+    QTest::addColumn<bool>("readOnly");
+    QTest::addColumn<bool>("selectByKeyboard");
+    QTest::addColumn<int>("cursorPosition");
+    QTest::addColumn<QKeySequence::StandardKey>("standardKey");
+    QTest::addColumn<QString>("selectedText");
+
+    QTest::newRow("editable - select first char")
+            << QStringLiteral("editable - select first char") << false << true << 0 << QKeySequence::SelectNextChar << QStringLiteral("e");
+    QTest::newRow("editable - select first word")
+            << QStringLiteral("editable - select first char") << false << true << 0 << QKeySequence::SelectNextWord << QStringLiteral("editable ");
+
+    QTest::newRow("editable - cannot select first char")
+            << QStringLiteral("editable - cannot select first char") << false << false << 0 << QKeySequence::SelectNextChar << QStringLiteral("");
+    QTest::newRow("editable - cannot select first word")
+            << QStringLiteral("editable - cannot select first word") << false << false << 0 << QKeySequence::SelectNextWord << QStringLiteral("");
+
+    QTest::newRow("editable - select last char")
+            << QStringLiteral("editable - select last char") << false << true << 27 << QKeySequence::SelectPreviousChar << QStringLiteral("r");
+    QTest::newRow("editable - select last word")
+            << QStringLiteral("editable - select last word") << false << true << 27 << QKeySequence::SelectPreviousWord << QStringLiteral("word");
+
+    QTest::newRow("editable - cannot select last char")
+            << QStringLiteral("editable - cannot select last char") << false << false << 35 << QKeySequence::SelectPreviousChar << QStringLiteral("");
+    QTest::newRow("editable - cannot select last word")
+            << QStringLiteral("editable - cannot select last word") << false << false << 35 << QKeySequence::SelectPreviousWord << QStringLiteral("");
+
+    QTest::newRow("read-only - cannot select first char")
+            << QStringLiteral("read-only - cannot select first char") << true << false << 0 << QKeySequence::SelectNextChar << QStringLiteral("");
+    QTest::newRow("read-only - cannot select first word")
+            << QStringLiteral("read-only - cannot select first word") << true << false << 0 << QKeySequence::SelectNextWord << QStringLiteral("");
+
+    QTest::newRow("read-only - cannot select last char")
+            << QStringLiteral("read-only - cannot select last char") << true << false << 35 << QKeySequence::SelectPreviousChar << QStringLiteral("");
+    QTest::newRow("read-only - cannot select last word")
+            << QStringLiteral("read-only - cannot select last word") << true << false << 35 << QKeySequence::SelectPreviousWord << QStringLiteral("");
+
+    QTest::newRow("read-only - select first char")
+            << QStringLiteral("read-only - select first char") << true << true << 0 << QKeySequence::SelectNextChar << QStringLiteral("r");
+    QTest::newRow("read-only - select first word")
+            << QStringLiteral("read-only - select first word") << true << true << 0 << QKeySequence::SelectNextWord << QStringLiteral("read");
+
+    QTest::newRow("read-only - select last char")
+            << QStringLiteral("read-only - select last char") << true << true << 28 << QKeySequence::SelectPreviousChar << QStringLiteral("r");
+    QTest::newRow("read-only - select last word")
+            << QStringLiteral("read-only - select last word") << true << true << 28 << QKeySequence::SelectPreviousWord << QStringLiteral("word");
+}
+
+void tst_qquicktextedit::keyboardSelection()
+{
+    QFETCH(QString, text);
+    QFETCH(bool, readOnly);
+    QFETCH(bool, selectByKeyboard);
+    QFETCH(int, cursorPosition);
+    QFETCH(QKeySequence::StandardKey, standardKey);
+    QFETCH(QString, selectedText);
+
+    QQmlComponent component(&engine);
+    component.setData("import QtQuick 2.1\n TextEdit { focus: true }", QUrl());
+    QScopedPointer<QObject> object(component.create());
+    QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(object.data());
+    QVERIFY(edit);
+
+    edit->setText(text);
+    edit->setReadOnly(readOnly);
+    edit->setSelectByKeyboard(selectByKeyboard);
+    edit->setCursorPosition(cursorPosition);
+
+    QQuickWindow window;
+    edit->setParentItem(window.contentItem());
+    window.show();
+    window.requestActivate();
+    QTest::qWaitForWindowActive(&window);
+    QVERIFY(edit->hasActiveFocus());
+
+    simulateKeys(&window, standardKey);
+
+    QCOMPARE(edit->selectedText(), selectedText);
+}
+
 void tst_qquicktextedit::renderType()
 {
     QQmlComponent component(&engine);
diff --git a/tests/testapplications/text/textedit.qml b/tests/testapplications/text/textedit.qml
index 789a52894e4c1dba7cac7f98da2c55bf1c3b5672..e0d7dbdde45ba72b13a15b08a427a9fb679efac9 100644
--- a/tests/testapplications/text/textedit.qml
+++ b/tests/testapplications/text/textedit.qml
@@ -39,7 +39,7 @@
 **
 ****************************************************************************/
 
-import QtQuick 2.0
+import QtQuick 2.1
 
 Rectangle {
     height: 360; width: 640
@@ -75,6 +75,7 @@ Rectangle {
             wrapMode: { wrapvalue.model.get(wrapvalue.currentIndex).value }
             smooth: { smoothvalue.model.get(smoothvalue.currentIndex).value }
             selectByMouse: { mousevalue.model.get(mousevalue.currentIndex).value }
+            selectByKeyboard: { keyboardvalue.model.get(keyboardvalue.currentIndex).value }
             onLinkActivated: { bordercolor.border.color = "red" }
             Rectangle { id: bordercolor; color: "transparent"; border.color: "green"; anchors.fill: parent }
         }
@@ -227,6 +228,10 @@ Rectangle {
                 id: mousevalue
                 controlname: "Mouse"
                 model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } }
+            ControlView {
+                id: keyboardvalue
+                controlname: "Keyboard"
+                model: ListModel { ListElement { name: "Off"; value: false } ListElement { name: "On"; value: true } } }
             ControlView {
                 id: halignvalue
                 controlname: "HAlign"