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