diff options
Diffstat (limited to 'src/declarative/items/qquicktextedit.cpp')
-rw-r--r-- | src/declarative/items/qquicktextedit.cpp | 2091 |
1 files changed, 0 insertions, 2091 deletions
diff --git a/src/declarative/items/qquicktextedit.cpp b/src/declarative/items/qquicktextedit.cpp deleted file mode 100644 index b40b5c09a1..0000000000 --- a/src/declarative/items/qquicktextedit.cpp +++ /dev/null @@ -1,2091 +0,0 @@ -/**************************************************************************** -** -** 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 "qquicktextedit_p.h" -#include "qquicktextedit_p_p.h" -#include "qquickevents_p_p.h" -#include "qquickcanvas.h" -#include "qquicktextnode_p.h" -#include "qsgsimplerectnode.h" - -#include <QtDeclarative/qdeclarativeinfo.h> -#include <QtGui/qguiapplication.h> -#include <QtGui/qevent.h> -#include <QtGui/qpainter.h> -#include <QtGui/qtextobject.h> -#include <QtCore/qmath.h> - -#include <private/qdeclarativeglobal_p.h> -#include <private/qtextcontrol_p.h> -#include <private/qtextengine_p.h> -#include <private/qsgtexture_p.h> -#include <private/qsgadaptationlayer_p.h> - -QT_BEGIN_NAMESPACE - -DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) -DEFINE_BOOL_CONFIG_OPTION(qmlEnableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE) - -/*! - \qmlclass TextEdit QQuickTextEdit - \inqmlmodule QtQuick 2 - \ingroup qml-basic-visual-elements - \brief The TextEdit item displays multiple lines of editable formatted text. - \inherits Item - - The TextEdit item displays a block of editable, formatted text. - - It can display both plain and rich text. For example: - - \qml -TextEdit { - width: 240 - text: "<b>Hello</b> <i>World!</i>" - font.family: "Helvetica" - font.pointSize: 20 - color: "blue" - focus: true -} - \endqml - - \image declarative-textedit.gif - - Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus. - - Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific - to a look-and-feel. For example, to add flickable scrolling that follows the cursor: - - \snippet snippets/declarative/texteditor.qml 0 - - A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible - scrollbar, or a scrollbar that fades in to show location, etc. - - Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can - be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely - from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord(). - - You can translate between cursor positions (characters from the start of the document) and pixel - points using positionAt() and positionToRectangle(). - - \sa Text, TextInput, {declarative/text/textselection}{Text Selection example} -*/ - -/*! - \qmlsignal QtQuick2::TextEdit::onLinkActivated(string link) - - This handler is called when the user clicks on a link embedded in the text. - The link must be in rich text or HTML format and the - \a link string provides access to the particular link. -*/ -QQuickTextEdit::QQuickTextEdit(QQuickItem *parent) -: QQuickImplicitSizeItem(*(new QQuickTextEditPrivate), parent) -{ - Q_D(QQuickTextEdit); - d->init(); -} - -QString QQuickTextEdit::text() const -{ - Q_D(const QQuickTextEdit); - -#ifndef QT_NO_TEXTHTMLPARSER - if (d->richText) - return d->document->toHtml(); - else -#endif - return d->document->toPlainText(); -} - -/*! - \qmlproperty string QtQuick2::TextEdit::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::TextEdit::font.bold - - Sets whether the font weight is bold. -*/ - -/*! - \qmlproperty enumeration QtQuick2::TextEdit::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 - TextEdit { text: "Hello"; font.weight: Font.DemiBold } - \endqml -*/ - -/*! - \qmlproperty bool QtQuick2::TextEdit::font.italic - - Sets whether the font has an italic style. -*/ - -/*! - \qmlproperty bool QtQuick2::TextEdit::font.underline - - Sets whether the text is underlined. -*/ - -/*! - \qmlproperty bool QtQuick2::TextEdit::font.strikeout - - Sets whether the font has a strikeout style. -*/ - -/*! - \qmlproperty real QtQuick2::TextEdit::font.pointSize - - Sets the font size in points. The point size must be greater than zero. -*/ - -/*! - \qmlproperty int QtQuick2::TextEdit::font.pixelSize - - Sets the font size in pixels. - - Using this function makes the font device dependent. Use - \l{TextEdit::font.pointSize} to set the size of the font in a - device independent manner. -*/ - -/*! - \qmlproperty real QtQuick2::TextEdit::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::TextEdit::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::TextEdit::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 - TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase } - \endqml -*/ - -/*! - \qmlproperty string QtQuick2::TextEdit::text - - The text to display. If the text format is AutoText the text edit will - automatically determine whether the text should be treated as - rich text. This determination is made using Qt::mightBeRichText(). -*/ -void QQuickTextEdit::setText(const QString &text) -{ - Q_D(QQuickTextEdit); - if (QQuickTextEdit::text() == text) - return; - - d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text)); - if (d->richText) { -#ifndef QT_NO_TEXTHTMLPARSER - d->control->setHtml(text); -#else - d->control->setPlainText(text); -#endif - d->useImageFallback = qmlEnableImageCache(); - } else { - d->control->setPlainText(text); - } - q_textChanged(); -} - -/*! - \qmlproperty enumeration QtQuick2::TextEdit::textFormat - - The way the text property should be displayed. - - \list - \o TextEdit.AutoText - \o TextEdit.PlainText - \o TextEdit.RichText - \endlist - - The default is TextEdit.AutoText. If the text format is TextEdit.AutoText the text edit - will automatically determine whether the text should be treated as - rich text. This determination is made using Qt::mightBeRichText(). - - \table - \row - \o - \qml -Column { - TextEdit { - font.pointSize: 24 - text: "<b>Hello</b> <i>World!</i>" - } - TextEdit { - font.pointSize: 24 - textFormat: TextEdit.RichText - text: "<b>Hello</b> <i>World!</i>" - } - TextEdit { - font.pointSize: 24 - textFormat: TextEdit.PlainText - text: "<b>Hello</b> <i>World!</i>" - } -} - \endqml - \o \image declarative-textformat.png - \endtable -*/ -QQuickTextEdit::TextFormat QQuickTextEdit::textFormat() const -{ - Q_D(const QQuickTextEdit); - return d->format; -} - -void QQuickTextEdit::setTextFormat(TextFormat format) -{ - Q_D(QQuickTextEdit); - if (format == d->format) - return; - bool wasRich = d->richText; - d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text)); - - if (wasRich && !d->richText) { - d->control->setPlainText(d->text); - updateSize(); - } else if (!wasRich && d->richText) { -#ifndef QT_NO_TEXTHTMLPARSER - d->control->setHtml(d->text); -#else - d->control->setPlainText(d->text); -#endif - updateSize(); - d->useImageFallback = qmlEnableImageCache(); - } - d->format = format; - d->control->setAcceptRichText(d->format != PlainText); - emit textFormatChanged(d->format); -} - -QFont QQuickTextEdit::font() const -{ - Q_D(const QQuickTextEdit); - return d->sourceFont; -} - -void QQuickTextEdit::setFont(const QFont &font) -{ - Q_D(QQuickTextEdit); - 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->document->setDefaultFont(d->font); - if (d->cursor) { - d->cursor->setHeight(QFontMetrics(d->font).height()); - moveCursorDelegate(); - } - updateSize(); - updateDocument(); - } - emit fontChanged(d->sourceFont); -} - -/*! - \qmlproperty color QtQuick2::TextEdit::color - - The text color. - - \qml - // green text using hexadecimal notation - TextEdit { color: "#00FF00" } - \endqml - - \qml - // steelblue text using SVG color name - TextEdit { color: "steelblue" } - \endqml -*/ -QColor QQuickTextEdit::color() const -{ - Q_D(const QQuickTextEdit); - return d->color; -} - -void QQuickTextEdit::setColor(const QColor &color) -{ - Q_D(QQuickTextEdit); - if (d->color == color) - return; - - d->color = color; - QPalette pal = d->control->palette(); - pal.setColor(QPalette::Text, color); - d->control->setPalette(pal); - updateDocument(); - emit colorChanged(d->color); -} - -/*! - \qmlproperty color QtQuick2::TextEdit::selectionColor - - The text highlight color, used behind selections. -*/ -QColor QQuickTextEdit::selectionColor() const -{ - Q_D(const QQuickTextEdit); - return d->selectionColor; -} - -void QQuickTextEdit::setSelectionColor(const QColor &color) -{ - Q_D(QQuickTextEdit); - if (d->selectionColor == color) - return; - - d->selectionColor = color; - QPalette pal = d->control->palette(); - pal.setColor(QPalette::Highlight, color); - d->control->setPalette(pal); - updateDocument(); - emit selectionColorChanged(d->selectionColor); -} - -/*! - \qmlproperty color QtQuick2::TextEdit::selectedTextColor - - The selected text color, used in selections. -*/ -QColor QQuickTextEdit::selectedTextColor() const -{ - Q_D(const QQuickTextEdit); - return d->selectedTextColor; -} - -void QQuickTextEdit::setSelectedTextColor(const QColor &color) -{ - Q_D(QQuickTextEdit); - if (d->selectedTextColor == color) - return; - - d->selectedTextColor = color; - QPalette pal = d->control->palette(); - pal.setColor(QPalette::HighlightedText, color); - d->control->setPalette(pal); - updateDocument(); - emit selectedTextColorChanged(d->selectedTextColor); -} - -/*! - \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment - \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment - \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment - - Sets the horizontal and vertical alignment of the text within the TextEdit 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. - - Valid values for \c horizontalAlignment are: - \list - \o TextEdit.AlignLeft (default) - \o TextEdit.AlignRight - \o TextEdit.AlignHCenter - \o TextEdit.AlignJustify - \endlist - - Valid values for \c verticalAlignment are: - \list - \o TextEdit.AlignTop (default) - \o TextEdit.AlignBottom - \o TextEdit.AlignVCenter - \endlist - - 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 TextEdit, use the read-only property \c effectiveHorizontalAlignment. -*/ -QQuickTextEdit::HAlignment QQuickTextEdit::hAlign() const -{ - Q_D(const QQuickTextEdit); - return d->hAlign; -} - -void QQuickTextEdit::setHAlign(HAlignment align) -{ - Q_D(QQuickTextEdit); - bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror; - d->hAlignImplicit = false; - if (d->setHAlign(align, forceAlign) && isComponentComplete()) { - d->updateDefaultTextOption(); - updateSize(); - } -} - -void QQuickTextEdit::resetHAlign() -{ - Q_D(QQuickTextEdit); - d->hAlignImplicit = true; - if (d->determineHorizontalAlignment() && isComponentComplete()) { - d->updateDefaultTextOption(); - updateSize(); - } -} - -QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign() const -{ - Q_D(const QQuickTextEdit); - QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign; - if (!d->hAlignImplicit && d->effectiveLayoutMirror) { - switch (d->hAlign) { - case QQuickTextEdit::AlignLeft: - effectiveAlignment = QQuickTextEdit::AlignRight; - break; - case QQuickTextEdit::AlignRight: - effectiveAlignment = QQuickTextEdit::AlignLeft; - break; - default: - break; - } - } - return effectiveAlignment; -} - -bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment alignment, bool forceAlign) -{ - Q_Q(QQuickTextEdit); - if (hAlign != alignment || forceAlign) { - QQuickTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign(); - hAlign = alignment; - emit q->horizontalAlignmentChanged(alignment); - if (oldEffectiveHAlign != q->effectiveHAlign()) - emit q->effectiveHorizontalAlignmentChanged(); - return true; - } - return false; -} - -bool QQuickTextEditPrivate::determineHorizontalAlignment() -{ - Q_Q(QQuickTextEdit); - if (hAlignImplicit && q->isComponentComplete()) { - bool alignToRight; - if (text.isEmpty()) { - const QString preeditText = control->textCursor().block().layout()->preeditAreaText(); - alignToRight = preeditText.isEmpty() - ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft - : preeditText.isRightToLeft(); - } else { - alignToRight = rightToLeftText; - } - return setHAlign(alignToRight ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft); - } - return false; -} - -void QQuickTextEditPrivate::mirrorChange() -{ - Q_Q(QQuickTextEdit); - if (q->isComponentComplete()) { - if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) { - updateDefaultTextOption(); - q->updateSize(); - emit q->effectiveHorizontalAlignmentChanged(); - } - } -} - -QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const -{ - Q_D(const QQuickTextEdit); - return d->vAlign; -} - -void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment) -{ - Q_D(QQuickTextEdit); - if (alignment == d->vAlign) - return; - d->vAlign = alignment; - d->updateDefaultTextOption(); - updateSize(); - moveCursorDelegate(); - emit verticalAlignmentChanged(d->vAlign); -} -/*! - \qmlproperty enumeration QtQuick2::TextEdit::wrapMode - - Set this property to wrap the text to the TextEdit item's width. - The text will only wrap if an explicit width has been set. - - \list - \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width. - \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width. - \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word. - \o TextEdit.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word. - \endlist - - The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap. -*/ -QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode() const -{ - Q_D(const QQuickTextEdit); - return d->wrapMode; -} - -void QQuickTextEdit::setWrapMode(WrapMode mode) -{ - Q_D(QQuickTextEdit); - if (mode == d->wrapMode) - return; - d->wrapMode = mode; - d->updateDefaultTextOption(); - updateSize(); - emit wrapModeChanged(); -} - -/*! - \qmlproperty int QtQuick2::TextEdit::lineCount - - Returns the total number of lines in the textEdit item. -*/ -int QQuickTextEdit::lineCount() const -{ - Q_D(const QQuickTextEdit); - return d->lineCount; -} - -/*! - \qmlproperty int QtQuick2::TextEdit::length - - Returns the total number of plain text characters in the TextEdit item. - - As this number doesn't include any formatting markup it may not be the same as the - length of the string returned by the \l text property. - - This property can be faster than querying the length the \l text property as it doesn't - require any copying or conversion of the TextEdit's internal string data. -*/ - -int QQuickTextEdit::length() const -{ - Q_D(const QQuickTextEdit); - // QTextDocument::characterCount() includes the terminating null character. - return qMax(0, d->document->characterCount() - 1); -} - -/*! - \qmlproperty real QtQuick2::TextEdit::paintedWidth - - Returns the width of the text, including the width past the width - which is covered due to insufficient wrapping if \l wrapMode is set. -*/ -qreal QQuickTextEdit::paintedWidth() const -{ - Q_D(const QQuickTextEdit); - return d->paintedSize.width(); -} - -/*! - \qmlproperty real QtQuick2::TextEdit::paintedHeight - - Returns the height of the text, including the height past the height - that is covered if the text does not fit within the set height. -*/ -qreal QQuickTextEdit::paintedHeight() const -{ - Q_D(const QQuickTextEdit); - return d->paintedSize.height(); -} - -/*! - \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position) - - Returns the rectangle at the given \a position in the text. The x, y, - and height properties correspond to the cursor that would describe - that position. -*/ -QRectF QQuickTextEdit::positionToRectangle(int pos) const -{ - Q_D(const QQuickTextEdit); - QTextCursor c(d->document); - c.setPosition(pos); - return d->control->cursorRect(c); - -} - -/*! - \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y) - - Returns the text position closest to pixel position (\a x, \a y). - - Position 0 is before the first character, position 1 is after the first character - but before the second, and so on until position \l {text}.length, which is after all characters. -*/ -int QQuickTextEdit::positionAt(int x, int y) const -{ - Q_D(const QQuickTextEdit); - int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit); - QTextCursor cursor = d->control->textCursor(); - if (r > cursor.position()) { - // The cursor position includes positions within the preedit text, but only positions in the - // same text block are offset so it is possible to get a position that is either part of the - // preedit or the next text block. - QTextLayout *layout = cursor.block().layout(); - const int preeditLength = layout - ? layout->preeditAreaText().length() - : 0; - if (preeditLength > 0 - && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) { - r = r > cursor.position() + preeditLength - ? r - preeditLength - : cursor.position(); - } - } - return r; -} - -/*! - \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.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 TextEdit.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, TextEdit.SelectCharacters) - moveCursorSelection(7, TextEdit.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 TextEdit.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 QQuickTextEdit::moveCursorSelection(int pos) -{ - //Note that this is the same as setCursorPosition but with the KeepAnchor flag set - Q_D(QQuickTextEdit); - QTextCursor cursor = d->control->textCursor(); - if (cursor.position() == pos) - return; - cursor.setPosition(pos, QTextCursor::KeepAnchor); - d->control->setTextCursor(cursor); -} - -void QQuickTextEdit::moveCursorSelection(int pos, SelectionMode mode) -{ - Q_D(QQuickTextEdit); - QTextCursor cursor = d->control->textCursor(); - if (cursor.position() == pos) - return; - if (mode == SelectCharacters) { - cursor.setPosition(pos, QTextCursor::KeepAnchor); - } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) { - if (cursor.anchor() > cursor.position()) { - cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); - if (cursor.position() == cursor.anchor()) - cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor); - else - cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor); - } else { - cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor); - } - - cursor.setPosition(pos, QTextCursor::KeepAnchor); - cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); - if (cursor.position() != pos) - cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); - } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) { - if (cursor.anchor() < cursor.position()) { - cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor); - } else { - cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); - cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); - if (cursor.position() != cursor.anchor()) { - cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor); - cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor); - } - } - - cursor.setPosition(pos, QTextCursor::KeepAnchor); - cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); - if (cursor.position() != pos) { - cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); - cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor); - } - } - d->control->setTextCursor(cursor); -} - -/*! - \qmlproperty bool QtQuick2::TextEdit::cursorVisible - If true the text edit shows a cursor. - - This property is set and unset when the text edit gets active focus, but it can also - be set directly (useful, for example, if a KeyProxy might forward keys to it). -*/ -bool QQuickTextEdit::isCursorVisible() const -{ - Q_D(const QQuickTextEdit); - return d->cursorVisible; -} - -void QQuickTextEdit::setCursorVisible(bool on) -{ - Q_D(QQuickTextEdit); - if (d->cursorVisible == on) - return; - d->cursorVisible = on; - QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut); - if (!on && !d->persistentSelection) - d->control->setCursorIsFocusIndicator(true); - d->control->processEvent(&focusEvent, QPointF(0, -d->yoff)); - emit cursorVisibleChanged(d->cursorVisible); -} - -/*! - \qmlproperty int QtQuick2::TextEdit::cursorPosition - The position of the cursor in the TextEdit. -*/ -int QQuickTextEdit::cursorPosition() const -{ - Q_D(const QQuickTextEdit); - return d->control->textCursor().position(); -} - -void QQuickTextEdit::setCursorPosition(int pos) -{ - Q_D(QQuickTextEdit); - if (pos < 0 || pos > d->text.length()) - return; - QTextCursor cursor = d->control->textCursor(); - if (cursor.position() == pos && cursor.anchor() == pos) - return; - cursor.setPosition(pos); - d->control->setTextCursor(cursor); -} - -/*! - \qmlproperty Component QtQuick2::TextEdit::cursorDelegate - The delegate for the cursor in the TextEdit. - - If you set a cursorDelegate for a TextEdit, 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 text edit when a cursor is - needed, and the x and y properties 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* QQuickTextEdit::cursorDelegate() const -{ - Q_D(const QQuickTextEdit); - return d->cursorComponent; -} - -void QQuickTextEdit::setCursorDelegate(QDeclarativeComponent* c) -{ - Q_D(QQuickTextEdit); - if (d->cursorComponent) { - if (d->cursor) { - d->control->setCursorWidth(-1); - updateCursor(); - delete d->cursor; - d->cursor = 0; - } - } - d->cursorComponent = c; - if (c && c->isReady()) { - loadCursorDelegate(); - } else { - if (c) - connect(c, SIGNAL(statusChanged()), - this, SLOT(loadCursorDelegate())); - } - - emit cursorDelegateChanged(); -} - -void QQuickTextEdit::loadCursorDelegate() -{ - Q_D(QQuickTextEdit); - if (d->cursorComponent->isLoading()) - return; - QDeclarativeContext *creationContext = d->cursorComponent->creationContext(); - QObject *object = d->cursorComponent->create(creationContext ? creationContext : qmlContext(this)); - d->cursor = qobject_cast<QQuickItem*>(object); - if (d->cursor) { - d->control->setCursorWidth(0); - updateCursor(); - QDeclarative_setParent_noEvent(d->cursor, this); - d->cursor->setParentItem(this); - d->cursor->setHeight(QFontMetrics(d->font).height()); - moveCursorDelegate(); - }else{ - delete object; - qmlInfo(this) << "Error loading cursor delegate."; - } -} - -/*! - \qmlproperty int QtQuick2::TextEdit::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 QQuickTextEdit::selectionStart() const -{ - Q_D(const QQuickTextEdit); - return d->control->textCursor().selectionStart(); -} - -/*! - \qmlproperty int QtQuick2::TextEdit::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 QQuickTextEdit::selectionEnd() const -{ - Q_D(const QQuickTextEdit); - return d->control->textCursor().selectionEnd(); -} - -/*! - \qmlproperty string QtQuick2::TextEdit::selectedText - - This read-only property provides the text currently selected in the - text edit. - - It is equivalent to the following snippet, but is faster and easier - to use. - \code - //myTextEdit is the id of the TextEdit - myTextEdit.text.toString().substring(myTextEdit.selectionStart, - myTextEdit.selectionEnd); - \endcode -*/ -QString QQuickTextEdit::selectedText() const -{ - Q_D(const QQuickTextEdit); - return d->control->textCursor().selectedText(); -} - -/*! - \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress - - Whether the TextEdit should gain active focus on a mouse press. By default this is - set to true. -*/ -bool QQuickTextEdit::focusOnPress() const -{ - Q_D(const QQuickTextEdit); - return d->focusOnPress; -} - -void QQuickTextEdit::setFocusOnPress(bool on) -{ - Q_D(QQuickTextEdit); - if (d->focusOnPress == on) - return; - d->focusOnPress = on; - emit activeFocusOnPressChanged(d->focusOnPress); -} - -/*! - \qmlproperty bool QtQuick2::TextEdit::persistentSelection - - Whether the TextEdit should keep the selection visible when it loses active focus to another - item in the scene. By default this is set to true; -*/ -bool QQuickTextEdit::persistentSelection() const -{ - Q_D(const QQuickTextEdit); - return d->persistentSelection; -} - -void QQuickTextEdit::setPersistentSelection(bool on) -{ - Q_D(QQuickTextEdit); - if (d->persistentSelection == on) - return; - d->persistentSelection = on; - emit persistentSelectionChanged(d->persistentSelection); -} - -/* - \qmlproperty real QtQuick2::TextEdit::textMargin - - The margin, in pixels, around the text in the TextEdit. -*/ -qreal QQuickTextEdit::textMargin() const -{ - Q_D(const QQuickTextEdit); - return d->textMargin; -} - -void QQuickTextEdit::setTextMargin(qreal margin) -{ - Q_D(QQuickTextEdit); - if (d->textMargin == margin) - return; - d->textMargin = margin; - d->document->setDocumentMargin(d->textMargin); - emit textMarginChanged(d->textMargin); -} - -void QQuickTextEdit::geometryChanged(const QRectF &newGeometry, - const QRectF &oldGeometry) -{ - if (newGeometry.width() != oldGeometry.width()) - updateSize(); - QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry); -} - -/*! - Ensures any delayed caching or data loading the class - needs to performed is complete. -*/ -void QQuickTextEdit::componentComplete() -{ - Q_D(QQuickTextEdit); - QQuickImplicitSizeItem::componentComplete(); - - if (d->richText) - d->useImageFallback = qmlEnableImageCache(); - - if (d->dirty) { - d->determineHorizontalAlignment(); - d->updateDefaultTextOption(); - updateSize(); - d->dirty = false; - } - -} -/*! - \qmlproperty bool QtQuick2::TextEdit::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 QQuickTextEdit::selectByMouse() const -{ - Q_D(const QQuickTextEdit); - return d->selectByMouse; -} - -void QQuickTextEdit::setSelectByMouse(bool on) -{ - Q_D(QQuickTextEdit); - if (d->selectByMouse != on) { - d->selectByMouse = on; - setKeepMouseGrab(on); - if (on) - setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse); - else - setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse); - emit selectByMouseChanged(on); - } -} - -/*! - \qmlproperty enum QtQuick2::TextEdit::mouseSelectionMode - - Specifies how text should be selected using a mouse. - - \list - \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default) - \o TextEdit.SelectWords - The selection is updated with whole words. - \endlist - - This property only applies when \l selectByMouse is true. -*/ -QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode() const -{ - Q_D(const QQuickTextEdit); - return d->mouseSelectionMode; -} - -void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode) -{ - Q_D(QQuickTextEdit); - if (d->mouseSelectionMode != mode) { - d->mouseSelectionMode = mode; - d->control->setWordSelectionEnabled(mode == SelectWords); - emit mouseSelectionModeChanged(mode); - } -} - -/*! - \qmlproperty bool QtQuick2::TextEdit::readOnly - - Whether the user can interact with the TextEdit item. If this - property is set to true the text cannot be edited by user interaction. - - By default this property is false. -*/ -void QQuickTextEdit::setReadOnly(bool r) -{ - Q_D(QQuickTextEdit); - if (r == isReadOnly()) - return; - - setFlag(QQuickItem::ItemAcceptsInputMethod, !r); - Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse; - if (d->selectByMouse) - flags = flags | Qt::TextSelectableByMouse; - if (!r) - flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable; - d->control->setTextInteractionFlags(flags); - if (!r) - d->control->moveCursor(QTextCursor::End); - - emit readOnlyChanged(r); -} - -bool QQuickTextEdit::isReadOnly() const -{ - Q_D(const QQuickTextEdit); - return !(d->control->textInteractionFlags() & Qt::TextEditable); -} - -/*! - Sets how the text edit should interact with user input to the given - \a flags. -*/ -void QQuickTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags) -{ - Q_D(QQuickTextEdit); - d->control->setTextInteractionFlags(flags); -} - -/*! - Returns the flags specifying how the text edit should interact - with user input. -*/ -Qt::TextInteractionFlags QQuickTextEdit::textInteractionFlags() const -{ - Q_D(const QQuickTextEdit); - return d->control->textInteractionFlags(); -} - -/*! - \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle - - The rectangle where the text cursor is rendered - within the text edit. Read-only. -*/ -QRect QQuickTextEdit::cursorRectangle() const -{ - Q_D(const QQuickTextEdit); - return d->control->cursorRect().toRect().translated(0,d->yoff); -} - -bool QQuickTextEdit::event(QEvent *event) -{ - Q_D(QQuickTextEdit); - if (event->type() == QEvent::ShortcutOverride) { - d->control->processEvent(event, QPointF(0, -d->yoff)); - return event->isAccepted(); - } - return QQuickImplicitSizeItem::event(event); -} - -/*! -\overload -Handles the given key \a event. -*/ -void QQuickTextEdit::keyPressEvent(QKeyEvent *event) -{ - Q_D(QQuickTextEdit); - d->control->processEvent(event, QPointF(0, -d->yoff)); - if (!event->isAccepted()) - QQuickImplicitSizeItem::keyPressEvent(event); -} - -/*! -\overload -Handles the given key \a event. -*/ -void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event) -{ - Q_D(QQuickTextEdit); - d->control->processEvent(event, QPointF(0, -d->yoff)); - if (!event->isAccepted()) - QQuickImplicitSizeItem::keyReleaseEvent(event); -} - -/*! - \qmlmethod void QtQuick2::TextEdit::deselect() - - Removes active text selection. -*/ -void QQuickTextEdit::deselect() -{ - Q_D(QQuickTextEdit); - QTextCursor c = d->control->textCursor(); - c.clearSelection(); - d->control->setTextCursor(c); -} - -/*! - \qmlmethod void QtQuick2::TextEdit::selectAll() - - Causes all text to be selected. -*/ -void QQuickTextEdit::selectAll() -{ - Q_D(QQuickTextEdit); - d->control->selectAll(); -} - -/*! - \qmlmethod void QtQuick2::TextEdit::selectWord() - - Causes the word closest to the current cursor position to be selected. -*/ -void QQuickTextEdit::selectWord() -{ - Q_D(QQuickTextEdit); - QTextCursor c = d->control->textCursor(); - c.select(QTextCursor::WordUnderCursor); - d->control->setTextCursor(c); -} - -/*! - \qmlmethod void QtQuick2::TextEdit::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 QQuickTextEdit::select(int start, int end) -{ - Q_D(QQuickTextEdit); - if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length()) - return; - QTextCursor cursor = d->control->textCursor(); - cursor.beginEditBlock(); - cursor.setPosition(start, QTextCursor::MoveAnchor); - cursor.setPosition(end, QTextCursor::KeepAnchor); - cursor.endEditBlock(); - d->control->setTextCursor(cursor); - - // QTBUG-11100 - updateSelectionMarkers(); -} - -/*! - \qmlmethod void QtQuick2::TextEdit::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 QQuickTextEdit::isRightToLeft(int start, int end) -{ - Q_D(QQuickTextEdit); - if (start > end) { - qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start."; - return false; - } else { - return d->text.mid(start, end - start).isRightToLeft(); - } -} - -#ifndef QT_NO_CLIPBOARD -/*! - \qmlmethod QtQuick2::TextEdit::cut() - - Moves the currently selected text to the system clipboard. -*/ -void QQuickTextEdit::cut() -{ - Q_D(QQuickTextEdit); - d->control->cut(); -} - -/*! - \qmlmethod QtQuick2::TextEdit::copy() - - Copies the currently selected text to the system clipboard. -*/ -void QQuickTextEdit::copy() -{ - Q_D(QQuickTextEdit); - d->control->copy(); -} - -/*! - \qmlmethod QtQuick2::TextEdit::paste() - - Replaces the currently selected text by the contents of the system clipboard. -*/ -void QQuickTextEdit::paste() -{ - Q_D(QQuickTextEdit); - d->control->paste(); -} -#endif // QT_NO_CLIPBOARD - -/*! -\overload -Handles the given mouse \a event. -*/ -void QQuickTextEdit::mousePressEvent(QMouseEvent *event) -{ - Q_D(QQuickTextEdit); - if (d->focusOnPress){ - bool hadActiveFocus = hasActiveFocus(); - forceActiveFocus(); - // re-open input panel on press if already focused - if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) - openSoftwareInputPanel(); - } - d->control->processEvent(event, QPointF(0, -d->yoff)); - if (!event->isAccepted()) - QQuickImplicitSizeItem::mousePressEvent(event); -} - -/*! -\overload -Handles the given mouse \a event. -*/ -void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event) -{ - Q_D(QQuickTextEdit); - d->control->processEvent(event, QPointF(0, -d->yoff)); - - if (!event->isAccepted()) - QQuickImplicitSizeItem::mouseReleaseEvent(event); -} - -/*! -\overload -Handles the given mouse \a event. -*/ -void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event) -{ - Q_D(QQuickTextEdit); - d->control->processEvent(event, QPointF(0, -d->yoff)); - if (!event->isAccepted()) - QQuickImplicitSizeItem::mouseDoubleClickEvent(event); -} - -/*! -\overload -Handles the given mouse \a event. -*/ -void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event) -{ - Q_D(QQuickTextEdit); - d->control->processEvent(event, QPointF(0, -d->yoff)); - if (!event->isAccepted()) - QQuickImplicitSizeItem::mouseMoveEvent(event); -} - -/*! -\overload -Handles the given input method \a event. -*/ -void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event) -{ - Q_D(QQuickTextEdit); - const bool wasComposing = isInputMethodComposing(); - d->control->processEvent(event, QPointF(0, -d->yoff)); - if (wasComposing != isInputMethodComposing()) - emit inputMethodComposingChanged(); -} - -void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value) -{ - if (change == ItemActiveFocusHasChanged) { - setCursorVisible(value.boolValue); // ### refactor: focus handling && d->canvas && d->canvas->hasFocus()); - } - QQuickItem::itemChange(change, value); -} - -/*! -\overload -Returns the value of the given \a property. -*/ -QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const -{ - Q_D(const QQuickTextEdit); - - QVariant v; - switch (property) { - case Qt::ImEnabled: - v = (bool)(flags() & ItemAcceptsInputMethod); - break; - case Qt::ImHints: - v = (int)inputMethodHints(); - break; - default: - v = d->control->inputMethodQuery(property); - break; - } - return v; - -} - -void QQuickTextEdit::updateImageCache(const QRectF &) -{ - Q_D(QQuickTextEdit); - - // Do we really need the image cache? - if (!d->richText || !d->useImageFallback) { - if (!d->pixmapCache.isNull()) - d->pixmapCache = QPixmap(); - return; - } - - if (width() != d->pixmapCache.width() || height() != d->pixmapCache.height()) - d->pixmapCache = QPixmap(width(), height()); - - if (d->pixmapCache.isNull()) - return; - - // ### Use supplied rect, clear area and update only this part (for cursor updates) - QRectF bounds = QRectF(0, 0, width(), height()); - d->pixmapCache.fill(Qt::transparent); - { - QPainter painter(&d->pixmapCache); - - painter.setRenderHint(QPainter::TextAntialiasing); - painter.translate(0, d->yoff); - - d->control->drawContents(&painter, bounds); - } - -} - -QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) -{ - Q_UNUSED(updatePaintNodeData); - Q_D(QQuickTextEdit); - - QSGNode *currentNode = oldNode; - if (d->richText && d->useImageFallback) { - QSGImageNode *node = 0; - if (oldNode == 0 || d->nodeType != QQuickTextEditPrivate::NodeIsTexture) { - delete oldNode; - node = QQuickItemPrivate::get(this)->sceneGraphContext()->createImageNode(); - d->texture = new QSGPlainTexture(); - d->nodeType = QQuickTextEditPrivate::NodeIsTexture; - currentNode = node; - } else { - node = static_cast<QSGImageNode *>(oldNode); - } - - qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->pixmapCache.toImage()); - node->setTexture(0); - node->setTexture(d->texture); - - node->setTargetRect(QRectF(0, 0, d->pixmapCache.width(), d->pixmapCache.height())); - node->setSourceRect(QRectF(0, 0, 1, 1)); - node->setHorizontalWrapMode(QSGTexture::ClampToEdge); - node->setVerticalWrapMode(QSGTexture::ClampToEdge); - node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that.. - node->update(); - - } else if (oldNode == 0 || d->documentDirty) { - d->documentDirty = false; - -#if defined(Q_OS_MAC) - // Make sure document is relayouted in the paint node on Mac - // to avoid crashes due to the font engines created in the - // shaping process - d->document->markContentsDirty(0, d->document->characterCount()); -#endif - - QQuickTextNode *node = 0; - if (oldNode == 0 || d->nodeType != QQuickTextEditPrivate::NodeIsText) { - delete oldNode; - node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext()); - d->nodeType = QQuickTextEditPrivate::NodeIsText; - currentNode = node; - } else { - node = static_cast<QQuickTextNode *>(oldNode); - } - - node->deleteContent(); - node->setMatrix(QMatrix4x4()); - - QRectF bounds = boundingRect(); - - QColor selectionColor = d->control->palette().color(QPalette::Highlight); - QColor selectedTextColor = d->control->palette().color(QPalette::HighlightedText); - node->addTextDocument(bounds.topLeft(), d->document, d->color, QQuickText::Normal, QColor(), - selectionColor, selectedTextColor, selectionStart(), - selectionEnd() - 1); // selectionEnd() returns first char after - // selection - -#if defined(Q_OS_MAC) - // We also need to make sure the document layout is redone when - // control is returned to the main thread, as all the font engines - // are now owned by the rendering thread - d->document->markContentsDirty(0, d->document->characterCount()); -#endif - } - - if (d->nodeType == QQuickTextEditPrivate::NodeIsText && d->cursorComponent == 0 && !isReadOnly()) { - QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode); - - QColor color = (!d->cursorVisible || !d->control->cursorOn()) - ? QColor(0, 0, 0, 0) - : d->color; - - if (node->cursorNode() == 0) { - node->setCursor(cursorRectangle(), color); - } else { - node->cursorNode()->setRect(cursorRectangle()); - node->cursorNode()->setColor(color); - } - - } - - return currentNode; -} - -/*! - \qmlproperty bool QtQuick2::TextEdit::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 bool QtQuick2::TextEdit::canPaste - - Returns true if the TextEdit is writable and the content of the clipboard is - suitable for pasting into the TextEdit. -*/ -bool QQuickTextEdit::canPaste() const -{ - Q_D(const QQuickTextEdit); - return d->canPaste; -} - -/*! - \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing - - - This property holds whether the TextEdit has partial text input from an - input method. - - While it is composing an input method may rely on mouse or key events from - the TextEdit 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 QQuickTextEdit::isInputMethodComposing() const -{ - Q_D(const QQuickTextEdit); - if (QTextLayout *layout = d->control->textCursor().block().layout()) - return layout->preeditAreaText().length() > 0; - return false; -} - -void QQuickTextEditPrivate::init() -{ - Q_Q(QQuickTextEdit); - - q->setSmooth(smooth); - q->setAcceptedMouseButtons(Qt::LeftButton); - q->setFlag(QQuickItem::ItemAcceptsInputMethod); - q->setFlag(QQuickItem::ItemHasContents); - - control = new QTextControl(q); - control->setIgnoreUnusedNavigationEvents(true); - control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable); - control->setDragEnabled(false); - - // By default, QTextControl will issue both a updateCursorRequest() and an updateRequest() - // when the cursor needs to be repainted. We need the signals to be separate to be able to - // distinguish the cursor updates so that we can avoid updating the whole subtree when the - // cursor blinks. - if (!QObject::disconnect(control, SIGNAL(updateCursorRequest(QRectF)), - control, SIGNAL(updateRequest(QRectF)))) { - qWarning("QQuickTextEditPrivate::init: Failed to disconnect updateCursorRequest and updateRequest"); - } - - // QTextControl follows the default text color - // defined by the platform, declarative text - // should be black by default - QPalette pal = control->palette(); - if (pal.color(QPalette::Text) != color) { - pal.setColor(QPalette::Text, color); - control->setPalette(pal); - } - - QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument())); - QObject::connect(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor())); - QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); - QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); - QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); - QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); - QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); - QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate())); - QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString))); -#ifndef QT_NO_CLIPBOARD - QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged())); - QObject::connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged())); - canPaste = control->canPaste(); -#endif - - document = control->document(); - document->setDefaultFont(font); - document->setDocumentMargin(textMargin); - document->setUndoRedoEnabled(false); // flush undo buffer. - document->setUndoRedoEnabled(true); - updateDefaultTextOption(); -} - -void QQuickTextEdit::q_textChanged() -{ - Q_D(QQuickTextEdit); - d->text = text(); - d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft(); - d->determineHorizontalAlignment(); - d->updateDefaultTextOption(); - updateSize(); - updateTotalLines(); - emit textChanged(d->text); -} - -void QQuickTextEdit::moveCursorDelegate() -{ - Q_D(QQuickTextEdit); - d->determineHorizontalAlignment(); - updateMicroFocus(); - emit cursorRectangleChanged(); - if (!d->cursor) - return; - QRectF cursorRect = cursorRectangle(); - d->cursor->setX(cursorRect.x()); - d->cursor->setY(cursorRect.y()); -} - -void QQuickTextEditPrivate::updateSelection() -{ - Q_Q(QQuickTextEdit); - QTextCursor cursor = control->textCursor(); - bool startChange = (lastSelectionStart != cursor.selectionStart()); - bool endChange = (lastSelectionEnd != cursor.selectionEnd()); - cursor.beginEditBlock(); - cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor); - cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); - cursor.endEditBlock(); - control->setTextCursor(cursor); - if (startChange) - q->selectionStartChanged(); - if (endChange) - q->selectionEndChanged(); -} - -void QQuickTextEdit::updateSelectionMarkers() -{ - Q_D(QQuickTextEdit); - if (d->lastSelectionStart != d->control->textCursor().selectionStart()) { - d->lastSelectionStart = d->control->textCursor().selectionStart(); - emit selectionStartChanged(); - } - if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) { - d->lastSelectionEnd = d->control->textCursor().selectionEnd(); - emit selectionEndChanged(); - } -} - -QRectF QQuickTextEdit::boundingRect() const -{ - Q_D(const QQuickTextEdit); - QRectF r = QQuickImplicitSizeItem::boundingRect(); - int cursorWidth = 1; - if (d->cursor) - cursorWidth = d->cursor->width(); - if (!d->document->isEmpty()) - cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor - - // Could include font max left/right bearings to either side of rectangle. - - r.setRight(r.right() + cursorWidth); - return r.translated(0,d->yoff); -} - -qreal QQuickTextEditPrivate::getImplicitWidth() const -{ - Q_Q(const QQuickTextEdit); - if (!requireImplicitWidth) { - // We don't calculate implicitWidth unless it is required. - // We need to force a size update now to ensure implicitWidth is calculated - const_cast<QQuickTextEditPrivate*>(this)->requireImplicitWidth = true; - const_cast<QQuickTextEdit*>(q)->updateSize(); - } - return implicitWidth; -} - -//### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't -// need to do all the calculations each time -void QQuickTextEdit::updateSize() -{ - Q_D(QQuickTextEdit); - if (isComponentComplete()) { - qreal naturalWidth = d->implicitWidth; - // ### assumes that if the width is set, the text will fill to edges - // ### (unless wrap is false, then clipping will occur) - if (widthValid()) { - if (!d->requireImplicitWidth) { - emit implicitWidthChanged(); - // if the implicitWidth is used, then updateSize() has already been called (recursively) - if (d->requireImplicitWidth) - return; - } - if (d->requireImplicitWidth) { - d->document->setTextWidth(-1); - naturalWidth = d->document->idealWidth(); - } - if (d->document->textWidth() != width()) - d->document->setTextWidth(width()); - } else { - d->document->setTextWidth(-1); - } - QFontMetrics fm = QFontMetrics(d->font); - int dy = height(); - dy -= (int)d->document->size().height(); - - int nyoff; - if (heightValid()) { - if (d->vAlign == AlignBottom) - nyoff = dy; - else if (d->vAlign == AlignVCenter) - nyoff = dy/2; - else - nyoff = 0; - } else { - nyoff = 0; - } - if (nyoff != d->yoff) - d->yoff = nyoff; - setBaselineOffset(fm.ascent() + d->yoff + d->textMargin); - - //### need to comfirm cost of always setting these - int newWidth = qCeil(d->document->idealWidth()); - if (!widthValid() && d->document->textWidth() != newWidth) - d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug) - // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed. - qreal iWidth = -1; - if (!widthValid()) - iWidth = newWidth; - else if (d->requireImplicitWidth) - iWidth = naturalWidth; - qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height(); - if (iWidth > -1) - setImplicitSize(iWidth, newHeight); - else - setImplicitHeight(newHeight); - - d->paintedSize = QSize(newWidth, newHeight); - emit paintedSizeChanged(); - } else { - d->dirty = true; - } - updateDocument(); -} - -void QQuickTextEdit::updateDocument() -{ - Q_D(QQuickTextEdit); - d->documentDirty = true; - - if (isComponentComplete()) { - updateImageCache(); - update(); - } -} - -void QQuickTextEdit::updateCursor() -{ - Q_D(QQuickTextEdit); - if (isComponentComplete()) { - updateImageCache(d->control->cursorRect()); - update(); - } -} - -void QQuickTextEdit::updateTotalLines() -{ - Q_D(QQuickTextEdit); - - int subLines = 0; - - for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) { - QTextLayout *layout = it.layout(); - if (!layout) - continue; - subLines += layout->lineCount()-1; - } - - int newTotalLines = d->document->lineCount() + subLines; - if (d->lineCount != newTotalLines) { - d->lineCount = newTotalLines; - emit lineCountChanged(); - } -} - -void QQuickTextEditPrivate::updateDefaultTextOption() -{ - Q_Q(QQuickTextEdit); - QTextOption opt = document->defaultTextOption(); - int oldAlignment = opt.alignment(); - - QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign(); - if (rightToLeftText) { - if (horizontalAlignment == QQuickTextEdit::AlignLeft) - horizontalAlignment = QQuickTextEdit::AlignRight; - else if (horizontalAlignment == QQuickTextEdit::AlignRight) - horizontalAlignment = QQuickTextEdit::AlignLeft; - } - opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign)); - - QTextOption::WrapMode oldWrapMode = opt.wrapMode(); - opt.setWrapMode(QTextOption::WrapMode(wrapMode)); - - bool oldUseDesignMetrics = opt.useDesignMetrics(); - bool useDesignMetrics = !qmlDisableDistanceField(); - opt.setUseDesignMetrics(useDesignMetrics); - - if (oldWrapMode == opt.wrapMode() - && oldAlignment == opt.alignment() - && oldUseDesignMetrics == useDesignMetrics) { - return; - } - document->setDefaultTextOption(opt); -} - - - -/*! - \qmlmethod void QtQuick2::TextEdit::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. - - \code - import QtQuick 1.0 - TextEdit { - id: textEdit - text: "Hello world!" - activeFocusOnPress: false - MouseArea { - anchors.fill: parent - onClicked: { - if (!textEdit.activeFocus) { - textEdit.forceActiveFocus(); - textEdit.openSoftwareInputPanel(); - } else { - textEdit.focus = false; - } - } - onPressAndHold: textEdit.closeSoftwareInputPanel(); - } - } - \endcode -*/ -void QQuickTextEdit::openSoftwareInputPanel() -{ - if (qGuiApp) - qGuiApp->inputPanel()->show(); -} - -/*! - \qmlmethod void QtQuick2::TextEdit::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. - - \code - import QtQuick 1.0 - TextEdit { - id: textEdit - text: "Hello world!" - activeFocusOnPress: false - MouseArea { - anchors.fill: parent - onClicked: { - if (!textEdit.activeFocus) { - textEdit.forceActiveFocus(); - textEdit.openSoftwareInputPanel(); - } else { - textEdit.focus = false; - } - } - onPressAndHold: textEdit.closeSoftwareInputPanel(); - } - } - \endcode -*/ -void QQuickTextEdit::closeSoftwareInputPanel() -{ - if (qGuiApp) - qGuiApp->inputPanel()->hide(); -} - -void QQuickTextEdit::focusInEvent(QFocusEvent *event) -{ - Q_D(const QQuickTextEdit); - if (d->focusOnPress && !isReadOnly()) - openSoftwareInputPanel(); - QQuickImplicitSizeItem::focusInEvent(event); -} - -void QQuickTextEdit::q_canPasteChanged() -{ - Q_D(QQuickTextEdit); - bool old = d->canPaste; - d->canPaste = d->control->canPaste(); - if (old!=d->canPaste) - emit canPasteChanged(); -} - -/*! - \qmlmethod string QtQuick2::TextEdit::getText(int start, int end) - - Returns the section of text that is between the \a start and \a end positions. - - The returned text does not include any rich text formatting. -*/ - -QString QQuickTextEdit::getText(int start, int end) const -{ - Q_D(const QQuickTextEdit); - start = qBound(0, start, d->document->characterCount() - 1); - end = qBound(0, end, d->document->characterCount() - 1); - QTextCursor cursor(d->document); - cursor.setPosition(start, QTextCursor::MoveAnchor); - cursor.setPosition(end, QTextCursor::KeepAnchor); - return cursor.selectedText(); -} - -/*! - \qmlmethod string QtQuick2::TextEdit::getFormattedText(int start, int end) - - Returns the section of text that is between the \a start and \a end positions. - - The returned text will be formatted according the \l textFormat property. -*/ - -QString QQuickTextEdit::getFormattedText(int start, int end) const -{ - Q_D(const QQuickTextEdit); - - start = qBound(0, start, d->document->characterCount() - 1); - end = qBound(0, end, d->document->characterCount() - 1); - - QTextCursor cursor(d->document); - cursor.setPosition(start, QTextCursor::MoveAnchor); - cursor.setPosition(end, QTextCursor::KeepAnchor); - - if (d->richText) { -#ifndef QT_NO_TEXTHTMLPARSER - return cursor.selection().toHtml(); -#else - return cursor.selection().toPlainText(); -#endif - } else { - return cursor.selection().toPlainText(); - } -} - -/*! - \qmlmethod void QtQuick2::TextEdit::insert(int position, string text) - - Inserts \a text into the TextEdit at position. -*/ -void QQuickTextEdit::insert(int position, const QString &text) -{ - Q_D(QQuickTextEdit); - if (position < 0 || position >= d->document->characterCount()) - return; - QTextCursor cursor(d->document); - cursor.setPosition(position); - d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text)); - if (d->richText) { -#ifndef QT_NO_TEXTHTMLPARSER - cursor.insertHtml(text); -#else - cursor.insertText(text); -#endif - } else { - cursor.insertText(text); - } -} - -/*! - \qmlmethod string QtQuick2::TextEdit::getText(int start, int end) - - Removes the section of text that is between the \a start and \a end positions from the TextEdit. -*/ - -void QQuickTextEdit::remove(int start, int end) -{ - Q_D(QQuickTextEdit); - start = qBound(0, start, d->document->characterCount() - 1); - end = qBound(0, end, d->document->characterCount() - 1); - QTextCursor cursor(d->document); - cursor.setPosition(start, QTextCursor::MoveAnchor); - cursor.setPosition(end, QTextCursor::KeepAnchor); - cursor.removeSelectedText(); -} - -QT_END_NAMESPACE |