QQuickCanvas renames
[profile/ivi/qtdeclarative.git] / src / quick / items / qquicktextedit.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquicktextedit_p.h"
43 #include "qquicktextedit_p_p.h"
44 #include "qquicktextcontrol_p.h"
45 #include "qquicktext_p_p.h"
46 #include "qquickevents_p_p.h"
47 #include "qquickwindow.h"
48 #include "qquicktextnode_p.h"
49 #include "qquicktextutil_p.h"
50 #include <QtQuick/qsgsimplerectnode.h>
51
52 #include <QtQml/qqmlinfo.h>
53 #include <QtGui/qguiapplication.h>
54 #include <QtGui/qevent.h>
55 #include <QtGui/qpainter.h>
56 #include <QtGui/qtextobject.h>
57 #include <QtCore/qmath.h>
58
59 #include <private/qqmlglobal_p.h>
60 #include <private/qqmlproperty_p.h>
61 #include <private/qtextengine_p.h>
62 #include <private/qsgadaptationlayer_p.h>
63
64
65 QT_BEGIN_NAMESPACE
66
67 /*!
68     \qmlclass TextEdit QQuickTextEdit
69     \inqmlmodule QtQuick 2
70     \ingroup qtquick-visual
71     \ingroup qtquick-input
72     \inherits Item
73     \brief Displays multiple lines of editable formatted text
74
75     The TextEdit item displays a block of editable, formatted text.
76
77     It can display both plain and rich text. For example:
78
79     \qml
80 TextEdit {
81     width: 240
82     text: "<b>Hello</b> <i>World!</i>"
83     font.family: "Helvetica"
84     font.pointSize: 20
85     color: "blue"
86     focus: true
87 }
88     \endqml
89
90     \image declarative-textedit.gif
91
92     Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
93
94     Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
95     to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
96
97     \snippet qml/texteditor.qml 0
98
99     A particular look-and-feel might use smooth scrolling (eg. using SmoothedAnimation), might have a visible
100     scrollbar, or a scrollbar that fades in to show location, etc.
101
102     Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
103     be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
104     from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
105
106     You can translate between cursor positions (characters from the start of the document) and pixel
107     points using positionAt() and positionToRectangle().
108
109     \sa Text, TextInput, {examples/quick/text/textselection}{Text Selection example}
110 */
111
112 /*!
113     \qmlsignal QtQuick2::TextEdit::onLinkActivated(string link)
114
115     This handler is called when the user clicks on a link embedded in the text.
116     The link must be in rich text or HTML format and the
117     \a link string provides access to the particular link.
118 */
119 QQuickTextEdit::QQuickTextEdit(QQuickItem *parent)
120 : QQuickImplicitSizeItem(*(new QQuickTextEditPrivate), parent)
121 {
122     Q_D(QQuickTextEdit);
123     d->init();
124 }
125
126 QString QQuickTextEdit::text() const
127 {
128     Q_D(const QQuickTextEdit);
129     if (!d->textCached) {
130         QQuickTextEditPrivate *d = const_cast<QQuickTextEditPrivate *>(d_func());
131 #ifndef QT_NO_TEXTHTMLPARSER
132         if (d->richText)
133             d->text = d->control->toHtml();
134         else
135 #endif
136             d->text = d->control->toPlainText();
137         d->textCached = true;
138     }
139     return d->text;
140 }
141
142 /*!
143     \qmlproperty string QtQuick2::TextEdit::font.family
144
145     Sets the family name of the font.
146
147     The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
148     If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
149     If the family isn't available a family will be set using the font matching algorithm.
150 */
151
152 /*!
153     \qmlproperty bool QtQuick2::TextEdit::font.bold
154
155     Sets whether the font weight is bold.
156 */
157
158 /*!
159     \qmlproperty enumeration QtQuick2::TextEdit::font.weight
160
161     Sets the font's weight.
162
163     The weight can be one of:
164     \list
165     \li Font.Light
166     \li Font.Normal - the default
167     \li Font.DemiBold
168     \li Font.Bold
169     \li Font.Black
170     \endlist
171
172     \qml
173     TextEdit { text: "Hello"; font.weight: Font.DemiBold }
174     \endqml
175 */
176
177 /*!
178     \qmlproperty bool QtQuick2::TextEdit::font.italic
179
180     Sets whether the font has an italic style.
181 */
182
183 /*!
184     \qmlproperty bool QtQuick2::TextEdit::font.underline
185
186     Sets whether the text is underlined.
187 */
188
189 /*!
190     \qmlproperty bool QtQuick2::TextEdit::font.strikeout
191
192     Sets whether the font has a strikeout style.
193 */
194
195 /*!
196     \qmlproperty real QtQuick2::TextEdit::font.pointSize
197
198     Sets the font size in points. The point size must be greater than zero.
199 */
200
201 /*!
202     \qmlproperty int QtQuick2::TextEdit::font.pixelSize
203
204     Sets the font size in pixels.
205
206     Using this function makes the font device dependent.  Use
207     \l{TextEdit::font.pointSize} to set the size of the font in a
208     device independent manner.
209 */
210
211 /*!
212     \qmlproperty real QtQuick2::TextEdit::font.letterSpacing
213
214     Sets the letter spacing for the font.
215
216     Letter spacing changes the default spacing between individual letters in the font.
217     A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
218 */
219
220 /*!
221     \qmlproperty real QtQuick2::TextEdit::font.wordSpacing
222
223     Sets the word spacing for the font.
224
225     Word spacing changes the default spacing between individual words.
226     A positive value increases the word spacing by a corresponding amount of pixels,
227     while a negative value decreases the inter-word spacing accordingly.
228 */
229
230 /*!
231     \qmlproperty enumeration QtQuick2::TextEdit::font.capitalization
232
233     Sets the capitalization for the text.
234
235     \list
236     \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
237     \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
238     \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
239     \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
240     \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
241     \endlist
242
243     \qml
244     TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
245     \endqml
246 */
247
248 /*!
249     \qmlproperty string QtQuick2::TextEdit::text
250
251     The text to display.  If the text format is AutoText the text edit will
252     automatically determine whether the text should be treated as
253     rich text.  This determination is made using Qt::mightBeRichText().
254 */
255 void QQuickTextEdit::setText(const QString &text)
256 {
257     Q_D(QQuickTextEdit);
258     if (QQuickTextEdit::text() == text)
259         return;
260
261     d->document->clearResources();
262     d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
263     if (!isComponentComplete()) {
264         d->text = text;
265     } else if (d->richText) {
266 #ifndef QT_NO_TEXTHTMLPARSER
267         d->control->setHtml(text);
268 #else
269         d->control->setPlainText(text);
270 #endif
271     } else {
272         d->control->setPlainText(text);
273     }
274 }
275
276 /*!
277     \qmlproperty enumeration QtQuick2::TextEdit::textFormat
278
279     The way the text property should be displayed.
280
281     \list
282     \li TextEdit.AutoText
283     \li TextEdit.PlainText
284     \li TextEdit.RichText
285     \endlist
286
287     The default is TextEdit.PlainText.  If the text format is TextEdit.AutoText the text edit
288     will automatically determine whether the text should be treated as
289     rich text.  This determination is made using Qt::mightBeRichText().
290
291     \table
292     \row
293     \li
294     \qml
295 Column {
296     TextEdit {
297         font.pointSize: 24
298         text: "<b>Hello</b> <i>World!</i>"
299     }
300     TextEdit {
301         font.pointSize: 24
302         textFormat: TextEdit.RichText
303         text: "<b>Hello</b> <i>World!</i>"
304     }
305     TextEdit {
306         font.pointSize: 24
307         textFormat: TextEdit.PlainText
308         text: "<b>Hello</b> <i>World!</i>"
309     }
310 }
311     \endqml
312     \li \image declarative-textformat.png
313     \endtable
314 */
315 QQuickTextEdit::TextFormat QQuickTextEdit::textFormat() const
316 {
317     Q_D(const QQuickTextEdit);
318     return d->format;
319 }
320
321 void QQuickTextEdit::setTextFormat(TextFormat format)
322 {
323     Q_D(QQuickTextEdit);
324     if (format == d->format)
325         return;
326
327     bool wasRich = d->richText;
328     d->richText = format == RichText || (format == AutoText && (wasRich || Qt::mightBeRichText(text())));
329
330 #ifndef QT_NO_TEXTHTMLPARSER
331     if (isComponentComplete()) {
332         if (wasRich && !d->richText) {
333             d->control->setPlainText(!d->textCached ? d->control->toHtml() : d->text);
334             updateSize();
335         } else if (!wasRich && d->richText) {
336             d->control->setHtml(!d->textCached ? d->control->toPlainText() : d->text);
337             updateSize();
338         }
339     }
340 #endif
341
342     d->format = format;
343     d->control->setAcceptRichText(d->format != PlainText);
344     emit textFormatChanged(d->format);
345 }
346
347 /*!
348     \qmlproperty enumeration QtQuick2::TextEdit::renderType
349
350     Override the default rendering type for this component.
351
352     Supported render types are:
353     \list
354     \li Text.QtRendering - the default
355     \li Text.NativeRendering
356     \endlist
357
358     Select Text.NativeRendering if you prefer text to look native on the target platform and do
359     not require advanced features such as transformation of the text. Using such features in
360     combination with the NativeRendering render type will lend poor and sometimes pixelated
361     results.
362 */
363 QQuickTextEdit::RenderType QQuickTextEdit::renderType() const
364 {
365     Q_D(const QQuickTextEdit);
366     return d->renderType;
367 }
368
369 void QQuickTextEdit::setRenderType(QQuickTextEdit::RenderType renderType)
370 {
371     Q_D(QQuickTextEdit);
372     if (d->renderType == renderType)
373         return;
374
375     d->renderType = renderType;
376     emit renderTypeChanged();
377     d->updateDefaultTextOption();
378
379     if (isComponentComplete())
380         updateSize();
381 }
382
383 QFont QQuickTextEdit::font() const
384 {
385     Q_D(const QQuickTextEdit);
386     return d->sourceFont;
387 }
388
389 void QQuickTextEdit::setFont(const QFont &font)
390 {
391     Q_D(QQuickTextEdit);
392     if (d->sourceFont == font)
393         return;
394
395     d->sourceFont = font;
396     QFont oldFont = d->font;
397     d->font = font;
398     if (d->font.pointSizeF() != -1) {
399         // 0.5pt resolution
400         qreal size = qRound(d->font.pointSizeF()*2.0);
401         d->font.setPointSizeF(size/2.0);
402     }
403
404     if (oldFont != d->font) {
405         d->document->setDefaultFont(d->font);
406         if (d->cursorItem) {
407             d->cursorItem->setHeight(QFontMetrics(d->font).height());
408             moveCursorDelegate();
409         }
410         updateSize();
411         updateDocument();
412         updateInputMethod(Qt::ImCursorRectangle | Qt::ImFont);
413     }
414     emit fontChanged(d->sourceFont);
415 }
416
417 /*!
418     \qmlproperty color QtQuick2::TextEdit::color
419
420     The text color.
421
422     \qml
423     // green text using hexadecimal notation
424     TextEdit { color: "#00FF00" }
425     \endqml
426
427     \qml
428     // steelblue text using SVG color name
429     TextEdit { color: "steelblue" }
430     \endqml
431 */
432 QColor QQuickTextEdit::color() const
433 {
434     Q_D(const QQuickTextEdit);
435     return d->color;
436 }
437
438 void QQuickTextEdit::setColor(const QColor &color)
439 {
440     Q_D(QQuickTextEdit);
441     if (d->color == color)
442         return;
443
444     d->color = color;
445     updateDocument();
446     emit colorChanged(d->color);
447 }
448
449 /*!
450     \qmlproperty color QtQuick2::TextEdit::selectionColor
451
452     The text highlight color, used behind selections.
453 */
454 QColor QQuickTextEdit::selectionColor() const
455 {
456     Q_D(const QQuickTextEdit);
457     return d->selectionColor;
458 }
459
460 void QQuickTextEdit::setSelectionColor(const QColor &color)
461 {
462     Q_D(QQuickTextEdit);
463     if (d->selectionColor == color)
464         return;
465
466     d->selectionColor = color;
467     updateDocument();
468     emit selectionColorChanged(d->selectionColor);
469 }
470
471 /*!
472     \qmlproperty color QtQuick2::TextEdit::selectedTextColor
473
474     The selected text color, used in selections.
475 */
476 QColor QQuickTextEdit::selectedTextColor() const
477 {
478     Q_D(const QQuickTextEdit);
479     return d->selectedTextColor;
480 }
481
482 void QQuickTextEdit::setSelectedTextColor(const QColor &color)
483 {
484     Q_D(QQuickTextEdit);
485     if (d->selectedTextColor == color)
486         return;
487
488     d->selectedTextColor = color;
489     updateDocument();
490     emit selectedTextColorChanged(d->selectedTextColor);
491 }
492
493 /*!
494     \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment
495     \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment
496     \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment
497
498     Sets the horizontal and vertical alignment of the text within the TextEdit item's
499     width and height. By default, the text alignment follows the natural alignment
500     of the text, for example text that is read from left to right will be aligned to
501     the left.
502
503     Valid values for \c horizontalAlignment are:
504     \list
505     \li TextEdit.AlignLeft (default)
506     \li TextEdit.AlignRight
507     \li TextEdit.AlignHCenter
508     \li TextEdit.AlignJustify
509     \endlist
510
511     Valid values for \c verticalAlignment are:
512     \list
513     \li TextEdit.AlignTop (default)
514     \li TextEdit.AlignBottom
515     \li TextEdit.AlignVCenter
516     \endlist
517
518     When using the attached property LayoutMirroring::enabled to mirror application
519     layouts, the horizontal alignment of text will also be mirrored. However, the property
520     \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
521     of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
522 */
523 QQuickTextEdit::HAlignment QQuickTextEdit::hAlign() const
524 {
525     Q_D(const QQuickTextEdit);
526     return d->hAlign;
527 }
528
529 void QQuickTextEdit::setHAlign(HAlignment align)
530 {
531     Q_D(QQuickTextEdit);
532     bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
533     d->hAlignImplicit = false;
534     if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
535         d->updateDefaultTextOption();
536         updateSize();
537     }
538 }
539
540 void QQuickTextEdit::resetHAlign()
541 {
542     Q_D(QQuickTextEdit);
543     d->hAlignImplicit = true;
544     if (d->determineHorizontalAlignment() && isComponentComplete()) {
545         d->updateDefaultTextOption();
546         updateSize();
547     }
548 }
549
550 QQuickTextEdit::HAlignment QQuickTextEdit::effectiveHAlign() const
551 {
552     Q_D(const QQuickTextEdit);
553     QQuickTextEdit::HAlignment effectiveAlignment = d->hAlign;
554     if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
555         switch (d->hAlign) {
556         case QQuickTextEdit::AlignLeft:
557             effectiveAlignment = QQuickTextEdit::AlignRight;
558             break;
559         case QQuickTextEdit::AlignRight:
560             effectiveAlignment = QQuickTextEdit::AlignLeft;
561             break;
562         default:
563             break;
564         }
565     }
566     return effectiveAlignment;
567 }
568
569 bool QQuickTextEditPrivate::setHAlign(QQuickTextEdit::HAlignment alignment, bool forceAlign)
570 {
571     Q_Q(QQuickTextEdit);
572     if (hAlign != alignment || forceAlign) {
573         QQuickTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
574         hAlign = alignment;
575         emit q->horizontalAlignmentChanged(alignment);
576         if (oldEffectiveHAlign != q->effectiveHAlign())
577             emit q->effectiveHorizontalAlignmentChanged();
578         return true;
579     }
580     return false;
581 }
582
583
584 Qt::LayoutDirection QQuickTextEditPrivate::textDirection(const QString &text) const
585 {
586     const QChar *character = text.constData();
587     while (!character->isNull()) {
588         switch (character->direction()) {
589         case QChar::DirL:
590             return Qt::LeftToRight;
591         case QChar::DirR:
592         case QChar::DirAL:
593         case QChar::DirAN:
594             return Qt::RightToLeft;
595         default:
596             break;
597         }
598         character++;
599     }
600     return Qt::LayoutDirectionAuto;
601 }
602
603 bool QQuickTextEditPrivate::determineHorizontalAlignment()
604 {
605     Q_Q(QQuickTextEdit);
606     if (hAlignImplicit && q->isComponentComplete()) {
607         Qt::LayoutDirection direction = contentDirection;
608         if (direction == Qt::LayoutDirectionAuto) {
609             const QString preeditText = control->textCursor().block().layout()->preeditAreaText();
610             direction = textDirection(preeditText);
611         }
612         if (direction == Qt::LayoutDirectionAuto)
613             direction = qGuiApp->inputMethod()->inputDirection();
614
615         return setHAlign(direction == Qt::RightToLeft ? QQuickTextEdit::AlignRight : QQuickTextEdit::AlignLeft);
616     }
617     return false;
618 }
619
620 void QQuickTextEditPrivate::mirrorChange()
621 {
622     Q_Q(QQuickTextEdit);
623     if (q->isComponentComplete()) {
624         if (!hAlignImplicit && (hAlign == QQuickTextEdit::AlignRight || hAlign == QQuickTextEdit::AlignLeft)) {
625             updateDefaultTextOption();
626             q->updateSize();
627             emit q->effectiveHorizontalAlignmentChanged();
628         }
629     }
630 }
631
632 QQuickTextEdit::VAlignment QQuickTextEdit::vAlign() const
633 {
634     Q_D(const QQuickTextEdit);
635     return d->vAlign;
636 }
637
638 void QQuickTextEdit::setVAlign(QQuickTextEdit::VAlignment alignment)
639 {
640     Q_D(QQuickTextEdit);
641     if (alignment == d->vAlign)
642         return;
643     d->vAlign = alignment;
644     d->updateDefaultTextOption();
645     updateSize();
646     moveCursorDelegate();
647     emit verticalAlignmentChanged(d->vAlign);
648 }
649 /*!
650     \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
651
652     Set this property to wrap the text to the TextEdit item's width.
653     The text will only wrap if an explicit width has been set.
654
655     \list
656     \li TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
657     \li TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
658     \li TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
659     \li 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.
660     \endlist
661
662     The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
663 */
664 QQuickTextEdit::WrapMode QQuickTextEdit::wrapMode() const
665 {
666     Q_D(const QQuickTextEdit);
667     return d->wrapMode;
668 }
669
670 void QQuickTextEdit::setWrapMode(WrapMode mode)
671 {
672     Q_D(QQuickTextEdit);
673     if (mode == d->wrapMode)
674         return;
675     d->wrapMode = mode;
676     d->updateDefaultTextOption();
677     updateSize();
678     emit wrapModeChanged();
679 }
680
681 /*!
682     \qmlproperty int QtQuick2::TextEdit::lineCount
683
684     Returns the total number of lines in the textEdit item.
685 */
686 int QQuickTextEdit::lineCount() const
687 {
688     Q_D(const QQuickTextEdit);
689     return d->lineCount;
690 }
691
692 /*!
693     \qmlproperty int QtQuick2::TextEdit::length
694
695     Returns the total number of plain text characters in the TextEdit item.
696
697     As this number doesn't include any formatting markup it may not be the same as the
698     length of the string returned by the \l text property.
699
700     This property can be faster than querying the length the \l text property as it doesn't
701     require any copying or conversion of the TextEdit's internal string data.
702 */
703
704 int QQuickTextEdit::length() const
705 {
706     Q_D(const QQuickTextEdit);
707     // QTextDocument::characterCount() includes the terminating null character.
708     return qMax(0, d->document->characterCount() - 1);
709 }
710
711 /*!
712     \qmlproperty real QtQuick2::TextEdit::contentWidth
713
714     Returns the width of the text, including the width past the width
715     which is covered due to insufficient wrapping if \l wrapMode is set.
716 */
717 qreal QQuickTextEdit::contentWidth() const
718 {
719     Q_D(const QQuickTextEdit);
720     return d->contentSize.width();
721 }
722
723 /*!
724     \qmlproperty real QtQuick2::TextEdit::contentHeight
725
726     Returns the height of the text, including the height past the height
727     that is covered if the text does not fit within the set height.
728 */
729 qreal QQuickTextEdit::contentHeight() const
730 {
731     Q_D(const QQuickTextEdit);
732     return d->contentSize.height();
733 }
734
735 /*!
736     \qmlproperty url QtQuick2::TextEdit::baseUrl
737
738     This property specifies a base URL which is used to resolve relative URLs
739     within the text.
740
741     The default value is the url of the QML file instantiating the TextEdit item.
742 */
743
744 QUrl QQuickTextEdit::baseUrl() const
745 {
746     Q_D(const QQuickTextEdit);
747     if (d->baseUrl.isEmpty()) {
748         if (QQmlContext *context = qmlContext(this))
749             const_cast<QQuickTextEditPrivate *>(d)->baseUrl = context->baseUrl();
750     }
751     return d->baseUrl;
752 }
753
754 void QQuickTextEdit::setBaseUrl(const QUrl &url)
755 {
756     Q_D(QQuickTextEdit);
757     if (baseUrl() != url) {
758         d->baseUrl = url;
759
760         d->document->setBaseUrl(url, d->richText);
761         emit baseUrlChanged();
762     }
763 }
764
765 void QQuickTextEdit::resetBaseUrl()
766 {
767     if (QQmlContext *context = qmlContext(this))
768         setBaseUrl(context->baseUrl());
769     else
770         setBaseUrl(QUrl());
771 }
772
773 /*!
774     \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
775
776     Returns the rectangle at the given \a position in the text. The x, y,
777     and height properties correspond to the cursor that would describe
778     that position.
779 */
780 QRectF QQuickTextEdit::positionToRectangle(int pos) const
781 {
782     Q_D(const QQuickTextEdit);
783     QTextCursor c(d->document);
784     c.setPosition(pos);
785     return d->control->cursorRect(c).translated(d->xoff, d->yoff);
786
787 }
788
789 /*!
790     \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
791
792     Returns the text position closest to pixel position (\a x, \a y).
793
794     Position 0 is before the first character, position 1 is after the first character
795     but before the second, and so on until position \l {text}.length, which is after all characters.
796 */
797 int QQuickTextEdit::positionAt(qreal x, qreal y) const
798 {
799     Q_D(const QQuickTextEdit);
800     x -= d->xoff;
801     y -= d->yoff;
802
803     int r = d->document->documentLayout()->hitTest(QPointF(x, y), Qt::FuzzyHit);
804     QTextCursor cursor = d->control->textCursor();
805     if (r > cursor.position()) {
806         // The cursor position includes positions within the preedit text, but only positions in the
807         // same text block are offset so it is possible to get a position that is either part of the
808         // preedit or the next text block.
809         QTextLayout *layout = cursor.block().layout();
810         const int preeditLength = layout
811                 ? layout->preeditAreaText().length()
812                 : 0;
813         if (preeditLength > 0
814                 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x, y)) {
815             r = r > cursor.position() + preeditLength
816                     ? r - preeditLength
817                     : cursor.position();
818         }
819     }
820     return r;
821 }
822
823 /*!
824     \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
825
826     Moves the cursor to \a position and updates the selection according to the optional \a mode
827     parameter. (To only move the cursor, set the \l cursorPosition property.)
828
829     When this method is called it additionally sets either the
830     selectionStart or the selectionEnd (whichever was at the previous cursor position)
831     to the specified position. This allows you to easily extend and contract the selected
832     text range.
833
834     The selection mode specifies whether the selection is updated on a per character or a per word
835     basis.  If not specified the selection mode will default to TextEdit.SelectCharacters.
836
837     \list
838     \li TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
839     the previous cursor position) to the specified position.
840     \li TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
841     words between the specified position and the previous cursor position.  Words partially in the
842     range are included.
843     \endlist
844
845     For example, take this sequence of calls:
846
847     \code
848         cursorPosition = 5
849         moveCursorSelection(9, TextEdit.SelectCharacters)
850         moveCursorSelection(7, TextEdit.SelectCharacters)
851     \endcode
852
853     This moves the cursor to position 5, extend the selection end from 5 to 9
854     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
855     selected (the 6th and 7th characters).
856
857     The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
858     before or on position 5 and extend the selection end to a word boundary on or past position 9.
859 */
860 void QQuickTextEdit::moveCursorSelection(int pos)
861 {
862     //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
863     Q_D(QQuickTextEdit);
864     QTextCursor cursor = d->control->textCursor();
865     if (cursor.position() == pos)
866         return;
867     cursor.setPosition(pos, QTextCursor::KeepAnchor);
868     d->control->setTextCursor(cursor);
869 }
870
871 void QQuickTextEdit::moveCursorSelection(int pos, SelectionMode mode)
872 {
873     Q_D(QQuickTextEdit);
874     QTextCursor cursor = d->control->textCursor();
875     if (cursor.position() == pos)
876         return;
877     if (mode == SelectCharacters) {
878         cursor.setPosition(pos, QTextCursor::KeepAnchor);
879     } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
880         if (cursor.anchor() > cursor.position()) {
881             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
882             cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
883             if (cursor.position() == cursor.anchor())
884                 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
885             else
886                 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
887         } else {
888             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
889             cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
890         }
891
892         cursor.setPosition(pos, QTextCursor::KeepAnchor);
893         cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
894         if (cursor.position() != pos)
895             cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
896     } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
897         if (cursor.anchor() < cursor.position()) {
898             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
899             cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
900         } else {
901             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
902             cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
903             cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
904             if (cursor.position() != cursor.anchor()) {
905                 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
906                 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
907             }
908         }
909
910         cursor.setPosition(pos, QTextCursor::KeepAnchor);
911         cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
912         if (cursor.position() != pos) {
913             cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
914             cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
915         }
916     }
917     d->control->setTextCursor(cursor);
918 }
919
920 /*!
921     \qmlproperty bool QtQuick2::TextEdit::cursorVisible
922     If true the text edit shows a cursor.
923
924     This property is set and unset when the text edit gets active focus, but it can also
925     be set directly (useful, for example, if a KeyProxy might forward keys to it).
926 */
927 bool QQuickTextEdit::isCursorVisible() const
928 {
929     Q_D(const QQuickTextEdit);
930     return d->cursorVisible;
931 }
932
933 void QQuickTextEdit::setCursorVisible(bool on)
934 {
935     Q_D(QQuickTextEdit);
936     if (d->cursorVisible == on)
937         return;
938     d->cursorVisible = on;
939     if (on && isComponentComplete())
940         QQuickTextUtil::createCursor(d);
941     if (!on && !d->persistentSelection)
942         d->control->setCursorIsFocusIndicator(true);
943     d->control->setCursorVisible(on);
944     emit cursorVisibleChanged(d->cursorVisible);
945 }
946
947 /*!
948     \qmlproperty int QtQuick2::TextEdit::cursorPosition
949     The position of the cursor in the TextEdit.
950 */
951 int QQuickTextEdit::cursorPosition() const
952 {
953     Q_D(const QQuickTextEdit);
954     return d->control->textCursor().position();
955 }
956
957 void QQuickTextEdit::setCursorPosition(int pos)
958 {
959     Q_D(QQuickTextEdit);
960     if (pos < 0 || pos >= d->document->characterCount()) // characterCount includes the terminating null.
961         return;
962     QTextCursor cursor = d->control->textCursor();
963     if (cursor.position() == pos && cursor.anchor() == pos)
964         return;
965     cursor.setPosition(pos);
966     d->control->setTextCursor(cursor);
967     d->control->updateCursorRectangle(true);
968 }
969
970 /*!
971     \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
972     The delegate for the cursor in the TextEdit.
973
974     If you set a cursorDelegate for a TextEdit, this delegate will be used for
975     drawing the cursor instead of the standard cursor. An instance of the
976     delegate will be created and managed by the text edit when a cursor is
977     needed, and the x and y properties of delegate instance will be set so as
978     to be one pixel before the top left of the current character.
979
980     Note that the root item of the delegate component must be a QQuickItem or
981     QQuickItem derived item.
982 */
983 QQmlComponent* QQuickTextEdit::cursorDelegate() const
984 {
985     Q_D(const QQuickTextEdit);
986     return d->cursorComponent;
987 }
988
989 void QQuickTextEdit::setCursorDelegate(QQmlComponent* c)
990 {
991     Q_D(QQuickTextEdit);
992     QQuickTextUtil::setCursorDelegate(d, c);
993 }
994
995 void QQuickTextEdit::createCursor()
996 {
997     Q_D(QQuickTextEdit);
998     d->cursorPending = true;
999     QQuickTextUtil::createCursor(d);
1000 }
1001
1002 /*!
1003     \qmlproperty int QtQuick2::TextEdit::selectionStart
1004
1005     The cursor position before the first character in the current selection.
1006
1007     This property is read-only. To change the selection, use select(start,end),
1008     selectAll(), or selectWord().
1009
1010     \sa selectionEnd, cursorPosition, selectedText
1011 */
1012 int QQuickTextEdit::selectionStart() const
1013 {
1014     Q_D(const QQuickTextEdit);
1015     return d->control->textCursor().selectionStart();
1016 }
1017
1018 /*!
1019     \qmlproperty int QtQuick2::TextEdit::selectionEnd
1020
1021     The cursor position after the last character in the current selection.
1022
1023     This property is read-only. To change the selection, use select(start,end),
1024     selectAll(), or selectWord().
1025
1026     \sa selectionStart, cursorPosition, selectedText
1027 */
1028 int QQuickTextEdit::selectionEnd() const
1029 {
1030     Q_D(const QQuickTextEdit);
1031     return d->control->textCursor().selectionEnd();
1032 }
1033
1034 /*!
1035     \qmlproperty string QtQuick2::TextEdit::selectedText
1036
1037     This read-only property provides the text currently selected in the
1038     text edit.
1039
1040     It is equivalent to the following snippet, but is faster and easier
1041     to use.
1042     \code
1043     //myTextEdit is the id of the TextEdit
1044     myTextEdit.text.toString().substring(myTextEdit.selectionStart,
1045             myTextEdit.selectionEnd);
1046     \endcode
1047 */
1048 QString QQuickTextEdit::selectedText() const
1049 {
1050     Q_D(const QQuickTextEdit);
1051 #ifndef QT_NO_TEXTHTMLPARSER
1052     return d->richText
1053             ? d->control->textCursor().selectedText()
1054             : d->control->textCursor().selection().toPlainText();
1055 #else
1056     return d->control->textCursor().selection().toPlainText();
1057 #endif
1058 }
1059
1060 /*!
1061     \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
1062
1063     Whether the TextEdit should gain active focus on a mouse press. By default this is
1064     set to true.
1065 */
1066 bool QQuickTextEdit::focusOnPress() const
1067 {
1068     Q_D(const QQuickTextEdit);
1069     return d->focusOnPress;
1070 }
1071
1072 void QQuickTextEdit::setFocusOnPress(bool on)
1073 {
1074     Q_D(QQuickTextEdit);
1075     if (d->focusOnPress == on)
1076         return;
1077     d->focusOnPress = on;
1078     emit activeFocusOnPressChanged(d->focusOnPress);
1079 }
1080
1081 /*!
1082     \qmlproperty bool QtQuick2::TextEdit::persistentSelection
1083
1084     Whether the TextEdit should keep the selection visible when it loses active focus to another
1085     item in the scene. By default this is set to true;
1086 */
1087 bool QQuickTextEdit::persistentSelection() const
1088 {
1089     Q_D(const QQuickTextEdit);
1090     return d->persistentSelection;
1091 }
1092
1093 void QQuickTextEdit::setPersistentSelection(bool on)
1094 {
1095     Q_D(QQuickTextEdit);
1096     if (d->persistentSelection == on)
1097         return;
1098     d->persistentSelection = on;
1099     emit persistentSelectionChanged(d->persistentSelection);
1100 }
1101
1102 /*!
1103    \qmlproperty real QtQuick2::TextEdit::textMargin
1104
1105    The margin, in pixels, around the text in the TextEdit.
1106 */
1107 qreal QQuickTextEdit::textMargin() const
1108 {
1109     Q_D(const QQuickTextEdit);
1110     return d->textMargin;
1111 }
1112
1113 void QQuickTextEdit::setTextMargin(qreal margin)
1114 {
1115     Q_D(QQuickTextEdit);
1116     if (d->textMargin == margin)
1117         return;
1118     d->textMargin = margin;
1119     d->document->setDocumentMargin(d->textMargin);
1120     emit textMarginChanged(d->textMargin);
1121 }
1122
1123 /*!
1124     \qmlproperty enumeration QtQuick2::TextEdit::inputMethodHints
1125
1126     Provides hints to the input method about the expected content of the text edit and how it
1127     should operate.
1128
1129     The value is a bit-wise combination of flags or Qt.ImhNone if no hints are set.
1130
1131     Flags that alter behaviour are:
1132
1133     \list
1134     \li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
1135     \li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
1136             in any persistent storage like predictive user dictionary.
1137     \li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
1138             when a sentence ends.
1139     \li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
1140     \li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
1141     \li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
1142     \li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
1143
1144     \li Qt.ImhDate - The text editor functions as a date field.
1145     \li Qt.ImhTime - The text editor functions as a time field.
1146     \endlist
1147
1148     Flags that restrict input (exclusive flags) are:
1149
1150     \list
1151     \li Qt.ImhDigitsOnly - Only digits are allowed.
1152     \li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
1153     \li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
1154     \li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
1155     \li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
1156     \li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
1157     \li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
1158     \endlist
1159
1160     Masks:
1161
1162     \list
1163     \li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
1164     \endlist
1165 */
1166
1167 Qt::InputMethodHints QQuickTextEdit::inputMethodHints() const
1168 {
1169     Q_D(const QQuickTextEdit);
1170     return d->inputMethodHints;
1171 }
1172
1173 void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints)
1174 {
1175     Q_D(QQuickTextEdit);
1176
1177     if (hints == d->inputMethodHints)
1178         return;
1179
1180     d->inputMethodHints = hints;
1181     updateInputMethod(Qt::ImHints);
1182     emit inputMethodHintsChanged();
1183 }
1184
1185 void QQuickTextEdit::geometryChanged(const QRectF &newGeometry,
1186                                   const QRectF &oldGeometry)
1187 {
1188     Q_D(QQuickTextEdit);
1189     if (newGeometry.width() != oldGeometry.width() && widthValid() && !d->inLayout) {
1190         updateSize();
1191         moveCursorDelegate();
1192     }
1193     QQuickImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1194
1195 }
1196
1197 /*!
1198     Ensures any delayed caching or data loading the class
1199     needs to performed is complete.
1200 */
1201 void QQuickTextEdit::componentComplete()
1202 {
1203     Q_D(QQuickTextEdit);
1204     QQuickImplicitSizeItem::componentComplete();
1205
1206     d->document->setBaseUrl(baseUrl(), d->richText);
1207 #ifndef QT_NO_TEXTHTML_PARSER
1208     if (d->richText)
1209         d->control->setHtml(d->text);
1210     else
1211 #endif
1212     if (!d->text.isEmpty())
1213         d->control->setPlainText(d->text);
1214
1215     if (d->dirty) {
1216         d->determineHorizontalAlignment();
1217         d->updateDefaultTextOption();
1218         updateSize();
1219         d->dirty = false;
1220     }
1221     if (d->cursorComponent && isCursorVisible())
1222         QQuickTextUtil::createCursor(d);
1223 }
1224 /*!
1225     \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1226
1227     Defaults to false.
1228
1229     If true, the user can use the mouse to select text in some
1230     platform-specific way. Note that for some platforms this may
1231     not be an appropriate interaction (eg. may conflict with how
1232     the text needs to behave inside a Flickable.
1233 */
1234 bool QQuickTextEdit::selectByMouse() const
1235 {
1236     Q_D(const QQuickTextEdit);
1237     return d->selectByMouse;
1238 }
1239
1240 void QQuickTextEdit::setSelectByMouse(bool on)
1241 {
1242     Q_D(QQuickTextEdit);
1243     if (d->selectByMouse != on) {
1244         d->selectByMouse = on;
1245         setKeepMouseGrab(on);
1246         if (on)
1247             d->control->setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1248         else
1249             d->control->setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1250         emit selectByMouseChanged(on);
1251     }
1252 }
1253
1254 /*!
1255     \qmlproperty enumeration QtQuick2::TextEdit::mouseSelectionMode
1256
1257     Specifies how text should be selected using a mouse.
1258
1259     \list
1260     \li TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1261     \li TextEdit.SelectWords - The selection is updated with whole words.
1262     \endlist
1263
1264     This property only applies when \l selectByMouse is true.
1265 */
1266 QQuickTextEdit::SelectionMode QQuickTextEdit::mouseSelectionMode() const
1267 {
1268     Q_D(const QQuickTextEdit);
1269     return d->mouseSelectionMode;
1270 }
1271
1272 void QQuickTextEdit::setMouseSelectionMode(SelectionMode mode)
1273 {
1274     Q_D(QQuickTextEdit);
1275     if (d->mouseSelectionMode != mode) {
1276         d->mouseSelectionMode = mode;
1277         d->control->setWordSelectionEnabled(mode == SelectWords);
1278         emit mouseSelectionModeChanged(mode);
1279     }
1280 }
1281
1282 /*!
1283     \qmlproperty bool QtQuick2::TextEdit::readOnly
1284
1285     Whether the user can interact with the TextEdit item. If this
1286     property is set to true the text cannot be edited by user interaction.
1287
1288     By default this property is false.
1289 */
1290 void QQuickTextEdit::setReadOnly(bool r)
1291 {
1292     Q_D(QQuickTextEdit);
1293     if (r == isReadOnly())
1294         return;
1295
1296     setFlag(QQuickItem::ItemAcceptsInputMethod, !r);
1297     Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1298     if (d->selectByMouse)
1299         flags = flags | Qt::TextSelectableByMouse;
1300     if (!r)
1301         flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1302     d->control->setTextInteractionFlags(flags);
1303     if (!r)
1304         d->control->moveCursor(QTextCursor::End);
1305
1306     updateInputMethod(Qt::ImEnabled);
1307     q_canPasteChanged();
1308     emit readOnlyChanged(r);
1309 }
1310
1311 bool QQuickTextEdit::isReadOnly() const
1312 {
1313     Q_D(const QQuickTextEdit);
1314     return !(d->control->textInteractionFlags() & Qt::TextEditable);
1315 }
1316
1317 /*!
1318     \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1319
1320     The rectangle where the standard text cursor is rendered
1321     within the text edit. Read-only.
1322
1323     The position and height of a custom cursorDelegate are updated to follow the cursorRectangle
1324     automatically when it changes.  The width of the delegate is unaffected by changes in the
1325     cursor rectangle.
1326 */
1327 QRectF QQuickTextEdit::cursorRectangle() const
1328 {
1329     Q_D(const QQuickTextEdit);
1330     return d->control->cursorRect().translated(d->xoff, d->yoff);
1331 }
1332
1333 bool QQuickTextEdit::event(QEvent *event)
1334 {
1335     Q_D(QQuickTextEdit);
1336     if (event->type() == QEvent::ShortcutOverride) {
1337         d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1338         return event->isAccepted();
1339     }
1340     return QQuickImplicitSizeItem::event(event);
1341 }
1342
1343 /*!
1344 \overload
1345 Handles the given key \a event.
1346 */
1347 void QQuickTextEdit::keyPressEvent(QKeyEvent *event)
1348 {
1349     Q_D(QQuickTextEdit);
1350     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1351     if (!event->isAccepted())
1352         QQuickImplicitSizeItem::keyPressEvent(event);
1353 }
1354
1355 /*!
1356 \overload
1357 Handles the given key \a event.
1358 */
1359 void QQuickTextEdit::keyReleaseEvent(QKeyEvent *event)
1360 {
1361     Q_D(QQuickTextEdit);
1362     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1363     if (!event->isAccepted())
1364         QQuickImplicitSizeItem::keyReleaseEvent(event);
1365 }
1366
1367 /*!
1368     \qmlmethod void QtQuick2::TextEdit::deselect()
1369
1370     Removes active text selection.
1371 */
1372 void QQuickTextEdit::deselect()
1373 {
1374     Q_D(QQuickTextEdit);
1375     QTextCursor c = d->control->textCursor();
1376     c.clearSelection();
1377     d->control->setTextCursor(c);
1378 }
1379
1380 /*!
1381     \qmlmethod void QtQuick2::TextEdit::selectAll()
1382
1383     Causes all text to be selected.
1384 */
1385 void QQuickTextEdit::selectAll()
1386 {
1387     Q_D(QQuickTextEdit);
1388     d->control->selectAll();
1389 }
1390
1391 /*!
1392     \qmlmethod void QtQuick2::TextEdit::selectWord()
1393
1394     Causes the word closest to the current cursor position to be selected.
1395 */
1396 void QQuickTextEdit::selectWord()
1397 {
1398     Q_D(QQuickTextEdit);
1399     QTextCursor c = d->control->textCursor();
1400     c.select(QTextCursor::WordUnderCursor);
1401     d->control->setTextCursor(c);
1402 }
1403
1404 /*!
1405     \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1406
1407     Causes the text from \a start to \a end to be selected.
1408
1409     If either start or end is out of range, the selection is not changed.
1410
1411     After calling this, selectionStart will become the lesser
1412     and selectionEnd will become the greater (regardless of the order passed
1413     to this method).
1414
1415     \sa selectionStart, selectionEnd
1416 */
1417 void QQuickTextEdit::select(int start, int end)
1418 {
1419     Q_D(QQuickTextEdit);
1420     if (start < 0 || end < 0 || start >= d->document->characterCount() || end >= d->document->characterCount())
1421         return;
1422     QTextCursor cursor = d->control->textCursor();
1423     cursor.beginEditBlock();
1424     cursor.setPosition(start, QTextCursor::MoveAnchor);
1425     cursor.setPosition(end, QTextCursor::KeepAnchor);
1426     cursor.endEditBlock();
1427     d->control->setTextCursor(cursor);
1428
1429     // QTBUG-11100
1430     updateSelectionMarkers();
1431 }
1432
1433 /*!
1434     \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1435
1436     Returns true if the natural reading direction of the editor text
1437     found between positions \a start and \a end is right to left.
1438 */
1439 bool QQuickTextEdit::isRightToLeft(int start, int end)
1440 {
1441     if (start > end) {
1442         qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1443         return false;
1444     } else {
1445         return getText(start, end).isRightToLeft();
1446     }
1447 }
1448
1449 #ifndef QT_NO_CLIPBOARD
1450 /*!
1451     \qmlmethod QtQuick2::TextEdit::cut()
1452
1453     Moves the currently selected text to the system clipboard.
1454 */
1455 void QQuickTextEdit::cut()
1456 {
1457     Q_D(QQuickTextEdit);
1458     d->control->cut();
1459 }
1460
1461 /*!
1462     \qmlmethod QtQuick2::TextEdit::copy()
1463
1464     Copies the currently selected text to the system clipboard.
1465 */
1466 void QQuickTextEdit::copy()
1467 {
1468     Q_D(QQuickTextEdit);
1469     d->control->copy();
1470 }
1471
1472 /*!
1473     \qmlmethod QtQuick2::TextEdit::paste()
1474
1475     Replaces the currently selected text by the contents of the system clipboard.
1476 */
1477 void QQuickTextEdit::paste()
1478 {
1479     Q_D(QQuickTextEdit);
1480     d->control->paste();
1481 }
1482 #endif // QT_NO_CLIPBOARD
1483
1484
1485 /*!
1486     Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1487     current selection, and updates the selection start to the current cursor
1488     position.
1489 */
1490
1491 void QQuickTextEdit::undo()
1492 {
1493     Q_D(QQuickTextEdit);
1494     d->control->undo();
1495 }
1496
1497 /*!
1498     Redoes the last operation if redo is \l {canRedo}{available}.
1499 */
1500
1501 void QQuickTextEdit::redo()
1502 {
1503     Q_D(QQuickTextEdit);
1504     d->control->redo();
1505 }
1506
1507 /*!
1508 \overload
1509 Handles the given mouse \a event.
1510 */
1511 void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
1512 {
1513     Q_D(QQuickTextEdit);
1514     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1515     if (d->focusOnPress){
1516         bool hadActiveFocus = hasActiveFocus();
1517         forceActiveFocus();
1518         // re-open input panel on press if already focused
1519         if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1520             qGuiApp->inputMethod()->show();
1521     }
1522     if (!event->isAccepted())
1523         QQuickImplicitSizeItem::mousePressEvent(event);
1524 }
1525
1526 /*!
1527 \overload
1528 Handles the given mouse \a event.
1529 */
1530 void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
1531 {
1532     Q_D(QQuickTextEdit);
1533     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1534
1535     if (!event->isAccepted())
1536         QQuickImplicitSizeItem::mouseReleaseEvent(event);
1537 }
1538
1539 /*!
1540 \overload
1541 Handles the given mouse \a event.
1542 */
1543 void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
1544 {
1545     Q_D(QQuickTextEdit);
1546     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1547     if (!event->isAccepted())
1548         QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1549 }
1550
1551 /*!
1552 \overload
1553 Handles the given mouse \a event.
1554 */
1555 void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
1556 {
1557     Q_D(QQuickTextEdit);
1558     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1559     if (!event->isAccepted())
1560         QQuickImplicitSizeItem::mouseMoveEvent(event);
1561 }
1562
1563 /*!
1564 \overload
1565 Handles the given input method \a event.
1566 */
1567 void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
1568 {
1569     Q_D(QQuickTextEdit);
1570     const bool wasComposing = isInputMethodComposing();
1571     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1572     setCursorVisible(d->control->cursorVisible());
1573     if (wasComposing != isInputMethodComposing())
1574         emit inputMethodComposingChanged();
1575 }
1576
1577 void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1578 {
1579     Q_D(QQuickTextEdit);
1580     if (change == ItemActiveFocusHasChanged) {
1581         setCursorVisible(value.boolValue);
1582         QFocusEvent focusEvent(value.boolValue ? QEvent::FocusIn : QEvent::FocusOut);
1583         d->control->processEvent(&focusEvent, QPointF(-d->xoff, -d->yoff));
1584         if (value.boolValue) {
1585             q_updateAlignment();
1586             connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1587                     this, SLOT(q_updateAlignment()));
1588         } else {
1589             disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1590                        this, SLOT(q_updateAlignment()));
1591         }
1592     }
1593     QQuickItem::itemChange(change, value);
1594 }
1595
1596 /*!
1597 \overload
1598 Returns the value of the given \a property.
1599 */
1600 QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1601 {
1602     Q_D(const QQuickTextEdit);
1603
1604     QVariant v;
1605     switch (property) {
1606     case Qt::ImEnabled:
1607         v = (bool)(flags() & ItemAcceptsInputMethod);
1608         break;
1609     case Qt::ImHints:
1610         v = (int)inputMethodHints();
1611         break;
1612     default:
1613         v = d->control->inputMethodQuery(property);
1614         break;
1615     }
1616     return v;
1617
1618 }
1619
1620 void QQuickTextEdit::triggerPreprocess()
1621 {
1622     Q_D(QQuickTextEdit);
1623     if (d->updateType == QQuickTextEditPrivate::UpdateNone)
1624         d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
1625     update();
1626 }
1627
1628 QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1629 {
1630     Q_UNUSED(updatePaintNodeData);
1631     Q_D(QQuickTextEdit);
1632
1633     if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != 0) {
1634         // Update done in preprocess() in the nodes
1635         d->updateType = QQuickTextEditPrivate::UpdateNone;
1636         return oldNode;
1637     }
1638
1639     d->updateType = QQuickTextEditPrivate::UpdateNone;
1640
1641     QSGNode *currentNode = oldNode;
1642     if (oldNode == 0 || d->documentDirty) {
1643         d->documentDirty = false;
1644
1645         QQuickTextNode *node = 0;
1646         if (oldNode == 0) {
1647             node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1648             currentNode = node;
1649         } else {
1650             node = static_cast<QQuickTextNode *>(oldNode);
1651         }
1652
1653         node->setUseNativeRenderer(d->renderType == NativeRendering);
1654         node->deleteContent();
1655         node->setMatrix(QMatrix4x4());
1656
1657         node->addTextDocument(QPointF(d->xoff, d->yoff), d->document, d->color, QQuickText::Normal, QColor(),
1658                               QColor(), d->selectionColor, d->selectedTextColor, selectionStart(),
1659                               selectionEnd() - 1);  // selectionEnd() returns first char after
1660                                                     // selection
1661     }
1662
1663     if (d->cursorComponent == 0 && !isReadOnly()) {
1664         QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode);
1665
1666         QColor color = (!d->cursorVisible || !d->control->cursorOn())
1667                 ? QColor(0, 0, 0, 0)
1668                 : d->color;
1669
1670         if (node->cursorNode() == 0) {
1671             node->setCursor(cursorRectangle(), color);
1672         } else {
1673             node->cursorNode()->setRect(cursorRectangle());
1674             node->cursorNode()->setColor(color);
1675         }
1676
1677     }
1678
1679     return currentNode;
1680 }
1681
1682 /*!
1683     \qmlproperty bool QtQuick2::TextEdit::smooth
1684
1685     This property holds whether the text is smoothly scaled or transformed.
1686
1687     Smooth filtering gives better visual quality, but is slower.  If
1688     the item is displayed at its natural size, this property has no visual or
1689     performance effect.
1690
1691     \note Generally scaling artifacts are only visible if the item is stationary on
1692     the screen.  A common pattern when animating an item is to disable smooth
1693     filtering at the beginning of the animation and reenable it at the conclusion.
1694 */
1695
1696 /*!
1697     \qmlproperty bool QtQuick2::TextEdit::canPaste
1698
1699     Returns true if the TextEdit is writable and the content of the clipboard is
1700     suitable for pasting into the TextEdit.
1701 */
1702 bool QQuickTextEdit::canPaste() const
1703 {
1704     Q_D(const QQuickTextEdit);
1705     if (!d->canPasteValid) {
1706         const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
1707         const_cast<QQuickTextEditPrivate *>(d)->canPasteValid = true;
1708     }
1709     return d->canPaste;
1710 }
1711
1712 /*!
1713     \qmlproperty bool QtQuick2::TextEdit::canUndo
1714
1715     Returns true if the TextEdit is writable and there are previous operations
1716     that can be undone.
1717 */
1718
1719 bool QQuickTextEdit::canUndo() const
1720 {
1721     Q_D(const QQuickTextEdit);
1722     return d->document->isUndoAvailable();
1723 }
1724
1725 /*!
1726     \qmlproperty bool QtQuick2::TextEdit::canRedo
1727
1728     Returns true if the TextEdit is writable and there are \l {undo}{undone}
1729     operations that can be redone.
1730 */
1731
1732 bool QQuickTextEdit::canRedo() const
1733 {
1734     Q_D(const QQuickTextEdit);
1735     return d->document->isRedoAvailable();
1736 }
1737
1738 /*!
1739     \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1740
1741
1742     This property holds whether the TextEdit has partial text input from an
1743     input method.
1744
1745     While it is composing an input method may rely on mouse or key events from
1746     the TextEdit to edit or commit the partial text.  This property can be used
1747     to determine when to disable events handlers that may interfere with the
1748     correct operation of an input method.
1749 */
1750 bool QQuickTextEdit::isInputMethodComposing() const
1751 {
1752     Q_D(const QQuickTextEdit);
1753     return d->control->hasImState();
1754 }
1755
1756 void QQuickTextEditPrivate::init()
1757 {
1758     Q_Q(QQuickTextEdit);
1759
1760     q->setSmooth(smooth);
1761     q->setAcceptedMouseButtons(Qt::LeftButton);
1762     q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1763     q->setFlag(QQuickItem::ItemHasContents);
1764
1765     document = new QQuickTextDocumentWithImageResources(q);
1766
1767     control = new QQuickTextControl(document, q);
1768     control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1769     control->setAcceptRichText(false);
1770     control->setCursorIsFocusIndicator(true);
1771
1772     qmlobject_connect(control, QQuickTextControl, SIGNAL(updateRequest()), q, QQuickTextEdit, SLOT(updateDocument()));
1773     qmlobject_connect(control, QQuickTextControl, SIGNAL(updateCursorRequest()), q, QQuickTextEdit, SLOT(updateCursor()));
1774     qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged()));
1775     qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SIGNAL(selectedTextChanged()));
1776     qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SLOT(updateSelectionMarkers()));
1777     qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SLOT(updateSelectionMarkers()));
1778     qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SIGNAL(cursorPositionChanged()));
1779     qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate()));
1780     qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString)));
1781 #ifndef QT_NO_CLIPBOARD
1782     qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()), q, QQuickTextEdit, SLOT(q_canPasteChanged()));
1783 #endif
1784     qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(undoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canUndoChanged()));
1785     qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(redoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canRedoChanged()));
1786     qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()), q, QQuickTextEdit, SLOT(updateSize()));
1787
1788     document->setDefaultFont(font);
1789     document->setDocumentMargin(textMargin);
1790     document->setUndoRedoEnabled(false); // flush undo buffer.
1791     document->setUndoRedoEnabled(true);
1792     updateDefaultTextOption();
1793 }
1794
1795 void QQuickTextEdit::q_textChanged()
1796 {
1797     Q_D(QQuickTextEdit);
1798     d->textCached = false;
1799     for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1800         d->contentDirection = d->textDirection(it.text());
1801         if (d->contentDirection != Qt::LayoutDirectionAuto)
1802             break;
1803     }
1804     d->determineHorizontalAlignment();
1805     d->updateDefaultTextOption();
1806     updateSize();
1807     updateTotalLines();
1808     emit textChanged();
1809 }
1810
1811 void QQuickTextEdit::moveCursorDelegate()
1812 {
1813     Q_D(QQuickTextEdit);
1814     updateInputMethod();
1815     emit cursorRectangleChanged();
1816     if (!d->cursorItem)
1817         return;
1818     QRectF cursorRect = cursorRectangle();
1819     d->cursorItem->setX(cursorRect.x());
1820     d->cursorItem->setY(cursorRect.y());
1821 }
1822
1823 void QQuickTextEdit::updateSelectionMarkers()
1824 {
1825     Q_D(QQuickTextEdit);
1826     if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
1827         d->lastSelectionStart = d->control->textCursor().selectionStart();
1828         emit selectionStartChanged();
1829     }
1830     if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
1831         d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1832         emit selectionEndChanged();
1833     }
1834 }
1835
1836 QRectF QQuickTextEdit::boundingRect() const
1837 {
1838     Q_D(const QQuickTextEdit);
1839     QRectF r(
1840             QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign()),
1841             d->yoff,
1842             d->contentSize.width(),
1843             d->contentSize.height());
1844
1845     int cursorWidth = 1;
1846     if (d->cursorItem)
1847         cursorWidth = 0;
1848     else if (!d->document->isEmpty())
1849         cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1850
1851     // Could include font max left/right bearings to either side of rectangle.
1852     r.setRight(r.right() + cursorWidth);
1853
1854     return r;
1855 }
1856
1857 QRectF QQuickTextEdit::clipRect() const
1858 {
1859     Q_D(const QQuickTextEdit);
1860     QRectF r = QQuickImplicitSizeItem::clipRect();
1861     int cursorWidth = 1;
1862     if (d->cursorItem)
1863         cursorWidth = d->cursorItem->width();
1864     if (!d->document->isEmpty())
1865         cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1866
1867     // Could include font max left/right bearings to either side of rectangle.
1868
1869     r.setRight(r.right() + cursorWidth);
1870     return r;
1871 }
1872
1873 qreal QQuickTextEditPrivate::getImplicitWidth() const
1874 {
1875     Q_Q(const QQuickTextEdit);
1876     if (!requireImplicitWidth) {
1877         // We don't calculate implicitWidth unless it is required.
1878         // We need to force a size update now to ensure implicitWidth is calculated
1879         const_cast<QQuickTextEditPrivate*>(this)->requireImplicitWidth = true;
1880         const_cast<QQuickTextEdit*>(q)->updateSize();
1881     }
1882     return implicitWidth;
1883 }
1884
1885 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1886 //    need to do all the calculations each time
1887 void QQuickTextEdit::updateSize()
1888 {
1889     Q_D(QQuickTextEdit);
1890     if (isComponentComplete()) {
1891         qreal naturalWidth = d->implicitWidth;
1892         // ### assumes that if the width is set, the text will fill to edges
1893         // ### (unless wrap is false, then clipping will occur)
1894         if (widthValid()) {
1895             if (!d->requireImplicitWidth) {
1896                 emit implicitWidthChanged();
1897                 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1898                 if (d->requireImplicitWidth)
1899                     return;
1900             }
1901             if (d->requireImplicitWidth) {
1902                 d->document->setTextWidth(-1);
1903                 naturalWidth = d->document->idealWidth();
1904
1905                 const bool wasInLayout = d->inLayout;
1906                 d->inLayout = true;
1907                 setImplicitWidth(naturalWidth);
1908                 d->inLayout = wasInLayout;
1909                 if (d->inLayout)    // probably the result of a binding loop, but by letting it
1910                     return;         // get this far we'll get a warning to that effect.
1911             }
1912             if (d->document->textWidth() != width())
1913                 d->document->setTextWidth(width());
1914         } else {
1915             d->document->setTextWidth(-1);
1916         }
1917
1918         //### need to confirm cost of always setting these
1919         qreal newWidth = d->document->idealWidth();
1920         if ((!widthValid() || d->wrapMode == NoWrap) && d->document->textWidth() != newWidth)
1921             d->document->setTextWidth(newWidth); // ### Text does not align if width is not set or the idealWidth exceeds the textWidth (QTextDoc bug)
1922         // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1923         qreal iWidth = -1;
1924         if (!widthValid() && !d->requireImplicitWidth)
1925             iWidth = newWidth;
1926
1927         QFontMetricsF fm(d->font);
1928         qreal newHeight = d->document->isEmpty() ? qCeil(fm.height()) : d->document->size().height();
1929
1930         if (iWidth > -1)
1931             setImplicitSize(iWidth, newHeight);
1932         else
1933             setImplicitHeight(newHeight);
1934
1935         d->xoff = QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign());
1936         d->yoff = QQuickTextUtil::alignedY(d->document->size().height(), height(), d->vAlign);
1937         setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1938
1939         QSizeF size(newWidth, newHeight);
1940         if (d->contentSize != size) {
1941             d->contentSize = size;
1942             emit contentSizeChanged();
1943         }
1944     } else {
1945         d->dirty = true;
1946     }
1947     updateDocument();
1948 }
1949
1950 void QQuickTextEdit::updateDocument()
1951 {
1952     Q_D(QQuickTextEdit);
1953     d->documentDirty = true;
1954
1955     if (isComponentComplete()) {
1956         d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1957         update();
1958     }
1959 }
1960
1961 void QQuickTextEdit::updateCursor()
1962 {
1963     Q_D(QQuickTextEdit);
1964     if (isComponentComplete()) {
1965         d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1966         update();
1967     }
1968 }
1969
1970 void QQuickTextEdit::q_updateAlignment()
1971 {
1972     Q_D(QQuickTextEdit);
1973     if (d->determineHorizontalAlignment()) {
1974         d->updateDefaultTextOption();
1975         d->xoff = QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign());
1976         moveCursorDelegate();
1977     }
1978 }
1979
1980 void QQuickTextEdit::updateTotalLines()
1981 {
1982     Q_D(QQuickTextEdit);
1983
1984     int subLines = 0;
1985
1986     for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1987         QTextLayout *layout = it.layout();
1988         if (!layout)
1989             continue;
1990         subLines += layout->lineCount()-1;
1991     }
1992
1993     int newTotalLines = d->document->lineCount() + subLines;
1994     if (d->lineCount != newTotalLines) {
1995         d->lineCount = newTotalLines;
1996         emit lineCountChanged();
1997     }
1998 }
1999
2000 void QQuickTextEditPrivate::updateDefaultTextOption()
2001 {
2002     Q_Q(QQuickTextEdit);
2003     QTextOption opt = document->defaultTextOption();
2004     int oldAlignment = opt.alignment();
2005     Qt::LayoutDirection oldTextDirection = opt.textDirection();
2006
2007     QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
2008     if (contentDirection == Qt::RightToLeft) {
2009         if (horizontalAlignment == QQuickTextEdit::AlignLeft)
2010             horizontalAlignment = QQuickTextEdit::AlignRight;
2011         else if (horizontalAlignment == QQuickTextEdit::AlignRight)
2012             horizontalAlignment = QQuickTextEdit::AlignLeft;
2013     }
2014     if (!hAlignImplicit)
2015         opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
2016     else
2017         opt.setAlignment(Qt::Alignment(vAlign));
2018
2019     if (contentDirection == Qt::LayoutDirectionAuto) {
2020         opt.setTextDirection(qGuiApp->inputMethod()->inputDirection());
2021     } else {
2022         opt.setTextDirection(contentDirection);
2023     }
2024
2025     QTextOption::WrapMode oldWrapMode = opt.wrapMode();
2026     opt.setWrapMode(QTextOption::WrapMode(wrapMode));
2027
2028     bool oldUseDesignMetrics = opt.useDesignMetrics();
2029     opt.setUseDesignMetrics(renderType != QQuickTextEdit::NativeRendering);
2030
2031     if (oldWrapMode != opt.wrapMode() || oldAlignment != opt.alignment()
2032         || oldTextDirection != opt.textDirection()
2033         || oldUseDesignMetrics != opt.useDesignMetrics()) {
2034         document->setDefaultTextOption(opt);
2035     }
2036 }
2037
2038 void QQuickTextEdit::focusInEvent(QFocusEvent *event)
2039 {
2040     Q_D(const QQuickTextEdit);
2041     if (d->focusOnPress && !isReadOnly())
2042         qGuiApp->inputMethod()->show();
2043     QQuickImplicitSizeItem::focusInEvent(event);
2044 }
2045
2046 void QQuickTextEdit::q_canPasteChanged()
2047 {
2048     Q_D(QQuickTextEdit);
2049     bool old = d->canPaste;
2050     d->canPaste = d->control->canPaste();
2051     bool changed = old!=d->canPaste || !d->canPasteValid;
2052     d->canPasteValid = true;
2053     if (changed)
2054         emit canPasteChanged();
2055 }
2056
2057 /*!
2058     \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2059
2060     Returns the section of text that is between the \a start and \a end positions.
2061
2062     The returned text does not include any rich text formatting.
2063 */
2064
2065 QString QQuickTextEdit::getText(int start, int end) const
2066 {
2067     Q_D(const QQuickTextEdit);
2068     start = qBound(0, start, d->document->characterCount() - 1);
2069     end = qBound(0, end, d->document->characterCount() - 1);
2070     QTextCursor cursor(d->document);
2071     cursor.setPosition(start, QTextCursor::MoveAnchor);
2072     cursor.setPosition(end, QTextCursor::KeepAnchor);
2073 #ifndef QT_NO_TEXTHTMLPARSER
2074     return d->richText
2075             ? cursor.selectedText()
2076             : cursor.selection().toPlainText();
2077 #else
2078     return cursor.selection().toPlainText();
2079 #endif
2080 }
2081
2082 /*!
2083     \qmlmethod string QtQuick2::TextEdit::getFormattedText(int start, int end)
2084
2085     Returns the section of text that is between the \a start and \a end positions.
2086
2087     The returned text will be formatted according the \l textFormat property.
2088 */
2089
2090 QString QQuickTextEdit::getFormattedText(int start, int end) const
2091 {
2092     Q_D(const QQuickTextEdit);
2093
2094     start = qBound(0, start, d->document->characterCount() - 1);
2095     end = qBound(0, end, d->document->characterCount() - 1);
2096
2097     QTextCursor cursor(d->document);
2098     cursor.setPosition(start, QTextCursor::MoveAnchor);
2099     cursor.setPosition(end, QTextCursor::KeepAnchor);
2100
2101     if (d->richText) {
2102 #ifndef QT_NO_TEXTHTMLPARSER
2103         return cursor.selection().toHtml();
2104 #else
2105         return cursor.selection().toPlainText();
2106 #endif
2107     } else {
2108         return cursor.selection().toPlainText();
2109     }
2110 }
2111
2112 /*!
2113     \qmlmethod void QtQuick2::TextEdit::insert(int position, string text)
2114
2115     Inserts \a text into the TextEdit at position.
2116 */
2117 void QQuickTextEdit::insert(int position, const QString &text)
2118 {
2119     Q_D(QQuickTextEdit);
2120     if (position < 0 || position >= d->document->characterCount())
2121         return;
2122     QTextCursor cursor(d->document);
2123     cursor.setPosition(position);
2124     d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
2125     if (d->richText) {
2126 #ifndef QT_NO_TEXTHTMLPARSER
2127         cursor.insertHtml(text);
2128 #else
2129         cursor.insertText(text);
2130 #endif
2131     } else {
2132         cursor.insertText(text);
2133     }
2134     d->control->updateCursorRectangle(false);
2135 }
2136
2137 /*!
2138     \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2139
2140     Removes the section of text that is between the \a start and \a end positions from the TextEdit.
2141 */
2142
2143 void QQuickTextEdit::remove(int start, int end)
2144 {
2145     Q_D(QQuickTextEdit);
2146     start = qBound(0, start, d->document->characterCount() - 1);
2147     end = qBound(0, end, d->document->characterCount() - 1);
2148     QTextCursor cursor(d->document);
2149     cursor.setPosition(start, QTextCursor::MoveAnchor);
2150     cursor.setPosition(end, QTextCursor::KeepAnchor);
2151     cursor.removeSelectedText();
2152     d->control->updateCursorRectangle(false);
2153 }
2154
2155 QT_END_NAMESPACE