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