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