source: trunk/src/declarative/graphicsitems/qdeclarativetextedit.cpp@ 1119

Last change on this file since 1119 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 44.2 KB
Line 
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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
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
60QT_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
74TextEdit {
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
106QDeclarativeTextEdit::QDeclarativeTextEdit(QDeclarativeItem *parent)
107: QDeclarativePaintedItem(*(new QDeclarativeTextEditPrivate), parent)
108{
109 Q_D(QDeclarativeTextEdit);
110 d->init();
111}
112
113QString 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*/
238void 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
276Column {
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*/
296QDeclarativeTextEdit::TextFormat QDeclarativeTextEdit::textFormat() const
297{
298 Q_D(const QDeclarativeTextEdit);
299 return d->format;
300}
301
302void 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
326QFont QDeclarativeTextEdit::font() const
327{
328 Q_D(const QDeclarativeTextEdit);
329 return d->sourceFont;
330}
331
332void QDeclarativeTextEdit::setFont(const QFont &font)
333{
334 Q_D(QDeclarativeTextEdit);
335 if (d->sourceFont == font)
336 return;
337
338 d->sourceFont = font;
339 QFont oldFont = d->font;
340 d->font = font;
341 if (d->font.pointSizeF() != -1) {
342 // 0.5pt resolution
343 qreal size = qRound(d->font.pointSizeF()*2.0);
344 d->font.setPointSizeF(size/2.0);
345 }
346
347 if (oldFont != d->font) {
348 clearCache();
349 d->document->setDefaultFont(d->font);
350 if(d->cursor){
351 d->cursor->setHeight(QFontMetrics(d->font).height());
352 moveCursorDelegate();
353 }
354 updateSize();
355 update();
356 }
357 emit fontChanged(d->sourceFont);
358}
359
360/*!
361 \qmlproperty color TextEdit::color
362
363 The text color.
364
365 \qml
366// green text using hexadecimal notation
367TextEdit { color: "#00FF00"; ... }
368
369// steelblue text using SVG color name
370TextEdit { color: "steelblue"; ... }
371 \endqml
372*/
373QColor QDeclarativeTextEdit::color() const
374{
375 Q_D(const QDeclarativeTextEdit);
376 return d->color;
377}
378
379void QDeclarativeTextEdit::setColor(const QColor &color)
380{
381 Q_D(QDeclarativeTextEdit);
382 if (d->color == color)
383 return;
384
385 clearCache();
386 d->color = color;
387 QPalette pal = d->control->palette();
388 pal.setColor(QPalette::Text, color);
389 d->control->setPalette(pal);
390 update();
391 emit colorChanged(d->color);
392}
393
394/*!
395 \qmlproperty color TextEdit::selectionColor
396
397 The text highlight color, used behind selections.
398*/
399QColor QDeclarativeTextEdit::selectionColor() const
400{
401 Q_D(const QDeclarativeTextEdit);
402 return d->selectionColor;
403}
404
405void QDeclarativeTextEdit::setSelectionColor(const QColor &color)
406{
407 Q_D(QDeclarativeTextEdit);
408 if (d->selectionColor == color)
409 return;
410
411 clearCache();
412 d->selectionColor = color;
413 QPalette pal = d->control->palette();
414 pal.setColor(QPalette::Highlight, color);
415 d->control->setPalette(pal);
416 update();
417 emit selectionColorChanged(d->selectionColor);
418}
419
420/*!
421 \qmlproperty color TextEdit::selectedTextColor
422
423 The selected text color, used in selections.
424*/
425QColor QDeclarativeTextEdit::selectedTextColor() const
426{
427 Q_D(const QDeclarativeTextEdit);
428 return d->selectedTextColor;
429}
430
431void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color)
432{
433 Q_D(QDeclarativeTextEdit);
434 if (d->selectedTextColor == color)
435 return;
436
437 clearCache();
438 d->selectedTextColor = color;
439 QPalette pal = d->control->palette();
440 pal.setColor(QPalette::HighlightedText, color);
441 d->control->setPalette(pal);
442 update();
443 emit selectedTextColorChanged(d->selectedTextColor);
444}
445
446/*!
447 \qmlproperty enumeration TextEdit::horizontalAlignment
448 \qmlproperty enumeration TextEdit::verticalAlignment
449
450 Sets the horizontal and vertical alignment of the text within the TextEdit item's
451 width and height. By default, the text is top-left aligned.
452
453 Valid values for \c horizontalAlignment are:
454 \list
455 \o TextEdit.AlignLeft (default)
456 \o TextEdit.AlignRight
457 \o TextEdit.AlignHCenter
458 \endlist
459
460 Valid values for \c verticalAlignment are:
461 \list
462 \o TextEdit.AlignTop (default)
463 \o TextEdit.AlignBottom
464 \c TextEdit.AlignVCenter
465 \endlist
466*/
467QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const
468{
469 Q_D(const QDeclarativeTextEdit);
470 return d->hAlign;
471}
472
473void QDeclarativeTextEdit::setHAlign(QDeclarativeTextEdit::HAlignment alignment)
474{
475 Q_D(QDeclarativeTextEdit);
476 if (alignment == d->hAlign)
477 return;
478 d->hAlign = alignment;
479 d->updateDefaultTextOption();
480 updateSize();
481 emit horizontalAlignmentChanged(d->hAlign);
482}
483
484QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const
485{
486 Q_D(const QDeclarativeTextEdit);
487 return d->vAlign;
488}
489
490void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment)
491{
492 Q_D(QDeclarativeTextEdit);
493 if (alignment == d->vAlign)
494 return;
495 d->vAlign = alignment;
496 d->updateDefaultTextOption();
497 updateSize();
498 emit verticalAlignmentChanged(d->vAlign);
499}
500
501/*!
502 \qmlproperty enumeration TextEdit::wrapMode
503
504 Set this property to wrap the text to the TextEdit item's width.
505 The text will only wrap if an explicit width has been set.
506
507 \list
508 \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width.
509 \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width.
510 \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
511 \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.
512 \endlist
513
514 The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap.
515*/
516QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const
517{
518 Q_D(const QDeclarativeTextEdit);
519 return d->wrapMode;
520}
521
522void QDeclarativeTextEdit::setWrapMode(WrapMode mode)
523{
524 Q_D(QDeclarativeTextEdit);
525 if (mode == d->wrapMode)
526 return;
527 d->wrapMode = mode;
528 d->updateDefaultTextOption();
529 updateSize();
530 emit wrapModeChanged();
531}
532
533/*!
534 \qmlproperty real TextEdit::paintedWidth
535
536 Returns the width of the text, including the width past the width
537 which is covered due to insufficient wrapping if \l wrapMode is set.
538*/
539qreal QDeclarativeTextEdit::paintedWidth() const
540{
541 return implicitWidth();
542}
543
544/*!
545 \qmlproperty real TextEdit::paintedHeight
546
547 Returns the height of the text, including the height past the height
548 that is covered if the text does not fit within the set height.
549*/
550qreal QDeclarativeTextEdit::paintedHeight() const
551{
552 return implicitHeight();
553}
554
555/*!
556 \qmlmethod rectangle TextEdit::positionToRectangle(position)
557
558 Returns the rectangle at the given \a position in the text. The x, y,
559 and height properties correspond to the cursor that would describe
560 that position.
561*/
562QRectF QDeclarativeTextEdit::positionToRectangle(int pos) const
563{
564 Q_D(const QDeclarativeTextEdit);
565 QTextCursor c(d->document);
566 c.setPosition(pos);
567 return d->control->cursorRect(c);
568
569}
570
571/*!
572 \qmlmethod int TextEdit::positionAt(int x, int y)
573
574 Returns the text position closest to pixel position (\a x, \a y).
575
576 Position 0 is before the first character, position 1 is after the first character
577 but before the second, and so on until position \l {text}.length, which is after all characters.
578*/
579int QDeclarativeTextEdit::positionAt(int x, int y) const
580{
581 Q_D(const QDeclarativeTextEdit);
582 int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
583 return r;
584}
585
586/*!
587 \qmlmethod int TextEdit::moveCursorSelection(int pos)
588
589 Moves the cursor to \a position and updates the selection accordingly.
590 (To only move the cursor, set the \l cursorPosition property.)
591
592 When this method is called it additionally sets either the
593 selectionStart or the selectionEnd (whichever was at the previous cursor position)
594 to the specified position. This allows you to easily extend and contract the selected
595 text range.
596
597 For example, take this sequence of calls:
598
599 \code
600 cursorPosition = 5
601 moveCursorSelection(9)
602 moveCursorSelection(7)
603 \endcode
604
605 This moves the cursor to position 5, extend the selection end from 5 to 9
606 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
607 selected (the 6th and 7th characters).
608*/
609void QDeclarativeTextEdit::moveCursorSelection(int pos)
610{
611 //Note that this is the same as setCursorPosition but with the KeepAnchor flag set
612 Q_D(QDeclarativeTextEdit);
613 QTextCursor cursor = d->control->textCursor();
614 if (cursor.position() == pos)
615 return;
616 cursor.setPosition(pos, QTextCursor::KeepAnchor);
617 d->control->setTextCursor(cursor);
618}
619
620/*!
621 \qmlproperty bool TextEdit::cursorVisible
622 If true the text edit shows a cursor.
623
624 This property is set and unset when the text edit gets active focus, but it can also
625 be set directly (useful, for example, if a KeyProxy might forward keys to it).
626*/
627bool QDeclarativeTextEdit::isCursorVisible() const
628{
629 Q_D(const QDeclarativeTextEdit);
630 return d->cursorVisible;
631}
632
633void QDeclarativeTextEdit::setCursorVisible(bool on)
634{
635 Q_D(QDeclarativeTextEdit);
636 if (d->cursorVisible == on)
637 return;
638 d->cursorVisible = on;
639 QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
640 if (!on && !d->persistentSelection)
641 d->control->setCursorIsFocusIndicator(true);
642 d->control->processEvent(&focusEvent, QPointF(0, -d->yoff));
643 emit cursorVisibleChanged(d->cursorVisible);
644}
645
646/*!
647 \qmlproperty int TextEdit::cursorPosition
648 The position of the cursor in the TextEdit.
649*/
650int QDeclarativeTextEdit::cursorPosition() const
651{
652 Q_D(const QDeclarativeTextEdit);
653 return d->control->textCursor().position();
654}
655
656void QDeclarativeTextEdit::setCursorPosition(int pos)
657{
658 Q_D(QDeclarativeTextEdit);
659 if (pos < 0 || pos > d->text.length())
660 return;
661 QTextCursor cursor = d->control->textCursor();
662 if (cursor.position() == pos)
663 return;
664 cursor.setPosition(pos);
665 d->control->setTextCursor(cursor);
666}
667
668/*!
669 \qmlproperty Component TextEdit::cursorDelegate
670 The delegate for the cursor in the TextEdit.
671
672 If you set a cursorDelegate for a TextEdit, this delegate will be used for
673 drawing the cursor instead of the standard cursor. An instance of the
674 delegate will be created and managed by the text edit when a cursor is
675 needed, and the x and y properties of delegate instance will be set so as
676 to be one pixel before the top left of the current character.
677
678 Note that the root item of the delegate component must be a QDeclarativeItem or
679 QDeclarativeItem derived item.
680*/
681QDeclarativeComponent* QDeclarativeTextEdit::cursorDelegate() const
682{
683 Q_D(const QDeclarativeTextEdit);
684 return d->cursorComponent;
685}
686
687void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c)
688{
689 Q_D(QDeclarativeTextEdit);
690 if(d->cursorComponent){
691 if(d->cursor){
692 disconnect(d->control, SIGNAL(cursorPositionChanged()),
693 this, SLOT(moveCursorDelegate()));
694 d->control->setCursorWidth(-1);
695 dirtyCache(cursorRectangle());
696 delete d->cursor;
697 d->cursor = 0;
698 }
699 }
700 d->cursorComponent = c;
701 if(c && c->isReady()){
702 loadCursorDelegate();
703 }else{
704 if(c)
705 connect(c, SIGNAL(statusChanged()),
706 this, SLOT(loadCursorDelegate()));
707 }
708
709 emit cursorDelegateChanged();
710}
711
712void QDeclarativeTextEdit::loadCursorDelegate()
713{
714 Q_D(QDeclarativeTextEdit);
715 if(d->cursorComponent->isLoading())
716 return;
717 d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this)));
718 if(d->cursor){
719 connect(d->control, SIGNAL(cursorPositionChanged()),
720 this, SLOT(moveCursorDelegate()));
721 d->control->setCursorWidth(0);
722 dirtyCache(cursorRectangle());
723 QDeclarative_setParent_noEvent(d->cursor, this);
724 d->cursor->setParentItem(this);
725 d->cursor->setHeight(QFontMetrics(d->font).height());
726 moveCursorDelegate();
727 }else{
728 qmlInfo(this) << "Error loading cursor delegate.";
729 }
730}
731
732/*!
733 \qmlproperty int TextEdit::selectionStart
734
735 The cursor position before the first character in the current selection.
736
737 This property is read-only. To change the selection, use select(start,end),
738 selectAll(), or selectWord().
739
740 \sa selectionEnd, cursorPosition, selectedText
741*/
742int QDeclarativeTextEdit::selectionStart() const
743{
744 Q_D(const QDeclarativeTextEdit);
745 return d->control->textCursor().selectionStart();
746}
747
748/*!
749 \qmlproperty int TextEdit::selectionEnd
750
751 The cursor position after the last character in the current selection.
752
753 This property is read-only. To change the selection, use select(start,end),
754 selectAll(), or selectWord().
755
756 \sa selectionStart, cursorPosition, selectedText
757*/
758int QDeclarativeTextEdit::selectionEnd() const
759{
760 Q_D(const QDeclarativeTextEdit);
761 return d->control->textCursor().selectionEnd();
762}
763
764/*!
765 \qmlproperty string TextEdit::selectedText
766
767 This read-only property provides the text currently selected in the
768 text edit.
769
770 It is equivalent to the following snippet, but is faster and easier
771 to use.
772 \code
773 //myTextEdit is the id of the TextEdit
774 myTextEdit.text.toString().substring(myTextEdit.selectionStart,
775 myTextEdit.selectionEnd);
776 \endcode
777*/
778QString QDeclarativeTextEdit::selectedText() const
779{
780 Q_D(const QDeclarativeTextEdit);
781 return d->control->textCursor().selectedText();
782}
783
784/*!
785 \qmlproperty bool TextEdit::activeFocusOnPress
786
787 Whether the TextEdit should gain active focus on a mouse press. By default this is
788 set to true.
789*/
790bool QDeclarativeTextEdit::focusOnPress() const
791{
792 Q_D(const QDeclarativeTextEdit);
793 return d->focusOnPress;
794}
795
796void QDeclarativeTextEdit::setFocusOnPress(bool on)
797{
798 Q_D(QDeclarativeTextEdit);
799 if (d->focusOnPress == on)
800 return;
801 d->focusOnPress = on;
802 emit activeFocusOnPressChanged(d->focusOnPress);
803}
804
805/*!
806 \qmlproperty bool TextEdit::persistentSelection
807
808 Whether the TextEdit should keep the selection visible when it loses active focus to another
809 item in the scene. By default this is set to true;
810*/
811bool QDeclarativeTextEdit::persistentSelection() const
812{
813 Q_D(const QDeclarativeTextEdit);
814 return d->persistentSelection;
815}
816
817void QDeclarativeTextEdit::setPersistentSelection(bool on)
818{
819 Q_D(QDeclarativeTextEdit);
820 if (d->persistentSelection == on)
821 return;
822 d->persistentSelection = on;
823 emit persistentSelectionChanged(d->persistentSelection);
824}
825
826/*
827 \qmlproperty real TextEdit::textMargin
828
829 The margin, in pixels, around the text in the TextEdit.
830*/
831qreal QDeclarativeTextEdit::textMargin() const
832{
833 Q_D(const QDeclarativeTextEdit);
834 return d->textMargin;
835}
836
837void QDeclarativeTextEdit::setTextMargin(qreal margin)
838{
839 Q_D(QDeclarativeTextEdit);
840 if (d->textMargin == margin)
841 return;
842 d->textMargin = margin;
843 d->document->setDocumentMargin(d->textMargin);
844 emit textMarginChanged(d->textMargin);
845}
846
847void QDeclarativeTextEdit::geometryChanged(const QRectF &newGeometry,
848 const QRectF &oldGeometry)
849{
850 if (newGeometry.width() != oldGeometry.width())
851 updateSize();
852 QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry);
853}
854
855/*!
856 Ensures any delayed caching or data loading the class
857 needs to performed is complete.
858*/
859void QDeclarativeTextEdit::componentComplete()
860{
861 Q_D(QDeclarativeTextEdit);
862 QDeclarativePaintedItem::componentComplete();
863 if (d->dirty) {
864 updateSize();
865 d->dirty = false;
866 }
867}
868
869/*!
870 \qmlproperty bool TextEdit::selectByMouse
871
872 Defaults to false.
873
874 If true, the user can use the mouse to select text in some
875 platform-specific way. Note that for some platforms this may
876 not be an appropriate interaction (eg. may conflict with how
877 the text needs to behave inside a Flickable.
878*/
879bool QDeclarativeTextEdit::selectByMouse() const
880{
881 Q_D(const QDeclarativeTextEdit);
882 return d->selectByMouse;
883}
884
885void QDeclarativeTextEdit::setSelectByMouse(bool on)
886{
887 Q_D(QDeclarativeTextEdit);
888 if (d->selectByMouse != on) {
889 d->selectByMouse = on;
890 emit selectByMouseChanged(on);
891 }
892}
893
894
895
896/*!
897 \qmlproperty bool TextEdit::readOnly
898
899 Whether the user an interact with the TextEdit item. If this
900 property is set to true the text cannot be edited by user interaction.
901
902 By default this property is false.
903*/
904void QDeclarativeTextEdit::setReadOnly(bool r)
905{
906 Q_D(QDeclarativeTextEdit);
907 if (r == isReadOnly())
908 return;
909
910
911 Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
912 if (r) {
913 flags = Qt::TextSelectableByMouse;
914 } else {
915 flags = Qt::TextEditorInteraction;
916 }
917 d->control->setTextInteractionFlags(flags);
918 if (!r)
919 d->control->moveCursor(QTextCursor::End);
920
921 emit readOnlyChanged(r);
922}
923
924bool QDeclarativeTextEdit::isReadOnly() const
925{
926 Q_D(const QDeclarativeTextEdit);
927 return !(d->control->textInteractionFlags() & Qt::TextEditable);
928}
929
930/*!
931 Sets how the text edit should interact with user input to the given
932 \a flags.
933*/
934void QDeclarativeTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
935{
936 Q_D(QDeclarativeTextEdit);
937 d->control->setTextInteractionFlags(flags);
938}
939
940/*!
941 Returns the flags specifying how the text edit should interact
942 with user input.
943*/
944Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const
945{
946 Q_D(const QDeclarativeTextEdit);
947 return d->control->textInteractionFlags();
948}
949
950/*!
951 \qmlproperty rectangle TextEdit::cursorRectangle
952
953 The rectangle where the text cursor is rendered
954 within the text edit. Read-only.
955*/
956QRect QDeclarativeTextEdit::cursorRectangle() const
957{
958 Q_D(const QDeclarativeTextEdit);
959 return d->control->cursorRect().toRect().translated(0,-d->yoff);
960}
961
962
963/*!
964\overload
965Handles the given \a event.
966*/
967bool QDeclarativeTextEdit::event(QEvent *event)
968{
969 Q_D(QDeclarativeTextEdit);
970 if (event->type() == QEvent::ShortcutOverride) {
971 d->control->processEvent(event, QPointF(0, -d->yoff));
972 return event->isAccepted();
973 }
974 return QDeclarativePaintedItem::event(event);
975}
976
977/*!
978\overload
979Handles the given key \a event.
980*/
981void QDeclarativeTextEdit::keyPressEvent(QKeyEvent *event)
982{
983 Q_D(QDeclarativeTextEdit);
984 keyPressPreHandler(event);
985 if (!event->isAccepted())
986 d->control->processEvent(event, QPointF(0, -d->yoff));
987 if (!event->isAccepted())
988 QDeclarativePaintedItem::keyPressEvent(event);
989}
990
991/*!
992\overload
993Handles the given key \a event.
994*/
995void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event)
996{
997 Q_D(QDeclarativeTextEdit);
998 keyReleasePreHandler(event);
999 if (!event->isAccepted())
1000 d->control->processEvent(event, QPointF(0, -d->yoff));
1001 if (!event->isAccepted())
1002 QDeclarativePaintedItem::keyReleaseEvent(event);
1003}
1004
1005void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus)
1006{
1007 Q_Q(QDeclarativeTextEdit);
1008 q->setCursorVisible(hasFocus);
1009 QDeclarativeItemPrivate::focusChanged(hasFocus);
1010}
1011
1012/*!
1013 \qmlmethod void TextEdit::selectAll()
1014
1015 Causes all text to be selected.
1016*/
1017void QDeclarativeTextEdit::selectAll()
1018{
1019 Q_D(QDeclarativeTextEdit);
1020 d->control->selectAll();
1021}
1022
1023/*!
1024 \qmlmethod void TextEdit::selectWord()
1025
1026 Causes the word closest to the current cursor position to be selected.
1027*/
1028void QDeclarativeTextEdit::selectWord()
1029{
1030 Q_D(QDeclarativeTextEdit);
1031 QTextCursor c = d->control->textCursor();
1032 c.select(QTextCursor::WordUnderCursor);
1033 d->control->setTextCursor(c);
1034}
1035
1036/*!
1037 \qmlmethod void TextEdit::select(int start, int end)
1038
1039 Causes the text from \a start to \a end to be selected.
1040
1041 If either start or end is out of range, the selection is not changed.
1042
1043 After calling this, selectionStart will become the lesser
1044 and selectionEnd will become the greater (regardless of the order passed
1045 to this method).
1046
1047 \sa selectionStart, selectionEnd
1048*/
1049void QDeclarativeTextEdit::select(int start, int end)
1050{
1051 Q_D(QDeclarativeTextEdit);
1052 if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length())
1053 return;
1054 QTextCursor cursor = d->control->textCursor();
1055 cursor.beginEditBlock();
1056 cursor.setPosition(start, QTextCursor::MoveAnchor);
1057 cursor.setPosition(end, QTextCursor::KeepAnchor);
1058 cursor.endEditBlock();
1059 d->control->setTextCursor(cursor);
1060
1061 // QTBUG-11100
1062 updateSelectionMarkers();
1063}
1064
1065#ifndef QT_NO_CLIPBOARD
1066/*!
1067 \qmlmethod TextEdit::cut()
1068
1069 Moves the currently selected text to the system clipboard.
1070*/
1071void QDeclarativeTextEdit::cut()
1072{
1073 Q_D(QDeclarativeTextEdit);
1074 d->control->cut();
1075}
1076
1077/*!
1078 \qmlmethod TextEdit::copy()
1079
1080 Copies the currently selected text to the system clipboard.
1081*/
1082void QDeclarativeTextEdit::copy()
1083{
1084 Q_D(QDeclarativeTextEdit);
1085 d->control->copy();
1086}
1087
1088/*!
1089 \qmlmethod TextEdit::paste()
1090
1091 Replaces the currently selected text by the contents of the system clipboard.
1092*/
1093void QDeclarativeTextEdit::paste()
1094{
1095 Q_D(QDeclarativeTextEdit);
1096 d->control->paste();
1097}
1098#endif // QT_NO_CLIPBOARD
1099
1100/*!
1101\overload
1102Handles the given mouse \a event.
1103*/
1104void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
1105{
1106 Q_D(QDeclarativeTextEdit);
1107 if (d->focusOnPress){
1108 bool hadActiveFocus = hasActiveFocus();
1109 forceActiveFocus();
1110 if (d->showInputPanelOnFocus) {
1111 if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1112 // re-open input panel on press if already focused
1113 openSoftwareInputPanel();
1114 }
1115 } else { // show input panel on click
1116 if (hasActiveFocus() && !hadActiveFocus) {
1117 d->clickCausedFocus = true;
1118 }
1119 }
1120 }
1121 if (event->type() != QEvent::GraphicsSceneMouseDoubleClick || d->selectByMouse)
1122 d->control->processEvent(event, QPointF(0, -d->yoff));
1123 if (!event->isAccepted())
1124 QDeclarativePaintedItem::mousePressEvent(event);
1125}
1126
1127/*!
1128\overload
1129Handles the given mouse \a event.
1130*/
1131void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1132{
1133 Q_D(QDeclarativeTextEdit);
1134 d->control->processEvent(event, QPointF(0, -d->yoff));
1135 if (!d->showInputPanelOnFocus) { // input panel on click
1136 if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1137 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1138 if (view->scene() && view->scene() == scene()) {
1139 qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1140 }
1141 }
1142 }
1143 }
1144 d->clickCausedFocus = false;
1145
1146 if (!event->isAccepted())
1147 QDeclarativePaintedItem::mouseReleaseEvent(event);
1148}
1149
1150/*!
1151\overload
1152Handles the given mouse \a event.
1153*/
1154void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1155{
1156 Q_D(QDeclarativeTextEdit);
1157 if (d->selectByMouse) {
1158 d->control->processEvent(event, QPointF(0, -d->yoff));
1159 if (!event->isAccepted())
1160 QDeclarativePaintedItem::mouseDoubleClickEvent(event);
1161 } else {
1162 QDeclarativePaintedItem::mouseDoubleClickEvent(event);
1163 }
1164}
1165
1166/*!
1167\overload
1168Handles the given mouse \a event.
1169*/
1170void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1171{
1172 Q_D(QDeclarativeTextEdit);
1173 if (d->selectByMouse) {
1174 d->control->processEvent(event, QPointF(0, -d->yoff));
1175 if (!event->isAccepted())
1176 QDeclarativePaintedItem::mouseMoveEvent(event);
1177 event->setAccepted(true);
1178 } else {
1179 QDeclarativePaintedItem::mouseMoveEvent(event);
1180 }
1181}
1182
1183/*!
1184\overload
1185Handles the given input method \a event.
1186*/
1187void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event)
1188{
1189 Q_D(QDeclarativeTextEdit);
1190 d->control->processEvent(event, QPointF(0, -d->yoff));
1191}
1192
1193/*!
1194\overload
1195Returns the value of the given \a property.
1196*/
1197QVariant QDeclarativeTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
1198{
1199 Q_D(const QDeclarativeTextEdit);
1200 return d->control->inputMethodQuery(property);
1201}
1202
1203/*!
1204Draws the contents of the text edit using the given \a painter within
1205the given \a bounds.
1206*/
1207void QDeclarativeTextEdit::drawContents(QPainter *painter, const QRect &bounds)
1208{
1209 Q_D(QDeclarativeTextEdit);
1210
1211 painter->setRenderHint(QPainter::TextAntialiasing, true);
1212 painter->translate(0,d->yoff);
1213
1214 d->control->drawContents(painter, bounds.translated(0,-d->yoff));
1215
1216 painter->translate(0,-d->yoff);
1217}
1218
1219void QDeclarativeTextEdit::updateImgCache(const QRectF &rf)
1220{
1221 Q_D(const QDeclarativeTextEdit);
1222 QRect r;
1223 if (!rf.isValid()) {
1224 r = QRect(0,0,INT_MAX,INT_MAX);
1225 } else {
1226 r = rf.toRect();
1227 if (r.height() > INT_MAX/2) {
1228 // Take care of overflow when translating "everything"
1229 r.setTop(r.y() + d->yoff);
1230 r.setBottom(INT_MAX/2);
1231 } else {
1232 r = r.translated(0,d->yoff);
1233 }
1234 }
1235 dirtyCache(r);
1236 emit update();
1237}
1238
1239/*!
1240 \qmlproperty bool TextEdit::smooth
1241
1242 This property holds whether the text is smoothly scaled or transformed.
1243
1244 Smooth filtering gives better visual quality, but is slower. If
1245 the item is displayed at its natural size, this property has no visual or
1246 performance effect.
1247
1248 \note Generally scaling artifacts are only visible if the item is stationary on
1249 the screen. A common pattern when animating an item is to disable smooth
1250 filtering at the beginning of the animation and reenable it at the conclusion.
1251*/
1252
1253void QDeclarativeTextEditPrivate::init()
1254{
1255 Q_Q(QDeclarativeTextEdit);
1256
1257 q->setSmooth(smooth);
1258 q->setAcceptedMouseButtons(Qt::LeftButton);
1259 q->setFlag(QGraphicsItem::ItemHasNoContents, false);
1260 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod);
1261
1262 control = new QTextControl(q);
1263 control->setIgnoreUnusedNavigationEvents(true);
1264
1265 // QTextControl follows the default text color
1266 // defined by the platform, declarative text
1267 // should be black by default
1268 QPalette pal = control->palette();
1269 if (pal.color(QPalette::Text) != color) {
1270 pal.setColor(QPalette::Text, color);
1271 control->setPalette(pal);
1272 }
1273
1274 QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
1275
1276 QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
1277 QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
1278 QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers()));
1279 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers()));
1280 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
1281 QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorRectangleChanged()));
1282
1283 document = control->document();
1284 document->setDefaultFont(font);
1285 document->setDocumentMargin(textMargin);
1286 document->setUndoRedoEnabled(false); // flush undo buffer.
1287 document->setUndoRedoEnabled(true);
1288 updateDefaultTextOption();
1289}
1290
1291void QDeclarativeTextEdit::q_textChanged()
1292{
1293 Q_D(QDeclarativeTextEdit);
1294 d->text = text();
1295 updateSize();
1296 updateMicroFocus();
1297 emit textChanged(d->text);
1298}
1299
1300void QDeclarativeTextEdit::moveCursorDelegate()
1301{
1302 Q_D(QDeclarativeTextEdit);
1303 if(!d->cursor)
1304 return;
1305 QRectF cursorRect = d->control->cursorRect();
1306 d->cursor->setX(cursorRect.x());
1307 d->cursor->setY(cursorRect.y());
1308}
1309
1310void QDeclarativeTextEditPrivate::updateSelection()
1311{
1312 Q_Q(QDeclarativeTextEdit);
1313 QTextCursor cursor = control->textCursor();
1314 bool startChange = (lastSelectionStart != cursor.selectionStart());
1315 bool endChange = (lastSelectionEnd != cursor.selectionEnd());
1316 cursor.beginEditBlock();
1317 cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor);
1318 cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor);
1319 cursor.endEditBlock();
1320 control->setTextCursor(cursor);
1321 if(startChange)
1322 q->selectionStartChanged();
1323 if(endChange)
1324 q->selectionEndChanged();
1325}
1326
1327void QDeclarativeTextEdit::updateSelectionMarkers()
1328{
1329 Q_D(QDeclarativeTextEdit);
1330 if(d->lastSelectionStart != d->control->textCursor().selectionStart()){
1331 d->lastSelectionStart = d->control->textCursor().selectionStart();
1332 emit selectionStartChanged();
1333 }
1334 if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){
1335 d->lastSelectionEnd = d->control->textCursor().selectionEnd();
1336 emit selectionEndChanged();
1337 }
1338 updateMicroFocus();
1339}
1340
1341QRectF QDeclarativeTextEdit::boundingRect() const
1342{
1343 Q_D(const QDeclarativeTextEdit);
1344 QRectF r = QDeclarativePaintedItem::boundingRect();
1345 int cursorWidth = 1;
1346 if(d->cursor)
1347 cursorWidth = d->cursor->width();
1348 if(!d->document->isEmpty())
1349 cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor
1350
1351 // Could include font max left/right bearings to either side of rectangle.
1352
1353 r.setRight(r.right() + cursorWidth);
1354 return r.translated(0,d->yoff);
1355}
1356
1357
1358//### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
1359// need to do all the calculations each time
1360void QDeclarativeTextEdit::updateSize()
1361{
1362 Q_D(QDeclarativeTextEdit);
1363 if (isComponentComplete()) {
1364 QFontMetrics fm = QFontMetrics(d->font);
1365 int dy = height();
1366 // ### assumes that if the width is set, the text will fill to edges
1367 // ### (unless wrap is false, then clipping will occur)
1368 if (widthValid()) {
1369 if (d->document->textWidth() != width())
1370 d->document->setTextWidth(width());
1371 } else {
1372 d->document->setTextWidth(-1);
1373 }
1374 dy -= (int)d->document->size().height();
1375
1376 int nyoff;
1377 if (heightValid()) {
1378 if (d->vAlign == AlignBottom)
1379 nyoff = dy;
1380 else if (d->vAlign == AlignVCenter)
1381 nyoff = dy/2;
1382 else
1383 nyoff = 0;
1384 } else {
1385 nyoff = 0;
1386 }
1387 if (nyoff != d->yoff) {
1388 prepareGeometryChange();
1389 d->yoff = nyoff;
1390 }
1391 setBaselineOffset(fm.ascent() + d->yoff + d->textMargin);
1392
1393 //### need to comfirm cost of always setting these
1394 int newWidth = qCeil(d->document->idealWidth());
1395 if (!widthValid() && d->document->textWidth() != newWidth)
1396 d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug)
1397 // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed.
1398 setImplicitWidth(newWidth);
1399 qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height();
1400 setImplicitHeight(newHeight);
1401
1402 setContentsSize(QSize(newWidth, newHeight));
1403
1404 emit paintedSizeChanged();
1405 } else {
1406 d->dirty = true;
1407 }
1408 emit update();
1409}
1410
1411void QDeclarativeTextEditPrivate::updateDefaultTextOption()
1412{
1413 QTextOption opt = document->defaultTextOption();
1414 int oldAlignment = opt.alignment();
1415 opt.setAlignment((Qt::Alignment)(int)(hAlign | vAlign));
1416
1417 QTextOption::WrapMode oldWrapMode = opt.wrapMode();
1418 opt.setWrapMode(QTextOption::WrapMode(wrapMode));
1419
1420 if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
1421 return;
1422 document->setDefaultTextOption(opt);
1423}
1424
1425
1426/*!
1427 \qmlmethod void TextEdit::openSoftwareInputPanel()
1428
1429 Opens software input panels like virtual keyboards for typing, useful for
1430 customizing when you want the input keyboard to be shown and hidden in
1431 your application.
1432
1433 By default the opening of input panels follows the platform style. On Symbian^1 and
1434 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1435 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1436 always closed if no editor has active focus.
1437
1438 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1439 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1440 the behavior you want.
1441
1442 Only relevant on platforms, which provide virtual keyboards.
1443
1444 \code
1445 import QtQuick 1.0
1446 TextEdit {
1447 id: textEdit
1448 text: "Hello world!"
1449 activeFocusOnPress: false
1450 MouseArea {
1451 anchors.fill: parent
1452 onClicked: {
1453 if (!textEdit.activeFocus) {
1454 textEdit.forceActiveFocus();
1455 textEdit.openSoftwareInputPanel();
1456 } else {
1457 textEdit.focus = false;
1458 }
1459 }
1460 onPressAndHold: textEdit.closeSoftwareInputPanel();
1461 }
1462 }
1463 \endcode
1464*/
1465void QDeclarativeTextEdit::openSoftwareInputPanel()
1466{
1467 QEvent event(QEvent::RequestSoftwareInputPanel);
1468 if (qApp) {
1469 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1470 if (view->scene() && view->scene() == scene()) {
1471 QApplication::sendEvent(view, &event);
1472 }
1473 }
1474 }
1475}
1476
1477/*!
1478 \qmlmethod void TextEdit::closeSoftwareInputPanel()
1479
1480 Closes a software input panel like a virtual keyboard shown on the screen, useful
1481 for customizing when you want the input keyboard to be shown and hidden in
1482 your application.
1483
1484 By default the opening of input panels follows the platform style. On Symbian^1 and
1485 Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms
1486 the panels are automatically opened when TextEdit element gains active focus. Input panels are
1487 always closed if no editor has active focus.
1488
1489 You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1490 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1491 the behavior you want.
1492
1493 Only relevant on platforms, which provide virtual keyboards.
1494
1495 \code
1496 import QtQuick 1.0
1497 TextEdit {
1498 id: textEdit
1499 text: "Hello world!"
1500 activeFocusOnPress: false
1501 MouseArea {
1502 anchors.fill: parent
1503 onClicked: {
1504 if (!textEdit.activeFocus) {
1505 textEdit.forceActiveFocus();
1506 textEdit.openSoftwareInputPanel();
1507 } else {
1508 textEdit.focus = false;
1509 }
1510 }
1511 onPressAndHold: textEdit.closeSoftwareInputPanel();
1512 }
1513 }
1514 \endcode
1515*/
1516void QDeclarativeTextEdit::closeSoftwareInputPanel()
1517{
1518 QEvent event(QEvent::CloseSoftwareInputPanel);
1519 if (qApp) {
1520 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) {
1521 if (view->scene() && view->scene() == scene()) {
1522 QApplication::sendEvent(view, &event);
1523 }
1524 }
1525 }
1526}
1527
1528void QDeclarativeTextEdit::focusInEvent(QFocusEvent *event)
1529{
1530 Q_D(const QDeclarativeTextEdit);
1531 if (d->showInputPanelOnFocus) {
1532 if (d->focusOnPress && !isReadOnly()) {
1533 openSoftwareInputPanel();
1534 }
1535 }
1536 QDeclarativePaintedItem::focusInEvent(event);
1537}
1538
1539QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.