Doc: Changed \qmlclass to \qmltype and added \instantiates.
[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     \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 void 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 void 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 void 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 void 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 void 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 void 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     Undoes the last operation if undo is \l {canUndo}{available}. Deselects any
1488     current selection, and updates the selection start to the current cursor
1489     position.
1490 */
1491
1492 void QQuickTextEdit::undo()
1493 {
1494     Q_D(QQuickTextEdit);
1495     d->control->undo();
1496 }
1497
1498 /*!
1499     Redoes the last operation if redo is \l {canRedo}{available}.
1500 */
1501
1502 void QQuickTextEdit::redo()
1503 {
1504     Q_D(QQuickTextEdit);
1505     d->control->redo();
1506 }
1507
1508 /*!
1509 \overload
1510 Handles the given mouse \a event.
1511 */
1512 void QQuickTextEdit::mousePressEvent(QMouseEvent *event)
1513 {
1514     Q_D(QQuickTextEdit);
1515     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1516     if (d->focusOnPress){
1517         bool hadActiveFocus = hasActiveFocus();
1518         forceActiveFocus();
1519         // re-open input panel on press if already focused
1520         if (hasActiveFocus() && hadActiveFocus && !isReadOnly())
1521             qGuiApp->inputMethod()->show();
1522     }
1523     if (!event->isAccepted())
1524         QQuickImplicitSizeItem::mousePressEvent(event);
1525 }
1526
1527 /*!
1528 \overload
1529 Handles the given mouse \a event.
1530 */
1531 void QQuickTextEdit::mouseReleaseEvent(QMouseEvent *event)
1532 {
1533     Q_D(QQuickTextEdit);
1534     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1535
1536     if (!event->isAccepted())
1537         QQuickImplicitSizeItem::mouseReleaseEvent(event);
1538 }
1539
1540 /*!
1541 \overload
1542 Handles the given mouse \a event.
1543 */
1544 void QQuickTextEdit::mouseDoubleClickEvent(QMouseEvent *event)
1545 {
1546     Q_D(QQuickTextEdit);
1547     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1548     if (!event->isAccepted())
1549         QQuickImplicitSizeItem::mouseDoubleClickEvent(event);
1550 }
1551
1552 /*!
1553 \overload
1554 Handles the given mouse \a event.
1555 */
1556 void QQuickTextEdit::mouseMoveEvent(QMouseEvent *event)
1557 {
1558     Q_D(QQuickTextEdit);
1559     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1560     if (!event->isAccepted())
1561         QQuickImplicitSizeItem::mouseMoveEvent(event);
1562 }
1563
1564 /*!
1565 \overload
1566 Handles the given input method \a event.
1567 */
1568 void QQuickTextEdit::inputMethodEvent(QInputMethodEvent *event)
1569 {
1570     Q_D(QQuickTextEdit);
1571     const bool wasComposing = isInputMethodComposing();
1572     d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
1573     setCursorVisible(d->control->cursorVisible());
1574     if (wasComposing != isInputMethodComposing())
1575         emit inputMethodComposingChanged();
1576 }
1577
1578 void QQuickTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1579 {
1580     Q_D(QQuickTextEdit);
1581     if (change == ItemActiveFocusHasChanged) {
1582         setCursorVisible(value.boolValue);
1583         QFocusEvent focusEvent(value.boolValue ? QEvent::FocusIn : QEvent::FocusOut);
1584         d->control->processEvent(&focusEvent, QPointF(-d->xoff, -d->yoff));
1585         if (value.boolValue) {
1586             q_updateAlignment();
1587             connect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1588                     this, SLOT(q_updateAlignment()));
1589         } else {
1590             disconnect(qApp->inputMethod(), SIGNAL(inputDirectionChanged(Qt::LayoutDirection)),
1591                        this, SLOT(q_updateAlignment()));
1592         }
1593     }
1594     QQuickItem::itemChange(change, value);
1595 }
1596
1597 /*!
1598 \overload
1599 Returns the value of the given \a property.
1600 */
1601 QVariant QQuickTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1602 {
1603     Q_D(const QQuickTextEdit);
1604
1605     QVariant v;
1606     switch (property) {
1607     case Qt::ImEnabled:
1608         v = (bool)(flags() & ItemAcceptsInputMethod);
1609         break;
1610     case Qt::ImHints:
1611         v = (int)inputMethodHints();
1612         break;
1613     default:
1614         v = d->control->inputMethodQuery(property);
1615         break;
1616     }
1617     return v;
1618
1619 }
1620
1621 void QQuickTextEdit::triggerPreprocess()
1622 {
1623     Q_D(QQuickTextEdit);
1624     if (d->updateType == QQuickTextEditPrivate::UpdateNone)
1625         d->updateType = QQuickTextEditPrivate::UpdateOnlyPreprocess;
1626     update();
1627 }
1628
1629 QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1630 {
1631     Q_UNUSED(updatePaintNodeData);
1632     Q_D(QQuickTextEdit);
1633
1634     if (d->updateType != QQuickTextEditPrivate::UpdatePaintNode && oldNode != 0) {
1635         // Update done in preprocess() in the nodes
1636         d->updateType = QQuickTextEditPrivate::UpdateNone;
1637         return oldNode;
1638     }
1639
1640     d->updateType = QQuickTextEditPrivate::UpdateNone;
1641
1642     QSGNode *currentNode = oldNode;
1643     if (oldNode == 0 || d->documentDirty) {
1644         d->documentDirty = false;
1645
1646         QQuickTextNode *node = 0;
1647         if (oldNode == 0) {
1648             node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1649             currentNode = node;
1650         } else {
1651             node = static_cast<QQuickTextNode *>(oldNode);
1652         }
1653
1654         node->setUseNativeRenderer(d->renderType == NativeRendering);
1655         node->deleteContent();
1656         node->setMatrix(QMatrix4x4());
1657
1658         node->addTextDocument(QPointF(d->xoff, d->yoff), d->document, d->color, QQuickText::Normal, QColor(),
1659                               QColor(), d->selectionColor, d->selectedTextColor, selectionStart(),
1660                               selectionEnd() - 1);  // selectionEnd() returns first char after
1661                                                     // selection
1662     }
1663
1664     if (d->cursorComponent == 0 && !isReadOnly()) {
1665         QQuickTextNode *node = static_cast<QQuickTextNode *>(currentNode);
1666
1667         QColor color = (!d->cursorVisible || !d->control->cursorOn())
1668                 ? QColor(0, 0, 0, 0)
1669                 : d->color;
1670
1671         if (node->cursorNode() == 0) {
1672             node->setCursor(cursorRectangle(), color);
1673         } else {
1674             node->cursorNode()->setRect(cursorRectangle());
1675             node->cursorNode()->setColor(color);
1676         }
1677
1678     }
1679
1680     return currentNode;
1681 }
1682
1683 /*!
1684     \qmlproperty bool QtQuick2::TextEdit::canPaste
1685
1686     Returns true if the TextEdit is writable and the content of the clipboard is
1687     suitable for pasting into the TextEdit.
1688 */
1689 bool QQuickTextEdit::canPaste() const
1690 {
1691     Q_D(const QQuickTextEdit);
1692     if (!d->canPasteValid) {
1693         const_cast<QQuickTextEditPrivate *>(d)->canPaste = d->control->canPaste();
1694         const_cast<QQuickTextEditPrivate *>(d)->canPasteValid = true;
1695     }
1696     return d->canPaste;
1697 }
1698
1699 /*!
1700     \qmlproperty bool QtQuick2::TextEdit::canUndo
1701
1702     Returns true if the TextEdit is writable and there are previous operations
1703     that can be undone.
1704 */
1705
1706 bool QQuickTextEdit::canUndo() const
1707 {
1708     Q_D(const QQuickTextEdit);
1709     return d->document->isUndoAvailable();
1710 }
1711
1712 /*!
1713     \qmlproperty bool QtQuick2::TextEdit::canRedo
1714
1715     Returns true if the TextEdit is writable and there are \l {undo}{undone}
1716     operations that can be redone.
1717 */
1718
1719 bool QQuickTextEdit::canRedo() const
1720 {
1721     Q_D(const QQuickTextEdit);
1722     return d->document->isRedoAvailable();
1723 }
1724
1725 /*!
1726     \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1727
1728
1729     This property holds whether the TextEdit has partial text input from an
1730     input method.
1731
1732     While it is composing an input method may rely on mouse or key events from
1733     the TextEdit to edit or commit the partial text.  This property can be used
1734     to determine when to disable events handlers that may interfere with the
1735     correct operation of an input method.
1736 */
1737 bool QQuickTextEdit::isInputMethodComposing() const
1738 {
1739     Q_D(const QQuickTextEdit);
1740     return d->control->hasImState();
1741 }
1742
1743 void QQuickTextEditPrivate::init()
1744 {
1745     Q_Q(QQuickTextEdit);
1746
1747     q->setAcceptedMouseButtons(Qt::LeftButton);
1748     q->setFlag(QQuickItem::ItemAcceptsInputMethod);
1749     q->setFlag(QQuickItem::ItemHasContents);
1750
1751     document = new QQuickTextDocumentWithImageResources(q);
1752
1753     control = new QQuickTextControl(document, q);
1754     control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1755     control->setAcceptRichText(false);
1756     control->setCursorIsFocusIndicator(true);
1757
1758     qmlobject_connect(control, QQuickTextControl, SIGNAL(updateRequest()), q, QQuickTextEdit, SLOT(updateDocument()));
1759     qmlobject_connect(control, QQuickTextControl, SIGNAL(updateCursorRequest()), q, QQuickTextEdit, SLOT(updateCursor()));
1760     qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged()));
1761     qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SIGNAL(selectedTextChanged()));
1762     qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SLOT(updateSelectionMarkers()));
1763     qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SLOT(updateSelectionMarkers()));
1764     qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SIGNAL(cursorPositionChanged()));
1765     qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate()));
1766     qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString)));
1767 #ifndef QT_NO_CLIPBOARD
1768     qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()), q, QQuickTextEdit, SLOT(q_canPasteChanged()));
1769 #endif
1770     qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(undoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canUndoChanged()));
1771     qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(redoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canRedoChanged()));
1772     qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()), q, QQuickTextEdit, SLOT(updateSize()));
1773
1774     document->setDefaultFont(font);
1775     document->setDocumentMargin(textMargin);
1776     document->setUndoRedoEnabled(false); // flush undo buffer.
1777     document->setUndoRedoEnabled(true);
1778     updateDefaultTextOption();
1779 }
1780
1781 void QQuickTextEdit::q_textChanged()
1782 {
1783     Q_D(QQuickTextEdit);
1784     d->textCached = false;
1785     for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1786         d->contentDirection = d->textDirection(it.text());
1787         if (d->contentDirection != Qt::LayoutDirectionAuto)
1788             break;
1789     }
1790     d->determineHorizontalAlignment();
1791     d->updateDefaultTextOption();
1792     updateSize();
1793     updateTotalLines();
1794     emit textChanged();
1795 }
1796
1797 void QQuickTextEdit::moveCursorDelegate()
1798 {
1799     Q_D(QQuickTextEdit);
1800     updateInputMethod();
1801     emit cursorRectangleChanged();
1802     if (!d->cursorItem)
1803         return;
1804     QRectF cursorRect = cursorRectangle();
1805     d->cursorItem->setX(cursorRect.x());
1806     d->cursorItem->setY(cursorRect.y());
1807 }
1808
1809 void QQuickTextEdit::updateSelectionMarkers()
1810 {
1811     Q_D(QQuickTextEdit);
1812     if (d->lastSelectionStart != d->control->textCursor().selectionStart()) {
1813         d->lastSelectionStart = d->control->textCursor().selectionStart();
1814         emit selectionStartChanged();
1815     }
1816     if (d->lastSelectionEnd != d->control->textCursor().selectionEnd()) {
1817         d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1818         emit selectionEndChanged();
1819     }
1820 }
1821
1822 QRectF QQuickTextEdit::boundingRect() const
1823 {
1824     Q_D(const QQuickTextEdit);
1825     QRectF r(
1826             QQuickTextUtil::alignedX(d->contentSize.width(), width(), effectiveHAlign()),
1827             d->yoff,
1828             d->contentSize.width(),
1829             d->contentSize.height());
1830
1831     int cursorWidth = 1;
1832     if (d->cursorItem)
1833         cursorWidth = 0;
1834     else if (!d->document->isEmpty())
1835         cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1836
1837     // Could include font max left/right bearings to either side of rectangle.
1838     r.setRight(r.right() + cursorWidth);
1839
1840     return r;
1841 }
1842
1843 QRectF QQuickTextEdit::clipRect() const
1844 {
1845     Q_D(const QQuickTextEdit);
1846     QRectF r = QQuickImplicitSizeItem::clipRect();
1847     int cursorWidth = 1;
1848     if (d->cursorItem)
1849         cursorWidth = d->cursorItem->width();
1850     if (!d->document->isEmpty())
1851         cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1852
1853     // Could include font max left/right bearings to either side of rectangle.
1854
1855     r.setRight(r.right() + cursorWidth);
1856     return r;
1857 }
1858
1859 qreal QQuickTextEditPrivate::getImplicitWidth() const
1860 {
1861     Q_Q(const QQuickTextEdit);
1862     if (!requireImplicitWidth) {
1863         // We don't calculate implicitWidth unless it is required.
1864         // We need to force a size update now to ensure implicitWidth is calculated
1865         const_cast<QQuickTextEditPrivate*>(this)->requireImplicitWidth = true;
1866         const_cast<QQuickTextEdit*>(q)->updateSize();
1867     }
1868     return implicitWidth;
1869 }
1870
1871 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1872 //    need to do all the calculations each time
1873 void QQuickTextEdit::updateSize()
1874 {
1875     Q_D(QQuickTextEdit);
1876     if (isComponentComplete()) {
1877         qreal naturalWidth = d->implicitWidth;
1878         // ### assumes that if the width is set, the text will fill to edges
1879         // ### (unless wrap is false, then clipping will occur)
1880         if (widthValid()) {
1881             if (!d->requireImplicitWidth) {
1882                 emit implicitWidthChanged();
1883                 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1884                 if (d->requireImplicitWidth)
1885                     return;
1886             }
1887             if (d->requireImplicitWidth) {
1888                 d->document->setTextWidth(-1);
1889                 naturalWidth = d->document->idealWidth();
1890
1891                 const bool wasInLayout = d->inLayout;
1892                 d->inLayout = true;
1893                 setImplicitWidth(naturalWidth);
1894                 d->inLayout = wasInLayout;
1895                 if (d->inLayout)    // probably the result of a binding loop, but by letting it
1896                     return;         // get this far we'll get a warning to that effect.
1897             }
1898             if (d->document->textWidth() != width())
1899                 d->document->setTextWidth(width());
1900         } else {
1901             d->document->setTextWidth(-1);
1902         }
1903
1904         //### need to confirm cost of always setting these
1905         qreal newWidth = d->document->idealWidth();
1906         if ((!widthValid() || d->wrapMode == NoWrap) && d->document->textWidth() != newWidth)
1907             d->document->setTextWidth(newWidth); // ### Text does not align if width is not set or the idealWidth exceeds the textWidth (QTextDoc bug)
1908         // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1909         qreal iWidth = -1;
1910         if (!widthValid() && !d->requireImplicitWidth)
1911             iWidth = newWidth;
1912
1913         QFontMetricsF fm(d->font);
1914         qreal newHeight = d->document->isEmpty() ? qCeil(fm.height()) : d->document->size().height();
1915
1916         if (iWidth > -1)
1917             setImplicitSize(iWidth, newHeight);
1918         else
1919             setImplicitHeight(newHeight);
1920
1921         d->xoff = QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign());
1922         d->yoff = QQuickTextUtil::alignedY(d->document->size().height(), height(), d->vAlign);
1923         setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1924
1925         QSizeF size(newWidth, newHeight);
1926         if (d->contentSize != size) {
1927             d->contentSize = size;
1928             emit contentSizeChanged();
1929         }
1930     } else {
1931         d->dirty = true;
1932     }
1933     updateDocument();
1934 }
1935
1936 void QQuickTextEdit::updateDocument()
1937 {
1938     Q_D(QQuickTextEdit);
1939     d->documentDirty = true;
1940
1941     if (isComponentComplete()) {
1942         d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1943         update();
1944     }
1945 }
1946
1947 void QQuickTextEdit::updateCursor()
1948 {
1949     Q_D(QQuickTextEdit);
1950     if (isComponentComplete()) {
1951         d->updateType = QQuickTextEditPrivate::UpdatePaintNode;
1952         update();
1953     }
1954 }
1955
1956 void QQuickTextEdit::q_updateAlignment()
1957 {
1958     Q_D(QQuickTextEdit);
1959     if (d->determineHorizontalAlignment()) {
1960         d->updateDefaultTextOption();
1961         d->xoff = QQuickTextUtil::alignedX(d->document->size().width(), width(), effectiveHAlign());
1962         moveCursorDelegate();
1963     }
1964 }
1965
1966 void QQuickTextEdit::updateTotalLines()
1967 {
1968     Q_D(QQuickTextEdit);
1969
1970     int subLines = 0;
1971
1972     for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1973         QTextLayout *layout = it.layout();
1974         if (!layout)
1975             continue;
1976         subLines += layout->lineCount()-1;
1977     }
1978
1979     int newTotalLines = d->document->lineCount() + subLines;
1980     if (d->lineCount != newTotalLines) {
1981         d->lineCount = newTotalLines;
1982         emit lineCountChanged();
1983     }
1984 }
1985
1986 void QQuickTextEditPrivate::updateDefaultTextOption()
1987 {
1988     Q_Q(QQuickTextEdit);
1989     QTextOption opt = document->defaultTextOption();
1990     int oldAlignment = opt.alignment();
1991     Qt::LayoutDirection oldTextDirection = opt.textDirection();
1992
1993     QQuickTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1994     if (contentDirection == Qt::RightToLeft) {
1995         if (horizontalAlignment == QQuickTextEdit::AlignLeft)
1996             horizontalAlignment = QQuickTextEdit::AlignRight;
1997         else if (horizontalAlignment == QQuickTextEdit::AlignRight)
1998             horizontalAlignment = QQuickTextEdit::AlignLeft;
1999     }
2000     if (!hAlignImplicit)
2001         opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
2002     else
2003         opt.setAlignment(Qt::Alignment(vAlign));
2004
2005     if (contentDirection == Qt::LayoutDirectionAuto) {
2006         opt.setTextDirection(qGuiApp->inputMethod()->inputDirection());
2007     } else {
2008         opt.setTextDirection(contentDirection);
2009     }
2010
2011     QTextOption::WrapMode oldWrapMode = opt.wrapMode();
2012     opt.setWrapMode(QTextOption::WrapMode(wrapMode));
2013
2014     bool oldUseDesignMetrics = opt.useDesignMetrics();
2015     opt.setUseDesignMetrics(renderType != QQuickTextEdit::NativeRendering);
2016
2017     if (oldWrapMode != opt.wrapMode() || oldAlignment != opt.alignment()
2018         || oldTextDirection != opt.textDirection()
2019         || oldUseDesignMetrics != opt.useDesignMetrics()) {
2020         document->setDefaultTextOption(opt);
2021     }
2022 }
2023
2024 void QQuickTextEdit::focusInEvent(QFocusEvent *event)
2025 {
2026     Q_D(const QQuickTextEdit);
2027     if (d->focusOnPress && !isReadOnly())
2028         qGuiApp->inputMethod()->show();
2029     QQuickImplicitSizeItem::focusInEvent(event);
2030 }
2031
2032 void QQuickTextEdit::q_canPasteChanged()
2033 {
2034     Q_D(QQuickTextEdit);
2035     bool old = d->canPaste;
2036     d->canPaste = d->control->canPaste();
2037     bool changed = old!=d->canPaste || !d->canPasteValid;
2038     d->canPasteValid = true;
2039     if (changed)
2040         emit canPasteChanged();
2041 }
2042
2043 /*!
2044     \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2045
2046     Returns the section of text that is between the \a start and \a end positions.
2047
2048     The returned text does not include any rich text formatting.
2049 */
2050
2051 QString QQuickTextEdit::getText(int start, int end) const
2052 {
2053     Q_D(const QQuickTextEdit);
2054     start = qBound(0, start, d->document->characterCount() - 1);
2055     end = qBound(0, end, d->document->characterCount() - 1);
2056     QTextCursor cursor(d->document);
2057     cursor.setPosition(start, QTextCursor::MoveAnchor);
2058     cursor.setPosition(end, QTextCursor::KeepAnchor);
2059 #ifndef QT_NO_TEXTHTMLPARSER
2060     return d->richText
2061             ? cursor.selectedText()
2062             : cursor.selection().toPlainText();
2063 #else
2064     return cursor.selection().toPlainText();
2065 #endif
2066 }
2067
2068 /*!
2069     \qmlmethod string QtQuick2::TextEdit::getFormattedText(int start, int end)
2070
2071     Returns the section of text that is between the \a start and \a end positions.
2072
2073     The returned text will be formatted according the \l textFormat property.
2074 */
2075
2076 QString QQuickTextEdit::getFormattedText(int start, int end) const
2077 {
2078     Q_D(const QQuickTextEdit);
2079
2080     start = qBound(0, start, d->document->characterCount() - 1);
2081     end = qBound(0, end, d->document->characterCount() - 1);
2082
2083     QTextCursor cursor(d->document);
2084     cursor.setPosition(start, QTextCursor::MoveAnchor);
2085     cursor.setPosition(end, QTextCursor::KeepAnchor);
2086
2087     if (d->richText) {
2088 #ifndef QT_NO_TEXTHTMLPARSER
2089         return cursor.selection().toHtml();
2090 #else
2091         return cursor.selection().toPlainText();
2092 #endif
2093     } else {
2094         return cursor.selection().toPlainText();
2095     }
2096 }
2097
2098 /*!
2099     \qmlmethod void QtQuick2::TextEdit::insert(int position, string text)
2100
2101     Inserts \a text into the TextEdit at position.
2102 */
2103 void QQuickTextEdit::insert(int position, const QString &text)
2104 {
2105     Q_D(QQuickTextEdit);
2106     if (position < 0 || position >= d->document->characterCount())
2107         return;
2108     QTextCursor cursor(d->document);
2109     cursor.setPosition(position);
2110     d->richText = d->richText || (d->format == AutoText && Qt::mightBeRichText(text));
2111     if (d->richText) {
2112 #ifndef QT_NO_TEXTHTMLPARSER
2113         cursor.insertHtml(text);
2114 #else
2115         cursor.insertText(text);
2116 #endif
2117     } else {
2118         cursor.insertText(text);
2119     }
2120     d->control->updateCursorRectangle(false);
2121 }
2122
2123 /*!
2124     \qmlmethod string QtQuick2::TextEdit::getText(int start, int end)
2125
2126     Removes the section of text that is between the \a start and \a end positions from the TextEdit.
2127 */
2128
2129 void QQuickTextEdit::remove(int start, int end)
2130 {
2131     Q_D(QQuickTextEdit);
2132     start = qBound(0, start, d->document->characterCount() - 1);
2133     end = qBound(0, end, d->document->characterCount() - 1);
2134     QTextCursor cursor(d->document);
2135     cursor.setPosition(start, QTextCursor::MoveAnchor);
2136     cursor.setPosition(end, QTextCursor::KeepAnchor);
2137     cursor.removeSelectedText();
2138     d->control->updateCursorRectangle(false);
2139 }
2140
2141 QT_END_NAMESPACE