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