diff options
Diffstat (limited to 'src/quick/items/qquicktextinput.cpp')
-rw-r--r-- | src/quick/items/qquicktextinput.cpp | 219 |
1 files changed, 154 insertions, 65 deletions
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 072bfd3440..168fd0d9b6 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -37,7 +43,7 @@ #include "qquicktextutil_p.h" #include <private/qqmlglobal_p.h> - +#include <private/qv4scopedvalue_p.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qmimedata.h> @@ -118,6 +124,8 @@ void QQuickTextInput::componentComplete() \qmlproperty string QtQuick::TextInput::text The text in the TextInput. + + \sa clear() */ QString QQuickTextInput::text() const { @@ -361,7 +369,7 @@ void QQuickTextInput::setFont(const QFont &font) d->updateLayout(); updateCursorRectangle(); #ifndef QT_NO_IM - updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont); + updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont | Qt::ImAnchorRectangle); #endif } emit fontChanged(d->sourceFont); @@ -671,8 +679,7 @@ void QQuickTextInput::setReadOnly(bool ro) setFlag(QQuickItem::ItemAcceptsInputMethod, !ro); #endif d->m_readOnly = ro; - if (!ro) - d->setCursorPosition(d->end()); + d->setCursorPosition(d->end()); #ifndef QT_NO_IM updateInputMethod(Qt::ImEnabled); #endif @@ -753,12 +760,8 @@ void QQuickTextInput::setCursorVisible(bool on) d->cursorVisible = on; if (on && isComponentComplete()) QQuickTextUtil::createCursor(d); - if (!d->cursorItem) { - d->setCursorBlinkPeriod(on ? QGuiApplication::styleHints()->cursorFlashTime() : 0); - d->updateType = QQuickTextInputPrivate::UpdatePaintNode; - polish(); - update(); - } + if (!d->cursorItem) + d->updateCursorBlinking(); emit cursorVisibleChanged(d->cursorVisible); } @@ -998,6 +1001,37 @@ void QQuickTextInput::q_validatorChanged() } #endif // QT_NO_VALIDATOR +QRectF QQuickTextInputPrivate::anchorRectangle() const +{ + Q_Q(const QQuickTextInput); + QRectF rect; + int a; + // Unfortunately we cannot use selectionStart() and selectionEnd() + // since they always assume that the selectionStart is logically before selectionEnd. + // To rely on that would cause havoc if the user was interactively moving the end selection + // handle to become before the start selection + if (m_selstart == m_selend) + // This is to handle the case when there is "no selection" while moving the handle onto the + // same position as the other handle (in which case it would hide the selection handles) + a = m_cursor; + else + a = m_selstart == m_cursor ? m_selend : m_selstart; + if (a >= 0) { +#ifndef QT_NO_IM + a += m_preeditCursor; +#endif + if (m_echoMode == QQuickTextInput::NoEcho) + a = 0; + QTextLine l = m_textLayout.lineForTextPosition(a); + if (l.isValid()) { + qreal x = l.cursorToX(a) - hscroll + q->leftPadding(); + qreal y = l.y() - vscroll + q->topPadding(); + rect.setRect(x, y, 1, l.height()); + } + } + return rect; +} + void QQuickTextInputPrivate::checkIsValid() { Q_Q(QQuickTextInput); @@ -1745,7 +1779,7 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData node = new QQuickTextNode(this); d->textNode = node; - const bool showCursor = !isReadOnly() && d->cursorItem == 0 && d->cursorVisible && (d->m_blinkStatus || d->m_blinkPeriod == 0); + const bool showCursor = !isReadOnly() && d->cursorItem == 0 && d->cursorVisible && d->m_blinkStatus; if (!d->textLayoutDirty && oldNode != 0) { if (showCursor) @@ -1806,10 +1840,16 @@ QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, QVaria return QVariant((int) d->effectiveInputMethodHints()); case Qt::ImCursorRectangle: return cursorRectangle(); + case Qt::ImAnchorRectangle: + return d->anchorRectangle(); case Qt::ImFont: return font(); - case Qt::ImCursorPosition: + case Qt::ImCursorPosition: { + const QPointF pt = argument.toPointF(); + if (!pt.isNull()) + return QVariant(d->positionAt(pt)); return QVariant(d->m_cursor); + } case Qt::ImSurroundingText: if (d->m_echoMode == PasswordEchoOnEdit && !d->m_passwordEchoEditing) { return QVariant(displayText()); @@ -1835,7 +1875,7 @@ QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, QVaria return QVariant(d->m_text.mid(d->m_cursor)); case Qt::ImTextBeforeCursor: if (argument.isValid()) - return QVariant(d->m_text.left(d->m_cursor).right(argument.toInt())); + return QVariant(d->m_text.leftRef(d->m_cursor).right(argument.toInt()).toString()); return QVariant(d->m_text.left(d->m_cursor)); default: return QQuickItem::inputMethodQuery(property); @@ -1940,6 +1980,7 @@ void QQuickTextInput::undo() { Q_D(QQuickTextInput); if (!d->m_readOnly) { + d->resetInputMethod(); d->internalUndo(); d->finishChange(-1, true); } @@ -1955,6 +1996,7 @@ void QQuickTextInput::redo() { Q_D(QQuickTextInput); if (!d->m_readOnly) { + d->resetInputMethod(); d->internalRedo(); d->finishChange(); } @@ -2192,6 +2234,7 @@ void QQuickTextInput::resetPasswordMaskDelay() partial text input from an input method. \readonly + \sa preeditText */ QString QQuickTextInput::displayText() const { @@ -2200,6 +2243,21 @@ QString QQuickTextInput::displayText() const } /*! + \qmlproperty string QtQuick::TextInput::preeditText + \readonly + \since 5.7 + + This property contains partial text input from an input method. + + \sa displayText +*/ +QString QQuickTextInput::preeditText() const +{ + Q_D(const QQuickTextInput); + return d->m_textLayout.preeditAreaText(); +} + +/*! \qmlproperty bool QtQuick::TextInput::selectByMouse Defaults to false. @@ -2457,8 +2515,10 @@ void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event) { Q_Q(QQuickTextInput); bool focus = event->gotFocus(); - if (!m_readOnly) + if (!m_readOnly) { q->setCursorVisible(focus); + setBlinkingCursorEnabled(focus); + } if (focus) { q->q_updateAlignment(); #ifndef QT_NO_IM @@ -2561,6 +2621,13 @@ void QQuickTextInputPrivate::init() } } +void QQuickTextInputPrivate::resetInputMethod() +{ + Q_Q(QQuickTextInput); + if (!m_readOnly && q->hasActiveFocus() && qGuiApp) + QGuiApplication::inputMethod()->reset(); +} + void QQuickTextInput::updateCursorRectangle(bool scroll) { Q_D(QQuickTextInput); @@ -2581,7 +2648,7 @@ void QQuickTextInput::updateCursorRectangle(bool scroll) d->cursorItem->setHeight(r.height()); } #ifndef QT_NO_IM - updateInputMethod(Qt::ImCursorRectangle); + updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle); #endif } @@ -2849,7 +2916,7 @@ void QQuickTextInputPrivate::updateLayout() if (inLayout) // probably the result of a binding loop, but by letting it return; // get this far we'll get a warning to that effect. } - qreal lineWidth = q->widthValid() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX; + qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX; qreal height = 0; qreal width = 0; do { @@ -3115,8 +3182,8 @@ void QQuickTextInputPrivate::setSelection(int start, int length) emit q->selectionChanged(); emitCursorPositionChanged(); #ifndef QT_NO_IM - q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition - | Qt::ImCursorPosition | Qt::ImCurrentSelection); + q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle | Qt::ImCursorPosition | Qt::ImAnchorPosition + | Qt::ImCurrentSelection); #endif } @@ -3271,7 +3338,10 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) cursorPositionChanged = true; } } + QString oldPreeditString = m_textLayout.preeditAreaText(); m_textLayout.setPreeditArea(m_cursor, event->preeditString()); + if (oldPreeditString != m_textLayout.preeditAreaText()) + emit q->preeditTextChanged(); const int oldPreeditCursor = m_preeditCursor; m_preeditCursor = event->preeditString().length(); hasImState = !event->preeditString().isEmpty(); @@ -3311,8 +3381,8 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event) if (selectionChange) { emit q->selectionChanged(); - q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorPosition - | Qt::ImCursorPosition | Qt::ImCurrentSelection); + q->updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle + | Qt::ImCurrentSelection); } } #endif // QT_NO_IM @@ -3542,7 +3612,7 @@ void QQuickTextInputPrivate::internalInsert(const QString &s) int remaining = m_maxLength - m_text.length(); if (remaining != 0) { m_text.insert(m_cursor, s.left(remaining)); - for (int i = 0; i < (int) s.left(remaining).length(); ++i) + for (int i = 0; i < (int) s.leftRef(remaining).length(); ++i) addCommand(Command(Insert, m_cursor++, s.at(i), -1, -1)); m_textDirty = true; } @@ -3895,14 +3965,14 @@ QString QQuickTextInputPrivate::maskString(uint pos, const QString &str, bool cl int n = findInMask(i, true, true, str[(int)strIndex]); if (n != -1) { if (str.length() != 1 || i == 0 || (i > 0 && (!m_maskData[i-1].separator || m_maskData[i-1].maskChar != str[(int)strIndex]))) { - s += fill.mid(i, n-i+1); + s += fill.midRef(i, n-i+1); i = n + 1; // update i to find + 1 } } else { // search for valid m_blank if not n = findInMask(i, true, false, str[(int)strIndex]); if (n != -1) { - s += fill.mid(i, n-i); + s += fill.midRef(i, n-i); switch (m_maskData[n].caseMode) { case MaskInputData::Upper: s += str[(int)strIndex].toUpper(); @@ -4148,26 +4218,39 @@ bool QQuickTextInputPrivate::emitCursorPositionChanged() } -void QQuickTextInputPrivate::setCursorBlinkPeriod(int msec) +void QQuickTextInputPrivate::setBlinkingCursorEnabled(bool enable) { - Q_Q(QQuickTextInput); - if (msec == m_blinkPeriod) + if (enable == m_blinkEnabled) return; + + m_blinkEnabled = enable; + updateCursorBlinking(); + + if (enable) + connect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged, this, &QQuickTextInputPrivate::updateCursorBlinking); + else + disconnect(qApp->styleHints(), &QStyleHints::cursorFlashTimeChanged, this, &QQuickTextInputPrivate::updateCursorBlinking); +} + +void QQuickTextInputPrivate::updateCursorBlinking() +{ + Q_Q(QQuickTextInput); + if (m_blinkTimer) { q->killTimer(m_blinkTimer); - } - if (msec) { - m_blinkTimer = q->startTimer(msec / 2); - m_blinkStatus = 1; - } else { m_blinkTimer = 0; - if (m_blinkStatus == 1) { - updateType = UpdatePaintNode; - q->polish(); - q->update(); - } } - m_blinkPeriod = msec; + + if (m_blinkEnabled && cursorVisible && !cursorItem && !m_readOnly) { + int flashTime = QGuiApplication::styleHints()->cursorFlashTime(); + if (flashTime >= 2) + m_blinkTimer = q->startTimer(flashTime / 2); + } + + m_blinkStatus = 1; + updateType = UpdatePaintNode; + q->polish(); + q->update(); } void QQuickTextInput::timerEvent(QTimerEvent *event) @@ -4209,20 +4292,8 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) return; } - if (m_blinkPeriod > 0) { - if (m_blinkTimer) - q->killTimer(m_blinkTimer); - - m_blinkTimer = q->startTimer(m_blinkPeriod / 2); - - if (m_blinkStatus == 0) { - m_blinkStatus = 1; - - updateType = UpdatePaintNode; - q->polish(); - q->update(); - } - } + if (m_blinkEnabled) + updateCursorBlinking(); if (m_echoMode == QQuickTextInput::PasswordEchoOnEdit && !m_passwordEchoEditing @@ -4465,6 +4536,24 @@ void QQuickTextInput::ensureVisible(int position) } /*! + \qmlmethod QtQuick::TextInput::clear() + \since 5.7 + + Clears the contents of the text input + and resets partial text input from an input method. + + Use this method instead of setting the \l text property to an empty string. + + \sa QInputMethod::reset() +*/ +void QQuickTextInput::clear() +{ + Q_D(QQuickTextInput); + d->resetInputMethod(); + d->clear(); +} + +/*! \since 5.6 \qmlproperty real QtQuick::TextInput::padding \qmlproperty real QtQuick::TextInput::topPadding |