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