44 |
44 |
45 #include <private/qdeclarativeglobal_p.h> |
45 #include <private/qdeclarativeglobal_p.h> |
46 #include <qdeclarativeinfo.h> |
46 #include <qdeclarativeinfo.h> |
47 |
47 |
48 #include <QValidator> |
48 #include <QValidator> |
|
49 #include <QTextCursor> |
49 #include <QApplication> |
50 #include <QApplication> |
50 #include <QFontMetrics> |
51 #include <QFontMetrics> |
51 #include <QPainter> |
52 #include <QPainter> |
52 |
53 |
53 QT_BEGIN_NAMESPACE |
54 QT_BEGIN_NAMESPACE |
54 |
55 |
55 /*! |
56 /*! |
56 \qmlclass TextInput QDeclarativeTextInput |
57 \qmlclass TextInput QDeclarativeTextInput |
57 \since 4.7 |
58 \since 4.7 |
58 \brief The TextInput item allows you to add an editable line of text to a scene. |
59 \brief The TextInput item displays an editable line of text. |
59 |
60 \inherits Item |
60 TextInput can only display a single line of text, and can only display |
61 |
61 plain text. However it can provide addition input constraints on the text. |
62 The TextInput element displays a single line of editable plain text. |
62 |
63 |
63 Input constraints include setting a QValidator, an input mask, or a |
64 TextInput is used to accept a line of text input. Input constraints |
64 maximum input length. |
65 can be placed on a TextInput item (for example, through a \l validator or \l inputMask), |
|
66 and setting \l echoMode to an appropriate value enables TextInput to be used for |
|
67 a password input field. |
65 |
68 |
66 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled. |
69 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled. |
67 If you want such bindings (on any platform), you will need to construct them in QML. |
70 If you want such bindings (on any platform), you will need to construct them in QML. |
|
71 |
|
72 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example} |
68 */ |
73 */ |
69 QDeclarativeTextInput::QDeclarativeTextInput(QDeclarativeItem* parent) |
74 QDeclarativeTextInput::QDeclarativeTextInput(QDeclarativeItem* parent) |
70 : QDeclarativePaintedItem(*(new QDeclarativeTextInputPrivate), parent) |
75 : QDeclarativePaintedItem(*(new QDeclarativeTextInputPrivate), parent) |
71 { |
76 { |
72 Q_D(QDeclarativeTextInput); |
77 Q_D(QDeclarativeTextInput); |
366 |
373 |
367 /*! |
374 /*! |
368 \qmlproperty bool TextInput::cursorVisible |
375 \qmlproperty bool TextInput::cursorVisible |
369 Set to true when the TextInput shows a cursor. |
376 Set to true when the TextInput shows a cursor. |
370 |
377 |
371 This property is set and unset when the TextInput gets focus, so that other |
378 This property is set and unset when the TextInput gets active focus, so that other |
372 properties can be bound to whether the cursor is currently showing. As it |
379 properties can be bound to whether the cursor is currently showing. As it |
373 gets set and unset automatically, when you set the value yourself you must |
380 gets set and unset automatically, when you set the value yourself you must |
374 keep in mind that your value may be overwritten. |
381 keep in mind that your value may be overwritten. |
375 |
382 |
376 It can be set directly in script, for example if a KeyProxy might |
383 It can be set directly in script, for example if a KeyProxy might |
377 forward keys to it and you desire it to look active when this happens |
384 forward keys to it and you desire it to look active when this happens |
378 (but without actually giving it the focus). |
385 (but without actually giving it active focus). |
379 |
386 |
380 It should not be set directly on the element, like in the below QML, |
387 It should not be set directly on the element, like in the below QML, |
381 as the specified value will be overridden an lost on focus changes. |
388 as the specified value will be overridden an lost on focus changes. |
382 |
389 |
383 \code |
390 \code |
818 } |
825 } |
819 |
826 |
820 QDeclarative_setParent_noEvent(d->cursorItem, this); |
827 QDeclarative_setParent_noEvent(d->cursorItem, this); |
821 d->cursorItem->setParentItem(this); |
828 d->cursorItem->setParentItem(this); |
822 d->cursorItem->setX(d->control->cursorToX()); |
829 d->cursorItem->setX(d->control->cursorToX()); |
823 d->cursorItem->setHeight(d->control->height()); |
830 d->cursorItem->setHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text. |
824 } |
831 } |
825 |
832 |
826 void QDeclarativeTextInput::moveCursor() |
833 void QDeclarativeTextInput::moveCursor() |
827 { |
834 { |
828 Q_D(QDeclarativeTextInput); |
835 Q_D(QDeclarativeTextInput); |
829 if(!d->cursorItem) |
836 if(!d->cursorItem) |
830 return; |
837 return; |
|
838 d->updateHorizontalScroll(); |
831 d->cursorItem->setX(d->control->cursorToX() - d->hscroll); |
839 d->cursorItem->setX(d->control->cursorToX() - d->hscroll); |
832 } |
840 } |
833 |
841 |
834 /*! |
842 /*! |
835 \qmlmethod int TextInput::xToPosition(int x) |
843 \qmlmethod rect TextInput::positionToRectangle(int pos) |
|
844 |
|
845 This function takes a character position and returns the rectangle that the |
|
846 cursor would occupy, if it was placed at that character position. |
|
847 |
|
848 This is similar to setting the cursorPosition, and then querying the cursor |
|
849 rectangle, but the cursorPosition is not changed. |
|
850 */ |
|
851 QRectF QDeclarativeTextInput::positionToRectangle(int pos) const |
|
852 { |
|
853 Q_D(const QDeclarativeTextInput); |
|
854 return QRectF(d->control->cursorToX(pos)-d->hscroll, |
|
855 0.0, |
|
856 d->control->cursorWidth(), |
|
857 cursorRectangle().height()); |
|
858 } |
|
859 |
|
860 /*! |
|
861 \qmlmethod int TextInput::positionAt(int x) |
836 |
862 |
837 This function returns the character position at |
863 This function returns the character position at |
838 x pixels from the left of the textInput. Position 0 is before the |
864 x pixels from the left of the textInput. Position 0 is before the |
839 first character, position 1 is after the first character but before the second, |
865 first character, position 1 is after the first character but before the second, |
840 and so on until position text.length, which is after all characters. |
866 and so on until position text.length, which is after all characters. |
841 |
867 |
842 This means that for all x values before the first character this function returns 0, |
868 This means that for all x values before the first character this function returns 0, |
843 and for all x values after the last character this function returns text.length. |
869 and for all x values after the last character this function returns text.length. |
844 */ |
870 */ |
845 int QDeclarativeTextInput::xToPosition(int x) |
871 int QDeclarativeTextInput::positionAt(int x) const |
846 { |
872 { |
847 Q_D(const QDeclarativeTextInput); |
873 Q_D(const QDeclarativeTextInput); |
848 return d->control->xToPos(x - d->hscroll); |
874 return d->control->xToPos(x + d->hscroll); |
849 } |
875 } |
850 |
876 |
851 void QDeclarativeTextInputPrivate::focusChanged(bool hasFocus) |
877 void QDeclarativeTextInputPrivate::focusChanged(bool hasFocus) |
852 { |
878 { |
853 Q_Q(QDeclarativeTextInput); |
879 Q_Q(QDeclarativeTextInput); |
880 } |
906 } |
881 if (!ev->isAccepted()) |
907 if (!ev->isAccepted()) |
882 QDeclarativePaintedItem::keyPressEvent(ev); |
908 QDeclarativePaintedItem::keyPressEvent(ev); |
883 } |
909 } |
884 |
910 |
|
911 void QDeclarativeTextInput::inputMethodEvent(QInputMethodEvent *ev) |
|
912 { |
|
913 Q_D(QDeclarativeTextInput); |
|
914 ev->ignore(); |
|
915 inputMethodPreHandler(ev); |
|
916 if (ev->isAccepted()) |
|
917 return; |
|
918 if (d->control->isReadOnly()) { |
|
919 ev->ignore(); |
|
920 } else { |
|
921 d->control->processInputMethodEvent(ev); |
|
922 updateSize(); |
|
923 } |
|
924 if (!ev->isAccepted()) |
|
925 QDeclarativePaintedItem::inputMethodEvent(ev); |
|
926 } |
|
927 |
|
928 /*! |
|
929 \overload |
|
930 Handles the given mouse \a event. |
|
931 */ |
|
932 void QDeclarativeTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) |
|
933 { |
|
934 Q_D(QDeclarativeTextInput); |
|
935 if (d->selectByMouse) { |
|
936 int cursor = d->xToPos(event->pos().x()); |
|
937 d->control->selectWordAtPos(cursor); |
|
938 event->setAccepted(true); |
|
939 } else { |
|
940 QDeclarativePaintedItem::mouseDoubleClickEvent(event); |
|
941 } |
|
942 } |
|
943 |
885 void QDeclarativeTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event) |
944 void QDeclarativeTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event) |
886 { |
945 { |
887 Q_D(QDeclarativeTextInput); |
946 Q_D(QDeclarativeTextInput); |
888 bool hadFocus = hasFocus(); |
|
889 if(d->focusOnPress){ |
947 if(d->focusOnPress){ |
890 QGraphicsItem *p = parentItem();//###Is there a better way to find my focus scope? |
948 bool hadActiveFocus = hasActiveFocus(); |
891 while(p) { |
949 forceActiveFocus(); |
892 if (p->flags() & QGraphicsItem::ItemIsFocusScope) |
950 if (d->showInputPanelOnFocus) { |
893 p->setFocus(); |
951 if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) { |
894 p = p->parentItem(); |
952 // re-open input panel on press if already focused |
|
953 openSoftwareInputPanel(); |
|
954 } |
|
955 } else { // show input panel on click |
|
956 if (hasActiveFocus() && !hadActiveFocus) { |
|
957 d->clickCausedFocus = true; |
|
958 } |
895 } |
959 } |
896 setFocus(true); |
960 } |
897 } |
|
898 if (!hadFocus && hasFocus()) |
|
899 d->clickCausedFocus = true; |
|
900 |
|
901 bool mark = event->modifiers() & Qt::ShiftModifier; |
961 bool mark = event->modifiers() & Qt::ShiftModifier; |
902 int cursor = d->xToPos(event->pos().x()); |
962 int cursor = d->xToPos(event->pos().x()); |
903 d->control->moveCursor(cursor, mark); |
963 d->control->moveCursor(cursor, mark); |
904 event->setAccepted(true); |
964 event->setAccepted(true); |
905 } |
965 } |
936 //Anything we don't deal with ourselves, pass to the control |
1003 //Anything we don't deal with ourselves, pass to the control |
937 bool handled = false; |
1004 bool handled = false; |
938 switch(ev->type()){ |
1005 switch(ev->type()){ |
939 case QEvent::KeyPress: |
1006 case QEvent::KeyPress: |
940 case QEvent::KeyRelease://###Should the control be doing anything with release? |
1007 case QEvent::KeyRelease://###Should the control be doing anything with release? |
|
1008 case QEvent::InputMethod: |
941 case QEvent::GraphicsSceneMousePress: |
1009 case QEvent::GraphicsSceneMousePress: |
942 case QEvent::GraphicsSceneMouseMove: |
1010 case QEvent::GraphicsSceneMouseMove: |
943 case QEvent::GraphicsSceneMouseRelease: |
1011 case QEvent::GraphicsSceneMouseRelease: |
|
1012 case QEvent::GraphicsSceneMouseDoubleClick: |
944 break; |
1013 break; |
945 default: |
1014 default: |
946 if (ev->type() == QEvent::GraphicsSceneMouseDoubleClick && !d->selectByMouse) |
|
947 break; |
|
948 handled = d->control->processEvent(ev); |
1015 handled = d->control->processEvent(ev); |
949 if (ev->type() == QEvent::InputMethod) |
|
950 updateSize(); |
|
951 } |
1016 } |
952 if(!handled) |
1017 if(!handled) |
953 handled = QDeclarativePaintedItem::event(ev); |
1018 handled = QDeclarativePaintedItem::event(ev); |
954 return handled; |
1019 return handled; |
955 } |
1020 } |
956 |
1021 |
957 void QDeclarativeTextInput::geometryChanged(const QRectF &newGeometry, |
1022 void QDeclarativeTextInput::geometryChanged(const QRectF &newGeometry, |
958 const QRectF &oldGeometry) |
1023 const QRectF &oldGeometry) |
959 { |
1024 { |
960 if (newGeometry.width() != oldGeometry.width()) |
1025 Q_D(QDeclarativeTextInput); |
|
1026 if (newGeometry.width() != oldGeometry.width()) { |
961 updateSize(); |
1027 updateSize(); |
|
1028 d->updateHorizontalScroll(); |
|
1029 } |
962 QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry); |
1030 QDeclarativePaintedItem::geometryChanged(newGeometry, oldGeometry); |
|
1031 } |
|
1032 |
|
1033 int QDeclarativeTextInputPrivate::calculateTextWidth() |
|
1034 { |
|
1035 return qRound(control->naturalTextWidth()); |
|
1036 } |
|
1037 |
|
1038 void QDeclarativeTextInputPrivate::updateHorizontalScroll() |
|
1039 { |
|
1040 Q_Q(QDeclarativeTextInput); |
|
1041 int cix = qRound(control->cursorToX()); |
|
1042 QRect br(q->boundingRect().toRect()); |
|
1043 int widthUsed = calculateTextWidth(); |
|
1044 if (autoScroll) { |
|
1045 if (widthUsed <= br.width()) { |
|
1046 // text fits in br; use hscroll for alignment |
|
1047 switch (hAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) { |
|
1048 case Qt::AlignRight: |
|
1049 hscroll = widthUsed - br.width() - 1; |
|
1050 break; |
|
1051 case Qt::AlignHCenter: |
|
1052 hscroll = (widthUsed - br.width()) / 2; |
|
1053 break; |
|
1054 default: |
|
1055 // Left |
|
1056 hscroll = 0; |
|
1057 break; |
|
1058 } |
|
1059 } else if (cix - hscroll >= br.width()) { |
|
1060 // text doesn't fit, cursor is to the right of br (scroll right) |
|
1061 hscroll = cix - br.width() + 1; |
|
1062 } else if (cix - hscroll < 0 && hscroll < widthUsed) { |
|
1063 // text doesn't fit, cursor is to the left of br (scroll left) |
|
1064 hscroll = cix; |
|
1065 } else if (widthUsed - hscroll < br.width()) { |
|
1066 // text doesn't fit, text document is to the left of br; align |
|
1067 // right |
|
1068 hscroll = widthUsed - br.width() + 1; |
|
1069 } |
|
1070 } else { |
|
1071 if(hAlign == QDeclarativeTextInput::AlignRight){ |
|
1072 hscroll = q->width() - widthUsed; |
|
1073 }else if(hAlign == QDeclarativeTextInput::AlignHCenter){ |
|
1074 hscroll = (q->width() - widthUsed) / 2; |
|
1075 } else { |
|
1076 hscroll = 0; |
|
1077 } |
|
1078 } |
963 } |
1079 } |
964 |
1080 |
965 void QDeclarativeTextInput::drawContents(QPainter *p, const QRect &r) |
1081 void QDeclarativeTextInput::drawContents(QPainter *p, const QRect &r) |
966 { |
1082 { |
967 Q_D(QDeclarativeTextInput); |
1083 Q_D(QDeclarativeTextInput); |
973 flags |= QLineControl::DrawCursor; |
1089 flags |= QLineControl::DrawCursor; |
974 if (d->control->hasSelectedText()) |
1090 if (d->control->hasSelectedText()) |
975 flags |= QLineControl::DrawSelections; |
1091 flags |= QLineControl::DrawSelections; |
976 QPoint offset = QPoint(0,0); |
1092 QPoint offset = QPoint(0,0); |
977 QFontMetrics fm = QFontMetrics(d->font); |
1093 QFontMetrics fm = QFontMetrics(d->font); |
978 int cix = qRound(d->control->cursorToX()); |
|
979 QRect br(boundingRect().toRect()); |
1094 QRect br(boundingRect().toRect()); |
980 //###Is this using bearing appropriately? |
|
981 int minLB = qMax(0, -fm.minLeftBearing()); |
|
982 int minRB = qMax(0, -fm.minRightBearing()); |
|
983 int widthUsed = qRound(d->control->naturalTextWidth()) + 1 + minRB; |
|
984 if (d->autoScroll) { |
1095 if (d->autoScroll) { |
985 if ((minLB + widthUsed) <= br.width()) { |
|
986 // text fits in br; use hscroll for alignment |
|
987 switch (d->hAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) { |
|
988 case Qt::AlignRight: |
|
989 d->hscroll = widthUsed - br.width() + 1; |
|
990 break; |
|
991 case Qt::AlignHCenter: |
|
992 d->hscroll = (widthUsed - br.width()) / 2; |
|
993 break; |
|
994 default: |
|
995 // Left |
|
996 d->hscroll = 0; |
|
997 break; |
|
998 } |
|
999 d->hscroll -= minLB; |
|
1000 } else if (cix - d->hscroll >= br.width()) { |
|
1001 // text doesn't fit, cursor is to the right of br (scroll right) |
|
1002 d->hscroll = cix - br.width() + 1; |
|
1003 } else if (cix - d->hscroll < 0 && d->hscroll < widthUsed) { |
|
1004 // text doesn't fit, cursor is to the left of br (scroll left) |
|
1005 d->hscroll = cix; |
|
1006 } else if (widthUsed - d->hscroll < br.width()) { |
|
1007 // text doesn't fit, text document is to the left of br; align |
|
1008 // right |
|
1009 d->hscroll = widthUsed - br.width() + 1; |
|
1010 } |
|
1011 // the y offset is there to keep the baseline constant in case we have script changes in the text. |
1096 // the y offset is there to keep the baseline constant in case we have script changes in the text. |
1012 offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent()); |
1097 offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent()); |
1013 } else { |
1098 } else { |
1014 if(d->hAlign == AlignRight){ |
|
1015 d->hscroll = width() - widthUsed; |
|
1016 }else if(d->hAlign == AlignHCenter){ |
|
1017 d->hscroll = (width() - widthUsed) / 2; |
|
1018 } |
|
1019 d->hscroll -= minLB; |
|
1020 offset = QPoint(d->hscroll, 0); |
1099 offset = QPoint(d->hscroll, 0); |
1021 } |
1100 } |
1022 |
|
1023 d->control->draw(p, offset, r, flags); |
1101 d->control->draw(p, offset, r, flags); |
1024 |
|
1025 p->restore(); |
1102 p->restore(); |
1026 } |
1103 } |
1027 |
1104 |
1028 /*! |
1105 /*! |
1029 \overload |
1106 \overload |
1055 default: |
1132 default: |
1056 return QVariant(); |
1133 return QVariant(); |
1057 } |
1134 } |
1058 } |
1135 } |
1059 |
1136 |
|
1137 /*! |
|
1138 \qmlmethod void TextInput::selectAll() |
|
1139 |
|
1140 Causes all text to be selected. |
|
1141 */ |
1060 void QDeclarativeTextInput::selectAll() |
1142 void QDeclarativeTextInput::selectAll() |
1061 { |
1143 { |
1062 Q_D(QDeclarativeTextInput); |
1144 Q_D(QDeclarativeTextInput); |
1063 d->control->setSelection(0, d->control->text().length()); |
1145 d->control->setSelection(0, d->control->text().length()); |
1064 } |
1146 } |
1065 |
1147 |
|
1148 #ifndef QT_NO_CLIPBOARD |
|
1149 /*! |
|
1150 \qmlmethod TextInput::cut() |
|
1151 |
|
1152 Moves the currently selected text to the system clipboard. |
|
1153 */ |
|
1154 void QDeclarativeTextInput::cut() |
|
1155 { |
|
1156 Q_D(QDeclarativeTextInput); |
|
1157 d->control->copy(); |
|
1158 d->control->del(); |
|
1159 } |
|
1160 |
|
1161 /*! |
|
1162 \qmlmethod TextInput::copy() |
|
1163 |
|
1164 Copies the currently selected text to the system clipboard. |
|
1165 */ |
|
1166 void QDeclarativeTextInput::copy() |
|
1167 { |
|
1168 Q_D(QDeclarativeTextInput); |
|
1169 d->control->copy(); |
|
1170 } |
|
1171 |
|
1172 /*! |
|
1173 \qmlmethod TextInput::paste() |
|
1174 |
|
1175 Replaces the currently selected text by the contents of the system clipboard. |
|
1176 */ |
|
1177 void QDeclarativeTextInput::paste() |
|
1178 { |
|
1179 Q_D(QDeclarativeTextInput); |
|
1180 d->control->paste(); |
|
1181 } |
|
1182 #endif // QT_NO_CLIPBOARD |
|
1183 |
|
1184 /*! |
|
1185 \qmlmethod void TextInput::selectWord() |
|
1186 |
|
1187 Causes the word closest to the current cursor position to be selected. |
|
1188 */ |
|
1189 void QDeclarativeTextInput::selectWord() |
|
1190 { |
|
1191 Q_D(QDeclarativeTextInput); |
|
1192 d->control->selectWordAtPos(d->control->cursor()); |
|
1193 } |
1066 |
1194 |
1067 /*! |
1195 /*! |
1068 \qmlproperty bool TextInput::smooth |
1196 \qmlproperty bool TextInput::smooth |
1069 |
1197 |
1070 This property holds whether the text is smoothly scaled or transformed. |
1198 This property holds whether the text is smoothly scaled or transformed. |
1170 */ |
1298 */ |
1171 void QDeclarativeTextInput::moveCursorSelection(int position) |
1299 void QDeclarativeTextInput::moveCursorSelection(int position) |
1172 { |
1300 { |
1173 Q_D(QDeclarativeTextInput); |
1301 Q_D(QDeclarativeTextInput); |
1174 d->control->moveCursor(position, true); |
1302 d->control->moveCursor(position, true); |
|
1303 d->updateHorizontalScroll(); |
|
1304 } |
|
1305 |
|
1306 /*! |
|
1307 \qmlmethod void TextInput::openSoftwareInputPanel() |
|
1308 |
|
1309 Opens software input panels like virtual keyboards for typing, useful for |
|
1310 customizing when you want the input keyboard to be shown and hidden in |
|
1311 your application. |
|
1312 |
|
1313 By default the opening of input panels follows the platform style. On Symbian^1 and |
|
1314 Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms |
|
1315 the panels are automatically opened when TextInput element gains active focus. Input panels are |
|
1316 always closed if no editor has active focus. |
|
1317 |
|
1318 . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false |
|
1319 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement |
|
1320 the behavior you want. |
|
1321 |
|
1322 Only relevant on platforms, which provide virtual keyboards. |
|
1323 |
|
1324 \qml |
|
1325 import Qt 4.7 |
|
1326 TextInput { |
|
1327 id: textInput |
|
1328 text: "Hello world!" |
|
1329 activeFocusOnPress: false |
|
1330 MouseArea { |
|
1331 anchors.fill: parent |
|
1332 onClicked: { |
|
1333 if (!textInput.activeFocus) { |
|
1334 textInput.forceActiveFocus() |
|
1335 textInput.openSoftwareInputPanel(); |
|
1336 } else { |
|
1337 textInput.focus = false; |
|
1338 } |
|
1339 } |
|
1340 onPressAndHold: textInput.closeSoftwareInputPanel(); |
|
1341 } |
|
1342 } |
|
1343 \endqml |
|
1344 */ |
|
1345 void QDeclarativeTextInput::openSoftwareInputPanel() |
|
1346 { |
|
1347 QEvent event(QEvent::RequestSoftwareInputPanel); |
|
1348 if (qApp) { |
|
1349 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) { |
|
1350 if (view->scene() && view->scene() == scene()) { |
|
1351 QApplication::sendEvent(view, &event); |
|
1352 } |
|
1353 } |
|
1354 } |
|
1355 } |
|
1356 |
|
1357 /*! |
|
1358 \qmlmethod void TextInput::closeSoftwareInputPanel() |
|
1359 |
|
1360 Closes a software input panel like a virtual keyboard shown on the screen, useful |
|
1361 for customizing when you want the input keyboard to be shown and hidden in |
|
1362 your application. |
|
1363 |
|
1364 By default the opening of input panels follows the platform style. On Symbian^1 and |
|
1365 Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms |
|
1366 the panels are automatically opened when TextInput element gains active focus. Input panels are |
|
1367 always closed if no editor has active focus. |
|
1368 |
|
1369 . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false |
|
1370 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement |
|
1371 the behavior you want. |
|
1372 |
|
1373 Only relevant on platforms, which provide virtual keyboards. |
|
1374 |
|
1375 \qml |
|
1376 import Qt 4.7 |
|
1377 TextInput { |
|
1378 id: textInput |
|
1379 text: "Hello world!" |
|
1380 activeFocusOnPress: false |
|
1381 MouseArea { |
|
1382 anchors.fill: parent |
|
1383 onClicked: { |
|
1384 if (!textInput.activeFocus) { |
|
1385 textInput.forceActiveFocus(); |
|
1386 textInput.openSoftwareInputPanel(); |
|
1387 } else { |
|
1388 textInput.focus = false; |
|
1389 } |
|
1390 } |
|
1391 onPressAndHold: textInput.closeSoftwareInputPanel(); |
|
1392 } |
|
1393 } |
|
1394 \endqml |
|
1395 */ |
|
1396 void QDeclarativeTextInput::closeSoftwareInputPanel() |
|
1397 { |
|
1398 QEvent event(QEvent::CloseSoftwareInputPanel); |
|
1399 if (qApp) { |
|
1400 QEvent event(QEvent::CloseSoftwareInputPanel); |
|
1401 if (QGraphicsView * view = qobject_cast<QGraphicsView*>(qApp->focusWidget())) { |
|
1402 if (view->scene() && view->scene() == scene()) { |
|
1403 QApplication::sendEvent(view, &event); |
|
1404 } |
|
1405 } |
|
1406 } |
|
1407 } |
|
1408 |
|
1409 void QDeclarativeTextInput::focusInEvent(QFocusEvent *event) |
|
1410 { |
|
1411 Q_D(const QDeclarativeTextInput); |
|
1412 if (d->showInputPanelOnFocus) { |
|
1413 if (d->focusOnPress && !isReadOnly()) { |
|
1414 openSoftwareInputPanel(); |
|
1415 } |
|
1416 } |
|
1417 QDeclarativePaintedItem::focusInEvent(event); |
1175 } |
1418 } |
1176 |
1419 |
1177 void QDeclarativeTextInputPrivate::init() |
1420 void QDeclarativeTextInputPrivate::init() |
1178 { |
1421 { |
1179 Q_Q(QDeclarativeTextInput); |
1422 Q_Q(QDeclarativeTextInput); |
1180 control->setCursorWidth(1); |
1423 control->setCursorWidth(1); |
1181 control->setPasswordCharacter(QLatin1Char('*')); |
1424 control->setPasswordCharacter(QLatin1Char('*')); |
1182 control->setLayoutDirection(Qt::LeftToRight); |
|
1183 q->setSmooth(smooth); |
1425 q->setSmooth(smooth); |
1184 q->setAcceptedMouseButtons(Qt::LeftButton); |
1426 q->setAcceptedMouseButtons(Qt::LeftButton); |
1185 q->setFlag(QGraphicsItem::ItemHasNoContents, false); |
1427 q->setFlag(QGraphicsItem::ItemHasNoContents, false); |
1186 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod); |
1428 q->setFlag(QGraphicsItem::ItemAcceptsInputMethod); |
1187 q->connect(control, SIGNAL(cursorPositionChanged(int,int)), |
1429 q->connect(control, SIGNAL(cursorPositionChanged(int,int)), |
1188 q, SLOT(cursorPosChanged())); |
1430 q, SLOT(cursorPosChanged())); |
1189 q->connect(control, SIGNAL(selectionChanged()), |
1431 q->connect(control, SIGNAL(selectionChanged()), |
1190 q, SLOT(selectionChanged())); |
1432 q, SLOT(selectionChanged())); |
1191 q->connect(control, SIGNAL(textChanged(const QString &)), |
1433 q->connect(control, SIGNAL(textChanged(const QString &)), |
1192 q, SIGNAL(displayTextChanged(const QString &))); |
|
1193 q->connect(control, SIGNAL(textChanged(const QString &)), |
|
1194 q, SLOT(q_textChanged())); |
1434 q, SLOT(q_textChanged())); |
1195 q->connect(control, SIGNAL(accepted()), |
1435 q->connect(control, SIGNAL(accepted()), |
1196 q, SIGNAL(accepted())); |
1436 q, SIGNAL(accepted())); |
1197 q->connect(control, SIGNAL(updateNeeded(QRect)), |
1437 q->connect(control, SIGNAL(updateNeeded(QRect)), |
1198 q, SLOT(updateRect(QRect))); |
1438 q, SLOT(updateRect(QRect))); |
1199 q->connect(control, SIGNAL(cursorPositionChanged(int,int)), |
|
1200 q, SLOT(updateRect()));//TODO: Only update rect between pos's |
|
1201 q->connect(control, SIGNAL(selectionChanged()), |
|
1202 q, SLOT(updateRect()));//TODO: Only update rect in selection |
|
1203 //Note that above TODOs probably aren't that big a savings |
|
1204 q->updateSize(); |
1439 q->updateSize(); |
1205 oldValidity = control->hasAcceptableInput(); |
1440 oldValidity = control->hasAcceptableInput(); |
1206 lastSelectionStart = 0; |
1441 lastSelectionStart = 0; |
1207 lastSelectionEnd = 0; |
1442 lastSelectionEnd = 0; |
1208 QPalette p = control->palette(); |
1443 QPalette p = control->palette(); |