eeeaa206db90dbddb30c4461c488224be8c593a8
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsgtextedit.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
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 "qsgtextedit_p.h"
43 #include "qsgtextedit_p_p.h"
44 #include "qsgevents_p_p.h"
45 #include "qsgcanvas.h"
46 #include "qsgtextnode_p.h"
47 #include "qsgsimplerectnode.h"
48
49 #include <QtDeclarative/qdeclarativeinfo.h>
50 #include <QtGui/qapplication.h>
51 #include <QtGui/qgraphicssceneevent.h>
52 #include <QtGui/qpainter.h>
53 #include <QtGui/qtextobject.h>
54 #include <QtCore/qmath.h>
55
56 #include <private/qdeclarativeglobal_p.h>
57 #include <private/qtextcontrol_p.h>
58 #include <private/qtextengine_p.h>
59 #include <private/qwidget_p.h>
60 #include <private/qsgdistancefieldglyphcache_p.h>
61 #include <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
68 QWidgetPrivate *qt_widget_private(QWidget *widget);
69 /*!
70     \qmlclass TextEdit QSGTextEdit
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 QSGTextEdit::QSGTextEdit(QSGItem *parent)
121 : QSGImplicitSizeItem(*(new QSGTextEditPrivate), parent)
122 {
123     Q_D(QSGTextEdit);
124     d->init();
125 }
126
127 QString QSGTextEdit::text() const
128 {
129     Q_D(const QSGTextEdit);
130
131 #ifndef QT_NO_TEXTHTMLPARSER
132     if (d->richText)
133         return d->document->toHtml();
134     else
135 #endif
136         return d->document->toPlainText();
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 QSGTextEdit::setText(const QString &text)
253 {
254     Q_D(QSGTextEdit);
255     if (QSGTextEdit::text() == text)
256         return;
257
258     d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
259     if (d->richText) {
260 #ifndef QT_NO_TEXTHTMLPARSER
261         d->control->setHtml(text);
262 #else
263         d->control->setPlainText(text);
264 #endif
265         d->isComplexRichText = QSGTextNode::isComplexRichText(d->document);
266     } else {
267         d->control->setPlainText(text);
268     }
269     q_textChanged();
270 }
271
272 /*!
273     \qmlproperty enumeration QtQuick2::TextEdit::textFormat
274
275     The way the text property should be displayed.
276
277     \list
278     \o TextEdit.AutoText
279     \o TextEdit.PlainText
280     \o TextEdit.RichText
281     \endlist
282
283     The default is TextEdit.AutoText.  If the text format is TextEdit.AutoText the text edit
284     will automatically determine whether the text should be treated as
285     rich text.  This determination is made using Qt::mightBeRichText().
286
287     \table
288     \row
289     \o
290     \qml
291 Column {
292     TextEdit {
293         font.pointSize: 24
294         text: "<b>Hello</b> <i>World!</i>"
295     }
296     TextEdit {
297         font.pointSize: 24
298         textFormat: TextEdit.RichText
299         text: "<b>Hello</b> <i>World!</i>"
300     }
301     TextEdit {
302         font.pointSize: 24
303         textFormat: TextEdit.PlainText
304         text: "<b>Hello</b> <i>World!</i>"
305     }
306 }
307     \endqml
308     \o \image declarative-textformat.png
309     \endtable
310 */
311 QSGTextEdit::TextFormat QSGTextEdit::textFormat() const
312 {
313     Q_D(const QSGTextEdit);
314     return d->format;
315 }
316
317 void QSGTextEdit::setTextFormat(TextFormat format)
318 {
319     Q_D(QSGTextEdit);
320     if (format == d->format)
321         return;
322     bool wasRich = d->richText;
323     d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
324
325     if (wasRich && !d->richText) {
326         d->control->setPlainText(d->text);
327         updateSize();
328     } else if (!wasRich && d->richText) {
329 #ifndef QT_NO_TEXTHTMLPARSER
330         d->control->setHtml(d->text);
331 #else
332         d->control->setPlainText(d->text);
333 #endif
334         updateSize();
335         d->isComplexRichText = QSGTextNode::isComplexRichText(d->document);
336     }
337     d->format = format;
338     d->control->setAcceptRichText(d->format != PlainText);
339     emit textFormatChanged(d->format);
340 }
341
342 QFont QSGTextEdit::font() const
343 {
344     Q_D(const QSGTextEdit);
345     return d->sourceFont;
346 }
347
348 void QSGTextEdit::setFont(const QFont &font)
349 {
350     Q_D(QSGTextEdit);
351     if (d->sourceFont == font)
352         return;
353
354     d->sourceFont = font;
355     QFont oldFont = d->font;
356     d->font = font;
357     if (d->font.pointSizeF() != -1) {
358         // 0.5pt resolution
359         qreal size = qRound(d->font.pointSizeF()*2.0);
360         d->font.setPointSizeF(size/2.0);
361     }
362
363     if (oldFont != d->font) {
364         d->document->setDefaultFont(d->font);
365         if(d->cursor){
366             d->cursor->setHeight(QFontMetrics(d->font).height());
367             moveCursorDelegate();
368         }
369         updateSize();
370         updateDocument();
371     }
372     emit fontChanged(d->sourceFont);
373 }
374
375 /*!
376     \qmlproperty color QtQuick2::TextEdit::color
377
378     The text color.
379
380     \qml
381     // green text using hexadecimal notation
382     TextEdit { color: "#00FF00" }
383     \endqml
384
385     \qml
386     // steelblue text using SVG color name
387     TextEdit { color: "steelblue" }
388     \endqml
389 */
390 QColor QSGTextEdit::color() const
391 {
392     Q_D(const QSGTextEdit);
393     return d->color;
394 }
395
396 void QSGTextEdit::setColor(const QColor &color)
397 {
398     Q_D(QSGTextEdit);
399     if (d->color == color)
400         return;
401
402     d->color = color;
403     QPalette pal = d->control->palette();
404     pal.setColor(QPalette::Text, color);
405     d->control->setPalette(pal);
406     updateDocument();
407     emit colorChanged(d->color);
408 }
409
410 /*!
411     \qmlproperty color QtQuick2::TextEdit::selectionColor
412
413     The text highlight color, used behind selections.
414 */
415 QColor QSGTextEdit::selectionColor() const
416 {
417     Q_D(const QSGTextEdit);
418     return d->selectionColor;
419 }
420
421 void QSGTextEdit::setSelectionColor(const QColor &color)
422 {
423     Q_D(QSGTextEdit);
424     if (d->selectionColor == color)
425         return;
426
427     d->selectionColor = color;
428     QPalette pal = d->control->palette();
429     pal.setColor(QPalette::Highlight, color);
430     d->control->setPalette(pal);
431     updateDocument();
432     emit selectionColorChanged(d->selectionColor);
433 }
434
435 /*!
436     \qmlproperty color QtQuick2::TextEdit::selectedTextColor
437
438     The selected text color, used in selections.
439 */
440 QColor QSGTextEdit::selectedTextColor() const
441 {
442     Q_D(const QSGTextEdit);
443     return d->selectedTextColor;
444 }
445
446 void QSGTextEdit::setSelectedTextColor(const QColor &color)
447 {
448     Q_D(QSGTextEdit);
449     if (d->selectedTextColor == color)
450         return;
451
452     d->selectedTextColor = color;
453     QPalette pal = d->control->palette();
454     pal.setColor(QPalette::HighlightedText, color);
455     d->control->setPalette(pal);
456     updateDocument();
457     emit selectedTextColorChanged(d->selectedTextColor);
458 }
459
460 /*!
461     \qmlproperty enumeration QtQuick2::TextEdit::horizontalAlignment
462     \qmlproperty enumeration QtQuick2::TextEdit::verticalAlignment
463     \qmlproperty enumeration QtQuick2::TextEdit::effectiveHorizontalAlignment
464
465     Sets the horizontal and vertical alignment of the text within the TextEdit item's
466     width and height. By default, the text alignment follows the natural alignment
467     of the text, for example text that is read from left to right will be aligned to
468     the left.
469
470     Valid values for \c horizontalAlignment are:
471     \list
472     \o TextEdit.AlignLeft (default)
473     \o TextEdit.AlignRight
474     \o TextEdit.AlignHCenter
475     \o TextEdit.AlignJustify
476     \endlist
477
478     Valid values for \c verticalAlignment are:
479     \list
480     \o TextEdit.AlignTop (default)
481     \o TextEdit.AlignBottom
482     \o TextEdit.AlignVCenter
483     \endlist
484
485     When using the attached property LayoutMirroring::enabled to mirror application
486     layouts, the horizontal alignment of text will also be mirrored. However, the property
487     \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
488     of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
489 */
490 QSGTextEdit::HAlignment QSGTextEdit::hAlign() const
491 {
492     Q_D(const QSGTextEdit);
493     return d->hAlign;
494 }
495
496 void QSGTextEdit::setHAlign(HAlignment align)
497 {
498     Q_D(QSGTextEdit);
499     bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
500     d->hAlignImplicit = false;
501     if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
502         d->updateDefaultTextOption();
503         updateSize();
504     }
505 }
506
507 void QSGTextEdit::resetHAlign()
508 {
509     Q_D(QSGTextEdit);
510     d->hAlignImplicit = true;
511     if (d->determineHorizontalAlignment() && isComponentComplete()) {
512         d->updateDefaultTextOption();
513         updateSize();
514     }
515 }
516
517 QSGTextEdit::HAlignment QSGTextEdit::effectiveHAlign() const
518 {
519     Q_D(const QSGTextEdit);
520     QSGTextEdit::HAlignment effectiveAlignment = d->hAlign;
521     if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
522         switch (d->hAlign) {
523         case QSGTextEdit::AlignLeft:
524             effectiveAlignment = QSGTextEdit::AlignRight;
525             break;
526         case QSGTextEdit::AlignRight:
527             effectiveAlignment = QSGTextEdit::AlignLeft;
528             break;
529         default:
530             break;
531         }
532     }
533     return effectiveAlignment;
534 }
535
536 bool QSGTextEditPrivate::setHAlign(QSGTextEdit::HAlignment alignment, bool forceAlign)
537 {
538     Q_Q(QSGTextEdit);
539     if (hAlign != alignment || forceAlign) {
540         QSGTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
541         hAlign = alignment;
542         emit q->horizontalAlignmentChanged(alignment);
543         if (oldEffectiveHAlign != q->effectiveHAlign())
544             emit q->effectiveHorizontalAlignmentChanged();
545         return true;
546     }
547     return false;
548 }
549
550 bool QSGTextEditPrivate::determineHorizontalAlignment()
551 {
552     Q_Q(QSGTextEdit);
553     if (hAlignImplicit && q->isComponentComplete()) {
554         bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
555         return setHAlign(alignToRight ? QSGTextEdit::AlignRight : QSGTextEdit::AlignLeft);
556     }
557     return false;
558 }
559
560 void QSGTextEditPrivate::mirrorChange()
561 {
562     Q_Q(QSGTextEdit);
563     if (q->isComponentComplete()) {
564         if (!hAlignImplicit && (hAlign == QSGTextEdit::AlignRight || hAlign == QSGTextEdit::AlignLeft)) {
565             updateDefaultTextOption();
566             q->updateSize();
567             emit q->effectiveHorizontalAlignmentChanged();
568         }
569     }
570 }
571
572 QSGTextEdit::VAlignment QSGTextEdit::vAlign() const
573 {
574     Q_D(const QSGTextEdit);
575     return d->vAlign;
576 }
577
578 void QSGTextEdit::setVAlign(QSGTextEdit::VAlignment alignment)
579 {
580     Q_D(QSGTextEdit);
581     if (alignment == d->vAlign)
582         return;
583     d->vAlign = alignment;
584     d->updateDefaultTextOption();
585     updateSize();
586     moveCursorDelegate();
587     emit verticalAlignmentChanged(d->vAlign);
588 }
589 /*!
590     \qmlproperty enumeration QtQuick2::TextEdit::wrapMode
591
592     Set this property to wrap the text to the TextEdit item's width.
593     The text will only wrap if an explicit width has been set.
594
595     \list
596     \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
597     \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
598     \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
599     \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.
600     \endlist
601
602     The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
603 */
604 QSGTextEdit::WrapMode QSGTextEdit::wrapMode() const
605 {
606     Q_D(const QSGTextEdit);
607     return d->wrapMode;
608 }
609
610 void QSGTextEdit::setWrapMode(WrapMode mode)
611 {
612     Q_D(QSGTextEdit);
613     if (mode == d->wrapMode)
614         return;
615     d->wrapMode = mode;
616     d->updateDefaultTextOption();
617     updateSize();
618     emit wrapModeChanged();
619 }
620
621 /*!
622     \qmlproperty int QtQuick2::TextEdit::lineCount
623
624     Returns the total number of lines in the textEdit item.
625 */
626 int QSGTextEdit::lineCount() const
627 {
628     Q_D(const QSGTextEdit);
629     return d->lineCount;
630 }
631
632 /*!
633     \qmlproperty real QtQuick2::TextEdit::paintedWidth
634
635     Returns the width of the text, including the width past the width
636     which is covered due to insufficient wrapping if \l wrapMode is set.
637 */
638 qreal QSGTextEdit::paintedWidth() const
639 {
640     Q_D(const QSGTextEdit);
641     return d->paintedSize.width();
642 }
643
644 /*!
645     \qmlproperty real QtQuick2::TextEdit::paintedHeight
646
647     Returns the height of the text, including the height past the height
648     that is covered if the text does not fit within the set height.
649 */
650 qreal QSGTextEdit::paintedHeight() const
651 {
652     Q_D(const QSGTextEdit);
653     return d->paintedSize.height();
654 }
655
656 /*!
657     \qmlmethod rectangle QtQuick2::TextEdit::positionToRectangle(position)
658
659     Returns the rectangle at the given \a position in the text. The x, y,
660     and height properties correspond to the cursor that would describe
661     that position.
662 */
663 QRectF QSGTextEdit::positionToRectangle(int pos) const
664 {
665     Q_D(const QSGTextEdit);
666     QTextCursor c(d->document);
667     c.setPosition(pos);
668     return d->control->cursorRect(c);
669
670 }
671
672 /*!
673     \qmlmethod int QtQuick2::TextEdit::positionAt(int x, int y)
674
675     Returns the text position closest to pixel position (\a x, \a y).
676
677     Position 0 is before the first character, position 1 is after the first character
678     but before the second, and so on until position \l {text}.length, which is after all characters.
679 */
680 int QSGTextEdit::positionAt(int x, int y) const
681 {
682     Q_D(const QSGTextEdit);
683     int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
684     QTextCursor cursor = d->control->textCursor();
685     if (r > cursor.position()) {
686         // The cursor position includes positions within the preedit text, but only positions in the
687         // same text block are offset so it is possible to get a position that is either part of the
688         // preedit or the next text block.
689         QTextLayout *layout = cursor.block().layout();
690         const int preeditLength = layout
691                 ? layout->preeditAreaText().length()
692                 : 0;
693         if (preeditLength > 0
694                 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
695             r = r > cursor.position() + preeditLength
696                     ? r - preeditLength
697                     : cursor.position();
698         }
699     }
700     return r;
701 }
702
703 /*!
704     \qmlmethod void QtQuick2::TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
705
706     Moves the cursor to \a position and updates the selection according to the optional \a mode
707     parameter. (To only move the cursor, set the \l cursorPosition property.)
708
709     When this method is called it additionally sets either the
710     selectionStart or the selectionEnd (whichever was at the previous cursor position)
711     to the specified position. This allows you to easily extend and contract the selected
712     text range.
713
714     The selection mode specifies whether the selection is updated on a per character or a per word
715     basis.  If not specified the selection mode will default to TextEdit.SelectCharacters.
716
717     \list
718     \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
719     the previous cursor position) to the specified position.
720     \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
721     words between the specified postion and the previous cursor position.  Words partially in the
722     range are included.
723     \endlist
724
725     For example, take this sequence of calls:
726
727     \code
728         cursorPosition = 5
729         moveCursorSelection(9, TextEdit.SelectCharacters)
730         moveCursorSelection(7, TextEdit.SelectCharacters)
731     \endcode
732
733     This moves the cursor to position 5, extend the selection end from 5 to 9
734     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
735     selected (the 6th and 7th characters).
736
737     The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
738     before or on position 5 and extend the selection end to a word boundary on or past position 9.
739 */
740 void QSGTextEdit::moveCursorSelection(int pos)
741 {
742     //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
743     Q_D(QSGTextEdit);
744     QTextCursor cursor = d->control->textCursor();
745     if (cursor.position() == pos)
746         return;
747     cursor.setPosition(pos, QTextCursor::KeepAnchor);
748     d->control->setTextCursor(cursor);
749 }
750
751 void QSGTextEdit::moveCursorSelection(int pos, SelectionMode mode)
752 {
753     Q_D(QSGTextEdit);
754     QTextCursor cursor = d->control->textCursor();
755     if (cursor.position() == pos)
756         return;
757     if (mode == SelectCharacters) {
758         cursor.setPosition(pos, QTextCursor::KeepAnchor);
759     } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
760         if (cursor.anchor() > cursor.position()) {
761             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
762             cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
763             if (cursor.position() == cursor.anchor())
764                 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
765             else
766                 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
767         } else {
768             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
769             cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
770         }
771
772         cursor.setPosition(pos, QTextCursor::KeepAnchor);
773         cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
774         if (cursor.position() != pos)
775             cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
776     } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
777         if (cursor.anchor() < cursor.position()) {
778             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
779             cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
780         } else {
781             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
782             cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
783             cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
784             if (cursor.position() != cursor.anchor()) {
785                 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
786                 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
787             }
788         }
789
790         cursor.setPosition(pos, QTextCursor::KeepAnchor);
791         cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
792         if (cursor.position() != pos) {
793             cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
794             cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
795         }
796     }
797     d->control->setTextCursor(cursor);
798 }
799
800 /*!
801     \qmlproperty bool QtQuick2::TextEdit::cursorVisible
802     If true the text edit shows a cursor.
803
804     This property is set and unset when the text edit gets active focus, but it can also
805     be set directly (useful, for example, if a KeyProxy might forward keys to it).
806 */
807 bool QSGTextEdit::isCursorVisible() const
808 {
809     Q_D(const QSGTextEdit);
810     return d->cursorVisible;
811 }
812
813 void QSGTextEdit::setCursorVisible(bool on)
814 {
815     Q_D(QSGTextEdit);
816     if (d->cursorVisible == on)
817         return;
818     d->cursorVisible = on;
819     QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
820     if (!on && !d->persistentSelection)
821         d->control->setCursorIsFocusIndicator(true);
822     d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
823     emit cursorVisibleChanged(d->cursorVisible);
824 }
825
826 /*!
827     \qmlproperty int QtQuick2::TextEdit::cursorPosition
828     The position of the cursor in the TextEdit.
829 */
830 int QSGTextEdit::cursorPosition() const
831 {
832     Q_D(const QSGTextEdit);
833     return d->control->textCursor().position();
834 }
835
836 void QSGTextEdit::setCursorPosition(int pos)
837 {
838     Q_D(QSGTextEdit);
839     if (pos < 0 || pos > d->text.length())
840         return;
841     QTextCursor cursor = d->control->textCursor();
842     if (cursor.position() == pos && cursor.anchor() == pos)
843         return;
844     cursor.setPosition(pos);
845     d->control->setTextCursor(cursor);
846 }
847
848 /*!
849     \qmlproperty Component QtQuick2::TextEdit::cursorDelegate
850     The delegate for the cursor in the TextEdit.
851
852     If you set a cursorDelegate for a TextEdit, this delegate will be used for
853     drawing the cursor instead of the standard cursor. An instance of the
854     delegate will be created and managed by the text edit when a cursor is
855     needed, and the x and y properties of delegate instance will be set so as
856     to be one pixel before the top left of the current character.
857
858     Note that the root item of the delegate component must be a QDeclarativeItem or
859     QDeclarativeItem derived item.
860 */
861 QDeclarativeComponent* QSGTextEdit::cursorDelegate() const
862 {
863     Q_D(const QSGTextEdit);
864     return d->cursorComponent;
865 }
866
867 void QSGTextEdit::setCursorDelegate(QDeclarativeComponent* c)
868 {
869     Q_D(QSGTextEdit);
870     if(d->cursorComponent){
871         if(d->cursor){
872             d->control->setCursorWidth(-1);
873             updateCursor();
874             delete d->cursor;
875             d->cursor = 0;
876         }
877     }
878     d->cursorComponent = c;
879     if(c && c->isReady()){
880         loadCursorDelegate();
881     }else{
882         if(c)
883             connect(c, SIGNAL(statusChanged()),
884                     this, SLOT(loadCursorDelegate()));
885     }
886
887     emit cursorDelegateChanged();
888 }
889
890 void QSGTextEdit::loadCursorDelegate()
891 {
892     Q_D(QSGTextEdit);
893     if(d->cursorComponent->isLoading())
894         return;
895     d->cursor = qobject_cast<QSGItem*>(d->cursorComponent->create(qmlContext(this)));
896     if(d->cursor){
897         d->control->setCursorWidth(0);
898         updateCursor();
899         QDeclarative_setParent_noEvent(d->cursor, this);
900         d->cursor->setParentItem(this);
901         d->cursor->setHeight(QFontMetrics(d->font).height());
902         moveCursorDelegate();
903     }else{
904         qmlInfo(this) << "Error loading cursor delegate.";
905     }
906 }
907
908 /*!
909     \qmlproperty int QtQuick2::TextEdit::selectionStart
910
911     The cursor position before the first character in the current selection.
912
913     This property is read-only. To change the selection, use select(start,end),
914     selectAll(), or selectWord().
915
916     \sa selectionEnd, cursorPosition, selectedText
917 */
918 int QSGTextEdit::selectionStart() const
919 {
920     Q_D(const QSGTextEdit);
921     return d->control->textCursor().selectionStart();
922 }
923
924 /*!
925     \qmlproperty int QtQuick2::TextEdit::selectionEnd
926
927     The cursor position after the last character in the current selection.
928
929     This property is read-only. To change the selection, use select(start,end),
930     selectAll(), or selectWord().
931
932     \sa selectionStart, cursorPosition, selectedText
933 */
934 int QSGTextEdit::selectionEnd() const
935 {
936     Q_D(const QSGTextEdit);
937     return d->control->textCursor().selectionEnd();
938 }
939
940 /*!
941     \qmlproperty string QtQuick2::TextEdit::selectedText
942
943     This read-only property provides the text currently selected in the
944     text edit.
945
946     It is equivalent to the following snippet, but is faster and easier
947     to use.
948     \code
949     //myTextEdit is the id of the TextEdit
950     myTextEdit.text.toString().substring(myTextEdit.selectionStart,
951             myTextEdit.selectionEnd);
952     \endcode
953 */
954 QString QSGTextEdit::selectedText() const
955 {
956     Q_D(const QSGTextEdit);
957     return d->control->textCursor().selectedText();
958 }
959
960 /*!
961     \qmlproperty bool QtQuick2::TextEdit::activeFocusOnPress
962
963     Whether the TextEdit should gain active focus on a mouse press. By default this is
964     set to true.
965 */
966 bool QSGTextEdit::focusOnPress() const
967 {
968     Q_D(const QSGTextEdit);
969     return d->focusOnPress;
970 }
971
972 void QSGTextEdit::setFocusOnPress(bool on)
973 {
974     Q_D(QSGTextEdit);
975     if (d->focusOnPress == on)
976         return;
977     d->focusOnPress = on;
978     emit activeFocusOnPressChanged(d->focusOnPress);
979 }
980
981 /*!
982     \qmlproperty bool QtQuick2::TextEdit::persistentSelection
983
984     Whether the TextEdit should keep the selection visible when it loses active focus to another
985     item in the scene. By default this is set to true;
986 */
987 bool QSGTextEdit::persistentSelection() const
988 {
989     Q_D(const QSGTextEdit);
990     return d->persistentSelection;
991 }
992
993 void QSGTextEdit::setPersistentSelection(bool on)
994 {
995     Q_D(QSGTextEdit);
996     if (d->persistentSelection == on)
997         return;
998     d->persistentSelection = on;
999     emit persistentSelectionChanged(d->persistentSelection);
1000 }
1001
1002 /*
1003    \qmlproperty real QtQuick2::TextEdit::textMargin
1004
1005    The margin, in pixels, around the text in the TextEdit.
1006 */
1007 qreal QSGTextEdit::textMargin() const
1008 {
1009     Q_D(const QSGTextEdit);
1010     return d->textMargin;
1011 }
1012
1013 void QSGTextEdit::setTextMargin(qreal margin)
1014 {
1015     Q_D(QSGTextEdit);
1016     if (d->textMargin == margin)
1017         return;
1018     d->textMargin = margin;
1019     d->document->setDocumentMargin(d->textMargin);
1020     emit textMarginChanged(d->textMargin);
1021 }
1022
1023 void QSGTextEdit::geometryChanged(const QRectF &newGeometry,
1024                                   const QRectF &oldGeometry)
1025 {
1026     if (newGeometry.width() != oldGeometry.width())
1027         updateSize();
1028     QSGImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1029 }
1030
1031 /*!
1032     Ensures any delayed caching or data loading the class
1033     needs to performed is complete.
1034 */
1035 void QSGTextEdit::componentComplete()
1036 {
1037     Q_D(QSGTextEdit);
1038     QSGImplicitSizeItem::componentComplete();
1039
1040     if (d->richText) {
1041         d->isComplexRichText = QSGTextNode::isComplexRichText(d->document);
1042     }
1043
1044     if (d->dirty) {
1045         d->determineHorizontalAlignment();
1046         d->updateDefaultTextOption();
1047         updateSize();
1048         d->dirty = false;
1049     }
1050
1051 }
1052 /*!
1053     \qmlproperty bool QtQuick2::TextEdit::selectByMouse
1054
1055     Defaults to false.
1056
1057     If true, the user can use the mouse to select text in some
1058     platform-specific way. Note that for some platforms this may
1059     not be an appropriate interaction (eg. may conflict with how
1060     the text needs to behave inside a Flickable.
1061 */
1062 bool QSGTextEdit::selectByMouse() const
1063 {
1064     Q_D(const QSGTextEdit);
1065     return d->selectByMouse;
1066 }
1067
1068 void QSGTextEdit::setSelectByMouse(bool on)
1069 {
1070     Q_D(QSGTextEdit);
1071     if (d->selectByMouse != on) {
1072         d->selectByMouse = on;
1073         setKeepMouseGrab(on);
1074         if (on)
1075             setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1076         else
1077             setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1078         emit selectByMouseChanged(on);
1079     }
1080 }
1081
1082 /*!
1083     \qmlproperty enum QtQuick2::TextEdit::mouseSelectionMode
1084
1085     Specifies how text should be selected using a mouse.
1086
1087     \list
1088     \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1089     \o TextEdit.SelectWords - The selection is updated with whole words.
1090     \endlist
1091
1092     This property only applies when \l selectByMouse is true.
1093 */
1094 QSGTextEdit::SelectionMode QSGTextEdit::mouseSelectionMode() const
1095 {
1096     Q_D(const QSGTextEdit);
1097     return d->mouseSelectionMode;
1098 }
1099
1100 void QSGTextEdit::setMouseSelectionMode(SelectionMode mode)
1101 {
1102     Q_D(QSGTextEdit);
1103     if (d->mouseSelectionMode != mode) {
1104         d->mouseSelectionMode = mode;
1105         d->control->setWordSelectionEnabled(mode == SelectWords);
1106         emit mouseSelectionModeChanged(mode);
1107     }
1108 }
1109
1110 /*!
1111     \qmlproperty bool QtQuick2::TextEdit::readOnly
1112
1113     Whether the user can interact with the TextEdit item. If this
1114     property is set to true the text cannot be edited by user interaction.
1115
1116     By default this property is false.
1117 */
1118 void QSGTextEdit::setReadOnly(bool r)
1119 {
1120     Q_D(QSGTextEdit);
1121     if (r == isReadOnly())
1122         return;
1123
1124     setFlag(QSGItem::ItemAcceptsInputMethod, !r);
1125     Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1126     if (d->selectByMouse)
1127         flags = flags | Qt::TextSelectableByMouse;
1128     if (!r)
1129         flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1130     d->control->setTextInteractionFlags(flags);
1131     if (!r)
1132         d->control->moveCursor(QTextCursor::End);
1133
1134     emit readOnlyChanged(r);
1135 }
1136
1137 bool QSGTextEdit::isReadOnly() const
1138 {
1139     Q_D(const QSGTextEdit);
1140     return !(d->control->textInteractionFlags() & Qt::TextEditable);
1141 }
1142
1143 /*!
1144     Sets how the text edit should interact with user input to the given
1145     \a flags.
1146 */
1147 void QSGTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1148 {
1149     Q_D(QSGTextEdit);
1150     d->control->setTextInteractionFlags(flags);
1151 }
1152
1153 /*!
1154     Returns the flags specifying how the text edit should interact
1155     with user input.
1156 */
1157 Qt::TextInteractionFlags QSGTextEdit::textInteractionFlags() const
1158 {
1159     Q_D(const QSGTextEdit);
1160     return d->control->textInteractionFlags();
1161 }
1162
1163 /*!
1164     \qmlproperty rectangle QtQuick2::TextEdit::cursorRectangle
1165
1166     The rectangle where the text cursor is rendered
1167     within the text edit. Read-only.
1168 */
1169 QRect QSGTextEdit::cursorRectangle() const
1170 {
1171     Q_D(const QSGTextEdit);
1172     return d->control->cursorRect().toRect().translated(0,d->yoff);
1173 }
1174
1175 bool QSGTextEdit::event(QEvent *event)
1176 {
1177     Q_D(QSGTextEdit);
1178     if (event->type() == QEvent::ShortcutOverride) {
1179         d->control->processEvent(event, QPointF(0, -d->yoff));
1180         return event->isAccepted();
1181     }
1182     return QSGImplicitSizeItem::event(event);
1183 }
1184
1185 /*!
1186 \overload
1187 Handles the given key \a event.
1188 */
1189 void QSGTextEdit::keyPressEvent(QKeyEvent *event)
1190 {
1191     Q_D(QSGTextEdit);
1192     d->control->processEvent(event, QPointF(0, -d->yoff));
1193     if (!event->isAccepted())
1194         QSGImplicitSizeItem::keyPressEvent(event);
1195 }
1196
1197 /*!
1198 \overload
1199 Handles the given key \a event.
1200 */
1201 void QSGTextEdit::keyReleaseEvent(QKeyEvent *event)
1202 {
1203     Q_D(QSGTextEdit);
1204     d->control->processEvent(event, QPointF(0, -d->yoff));
1205     if (!event->isAccepted())
1206         QSGImplicitSizeItem::keyReleaseEvent(event);
1207 }
1208
1209 /*!
1210     \qmlmethod void QtQuick2::TextEdit::deselect()
1211
1212     Removes active text selection.
1213 */
1214 void QSGTextEdit::deselect()
1215 {
1216     Q_D(QSGTextEdit);
1217     QTextCursor c = d->control->textCursor();
1218     c.clearSelection();
1219     d->control->setTextCursor(c);
1220 }
1221
1222 /*!
1223     \qmlmethod void QtQuick2::TextEdit::selectAll()
1224
1225     Causes all text to be selected.
1226 */
1227 void QSGTextEdit::selectAll()
1228 {
1229     Q_D(QSGTextEdit);
1230     d->control->selectAll();
1231 }
1232
1233 /*!
1234     \qmlmethod void QtQuick2::TextEdit::selectWord()
1235
1236     Causes the word closest to the current cursor position to be selected.
1237 */
1238 void QSGTextEdit::selectWord()
1239 {
1240     Q_D(QSGTextEdit);
1241     QTextCursor c = d->control->textCursor();
1242     c.select(QTextCursor::WordUnderCursor);
1243     d->control->setTextCursor(c);
1244 }
1245
1246 /*!
1247     \qmlmethod void QtQuick2::TextEdit::select(int start, int end)
1248
1249     Causes the text from \a start to \a end to be selected.
1250
1251     If either start or end is out of range, the selection is not changed.
1252
1253     After calling this, selectionStart will become the lesser
1254     and selectionEnd will become the greater (regardless of the order passed
1255     to this method).
1256
1257     \sa selectionStart, selectionEnd
1258 */
1259 void QSGTextEdit::select(int start, int end)
1260 {
1261     Q_D(QSGTextEdit);
1262     if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
1263         return;
1264     QTextCursor cursor = d->control->textCursor();
1265     cursor.beginEditBlock();
1266     cursor.setPosition(start, QTextCursor::MoveAnchor);
1267     cursor.setPosition(end, QTextCursor::KeepAnchor);
1268     cursor.endEditBlock();
1269     d->control->setTextCursor(cursor);
1270
1271     // QTBUG-11100
1272     updateSelectionMarkers();
1273 }
1274
1275 /*!
1276     \qmlmethod void QtQuick2::TextEdit::isRightToLeft(int start, int end)
1277
1278     Returns true if the natural reading direction of the editor text
1279     found between positions \a start and \a end is right to left.
1280 */
1281 bool QSGTextEdit::isRightToLeft(int start, int end)
1282 {
1283     Q_D(QSGTextEdit);
1284     if (start > end) {
1285         qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1286         return false;
1287     } else {
1288         return d->text.mid(start, end - start).isRightToLeft();
1289     }
1290 }
1291
1292 #ifndef QT_NO_CLIPBOARD
1293 /*!
1294     \qmlmethod QtQuick2::TextEdit::cut()
1295
1296     Moves the currently selected text to the system clipboard.
1297 */
1298 void QSGTextEdit::cut()
1299 {
1300     Q_D(QSGTextEdit);
1301     d->control->cut();
1302 }
1303
1304 /*!
1305     \qmlmethod QtQuick2::TextEdit::copy()
1306
1307     Copies the currently selected text to the system clipboard.
1308 */
1309 void QSGTextEdit::copy()
1310 {
1311     Q_D(QSGTextEdit);
1312     d->control->copy();
1313 }
1314
1315 /*!
1316     \qmlmethod QtQuick2::TextEdit::paste()
1317
1318     Replaces the currently selected text by the contents of the system clipboard.
1319 */
1320 void QSGTextEdit::paste()
1321 {
1322     Q_D(QSGTextEdit);
1323     d->control->paste();
1324 }
1325 #endif // QT_NO_CLIPBOARD
1326
1327 /*!
1328 \overload
1329 Handles the given mouse \a event.
1330 */
1331 void QSGTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
1332 {
1333     Q_D(QSGTextEdit);
1334     if (d->focusOnPress){
1335         bool hadActiveFocus = hasActiveFocus();
1336         forceActiveFocus();
1337         if (d->showInputPanelOnFocus) {
1338             if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1339                 // re-open input panel on press if already focused
1340                 openSoftwareInputPanel();
1341             }
1342         } else { // show input panel on click
1343             if (hasActiveFocus() && !hadActiveFocus) {
1344                 d->clickCausedFocus = true;
1345             }
1346         }
1347     }
1348     d->control->processEvent(event, QPointF(0, -d->yoff));
1349     if (!event->isAccepted())
1350         QSGImplicitSizeItem::mousePressEvent(event);
1351 }
1352
1353 /*!
1354 \overload
1355 Handles the given mouse \a event.
1356 */
1357 void QSGTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1358 {
1359     Q_D(QSGTextEdit);
1360     d->control->processEvent(event, QPointF(0, -d->yoff));
1361     if (!d->showInputPanelOnFocus) { // input panel on click
1362         if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1363             if (canvas() && canvas() == qApp->focusWidget()) {
1364                 qt_widget_private(canvas())->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1365             }
1366         }
1367     }
1368     d->clickCausedFocus = false;
1369
1370     if (!event->isAccepted())
1371         QSGImplicitSizeItem::mouseReleaseEvent(event);
1372 }
1373
1374 /*!
1375 \overload
1376 Handles the given mouse \a event.
1377 */
1378 void QSGTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1379 {
1380     Q_D(QSGTextEdit);
1381     d->control->processEvent(event, QPointF(0, -d->yoff));
1382     if (!event->isAccepted())
1383         QSGImplicitSizeItem::mouseDoubleClickEvent(event);
1384 }
1385
1386 /*!
1387 \overload
1388 Handles the given mouse \a event.
1389 */
1390 void QSGTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1391 {
1392     Q_D(QSGTextEdit);
1393     d->control->processEvent(event, QPointF(0, -d->yoff));
1394     if (!event->isAccepted())
1395         QSGImplicitSizeItem::mouseMoveEvent(event);
1396 }
1397
1398 /*!
1399 \overload
1400 Handles the given input method \a event.
1401 */
1402 void QSGTextEdit::inputMethodEvent(QInputMethodEvent *event)
1403 {
1404     Q_D(QSGTextEdit);
1405     const bool wasComposing = isInputMethodComposing();
1406     d->control->processEvent(event, QPointF(0, -d->yoff));
1407     if (wasComposing != isInputMethodComposing())
1408         emit inputMethodComposingChanged();
1409 }
1410
1411 void QSGTextEdit::itemChange(ItemChange change, const ItemChangeData &value)
1412 {
1413     Q_D(QSGTextEdit);
1414     if (change == ItemActiveFocusHasChanged) {
1415         setCursorVisible(value.boolValue && d->canvas && d->canvas->hasFocus());
1416     }
1417     QSGItem::itemChange(change, value);
1418 }
1419
1420 /*!
1421 \overload
1422 Returns the value of the given \a property.
1423 */
1424 QVariant QSGTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1425 {
1426     Q_D(const QSGTextEdit);
1427     return d->control->inputMethodQuery(property);
1428 }
1429
1430 void QSGTextEdit::updateImageCache(const QRectF &)
1431 {
1432     Q_D(QSGTextEdit);
1433
1434     // Do we really need the image cache?
1435     if (!d->richText || !d->isComplexRichText) {
1436         if (!d->pixmapCache.isNull())
1437             d->pixmapCache = QPixmap();
1438         return;
1439     }
1440
1441     if (width() != d->pixmapCache.width() || height() != d->pixmapCache.height())
1442         d->pixmapCache = QPixmap(width(), height());
1443
1444     if (d->pixmapCache.isNull())
1445         return;
1446
1447     // ### Use supplied rect, clear area and update only this part (for cursor updates)
1448     QRectF bounds = QRectF(0, 0, width(), height());
1449     d->pixmapCache.fill(Qt::transparent);
1450     {
1451         QPainter painter(&d->pixmapCache);
1452
1453         painter.setRenderHint(QPainter::TextAntialiasing);
1454         painter.translate(0, d->yoff);
1455
1456         d->control->drawContents(&painter, bounds);
1457     }
1458
1459 }
1460
1461 QSGNode *QSGTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
1462 {
1463     Q_UNUSED(updatePaintNodeData);
1464     Q_D(QSGTextEdit);
1465
1466     QSGNode *currentNode = oldNode;
1467     if (d->richText && d->isComplexRichText) {
1468         QSGImageNode *node = 0;
1469         if (oldNode == 0 || d->nodeType != QSGTextEditPrivate::NodeIsTexture) {
1470             delete oldNode;
1471             node = QSGItemPrivate::get(this)->sceneGraphContext()->createImageNode();
1472             d->texture = new QSGPlainTexture();
1473             d->nodeType = QSGTextEditPrivate::NodeIsTexture;
1474             currentNode = node;
1475         } else {
1476             node = static_cast<QSGImageNode *>(oldNode);
1477         }
1478
1479         qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->pixmapCache.toImage());
1480         node->setTexture(0);
1481         node->setTexture(d->texture);
1482
1483         node->setTargetRect(QRectF(0, 0, d->pixmapCache.width(), d->pixmapCache.height()));
1484         node->setSourceRect(QRectF(0, 0, 1, 1));
1485         node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
1486         node->setVerticalWrapMode(QSGTexture::ClampToEdge);
1487         node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that..
1488         node->update();
1489
1490     } else if (oldNode == 0 || d->documentDirty) {
1491         d->documentDirty = false;
1492
1493 #if defined(Q_WS_MAC)
1494         // Make sure document is relayouted in the paint node on Mac
1495         // to avoid crashes due to the font engines created in the
1496         // shaping process
1497         d->document->markContentsDirty(0, d->document->characterCount());
1498 #endif
1499
1500         QSGTextNode *node = 0;
1501         if (oldNode == 0 || d->nodeType != QSGTextEditPrivate::NodeIsText) {
1502             delete oldNode;
1503             node = new QSGTextNode(QSGItemPrivate::get(this)->sceneGraphContext());
1504             d->nodeType = QSGTextEditPrivate::NodeIsText;
1505             currentNode = node;
1506         } else {
1507             node = static_cast<QSGTextNode *>(oldNode);
1508         }
1509
1510         node->deleteContent();
1511         node->setMatrix(QMatrix4x4());
1512
1513         QRectF bounds = boundingRect();
1514
1515         QColor selectionColor = d->control->palette().color(QPalette::Highlight);
1516         QColor selectedTextColor = d->control->palette().color(QPalette::HighlightedText);
1517         node->addTextDocument(bounds.topLeft(), d->document, d->color, QSGText::Normal, QColor(),
1518                               selectionColor, selectedTextColor, selectionStart(),
1519                               selectionEnd());
1520
1521 #if defined(Q_WS_MAC)
1522         // We also need to make sure the document layout is redone when
1523         // control is returned to the main thread, as all the font engines
1524         // are now owned by the rendering thread
1525         d->document->markContentsDirty(0, d->document->characterCount());
1526 #endif
1527     }
1528
1529     if (d->nodeType == QSGTextEditPrivate::NodeIsText && d->cursorComponent == 0 && !isReadOnly()) {
1530         QSGTextNode *node = static_cast<QSGTextNode *>(currentNode);
1531
1532         QColor color = (!d->cursorVisible || !d->control->cursorOn())
1533                 ? QColor(0, 0, 0, 0)
1534                 : d->color;
1535
1536         if (node->cursorNode() == 0) {
1537             node->setCursor(cursorRectangle(), color);
1538         } else {
1539             node->cursorNode()->setRect(cursorRectangle());
1540             node->cursorNode()->setColor(color);
1541         }
1542
1543     }
1544
1545     return currentNode;
1546 }
1547
1548 /*!
1549     \qmlproperty bool QtQuick2::TextEdit::smooth
1550
1551     This property holds whether the text is smoothly scaled or transformed.
1552
1553     Smooth filtering gives better visual quality, but is slower.  If
1554     the item is displayed at its natural size, this property has no visual or
1555     performance effect.
1556
1557     \note Generally scaling artifacts are only visible if the item is stationary on
1558     the screen.  A common pattern when animating an item is to disable smooth
1559     filtering at the beginning of the animation and reenable it at the conclusion.
1560 */
1561
1562 /*!
1563     \qmlproperty bool QtQuick2::TextEdit::canPaste
1564
1565     Returns true if the TextEdit is writable and the content of the clipboard is
1566     suitable for pasting into the TextEdit.
1567 */
1568 bool QSGTextEdit::canPaste() const
1569 {
1570     Q_D(const QSGTextEdit);
1571     return d->canPaste;
1572 }
1573
1574 /*!
1575     \qmlproperty bool QtQuick2::TextEdit::inputMethodComposing
1576
1577
1578     This property holds whether the TextEdit has partial text input from an
1579     input method.
1580
1581     While it is composing an input method may rely on mouse or key events from
1582     the TextEdit to edit or commit the partial text.  This property can be used
1583     to determine when to disable events handlers that may interfere with the
1584     correct operation of an input method.
1585 */
1586 bool QSGTextEdit::isInputMethodComposing() const
1587 {
1588     Q_D(const QSGTextEdit);
1589     if (QTextLayout *layout = d->control->textCursor().block().layout())
1590         return layout->preeditAreaText().length() > 0;
1591     return false;
1592 }
1593
1594 void QSGTextEditPrivate::init()
1595 {
1596     Q_Q(QSGTextEdit);
1597
1598     q->setSmooth(smooth);
1599     q->setAcceptedMouseButtons(Qt::LeftButton);
1600     q->setFlag(QSGItem::ItemAcceptsInputMethod);
1601     q->setFlag(QSGItem::ItemHasContents);
1602
1603     control = new QTextControl(q);
1604     control->setIgnoreUnusedNavigationEvents(true);
1605     control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1606     control->setDragEnabled(false);
1607
1608     // By default, QTextControl will issue both a updateCursorRequest() and an updateRequest()
1609     // when the cursor needs to be repainted. We need the signals to be separate to be able to
1610     // distinguish the cursor updates so that we can avoid updating the whole subtree when the
1611     // cursor blinks.
1612     if (!QObject::disconnect(control, SIGNAL(updateCursorRequest(QRectF)),
1613                              control, SIGNAL(updateRequest(QRectF)))) {
1614         qWarning("QSGTextEditPrivate::init: Failed to disconnect updateCursorRequest and updateRequest");
1615     }
1616
1617     // QTextControl follows the default text color
1618     // defined by the platform, declarative text
1619     // should be black by default
1620     QPalette pal = control->palette();
1621     if (pal.color(QPalette::Text) != color) {
1622         pal.setColor(QPalette::Text, color);
1623         control->setPalette(pal);
1624     }
1625
1626     QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument()));
1627     QObject::connect(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor()));
1628     QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1629     QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1630     QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1631     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1632     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1633     QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate()));
1634     QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1635 #ifndef QT_NO_CLIPBOARD
1636     QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
1637     QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1638     canPaste = control->canPaste();
1639 #endif
1640
1641     document = control->document();
1642     document->setDefaultFont(font);
1643     document->setDocumentMargin(textMargin);
1644     document->setUndoRedoEnabled(false); // flush undo buffer.
1645     document->setUndoRedoEnabled(true);
1646     updateDefaultTextOption();
1647 }
1648
1649 void QSGTextEdit::q_textChanged()
1650 {
1651     Q_D(QSGTextEdit);
1652     d->text = text();
1653     d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
1654     d->determineHorizontalAlignment();
1655     d->updateDefaultTextOption();
1656     updateSize();
1657     updateTotalLines();
1658     emit textChanged(d->text);
1659 }
1660
1661 void QSGTextEdit::moveCursorDelegate()
1662 {
1663     Q_D(QSGTextEdit);
1664     updateMicroFocus();
1665     emit cursorRectangleChanged();
1666     if(!d->cursor)
1667         return;
1668     QRectF cursorRect = cursorRectangle();
1669     d->cursor->setX(cursorRect.x());
1670     d->cursor->setY(cursorRect.y());
1671 }
1672
1673 void QSGTextEditPrivate::updateSelection()
1674 {
1675     Q_Q(QSGTextEdit);
1676     QTextCursor cursor = control->textCursor();
1677     bool startChange = (lastSelectionStart != cursor.selectionStart());
1678     bool endChange = (lastSelectionEnd != cursor.selectionEnd());
1679     cursor.beginEditBlock();
1680     cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
1681     cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
1682     cursor.endEditBlock();
1683     control->setTextCursor(cursor);
1684     if(startChange)
1685         q->selectionStartChanged();
1686     if(endChange)
1687         q->selectionEndChanged();
1688 }
1689
1690 void QSGTextEdit::updateSelectionMarkers()
1691 {
1692     Q_D(QSGTextEdit);
1693     if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
1694         d->lastSelectionStart = d->control->textCursor().selectionStart();
1695         emit selectionStartChanged();
1696     }
1697     if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
1698         d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1699         emit selectionEndChanged();
1700     }
1701 }
1702
1703 QRectF QSGTextEdit::boundingRect() const
1704 {
1705     Q_D(const QSGTextEdit);
1706     QRectF r = QSGImplicitSizeItem::boundingRect();
1707     int cursorWidth = 1;
1708     if(d->cursor)
1709         cursorWidth = d->cursor->width();
1710     if(!d->document->isEmpty())
1711         cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1712
1713     // Could include font max left/right bearings to either side of rectangle.
1714
1715     r.setRight(r.right() + cursorWidth);
1716     return r.translated(0,d->yoff);
1717 }
1718
1719 qreal QSGTextEditPrivate::getImplicitWidth() const
1720 {
1721     Q_Q(const QSGTextEdit);
1722     if (!requireImplicitWidth) {
1723         // We don't calculate implicitWidth unless it is required.
1724         // We need to force a size update now to ensure implicitWidth is calculated
1725         const_cast<QSGTextEditPrivate*>(this)->requireImplicitWidth = true;
1726         const_cast<QSGTextEdit*>(q)->updateSize();
1727     }
1728     return implicitWidth;
1729 }
1730
1731 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1732 //    need to do all the calculations each time
1733 void QSGTextEdit::updateSize()
1734 {
1735     Q_D(QSGTextEdit);
1736     if (isComponentComplete()) {
1737         qreal naturalWidth = d->implicitWidth;
1738         // ### assumes that if the width is set, the text will fill to edges
1739         // ### (unless wrap is false, then clipping will occur)
1740         if (widthValid()) {
1741             if (!d->requireImplicitWidth) {
1742                 emit implicitWidthChanged();
1743                 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1744                 if (d->requireImplicitWidth)
1745                     return;
1746             }
1747             if (d->requireImplicitWidth) {
1748                 d->document->setTextWidth(-1);
1749                 naturalWidth = d->document->idealWidth();
1750             }
1751             if (d->document->textWidth() != width())
1752                 d->document->setTextWidth(width());
1753         } else {
1754             d->document->setTextWidth(-1);
1755         }
1756         QFontMetrics fm = QFontMetrics(d->font);
1757         int dy = height();
1758         dy -= (int)d->document->size().height();
1759
1760         int nyoff;
1761         if (heightValid()) {
1762             if (d->vAlign == AlignBottom)
1763                 nyoff = dy;
1764             else if (d->vAlign == AlignVCenter)
1765                 nyoff = dy/2;
1766             else
1767                 nyoff = 0;
1768         } else {
1769             nyoff = 0;
1770         }
1771         if (nyoff != d->yoff)
1772             d->yoff = nyoff;
1773         setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1774
1775         //### need to comfirm cost of always setting these
1776         int newWidth = qCeil(d->document->idealWidth());
1777         if (!widthValid() && d->document->textWidth() != newWidth)
1778             d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1779         // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1780         if (!widthValid())
1781             setImplicitWidth(newWidth);
1782         else if (d->requireImplicitWidth)
1783             setImplicitWidth(naturalWidth);
1784         qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1785         setImplicitHeight(newHeight);
1786
1787         d->paintedSize = QSize(newWidth, newHeight);
1788         emit paintedSizeChanged();
1789     } else {
1790         d->dirty = true;
1791     }
1792     updateDocument();
1793 }
1794
1795 void QSGTextEdit::updateDocument()
1796 {
1797     Q_D(QSGTextEdit);
1798     d->documentDirty = true;
1799
1800     if (isComponentComplete()) {
1801         updateImageCache();
1802         update();
1803     }
1804 }
1805
1806 void QSGTextEdit::updateCursor()
1807 {
1808     Q_D(QSGTextEdit);
1809     if (isComponentComplete()) {
1810         updateImageCache(d->control->cursorRect());
1811         update();
1812     }
1813 }
1814
1815 void QSGTextEdit::updateTotalLines()
1816 {
1817     Q_D(QSGTextEdit);
1818
1819     int subLines = 0;
1820
1821     for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1822         QTextLayout *layout = it.layout();
1823         if (!layout)
1824             continue;
1825         subLines += layout->lineCount()-1;
1826     }
1827
1828     int newTotalLines = d->document->lineCount() + subLines;
1829     if (d->lineCount != newTotalLines) {
1830         d->lineCount = newTotalLines;
1831         emit lineCountChanged();
1832     }
1833 }
1834
1835 void QSGTextEditPrivate::updateDefaultTextOption()
1836 {
1837     Q_Q(QSGTextEdit);
1838     QTextOption opt = document->defaultTextOption();
1839     int oldAlignment = opt.alignment();
1840
1841     QSGTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1842     if (rightToLeftText) {
1843         if (horizontalAlignment == QSGTextEdit::AlignLeft)
1844             horizontalAlignment = QSGTextEdit::AlignRight;
1845         else if (horizontalAlignment == QSGTextEdit::AlignRight)
1846             horizontalAlignment = QSGTextEdit::AlignLeft;
1847     }
1848     opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
1849
1850     QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1851     opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1852
1853     bool oldUseDesignMetrics = opt.useDesignMetrics();
1854     bool useDesignMetrics = !qmlDisableDistanceField();
1855     opt.setUseDesignMetrics(useDesignMetrics);
1856
1857     if (oldWrapMode == opt.wrapMode()
1858             && oldAlignment == opt.alignment()
1859             && oldUseDesignMetrics == useDesignMetrics) {
1860         return;
1861     }
1862     document->setDefaultTextOption(opt);
1863 }
1864
1865
1866
1867 /*!
1868     \qmlmethod void QtQuick2::TextEdit::openSoftwareInputPanel()
1869
1870     Opens software input panels like virtual keyboards for typing, useful for
1871     customizing when you want the input keyboard to be shown and hidden in
1872     your application.
1873
1874     By default the opening of input panels follows the platform style. On Symbian^1 and
1875     Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1876     the panels are automatically opened when TextEdit element gains active focus. Input panels are
1877     always closed if no editor has active focus.
1878
1879     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1880     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1881     the behavior you want.
1882
1883     Only relevant on platforms, which provide virtual keyboards.
1884
1885     \code
1886         import QtQuick 1.0
1887         TextEdit {
1888             id: textEdit
1889             text: "Hello world!"
1890             activeFocusOnPress: false
1891             MouseArea {
1892                 anchors.fill: parent
1893                 onClicked: {
1894                     if (!textEdit.activeFocus) {
1895                         textEdit.forceActiveFocus();
1896                         textEdit.openSoftwareInputPanel();
1897                     } else {
1898                         textEdit.focus = false;
1899                     }
1900                 }
1901                 onPressAndHold: textEdit.closeSoftwareInputPanel();
1902             }
1903         }
1904     \endcode
1905 */
1906 void QSGTextEdit::openSoftwareInputPanel()
1907 {
1908     if (qApp) {
1909         if (canvas() && canvas() == qApp->focusWidget()) {
1910             QEvent event(QEvent::RequestSoftwareInputPanel);
1911             QApplication::sendEvent(canvas(), &event);
1912         }
1913     }
1914 }
1915
1916 /*!
1917     \qmlmethod void QtQuick2::TextEdit::closeSoftwareInputPanel()
1918
1919     Closes a software input panel like a virtual keyboard shown on the screen, useful
1920     for customizing when you want the input keyboard to be shown and hidden in
1921     your application.
1922
1923     By default the opening of input panels follows the platform style. On Symbian^1 and
1924     Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1925     the panels are automatically opened when TextEdit element gains active focus. Input panels are
1926     always closed if no editor has active focus.
1927
1928     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1929     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1930     the behavior you want.
1931
1932     Only relevant on platforms, which provide virtual keyboards.
1933
1934     \code
1935         import QtQuick 1.0
1936         TextEdit {
1937             id: textEdit
1938             text: "Hello world!"
1939             activeFocusOnPress: false
1940             MouseArea {
1941                 anchors.fill: parent
1942                 onClicked: {
1943                     if (!textEdit.activeFocus) {
1944                         textEdit.forceActiveFocus();
1945                         textEdit.openSoftwareInputPanel();
1946                     } else {
1947                         textEdit.focus = false;
1948                     }
1949                 }
1950                 onPressAndHold: textEdit.closeSoftwareInputPanel();
1951             }
1952         }
1953     \endcode
1954 */
1955 void QSGTextEdit::closeSoftwareInputPanel()
1956 {
1957     if (qApp) {
1958         if (canvas() && canvas() == qApp->focusWidget()) {
1959             QEvent event(QEvent::CloseSoftwareInputPanel);
1960             QApplication::sendEvent(canvas(), &event);
1961         }
1962     }
1963 }
1964
1965 void QSGTextEdit::focusInEvent(QFocusEvent *event)
1966 {
1967     Q_D(const QSGTextEdit);
1968     if (d->showInputPanelOnFocus) {
1969         if (d->focusOnPress && !isReadOnly()) {
1970             openSoftwareInputPanel();
1971         }
1972     }
1973     QSGImplicitSizeItem::focusInEvent(event);
1974 }
1975
1976 void QSGTextEdit::q_canPasteChanged()
1977 {
1978     Q_D(QSGTextEdit);
1979     bool old = d->canPaste;
1980     d->canPaste = d->control->canPaste();
1981     if(old!=d->canPaste)
1982         emit canPasteChanged();
1983 }
1984
1985 QT_END_NAMESPACE