aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquicktextinput.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquicktextinput.cpp')
-rw-r--r--src/quick/items/qquicktextinput.cpp219
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