diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2010-09-01 13:40:45 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2010-09-01 13:40:45 (GMT) |
commit | f710dfded9da517e6451809f81a8cc12ac4f3883 (patch) | |
tree | 89e0c9870b68b2b44175e061d84aadb9b8e25c01 | |
parent | 408c2d9d6279b5c69c3e4ba0663ec36ddd3d5542 (diff) | |
parent | 331522fdcbf14d757b61ed79dcc11649f62f28c8 (diff) | |
download | Qt-f710dfded9da517e6451809f81a8cc12ac4f3883.zip Qt-f710dfded9da517e6451809f81a8cc12ac4f3883.tar.gz Qt-f710dfded9da517e6451809f81a8cc12ac4f3883.tar.bz2 |
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/qt-s60-public into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/qt-s60-public:
Fixed input context trying to squeeze content into a full widget.
Fixed a case where a newly created native widget would lose focus.
Cleaned up position tracking in the Symbian input methods.
Revert "Long-press shortcuts for symbols on QWERTY keyboard don't work"
Added catching of errors in timers.
QT_PLUGINS_BASE_DIR needs to be defined after load(qt_config)
QS60Style: Itemviews are drawn incorrectly
Fixed sporadically failing autotest on Symbian.
-rw-r--r-- | mkspecs/common/symbian/symbian.conf | 3 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian.cpp | 8 | ||||
-rw-r--r-- | src/gui/inputmethod/qcoefepinputcontext_p.h | 11 | ||||
-rw-r--r-- | src/gui/inputmethod/qcoefepinputcontext_s60.cpp | 41 | ||||
-rw-r--r-- | src/gui/kernel/qapplication_s60.cpp | 29 | ||||
-rw-r--r-- | src/gui/kernel/qt_s60_p.h | 4 | ||||
-rw-r--r-- | src/gui/styles/qs60style.cpp | 6 | ||||
-rw-r--r-- | src/gui/widgets/qlinecontrol.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qinputcontext/qinputcontext.pro | 4 | ||||
-rw-r--r-- | tests/auto/qinputcontext/tst_qinputcontext.cpp | 657 | ||||
-rw-r--r-- | tests/auto/qtimer/tst_qtimer.cpp | 5 | ||||
-rw-r--r-- | tests/auto/qwidget/tst_qwidget.cpp | 25 |
12 files changed, 746 insertions, 49 deletions
diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index 04b81b0..61cc7d9 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -117,11 +117,12 @@ QMAKE_GZIP = gzip -9f QT_ARCH = symbian +load(qt_config) + # These directories must match what configure uses for QT_INSTALL_PLUGINS and QT_INSTALL_IMPORTS QT_PLUGINS_BASE_DIR = /resource/qt$${QT_LIBINFIX}/plugins QT_IMPORTS_BASE_DIR = /resource/qt/imports -load(qt_config) load(symbian/platform_paths) # The Symbian^3 PDK does not necessarily contain the required sis files. diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 1bad8ed..5cc6ae3 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -232,8 +232,12 @@ void QTimerActiveObject::DoCancel() void QTimerActiveObject::RunL() { - int error; - QT_TRYCATCH_ERROR(error, Run()); + int error = KErrNone; + if (iStatus == KErrNone) { + QT_TRYCATCH_ERROR(error, Run()); + } else { + error = iStatus.Int(); + } // All Symbian error codes are negative. if (error < 0) { CActiveScheduler::Current()->Error(error); // stop and report here, as this timer will be deleted on scope exit diff --git a/src/gui/inputmethod/qcoefepinputcontext_p.h b/src/gui/inputmethod/qcoefepinputcontext_p.h index d5243c3..2fd6d16 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_p.h +++ b/src/gui/inputmethod/qcoefepinputcontext_p.h @@ -66,10 +66,10 @@ QT_BEGIN_NAMESPACE -class QCoeFepInputContext : public QInputContext, - public MCoeFepAwareTextEditor, - public MCoeFepAwareTextEditor_Extension1, - public MObjectProvider +class Q_AUTOTEST_EXPORT QCoeFepInputContext : public QInputContext, + public MCoeFepAwareTextEditor, + public MCoeFepAwareTextEditor_Extension1, + public MObjectProvider { Q_OBJECT @@ -151,9 +151,10 @@ private: int m_inlinePosition; MFepInlineTextFormatRetriever *m_formatRetriever; MFepPointerEventHandlerDuringInlineEdit *m_pointerHandler; - int m_cursorPos; QBasicTimer m_tempPreeditStringTimeout; bool m_hasTempPreeditString; + + friend class tst_QInputContext; }; QT_END_NAMESPACE diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index c4d60a5..add3d17 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -79,7 +79,6 @@ QCoeFepInputContext::QCoeFepInputContext(QObject *parent) m_inlinePosition(0), m_formatRetriever(0), m_pointerHandler(0), - m_cursorPos(0), m_hasTempPreeditString(false) { m_fepState->SetObjectProvider(this); @@ -237,11 +236,17 @@ bool QCoeFepInputContext::filterEvent(const QEvent *event) break; } + QString widgetText = focusWidget()->inputMethodQuery(Qt::ImSurroundingText).toString(); + int maxLength = focusWidget()->inputMethodQuery(Qt::ImMaximumTextLength).toInt(); + if (!keyEvent->text().isEmpty() && widgetText.size() + m_preeditString.size() >= maxLength) { + // Don't send key events with string content if the widget is "full". + return true; + } + if (keyEvent->type() == QEvent::KeyPress && focusWidget()->inputMethodHints() & Qt::ImhHiddenText && !keyEvent->text().isEmpty()) { // Send some temporary preedit text in order to make text visible for a moment. - m_cursorPos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt(); m_preeditString = keyEvent->text(); QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent imEvent(m_preeditString, attributes); @@ -297,10 +302,6 @@ void QCoeFepInputContext::commitTemporaryPreeditString() return; commitCurrentString(false); - - //update cursor position, now this pre-edit text has been committed. - //this prevents next keypress overwriting it (QTBUG-11673) - m_cursorPos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt(); } void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event) @@ -596,8 +597,6 @@ void QCoeFepInputContext::StartFepInlineEditL(const TDesC& aInitialInlineText, commitTemporaryPreeditString(); - m_cursorPos = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); - QList<QInputMethodEvent::Attribute> attributes; m_cursorVisibility = aCursorVisibility ? 1 : 0; @@ -612,9 +611,10 @@ void QCoeFepInputContext::StartFepInlineEditL(const TDesC& aInitialInlineText, // Let's remove the selected text if aInitialInlineText is empty and there is selected text if (m_preeditString.isEmpty()) { int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt(); - int replacementLength = qAbs(m_cursorPos-anchor); + int cursorPos = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); + int replacementLength = qAbs(cursorPos-anchor); if (replacementLength > 0) { - int replacementStart = m_cursorPos < anchor ? 0 : -replacementLength; + int replacementStart = cursorPos < anchor ? 0 : -replacementLength; QList<QInputMethodEvent::Attribute> clearSelectionAttributes; QInputMethodEvent clearSelectionEvent(QLatin1String(""), clearSelectionAttributes); clearSelectionEvent.setCommitString(QLatin1String(""), replacementStart, replacementLength); @@ -647,8 +647,13 @@ void QCoeFepInputContext::UpdateFepInlineTextL(const TDesC& aNewInlineText, m_inlinePosition, m_cursorVisibility, QVariant())); - m_preeditString = qt_TDesC2QString(aNewInlineText); - QInputMethodEvent event(m_preeditString, attributes); + QString newPreeditString = qt_TDesC2QString(aNewInlineText); + QInputMethodEvent event(newPreeditString, attributes); + if (newPreeditString.isEmpty() && m_preeditString.isEmpty()) { + // In Symbian world this means "erase last character". + event.setCommitString("", -1, 1); + } + m_preeditString = newPreeditString; sendEvent(event); } @@ -820,23 +825,13 @@ void QCoeFepInputContext::commitCurrentString(bool cancelFepTransaction) { int longPress = 0; - if (m_preeditString.size() == 0) { - QWidget *w = focusWidget(); - if (!cancelFepTransaction && w) { - // We must replace the last character only if the input box has already accepted one - if (w->inputMethodQuery(Qt::ImCursorPosition).toInt() != m_cursorPos) - longPress = 1; - } - } - QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event(QLatin1String(""), attributes); - event.setCommitString(m_preeditString, 0-longPress, longPress); + event.setCommitString(m_preeditString, 0, 0); m_preeditString.clear(); sendEvent(event); m_hasTempPreeditString = false; - longPress = 0; if (cancelFepTransaction) { CCoeFep* fep = CCoeEnv::Static()->Fep(); diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index e197dc5..4ed4ba3 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1242,17 +1242,28 @@ void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */) S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility); #endif } else if (QApplication::activeWindow() == qwidget->window()) { - if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || S60->menuBeingConstructed) { - QWidget *fw = QApplication::focusWidget(); - if (fw) { - QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason); - QCoreApplication::sendEvent(fw, &event); - } - m_symbianPopupIsOpen = true; - return; + bool focusedControlFound = false; + WId winId = 0; + for (QWidget *w = qwidget->parentWidget(); w && (winId = w->internalWinId()); w = w->parentWidget()) { + if (winId->IsFocused() && winId->IsVisible()) { + focusedControlFound = true; + break; + } else if (w->isWindow()) + break; } + if (!focusedControlFound) { + if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || S60->menuBeingConstructed) { + QWidget *fw = QApplication::focusWidget(); + if (fw) { + QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason); + QCoreApplication::sendEvent(fw, &event); + } + m_symbianPopupIsOpen = true; + return; + } - QApplication::setActiveWindow(0); + QApplication::setActiveWindow(0); + } } // else { We don't touch the active window unless we were explicitly activated or deactivated } } diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index eb1aa18..7fd2baa 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -87,7 +87,7 @@ const TInt KInternalStatusPaneChange = 0x50000000; //this macro exists because EColor16MAP enum value doesn't exist in Symbian OS 9.2 #define Q_SYMBIAN_ECOLOR16MAP TDisplayMode(13) -class QS60ThreadLocalData +class Q_AUTOTEST_EXPORT QS60ThreadLocalData { public: QS60ThreadLocalData(); @@ -171,7 +171,7 @@ public: #endif }; -QS60Data* qGlobalS60Data(); +Q_AUTOTEST_EXPORT QS60Data* qGlobalS60Data(); #define S60 qGlobalS60Data() class QAbstractLongTapObserver diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index e28403b..0ba1bc6 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -2340,16 +2340,20 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti tableView = true; QS60StylePrivate::SkinElements element; + bool themeGraphicDefined = false; QRect elementRect = option->rect; //draw item is drawn as pressed, if it already has focus. if (isPressed && (hasFocus || isSelected)) { + themeGraphicDefined = true; element = tableView ? QS60StylePrivate::SE_TableItemPressed : QS60StylePrivate::SE_ListItemPressed; } else if (hasFocus || (isSelected && selectionBehavior != QAbstractItemView::SelectItems)) { element = QS60StylePrivate::SE_ListHighlight; elementRect = highlightRect; + themeGraphicDefined = true; } - QS60StylePrivate::drawSkinElement(element, painter, elementRect, flags); + if (themeGraphicDefined) + QS60StylePrivate::drawSkinElement(element, painter, elementRect, flags); } else { QCommonStyle::drawPrimitive(element, option, painter, widget); } diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 7f0c6c8..69e6791 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -419,7 +419,7 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) int c = m_cursor; // cursor position after insertion of commit string - if (event->replacementStart() == 0) + if (event->replacementStart() <= 0) c += event->commitString().length() + qMin(-event->replacementStart(), event->replacementLength()); m_cursor += event->replacementStart(); diff --git a/tests/auto/qinputcontext/qinputcontext.pro b/tests/auto/qinputcontext/qinputcontext.pro index b3ea8c2..ec6831e 100644 --- a/tests/auto/qinputcontext/qinputcontext.pro +++ b/tests/auto/qinputcontext/qinputcontext.pro @@ -1,2 +1,6 @@ load(qttest_p4) SOURCES += tst_qinputcontext.cpp + +symbian { + LIBS += -lws32 -lcone +} diff --git a/tests/auto/qinputcontext/tst_qinputcontext.cpp b/tests/auto/qinputcontext/tst_qinputcontext.cpp index 644b463..93813f9 100644 --- a/tests/auto/qinputcontext/tst_qinputcontext.cpp +++ b/tests/auto/qinputcontext/tst_qinputcontext.cpp @@ -48,17 +48,26 @@ #include <qlayout.h> #include <qradiobutton.h> #include <qwindowsstyle.h> +#include <qdesktopwidget.h> + +#ifdef Q_OS_SYMBIAN +#include <private/qt_s60_p.h> +#include <private/qcoefepinputcontext_p.h> + +#include <w32std.h> +#include <coecntrl.h> +#endif class tst_QInputContext : public QObject { Q_OBJECT public: - tst_QInputContext() {} + tst_QInputContext() : m_phoneIsQwerty(false) {} virtual ~tst_QInputContext() {} public slots: - void initTestCase() {} + void initTestCase(); void cleanupTestCase() {} void init() {} void cleanup() {} @@ -69,8 +78,176 @@ private slots: void closeSoftwareInputPanel(); void selections(); void focusProxy(); + void symbianTestCoeFepInputContext_data(); + void symbianTestCoeFepInputContext(); + +private: + bool m_phoneIsQwerty; }; +#ifdef Q_OS_SYMBIAN +class KeyEvent : public TWsEvent +{ +public: + KeyEvent(QWidget *w, TInt type, TInt scanCode, TUint code, TUint modifiers, TInt repeats) { + iHandle = w->effectiveWinId()->DrawableWindow()->WindowGroupId(); + iType = type; + SetTimeNow(); + TKeyEvent *keyEvent = reinterpret_cast<TKeyEvent *>(iEventData); + keyEvent->iScanCode = scanCode; + keyEvent->iCode = code; + keyEvent->iModifiers = modifiers; + keyEvent->iRepeats = repeats; + } +}; + +class FepReplayEvent +{ +public: + enum Type { + Pause, + Key, + CompleteKey + }; + + FepReplayEvent(int msecsToPause) + : m_type(Pause) + , m_msecsToPause(msecsToPause) + { + } + + FepReplayEvent(TInt keyType, TInt scanCode, TUint code, TUint modifiers, TInt repeats) + : m_type(Key) + , m_keyType(keyType) + , m_scanCode(scanCode) + , m_code(code) + , m_modifiers(modifiers) + , m_repeats(repeats) + { + } + + FepReplayEvent(TInt scanCode, TUint code, TUint modifiers, TInt repeats) + : m_type(CompleteKey) + , m_scanCode(scanCode) + , m_code(code) + , m_modifiers(modifiers) + , m_repeats(repeats) + { + } + + void sendEvent(QWidget *w, TInt type, TInt scanCode, TUint code, TUint modifiers, TInt repeats) + { + KeyEvent event(w, type, scanCode, code, modifiers, repeats); + S60->wsSession().SendEventToWindowGroup(w->effectiveWinId()->DrawableWindow()->WindowGroupId(), event); + } + + void pause(int msecs) + { + // Don't use qWait here. The polling nature of that function screws up the test. + QTimer timer; + QEventLoop loop; + QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + timer.setSingleShot(true); + timer.start(msecs); + loop.exec(); + } + + // For some reason, the test fails if using processEvents instead of an event loop + // with a zero timer to quit it, so use the timer. +#define KEY_WAIT 0 + + void replay(QWidget *w) + { + if (m_type == Pause) { + pause(m_msecsToPause); + } else if (m_type == Key) { + sendEvent(w, m_keyType, m_scanCode, m_code, m_modifiers, m_repeats); + if (m_keyType != EEventKeyDown) + // EEventKeyDown events should have no pause before the EEventKey event. + pause(KEY_WAIT); + } else if (m_type == CompleteKey) { + sendEvent(w, EEventKeyDown, m_scanCode, 0, m_modifiers, m_repeats); + // EEventKeyDown events should have no pause before the EEventKey event. + sendEvent(w, EEventKey, m_scanCode, m_code, m_modifiers, m_repeats); + pause(KEY_WAIT); + sendEvent(w, EEventKeyUp, m_scanCode, 0, m_modifiers, m_repeats); + pause(KEY_WAIT); + } + } + +private: + Type m_type; + int m_msecsToPause; + TInt m_keyType; + TInt m_scanCode; + TUint m_code; + TUint m_modifiers; + TInt m_repeats; +}; + +Q_DECLARE_METATYPE(QList<FepReplayEvent>) +Q_DECLARE_METATYPE(Qt::InputMethodHints) +Q_DECLARE_METATYPE(QLineEdit::EchoMode); + +#endif // Q_OS_SYMBIAN + +void tst_QInputContext::initTestCase() +{ +#ifdef Q_OS_SYMBIAN + // Sanity test. Checks FEP for: + // - T9 mode is default (it will attempt to fix this) + // - Language is English (it cannot fix this; bail out if not correct) + QWidget w; + QLayout *layout = new QVBoxLayout; + w.setLayout(layout); + QLineEdit *lineedit = new QLineEdit; + layout->addWidget(lineedit); + lineedit->setFocus(); +#ifdef QT_KEYPAD_NAVIGATION + lineedit->setEditFocus(true); +#endif + w.show(); + + QDesktopWidget desktop; + QRect screenSize = desktop.screenGeometry(&w); + if (screenSize.width() > screenSize.height()) { + // Crude way of finding out we are running on a qwerty phone. + m_phoneIsQwerty = true; + return; + } + + for (int iterations = 0; iterations < 16; iterations++) { + QTest::qWait(500); + + QList<FepReplayEvent> keyEvents; + + keyEvents << FepReplayEvent('9', '9', 0, 0); + keyEvents << FepReplayEvent('6', '6', 0, 0); + keyEvents << FepReplayEvent('8', '8', 0, 0); + keyEvents << FepReplayEvent(EStdKeyRightArrow, EKeyRightArrow, 0, 0); + + foreach(FepReplayEvent event, keyEvents) { + event.replay(lineedit); + } + + QApplication::processEvents(); + + if (lineedit->text().endsWith("you", Qt::CaseInsensitive)) { + // Success! + return; + } + + // Try changing modes. + // After 8 iterations, try to press the mode switch twice before typing. + for (int c = 0; c <= iterations / 8; c++) { + FepReplayEvent(EStdKeyHash, '#', 0, 0).replay(lineedit); + } + } + + QFAIL("FEP sanity test failed. Either the phone is not set to English, or the test was unable to enable T9"); +#endif +} + void tst_QInputContext::maximumTextLength() { QLineEdit le; @@ -271,7 +448,6 @@ void tst_QInputContext::focusProxy() QInputContext *gic = qApp->inputContext(); QVERIFY(gic); - qDebug() << gic->focusWidget() << &proxy; QCOMPARE(gic->focusWidget(), &proxy); // then change the focus proxy and check that input context is valid @@ -285,5 +461,480 @@ void tst_QInputContext::focusProxy() QCOMPARE(gic->focusWidget(), &proxy); } +void tst_QInputContext::symbianTestCoeFepInputContext_data() +{ +#ifdef Q_OS_SYMBIAN + QTest::addColumn<bool> ("inputMethodEnabled"); + QTest::addColumn<Qt::InputMethodHints> ("inputMethodHints"); + QTest::addColumn<int> ("maxLength"); // Zero for no limit + QTest::addColumn<QLineEdit::EchoMode> ("echoMode"); + QTest::addColumn<QList<FepReplayEvent> > ("keyEvents"); + QTest::addColumn<QString> ("finalString"); + QTest::addColumn<QString> ("preeditString"); + QList<FepReplayEvent> events; + + events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0); + events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0); + events << FepReplayEvent('5', '5', 0, 0); + events << FepReplayEvent('4', '4', 0, 0); + events << FepReplayEvent('6', '6', 0, 0); + events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0); + events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0); + events << FepReplayEvent('1', '1', 0, 0); + events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0); + events << FepReplayEvent('2', '2', 0, 0); + events << FepReplayEvent('1', '1', 0, 0); + QTest::newRow("Numbers (no FEP)") + << false + << Qt::InputMethodHints(Qt::ImhNone) + << 0 + << QLineEdit::Normal + << events + << QString("521") + << QString(""); + QTest::newRow("Numbers and password mode (no FEP)") + << false + << Qt::InputMethodHints(Qt::ImhNone) + << 0 + << QLineEdit::Password + << events + << QString("521") + << QString(""); + QTest::newRow("Numbers") + << true + << Qt::InputMethodHints(Qt::ImhDigitsOnly) + << 0 + << QLineEdit::Normal + << events + << QString("521") + << QString(""); + QTest::newRow("Numbers max length (no FEP)") + << false + << Qt::InputMethodHints(Qt::ImhNone) + << 2 + << QLineEdit::Normal + << events + << QString("21") + << QString(""); + QTest::newRow("Numbers max length") + << true + << Qt::InputMethodHints(Qt::ImhDigitsOnly) + << 2 + << QLineEdit::Normal + << events + << QString("21") + << QString(""); + events.clear(); + + events << FepReplayEvent(EEventKeyDown, '5', 0, 0, 0); + events << FepReplayEvent(EEventKey, '5', '5', 0, 0); + events << FepReplayEvent(EEventKey, '5', '5', 0, 1); + events << FepReplayEvent(EEventKey, '5', '5', 0, 1); + events << FepReplayEvent(EEventKeyUp, '5', 0, 0, 0); + QTest::newRow("Numbers and autorepeat (no FEP)") + << false + << Qt::InputMethodHints(Qt::ImhNone) + << 0 + << QLineEdit::Normal + << events + << QString("555") + << QString(""); + events.clear(); + + events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0); + events << FepReplayEvent('2', '2', 0, 0); + events << FepReplayEvent('3', '3', 0, 0); + events << FepReplayEvent('4', '4', 0, 0); + events << FepReplayEvent('4', '4', 0, 0); + events << FepReplayEvent('5', '5', 0, 0); + events << FepReplayEvent('5', '5', 0, 0); + events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0); + QTest::newRow("Multitap") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText) + << 0 + << QLineEdit::Normal + << events + << QString("Adh") + << QString(""); + QTest::newRow("Multitap with no auto uppercase") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase) + << 0 + << QLineEdit::Normal + << events + << QString("adh") + << QString(""); + QTest::newRow("Multitap with uppercase") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferUppercase) + << 0 + << QLineEdit::Normal + << events + << QString("ADH") + << QString(""); + QTest::newRow("Multitap with lowercase") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferLowercase) + << 0 + << QLineEdit::Normal + << events + << QString("adh") + << QString(""); + QTest::newRow("Multitap with forced uppercase") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhUppercaseOnly) + << 0 + << QLineEdit::Normal + << events + << QString("ADH") + << QString(""); + QTest::newRow("Multitap with forced lowercase") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhLowercaseOnly) + << 0 + << QLineEdit::Normal + << events + << QString("adh") + << QString(""); + events.clear(); + + events << FepReplayEvent(EStdKeyHash, '#', 0, 0); + events << FepReplayEvent('2', '2', 0, 0); + events << FepReplayEvent('2', '2', 0, 0); + events << FepReplayEvent('3', '3', 0, 0); + events << FepReplayEvent('4', '4', 0, 0); + events << FepReplayEvent('4', '4', 0, 0); + events << FepReplayEvent('5', '5', 0, 0); + events << FepReplayEvent('5', '5', 0, 0); + events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0); + QTest::newRow("Multitap with mode switch") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText) + << 0 + << QLineEdit::Normal + << events + << QString("bdh") + << QString(""); + events.clear(); + + events << FepReplayEvent('7', '7', 0, 0); + events << FepReplayEvent('7', '7', 0, 0); + events << FepReplayEvent('8', '8', 0, 0); + events << FepReplayEvent('9', '9', 0, 0); + events << FepReplayEvent('9', '9', 0, 0); + QTest::newRow("Multitap with unfinished text") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText) + << 0 + << QLineEdit::Normal + << events + << QString("Qt") + << QString("x"); + events << FepReplayEvent(2000); + QTest::newRow("Multitap with committed text") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText) + << 0 + << QLineEdit::Normal + << events + << QString("Qtx") + << QString(""); + events.clear(); + + events << FepReplayEvent('4', '4', 0, 0); + events << FepReplayEvent('4', '4', 0, 0); + // Simulate holding down hash key. + events << FepReplayEvent(EEventKeyDown, EStdKeyHash, 0, 0, 0); + events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 0); + events << FepReplayEvent(500); + events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1); + events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1); + events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1); + events << FepReplayEvent(EEventKeyUp, EStdKeyHash, 0, 0, 0); + events << FepReplayEvent('7', '7', 0, 0); + events << FepReplayEvent('7', '7', 0, 0); + events << FepReplayEvent('8', '8', 0, 0); + // QTBUG-9867: Switch back as well to make sure we don't get extra symbols + events << FepReplayEvent(EEventKeyDown, EStdKeyHash, 0, 0, 0); + events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 0); + events << FepReplayEvent(500); + events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1); + events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1); + events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1); + events << FepReplayEvent(EEventKeyUp, EStdKeyHash, 0, 0, 0); + events << FepReplayEvent('9', '9', 0, 0); + events << FepReplayEvent('6', '6', 0, 0); + events << FepReplayEvent('8', '8', 0, 0); + events << FepReplayEvent(2000); + events << FepReplayEvent(EStdKeyDevice3, EKeyDevice3, 0, 0); // Select key + QTest::newRow("Multitap and numbers") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText) + << 0 + << QLineEdit::Normal + << events + << QString("H778wmt") + << QString(""); + QTest::newRow("T9 and numbers") + << true + << Qt::InputMethodHints(Qt::ImhPreferLowercase) + << 0 + << QLineEdit::Normal + << events + << QString("hi778you") + << QString(""); + events.clear(); + + events << FepReplayEvent('4', '4', 0, 0); + events << FepReplayEvent('4', '4', 0, 0); + events << FepReplayEvent(EStdKeyDevice3, EKeyDevice3, 0, 0); // Select key + QTest::newRow("T9") + << true + << Qt::InputMethodHints(Qt::ImhPreferLowercase) + << 0 + << QLineEdit::Normal + << events + << QString("hi") + << QString(""); + QTest::newRow("T9 with uppercase") + << true + << Qt::InputMethodHints(Qt::ImhPreferUppercase) + << 0 + << QLineEdit::Normal + << events + << QString("HI") + << QString(""); + QTest::newRow("T9 with forced lowercase") + << true + << Qt::InputMethodHints(Qt::ImhLowercaseOnly) + << 0 + << QLineEdit::Normal + << events + << QString("hi") + << QString(""); + QTest::newRow("T9 with forced uppercase") + << true + << Qt::InputMethodHints(Qt::ImhUppercaseOnly) + << 0 + << QLineEdit::Normal + << events + << QString("HI") + << QString(""); + QTest::newRow("T9 with maxlength") + << true + << Qt::InputMethodHints(Qt::ImhLowercaseOnly) + << 1 + << QLineEdit::Normal + << events + << QString("i") + << QString(""); + events.clear(); + + events << FepReplayEvent('4', '4', 0, 0); + events << FepReplayEvent('4', '4', 0, 0); + events << FepReplayEvent(EStdKeyLeftArrow, EKeyLeftArrow, 0, 0); + events << FepReplayEvent(EStdKeyLeftArrow, EKeyLeftArrow, 0, 0); + events << FepReplayEvent('9', '9', 0, 0); + events << FepReplayEvent('6', '6', 0, 0); + events << FepReplayEvent('8', '8', 0, 0); + events << FepReplayEvent('0', '0', 0, 0); + events << FepReplayEvent(EStdKeyRightArrow, EKeyRightArrow, 0, 0); + events << FepReplayEvent(EStdKeyRightArrow, EKeyRightArrow, 0, 0); + events << FepReplayEvent('8', '8', 0, 0); + events << FepReplayEvent('8', '8', 0, 0); + QTest::newRow("T9 with movement and unfinished text") + << true + << Qt::InputMethodHints(Qt::ImhPreferLowercase) + << 0 + << QLineEdit::Normal + << events + << QString("you hi") + << QString("tv"); + QTest::newRow("T9 with movement, password and unfinished text") + << true + << Qt::InputMethodHints(Qt::ImhPreferLowercase) + << 0 + << QLineEdit::Password + << events + << QString("wmt h") + << QString("u"); + QTest::newRow("T9 with movement, maxlength, password and unfinished text") + << true + << Qt::InputMethodHints(Qt::ImhPreferLowercase) + << 2 + << QLineEdit::Password + << events + << QString("wh") + << QString(""); + QTest::newRow("T9 with movement, maxlength and unfinished text") + << true + << Qt::InputMethodHints(Qt::ImhPreferLowercase) + << 2 + << QLineEdit::Normal + << events + << QString("hi") + << QString(""); + QTest::newRow("Multitap with movement and unfinished text") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferLowercase) + << 0 + << QLineEdit::Normal + << events + << QString("wmt h") + << QString("u"); + QTest::newRow("Multitap with movement, maxlength and unfinished text") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferLowercase) + << 2 + << QLineEdit::Normal + << events + << QString("wh") + << QString(""); + QTest::newRow("Numbers with movement") + << true + << Qt::InputMethodHints(Qt::ImhDigitsOnly) + << 0 + << QLineEdit::Normal + << events + << QString("96804488") + << QString(""); + QTest::newRow("Numbers with movement and maxlength") + << true + << Qt::InputMethodHints(Qt::ImhDigitsOnly) + << 2 + << QLineEdit::Normal + << events + << QString("44") + << QString(""); + QTest::newRow("Numbers with movement, password and unfinished text") + << true + << Qt::InputMethodHints(Qt::ImhDigitsOnly) + << 0 + << QLineEdit::Password + << events + << QString("9680448") + << QString("8"); + QTest::newRow("Numbers with movement, maxlength, password and unfinished text") + << true + << Qt::InputMethodHints(Qt::ImhDigitsOnly) + << 2 + << QLineEdit::Password + << events + << QString("44") + << QString(""); + events << FepReplayEvent(EStdKeyRightArrow, EKeyRightArrow, 0, 0); + QTest::newRow("T9 with movement") + << true + << Qt::InputMethodHints(Qt::ImhPreferLowercase) + << 0 + << QLineEdit::Normal + << events + << QString("you htvi") + << QString(""); + QTest::newRow("T9 with movement and password") + << true + << Qt::InputMethodHints(Qt::ImhPreferLowercase) + << 0 + << QLineEdit::Password + << events + << QString("wmt hu") + << QString(""); + QTest::newRow("T9 with movement, maxlength and password") + << true + << Qt::InputMethodHints(Qt::ImhPreferLowercase) + << 2 + << QLineEdit::Password + << events + << QString("wh") + << QString(""); + QTest::newRow("Multitap with movement") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferLowercase) + << 0 + << QLineEdit::Normal + << events + << QString("wmt hu") + << QString(""); + QTest::newRow("Multitap with movement and maxlength") + << true + << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferLowercase) + << 2 + << QLineEdit::Normal + << events + << QString("wh") + << QString(""); + QTest::newRow("Numbers with movement and password") + << true + << Qt::InputMethodHints(Qt::ImhDigitsOnly) + << 0 + << QLineEdit::Password + << events + << QString("96804488") + << QString(""); + QTest::newRow("Numbers with movement, maxlength and password") + << true + << Qt::InputMethodHints(Qt::ImhDigitsOnly) + << 2 + << QLineEdit::Password + << events + << QString("44") + << QString(""); + events.clear(); +#endif +} + +void tst_QInputContext::symbianTestCoeFepInputContext() +{ +#ifndef Q_OS_SYMBIAN + QSKIP("This is a Symbian-only test", SkipAll); +#else + QCoeFepInputContext *ic = qobject_cast<QCoeFepInputContext *>(qApp->inputContext()); + if (!ic) { + QSKIP("coefep is not the active input context; skipping test", SkipAll); + } + + QFETCH(bool, inputMethodEnabled); + QFETCH(Qt::InputMethodHints, inputMethodHints); + QFETCH(int, maxLength); + QFETCH(QLineEdit::EchoMode, echoMode); + QFETCH(QList<FepReplayEvent>, keyEvents); + QFETCH(QString, finalString); + QFETCH(QString, preeditString); + + if (inputMethodEnabled && m_phoneIsQwerty) { + QSKIP("Skipping advanced input method tests on QWERTY phones", SkipSingle); + } + + QWidget w; + QLayout *layout = new QVBoxLayout; + w.setLayout(layout); + QLineEdit *lineedit = new QLineEdit; + layout->addWidget(lineedit); + lineedit->setFocus(); +#ifdef QT_KEYPAD_NAVIGATION + lineedit->setEditFocus(true); +#endif + w.show(); + + lineedit->setAttribute(Qt::WA_InputMethodEnabled, inputMethodEnabled); + lineedit->setInputMethodHints(inputMethodHints); + if (maxLength > 0) + lineedit->setMaxLength(maxLength); + lineedit->setEchoMode(echoMode); + + QTest::qWait(200); + + foreach(FepReplayEvent event, keyEvents) { + event.replay(lineedit); + } + + QApplication::processEvents(); + + QCOMPARE(lineedit->text(), finalString); + QCOMPARE(ic->m_preeditString, preeditString); +#endif +} + QTEST_MAIN(tst_QInputContext) #include "tst_qinputcontext.moc" diff --git a/tests/auto/qtimer/tst_qtimer.cpp b/tests/auto/qtimer/tst_qtimer.cpp index 8d213ed..b651187 100644 --- a/tests/auto/qtimer/tst_qtimer.cpp +++ b/tests/auto/qtimer/tst_qtimer.cpp @@ -161,8 +161,9 @@ void tst_QTimer::singleShotTimeout() QCOMPARE(helper.count, 1); } -#if defined(Q_OS_SYMBIAN) && defined(Q_CC_NOKIAX86) -// Increase wait as emulator startup can cause unexpected delays +#if defined(Q_OS_SYMBIAN) +// Increase wait as emulator startup can cause unexpected delays, and +// on hardware there are sometimes spikes right after process startup. #define TIMEOUT_TIMEOUT 2000 #else #define TIMEOUT_TIMEOUT 200 diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index ef05b91..098ce3c 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -402,6 +402,8 @@ private slots: #endif // QT_MAC_USE_COCOA #endif + void nativeChildFocus(); + private: bool ensureScreenSize(int width, int height); QWidget *testWidget; @@ -10531,5 +10533,28 @@ void tst_QWidget::taskQTBUG_11373() #endif // QT_MAC_USE_COCOA #endif +void tst_QWidget::nativeChildFocus() +{ + QWidget w; + QLayout *layout = new QVBoxLayout; + w.setLayout(layout); + QLineEdit *p1 = new QLineEdit; + QLineEdit *p2 = new QLineEdit; + layout->addWidget(p1); + layout->addWidget(p2); + p1->setObjectName("p1"); + p2->setObjectName("p2"); + w.show(); + w.activateWindow(); + p1->setFocus(); + p1->setAttribute(Qt::WA_NativeWindow); + p2->setAttribute(Qt::WA_NativeWindow); + QApplication::processEvents(); + QTest::qWaitForWindowShown(&w); + + QCOMPARE(QApplication::activeWindow(), &w); + QCOMPARE(QApplication::focusWidget(), p1); +} + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" |