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