diff -r 5dc02b23752f -r 3e2da88830cd src/declarative/graphicsitems/qdeclarativetextedit.cpp --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp Tue Jul 06 15:10:48 2010 +0300 +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp Wed Aug 18 10:37:55 2010 +0300 @@ -61,26 +61,45 @@ /*! \qmlclass TextEdit QDeclarativeTextEdit - \since 4.7 - \brief The TextEdit item allows you to add editable formatted text to a scene. + \since 4.7 + \brief The TextEdit item displays multiple lines of editable formatted text. + \inherits Item + + The TextEdit item displays a block of editable, formatted text. It can display both plain and rich text. For example: \qml TextEdit { - id: edit + width: 240 text: "Hello World!" - focus: true font.family: "Helvetica" font.pointSize: 20 color: "blue" - width: 240 + focus: true } \endqml \image declarative-textedit.gif - \sa Text + Setting \l {Item::focus}{focus} to \c true enables the TextEdit item to receive keyboard focus. + + Note that the TextEdit does not implement scrolling, following the cursor, or other behaviors specific + to a look-and-feel. For example, to add flickable scrolling that follows the cursor: + + \snippet snippets/declarative/texteditor.qml 0 + + A particular look-and-feel might use smooth scrolling (eg. using SmoothedFollow), might have a visible + scrollbar, or a scrollbar that fades in to show location, etc. + + Clipboard support is provided by the cut(), copy(), and paste() functions, and the selection can + be handled in a traditional "mouse" mechanism by setting selectByMouse, or handled completely + from QML by manipulating selectionStart and selectionEnd, or using selectAll() or selectWord(). + + You can translate between cursor positions (characters from the start of the document) and pixel + points using positionAt() and positionToRectangle(). + + \sa Text, TextInput, {declarative/text/textselection}{Text Selection example} */ /*! @@ -94,7 +113,7 @@ \image declarative-textedit.png - A QDeclarativeTextEdit object can be instantiated in Qml using the tag \c <TextEdit>. + A QDeclarativeTextEdit object can be instantiated in QML using the tag \c <TextEdit>. */ /*! @@ -111,9 +130,11 @@ { Q_D(const QDeclarativeTextEdit); +#ifndef QT_NO_TEXTHTMLPARSER if (d->richText) return d->document->toHtml(); else +#endif return d->document->toPlainText(); } @@ -165,12 +186,6 @@ */ /*! - \qmlproperty bool TextEdit::font.outline - - Sets whether the font has an outline style. -*/ - -/*! \qmlproperty bool TextEdit::font.strikeout Sets whether the font has a strikeout style. @@ -187,8 +202,9 @@ Sets the font size in pixels. - Using this function makes the font device dependent. - Use \c pointSize to set the size of the font in a device independent manner. + Using this function makes the font device dependent. Use + \l{TextEdit::font.pointSize} to set the size of the font in a + device independent manner. */ /*! @@ -197,8 +213,7 @@ Sets the letter spacing for the font. Letter spacing changes the default spacing between individual letters in the font. - A value of 100 will keep the spacing unchanged; a value of 200 will enlarge the spacing after a character by - the width of the character itself. + A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing. */ /*! @@ -241,10 +256,13 @@ Q_D(QDeclarativeTextEdit); if (QDeclarativeTextEdit::text() == text) return; - d->text = text; d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text)); if (d->richText) { +#ifndef QT_NO_TEXTHTMLPARSER d->control->setHtml(text); +#else + d->control->setPlainText(text); +#endif } else { d->control->setPlainText(text); } @@ -309,7 +327,11 @@ d->control->setPlainText(d->text); updateSize(); } else if (!wasRich && d->richText) { +#ifndef QT_NO_TEXTHTMLPARSER d->control->setHtml(d->text); +#else + d->control->setPlainText(d->text); +#endif updateSize(); } d->format = format; @@ -427,12 +449,22 @@ \qmlproperty enumeration TextEdit::horizontalAlignment \qmlproperty enumeration TextEdit::verticalAlignment - Sets the horizontal and vertical alignment of the text within the TextEdit items + Sets the horizontal and vertical alignment of the text within the TextEdit item's width and height. By default, the text is top-left aligned. - The valid values for \c horizontalAlignment are \c TextEdit.AlignLeft, \c TextEdit.AlignRight and - \c TextEdit.AlignHCenter. The valid values for \c verticalAlignment are \c TextEdit.AlignTop, \c TextEdit.AlignBottom - and \c TextEdit.AlignVCenter. + Valid values for \c horizontalAlignment are: + \list + \o TextEdit.AlignLeft (default) + \o TextEdit.AlignRight + \o TextEdit.AlignHCenter + \endlist + + Valid values for \c verticalAlignment are: + \list + \o TextEdit.AlignTop (default) + \o TextEdit.AlignBottom + \c TextEdit.AlignVCenter + \endlist */ QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const { @@ -475,14 +507,13 @@ The text will only wrap if an explicit width has been set. \list - \o TextEdit.NoWrap - no wrapping will be performed. - \o TextEdit.WordWrap - wrapping is done on word boundaries. - \o TextEdit.WrapAnywhere - Text can be wrapped at any point on a line, even if it occurs in the middle of a word. - \o TextEdit.WrapAtWordBoundaryOrAnywhere - 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. + \o TextEdit.NoWrap - no wrapping will be performed. If the text contains insufficient newlines, then implicitWidth will exceed a set width. + \o TextEdit.WordWrap - wrapping is done on word boundaries only. If a word is too long, implicitWidth will exceed a set width. + \o TextEdit.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word. + \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. \endlist - The default is TextEdit.NoWrap. + The default is TextEdit.NoWrap. If you set a width, consider using TextEdit.Wrap. */ QDeclarativeTextEdit::WrapMode QDeclarativeTextEdit::wrapMode() const { @@ -502,10 +533,97 @@ } /*! + \qmlproperty real TextEdit::paintedWidth + + Returns the width of the text, including the width past the width + which is covered due to insufficient wrapping if \l wrapMode is set. +*/ +qreal QDeclarativeTextEdit::paintedWidth() const +{ + return implicitWidth(); +} + +/*! + \qmlproperty real TextEdit::paintedHeight + + Returns the height of the text, including the height past the height + that is covered if the text does not fit within the set height. +*/ +qreal QDeclarativeTextEdit::paintedHeight() const +{ + return implicitHeight(); +} + +/*! + \qmlmethod rectangle TextEdit::positionToRectangle(position) + + Returns the rectangle at the given \a position in the text. The x, y, + and height properties correspond to the cursor that would describe + that position. +*/ +QRectF QDeclarativeTextEdit::positionToRectangle(int pos) const +{ + Q_D(const QDeclarativeTextEdit); + QTextCursor c(d->document); + c.setPosition(pos); + return d->control->cursorRect(c); + +} + +/*! + \qmlmethod int TextEdit::positionAt(x,y) + + Returns the text position closest to pixel position (\a x, \a y). + + Position 0 is before the first character, position 1 is after the first character + but before the second, and so on until position \l {text}.length, which is after all characters. +*/ +int QDeclarativeTextEdit::positionAt(int x, int y) const +{ + Q_D(const QDeclarativeTextEdit); + int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit); + return r; +} + +/*! + \qmlmethod int TextEdit::moveCursorSelection(int pos) + + Moves the cursor to \a position and updates the selection accordingly. + (To only move the cursor, set the \l cursorPosition property.) + + When this method is called it additionally sets either the + selectionStart or the selectionEnd (whichever was at the previous cursor position) + to the specified position. This allows you to easily extend and contract the selected + text range. + + For example, take this sequence of calls: + + \code + cursorPosition = 5 + moveCursorSelection(9) + moveCursorSelection(7) + \endcode + + This moves the cursor to position 5, extend the selection end from 5 to 9 + and then retract the selection end from 9 to 7, leaving the text from position 5 to 7 + selected (the 6th and 7th characters). +*/ +void QDeclarativeTextEdit::moveCursorSelection(int pos) +{ + //Note that this is the same as setCursorPosition but with the KeepAnchor flag set + Q_D(QDeclarativeTextEdit); + QTextCursor cursor = d->control->textCursor(); + if (cursor.position() == pos) + return; + cursor.setPosition(pos, QTextCursor::KeepAnchor); + d->control->setTextCursor(cursor); +} + +/*! \qmlproperty bool TextEdit::cursorVisible If true the text edit shows a cursor. - This property is set and unset when the text edit gets focus, but it can also + This property is set and unset when the text edit gets active focus, but it can also be set directly (useful, for example, if a KeyProxy might forward keys to it). */ bool QDeclarativeTextEdit::isCursorVisible() const @@ -574,7 +692,7 @@ disconnect(d->control, SIGNAL(cursorPositionChanged()), this, SLOT(moveCursorDelegate())); d->control->setCursorWidth(-1); - dirtyCache(cursorRect()); + dirtyCache(cursorRectangle()); delete d->cursor; d->cursor = 0; } @@ -601,7 +719,7 @@ connect(d->control, SIGNAL(cursorPositionChanged()), this, SLOT(moveCursorDelegate())); d->control->setCursorWidth(0); - dirtyCache(cursorRect()); + dirtyCache(cursorRectangle()); QDeclarative_setParent_noEvent(d->cursor, this); d->cursor->setParentItem(this); d->cursor->setHeight(QFontMetrics(d->font).height()); @@ -615,12 +733,9 @@ \qmlproperty int TextEdit::selectionStart The cursor position before the first character in the current selection. - Setting this and selectionEnd allows you to specify a selection in the - text edit. - Note that if selectionStart == selectionEnd then there is no current - selection. If you attempt to set selectionStart to a value outside of - the current text, selectionStart will not be changed. + This property is read-only. To change the selection, use select(start,end), + selectAll(), or selectWord(). \sa selectionEnd, cursorPosition, selectedText */ @@ -630,25 +745,13 @@ return d->control->textCursor().selectionStart(); } -void QDeclarativeTextEdit::setSelectionStart(int s) -{ - Q_D(QDeclarativeTextEdit); - if(d->lastSelectionStart == s || s < 0 || s > text().length()) - return; - d->lastSelectionStart = s; - d->updateSelection();// Will emit the relevant signals -} - /*! \qmlproperty int TextEdit::selectionEnd The cursor position after the last character in the current selection. - Setting this and selectionStart allows you to specify a selection in the - text edit. - Note that if selectionStart == selectionEnd then there is no current - selection. If you attempt to set selectionEnd to a value outside of - the current text, selectionEnd will not be changed. + This property is read-only. To change the selection, use select(start,end), + selectAll(), or selectWord(). \sa selectionStart, cursorPosition, selectedText */ @@ -658,15 +761,6 @@ return d->control->textCursor().selectionEnd(); } -void QDeclarativeTextEdit::setSelectionEnd(int s) -{ - Q_D(QDeclarativeTextEdit); - if(d->lastSelectionEnd == s || s < 0 || s > text().length()) - return; - d->lastSelectionEnd = s; - d->updateSelection();// Will emit the relevant signals -} - /*! \qmlproperty string TextEdit::selectedText @@ -688,9 +782,9 @@ } /*! - \qmlproperty bool TextEdit::focusOnPress + \qmlproperty bool TextEdit::activeFocusOnPress - Whether the TextEdit should gain focus on a mouse press. By default this is + Whether the TextEdit should gain active focus on a mouse press. By default this is set to true. */ bool QDeclarativeTextEdit::focusOnPress() const @@ -705,13 +799,13 @@ if (d->focusOnPress == on) return; d->focusOnPress = on; - emit focusOnPressChanged(d->focusOnPress); + emit activeFocusOnPressChanged(d->focusOnPress); } /*! \qmlproperty bool TextEdit::persistentSelection - Whether the TextEdit should keep the selection visible when it loses focus to another + Whether the TextEdit should keep the selection visible when it loses active focus to another item in the scene. By default this is set to true; */ bool QDeclarativeTextEdit::persistentSelection() const @@ -773,7 +867,7 @@ } /*! - \qmlproperty string TextEdit::selectByMouse + \qmlproperty bool TextEdit::selectByMouse Defaults to false. @@ -854,10 +948,12 @@ } /*! - Returns the rectangle where the text cursor is rendered - within the text edit. + \qmlproperty rectangle TextEdit::cursorRectangle + + The rectangle where the text cursor is rendered + within the text edit. Read-only. */ -QRect QDeclarativeTextEdit::cursorRect() const +QRect QDeclarativeTextEdit::cursorRectangle() const { Q_D(const QDeclarativeTextEdit); return d->control->cursorRect().toRect().translated(0,-d->yoff); @@ -914,6 +1010,8 @@ } /*! + \qmlmethod void TextEdit::selectAll() + Causes all text to be selected. */ void QDeclarativeTextEdit::selectAll() @@ -923,24 +1021,103 @@ } /*! + \qmlmethod void TextEdit::selectWord() + + Causes the word closest to the current cursor position to be selected. +*/ +void QDeclarativeTextEdit::selectWord() +{ + Q_D(QDeclarativeTextEdit); + QTextCursor c = d->control->textCursor(); + c.select(QTextCursor::WordUnderCursor); + d->control->setTextCursor(c); +} + +/*! + \qmlmethod void TextEdit::select(start,end) + + Causes the text from \a start to \a end to be selected. + + If either start or end is out of range, the selection is not changed. + + After calling this, selectionStart will become the lesser + and selectionEnd will become the greater (regardless of the order passed + to this method). + + \sa selectionStart, selectionEnd +*/ +void QDeclarativeTextEdit::select(int start, int end) +{ + Q_D(QDeclarativeTextEdit); + if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length()) + return; + QTextCursor cursor = d->control->textCursor(); + cursor.beginEditBlock(); + cursor.setPosition(start, QTextCursor::MoveAnchor); + cursor.setPosition(end, QTextCursor::KeepAnchor); + cursor.endEditBlock(); + d->control->setTextCursor(cursor); + + // QTBUG-11100 + updateSelectionMarkers(); +} + +#ifndef QT_NO_CLIPBOARD +/*! + \qmlmethod TextEdit::cut() + + Moves the currently selected text to the system clipboard. +*/ +void QDeclarativeTextEdit::cut() +{ + Q_D(QDeclarativeTextEdit); + d->control->cut(); +} + +/*! + \qmlmethod TextEdit::copy() + + Copies the currently selected text to the system clipboard. +*/ +void QDeclarativeTextEdit::copy() +{ + Q_D(QDeclarativeTextEdit); + d->control->copy(); +} + +/*! + \qmlmethod TextEdit::paste() + + Replaces the currently selected text by the contents of the system clipboard. +*/ +void QDeclarativeTextEdit::paste() +{ + Q_D(QDeclarativeTextEdit); + d->control->paste(); +} +#endif // QT_NO_CLIPBOARD + +/*! \overload Handles the given mouse \a event. */ void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeTextEdit); - bool hadFocus = hasFocus(); if (d->focusOnPress){ - QGraphicsItem *p = parentItem();//###Is there a better way to find my focus scope? - while(p) { - if (p->flags() & QGraphicsItem::ItemIsFocusScope) - p->setFocus(); - p = p->parentItem(); + bool hadActiveFocus = hasActiveFocus(); + forceActiveFocus(); + if (d->showInputPanelOnFocus) { + if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) { + // re-open input panel on press if already focused + openSoftwareInputPanel(); + } + } else { // show input panel on click + if (hasActiveFocus() && !hadActiveFocus) { + d->clickCausedFocus = true; + } } - setFocus(true); } - if (!hadFocus && hasFocus()) - d->clickCausedFocus = true; if (event->type() != QEvent::GraphicsSceneMouseDoubleClick || d->selectByMouse) d->control->processEvent(event, QPointF(0, -d->yoff)); if (!event->isAccepted()) @@ -954,12 +1131,18 @@ void QDeclarativeTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { Q_D(QDeclarativeTextEdit); - QWidget *widget = event->widget(); - if (widget && (d->control->textInteractionFlags() & Qt::TextEditable) && boundingRect().contains(event->pos())) - qt_widget_private(widget)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus); + d->control->processEvent(event, QPointF(0, -d->yoff)); + if (!d->showInputPanelOnFocus) { // input panel on click + if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) { + if (QGraphicsView * view = qobject_cast(qApp->focusWidget())) { + if (view->scene() && view->scene() == scene()) { + qt_widget_private(view)->handleSoftwareInputPanel(event->button(), d->clickCausedFocus); + } + } + } + } d->clickCausedFocus = false; - d->control->processEvent(event, QPointF(0, -d->yoff)); if (!event->isAccepted()) QDeclarativePaintedItem::mouseReleaseEvent(event); } @@ -1036,9 +1219,19 @@ void QDeclarativeTextEdit::updateImgCache(const QRectF &rf) { Q_D(const QDeclarativeTextEdit); - QRect r = rf.toRect(); - if (r != QRect(0,0,INT_MAX,INT_MAX)) // Don't translate "everything" - r = r.translated(0,d->yoff); + QRect r; + if (!rf.isValid()) { + r = QRect(0,0,INT_MAX,INT_MAX); + } else { + r = rf.toRect(); + if (r.height() > INT_MAX/2) { + // Take care of overflow when translating "everything" + r.setTop(r.y() + d->yoff); + r.setBottom(INT_MAX/2); + } else { + r = r.translated(0,d->yoff); + } + } dirtyCache(r); emit update(); } @@ -1069,6 +1262,15 @@ control = new QTextControl(q); control->setIgnoreUnusedNavigationEvents(true); + // QTextControl follows the default text color + // defined by the platform, declarative text + // should be black by default + QPalette pal = control->palette(); + if (pal.color(QPalette::Text) != color) { + pal.setColor(QPalette::Text, color); + control->setPalette(pal); + } + QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF))); QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); @@ -1076,6 +1278,7 @@ QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); + QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorRectangleChanged())); document = control->document(); document->setDefaultFont(font); @@ -1087,8 +1290,11 @@ void QDeclarativeTextEdit::q_textChanged() { + Q_D(QDeclarativeTextEdit); + d->text = text(); updateSize(); - emit textChanged(text()); + updateMicroFocus(); + emit textChanged(d->text); } void QDeclarativeTextEdit::moveCursorDelegate() @@ -1107,7 +1313,6 @@ QTextCursor cursor = control->textCursor(); bool startChange = (lastSelectionStart != cursor.selectionStart()); bool endChange = (lastSelectionEnd != cursor.selectionEnd()); - //### Is it worth calculating a more minimal set of movements? cursor.beginEditBlock(); cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor); cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); @@ -1117,8 +1322,6 @@ q->selectionStartChanged(); if(endChange) q->selectionEndChanged(); - startChange = (lastSelectionStart != control->textCursor().selectionStart()); - endChange = (lastSelectionEnd != control->textCursor().selectionEnd()); } void QDeclarativeTextEdit::updateSelectionMarkers() @@ -1132,8 +1335,26 @@ d->lastSelectionEnd = d->control->textCursor().selectionEnd(); emit selectionEndChanged(); } + updateMicroFocus(); } +QRectF QDeclarativeTextEdit::boundingRect() const +{ + Q_D(const QDeclarativeTextEdit); + QRectF r = QDeclarativePaintedItem::boundingRect(); + int cursorWidth = 1; + if(d->cursor) + cursorWidth = d->cursor->width(); + if(!d->document->isEmpty()) + cursorWidth += 3;// ### Need a better way of accounting for space between char and cursor + + // Could include font max left/right bearings to either side of rectangle. + + r.setRight(r.right() + cursorWidth); + return r.translated(0,d->yoff); +} + + //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't // need to do all the calculations each time void QDeclarativeTextEdit::updateSize() @@ -1144,35 +1365,39 @@ int dy = height(); // ### assumes that if the width is set, the text will fill to edges // ### (unless wrap is false, then clipping will occur) - if (widthValid()) + if (widthValid() && d->document->textWidth() != width()) d->document->setTextWidth(width()); dy -= (int)d->document->size().height(); + int nyoff; if (heightValid()) { if (d->vAlign == AlignBottom) - d->yoff = dy; + nyoff = dy; else if (d->vAlign == AlignVCenter) - d->yoff = dy/2; + nyoff = dy/2; + else + nyoff = 0; } else { - d->yoff = 0; + nyoff = 0; + } + if (nyoff != d->yoff) { + prepareGeometryChange(); + d->yoff = nyoff; } setBaselineOffset(fm.ascent() + d->yoff + d->textMargin); //### need to comfirm cost of always setting these int newWidth = qCeil(d->document->idealWidth()); - if (!widthValid()) + if (!widthValid() && d->document->textWidth() != newWidth) d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug) - int cursorWidth = 1; - if(d->cursor) - cursorWidth = d->cursor->width(); - newWidth += cursorWidth; - if(!d->document->isEmpty()) - newWidth += 3;// ### Need a better way of accounting for space between char and cursor // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed. setImplicitWidth(newWidth); - setImplicitHeight(d->text.isEmpty() ? fm.height() : (int)d->document->size().height()); + qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height(); + setImplicitHeight(newHeight); - setContentsSize(QSize(width(), height())); + setContentsSize(QSize(newWidth, newHeight)); + + emit paintedSizeChanged(); } else { d->dirty = true; } @@ -1193,4 +1418,118 @@ document->setDefaultTextOption(opt); } + +/*! + \qmlmethod void TextEdit::openSoftwareInputPanel() + + Opens software input panels like virtual keyboards for typing, useful for + customizing when you want the input keyboard to be shown and hidden in + your application. + + By default the opening of input panels follows the platform style. On Symbian^1 and + Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms + the panels are automatically opened when TextEdit element gains active focus. Input panels are + always closed if no editor has active focus. + + You can disable the automatic behavior by setting the property \c activeFocusOnPress to false + and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement + the behavior you want. + + Only relevant on platforms, which provide virtual keyboards. + + \code + import Qt 4.7 + TextEdit { + id: textEdit + text: "Hello world!" + activeFocusOnPress: false + MouseArea { + anchors.fill: parent + onClicked: { + if (!textEdit.activeFocus) { + textEdit.forceActiveFocus(); + textEdit.openSoftwareInputPanel(); + } else { + textEdit.focus = false; + } + } + onPressAndHold: textEdit.closeSoftwareInputPanel(); + } + } + \endcode +*/ +void QDeclarativeTextEdit::openSoftwareInputPanel() +{ + QEvent event(QEvent::RequestSoftwareInputPanel); + if (qApp) { + if (QGraphicsView * view = qobject_cast(qApp->focusWidget())) { + if (view->scene() && view->scene() == scene()) { + QApplication::sendEvent(view, &event); + } + } + } +} + +/*! + \qmlmethod void TextEdit::closeSoftwareInputPanel() + + Closes a software input panel like a virtual keyboard shown on the screen, useful + for customizing when you want the input keyboard to be shown and hidden in + your application. + + By default the opening of input panels follows the platform style. On Symbian^1 and + Symbian^3 -based devices the panels are opened by clicking TextEdit. On other platforms + the panels are automatically opened when TextEdit element gains active focus. Input panels are + always closed if no editor has active focus. + + You can disable the automatic behavior by setting the property \c activeFocusOnPress to false + and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement + the behavior you want. + + Only relevant on platforms, which provide virtual keyboards. + + \code + import Qt 4.7 + TextEdit { + id: textEdit + text: "Hello world!" + activeFocusOnPress: false + MouseArea { + anchors.fill: parent + onClicked: { + if (!textEdit.activeFocus) { + textEdit.forceActiveFocus(); + textEdit.openSoftwareInputPanel(); + } else { + textEdit.focus = false; + } + } + onPressAndHold: textEdit.closeSoftwareInputPanel(); + } + } + \endcode +*/ +void QDeclarativeTextEdit::closeSoftwareInputPanel() +{ + QEvent event(QEvent::CloseSoftwareInputPanel); + if (qApp) { + if (QGraphicsView * view = qobject_cast(qApp->focusWidget())) { + if (view->scene() && view->scene() == scene()) { + QApplication::sendEvent(view, &event); + } + } + } +} + +void QDeclarativeTextEdit::focusInEvent(QFocusEvent *event) +{ + Q_D(const QDeclarativeTextEdit); + if (d->showInputPanelOnFocus) { + if (d->focusOnPress && !isReadOnly()) { + openSoftwareInputPanel(); + } + } + QDeclarativePaintedItem::focusInEvent(event); +} + QT_END_NAMESPACE