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