TextEdit implicit size varied depending upon wrapMode.
[qt:qt.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 <QTextLayout>
52 #include <QTextLine>
53 #include <QTextDocument>
54 #include <QGraphicsSceneMouseEvent>
55 #include <QDebug>
56 #include <QPainter>
57
58 #include <private/qtextcontrol_p.h>
59
60 QT_BEGIN_NAMESPACE
61
62 /*!
63     \qmlclass TextEdit QDeclarativeTextEdit
64     \ingroup qml-basic-visual-elements
65     \since 4.7
66     \brief The TextEdit item displays multiple lines of editable formatted text.
67     \inherits Item
68
69     The TextEdit item displays a block of editable, formatted text.
70
71     It can display both plain and rich text. For example:
72
73     \qml
74 TextEdit {
75     width: 240
76     text: "<b>Hello</b> <i>World!</i>"
77     font.family: "Helvetica"
78     font.pointSize: 20
79     color: "blue"
80     focus: true
81 }
82     \endqml
83
84     \image declarative-textedit.gif
85
86     Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus.
87
88     Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific
89     to a look-and-feel. For example, to add flickable scrolling that follows the cursor:
90
91     \snippet snippets/declarative/texteditor.qml 0
92
93     A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible
94     scrollbar, or a scrollbar that fades in to show location, etc.
95
96     Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can
97     be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely
98     from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord().
99
100     You can translate between cursor positions (characters from the start of the document) and pixel
101     points using positionAt() and positionToRectangle().
102
103     \sa Text, TextInput, {declarative/text/textselection}{Text Selection example}
104 */
105
106 QDeclarativeTextEdit::QDeclarativeTextEdit(QDeclarativeItem *parent)
107 : QDeclarativePaintedItem(*(new QDeclarativeTextEditPrivate), parent)
108 {
109     Q_D(QDeclarativeTextEdit);
110     d->init();
111 }
112
113 QString QDeclarativeTextEdit::text() const
114 {
115     Q_D(const QDeclarativeTextEdit);
116
117 #ifndef QT_NO_TEXTHTMLPARSER
118     if (d->richText)
119         return d->document->toHtml();
120     else
121 #endif
122         return d->document->toPlainText();
123 }
124
125 /*!
126     \qmlproperty string TextEdit::font.family
127
128     Sets the family name of the font.
129
130     The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
131     If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
132     If the family isn't available a family will be set using the font matching algorithm.
133 */
134
135 /*!
136     \qmlproperty bool TextEdit::font.bold
137
138     Sets whether the font weight is bold.
139 */
140
141 /*!
142     \qmlproperty enumeration TextEdit::font.weight
143
144     Sets the font's weight.
145
146     The weight can be one of:
147     \list
148     \o Font.Light
149     \o Font.Normal - the default
150     \o Font.DemiBold
151     \o Font.Bold
152     \o Font.Black
153     \endlist
154
155     \qml
156     TextEdit { text: "Hello"; font.weight: Font.DemiBold }
157     \endqml
158 */
159
160 /*!
161     \qmlproperty bool TextEdit::font.italic
162
163     Sets whether the font has an italic style.
164 */
165
166 /*!
167     \qmlproperty bool TextEdit::font.underline
168
169     Sets whether the text is underlined.
170 */
171
172 /*!
173     \qmlproperty bool TextEdit::font.strikeout
174
175     Sets whether the font has a strikeout style.
176 */
177
178 /*!
179     \qmlproperty real TextEdit::font.pointSize
180
181     Sets the font size in points. The point size must be greater than zero.
182 */
183
184 /*!
185     \qmlproperty int TextEdit::font.pixelSize
186
187     Sets the font size in pixels.
188
189     Using this function makes the font device dependent.  Use
190     \l{TextEdit::font.pointSize} to set the size of the font in a
191     device independent manner.
192 */
193
194 /*!
195     \qmlproperty real TextEdit::font.letterSpacing
196
197     Sets the letter spacing for the font.
198
199     Letter spacing changes the default spacing between individual letters in the font.
200     A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
201 */
202
203 /*!
204     \qmlproperty real TextEdit::font.wordSpacing
205
206     Sets the word spacing for the font.
207
208     Word spacing changes the default spacing between individual words.
209     A positive value increases the word spacing by a corresponding amount of pixels,
210     while a negative value decreases the inter-word spacing accordingly.
211 */
212
213 /*!
214     \qmlproperty enumeration TextEdit::font.capitalization
215
216     Sets the capitalization for the text.
217
218     \list
219     \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
220     \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
221     \o Font.AllLowercase         - This alters the text to be rendered in all lowercase type.
222     \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
223     \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
224     \endlist
225
226     \qml
227     TextEdit { text: "Hello"; font.capitalization: Font.AllLowercase }
228     \endqml
229 */
230
231 /*!
232     \qmlproperty string TextEdit::text
233
234     The text to display.  If the text format is AutoText the text edit will
235     automatically determine whether the text should be treated as
236     rich text.  This determination is made using Qt::mightBeRichText().
237 */
238 void QDeclarativeTextEdit::setText(const QString &text)
239 {
240     Q_D(QDeclarativeTextEdit);
241     if (QDeclarativeTextEdit::text() == text)
242         return;
243     d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
244     if (d->richText) {
245 #ifndef QT_NO_TEXTHTMLPARSER
246         d->control->setHtml(text);
247 #else
248         d->control->setPlainText(text);
249 #endif
250     } else {
251         d->control->setPlainText(text);
252     }
253     q_textChanged();
254 }
255
256 /*!
257     \qmlproperty enumeration TextEdit::textFormat
258
259     The way the text property should be displayed.
260
261     \list
262     \o TextEdit.AutoText
263     \o TextEdit.PlainText
264     \o TextEdit.RichText
265     \o TextEdit.StyledText
266     \endlist
267
268     The default is TextEdit.AutoText.  If the text format is TextEdit.AutoText the text edit
269     will automatically determine whether the text should be treated as
270     rich text.  This determination is made using Qt::mightBeRichText().
271
272     \table
273     \row
274     \o
275     \qml
276 Column {
277     TextEdit {
278         font.pointSize: 24
279         text: "<b>Hello</b> <i>World!</i>"
280     }
281     TextEdit {
282         font.pointSize: 24
283         textFormat: TextEdit.RichText
284         text: "<b>Hello</b> <i>World!</i>"
285     }
286     TextEdit {
287         font.pointSize: 24
288         textFormat: TextEdit.PlainText
289         text: "<b>Hello</b> <i>World!</i>"
290     }
291 }
292     \endqml
293     \o \image declarative-textformat.png
294     \endtable
295 */
296 QDeclarativeTextEdit::TextFormat QDeclarativeTextEdit::textFormat() const
297 {
298     Q_D(const QDeclarativeTextEdit);
299     return d->format;
300 }
301
302 void QDeclarativeTextEdit::setTextFormat(TextFormat format)
303 {
304     Q_D(QDeclarativeTextEdit);
305     if (format == d->format)
306         return;
307     bool wasRich = d->richText;
308     d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
309
310     if (wasRich && !d->richText) {
311         d->control->setPlainText(d->text);
312         updateSize();
313     } else if (!wasRich && d->richText) {
314 #ifndef QT_NO_TEXTHTMLPARSER
315         d->control->setHtml(d->text);
316 #else
317         d->control->setPlainText(d->text);
318 #endif
319         updateSize();
320     }
321     d->format = format;
322     d->control->setAcceptRichText(d->format != PlainText);
323     emit textFormatChanged(d->format);
324 }
325
326 QFont QDeclarativeTextEdit::font() const
327 {
328     Q_D(const QDeclarativeTextEdit);
329     return d->font;
330 }
331
332 void QDeclarativeTextEdit::setFont(const QFont &font)
333 {
334     Q_D(QDeclarativeTextEdit);
335     d->font = font;
336
337     clearCache();
338     d->document->setDefaultFont(d->font);
339     if(d->cursor){
340         d->cursor->setHeight(QFontMetrics(d->font).height());
341         moveCursorDelegate();
342     }
343     updateSize();
344     update();
345 }
346
347 /*!
348     \qmlproperty color TextEdit::color
349
350     The text color.
351
352     \qml
353 // green text using hexadecimal notation
354 TextEdit { color: "#00FF00"; ...  }
355
356 // steelblue text using SVG color name
357 TextEdit { color: "steelblue"; ...  }
358     \endqml
359 */
360 QColor QDeclarativeTextEdit::color() const
361 {
362     Q_D(const QDeclarativeTextEdit);
363     return d->color;
364 }
365
366 void QDeclarativeTextEdit::setColor(const QColor &color)
367 {
368     Q_D(QDeclarativeTextEdit);
369     if (d->color == color)
370         return;
371
372     clearCache();
373     d->color = color;
374     QPalette pal = d->control->palette();
375     pal.setColor(QPalette::Text, color);
376     d->control->setPalette(pal);
377     update();
378     emit colorChanged(d->color);
379 }
380
381 /*!
382     \qmlproperty color TextEdit::selectionColor
383
384     The text highlight color, used behind selections.
385 */
386 QColor QDeclarativeTextEdit::selectionColor() const
387 {
388     Q_D(const QDeclarativeTextEdit);
389     return d->selectionColor;
390 }
391
392 void QDeclarativeTextEdit::setSelectionColor(const QColor &color)
393 {
394     Q_D(QDeclarativeTextEdit);
395     if (d->selectionColor == color)
396         return;
397
398     clearCache();
399     d->selectionColor = color;
400     QPalette pal = d->control->palette();
401     pal.setColor(QPalette::Highlight, color);
402     d->control->setPalette(pal);
403     update();
404     emit selectionColorChanged(d->selectionColor);
405 }
406
407 /*!
408     \qmlproperty color TextEdit::selectedTextColor
409
410     The selected text color, used in selections.
411 */
412 QColor QDeclarativeTextEdit::selectedTextColor() const
413 {
414     Q_D(const QDeclarativeTextEdit);
415     return d->selectedTextColor;
416 }
417
418 void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color)
419 {
420     Q_D(QDeclarativeTextEdit);
421     if (d->selectedTextColor == color)
422         return;
423
424     clearCache();
425     d->selectedTextColor = color;
426     QPalette pal = d->control->palette();
427     pal.setColor(QPalette::HighlightedText, color);
428     d->control->setPalette(pal);
429     update();
430     emit selectedTextColorChanged(d->selectedTextColor);
431 }
432
433 /*!
434     \qmlproperty enumeration TextEdit::horizontalAlignment
435     \qmlproperty enumeration TextEdit::verticalAlignment
436
437     Sets the horizontal and vertical alignment of the text within the TextEdit item's
438     width and height.  By default, the text is top-left aligned.
439
440     Valid values for \c horizontalAlignment are:
441     \list
442     \o TextEdit.AlignLeft (default)
443     \o TextEdit.AlignRight 
444     \o TextEdit.AlignHCenter
445     \endlist
446     
447     Valid values for \c verticalAlignment are:
448     \list
449     \o TextEdit.AlignTop (default)
450     \o TextEdit.AlignBottom
451     \c TextEdit.AlignVCenter
452     \endlist
453 */
454 QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const
455 {
456     Q_D(const QDeclarativeTextEdit);
457     return d->hAlign;
458 }
459
460 void QDeclarativeTextEdit::setHAlign(QDeclarativeTextEdit::HAlignment alignment)
461 {
462     Q_D(QDeclarativeTextEdit);
463     if (alignment == d->hAlign)
464         return;
465     d->hAlign = alignment;
466     d->updateDefaultTextOption();
467     updateSize();
468     emit horizontalAlignmentChanged(d->hAlign);
469 }
470
471 QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const
472 {
473     Q_D(const QDeclarativeTextEdit);
474     return d->vAlign;
475 }
476
477 void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment)
478 {
479     Q_D(QDeclarativeTextEdit);
480     if (alignment == d->vAlign)
481         return;
482     d->vAlign = alignment;
483     d->updateDefaultTextOption();
484     updateSize();
485     emit verticalAlignmentChanged(d->vAlign);
486 }
487
488 /*!
489     \qmlproperty enumeration TextEdit::wrapMode
490
491     Set this property to wrap the text to the TextEdit item's width.
492     The text will only wrap if an explicit width has been set.
493
494     \list
495     \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
496     \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
497     \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
498     \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.
499     \endlist
500
501     The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
502 */
503 QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const
504 {
505     Q_D(const QDeclarativeTextEdit);
506     return d->wrapMode;
507 }
508
509 void QDeclarativeTextEdit::setWrapMode(WrapMode mode)
510 {
511     Q_D(QDeclarativeTextEdit);
512     if (mode == d->wrapMode)
513         return;
514     d->wrapMode = mode;
515     d->updateDefaultTextOption();
516     updateSize();
517     emit wrapModeChanged();
518 }
519
520 /*!
521     \qmlproperty real TextEdit::paintedWidth
522
523     Returns the width of the text, including the width past the width
524     which is covered due to insufficient wrapping if \l wrapMode is set.
525 */
526 qreal QDeclarativeTextEdit::paintedWidth() const
527 {
528     return implicitWidth();
529 }
530
531 /*!
532     \qmlproperty real TextEdit::paintedHeight
533
534     Returns the height of the text, including the height past the height
535     that is covered if the text does not fit within the set height.
536 */
537 qreal QDeclarativeTextEdit::paintedHeight() const
538 {
539     return implicitHeight();
540 }
541
542 /*!
543     \qmlmethod rectangle TextEdit::positionToRectangle(position)
544
545     Returns the rectangle at the given \a position in the text. The x, y,
546     and height properties correspond to the cursor that would describe
547     that position.
548 */
549 QRectF QDeclarativeTextEdit::positionToRectangle(int pos) const
550 {
551     Q_D(const QDeclarativeTextEdit);
552     QTextCursor c(d->document);
553     c.setPosition(pos);
554     return d->control->cursorRect(c);
555
556 }
557
558 /*!
559     \qmlmethod int TextEdit::positionAt(int x, int y)
560
561     Returns the text position closest to pixel position (\a x, \a y).
562
563     Position 0 is before the first character, position 1 is after the first character
564     but before the second, and so on until position \l {text}.length, which is after all characters.
565 */
566 int QDeclarativeTextEdit::positionAt(int x, int y) const
567 {
568     Q_D(const QDeclarativeTextEdit);
569     int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
570     return r;
571 }
572
573 /*!
574     \qmlmethod int TextEdit::moveCursorSelection(int pos)
575
576     Moves the cursor to \a position and updates the selection accordingly.
577     (To only move the cursor, set the \l cursorPosition property.)
578
579     When this method is called it additionally sets either the
580     selectionStart or the selectionEnd (whichever was at the previous cursor position)
581     to the specified position. This allows you to easily extend and contract the selected
582     text range.
583
584     For example, take this sequence of calls:
585
586     \code
587         cursorPosition = 5
588         moveCursorSelection(9)
589         moveCursorSelection(7)
590     \endcode
591
592     This moves the cursor to position 5, extend the selection end from 5 to 9
593     and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
594     selected (the 6th and 7th characters).
595 */
596 void QDeclarativeTextEdit::moveCursorSelection(int pos)
597 {
598     //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
599     Q_D(QDeclarativeTextEdit);
600     QTextCursor cursor = d->control->textCursor();
601     if (cursor.position() == pos)
602         return;
603     cursor.setPosition(pos, QTextCursor::KeepAnchor);
604     d->control->setTextCursor(cursor);
605 }
606
607 /*!
608     \qmlproperty bool TextEdit::cursorVisible
609     If true the text edit shows a cursor.
610
611     This property is set and unset when the text edit gets active focus, but it can also
612     be set directly (useful, for example, if a KeyProxy might forward keys to it).
613 */
614 bool QDeclarativeTextEdit::isCursorVisible() const
615 {
616     Q_D(const QDeclarativeTextEdit);
617     return d->cursorVisible;
618 }
619
620 void QDeclarativeTextEdit::setCursorVisible(bool on)
621 {
622     Q_D(QDeclarativeTextEdit);
623     if (d->cursorVisible == on)
624         return;
625     d->cursorVisible = on;
626     QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
627     if (!on && !d->persistentSelection)
628         d->control->setCursorIsFocusIndicator(true);
629     d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
630     emit cursorVisibleChanged(d->cursorVisible);
631 }
632
633 /*!
634     \qmlproperty int TextEdit::cursorPosition
635     The position of the cursor in the TextEdit.
636 */
637 int QDeclarativeTextEdit::cursorPosition() const
638 {
639     Q_D(const QDeclarativeTextEdit);
640     return d->control->textCursor().position();
641 }
642
643 void QDeclarativeTextEdit::setCursorPosition(int pos)
644 {
645     Q_D(QDeclarativeTextEdit);
646     if (pos < 0 || pos > d->text.length())
647         return;
648     QTextCursor cursor = d->control->textCursor();
649     if (cursor.position() == pos)
650         return;
651     cursor.setPosition(pos);
652     d->control->setTextCursor(cursor);
653 }
654
655 /*!
656     \qmlproperty Component TextEdit::cursorDelegate
657     The delegate for the cursor in the TextEdit.
658
659     If you set a cursorDelegate for a TextEdit, this delegate will be used for
660     drawing the cursor instead of the standard cursor. An instance of the
661     delegate will be created and managed by the text edit when a cursor is
662     needed, and the x and y properties of delegate instance will be set so as
663     to be one pixel before the top left of the current character.
664
665     Note that the root item of the delegate component must be a QDeclarativeItem or
666     QDeclarativeItem derived item.
667 */
668 QDeclarativeComponent* QDeclarativeTextEdit::cursorDelegate() const
669 {
670     Q_D(const QDeclarativeTextEdit);
671     return d->cursorComponent;
672 }
673
674 void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c)
675 {
676     Q_D(QDeclarativeTextEdit);
677     if(d->cursorComponent){
678         if(d->cursor){
679             disconnect(d->control, SIGNAL(cursorPositionChanged()),
680                     this, SLOT(moveCursorDelegate()));
681             d->control->setCursorWidth(-1);
682             dirtyCache(cursorRectangle());
683             delete d->cursor;
684             d->cursor = 0;
685         }
686     }
687     d->cursorComponent = c;
688     if(c && c->isReady()){
689         loadCursorDelegate();
690     }else{
691         if(c)
692             connect(c, SIGNAL(statusChanged()),
693                     this, SLOT(loadCursorDelegate()));
694     }
695
696     emit cursorDelegateChanged();
697 }
698
699 void QDeclarativeTextEdit::loadCursorDelegate()
700 {
701     Q_D(QDeclarativeTextEdit);
702     if(d->cursorComponent->isLoading())
703         return;
704     d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this)));
705     if(d->cursor){
706         connect(d->control, SIGNAL(cursorPositionChanged()),
707                 this, SLOT(moveCursorDelegate()));
708         d->control->setCursorWidth(0);
709         dirtyCache(cursorRectangle());
710         QDeclarative_setParent_noEvent(d->cursor, this);
711         d->cursor->setParentItem(this);
712         d->cursor->setHeight(QFontMetrics(d->font).height());
713         moveCursorDelegate();
714     }else{
715         qmlInfo(this) << "Error loading cursor delegate.";
716     }
717 }
718
719 /*!
720     \qmlproperty int TextEdit::selectionStart
721
722     The cursor position before the first character in the current selection.
723
724     This property is read-only. To change the selection, use select(start,end),
725     selectAll(), or selectWord().
726
727     \sa selectionEnd, cursorPosition, selectedText
728 */
729 int QDeclarativeTextEdit::selectionStart() const
730 {
731     Q_D(const QDeclarativeTextEdit);
732     return d->control->textCursor().selectionStart();
733 }
734
735 /*!
736     \qmlproperty int TextEdit::selectionEnd
737
738     The cursor position after the last character in the current selection.
739
740     This property is read-only. To change the selection, use select(start,end),
741     selectAll(), or selectWord().
742
743     \sa selectionStart, cursorPosition, selectedText
744 */
745 int QDeclarativeTextEdit::selectionEnd() const
746 {
747     Q_D(const QDeclarativeTextEdit);
748     return d->control->textCursor().selectionEnd();
749 }
750
751 /*!
752     \qmlproperty string TextEdit::selectedText
753
754     This read-only property provides the text currently selected in the
755     text edit.
756
757     It is equivalent to the following snippet, but is faster and easier
758     to use.
759     \code
760     //myTextEdit is the id of the TextEdit
761     myTextEdit.text.toString().substring(myTextEdit.selectionStart,
762             myTextEdit.selectionEnd);
763     \endcode
764 */
765 QString QDeclarativeTextEdit::selectedText() const
766 {
767     Q_D(const QDeclarativeTextEdit);
768     return d->control->textCursor().selectedText();
769 }
770
771 /*!
772     \qmlproperty bool TextEdit::activeFocusOnPress
773
774     Whether the TextEdit should gain active focus on a mouse press. By default this is
775     set to true.
776 */
777 bool QDeclarativeTextEdit::focusOnPress() const
778 {
779     Q_D(const QDeclarativeTextEdit);
780     return d->focusOnPress;
781 }
782
783 void QDeclarativeTextEdit::setFocusOnPress(bool on)
784 {
785     Q_D(QDeclarativeTextEdit);
786     if (d->focusOnPress == on)
787         return;
788     d->focusOnPress = on;
789     emit activeFocusOnPressChanged(d->focusOnPress);
790 }
791
792 /*!
793     \qmlproperty bool TextEdit::persistentSelection
794
795     Whether the TextEdit should keep the selection visible when it loses active focus to another
796     item in the scene. By default this is set to true;
797 */
798 bool QDeclarativeTextEdit::persistentSelection() const
799 {
800     Q_D(const QDeclarativeTextEdit);
801     return d->persistentSelection;
802 }
803
804 void QDeclarativeTextEdit::setPersistentSelection(bool on)
805 {
806     Q_D(QDeclarativeTextEdit);
807     if (d->persistentSelection == on)
808         return;
809     d->persistentSelection = on;
810     emit persistentSelectionChanged(d->persistentSelection);
811 }
812
813 /*
814    \qmlproperty real TextEdit::textMargin
815
816    The margin, in pixels, around the text in the TextEdit.
817 */
818 qreal QDeclarativeTextEdit::textMargin() const
819 {
820     Q_D(const QDeclarativeTextEdit);
821     return d->textMargin;
822 }
823
824 void QDeclarativeTextEdit::setTextMargin(qreal margin)
825 {
826     Q_D(QDeclarativeTextEdit);
827     if (d->textMargin == margin)
828         return;
829     d->textMargin = margin;
830     d->document->setDocumentMargin(d->textMargin);
831     emit textMarginChanged(d->textMargin);
832 }
833
834 void QDeclarativeTextEdit::geometryChanged(const QRectF &newGeometry,
835                                   const QRectF &oldGeometry)
836 {
837     if (newGeometry.width() != oldGeometry.width())
838         updateSize();
839     QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
840 }
841
842 /*!
843     Ensures any delayed caching or data loading the class
844     needs to performed is complete.
845 */
846 void QDeclarativeTextEdit::componentComplete()
847 {
848     Q_D(QDeclarativeTextEdit);
849     QDeclarativePaintedItem::componentComplete();
850     if (d->dirty) {
851         updateSize();
852         d->dirty = false;
853     }
854 }
855
856 /*!
857     \qmlproperty bool TextEdit::selectByMouse
858
859     Defaults to false.
860
861     If true, the user can use the mouse to select text in some
862     platform-specific way. Note that for some platforms this may
863     not be an appropriate interaction (eg. may conflict with how
864     the text needs to behave inside a Flickable.
865 */
866 bool QDeclarativeTextEdit::selectByMouse() const
867 {
868     Q_D(const QDeclarativeTextEdit);
869     return d->selectByMouse;
870 }
871
872 void QDeclarativeTextEdit::setSelectByMouse(bool on)
873 {
874     Q_D(QDeclarativeTextEdit);
875     if (d->selectByMouse != on) {
876         d->selectByMouse = on;
877         emit selectByMouseChanged(on);
878     }
879 }
880
881
882
883 /*!
884     \qmlproperty bool TextEdit::readOnly
885
886     Whether the user an interact with the TextEdit item. If this
887     property is set to true the text cannot be edited by user interaction.
888
889     By default this property is false.
890 */
891 void QDeclarativeTextEdit::setReadOnly(bool r)
892 {
893     Q_D(QDeclarativeTextEdit);
894     if (r == isReadOnly())
895         return;
896
897
898     Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
899     if (r) {
900         flags = Qt::TextSelectableByMouse;
901     } else {
902         flags = Qt::TextEditorInteraction;
903     }
904     d->control->setTextInteractionFlags(flags);
905     if (!r)
906         d->control->moveCursor(QTextCursor::End);
907
908     emit readOnlyChanged(r);
909 }
910
911 bool QDeclarativeTextEdit::isReadOnly() const
912 {
913     Q_D(const QDeclarativeTextEdit);
914     return !(d->control->textInteractionFlags() & Qt::TextEditable);
915 }
916
917 /*!
918     Sets how the text edit should interact with user input to the given
919     \a flags.
920 */
921 void QDeclarativeTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
922 {
923     Q_D(QDeclarativeTextEdit);
924     d->control->setTextInteractionFlags(flags);
925 }
926
927 /*!
928     Returns the flags specifying how the text edit should interact
929     with user input.
930 */
931 Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const
932 {
933     Q_D(const QDeclarativeTextEdit);
934     return d->control->textInteractionFlags();
935 }
936
937 /*!
938     \qmlproperty rectangle TextEdit::cursorRectangle
939
940     The rectangle where the text cursor is rendered
941     within the text edit. Read-only.
942 */
943 QRect QDeclarativeTextEdit::cursorRectangle() const
944 {
945     Q_D(const QDeclarativeTextEdit);
946     return d->control->cursorRect().toRect().translated(0,-d->yoff);
947 }
948
949
950 /*!
951 \overload
952 Handles the given \a event.
953 */
954 bool QDeclarativeTextEdit::event(QEvent *event)
955 {
956     Q_D(QDeclarativeTextEdit);
957     if (event->type() == QEvent::ShortcutOverride) {
958         d->control->processEvent(event, QPointF(0, -d->yoff));
959         return event->isAccepted();
960     }
961     return QDeclarativePaintedItem::event(event);
962 }
963
964 /*!
965 \overload
966 Handles the given key \a event.
967 */
968 void QDeclarativeTextEdit::keyPressEvent(QKeyEvent *event)
969 {
970     Q_D(QDeclarativeTextEdit);
971     keyPressPreHandler(event);
972     if (!event->isAccepted())
973         d->control->processEvent(event, QPointF(0, -d->yoff));
974     if (!event->isAccepted())
975         QDeclarativePaintedItem::keyPressEvent(event);
976 }
977
978 /*!
979 \overload
980 Handles the given key \a event.
981 */
982 void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event)
983 {
984     Q_D(QDeclarativeTextEdit);
985     keyReleasePreHandler(event);
986     if (!event->isAccepted())
987         d->control->processEvent(event, QPointF(0, -d->yoff));
988     if (!event->isAccepted())
989         QDeclarativePaintedItem::keyReleaseEvent(event);
990 }
991
992 void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus)
993 {
994     Q_Q(QDeclarativeTextEdit);
995     q->setCursorVisible(hasFocus);
996     QDeclarativeItemPrivate::focusChanged(hasFocus);
997 }
998
999 /*!
1000     \qmlmethod void TextEdit::selectAll()
1001
1002     Causes all text to be selected.
1003 */
1004 void QDeclarativeTextEdit::selectAll()
1005 {
1006     Q_D(QDeclarativeTextEdit);
1007     d->control->selectAll();
1008 }
1009
1010 /*!
1011     \qmlmethod void TextEdit::selectWord()
1012
1013     Causes the word closest to the current cursor position to be selected.
1014 */
1015 void QDeclarativeTextEdit::selectWord()
1016 {
1017     Q_D(QDeclarativeTextEdit);
1018     QTextCursor c = d->control->textCursor();
1019     c.select(QTextCursor::WordUnderCursor);
1020     d->control->setTextCursor(c);
1021 }
1022
1023 /*!
1024     \qmlmethod void TextEdit::select(int start, int end)
1025
1026     Causes the text from \a start to \a end to be selected.
1027
1028     If either start or end is out of range, the selection is not changed.
1029
1030     After calling this, selectionStart will become the lesser
1031     and selectionEnd will become the greater (regardless of the order passed
1032     to this method).
1033
1034     \sa selectionStart, selectionEnd
1035 */
1036 void QDeclarativeTextEdit::select(int start, int end)
1037 {
1038     Q_D(QDeclarativeTextEdit);
1039     if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
1040         return;
1041     QTextCursor cursor = d->control->textCursor();
1042     cursor.beginEditBlock();
1043     cursor.setPosition(start, QTextCursor::MoveAnchor);
1044     cursor.setPosition(end, QTextCursor::KeepAnchor);
1045     cursor.endEditBlock();
1046     d->control->setTextCursor(cursor);
1047
1048     // QTBUG-11100
1049     updateSelectionMarkers();
1050 }
1051
1052 #ifndef QT_NO_CLIPBOARD
1053 /*!
1054     \qmlmethod TextEdit::cut()
1055
1056     Moves the currently selected text to the system clipboard.
1057 */
1058 void QDeclarativeTextEdit::cut()
1059 {
1060     Q_D(QDeclarativeTextEdit);
1061     d->control->cut();
1062 }
1063
1064 /*!
1065     \qmlmethod TextEdit::copy()
1066
1067     Copies the currently selected text to the system clipboard.
1068 */
1069 void QDeclarativeTextEdit::copy()
1070 {
1071     Q_D(QDeclarativeTextEdit);
1072     d->control->copy();
1073 }
1074
1075 /*!
1076     \qmlmethod TextEdit::paste()
1077
1078     Replaces the currently selected text by the contents of the system clipboard.
1079 */
1080 void QDeclarativeTextEdit::paste()
1081 {
1082     Q_D(QDeclarativeTextEdit);
1083     d->control->paste();
1084 }
1085 #endif // QT_NO_CLIPBOARD
1086
1087 /*!
1088 \overload
1089 Handles the given mouse \a event.
1090 */
1091 void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
1092 {
1093     Q_D(QDeclarativeTextEdit);
1094     if (d->focusOnPress){
1095         bool hadActiveFocus = hasActiveFocus();
1096         forceActiveFocus();
1097         if (d->showInputPanelOnFocus) {
1098             if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1099                 // re-open input panel on press if already focused
1100                 openSoftwareInputPanel();
1101             }
1102         } else { // show input panel on click
1103             if (hasActiveFocus() && !hadActiveFocus) {
1104                 d->clickCausedFocus = true;
1105             }
1106         }
1107     }
1108     if (event->type() != QEvent::GraphicsSceneMouseDoubleClick || d->selectByMouse)
1109         d->control->processEvent(event, QPointF(0, -d->yoff));
1110     if (!event->isAccepted())
1111         QDeclarativePaintedItem::mousePressEvent(event);
1112 }
1113
1114 /*!
1115 \overload
1116 Handles the given mouse \a event.
1117 */
1118 void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1119 {
1120     Q_D(QDeclarativeTextEdit);
1121     d->control->processEvent(event, QPointF(0, -d->yoff));
1122     if (!d->showInputPanelOnFocus) { // input panel on click
1123         if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1124             if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1125                 if (view->scene() && view->scene() == scene()) {
1126                     qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1127                 }
1128             }
1129         }
1130     }
1131     d->clickCausedFocus = false;
1132
1133     if (!event->isAccepted())
1134         QDeclarativePaintedItem::mouseReleaseEvent(event);
1135 }
1136
1137 /*!
1138 \overload
1139 Handles the given mouse \a event.
1140 */
1141 void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1142 {
1143     Q_D(QDeclarativeTextEdit);
1144     if (d->selectByMouse) {
1145         d->control->processEvent(event, QPointF(0, -d->yoff));
1146         if (!event->isAccepted())
1147             QDeclarativePaintedItem::mouseDoubleClickEvent(event);
1148     } else {
1149         QDeclarativePaintedItem::mouseDoubleClickEvent(event);
1150     }
1151 }
1152
1153 /*!
1154 \overload
1155 Handles the given mouse \a event.
1156 */
1157 void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1158 {
1159     Q_D(QDeclarativeTextEdit);
1160     if (d->selectByMouse) {
1161         d->control->processEvent(event, QPointF(0, -d->yoff));
1162         if (!event->isAccepted())
1163             QDeclarativePaintedItem::mouseMoveEvent(event);
1164         event->setAccepted(true);
1165     } else {
1166         QDeclarativePaintedItem::mouseMoveEvent(event);
1167     }
1168 }
1169
1170 /*!
1171 \overload
1172 Handles the given input method \a event.
1173 */
1174 void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event)
1175 {
1176     Q_D(QDeclarativeTextEdit);
1177     d->control->processEvent(event, QPointF(0, -d->yoff));
1178 }
1179
1180 /*!
1181 \overload
1182 Returns the value of the given \a property.
1183 */
1184 QVariant QDeclarativeTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1185 {
1186     Q_D(const QDeclarativeTextEdit);
1187     return d->control->inputMethodQuery(property);
1188 }
1189
1190 /*!
1191 Draws the contents of the text edit using the given \a painter within
1192 the given \a bounds.
1193 */
1194 void QDeclarativeTextEdit::drawContents(QPainter *painter, const QRect &bounds)
1195 {
1196     Q_D(QDeclarativeTextEdit);
1197
1198     painter->setRenderHint(QPainter::TextAntialiasing, true);
1199     painter->translate(0,d->yoff);
1200
1201     d->control->drawContents(painter, bounds.translated(0,-d->yoff));
1202
1203     painter->translate(0,-d->yoff);
1204 }
1205
1206 void QDeclarativeTextEdit::updateImgCache(const QRectF &rf)
1207 {
1208     Q_D(const QDeclarativeTextEdit);
1209     QRect r;
1210     if (!rf.isValid()) {
1211         r = QRect(0,0,INT_MAX,INT_MAX);
1212     } else {
1213         r = rf.toRect();
1214         if (r.height() > INT_MAX/2) {
1215             // Take care of overflow when translating "everything"
1216             r.setTop(r.y() + d->yoff);
1217             r.setBottom(INT_MAX/2);
1218         } else {
1219             r = r.translated(0,d->yoff);
1220         }
1221     }
1222     dirtyCache(r);
1223     emit update();
1224 }
1225
1226 /*!
1227     \qmlproperty bool TextEdit::smooth
1228
1229     This property holds whether the text is smoothly scaled or transformed.
1230
1231     Smooth filtering gives better visual quality, but is slower.  If
1232     the item is displayed at its natural size, this property has no visual or
1233     performance effect.
1234
1235     \note Generally scaling artifacts are only visible if the item is stationary on
1236     the screen.  A common pattern when animating an item is to disable smooth
1237     filtering at the beginning of the animation and reenable it at the conclusion.
1238 */
1239
1240 void QDeclarativeTextEditPrivate::init()
1241 {
1242     Q_Q(QDeclarativeTextEdit);
1243
1244     q->setSmooth(smooth);
1245     q->setAcceptedMouseButtons(Qt::LeftButton);
1246     q->setFlag(QGraphicsItem::ItemHasNoContents, false);
1247     q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
1248
1249     control = new QTextControl(q);
1250     control->setIgnoreUnusedNavigationEvents(true);
1251
1252     // QTextControl follows the default text color
1253     // defined by the platform, declarative text
1254     // should be black by default
1255     QPalette pal = control->palette();
1256     if (pal.color(QPalette::Text) != color) {
1257         pal.setColor(QPalette::Text, color);
1258         control->setPalette(pal);
1259     }
1260
1261     QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
1262
1263     QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1264     QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1265     QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1266     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1267     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1268     QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorRectangleChanged()));
1269
1270     document = control->document();
1271     document->setDefaultFont(font);
1272     document->setDocumentMargin(textMargin);
1273     document->setUndoRedoEnabled(false); // flush undo buffer.
1274     document->setUndoRedoEnabled(true);
1275     updateDefaultTextOption();
1276 }
1277
1278 void QDeclarativeTextEdit::q_textChanged()
1279 {
1280     Q_D(QDeclarativeTextEdit);
1281     d->text = text();
1282     updateSize();
1283     updateMicroFocus();
1284     emit textChanged(d->text);
1285 }
1286
1287 void QDeclarativeTextEdit::moveCursorDelegate()
1288 {
1289     Q_D(QDeclarativeTextEdit);
1290     if(!d->cursor)
1291         return;
1292     QRectF cursorRect = d->control->cursorRect();
1293     d->cursor->setX(cursorRect.x());
1294     d->cursor->setY(cursorRect.y());
1295 }
1296
1297 void QDeclarativeTextEditPrivate::updateSelection()
1298 {
1299     Q_Q(QDeclarativeTextEdit);
1300     QTextCursor cursor = control->textCursor();
1301     bool startChange = (lastSelectionStart != cursor.selectionStart());
1302     bool endChange = (lastSelectionEnd != cursor.selectionEnd());
1303     cursor.beginEditBlock();
1304     cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
1305     cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
1306     cursor.endEditBlock();
1307     control->setTextCursor(cursor);
1308     if(startChange)
1309         q->selectionStartChanged();
1310     if(endChange)
1311         q->selectionEndChanged();
1312 }
1313
1314 void QDeclarativeTextEdit::updateSelectionMarkers()
1315 {
1316     Q_D(QDeclarativeTextEdit);
1317     if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
1318         d->lastSelectionStart = d->control->textCursor().selectionStart();
1319         emit selectionStartChanged();
1320     }
1321     if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
1322         d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1323         emit selectionEndChanged();
1324     }
1325     updateMicroFocus();
1326 }
1327
1328 QRectF QDeclarativeTextEdit::boundingRect() const
1329 {
1330     Q_D(const QDeclarativeTextEdit);
1331     QRectF r = QDeclarativePaintedItem::boundingRect();
1332     int cursorWidth = 1;
1333     if(d->cursor)
1334         cursorWidth = d->cursor->width();
1335     if(!d->document->isEmpty())
1336         cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1337
1338     // Could include font max left/right bearings to either side of rectangle.
1339
1340     r.setRight(r.right() + cursorWidth);
1341     return r.translated(0,d->yoff);
1342 }
1343
1344
1345 //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1346 //    need to do all the calculations each time
1347 void QDeclarativeTextEdit::updateSize()
1348 {
1349     Q_D(QDeclarativeTextEdit);
1350     if (isComponentComplete()) {
1351         QFontMetrics fm = QFontMetrics(d->font);
1352         int dy = height();
1353         // ### assumes that if the width is set, the text will fill to edges
1354         // ### (unless wrap is false, then clipping will occur)
1355         if (widthValid()) {
1356             if (d->document->textWidth() != width())
1357                 d->document->setTextWidth(width());
1358         } else {
1359             d->document->setTextWidth(-1);
1360         }
1361         dy -= (int)d->document->size().height();
1362
1363         int nyoff;
1364         if (heightValid()) {
1365             if (d->vAlign == AlignBottom)
1366                 nyoff = dy;
1367             else if (d->vAlign == AlignVCenter)
1368                 nyoff = dy/2;
1369             else
1370                 nyoff = 0;
1371         } else {
1372             nyoff = 0;
1373         }
1374         if (nyoff != d->yoff) {
1375             prepareGeometryChange();
1376             d->yoff = nyoff;
1377         }
1378         setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1379
1380         //### need to comfirm cost of always setting these
1381         int newWidth = qCeil(d->document->idealWidth());
1382         if (!widthValid() && d->document->textWidth() != newWidth)
1383             d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1384         // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1385         setImplicitWidth(newWidth);
1386         qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1387         setImplicitHeight(newHeight);
1388
1389         setContentsSize(QSize(newWidth, newHeight));
1390
1391         emit paintedSizeChanged();
1392     } else {
1393         d->dirty = true;
1394     }
1395     emit update();
1396 }
1397
1398 void QDeclarativeTextEditPrivate::updateDefaultTextOption()
1399 {
1400     QTextOption opt = document->defaultTextOption();
1401     int oldAlignment = opt.alignment();
1402     opt.setAlignment((Qt::Alignment)(int)(hAlign | vAlign));
1403
1404     QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1405     opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1406
1407     if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
1408         return;
1409     document->setDefaultTextOption(opt);
1410 }
1411
1412
1413 /*!
1414     \qmlmethod void TextEdit::openSoftwareInputPanel()
1415
1416     Opens software input panels like virtual keyboards for typing, useful for
1417     customizing when you want the input keyboard to be shown and hidden in
1418     your application.
1419
1420     By default the opening of input panels follows the platform style. On Symbian^1 and
1421     Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1422     the panels are automatically opened when TextEdit element gains active focus. Input panels are
1423     always closed if no editor has active focus.
1424
1425     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1426     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1427     the behavior you want.
1428
1429     Only relevant on platforms, which provide virtual keyboards.
1430
1431     \code
1432         import QtQuick 1.0
1433         TextEdit {
1434             id: textEdit
1435             text: "Hello world!"
1436             activeFocusOnPress: false
1437             MouseArea {
1438                 anchors.fill: parent
1439                 onClicked: {
1440                     if (!textEdit.activeFocus) {
1441                         textEdit.forceActiveFocus();
1442                         textEdit.openSoftwareInputPanel();
1443                     } else {
1444                         textEdit.focus = false;
1445                     }
1446                 }
1447                 onPressAndHold: textEdit.closeSoftwareInputPanel();
1448             }
1449         }
1450     \endcode
1451 */
1452 void QDeclarativeTextEdit::openSoftwareInputPanel()
1453 {
1454     QEvent event(QEvent::RequestSoftwareInputPanel);
1455     if (qApp) {
1456         if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1457             if (view->scene() && view->scene() == scene()) {
1458                 QApplication::sendEvent(view, &event);
1459             }
1460         }
1461     }
1462 }
1463
1464 /*!
1465     \qmlmethod void TextEdit::closeSoftwareInputPanel()
1466
1467     Closes a software input panel like a virtual keyboard shown on the screen, useful
1468     for customizing when you want the input keyboard to be shown and hidden in
1469     your application.
1470
1471     By default the opening of input panels follows the platform style. On Symbian^1 and
1472     Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1473     the panels are automatically opened when TextEdit element gains active focus. Input panels are
1474     always closed if no editor has active focus.
1475
1476     You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1477     and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1478     the behavior you want.
1479
1480     Only relevant on platforms, which provide virtual keyboards.
1481
1482     \code
1483         import QtQuick 1.0
1484         TextEdit {
1485             id: textEdit
1486             text: "Hello world!"
1487             activeFocusOnPress: false
1488             MouseArea {
1489                 anchors.fill: parent
1490                 onClicked: {
1491                     if (!textEdit.activeFocus) {
1492                         textEdit.forceActiveFocus();
1493                         textEdit.openSoftwareInputPanel();
1494                     } else {
1495                         textEdit.focus = false;
1496                     }
1497                 }
1498                 onPressAndHold: textEdit.closeSoftwareInputPanel();
1499             }
1500         }
1501     \endcode
1502 */
1503 void QDeclarativeTextEdit::closeSoftwareInputPanel()
1504 {
1505     QEvent event(QEvent::CloseSoftwareInputPanel);
1506     if (qApp) {
1507         if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1508             if (view->scene() && view->scene() == scene()) {
1509                 QApplication::sendEvent(view, &event);
1510             }
1511         }
1512     }
1513 }
1514
1515 void QDeclarativeTextEdit::focusInEvent(QFocusEvent *event)
1516 {
1517     Q_D(const QDeclarativeTextEdit);
1518     if (d->showInputPanelOnFocus) {
1519         if (d->focusOnPress && !isReadOnly()) {
1520             openSoftwareInputPanel();
1521         }
1522     }
1523     QDeclarativePaintedItem::focusInEvent(event);
1524 }
1525
1526 QT_END_NAMESPACE