Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / graphicsitems / qdeclarativetextedit.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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativetextedit_p.h"
43 #include "private/qdeclarativetextedit_p_p.h"
44
45 #include "private/qdeclarativeevents_p_p.h"
46 #include <private/qdeclarativeglobal_p.h>
47 #include <qdeclarativeinfo.h>
48
49 #include <QtCore/qmath.h>
50
51 #include <private/qtextengine_p.h>
52 #include <QTextLayout>
53 #include <QTextLine>
54 #include <QTextDocument>
55 #include <QTextObject>
56 #include <QGraphicsSceneMouseEvent>
57 #include <QDebug>
58 #include <QPainter>
59
60 #include <private/qtextcontrol_p.h>
61
62 QT_BEGIN_NAMESPACE
63
64 /*!
65     \qmlclass TextEdit QDeclarativeTextEdit
66     \ingroup qml-basic-visual-elements
67     \since 4.7
68     \brief The TextEdit item displays multiple lines of editable formatted text.
69     \inherits Item
70
71     The TextEdit item displays a block of editable, formatted text.
72
73     It can display both plain and rich text. For example:
74
75     \qml
76 TextEdit {
77     width: 240
78     text: "<b>Hello</b> <i>World!</i>"
79     font.family: "Helvetica"
80     font.pointSize: 20
81     color: "blue"
82     focus: true
83 }
84     \endqml
85
86     \image declarative-textedit.gif
87
88     Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
89
90     Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
91     to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
92
93     \snippet snippets/declarative/texteditor.qml 0
94
95     A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
96     scrollbar, or a scrollbar that fades in to show location, etc.
97
98     Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
99     be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
100     from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
101
102     You can translate between cursor positions (characters from the start of the document) and pixel
103     points using positionAt() and positionToRectangle().
104
105     \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
106 */
107
108 /*!
109     \qmlsignal TextEdit::onLinkActivated(string link)
110     \since Quick 1.1
111
112     This handler is called when the user clicks on a link embedded in the text.
113     The link must be in rich text or HTML format and the
114     \a link string provides access to the particular link.
115 */
116 QDeclarativeTextEdit::QDeclarativeTextEdit(QDeclarativeItem *parent)
117 : QDeclarativeImplicitSizePaintedItem(*(new QDeclarativeTextEditPrivate), parent)
118 {
119     Q_D(QDeclarativeTextEdit);
120     d->init();
121 }
122
123 QString QDeclarativeTextEdit::text() const
124 {
125     Q_D(const QDeclarativeTextEdit);
126
127 #ifndef QT_NO_TEXTHTMLPARSER
128     if (d->richText)
129         return d->document->toHtml();
130     else
131 #endif
132         return d->document->toPlainText();
133 }
134
135 /*!
136     \qmlproperty string TextEdit::font.family
137
138     Sets the family name of the font.
139
140     The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
141     If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
142     If the family isn't available a family will be set using the font matching algorithm.
143 */
144
145 /*!
146     \qmlproperty bool TextEdit::font.bold
147
148     Sets whether the font weight is bold.
149 */
150
151 /*!
152     \qmlproperty enumeration TextEdit::font.weight
153
154     Sets the font's weight.
155
156     The weight can be one of:
157     \list
158     \o Font.Light
159     \o Font.Normal - the default
160     \o Font.DemiBold
161     \o Font.Bold
162     \o Font.Black
163     \endlist
164
165     \qml
166     TextEdit { text: "Hello"; font.weight: Font.DemiBold }
167     \endqml
168 */
169
170 /*!
171     \qmlproperty bool TextEdit::font.italic
172
173     Sets whether the font has an italic style.
174 */
175
176 /*!
177     \qmlproperty bool TextEdit::font.underline
178
179     Sets whether the text is underlined.
180 */
181
182 /*!
183     \qmlproperty bool TextEdit::font.strikeout
184
185     Sets whether the font has a strikeout style.
186 */
187
188 /*!
189     \qmlproperty real TextEdit::font.pointSize
190
191     Sets the font size in points. The point size must be greater than zero.
192 */
193
194 /*!
195     \qmlproperty int TextEdit::font.pixelSize
196
197     Sets the font size in pixels.
198
199     Using this function makes the font device dependent.  Use
200     \l{TextEdit::font.pointSize} to set the size of the font in a
201     device independent manner.
202 */
203
204 /*!
205     \qmlproperty real TextEdit::font.letterSpacing
206
207     Sets the letter spacing for the font.
208
209     Letter spacing changes the default spacing between individual letters in the font.
210     A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
211 */
212
213 /*!
214     \qmlproperty real TextEdit::font.wordSpacing
215
216     Sets the word spacing for the font.
217
218     Word spacing changes the default spacing between individual words.
219     A positive value increases the word spacing by a corresponding amount of pixels,
220     while a negative value decreases the inter-word spacing accordingly.
221 */
222
223 /*!
224     \qmlproperty enumeration TextEdit::font.capitalization
225
226     Sets the capitalization for the text.
227
228     \list
229     \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
230     \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
231     \o Font.AllLowercase         - This alters the text to be rendered in all lowercase type.
232     \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
233     \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
234     \endlist
235
236     \qml
237     TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
238     \endqml
239 */
240
241 /*!
242     \qmlproperty string TextEdit::text
243
244     The text to display.  If the text format is AutoText the text edit will
245     automatically determine whether the text should be treated as
246     rich text.  This determination is made using Qt::mightBeRichText().
247 */
248 void QDeclarativeTextEdit::setText(const QString &text)
249 {
250     Q_D(QDeclarativeTextEdit);
251     if (QDeclarativeTextEdit::text() == text)
252         return;
253
254     d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
255     if (d->richText) {
256 #ifndef QT_NO_TEXTHTMLPARSER
257         d->control->setHtml(text);
258 #else
259         d->control->setPlainText(text);
260 #endif
261     } else {
262         d->control->setPlainText(text);
263     }
264     q_textChanged();
265 }
266
267 /*!
268     \qmlproperty enumeration TextEdit::textFormat
269
270     The way the text property should be displayed.
271
272     \list
273     \o TextEdit.AutoText
274     \o TextEdit.PlainText
275     \o TextEdit.RichText
276     \o TextEdit.StyledText
277     \endlist
278
279     The default is TextEdit.AutoText.  If the text format is TextEdit.AutoText the text edit
280     will automatically determine whether the text should be treated as
281     rich text.  This determination is made using Qt::mightBeRichText().
282
283     \table
284     \row
285     \o
286     \qml
287 Column {
288     TextEdit {
289         font.pointSize: 24
290         text: "<b>Hello</b> <i>World!</i>"
291     }
292     TextEdit {
293         font.pointSize: 24
294         textFormat: TextEdit.RichText
295         text: "<b>Hello</b> <i>World!</i>"
296     }
297     TextEdit {
298         font.pointSize: 24
299         textFormat: TextEdit.PlainText
300         text: "<b>Hello</b> <i>World!</i>"
301     }
302 }
303     \endqml
304     \o \image declarative-textformat.png
305     \endtable
306 */
307 QDeclarativeTextEdit::TextFormat QDeclarativeTextEdit::textFormat() const
308 {
309     Q_D(const QDeclarativeTextEdit);
310     return d->format;
311 }
312
313 void QDeclarativeTextEdit::setTextFormat(TextFormat format)
314 {
315     Q_D(QDeclarativeTextEdit);
316     if (format == d->format)
317         return;
318     bool wasRich = d->richText;
319     d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
320
321     if (wasRich && !d->richText) {
322         d->control->setPlainText(d->text);
323         updateSize();
324     } else if (!wasRich && d->richText) {
325 #ifndef QT_NO_TEXTHTMLPARSER
326         d->control->setHtml(d->text);
327 #else
328         d->control->setPlainText(d->text);
329 #endif
330         updateSize();
331     }
332     d->format = format;
333     d->control->setAcceptRichText(d->format != PlainText);
334     emit textFormatChanged(d->format);
335 }
336
337 QFont QDeclarativeTextEdit::font() const
338 {
339     Q_D(const QDeclarativeTextEdit);
340     return d->sourceFont;
341 }
342
343 void QDeclarativeTextEdit::setFont(const QFont &font)
344 {
345     Q_D(QDeclarativeTextEdit);
346     if (d->sourceFont == font)
347         return;
348
349     d->sourceFont = font;
350     QFont oldFont = d->font;
351     d->font = font;
352     if (d->font.pointSizeF() != -1) {
353         // 0.5pt resolution
354         qreal size = qRound(d->font.pointSizeF()*2.0);
355         d->font.setPointSizeF(size/2.0);
356     }
357
358     if (oldFont != d->font) {
359         clearCache();
360         d->document->setDefaultFont(d->font);
361         if(d->cursor){
362             d->cursor->setHeight(QFontMetrics(d->font).height());
363             moveCursorDelegate();
364         }
365         updateSize();
366         update();
367     }
368     emit fontChanged(d->sourceFont);
369 }
370
371 /*!
372     \qmlproperty color TextEdit::color
373
374     The text color.
375
376     \qml
377     // green text using hexadecimal notation
378     TextEdit { color: "#00FF00" }
379     \endqml
380
381     \qml
382     // steelblue text using SVG color name
383     TextEdit { color: "steelblue" }
384     \endqml
385 */
386 QColor QDeclarativeTextEdit::color() const
387 {
388     Q_D(const QDeclarativeTextEdit);
389     return d->color;
390 }
391
392 void QDeclarativeTextEdit::setColor(const QColor &color)
393 {
394     Q_D(QDeclarativeTextEdit);
395     if (d->color == color)
396         return;
397
398     clearCache();
399     d->color = color;
400     QPalette pal = d->control->palette();
401     pal.setColor(QPalette::Text, color);
402     d->control->setPalette(pal);
403     update();
404     emit colorChanged(d->color);
405 }
406
407 /*!
408     \qmlproperty color TextEdit::selectionColor
409
410     The text highlight color, used behind selections.
411 */
412 QColor QDeclarativeTextEdit::selectionColor() const
413 {
414     Q_D(const QDeclarativeTextEdit);
415     return d->selectionColor;
416 }
417
418 void QDeclarativeTextEdit::setSelectionColor(const QColor &color)
419 {
420     Q_D(QDeclarativeTextEdit);
421     if (d->selectionColor == color)
422         return;
423
424     clearCache();
425     d->selectionColor = color;
426     QPalette pal = d->control->palette();
427     pal.setColor(QPalette::Highlight, color);
428     d->control->setPalette(pal);
429     update();
430     emit selectionColorChanged(d->selectionColor);
431 }
432
433 /*!
434     \qmlproperty color TextEdit::selectedTextColor
435
436     The selected text color, used in selections.
437 */
438 QColor QDeclarativeTextEdit::selectedTextColor() const
439 {
440     Q_D(const QDeclarativeTextEdit);
441     return d->selectedTextColor;
442 }
443
444 void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color)
445 {
446     Q_D(QDeclarativeTextEdit);
447     if (d->selectedTextColor == color)
448         return;
449
450     clearCache();
451     d->selectedTextColor = color;
452     QPalette pal = d->control->palette();
453     pal.setColor(QPalette::HighlightedText, color);
454     d->control->setPalette(pal);
455     update();
456     emit selectedTextColorChanged(d->selectedTextColor);
457 }
458
459 /*!
460     \qmlproperty enumeration TextEdit::horizontalAlignment
461     \qmlproperty enumeration TextEdit::verticalAlignment
462     \qmlproperty enumeration TextEdit::effectiveHorizontalAlignment
463
464     Sets the horizontal and vertical alignment of the text within the TextEdit item's
465     width and height. By default, the text alignment follows the natural alignment
466     of the text, for example text that is read from left to right will be aligned to
467     the left.
468
469     Valid values for \c horizontalAlignment are:
470     \list
471     \o TextEdit.AlignLeft (default)
472     \o TextEdit.AlignRight 
473     \o TextEdit.AlignHCenter
474     \o TextEdit.AlignJustify
475     \endlist
476     
477     Valid values for \c verticalAlignment are:
478     \list
479     \o TextEdit.AlignTop (default)
480     \o TextEdit.AlignBottom
481     \o TextEdit.AlignVCenter
482     \endlist
483
484     When using the attached property LayoutMirroring::enabled to mirror application
485     layouts, the horizontal alignment of text will also be mirrored. However, the property
486     \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
487     of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
488 */
489 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const
490 {
491     Q_D(const QDeclarativeTextEdit);
492     return d->hAlign;
493 }
494
495 void QDeclarativeTextEdit::setHAlign(HAlignment align)
496 {
497     Q_D(QDeclarativeTextEdit);
498     bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
499     d->hAlignImplicit = false;
500     if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
501         d->updateDefaultTextOption();
502         updateSize();
503     }
504 }
505
506 void QDeclarativeTextEdit::resetHAlign()
507 {
508     Q_D(QDeclarativeTextEdit);
509     d->hAlignImplicit = true;
510     if (d->determineHorizontalAlignment() && isComponentComplete()) {
511         d->updateDefaultTextOption();
512         updateSize();
513     }
514 }
515
516 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::effectiveHAlign() const
517 {
518     Q_D(const QDeclarativeTextEdit);
519     QDeclarativeTextEdit::HAlignment effectiveAlignment = d->hAlign;
520     if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
521         switch (d->hAlign) {
522         case QDeclarativeTextEdit::AlignLeft:
523             effectiveAlignment = QDeclarativeTextEdit::AlignRight;
524             break;
525         case QDeclarativeTextEdit::AlignRight:
526             effectiveAlignment = QDeclarativeTextEdit::AlignLeft;
527             break;
528         default:
529             break;
530         }
531     }
532     return effectiveAlignment;
533 }
534
535 bool QDeclarativeTextEditPrivate::setHAlign(QDeclarativeTextEdit::HAlignment alignment, bool forceAlign)
536 {
537     Q_Q(QDeclarativeTextEdit);
538     if (hAlign != alignment || forceAlign) {
539         QDeclarativeTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
540         hAlign = alignment;
541         emit q->horizontalAlignmentChanged(alignment);
542         if (oldEffectiveHAlign != q->effectiveHAlign())
543             emit q->effectiveHorizontalAlignmentChanged();
544         return true;
545     }
546     return false;
547 }
548
549 bool QDeclarativeTextEditPrivate::determineHorizontalAlignment()
550 {
551     Q_Q(QDeclarativeTextEdit);
552     if (hAlignImplicit && q->isComponentComplete()) {
553         bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
554         return setHAlign(alignToRight ? QDeclarativeTextEdit::AlignRight : QDeclarativeTextEdit::AlignLeft);
555     }
556     return false;
557 }
558
559 void QDeclarativeTextEditPrivate::mirrorChange()
560 {
561     Q_Q(QDeclarativeTextEdit);
562     if (q->isComponentComplete()) {
563         if (!hAlignImplicit && (hAlign == QDeclarativeTextEdit::AlignRight || hAlign == QDeclarativeTextEdit::AlignLeft)) {
564             updateDefaultTextOption();
565             q->updateSize();
566             emit q->effectiveHorizontalAlignmentChanged();
567         }
568     }
569 }
570
571 QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const
572 {
573     Q_D(const QDeclarativeTextEdit);
574     return d->vAlign;
575 }
576
577 void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment)
578 {
579     Q_D(QDeclarativeTextEdit);
580     if (alignment == d->vAlign)
581         return;
582     d->vAlign = alignment;
583     d->updateDefaultTextOption();
584     updateSize();
585     moveCursorDelegate();
586     emit verticalAlignmentChanged(d->vAlign);
587 }
588
589 /*!
590     \qmlproperty enumeration 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 QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const
605 {
606     Q_D(const QDeclarativeTextEdit);
607     return d->wrapMode;
608 }
609
610 void QDeclarativeTextEdit::setWrapMode(WrapMode mode)
611 {
612     Q_D(QDeclarativeTextEdit);
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 TextEdit::lineCount
623     \since Quick 1.1
624
625     Returns the total number of lines in the textEdit item.
626 */
627 int QDeclarativeTextEdit::lineCount() const
628 {
629     Q_D(const QDeclarativeTextEdit);
630     return d->lineCount;
631 }
632
633 /*!
634     \qmlproperty real TextEdit::paintedWidth
635
636     Returns the width of the text, including the width past the width
637     which is covered due to insufficient wrapping if \l wrapMode is set.
638 */
639 qreal QDeclarativeTextEdit::paintedWidth() const
640 {
641     Q_D(const QDeclarativeTextEdit);
642     return d->paintedSize.width();
643 }
644
645 /*!
646     \qmlproperty real TextEdit::paintedHeight
647
648     Returns the height of the text, including the height past the height
649     that is covered if the text does not fit within the set height.
650 */
651 qreal QDeclarativeTextEdit::paintedHeight() const
652 {
653     Q_D(const QDeclarativeTextEdit);
654     return d->paintedSize.height();
655 }
656
657 /*!
658     \qmlmethod rectangle TextEdit::positionToRectangle(position)
659
660     Returns the rectangle at the given \a position in the text. The x, y,
661     and height properties correspond to the cursor that would describe
662     that position.
663 */
664 QRectF QDeclarativeTextEdit::positionToRectangle(int pos) const
665 {
666     Q_D(const QDeclarativeTextEdit);
667     QTextCursor c(d->document);
668     c.setPosition(pos);
669     return d->control->cursorRect(c);
670
671 }
672
673 /*!
674     \qmlmethod int TextEdit::positionAt(int x, int y)
675
676     Returns the text position closest to pixel position (\a x, \a y).
677
678     Position 0 is before the first character, position 1 is after the first character
679     but before the second, and so on until position \l {text}.length, which is after all characters.
680 */
681 int QDeclarativeTextEdit::positionAt(int x, int y) const
682 {
683     Q_D(const QDeclarativeTextEdit);
684     int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
685     QTextCursor cursor = d->control->textCursor();
686     if (r > cursor.position()) {
687         // The cursor position includes positions within the preedit text, but only positions in the
688         // same text block are offset so it is possible to get a position that is either part of the
689         // preedit or the next text block.
690         QTextLayout *layout = cursor.block().layout();
691         const int preeditLength = layout
692                 ? layout->preeditAreaText().length()
693                 : 0;
694         if (preeditLength > 0
695                 && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
696             r = r > cursor.position() + preeditLength
697                     ? r - preeditLength
698                     : cursor.position();
699         }
700     }
701     return r;
702 }
703
704 void QDeclarativeTextEdit::moveCursorSelection(int pos)
705 {
706     //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
707     Q_D(QDeclarativeTextEdit);
708     QTextCursor cursor = d->control->textCursor();
709     if (cursor.position() == pos)
710         return;
711     cursor.setPosition(pos, QTextCursor::KeepAnchor);
712     d->control->setTextCursor(cursor);
713 }
714
715 /*!
716     \qmlmethod void TextEdit::moveCursorSelection(int position, SelectionMode mode = TextEdit.SelectCharacters)
717     \since Quick 1.1
718
719     Moves the cursor to \a position and updates the selection according to the optional \a mode
720     parameter. (To only move the cursor, set the \l cursorPosition property.)
721
722     When this method is called it additionally sets either the
723     selectionStart or the selectionEnd (whichever was at the previous cursor position)
724     to the specified position. This allows you to easily extend and contract the selected
725     text range.
726
727     The selection mode specifies whether the selection is updated on a per character or a per word
728     basis.  If not specified the selection mode will default to TextEdit.SelectCharacters.
729
730     \list
731     \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
732     the previous cursor position) to the specified position.
733     \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
734     words between the specified postion and the previous cursor position.  Words partially in the
735     range are included.
736     \endlist
737
738     For example, take this sequence of calls:
739
740     \code
741         cursorPosition = 5
742         moveCursorSelection(9, TextEdit.SelectCharacters)
743         moveCursorSelection(7, TextEdit.SelectCharacters)
744     \endcode
745
746     This moves the cursor to position 5, extend the selection end from 5 to 9
747     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
748     selected (the 6th and 7th characters).
749
750     The same sequence with TextEdit.SelectWords will extend the selection start to a word boundary
751     before or on position 5 and extend the selection end to a word boundary on or past position 9.
752 */
753 void QDeclarativeTextEdit::moveCursorSelection(int pos, SelectionMode mode)
754 {
755     Q_D(QDeclarativeTextEdit);
756     QTextCursor cursor = d->control->textCursor();
757     if (cursor.position() == pos)
758         return;
759     if (mode == SelectCharacters) {
760         cursor.setPosition(pos, QTextCursor::KeepAnchor);
761     } else if (cursor.anchor() < pos || (cursor.anchor() == pos && cursor.position() < pos)) {
762         if (cursor.anchor() > cursor.position()) {
763             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
764             cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
765             if (cursor.position() == cursor.anchor())
766                 cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor);
767             else
768                 cursor.setPosition(cursor.position(), QTextCursor::MoveAnchor);
769         } else {
770             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
771             cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
772         }
773
774         cursor.setPosition(pos, QTextCursor::KeepAnchor);
775         cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
776         if (cursor.position() != pos)
777             cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
778     } else if (cursor.anchor() > pos || (cursor.anchor() == pos && cursor.position() > pos)) {
779         if (cursor.anchor() < cursor.position()) {
780             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
781             cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
782         } else {
783             cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
784             cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
785             cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
786             if (cursor.position() != cursor.anchor()) {
787                 cursor.setPosition(cursor.anchor(), QTextCursor::MoveAnchor);
788                 cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::MoveAnchor);
789             }
790         }
791
792         cursor.setPosition(pos, QTextCursor::KeepAnchor);
793         cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
794         if (cursor.position() != pos) {
795             cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
796             cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
797         }
798     }
799     d->control->setTextCursor(cursor);
800 }
801
802 /*!
803     \qmlproperty bool TextEdit::cursorVisible
804     If true the text edit shows a cursor.
805
806     This property is set and unset when the text edit gets active focus, but it can also
807     be set directly (useful, for example, if a KeyProxy might forward keys to it).
808 */
809 bool QDeclarativeTextEdit::isCursorVisible() const
810 {
811     Q_D(const QDeclarativeTextEdit);
812     return d->cursorVisible;
813 }
814
815 void QDeclarativeTextEdit::setCursorVisible(bool on)
816 {
817     Q_D(QDeclarativeTextEdit);
818     if (d->cursorVisible == on)
819         return;
820     d->cursorVisible = on;
821     QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
822     if (!on && !d->persistentSelection)
823         d->control->setCursorIsFocusIndicator(true);
824     d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
825     emit cursorVisibleChanged(d->cursorVisible);
826 }
827
828 /*!
829     \qmlproperty int TextEdit::cursorPosition
830     The position of the cursor in the TextEdit.
831 */
832 int QDeclarativeTextEdit::cursorPosition() const
833 {
834     Q_D(const QDeclarativeTextEdit);
835     return d->control->textCursor().position();
836 }
837
838 void QDeclarativeTextEdit::setCursorPosition(int pos)
839 {
840     Q_D(QDeclarativeTextEdit);
841     if (pos < 0 || pos > d->text.length())
842         return;
843     QTextCursor cursor = d->control->textCursor();
844     if (cursor.position() == pos && cursor.anchor() == pos)
845         return;
846     cursor.setPosition(pos);
847     d->control->setTextCursor(cursor);
848 }
849
850 /*!
851     \qmlproperty Component TextEdit::cursorDelegate
852     The delegate for the cursor in the TextEdit.
853
854     If you set a cursorDelegate for a TextEdit, this delegate will be used for
855     drawing the cursor instead of the standard cursor. An instance of the
856     delegate will be created and managed by the text edit when a cursor is
857     needed, and the x and y properties of delegate instance will be set so as
858     to be one pixel before the top left of the current character.
859
860     Note that the root item of the delegate component must be a QDeclarativeItem or
861     QDeclarativeItem derived item.
862 */
863 QDeclarativeComponent* QDeclarativeTextEdit::cursorDelegate() const
864 {
865     Q_D(const QDeclarativeTextEdit);
866     return d->cursorComponent;
867 }
868
869 void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c)
870 {
871     Q_D(QDeclarativeTextEdit);
872     if(d->cursorComponent){
873         if(d->cursor){
874             d->control->setCursorWidth(-1);
875             dirtyCache(cursorRectangle());
876             delete d->cursor;
877             d->cursor = 0;
878         }
879     }
880     d->cursorComponent = c;
881     if(c && c->isReady()){
882         loadCursorDelegate();
883     }else{
884         if(c)
885             connect(c, SIGNAL(statusChanged()),
886                     this, SLOT(loadCursorDelegate()));
887     }
888
889     emit cursorDelegateChanged();
890 }
891
892 void QDeclarativeTextEdit::loadCursorDelegate()
893 {
894     Q_D(QDeclarativeTextEdit);
895     if(d->cursorComponent->isLoading())
896         return;
897     d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this)));
898     if(d->cursor){
899         d->control->setCursorWidth(0);
900         dirtyCache(cursorRectangle());
901         QDeclarative_setParent_noEvent(d->cursor, this);
902         d->cursor->setParentItem(this);
903         d->cursor->setHeight(QFontMetrics(d->font).height());
904         moveCursorDelegate();
905     }else{
906         qmlInfo(this) << "Error loading cursor delegate.";
907     }
908 }
909
910 /*!
911     \qmlproperty int TextEdit::selectionStart
912
913     The cursor position before the first character in the current selection.
914
915     This property is read-only. To change the selection, use select(start,end),
916     selectAll(), or selectWord().
917
918     \sa selectionEnd, cursorPosition, selectedText
919 */
920 int QDeclarativeTextEdit::selectionStart() const
921 {
922     Q_D(const QDeclarativeTextEdit);
923     return d->control->textCursor().selectionStart();
924 }
925
926 /*!
927     \qmlproperty int TextEdit::selectionEnd
928
929     The cursor position after the last character in the current selection.
930
931     This property is read-only. To change the selection, use select(start,end),
932     selectAll(), or selectWord().
933
934     \sa selectionStart, cursorPosition, selectedText
935 */
936 int QDeclarativeTextEdit::selectionEnd() const
937 {
938     Q_D(const QDeclarativeTextEdit);
939     return d->control->textCursor().selectionEnd();
940 }
941
942 /*!
943     \qmlproperty string TextEdit::selectedText
944
945     This read-only property provides the text currently selected in the
946     text edit.
947
948     It is equivalent to the following snippet, but is faster and easier
949     to use.
950     \code
951     //myTextEdit is the id of the TextEdit
952     myTextEdit.text.toString().substring(myTextEdit.selectionStart,
953             myTextEdit.selectionEnd);
954     \endcode
955 */
956 QString QDeclarativeTextEdit::selectedText() const
957 {
958     Q_D(const QDeclarativeTextEdit);
959     return d->control->textCursor().selectedText();
960 }
961
962 /*!
963     \qmlproperty bool TextEdit::activeFocusOnPress
964
965     Whether the TextEdit should gain active focus on a mouse press. By default this is
966     set to true.
967 */
968 bool QDeclarativeTextEdit::focusOnPress() const
969 {
970     Q_D(const QDeclarativeTextEdit);
971     return d->focusOnPress;
972 }
973
974 void QDeclarativeTextEdit::setFocusOnPress(bool on)
975 {
976     Q_D(QDeclarativeTextEdit);
977     if (d->focusOnPress == on)
978         return;
979     d->focusOnPress = on;
980     emit activeFocusOnPressChanged(d->focusOnPress);
981 }
982
983 /*!
984     \qmlproperty bool TextEdit::persistentSelection
985
986     Whether the TextEdit should keep the selection visible when it loses active focus to another
987     item in the scene. By default this is set to true;
988 */
989 bool QDeclarativeTextEdit::persistentSelection() const
990 {
991     Q_D(const QDeclarativeTextEdit);
992     return d->persistentSelection;
993 }
994
995 void QDeclarativeTextEdit::setPersistentSelection(bool on)
996 {
997     Q_D(QDeclarativeTextEdit);
998     if (d->persistentSelection == on)
999         return;
1000     d->persistentSelection = on;
1001     emit persistentSelectionChanged(d->persistentSelection);
1002 }
1003
1004 /*
1005    \qmlproperty real TextEdit::textMargin
1006
1007    The margin, in pixels, around the text in the TextEdit.
1008 */
1009 qreal QDeclarativeTextEdit::textMargin() const
1010 {
1011     Q_D(const QDeclarativeTextEdit);
1012     return d->textMargin;
1013 }
1014
1015 void QDeclarativeTextEdit::setTextMargin(qreal margin)
1016 {
1017     Q_D(QDeclarativeTextEdit);
1018     if (d->textMargin == margin)
1019         return;
1020     d->textMargin = margin;
1021     d->document->setDocumentMargin(d->textMargin);
1022     emit textMarginChanged(d->textMargin);
1023 }
1024
1025 void QDeclarativeTextEdit::geometryChanged(const QRectF &newGeometry,
1026                                   const QRectF &oldGeometry)
1027 {
1028     if (newGeometry.width() != oldGeometry.width())
1029         updateSize();
1030     QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
1031 }
1032
1033 /*!
1034     Ensures any delayed caching or data loading the class
1035     needs to performed is complete.
1036 */
1037 void QDeclarativeTextEdit::componentComplete()
1038 {
1039     Q_D(QDeclarativeTextEdit);
1040     QDeclarativePaintedItem::componentComplete();
1041     if (d->dirty) {
1042         d->determineHorizontalAlignment();
1043         d->updateDefaultTextOption();
1044         updateSize();
1045         d->dirty = false;
1046     }
1047 }
1048
1049 /*!
1050     \qmlproperty bool TextEdit::selectByMouse
1051
1052     Defaults to false.
1053
1054     If true, the user can use the mouse to select text in some
1055     platform-specific way. Note that for some platforms this may
1056     not be an appropriate interaction (eg. may conflict with how
1057     the text needs to behave inside a Flickable.
1058 */
1059 bool QDeclarativeTextEdit::selectByMouse() const
1060 {
1061     Q_D(const QDeclarativeTextEdit);
1062     return d->selectByMouse;
1063 }
1064
1065 void QDeclarativeTextEdit::setSelectByMouse(bool on)
1066 {
1067     Q_D(QDeclarativeTextEdit);
1068     if (d->selectByMouse != on) {
1069         d->selectByMouse = on;
1070         setKeepMouseGrab(on);
1071         if (on)
1072             setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
1073         else
1074             setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
1075         emit selectByMouseChanged(on);
1076     }
1077 }
1078
1079
1080 /*!
1081     \qmlproperty enum TextEdit::mouseSelectionMode
1082     \since Quick 1.1
1083
1084     Specifies how text should be selected using a mouse.
1085
1086     \list
1087     \o TextEdit.SelectCharacters - The selection is updated with individual characters. (Default)
1088     \o TextEdit.SelectWords - The selection is updated with whole words.
1089     \endlist
1090
1091     This property only applies when \l selectByMouse is true.
1092 */
1093
1094 QDeclarativeTextEdit::SelectionMode QDeclarativeTextEdit::mouseSelectionMode() const
1095 {
1096     Q_D(const QDeclarativeTextEdit);
1097     return d->mouseSelectionMode;
1098 }
1099
1100 void QDeclarativeTextEdit::setMouseSelectionMode(SelectionMode mode)
1101 {
1102     Q_D(QDeclarativeTextEdit);
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 TextEdit::readOnly
1112
1113     Whether the user an 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 QDeclarativeTextEdit::setReadOnly(bool r)
1119 {
1120     Q_D(QDeclarativeTextEdit);
1121     if (r == isReadOnly())
1122         return;
1123
1124     setFlag(QGraphicsItem::ItemAcceptsInputMethod, !r);
1125
1126     Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
1127     if (d->selectByMouse)
1128         flags = flags | Qt::TextSelectableByMouse;
1129     if (!r)
1130         flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
1131     d->control->setTextInteractionFlags(flags);
1132     if (!r)
1133         d->control->moveCursor(QTextCursor::End);
1134
1135     emit readOnlyChanged(r);
1136 }
1137
1138 bool QDeclarativeTextEdit::isReadOnly() const
1139 {
1140     Q_D(const QDeclarativeTextEdit);
1141     return !(d->control->textInteractionFlags() & Qt::TextEditable);
1142 }
1143
1144 /*!
1145     Sets how the text edit should interact with user input to the given
1146     \a flags.
1147 */
1148 void QDeclarativeTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
1149 {
1150     Q_D(QDeclarativeTextEdit);
1151     d->control->setTextInteractionFlags(flags);
1152 }
1153
1154 /*!
1155     Returns the flags specifying how the text edit should interact
1156     with user input.
1157 */
1158 Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const
1159 {
1160     Q_D(const QDeclarativeTextEdit);
1161     return d->control->textInteractionFlags();
1162 }
1163
1164 /*!
1165     \qmlproperty rectangle TextEdit::cursorRectangle
1166
1167     The rectangle where the text cursor is rendered
1168     within the text edit. Read-only.
1169 */
1170 QRect QDeclarativeTextEdit::cursorRectangle() const
1171 {
1172     Q_D(const QDeclarativeTextEdit);
1173     return d->control->cursorRect().toRect().translated(0,d->yoff);
1174 }
1175
1176
1177 /*!
1178 \overload
1179 Handles the given \a event.
1180 */
1181 bool QDeclarativeTextEdit::event(QEvent *event)
1182 {
1183     Q_D(QDeclarativeTextEdit);
1184     if (event->type() == QEvent::ShortcutOverride) {
1185         d->control->processEvent(event, QPointF(0, -d->yoff));
1186         return event->isAccepted();
1187     }
1188     return QDeclarativePaintedItem::event(event);
1189 }
1190
1191 /*!
1192 \overload
1193 Handles the given key \a event.
1194 */
1195 void QDeclarativeTextEdit::keyPressEvent(QKeyEvent *event)
1196 {
1197     Q_D(QDeclarativeTextEdit);
1198     keyPressPreHandler(event);
1199     if (!event->isAccepted())
1200         d->control->processEvent(event, QPointF(0, -d->yoff));
1201     if (!event->isAccepted())
1202         QDeclarativePaintedItem::keyPressEvent(event);
1203 }
1204
1205 /*!
1206 \overload
1207 Handles the given key \a event.
1208 */
1209 void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event)
1210 {
1211     Q_D(QDeclarativeTextEdit);
1212     keyReleasePreHandler(event);
1213     if (!event->isAccepted())
1214         d->control->processEvent(event, QPointF(0, -d->yoff));
1215     if (!event->isAccepted())
1216         QDeclarativePaintedItem::keyReleaseEvent(event);
1217 }
1218
1219 void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus)
1220 {
1221     Q_Q(QDeclarativeTextEdit);
1222     q->setCursorVisible(hasFocus && scene && scene->hasFocus());
1223     QDeclarativeItemPrivate::focusChanged(hasFocus);
1224 }
1225
1226 /*!
1227     \qmlmethod void TextEdit::deselect()
1228     \since Quick 1.1
1229
1230     Removes active text selection.
1231 */
1232 void QDeclarativeTextEdit::deselect()
1233 {
1234     Q_D(QDeclarativeTextEdit);
1235     QTextCursor c = d->control->textCursor();
1236     c.clearSelection();
1237     d->control->setTextCursor(c);
1238 }
1239
1240 /*!
1241     \qmlmethod void TextEdit::selectAll()
1242
1243     Causes all text to be selected.
1244 */
1245 void QDeclarativeTextEdit::selectAll()
1246 {
1247     Q_D(QDeclarativeTextEdit);
1248     d->control->selectAll();
1249 }
1250
1251 /*!
1252     \qmlmethod void TextEdit::selectWord()
1253
1254     Causes the word closest to the current cursor position to be selected.
1255 */
1256 void QDeclarativeTextEdit::selectWord()
1257 {
1258     Q_D(QDeclarativeTextEdit);
1259     QTextCursor c = d->control->textCursor();
1260     c.select(QTextCursor::WordUnderCursor);
1261     d->control->setTextCursor(c);
1262 }
1263
1264 /*!
1265     \qmlmethod void TextEdit::select(int start, int end)
1266
1267     Causes the text from \a start to \a end to be selected.
1268
1269     If either start or end is out of range, the selection is not changed.
1270
1271     After calling this, selectionStart will become the lesser
1272     and selectionEnd will become the greater (regardless of the order passed
1273     to this method).
1274
1275     \sa selectionStart, selectionEnd
1276 */
1277 void QDeclarativeTextEdit::select(int start, int end)
1278 {
1279     Q_D(QDeclarativeTextEdit);
1280     if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
1281         return;
1282     QTextCursor cursor = d->control->textCursor();
1283     cursor.beginEditBlock();
1284     cursor.setPosition(start, QTextCursor::MoveAnchor);
1285     cursor.setPosition(end, QTextCursor::KeepAnchor);
1286     cursor.endEditBlock();
1287     d->control->setTextCursor(cursor);
1288
1289     // QTBUG-11100
1290     updateSelectionMarkers();
1291 }
1292
1293 /*!
1294     \qmlmethod void TextEdit::isRightToLeft(int start, int end)
1295
1296     Returns true if the natural reading direction of the editor text
1297     found between positions \a start and \a end is right to left.
1298 */
1299 bool QDeclarativeTextEdit::isRightToLeft(int start, int end)
1300 {
1301     Q_D(QDeclarativeTextEdit);
1302     if (start > end) {
1303         qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1304         return false;
1305     } else {
1306         return d->text.mid(start, end - start).isRightToLeft();
1307     }
1308 }
1309
1310 #ifndef QT_NO_CLIPBOARD
1311 /*!
1312     \qmlmethod TextEdit::cut()
1313
1314     Moves the currently selected text to the system clipboard.
1315 */
1316 void QDeclarativeTextEdit::cut()
1317 {
1318     Q_D(QDeclarativeTextEdit);
1319     d->control->cut();
1320 }
1321
1322 /*!
1323     \qmlmethod TextEdit::copy()
1324
1325     Copies the currently selected text to the system clipboard.
1326 */
1327 void QDeclarativeTextEdit::copy()
1328 {
1329     Q_D(QDeclarativeTextEdit);
1330     d->control->copy();
1331 }
1332
1333 /*!
1334     \qmlmethod TextEdit::paste()
1335
1336     Replaces the currently selected text by the contents of the system clipboard.
1337 */
1338 void QDeclarativeTextEdit::paste()
1339 {
1340     Q_D(QDeclarativeTextEdit);
1341     d->control->paste();
1342 }
1343 #endif // QT_NO_CLIPBOARD
1344
1345 /*!
1346 \overload
1347 Handles the given mouse \a event.
1348 */
1349 void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
1350 {
1351     Q_D(QDeclarativeTextEdit);
1352     if (d->focusOnPress){
1353         bool hadActiveFocus = hasActiveFocus();
1354         forceActiveFocus();
1355         if (d->showInputPanelOnFocus) {
1356             if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1357                 // re-open input panel on press if already focused
1358                 openSoftwareInputPanel();
1359             }
1360         } else { // show input panel on click
1361             if (hasActiveFocus() && !hadActiveFocus) {
1362                 d->clickCausedFocus = true;
1363             }
1364         }
1365     }
1366
1367     d->control->processEvent(event, QPointF(0, -d->yoff));
1368     if (!event->isAccepted())
1369         QDeclarativePaintedItem::mousePressEvent(event);
1370 }
1371
1372 /*!
1373 \overload
1374 Handles the given mouse \a event.
1375 */
1376 void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1377 {
1378     Q_D(QDeclarativeTextEdit);
1379     d->control->processEvent(event, QPointF(0, -d->yoff));
1380     if (!d->showInputPanelOnFocus) { // input panel on click
1381         if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1382             if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1383                 if (view->scene() && view->scene() == scene()) {
1384                     qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1385                 }
1386             }
1387         }
1388     }
1389     d->clickCausedFocus = false;
1390
1391     if (!event->isAccepted())
1392         QDeclarativePaintedItem::mouseReleaseEvent(event);
1393 }
1394
1395 /*!
1396 \overload
1397 Handles the given mouse \a event.
1398 */
1399 void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1400 {
1401     Q_D(QDeclarativeTextEdit);
1402
1403     d->control->processEvent(event, QPointF(0, -d->yoff));
1404     if (!event->isAccepted())
1405         QDeclarativePaintedItem::mouseDoubleClickEvent(event);
1406
1407 }
1408
1409 /*!
1410 \overload
1411 Handles the given mouse \a event.
1412 */
1413 void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1414 {
1415     Q_D(QDeclarativeTextEdit);
1416     d->control->processEvent(event, QPointF(0, -d->yoff));
1417     if (!event->isAccepted())
1418         QDeclarativePaintedItem::mouseMoveEvent(event);
1419 }
1420
1421 /*!
1422 \overload
1423 Handles the given input method \a event.
1424 */
1425 void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event)
1426 {
1427     Q_D(QDeclarativeTextEdit);
1428     const bool wasComposing = isInputMethodComposing();
1429     d->control->processEvent(event, QPointF(0, -d->yoff));
1430     if (wasComposing != isInputMethodComposing())
1431         emit inputMethodComposingChanged();
1432 }
1433
1434 /*!
1435 \overload
1436 Returns the value of the given \a property.
1437 */
1438 QVariant QDeclarativeTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1439 {
1440     Q_D(const QDeclarativeTextEdit);
1441     return d->control->inputMethodQuery(property);
1442 }
1443
1444 /*!
1445 Draws the contents of the text edit using the given \a painter within
1446 the given \a bounds.
1447 */
1448 void QDeclarativeTextEdit::drawContents(QPainter *painter, const QRect &bounds)
1449 {
1450     Q_D(QDeclarativeTextEdit);
1451
1452     painter->setRenderHint(QPainter::TextAntialiasing, true);
1453     painter->translate(0,d->yoff);
1454
1455     d->control->drawContents(painter, bounds.translated(0,-d->yoff));
1456
1457     painter->translate(0,-d->yoff);
1458 }
1459
1460 void QDeclarativeTextEdit::updateImgCache(const QRectF &rf)
1461 {
1462     Q_D(const QDeclarativeTextEdit);
1463     QRect r;
1464     if (!rf.isValid()) {
1465         r = QRect(0,0,INT_MAX,INT_MAX);
1466     } else {
1467         r = rf.toRect();
1468         if (r.height() > INT_MAX/2) {
1469             // Take care of overflow when translating "everything"
1470             r.setTop(r.y() + d->yoff);
1471             r.setBottom(INT_MAX/2);
1472         } else {
1473             r = r.translated(0,d->yoff);
1474         }
1475     }
1476     dirtyCache(r);
1477     emit update();
1478 }
1479
1480 /*!
1481     \qmlproperty bool TextEdit::smooth
1482
1483     This property holds whether the text is smoothly scaled or transformed.
1484
1485     Smooth filtering gives better visual quality, but is slower.  If
1486     the item is displayed at its natural size, this property has no visual or
1487     performance effect.
1488
1489     \note Generally scaling artifacts are only visible if the item is stationary on
1490     the screen.  A common pattern when animating an item is to disable smooth
1491     filtering at the beginning of the animation and reenable it at the conclusion.
1492 */
1493
1494 /*!
1495     \qmlproperty bool TextEdit::canPaste
1496     \since QtQuick 1.1
1497
1498     Returns true if the TextEdit is writable and the content of the clipboard is
1499     suitable for pasting into the TextEdit.
1500 */
1501 bool QDeclarativeTextEdit::canPaste() const
1502 {
1503     Q_D(const QDeclarativeTextEdit);
1504     return d->canPaste;
1505 }
1506
1507 /*!
1508     \qmlproperty bool TextEdit::inputMethodComposing
1509
1510     \since QtQuick 1.1
1511
1512     This property holds whether the TextEdit has partial text input from an
1513     input method.
1514
1515     While it is composing an input method may rely on mouse or key events from
1516     the TextEdit to edit or commit the partial text.  This property can be used
1517     to determine when to disable events handlers that may interfere with the
1518     correct operation of an input method.
1519 */
1520 bool QDeclarativeTextEdit::isInputMethodComposing() const
1521 {
1522     Q_D(const QDeclarativeTextEdit);
1523     if (QTextLayout *layout = d->control->textCursor().block().layout())
1524         return layout->preeditAreaText().length() > 0;
1525     return false;
1526 }
1527
1528 void QDeclarativeTextEditPrivate::init()
1529 {
1530     Q_Q(QDeclarativeTextEdit);
1531
1532     q->setSmooth(smooth);
1533     q->setAcceptedMouseButtons(Qt::LeftButton);
1534     q->setFlag(QGraphicsItem::ItemHasNoContents, false);
1535     q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
1536
1537     control = new QTextControl(q);
1538     control->setIgnoreUnusedNavigationEvents(true);
1539     control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
1540     control->setDragEnabled(false);
1541
1542     // QTextControl follows the default text color
1543     // defined by the platform, declarative text
1544     // should be black by default
1545     QPalette pal = control->palette();
1546     if (pal.color(QPalette::Text) != color) {
1547         pal.setColor(QPalette::Text, color);
1548         control->setPalette(pal);
1549     }
1550
1551     QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
1552
1553     QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1554     QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1555     QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1556     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1557     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1558     QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate()));
1559     QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)));
1560 #ifndef QT_NO_CLIPBOARD
1561     QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
1562     QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
1563     canPaste = control->canPaste();
1564 #endif
1565
1566     document = control->document();
1567     document->setDefaultFont(font);
1568     document->setDocumentMargin(textMargin);
1569     document->setUndoRedoEnabled(false); // flush undo buffer.
1570     document->setUndoRedoEnabled(true);
1571     updateDefaultTextOption();
1572 }
1573
1574 void QDeclarativeTextEdit::q_textChanged()
1575 {
1576     Q_D(QDeclarativeTextEdit);
1577     d->text = text();
1578     d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
1579     d->determineHorizontalAlignment();
1580     d->updateDefaultTextOption();
1581     updateSize();
1582     updateTotalLines();
1583     emit textChanged(d->text);
1584 }
1585
1586 void QDeclarativeTextEdit::moveCursorDelegate()
1587 {
1588     Q_D(QDeclarativeTextEdit);
1589     updateMicroFocus();
1590     emit cursorRectangleChanged();
1591     if(!d->cursor)
1592         return;
1593     QRectF cursorRect = cursorRectangle();
1594     d->cursor->setX(cursorRect.x());
1595     d->cursor->setY(cursorRect.y());
1596 }
1597
1598 void QDeclarativeTextEditPrivate::updateSelection()
1599 {
1600     Q_Q(QDeclarativeTextEdit);
1601     QTextCursor cursor = control->textCursor();
1602     bool startChange = (lastSelectionStart != cursor.selectionStart());
1603     bool endChange = (lastSelectionEnd != cursor.selectionEnd());
1604     cursor.beginEditBlock();
1605     cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
1606     cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
1607     cursor.endEditBlock();
1608     control->setTextCursor(cursor);
1609     if(startChange)
1610         q->selectionStartChanged();
1611     if(endChange)
1612         q->selectionEndChanged();
1613 }
1614
1615 void QDeclarativeTextEdit::updateSelectionMarkers()
1616 {
1617     Q_D(QDeclarativeTextEdit);
1618     if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
1619         d->lastSelectionStart = d->control->textCursor().selectionStart();
1620         emit selectionStartChanged();
1621     }
1622     if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
1623         d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1624         emit selectionEndChanged();
1625     }
1626 }
1627
1628 QRectF QDeclarativeTextEdit::boundingRect() const
1629 {
1630     Q_D(const QDeclarativeTextEdit);
1631     QRectF r = QDeclarativePaintedItem::boundingRect();
1632     int cursorWidth = 1;
1633     if(d->cursor)
1634         cursorWidth = d->cursor->width();
1635     if(!d->document->isEmpty())
1636         cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1637
1638     // Could include font max left/right bearings to either side of rectangle.
1639
1640     r.setRight(r.right() + cursorWidth);
1641     return r.translated(0,d->yoff);
1642 }
1643
1644 qreal QDeclarativeTextEditPrivate::implicitWidth() const
1645 {
1646     Q_Q(const QDeclarativeTextEdit);
1647     if (!requireImplicitWidth) {
1648         // We don't calculate implicitWidth unless it is required.
1649         // We need to force a size update now to ensure implicitWidth is calculated
1650         const_cast<QDeclarativeTextEditPrivate*>(this)->requireImplicitWidth = true;
1651         const_cast<QDeclarativeTextEdit*>(q)->updateSize();
1652     }
1653     return mImplicitWidth;
1654 }
1655
1656 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1657 //    need to do all the calculations each time
1658 void QDeclarativeTextEdit::updateSize()
1659 {
1660     Q_D(QDeclarativeTextEdit);
1661     if (isComponentComplete()) {
1662         qreal naturalWidth = d->mImplicitWidth;
1663         // ### assumes that if the width is set, the text will fill to edges
1664         // ### (unless wrap is false, then clipping will occur)
1665         if (widthValid()) {
1666             if (!d->requireImplicitWidth) {
1667                 emit implicitWidthChanged();
1668                 // if the implicitWidth is used, then updateSize() has already been called (recursively)
1669                 if (d->requireImplicitWidth)
1670                     return;
1671             }
1672             if (d->requireImplicitWidth) {
1673                 d->document->setTextWidth(-1);
1674                 naturalWidth = d->document->idealWidth();
1675             }
1676             if (d->document->textWidth() != width())
1677                 d->document->setTextWidth(width());
1678         } else {
1679             d->document->setTextWidth(-1);
1680         }
1681         QFontMetrics fm = QFontMetrics(d->font);
1682         int dy = height();
1683         dy -= (int)d->document->size().height();
1684
1685         int nyoff;
1686         if (heightValid()) {
1687             if (d->vAlign == AlignBottom)
1688                 nyoff = dy;
1689             else if (d->vAlign == AlignVCenter)
1690                 nyoff = dy/2;
1691             else
1692                 nyoff = 0;
1693         } else {
1694             nyoff = 0;
1695         }
1696         if (nyoff != d->yoff) {
1697             prepareGeometryChange();
1698             d->yoff = nyoff;
1699         }
1700         setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1701
1702         //### need to comfirm cost of always setting these
1703         int newWidth = qCeil(d->document->idealWidth());
1704         if (!widthValid() && d->document->textWidth() != newWidth)
1705             d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1706         // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1707         if (!widthValid())
1708             setImplicitWidth(newWidth);
1709         else if (d->requireImplicitWidth)
1710             setImplicitWidth(naturalWidth);
1711         qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1712         setImplicitHeight(newHeight);
1713
1714         d->paintedSize = QSize(newWidth, newHeight);
1715         setContentsSize(d->paintedSize);
1716         emit paintedSizeChanged();
1717     } else {
1718         d->dirty = true;
1719     }
1720     emit update();
1721 }
1722
1723 void QDeclarativeTextEdit::updateTotalLines()
1724 {
1725     Q_D(QDeclarativeTextEdit);
1726
1727     int subLines = 0;
1728
1729     for (QTextBlock it = d->document->begin(); it != d->document->end(); it = it.next()) {
1730         QTextLayout *layout = it.layout();
1731         if (!layout)
1732             continue;
1733         subLines += layout->lineCount()-1;
1734     }
1735
1736     int newTotalLines = d->document->lineCount() + subLines;
1737     if (d->lineCount != newTotalLines) {
1738         d->lineCount = newTotalLines;
1739         emit lineCountChanged();
1740     }
1741 }
1742
1743 void QDeclarativeTextEditPrivate::updateDefaultTextOption()
1744 {
1745     Q_Q(QDeclarativeTextEdit);
1746     QTextOption opt = document->defaultTextOption();
1747     int oldAlignment = opt.alignment();
1748
1749     QDeclarativeTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
1750     if (rightToLeftText) {
1751         if (horizontalAlignment == QDeclarativeTextEdit::AlignLeft)
1752             horizontalAlignment = QDeclarativeTextEdit::AlignRight;
1753         else if (horizontalAlignment == QDeclarativeTextEdit::AlignRight)
1754             horizontalAlignment = QDeclarativeTextEdit::AlignLeft;
1755     }
1756     opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
1757
1758     QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1759     opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1760
1761     if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
1762         return;
1763     document->setDefaultTextOption(opt);
1764 }
1765
1766
1767 /*!
1768     \qmlmethod void TextEdit::openSoftwareInputPanel()
1769
1770     Opens software input panels like virtual keyboards for typing, useful for
1771     customizing when you want the input keyboard to be shown and hidden in
1772     your application.
1773
1774     By default the opening of input panels follows the platform style. On Symbian^1 and
1775     Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1776     the panels are automatically opened when TextEdit element gains active focus. Input panels are
1777     always closed if no editor has active focus.
1778
1779     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1780     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1781     the behavior you want.
1782
1783     Only relevant on platforms, which provide virtual keyboards.
1784
1785     \code
1786         import QtQuick 1.0
1787         TextEdit {
1788             id: textEdit
1789             text: "Hello world!"
1790             activeFocusOnPress: false
1791             MouseArea {
1792                 anchors.fill: parent
1793                 onClicked: {
1794                     if (!textEdit.activeFocus) {
1795                         textEdit.forceActiveFocus();
1796                         textEdit.openSoftwareInputPanel();
1797                     } else {
1798                         textEdit.focus = false;
1799                     }
1800                 }
1801                 onPressAndHold: textEdit.closeSoftwareInputPanel();
1802             }
1803         }
1804     \endcode
1805 */
1806 void QDeclarativeTextEdit::openSoftwareInputPanel()
1807 {
1808     QEvent event(QEvent::RequestSoftwareInputPanel);
1809     if (qApp) {
1810         if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1811             if (view->scene() && view->scene() == scene()) {
1812                 QApplication::sendEvent(view, &event);
1813             }
1814         }
1815     }
1816 }
1817
1818 /*!
1819     \qmlmethod void TextEdit::closeSoftwareInputPanel()
1820
1821     Closes a software input panel like a virtual keyboard shown on the screen, useful
1822     for customizing when you want the input keyboard to be shown and hidden in
1823     your application.
1824
1825     By default the opening of input panels follows the platform style. On Symbian^1 and
1826     Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1827     the panels are automatically opened when TextEdit element gains active focus. Input panels are
1828     always closed if no editor has active focus.
1829
1830     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1831     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1832     the behavior you want.
1833
1834     Only relevant on platforms, which provide virtual keyboards.
1835
1836     \code
1837         import QtQuick 1.0
1838         TextEdit {
1839             id: textEdit
1840             text: "Hello world!"
1841             activeFocusOnPress: false
1842             MouseArea {
1843                 anchors.fill: parent
1844                 onClicked: {
1845                     if (!textEdit.activeFocus) {
1846                         textEdit.forceActiveFocus();
1847                         textEdit.openSoftwareInputPanel();
1848                     } else {
1849                         textEdit.focus = false;
1850                     }
1851                 }
1852                 onPressAndHold: textEdit.closeSoftwareInputPanel();
1853             }
1854         }
1855     \endcode
1856 */
1857 void QDeclarativeTextEdit::closeSoftwareInputPanel()
1858 {
1859     QEvent event(QEvent::CloseSoftwareInputPanel);
1860     if (qApp) {
1861         if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1862             if (view->scene() && view->scene() == scene()) {
1863                 QApplication::sendEvent(view, &event);
1864             }
1865         }
1866     }
1867 }
1868
1869 void QDeclarativeTextEdit::focusInEvent(QFocusEvent *event)
1870 {
1871     Q_D(const QDeclarativeTextEdit);
1872     if (d->showInputPanelOnFocus) {
1873         if (d->focusOnPress && !isReadOnly()) {
1874             openSoftwareInputPanel();
1875         }
1876     }
1877     QDeclarativePaintedItem::focusInEvent(event);
1878 }
1879
1880 void QDeclarativeTextEdit::q_canPasteChanged()
1881 {
1882     Q_D(QDeclarativeTextEdit);
1883     bool old = d->canPaste;
1884     d->canPaste = d->control->canPaste();
1885     if(old!=d->canPaste)
1886         emit canPasteChanged();
1887 }
1888
1889 QT_END_NAMESPACE