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.cpp2007
1 files changed, 2007 insertions, 0 deletions
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
new file mode 100644
index 0000000000..e9caaf2ee8
--- /dev/null
+++ b/src/quick/items/qquicktextinput.cpp
@@ -0,0 +1,2007 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktextinput_p.h"
+#include "qquicktextinput_p_p.h"
+#include "qquickcanvas.h"
+
+#include <private/qdeclarativeglobal_p.h>
+
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtGui/qevent.h>
+#include <QTextBoundaryFinder>
+#include "qquicktextnode_p.h"
+#include <QtQuick/qsgsimplerectnode.h>
+
+#include <QtGui/qstylehints.h>
+#include <QtGui/qinputpanel.h>
+
+QT_BEGIN_NAMESPACE
+
+DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
+
+/*!
+ \qmlclass TextInput QQuickTextInput
+ \inqmlmodule QtQuick 2
+ \ingroup qml-basic-visual-elements
+ \brief The TextInput item displays an editable line of text.
+ \inherits Item
+
+ The TextInput element displays a single line of editable plain text.
+
+ TextInput is used to accept a line of text input. Input constraints
+ can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
+ and setting \l echoMode to an appropriate value enables TextInput to be used for
+ a password input field.
+
+ On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
+ If you want such bindings (on any platform), you will need to construct them in QML.
+
+ \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
+*/
+QQuickTextInput::QQuickTextInput(QQuickItem* parent)
+: QQuickImplicitSizeItem(*(new QQuickTextInputPrivate), parent)
+{
+ Q_D(QQuickTextInput);
+ d->init();
+}
+
+QQuickTextInput::~QQuickTextInput()
+{
+}
+
+/*!
+ \qmlproperty string QtQuick2::TextInput::text
+
+ The text in the TextInput.
+*/
+QString QQuickTextInput::text() const
+{
+ Q_D(const QQuickTextInput);
+ return d->control->text();
+}
+
+void QQuickTextInput::setText(const QString &s)
+{
+ Q_D(QQuickTextInput);
+ if (s == text())
+ return;
+ d->control->setText(s);
+}
+
+/*!
+ \qmlproperty string QtQuick2::TextInput::font.family
+
+ Sets the family name of the font.
+
+ The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
+ If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
+ If the family isn't available a family will be set using the font matching algorithm.
+*/
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::font.bold
+
+ Sets whether the font weight is bold.
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick2::TextInput::font.weight
+
+ Sets the font's weight.
+
+ The weight can be one of:
+ \list
+ \o Font.Light
+ \o Font.Normal - the default
+ \o Font.DemiBold
+ \o Font.Bold
+ \o Font.Black
+ \endlist
+
+ \qml
+ TextInput { text: "Hello"; font.weight: Font.DemiBold }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::font.italic
+
+ Sets whether the font has an italic style.
+*/
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::font.underline
+
+ Sets whether the text is underlined.
+*/
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::font.strikeout
+
+ Sets whether the font has a strikeout style.
+*/
+
+/*!
+ \qmlproperty real QtQuick2::TextInput::font.pointSize
+
+ Sets the font size in points. The point size must be greater than zero.
+*/
+
+/*!
+ \qmlproperty int QtQuick2::TextInput::font.pixelSize
+
+ Sets the font size in pixels.
+
+ Using this function makes the font device dependent.
+ Use \c pointSize to set the size of the font in a device independent manner.
+*/
+
+/*!
+ \qmlproperty real QtQuick2::TextInput::font.letterSpacing
+
+ Sets the letter spacing for the font.
+
+ Letter spacing changes the default spacing between individual letters in the font.
+ A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
+*/
+
+/*!
+ \qmlproperty real QtQuick2::TextInput::font.wordSpacing
+
+ Sets the word spacing for the font.
+
+ Word spacing changes the default spacing between individual words.
+ A positive value increases the word spacing by a corresponding amount of pixels,
+ while a negative value decreases the inter-word spacing accordingly.
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
+
+ Sets the capitalization for the text.
+
+ \list
+ \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
+ \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
+ \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
+ \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
+ \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
+ \endlist
+
+ \qml
+ TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
+ \endqml
+*/
+
+QFont QQuickTextInput::font() const
+{
+ Q_D(const QQuickTextInput);
+ return d->sourceFont;
+}
+
+void QQuickTextInput::setFont(const QFont &font)
+{
+ Q_D(QQuickTextInput);
+ if (d->sourceFont == font)
+ return;
+
+ d->sourceFont = font;
+ QFont oldFont = d->font;
+ d->font = font;
+ if (d->font.pointSizeF() != -1) {
+ // 0.5pt resolution
+ qreal size = qRound(d->font.pointSizeF()*2.0);
+ d->font.setPointSizeF(size/2.0);
+ }
+ if (oldFont != d->font) {
+ d->control->setFont(d->font);
+ updateSize();
+ updateCursorRectangle();
+ if (d->cursorItem) {
+ d->cursorItem->setHeight(QFontMetrics(d->font).height());
+ }
+ }
+ emit fontChanged(d->sourceFont);
+}
+
+/*!
+ \qmlproperty color QtQuick2::TextInput::color
+
+ The text color.
+*/
+QColor QQuickTextInput::color() const
+{
+ Q_D(const QQuickTextInput);
+ return d->color;
+}
+
+void QQuickTextInput::setColor(const QColor &c)
+{
+ Q_D(QQuickTextInput);
+ if (c != d->color) {
+ d->color = c;
+ update();
+ emit colorChanged(c);
+ }
+}
+
+
+/*!
+ \qmlproperty color QtQuick2::TextInput::selectionColor
+
+ The text highlight color, used behind selections.
+*/
+QColor QQuickTextInput::selectionColor() const
+{
+ Q_D(const QQuickTextInput);
+ return d->selectionColor;
+}
+
+void QQuickTextInput::setSelectionColor(const QColor &color)
+{
+ Q_D(QQuickTextInput);
+ if (d->selectionColor == color)
+ return;
+
+ d->selectionColor = color;
+ QPalette p = d->control->palette();
+ p.setColor(QPalette::Highlight, d->selectionColor);
+ d->control->setPalette(p);
+ if (d->control->hasSelectedText())
+ update();
+ emit selectionColorChanged(color);
+}
+/*!
+ \qmlproperty color QtQuick2::TextInput::selectedTextColor
+
+ The highlighted text color, used in selections.
+*/
+QColor QQuickTextInput::selectedTextColor() const
+{
+ Q_D(const QQuickTextInput);
+ return d->selectedTextColor;
+}
+
+void QQuickTextInput::setSelectedTextColor(const QColor &color)
+{
+ Q_D(QQuickTextInput);
+ if (d->selectedTextColor == color)
+ return;
+
+ d->selectedTextColor = color;
+ QPalette p = d->control->palette();
+ p.setColor(QPalette::HighlightedText, d->selectedTextColor);
+ d->control->setPalette(p);
+ if (d->control->hasSelectedText())
+ update();
+ emit selectedTextColorChanged(color);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
+ \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
+
+ Sets the horizontal alignment of the text within the TextInput item's
+ width and height. By default, the text alignment follows the natural alignment
+ of the text, for example text that is read from left to right will be aligned to
+ the left.
+
+ TextInput does not have vertical alignment, as the natural height is
+ exactly the height of the single line of text. If you set the height
+ manually to something larger, TextInput will always be top aligned
+ vertically. You can use anchors to align it however you want within
+ another item.
+
+ The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
+ \c TextInput.AlignHCenter.
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of TextInput, use the read-only property \c effectiveHorizontalAlignment.
+*/
+QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
+{
+ Q_D(const QQuickTextInput);
+ return d->hAlign;
+}
+
+void QQuickTextInput::setHAlign(HAlignment align)
+{
+ Q_D(QQuickTextInput);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
+ updateCursorRectangle();
+ }
+}
+
+void QQuickTextInput::resetHAlign()
+{
+ Q_D(QQuickTextInput);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete()) {
+ updateCursorRectangle();
+ }
+}
+
+QQuickTextInput::HAlignment QQuickTextInput::effectiveHAlign() const
+{
+ Q_D(const QQuickTextInput);
+ QQuickTextInput::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QQuickTextInput::AlignLeft:
+ effectiveAlignment = QQuickTextInput::AlignRight;
+ break;
+ case QQuickTextInput::AlignRight:
+ effectiveAlignment = QQuickTextInput::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QQuickTextInputPrivate::setHAlign(QQuickTextInput::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QQuickTextInput);
+ if ((hAlign != alignment || forceAlign) && alignment <= QQuickTextInput::AlignHCenter) { // justify not supported
+ QQuickTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+ emit q->horizontalAlignmentChanged(alignment);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QQuickTextInputPrivate::determineHorizontalAlignment()
+{
+ if (hAlignImplicit) {
+ // if no explicit alignment has been set, follow the natural layout direction of the text
+ QString text = control->text();
+ if (text.isEmpty())
+ text = control->preeditAreaText();
+ bool isRightToLeft = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
+ return setHAlign(isRightToLeft ? QQuickTextInput::AlignRight : QQuickTextInput::AlignLeft);
+ }
+ return false;
+}
+
+void QQuickTextInputPrivate::mirrorChange()
+{
+ Q_Q(QQuickTextInput);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QQuickTextInput::AlignRight || hAlign == QQuickTextInput::AlignLeft)) {
+ q->updateCursorRectangle();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::readOnly
+
+ Sets whether user input can modify the contents of the TextInput.
+
+ If readOnly is set to true, then user input will not affect the text
+ property. Any bindings or attempts to set the text property will still
+ work.
+*/
+bool QQuickTextInput::isReadOnly() const
+{
+ Q_D(const QQuickTextInput);
+ return d->control->isReadOnly();
+}
+
+void QQuickTextInput::setReadOnly(bool ro)
+{
+ Q_D(QQuickTextInput);
+ if (d->control->isReadOnly() == ro)
+ return;
+
+ setFlag(QQuickItem::ItemAcceptsInputMethod, !ro);
+ d->control->setReadOnly(ro);
+ if (!ro)
+ d->control->setCursorPosition(d->control->end());
+
+ emit readOnlyChanged(ro);
+}
+
+/*!
+ \qmlproperty int QtQuick2::TextInput::maximumLength
+ The maximum permitted length of the text in the TextInput.
+
+ If the text is too long, it is truncated at the limit.
+
+ By default, this property contains a value of 32767.
+*/
+int QQuickTextInput::maxLength() const
+{
+ Q_D(const QQuickTextInput);
+ return d->control->maxLength();
+}
+
+void QQuickTextInput::setMaxLength(int ml)
+{
+ Q_D(QQuickTextInput);
+ if (d->control->maxLength() == ml)
+ return;
+
+ d->control->setMaxLength(ml);
+
+ emit maximumLengthChanged(ml);
+}
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::cursorVisible
+ Set to true when the TextInput shows a cursor.
+
+ This property is set and unset when the TextInput gets active focus, so that other
+ properties can be bound to whether the cursor is currently showing. As it
+ gets set and unset automatically, when you set the value yourself you must
+ keep in mind that your value may be overwritten.
+
+ It can be set directly in script, for example if a KeyProxy might
+ forward keys to it and you desire it to look active when this happens
+ (but without actually giving it active focus).
+
+ It should not be set directly on the element, like in the below QML,
+ as the specified value will be overridden an lost on focus changes.
+
+ \code
+ TextInput {
+ text: "Text"
+ cursorVisible: false
+ }
+ \endcode
+
+ In the above snippet the cursor will still become visible when the
+ TextInput gains active focus.
+*/
+bool QQuickTextInput::isCursorVisible() const
+{
+ Q_D(const QQuickTextInput);
+ return d->cursorVisible;
+}
+
+void QQuickTextInput::setCursorVisible(bool on)
+{
+ Q_D(QQuickTextInput);
+ if (d->cursorVisible == on)
+ return;
+ d->cursorVisible = on;
+ d->control->setCursorBlinkPeriod(on ? qApp->styleHints()->cursorFlashTime() : 0);
+ QRect r = d->control->cursorRect();
+ if (d->control->inputMask().isEmpty())
+ updateRect(r);
+ else
+ updateRect();
+ emit cursorVisibleChanged(d->cursorVisible);
+}
+
+/*!
+ \qmlproperty int QtQuick2::TextInput::cursorPosition
+ The position of the cursor in the TextInput.
+*/
+int QQuickTextInput::cursorPosition() const
+{
+ Q_D(const QQuickTextInput);
+ return d->control->cursor();
+}
+void QQuickTextInput::setCursorPosition(int cp)
+{
+ Q_D(QQuickTextInput);
+ if (cp < 0 || cp > d->control->text().length())
+ return;
+ d->control->moveCursor(cp);
+}
+
+/*!
+ Returns a Rect which encompasses the cursor, but which may be larger than is
+ required. Ignores custom cursor delegates.
+*/
+QRect QQuickTextInput::cursorRectangle() const
+{
+ Q_D(const QQuickTextInput);
+ QRect r = d->control->cursorRect();
+ // Scroll and make consistent with TextEdit
+ // QLineControl inexplicably adds 1 to the height and horizontal padding
+ // for unicode direction markers.
+ r.adjust(5 - d->hscroll, 0, -4 - d->hscroll, -1);
+ return r;
+}
+/*!
+ \qmlproperty int QtQuick2::TextInput::selectionStart
+
+ The cursor position before the first character in the current selection.
+
+ This property is read-only. To change the selection, use select(start,end),
+ selectAll(), or selectWord().
+
+ \sa selectionEnd, cursorPosition, selectedText
+*/
+int QQuickTextInput::selectionStart() const
+{
+ Q_D(const QQuickTextInput);
+ return d->lastSelectionStart;
+}
+/*!
+ \qmlproperty int QtQuick2::TextInput::selectionEnd
+
+ The cursor position after the last character in the current selection.
+
+ This property is read-only. To change the selection, use select(start,end),
+ selectAll(), or selectWord().
+
+ \sa selectionStart, cursorPosition, selectedText
+*/
+int QQuickTextInput::selectionEnd() const
+{
+ Q_D(const QQuickTextInput);
+ return d->lastSelectionEnd;
+}
+/*!
+ \qmlmethod void QtQuick2::TextInput::select(int start, int end)
+
+ Causes the text from \a start to \a end to be selected.
+
+ If either start or end is out of range, the selection is not changed.
+
+ After calling this, selectionStart will become the lesser
+ and selectionEnd will become the greater (regardless of the order passed
+ to this method).
+
+ \sa selectionStart, selectionEnd
+*/
+void QQuickTextInput::select(int start, int end)
+{
+ Q_D(QQuickTextInput);
+ if (start < 0 || end < 0 || start > d->control->text().length() || end > d->control->text().length())
+ return;
+ d->control->setSelection(start, end-start);
+}
+
+/*!
+ \qmlproperty string QtQuick2::TextInput::selectedText
+
+ This read-only property provides the text currently selected in the
+ text input.
+
+ It is equivalent to the following snippet, but is faster and easier
+ to use.
+
+ \js
+ myTextInput.text.toString().substring(myTextInput.selectionStart,
+ myTextInput.selectionEnd);
+ \endjs
+*/
+QString QQuickTextInput::selectedText() const
+{
+ Q_D(const QQuickTextInput);
+ return d->control->selectedText();
+}
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
+
+ Whether the TextInput should gain active focus on a mouse press. By default this is
+ set to true.
+*/
+bool QQuickTextInput::focusOnPress() const
+{
+ Q_D(const QQuickTextInput);
+ return d->focusOnPress;
+}
+
+void QQuickTextInput::setFocusOnPress(bool b)
+{
+ Q_D(QQuickTextInput);
+ if (d->focusOnPress == b)
+ return;
+
+ d->focusOnPress = b;
+
+ emit activeFocusOnPressChanged(d->focusOnPress);
+}
+/*!
+ \qmlproperty bool QtQuick2::TextInput::autoScroll
+
+ Whether the TextInput should scroll when the text is longer than the width. By default this is
+ set to true.
+*/
+bool QQuickTextInput::autoScroll() const
+{
+ Q_D(const QQuickTextInput);
+ return d->autoScroll;
+}
+
+void QQuickTextInput::setAutoScroll(bool b)
+{
+ Q_D(QQuickTextInput);
+ if (d->autoScroll == b)
+ return;
+
+ d->autoScroll = b;
+ //We need to repaint so that the scrolling is taking into account.
+ updateSize(true);
+ updateCursorRectangle();
+ emit autoScrollChanged(d->autoScroll);
+}
+
+#ifndef QT_NO_VALIDATOR
+
+/*!
+ \qmlclass IntValidator QIntValidator
+ \inqmlmodule QtQuick 2
+ \ingroup qml-basic-visual-elements
+
+ This element provides a validator for integer values.
+
+ IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
+ will accept locale specific digits, group separators, and positive and negative signs. In
+ addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
+ locale.
+*/
+/*!
+ \qmlproperty int QtQuick2::IntValidator::top
+
+ This property holds the validator's highest acceptable value.
+ By default, this property's value is derived from the highest signed integer available (typically 2147483647).
+*/
+/*!
+ \qmlproperty int QtQuick2::IntValidator::bottom
+
+ This property holds the validator's lowest acceptable value.
+ By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
+*/
+
+/*!
+ \qmlclass DoubleValidator QDoubleValidator
+ \inqmlmodule QtQuick 2
+ \ingroup qml-basic-visual-elements
+
+ This element provides a validator for non-integer numbers.
+*/
+
+/*!
+ \qmlproperty real QtQuick2::DoubleValidator::top
+
+ This property holds the validator's maximum acceptable value.
+ By default, this property contains a value of infinity.
+*/
+/*!
+ \qmlproperty real QtQuick2::DoubleValidator::bottom
+
+ This property holds the validator's minimum acceptable value.
+ By default, this property contains a value of -infinity.
+*/
+/*!
+ \qmlproperty int QtQuick2::DoubleValidator::decimals
+
+ This property holds the validator's maximum number of digits after the decimal point.
+ By default, this property contains a value of 1000.
+*/
+/*!
+ \qmlproperty enumeration QtQuick2::DoubleValidator::notation
+ This property holds the notation of how a string can describe a number.
+
+ The possible values for this property are:
+
+ \list
+ \o DoubleValidator.StandardNotation
+ \o DoubleValidator.ScientificNotation (default)
+ \endlist
+
+ If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
+*/
+
+/*!
+ \qmlclass RegExpValidator QRegExpValidator
+ \inqmlmodule QtQuick 2
+ \ingroup qml-basic-visual-elements
+
+ This element provides a validator, which counts as valid any string which
+ matches a specified regular expression.
+*/
+/*!
+ \qmlproperty regExp QtQuick2::RegExpValidator::regExp
+
+ This property holds the regular expression used for validation.
+
+ Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
+ matching "a".
+
+ By default, this property contains a regular expression with the pattern .* that matches any string.
+*/
+
+/*!
+ \qmlproperty Validator QtQuick2::TextInput::validator
+
+ Allows you to set a validator on the TextInput. When a validator is set
+ the TextInput will only accept input which leaves the text property in
+ an acceptable or intermediate state. The accepted signal will only be sent
+ if the text is in an acceptable state when enter is pressed.
+
+ Currently supported validators are IntValidator, DoubleValidator and
+ RegExpValidator. An example of using validators is shown below, which allows
+ input of integers between 11 and 31 into the text input:
+
+ \code
+ import QtQuick 1.0
+ TextInput{
+ validator: IntValidator{bottom: 11; top: 31;}
+ focus: true
+ }
+ \endcode
+
+ \sa acceptableInput, inputMask
+*/
+
+QValidator* QQuickTextInput::validator() const
+{
+ Q_D(const QQuickTextInput);
+ //###const cast isn't good, but needed for property system?
+ return const_cast<QValidator*>(d->control->validator());
+}
+
+void QQuickTextInput::setValidator(QValidator* v)
+{
+ Q_D(QQuickTextInput);
+ if (d->control->validator() == v)
+ return;
+
+ d->control->setValidator(v);
+ if (!d->control->hasAcceptableInput()) {
+ d->oldValidity = false;
+ emit acceptableInputChanged();
+ }
+
+ emit validatorChanged();
+}
+#endif // QT_NO_VALIDATOR
+
+/*!
+ \qmlproperty string QtQuick2::TextInput::inputMask
+
+ Allows you to set an input mask on the TextInput, restricting the allowable
+ text inputs. See QLineEdit::inputMask for further details, as the exact
+ same mask strings are used by TextInput.
+
+ \sa acceptableInput, validator
+*/
+QString QQuickTextInput::inputMask() const
+{
+ Q_D(const QQuickTextInput);
+ return d->control->inputMask();
+}
+
+void QQuickTextInput::setInputMask(const QString &im)
+{
+ Q_D(QQuickTextInput);
+ if (d->control->inputMask() == im)
+ return;
+
+ d->control->setInputMask(im);
+ emit inputMaskChanged(d->control->inputMask());
+}
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::acceptableInput
+
+ This property is always true unless a validator or input mask has been set.
+ If a validator or input mask has been set, this property will only be true
+ if the current text is acceptable to the validator or input mask as a final
+ string (not as an intermediate string).
+*/
+bool QQuickTextInput::hasAcceptableInput() const
+{
+ Q_D(const QQuickTextInput);
+ return d->control->hasAcceptableInput();
+}
+
+/*!
+ \qmlsignal QtQuick2::TextInput::onAccepted()
+
+ This handler is called when the Return or Enter key is pressed.
+ Note that if there is a \l validator or \l inputMask set on the text
+ input, the handler will only be emitted if the input is in an acceptable
+ state.
+*/
+
+void QQuickTextInputPrivate::updateInputMethodHints()
+{
+ Q_Q(QQuickTextInput);
+ Qt::InputMethodHints hints = inputMethodHints;
+ uint echo = control->echoMode();
+ if (echo == QQuickTextInput::Password || echo == QQuickTextInput::NoEcho)
+ hints |= Qt::ImhHiddenText;
+ else if (echo == QQuickTextInput::PasswordEchoOnEdit)
+ hints &= ~Qt::ImhHiddenText;
+ if (echo != QQuickTextInput::Normal)
+ hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
+ q->setInputMethodHints(hints);
+}
+/*!
+ \qmlproperty enumeration QtQuick2::TextInput::echoMode
+
+ Specifies how the text should be displayed in the TextInput.
+ \list
+ \o TextInput.Normal - Displays the text as it is. (Default)
+ \o TextInput.Password - Displays asterisks instead of characters.
+ \o TextInput.NoEcho - Displays nothing.
+ \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
+ while editing, otherwise displays asterisks.
+ \endlist
+*/
+QQuickTextInput::EchoMode QQuickTextInput::echoMode() const
+{
+ Q_D(const QQuickTextInput);
+ return (QQuickTextInput::EchoMode)d->control->echoMode();
+}
+
+void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo)
+{
+ Q_D(QQuickTextInput);
+ if (echoMode() == echo)
+ return;
+ d->control->setEchoMode((QLineControl::EchoMode)echo);
+ d->updateInputMethodHints();
+ q_textChanged();
+ emit echoModeChanged(echoMode());
+}
+
+Qt::InputMethodHints QQuickTextInput::imHints() const
+{
+ Q_D(const QQuickTextInput);
+ return d->inputMethodHints;
+}
+
+void QQuickTextInput::setIMHints(Qt::InputMethodHints hints)
+{
+ Q_D(QQuickTextInput);
+ if (d->inputMethodHints == hints)
+ return;
+ d->inputMethodHints = hints;
+ d->updateInputMethodHints();
+}
+
+/*!
+ \qmlproperty Component QtQuick2::TextInput::cursorDelegate
+ The delegate for the cursor in the TextInput.
+
+ If you set a cursorDelegate for a TextInput, this delegate will be used for
+ drawing the cursor instead of the standard cursor. An instance of the
+ delegate will be created and managed by the TextInput when a cursor is
+ needed, and the x property of delegate instance will be set so as
+ to be one pixel before the top left of the current character.
+
+ Note that the root item of the delegate component must be a QDeclarativeItem or
+ QDeclarativeItem derived item.
+*/
+QDeclarativeComponent* QQuickTextInput::cursorDelegate() const
+{
+ Q_D(const QQuickTextInput);
+ return d->cursorComponent;
+}
+
+void QQuickTextInput::setCursorDelegate(QDeclarativeComponent* c)
+{
+ Q_D(QQuickTextInput);
+ if (d->cursorComponent == c)
+ return;
+
+ d->cursorComponent = c;
+ if (!c) {
+ //note that the components are owned by something else
+ delete d->cursorItem;
+ } else {
+ d->startCreatingCursor();
+ }
+
+ emit cursorDelegateChanged();
+}
+
+void QQuickTextInputPrivate::startCreatingCursor()
+{
+ Q_Q(QQuickTextInput);
+ if (cursorComponent->isReady()) {
+ q->createCursor();
+ } else if (cursorComponent->isLoading()) {
+ q->connect(cursorComponent, SIGNAL(statusChanged(int)),
+ q, SLOT(createCursor()));
+ } else { // isError
+ qmlInfo(q, cursorComponent->errors()) << QQuickTextInput::tr("Could not load cursor delegate");
+ }
+}
+
+void QQuickTextInput::createCursor()
+{
+ Q_D(QQuickTextInput);
+ if (d->cursorComponent->isError()) {
+ qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
+ return;
+ }
+
+ if (!d->cursorComponent->isReady())
+ return;
+
+ if (d->cursorItem)
+ delete d->cursorItem;
+ QDeclarativeContext *creationContext = d->cursorComponent->creationContext();
+ QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this));
+ d->cursorItem = qobject_cast<QQuickItem*>(object);
+ if (!d->cursorItem) {
+ delete object;
+ qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
+ return;
+ }
+
+ QDeclarative_setParent_noEvent(d->cursorItem, this);
+ d->cursorItem->setParentItem(this);
+ d->cursorItem->setX(d->control->cursorToX());
+ d->cursorItem->setHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
+}
+
+/*!
+ \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
+
+ This function takes a character position and returns the rectangle that the
+ cursor would occupy, if it was placed at that character position.
+
+ This is similar to setting the cursorPosition, and then querying the cursor
+ rectangle, but the cursorPosition is not changed.
+*/
+QRectF QQuickTextInput::positionToRectangle(int pos) const
+{
+ Q_D(const QQuickTextInput);
+ if (pos > d->control->cursorPosition())
+ pos += d->control->preeditAreaText().length();
+ return QRectF(d->control->cursorToX(pos)-d->hscroll,
+ 0.0,
+ d->control->cursorWidth(),
+ cursorRectangle().height());
+}
+
+/*!
+ \qmlmethod int QtQuick2::TextInput::positionAt(int x, CursorPosition position = CursorBetweenCharacters)
+
+ This function returns the character position at
+ x pixels from the left of the textInput. Position 0 is before the
+ first character, position 1 is after the first character but before the second,
+ and so on until position text.length, which is after all characters.
+
+ This means that for all x values before the first character this function returns 0,
+ and for all x values after the last character this function returns text.length.
+
+ The cursor position type specifies how the cursor position should be resolved.
+
+ \list
+ \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
+ \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
+ \endlist
+*/
+int QQuickTextInput::positionAt(int x) const
+{
+ return positionAt(x, CursorBetweenCharacters);
+}
+
+int QQuickTextInput::positionAt(int x, CursorPosition position) const
+{
+ Q_D(const QQuickTextInput);
+ int pos = d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position));
+ const int cursor = d->control->cursor();
+ if (pos > cursor) {
+ const int preeditLength = d->control->preeditAreaText().length();
+ pos = pos > cursor + preeditLength
+ ? pos - preeditLength
+ : cursor;
+ }
+ return pos;
+}
+
+void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
+{
+ Q_D(QQuickTextInput);
+ // Don't allow MacOSX up/down support, and we don't allow a completer.
+ bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
+ if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
+ // Ignore when moving off the end unless there is a selection,
+ // because then moving will do something (deselect).
+ int cursorPosition = d->control->cursor();
+ if (cursorPosition == 0)
+ ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
+ if (cursorPosition == d->control->text().length())
+ ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
+ }
+ if (ignore) {
+ ev->ignore();
+ } else {
+ d->control->processKeyEvent(ev);
+ }
+ if (!ev->isAccepted())
+ QQuickImplicitSizeItem::keyPressEvent(ev);
+}
+
+void QQuickTextInput::inputMethodEvent(QInputMethodEvent *ev)
+{
+ Q_D(QQuickTextInput);
+ const bool wasComposing = d->control->preeditAreaText().length() > 0;
+ if (d->control->isReadOnly()) {
+ ev->ignore();
+ } else {
+ d->control->processInputMethodEvent(ev);
+ }
+ if (!ev->isAccepted())
+ QQuickImplicitSizeItem::inputMethodEvent(ev);
+
+ if (wasComposing != (d->control->preeditAreaText().length() > 0))
+ emit inputMethodComposingChanged();
+}
+
+void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextInput);
+
+ if (d->selectByMouse && event->button() == Qt::LeftButton) {
+ d->control->commitPreedit();
+ int cursor = d->xToPos(event->localPos().x());
+ d->control->selectWordAtPos(cursor);
+ event->setAccepted(true);
+ if (!d->hasPendingTripleClick()) {
+ d->tripleClickStartPoint = event->localPos().toPoint();
+ d->tripleClickTimer.start();
+ }
+ } else {
+ if (d->sendMouseEventToInputContext(event))
+ return;
+ QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
+ }
+}
+
+void QQuickTextInput::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextInput);
+
+ d->pressPos = event->localPos();
+
+ if (d->focusOnPress) {
+ bool hadActiveFocus = hasActiveFocus();
+ forceActiveFocus();
+ // re-open input panel on press if already focused
+ if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
+ openSoftwareInputPanel();
+ }
+ if (d->selectByMouse) {
+ setKeepMouseGrab(false);
+ d->selectPressed = true;
+ QPoint distanceVector = d->pressPos.toPoint() - d->tripleClickStartPoint;
+ if (d->hasPendingTripleClick()
+ && distanceVector.manhattanLength() < qApp->styleHints()->startDragDistance()) {
+ event->setAccepted(true);
+ selectAll();
+ return;
+ }
+ }
+
+ if (d->sendMouseEventToInputContext(event))
+ return;
+
+ bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
+ int cursor = d->xToPos(event->localPos().x());
+ d->control->moveCursor(cursor, mark);
+ event->setAccepted(true);
+}
+
+void QQuickTextInput::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextInput);
+
+ if (d->selectPressed) {
+ if (qAbs(int(event->localPos().x() - d->pressPos.x())) > qApp->styleHints()->startDragDistance())
+ setKeepMouseGrab(true);
+
+ if (d->control->composeMode()) {
+ // start selection
+ int startPos = d->xToPos(d->pressPos.x());
+ int currentPos = d->xToPos(event->localPos().x());
+ if (startPos != currentPos)
+ d->control->setSelection(startPos, currentPos - startPos);
+ } else {
+ moveCursorSelection(d->xToPos(event->localPos().x()), d->mouseSelectionMode);
+ }
+ event->setAccepted(true);
+ } else {
+ QQuickImplicitSizeItem::mouseMoveEvent(event);
+ }
+}
+
+void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextInput);
+ if (d->sendMouseEventToInputContext(event))
+ return;
+ if (d->selectPressed) {
+ d->selectPressed = false;
+ setKeepMouseGrab(false);
+ }
+ d->control->processEvent(event);
+ if (!event->isAccepted())
+ QQuickImplicitSizeItem::mouseReleaseEvent(event);
+}
+
+bool QQuickTextInputPrivate::sendMouseEventToInputContext(QMouseEvent *event)
+{
+#if !defined QT_NO_IM
+ if (control->composeMode()) {
+ int tmp_cursor = xToPos(event->localPos().x());
+ int mousePos = tmp_cursor - control->cursor();
+ if (mousePos >= 0 && mousePos <= control->preeditAreaText().length()) {
+ if (event->type() == QEvent::MouseButtonRelease) {
+ qApp->inputPanel()->invokeAction(QInputPanel::Click, mousePos);
+ }
+ return true;
+ }
+ }
+#else
+ Q_UNUSED(event);
+ Q_UNUSED(eventType)
+#endif
+
+ return false;
+}
+
+void QQuickTextInput::mouseUngrabEvent()
+{
+ Q_D(QQuickTextInput);
+ d->selectPressed = false;
+ setKeepMouseGrab(false);
+}
+
+bool QQuickTextInput::event(QEvent* ev)
+{
+ Q_D(QQuickTextInput);
+ //Anything we don't deal with ourselves, pass to the control
+ bool handled = false;
+ switch (ev->type()) {
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease://###Should the control be doing anything with release?
+ case QEvent::InputMethod:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ break;
+ default:
+ handled = d->control->processEvent(ev);
+ }
+ if (!handled)
+ handled = QQuickImplicitSizeItem::event(ev);
+ return handled;
+}
+
+void QQuickTextInput::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ if (newGeometry.width() != oldGeometry.width()) {
+ updateSize();
+ updateCursorRectangle();
+ }
+ QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+int QQuickTextInputPrivate::calculateTextWidth()
+{
+ return qRound(control->naturalTextWidth());
+}
+
+void QQuickTextInputPrivate::updateHorizontalScroll()
+{
+ Q_Q(QQuickTextInput);
+ const int preeditLength = control->preeditAreaText().length();
+ const int width = q->width();
+ int widthUsed = calculateTextWidth();
+
+ if (!autoScroll || widthUsed <= width) {
+ QQuickTextInput::HAlignment effectiveHAlign = q->effectiveHAlign();
+ // text fits in br; use hscroll for alignment
+ switch (effectiveHAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
+ case Qt::AlignRight:
+ hscroll = widthUsed - width;
+ break;
+ case Qt::AlignHCenter:
+ hscroll = (widthUsed - width) / 2;
+ break;
+ default:
+ // Left
+ hscroll = 0;
+ break;
+ }
+ } else {
+ int cix = qRound(control->cursorToX(control->cursor() + preeditLength));
+ if (cix - hscroll >= width) {
+ // text doesn't fit, cursor is to the right of br (scroll right)
+ hscroll = cix - width;
+ } else if (cix - hscroll < 0 && hscroll < widthUsed) {
+ // text doesn't fit, cursor is to the left of br (scroll left)
+ hscroll = cix;
+ } else if (widthUsed - hscroll < width) {
+ // text doesn't fit, text document is to the left of br; align
+ // right
+ hscroll = widthUsed - width;
+ }
+ if (preeditLength > 0) {
+ // check to ensure long pre-edit text doesn't push the cursor
+ // off to the left
+ cix = qRound(control->cursorToX(
+ control->cursor() + qMax(0, control->preeditCursor() - 1)));
+ if (cix < hscroll)
+ hscroll = cix;
+ }
+ }
+}
+
+QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_UNUSED(data);
+ Q_D(QQuickTextInput);
+
+ QQuickTextNode *node = static_cast<QQuickTextNode *>(oldNode);
+ if (node == 0)
+ node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
+ d->textNode = node;
+
+ if (!d->textLayoutDirty) {
+ QSGSimpleRectNode *cursorNode = node->cursorNode();
+ if (cursorNode != 0 && !isReadOnly()) {
+ QFontMetrics fm = QFontMetrics(d->font);
+ // the y offset is there to keep the baseline constant in case we have script changes in the text.
+ QPoint offset(-d->hscroll, fm.ascent() - d->control->ascent());
+ offset.rx() += d->control->cursorToX();
+
+ QRect br(boundingRect().toRect());
+ cursorNode->setRect(QRectF(offset, QSizeF(d->control->cursorWidth(), br.height())));
+
+ if (!d->cursorVisible
+ || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) {
+ d->hideCursor();
+ } else {
+ d->showCursor();
+ }
+ }
+ } else {
+ node->deleteContent();
+ node->setMatrix(QMatrix4x4());
+
+ QPoint offset = QPoint(0,0);
+ QFontMetrics fm = QFontMetrics(d->font);
+ QRect br(boundingRect().toRect());
+ if (d->autoScroll) {
+ // the y offset is there to keep the baseline constant in case we have script changes in the text.
+ offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
+ } else {
+ offset = QPoint(d->hscroll, 0);
+ }
+
+ QTextLayout *textLayout = d->control->textLayout();
+ if (!textLayout->text().isEmpty()) {
+ node->addTextLayout(offset, textLayout, d->color,
+ QQuickText::Normal, QColor(),
+ d->selectionColor, d->selectedTextColor,
+ d->control->selectionStart(),
+ d->control->selectionEnd() - 1); // selectionEnd() returns first char after
+ // selection
+ }
+
+ if (!isReadOnly() && d->cursorItem == 0) {
+ offset.rx() += d->control->cursorToX();
+ node->setCursor(QRectF(offset, QSizeF(d->control->cursorWidth(), br.height())), d->color);
+ if (!d->cursorVisible
+ || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) {
+ d->hideCursor();
+ } else {
+ d->showCursor();
+ }
+ }
+
+ d->textLayoutDirty = false;
+ }
+
+ return node;
+}
+
+QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QQuickTextInput);
+ switch (property) {
+ case Qt::ImEnabled:
+ return QVariant((bool)(flags() & ItemAcceptsInputMethod));
+ case Qt::ImHints:
+ return QVariant((int)inputMethodHints());
+ case Qt::ImCursorRectangle:
+ return cursorRectangle();
+ case Qt::ImFont:
+ return font();
+ case Qt::ImCursorPosition:
+ return QVariant(d->control->cursor());
+ case Qt::ImSurroundingText:
+ if (d->control->echoMode() == QLineControl::PasswordEchoOnEdit
+ && !d->control->passwordEchoEditing()) {
+ return QVariant(displayText());
+ } else {
+ return QVariant(d->control->realText());
+ }
+ case Qt::ImCurrentSelection:
+ return QVariant(selectedText());
+ case Qt::ImMaximumTextLength:
+ return QVariant(maxLength());
+ case Qt::ImAnchorPosition:
+ if (d->control->selectionStart() == d->control->selectionEnd())
+ return QVariant(d->control->cursor());
+ else if (d->control->selectionStart() == d->control->cursor())
+ return QVariant(d->control->selectionEnd());
+ else
+ return QVariant(d->control->selectionStart());
+ default:
+ return QVariant();
+ }
+}
+
+/*!
+ \qmlmethod void QtQuick2::TextInput::deselect()
+
+ Removes active text selection.
+*/
+void QQuickTextInput::deselect()
+{
+ Q_D(QQuickTextInput);
+ d->control->deselect();
+}
+
+/*!
+ \qmlmethod void QtQuick2::TextInput::selectAll()
+
+ Causes all text to be selected.
+*/
+void QQuickTextInput::selectAll()
+{
+ Q_D(QQuickTextInput);
+ d->control->setSelection(0, d->control->text().length());
+}
+
+/*!
+ \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
+
+ Returns true if the natural reading direction of the editor text
+ found between positions \a start and \a end is right to left.
+*/
+bool QQuickTextInput::isRightToLeft(int start, int end)
+{
+ Q_D(QQuickTextInput);
+ if (start > end) {
+ qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
+ return false;
+ } else {
+ return d->control->text().mid(start, end - start).isRightToLeft();
+ }
+}
+
+#ifndef QT_NO_CLIPBOARD
+/*!
+ \qmlmethod QtQuick2::TextInput::cut()
+
+ Moves the currently selected text to the system clipboard.
+*/
+void QQuickTextInput::cut()
+{
+ Q_D(QQuickTextInput);
+ d->control->copy();
+ d->control->del();
+}
+
+/*!
+ \qmlmethod QtQuick2::TextInput::copy()
+
+ Copies the currently selected text to the system clipboard.
+*/
+void QQuickTextInput::copy()
+{
+ Q_D(QQuickTextInput);
+ d->control->copy();
+}
+
+/*!
+ \qmlmethod QtQuick2::TextInput::paste()
+
+ Replaces the currently selected text by the contents of the system clipboard.
+*/
+void QQuickTextInput::paste()
+{
+ Q_D(QQuickTextInput);
+ if (!d->control->isReadOnly())
+ d->control->paste();
+}
+#endif // QT_NO_CLIPBOARD
+
+/*!
+ \qmlmethod void QtQuick2::TextInput::selectWord()
+
+ Causes the word closest to the current cursor position to be selected.
+*/
+void QQuickTextInput::selectWord()
+{
+ Q_D(QQuickTextInput);
+ d->control->selectWordAtPos(d->control->cursor());
+}
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::smooth
+
+ This property holds whether the text is smoothly scaled or transformed.
+
+ Smooth filtering gives better visual quality, but is slower. If
+ the item is displayed at its natural size, this property has no visual or
+ performance effect.
+
+ \note Generally scaling artifacts are only visible if the item is stationary on
+ the screen. A common pattern when animating an item is to disable smooth
+ filtering at the beginning of the animation and reenable it at the conclusion.
+*/
+
+/*!
+ \qmlproperty string QtQuick2::TextInput::passwordCharacter
+
+ This is the character displayed when echoMode is set to Password or
+ PasswordEchoOnEdit. By default it is an asterisk.
+
+ If this property is set to a string with more than one character,
+ the first character is used. If the string is empty, the value
+ is ignored and the property is not set.
+*/
+QString QQuickTextInput::passwordCharacter() const
+{
+ Q_D(const QQuickTextInput);
+ return QString(d->control->passwordCharacter());
+}
+
+void QQuickTextInput::setPasswordCharacter(const QString &str)
+{
+ Q_D(QQuickTextInput);
+ if (str.length() < 1)
+ return;
+ d->control->setPasswordCharacter(str.constData()[0]);
+ EchoMode echoMode_ = echoMode();
+ if (echoMode_ == Password || echoMode_ == PasswordEchoOnEdit) {
+ updateSize();
+ }
+ emit passwordCharacterChanged();
+}
+
+/*!
+ \qmlproperty string QtQuick2::TextInput::displayText
+
+ This is the text displayed in the TextInput.
+
+ If \l echoMode is set to TextInput::Normal, this holds the
+ same value as the TextInput::text property. Otherwise,
+ this property holds the text visible to the user, while
+ the \l text property holds the actual entered text.
+*/
+QString QQuickTextInput::displayText() const
+{
+ Q_D(const QQuickTextInput);
+ return d->control->displayText();
+}
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::selectByMouse
+
+ Defaults to false.
+
+ If true, the user can use the mouse to select text in some
+ platform-specific way. Note that for some platforms this may
+ not be an appropriate interaction (eg. may conflict with how
+ the text needs to behave inside a Flickable.
+*/
+bool QQuickTextInput::selectByMouse() const
+{
+ Q_D(const QQuickTextInput);
+ return d->selectByMouse;
+}
+
+void QQuickTextInput::setSelectByMouse(bool on)
+{
+ Q_D(QQuickTextInput);
+ if (d->selectByMouse != on) {
+ d->selectByMouse = on;
+ emit selectByMouseChanged(on);
+ }
+}
+
+/*!
+ \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
+
+ Specifies how text should be selected using a mouse.
+
+ \list
+ \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
+ \o TextInput.SelectWords - The selection is updated with whole words.
+ \endlist
+
+ This property only applies when \l selectByMouse is true.
+*/
+
+QQuickTextInput::SelectionMode QQuickTextInput::mouseSelectionMode() const
+{
+ Q_D(const QQuickTextInput);
+ return d->mouseSelectionMode;
+}
+
+void QQuickTextInput::setMouseSelectionMode(SelectionMode mode)
+{
+ Q_D(QQuickTextInput);
+ if (d->mouseSelectionMode != mode) {
+ d->mouseSelectionMode = mode;
+ emit mouseSelectionModeChanged(mode);
+ }
+}
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::canPaste
+
+ Returns true if the TextInput is writable and the content of the clipboard is
+ suitable for pasting into the TextEdit.
+*/
+bool QQuickTextInput::canPaste() const
+{
+ Q_D(const QQuickTextInput);
+ return d->canPaste;
+}
+
+void QQuickTextInput::moveCursorSelection(int position)
+{
+ Q_D(QQuickTextInput);
+ d->control->moveCursor(position, true);
+}
+
+/*!
+ \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
+
+ Moves the cursor to \a position and updates the selection according to the optional \a mode
+ parameter. (To only move the cursor, set the \l cursorPosition property.)
+
+ When this method is called it additionally sets either the
+ selectionStart or the selectionEnd (whichever was at the previous cursor position)
+ to the specified position. This allows you to easily extend and contract the selected
+ text range.
+
+ The selection mode specifies whether the selection is updated on a per character or a per word
+ basis. If not specified the selection mode will default to TextInput.SelectCharacters.
+
+ \list
+ \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
+ the previous cursor position) to the specified position.
+ \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
+ words between the specified position and the previous cursor position. Words partially in the
+ range are included.
+ \endlist
+
+ For example, take this sequence of calls:
+
+ \code
+ cursorPosition = 5
+ moveCursorSelection(9, TextInput.SelectCharacters)
+ moveCursorSelection(7, TextInput.SelectCharacters)
+ \endcode
+
+ This moves the cursor to position 5, extend the selection end from 5 to 9
+ and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
+ selected (the 6th and 7th characters).
+
+ The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
+ before or on position 5 and extend the selection end to a word boundary on or past position 9.
+*/
+void QQuickTextInput::moveCursorSelection(int pos, SelectionMode mode)
+{
+ Q_D(QQuickTextInput);
+
+ if (mode == SelectCharacters) {
+ d->control->moveCursor(pos, true);
+ } else if (pos != d->control->cursor()){
+ const int cursor = d->control->cursor();
+ int anchor;
+ if (!d->control->hasSelectedText())
+ anchor = d->control->cursor();
+ else if (d->control->selectionStart() == d->control->cursor())
+ anchor = d->control->selectionEnd();
+ else
+ anchor = d->control->selectionStart();
+
+ if (anchor < pos || (anchor == pos && cursor < pos)) {
+ const QString text = d->control->text();
+ QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
+ finder.setPosition(anchor);
+
+ const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
+ if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
+ || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
+ finder.toPreviousBoundary();
+ }
+ anchor = finder.position() != -1 ? finder.position() : 0;
+
+ finder.setPosition(pos);
+ if (pos > 0 && !finder.boundaryReasons())
+ finder.toNextBoundary();
+ const int cursor = finder.position() != -1 ? finder.position() : text.length();
+
+ d->control->setSelection(anchor, cursor - anchor);
+ } else if (anchor > pos || (anchor == pos && cursor > pos)) {
+ const QString text = d->control->text();
+ QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
+ finder.setPosition(anchor);
+
+ const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
+ if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
+ || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
+ finder.toNextBoundary();
+ }
+
+ anchor = finder.position() != -1 ? finder.position() : text.length();
+
+ finder.setPosition(pos);
+ if (pos < text.length() && !finder.boundaryReasons())
+ finder.toPreviousBoundary();
+ const int cursor = finder.position() != -1 ? finder.position() : 0;
+
+ d->control->setSelection(anchor, cursor - anchor);
+ }
+ }
+}
+
+/*!
+ \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
+
+ Opens software input panels like virtual keyboards for typing, useful for
+ customizing when you want the input keyboard to be shown and hidden in
+ your application.
+
+ By default the opening of input panels follows the platform style. Input panels are
+ always closed if no editor has active focus.
+
+ You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
+ and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
+ the behavior you want.
+
+ Only relevant on platforms, which provide virtual keyboards.
+
+ \qml
+ import QtQuick 1.0
+ TextInput {
+ id: textInput
+ text: "Hello world!"
+ activeFocusOnPress: false
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (!textInput.activeFocus) {
+ textInput.forceActiveFocus()
+ textInput.openSoftwareInputPanel();
+ } else {
+ textInput.focus = false;
+ }
+ }
+ onPressAndHold: textInput.closeSoftwareInputPanel();
+ }
+ }
+ \endqml
+*/
+void QQuickTextInput::openSoftwareInputPanel()
+{
+ if (qGuiApp)
+ qGuiApp->inputPanel()->show();
+}
+
+/*!
+ \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
+
+ Closes a software input panel like a virtual keyboard shown on the screen, useful
+ for customizing when you want the input keyboard to be shown and hidden in
+ your application.
+
+ By default the opening of input panels follows the platform style. Input panels are
+ always closed if no editor has active focus.
+
+ You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
+ and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
+ the behavior you want.
+
+ Only relevant on platforms, which provide virtual keyboards.
+
+ \qml
+ import QtQuick 1.0
+ TextInput {
+ id: textInput
+ text: "Hello world!"
+ activeFocusOnPress: false
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (!textInput.activeFocus) {
+ textInput.forceActiveFocus();
+ textInput.openSoftwareInputPanel();
+ } else {
+ textInput.focus = false;
+ }
+ }
+ onPressAndHold: textInput.closeSoftwareInputPanel();
+ }
+ }
+ \endqml
+*/
+void QQuickTextInput::closeSoftwareInputPanel()
+{
+ if (qGuiApp)
+ qGuiApp->inputPanel()->hide();
+}
+
+void QQuickTextInput::focusInEvent(QFocusEvent *event)
+{
+ Q_D(const QQuickTextInput);
+ if (d->focusOnPress && !isReadOnly())
+ openSoftwareInputPanel();
+ QQuickImplicitSizeItem::focusInEvent(event);
+}
+
+void QQuickTextInput::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QQuickTextInput);
+ if (change == ItemActiveFocusHasChanged) {
+ bool hasFocus = value.boolValue;
+ d->focused = hasFocus;
+ setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
+ if (echoMode() == QQuickTextInput::PasswordEchoOnEdit && !hasFocus)
+ d->control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events
+ if (!hasFocus)
+ d->control->deselect();
+ }
+ QQuickItem::itemChange(change, value);
+}
+
+/*!
+ \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
+
+
+ This property holds whether the TextInput has partial text input from an
+ input method.
+
+ While it is composing an input method may rely on mouse or key events from
+ the TextInput to edit or commit the partial text. This property can be
+ used to determine when to disable events handlers that may interfere with
+ the correct operation of an input method.
+*/
+bool QQuickTextInput::isInputMethodComposing() const
+{
+ Q_D(const QQuickTextInput);
+ return d->control->preeditAreaText().length() > 0;
+}
+
+void QQuickTextInputPrivate::init()
+{
+ Q_Q(QQuickTextInput);
+ control->setParent(q);//Now mandatory due to accessibility changes
+ control->setCursorWidth(1);
+ control->setPasswordCharacter(QLatin1Char('*'));
+ q->setSmooth(smooth);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setFlag(QQuickItem::ItemAcceptsInputMethod);
+ q->setFlag(QQuickItem::ItemHasContents);
+ q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
+ q, SLOT(cursorPosChanged()));
+ q->connect(control, SIGNAL(selectionChanged()),
+ q, SLOT(selectionChanged()));
+ q->connect(control, SIGNAL(textChanged(QString)),
+ q, SLOT(q_textChanged()));
+ q->connect(control, SIGNAL(accepted()),
+ q, SIGNAL(accepted()));
+ q->connect(control, SIGNAL(updateNeeded(QRect)),
+ q, SLOT(updateRect(QRect)));
+#ifndef QT_NO_CLIPBOARD
+ q->connect(q, SIGNAL(readOnlyChanged(bool)),
+ q, SLOT(q_canPasteChanged()));
+ q->connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
+ q, SLOT(q_canPasteChanged()));
+ canPaste = !control->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0;
+#endif // QT_NO_CLIPBOARD
+ q->connect(control, SIGNAL(updateMicroFocus()),
+ q, SLOT(updateCursorRectangle()));
+ q->connect(control, SIGNAL(displayTextChanged(QString)),
+ q, SLOT(updateRect()));
+ q->updateSize();
+ imHints &= ~Qt::ImhMultiLine;
+ oldValidity = control->hasAcceptableInput();
+ lastSelectionStart = 0;
+ lastSelectionEnd = 0;
+ QPalette p = control->palette();
+ selectedTextColor = p.color(QPalette::HighlightedText);
+ selectionColor = p.color(QPalette::Highlight);
+ determineHorizontalAlignment();
+
+ if (!qmlDisableDistanceField()) {
+ QTextOption option = control->textLayout()->textOption();
+ option.setUseDesignMetrics(true);
+ control->textLayout()->setTextOption(option);
+ }
+}
+
+void QQuickTextInput::cursorPosChanged()
+{
+ Q_D(QQuickTextInput);
+ updateCursorRectangle();
+ emit cursorPositionChanged();
+ // XXX todo - not in 4.8?
+#if 0
+ d->control->resetCursorBlinkTimer();
+#endif
+
+ if (!d->control->hasSelectedText()) {
+ if (d->lastSelectionStart != d->control->cursor()) {
+ d->lastSelectionStart = d->control->cursor();
+ emit selectionStartChanged();
+ }
+ if (d->lastSelectionEnd != d->control->cursor()) {
+ d->lastSelectionEnd = d->control->cursor();
+ emit selectionEndChanged();
+ }
+ }
+}
+
+void QQuickTextInput::updateCursorRectangle()
+{
+ Q_D(QQuickTextInput);
+ d->determineHorizontalAlignment();
+ d->updateHorizontalScroll();
+ updateRect();//TODO: Only update rect between pos's
+ updateMicroFocus();
+ emit cursorRectangleChanged();
+ if (d->cursorItem)
+ d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
+}
+
+void QQuickTextInput::selectionChanged()
+{
+ Q_D(QQuickTextInput);
+ updateRect();//TODO: Only update rect in selection
+ emit selectedTextChanged();
+
+ if (d->lastSelectionStart != d->control->selectionStart()) {
+ d->lastSelectionStart = d->control->selectionStart();
+ if (d->lastSelectionStart == -1)
+ d->lastSelectionStart = d->control->cursor();
+ emit selectionStartChanged();
+ }
+ if (d->lastSelectionEnd != d->control->selectionEnd()) {
+ d->lastSelectionEnd = d->control->selectionEnd();
+ if (d->lastSelectionEnd == -1)
+ d->lastSelectionEnd = d->control->cursor();
+ emit selectionEndChanged();
+ }
+}
+
+void QQuickTextInput::q_textChanged()
+{
+ Q_D(QQuickTextInput);
+ emit textChanged();
+ emit displayTextChanged();
+ updateSize();
+ d->determineHorizontalAlignment();
+ d->updateHorizontalScroll();
+ updateMicroFocus();
+ if (hasAcceptableInput() != d->oldValidity) {
+ d->oldValidity = hasAcceptableInput();
+ emit acceptableInputChanged();
+ }
+}
+
+void QQuickTextInputPrivate::showCursor()
+{
+ if (textNode != 0 && textNode->cursorNode() != 0)
+ textNode->cursorNode()->setColor(color);
+}
+
+void QQuickTextInputPrivate::hideCursor()
+{
+ if (textNode != 0 && textNode->cursorNode() != 0)
+ textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
+}
+
+void QQuickTextInput::updateRect(const QRect &r)
+{
+ Q_D(QQuickTextInput);
+ if (!isComponentComplete())
+ return;
+
+ if (r.isEmpty()) {
+ d->textLayoutDirty = true;
+ }
+
+ update();
+}
+
+QRectF QQuickTextInput::boundingRect() const
+{
+ Q_D(const QQuickTextInput);
+ QRectF r = QQuickImplicitSizeItem::boundingRect();
+
+ int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->control->cursorWidth();
+
+ // Could include font max left/right bearings to either side of rectangle.
+
+ r.setRight(r.right() + cursorWidth);
+ return r;
+}
+
+void QQuickTextInput::updateSize(bool needsRedraw)
+{
+ Q_D(QQuickTextInput);
+ int w = width();
+ int h = height();
+ setImplicitSize(d->calculateTextWidth(), d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
+ if (w==width() && h==height() && needsRedraw)
+ update();
+}
+
+void QQuickTextInput::q_canPasteChanged()
+{
+ Q_D(QQuickTextInput);
+ bool old = d->canPaste;
+#ifndef QT_NO_CLIPBOARD
+ d->canPaste = !d->control->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0;
+#endif
+ if (d->canPaste != old)
+ emit canPasteChanged();
+}
+
+QT_END_NAMESPACE
+