Reverted use of tentative commit use in QWidget editors

Feature to be reimplemented simplified. Cases when input method
needs to be reset with possibility to commit use
QInputMethod::commit() again.

Change-Id: Ibfe7aecc0799e7a76c7ac4f5d860971cfe6e97ca
Reviewed-by: Joona Petrell <joona.t.petrell@nokia.com>
This commit is contained in:
Pekka Vuorela 2012-02-28 13:35:17 +02:00 committed by Qt by Nokia
parent 4f92f9b725
commit 0ee1b4a1de
14 changed files with 109 additions and 113 deletions

View File

@ -815,20 +815,19 @@ void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
lastFocusItem = focusItem;
#ifndef QT_NO_IM
if (lastFocusItem
&& (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) {
if (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod) {
// Close any external input method panel. This happens
// automatically by removing WA_InputMethodEnabled on
// the views, but if we are changing focus, we have to
// do it ourselves.
if (qApp)
qApp->inputMethod()->reset();
qApp->inputMethod()->commit();
}
#endif //QT_NO_IM
focusItem = 0;
QFocusEvent event(QEvent::FocusOut, focusReason);
sendEvent(lastFocusItem, &event);
#endif //QT_NO_IM
}
// This handles the case that the item has been removed from the

View File

@ -2042,7 +2042,7 @@ void QApplication::setActiveWindow(QWidget* act)
if (QApplicationPrivate::focus_widget) {
if (QApplicationPrivate::focus_widget->testAttribute(Qt::WA_InputMethodEnabled))
qApp->inputMethod()->reset();
qApp->inputMethod()->commit();
QFocusEvent focusAboutToChange(QEvent::FocusAboutToChange, Qt::ActiveWindowFocusReason);
QApplication::sendEvent(QApplicationPrivate::focus_widget, &focusAboutToChange);

View File

@ -3090,7 +3090,7 @@ void QWidgetPrivate::setEnabled_helper(bool enable)
if (focusWidget->testAttribute(Qt::WA_InputMethodEnabled))
qApp->inputMethod()->update(Qt::ImEnabled);
} else {
qApp->inputMethod()->reset();
qApp->inputMethod()->commit();
qApp->inputMethod()->update(Qt::ImEnabled);
}
}
@ -5948,7 +5948,7 @@ void QWidget::setFocus(Qt::FocusReason reason)
if (prev) {
if (reason != Qt::PopupFocusReason && reason != Qt::MenuBarFocusReason
&& prev->testAttribute(Qt::WA_InputMethodEnabled)) {
qApp->inputMethod()->reset();
qApp->inputMethod()->commit();
}
if (reason != Qt::NoFocusReason) {
@ -6057,7 +6057,7 @@ void QWidget::clearFocus()
{
if (hasFocus()) {
if (testAttribute(Qt::WA_InputMethodEnabled))
qApp->inputMethod()->reset();
qApp->inputMethod()->commit();
QFocusEvent focusAboutToChange(QEvent::FocusAboutToChange);
QApplication::sendEvent(this, &focusAboutToChange);
@ -10087,7 +10087,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
QWidget *focusWidget = d->effectiveFocusWidget();
if (on && !internalWinId() && hasFocus()
&& focusWidget->testAttribute(Qt::WA_InputMethodEnabled)) {
qApp->inputMethod()->reset();
qApp->inputMethod()->commit();
qApp->inputMethod()->update(Qt::ImEnabled);
}
if (!qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings) && parentWidget()
@ -10137,7 +10137,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
#ifndef QT_NO_IM
if (qApp->focusObject() == this) {
if (!on)
qApp->inputMethod()->reset();
qApp->inputMethod()->commit();
qApp->inputMethod()->update(Qt::ImEnabled);
}
#endif //QT_NO_IM

View File

@ -1669,7 +1669,7 @@ QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const
case Qt::ImCursorPosition:
return QVariant(d->control->cursor());
case Qt::ImSurroundingText:
return QVariant(d->control->realText());
return QVariant(d->control->text());
case Qt::ImCurrentSelection:
return QVariant(selectedText());
case Qt::ImMaximumTextLength:
@ -1748,7 +1748,6 @@ void QLineEdit::focusOutEvent(QFocusEvent *e)
reason != Qt::PopupFocusReason)
deselect();
d->control->commitPreedit();
d->setCursorVisible(false);
d->control->setCursorBlinkPeriod(0);
#ifdef QT_KEYPAD_NAVIGATION

View File

@ -184,21 +184,15 @@ void QWidgetLineControl::paste(QClipboard::Mode clipboardMode)
/*!
\internal
Exits preedit mode and commits parts marked as tentative commit
*/
void QWidgetLineControl::commitPreedit()
{
if (!composeMode())
return;
qApp->inputMethod()->reset();
if (!m_tentativeCommit.isEmpty()) {
internalInsert(m_tentativeCommit);
m_tentativeCommit.clear();
finishChange(-1, true/*not used, not documented*/, false);
}
qApp->inputMethod()->commit();
if (!composeMode())
return;
m_preeditCursor = 0;
setPreeditArea(-1, QString());
@ -573,13 +567,7 @@ void QWidgetLineControl::processInputMethodEvent(QInputMethodEvent *event)
else if (m_preeditCursor != oldPreeditCursor)
emit updateMicroFocus();
bool tentativeCommitChanged = (m_tentativeCommit != event->tentativeCommitString());
if (tentativeCommitChanged) {
m_textDirty = true;
m_tentativeCommit = event->tentativeCommitString();
}
if (isGettingInput || tentativeCommitChanged)
if (isGettingInput)
finishChange(priorState);
if (selectionChange)
@ -687,15 +675,6 @@ bool QWidgetLineControl::finishChange(int validateFromState, bool update, bool e
return true;
}
m_cursor = cursorCopy;
if (!m_tentativeCommit.isEmpty()) {
textCopy.insert(m_cursor, m_tentativeCommit);
bool validInput = (m_validator->validate(textCopy, cursorCopy) != QValidator::Invalid);
if (!validInput)
m_tentativeCommit.clear();
}
} else {
m_tentativeCommit.clear();
}
}
#endif

View File

@ -217,22 +217,13 @@ public:
QString text() const
{
QString content = m_text;
if (!m_tentativeCommit.isEmpty())
content.insert(m_cursor, m_tentativeCommit);
QString res = m_maskData ? stripString(content) : content;
return (res.isNull() ? QString::fromLatin1("") : res);
}
// like text() but doesn't include preedit
QString realText() const
{
QString res = m_maskData ? stripString(m_text) : m_text;
return (res.isNull() ? QString::fromLatin1("") : res);
}
void setText(const QString &txt)
{
if (composeMode())
qApp->inputMethod()->reset();
m_tentativeCommit.clear();
internalSetText(txt, -1, false);
}
void commitPreedit();
@ -402,7 +393,6 @@ private:
int m_cursor;
int m_preeditCursor;
int m_cursorWidth;
QString m_tentativeCommit;
Qt::LayoutDirection m_layoutDirection;
uint m_hideCursor : 1; // used to hide the m_cursor inside preedit areas
uint m_separator : 1;

View File

@ -2000,7 +2000,6 @@ void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
}
}
layout->setAdditionalFormats(overrides);
tentativeCommit = e->tentativeCommitString();
cursor.endEditBlock();
@ -2057,7 +2056,6 @@ void QWidgetTextControlPrivate::focusEvent(QFocusEvent *e)
}
#endif
} else {
commitPreedit();
setBlinkingCursorEnabled(false);
if (cursorIsFocusIndicator
@ -2755,17 +2753,15 @@ bool QWidgetTextControlPrivate::isPreediting() const
void QWidgetTextControlPrivate::commitPreedit()
{
if (!isPreediting())
return;
qApp->inputMethod()->commit();
if (!isPreediting())
return;
cursor.beginEditBlock();
qApp->inputMethod()->reset();
if (!tentativeCommit.isEmpty()) {
cursor.insertText(tentativeCommit);
tentativeCommit.clear();
}
preeditCursor = 0;
QTextBlock block = cursor.block();
QTextLayout *layout = block.layout();
@ -2936,17 +2932,12 @@ bool QWidgetTextControl::find(const QString &exp, QTextDocument::FindFlags optio
QString QWidgetTextControl::toPlainText() const
{
Q_D(const QWidgetTextControl);
QString plainText = document()->toPlainText();
if (!d->tentativeCommit.isEmpty())
plainText.insert(textCursor().position(), d->tentativeCommit);
return plainText;
return document()->toPlainText();
}
#ifndef QT_NO_TEXTHTMLPARSER
QString QWidgetTextControl::toHtml() const
{
// note: currently not including tentative commit
return document()->toHtml();
}
#endif

View File

@ -209,7 +209,6 @@ public:
int preeditCursor;
bool hideCursor; // used to hide the cursor in the preedit area
QString tentativeCommit;
QVector<QAbstractTextDocumentLayout::Selection> extraSelections;

View File

@ -61,7 +61,19 @@ public:
virtual QRectF keyboardRect() const { return m_keyboardRect; }
virtual bool isAnimating() const { return m_animating; }
virtual void reset() { m_resetCallCount++; }
virtual void commit() { m_commitCallCount++; }
virtual void commit() {
m_commitCallCount++;
QInputMethodEvent commitEvent;
commitEvent.setCommitString(m_commitString);
if (qGuiApp->focusObject())
qGuiApp->sendEvent(qGuiApp->focusObject(), &commitEvent);
else
qWarning("Test input context to commit without focused object");
}
void setCommitString(const QString &commitString)
{
m_commitString = commitString;
}
virtual void update(Qt::InputMethodQueries queries)
{
@ -105,6 +117,7 @@ public:
int m_updateCallCount;
int m_resetCallCount;
int m_commitCallCount;
QString m_commitString;
mutable int m_localeCallCount;
mutable int m_inputDirectionCallCount;
Qt::InputMethodQueries m_lastQueries;

View File

@ -3784,6 +3784,7 @@ void tst_QGraphicsScene::inputMethod()
QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
inputContext.m_resetCallCount = 0;
inputContext.m_commitCallCount = 0;
scene.addItem(item);
QInputMethodEvent event;
@ -3802,7 +3803,7 @@ void tst_QGraphicsScene::inputMethod()
scene.setFocusItem(0);
// the input context is reset twice, once because an item has lost focus and again because
// the Qt::WA_InputMethodEnabled flag is cleared because no item has focus.
QCOMPARE(inputContext.m_resetCallCount, callFocusItem ? 2 : 0);
QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, callFocusItem ? 2 : 0);
QCOMPARE(item->queryCalls, callFocusItem ? 1 : 0); // verify that value is unaffected
item->eventCalls = 0;

View File

@ -4187,21 +4187,22 @@ void tst_QGraphicsView::inputContextReset()
item1->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod);
inputContext.m_resetCallCount = 0;
inputContext.m_commitCallCount = 0;
scene.addItem(item1);
QCOMPARE(inputContext.m_resetCallCount, 0);
QCOMPARE(inputContext.m_commitCallCount, 0);
inputContext.m_resetCallCount = 0;
scene.setFocusItem(item1);
QCOMPARE(scene.focusItem(), (QGraphicsItem *)item1);
QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled));
QCOMPARE(inputContext.m_resetCallCount, 0);
QCOMPARE(inputContext.m_commitCallCount, 0);
inputContext.m_resetCallCount = 0;
scene.setFocusItem(0);
// the input context is reset twice, once because an item has lost focus and again because
// the Qt::WA_InputMethodEnabled flag is cleared because no item has focus.
// QEXPECT_FAIL("", "QTBUG-22454", Abort);
QCOMPARE(inputContext.m_resetCallCount, 2);
QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, 2);
// introduce another item that is focusable but does not accept input methods
QGraphicsItem *item2 = new QGraphicsRectItem;
@ -4209,17 +4210,19 @@ void tst_QGraphicsView::inputContextReset()
scene.addItem(item2);
inputContext.m_resetCallCount = 0;
inputContext.m_commitCallCount = 0;
scene.setFocusItem(item2);
QCOMPARE(inputContext.m_resetCallCount, 0);
QCOMPARE(inputContext.m_commitCallCount, 0);
inputContext.m_resetCallCount = 0;
scene.setFocusItem(item1);
QCOMPARE(inputContext.m_resetCallCount, 0);
QCOMPARE(inputContext.m_commitCallCount, 0);
// test changing between between items that accept input methods.
item2->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod);
scene.setFocusItem(item2);
QCOMPARE(inputContext.m_resetCallCount, 1);
QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, 1);
}
void tst_QGraphicsView::indirectPainting()

View File

@ -72,6 +72,10 @@
#include "qplatformdefs.h"
#include "../../../shared/platforminputcontext.h"
#include <private/qinputmethod_p.h>
QT_BEGIN_NAMESPACE
class QPainter;
QT_END_NAMESPACE
@ -275,7 +279,6 @@ private slots:
void selectAndCursorPosition();
void inputMethod();
void inputMethodSelection();
void inputMethodTentativeCommit();
protected slots:
void editingFinished();
@ -301,6 +304,7 @@ private:
int newCursorPos;
QLineEdit *testWidget;
int m_keyboardScheme;
PlatformInputContext m_platformInputContext;
};
typedef QList<int> IntList;
@ -357,21 +361,23 @@ void tst_QLineEdit::initTestCase()
testWidget->resize(200,50);
testWidget->show();
QTest::qWaitForWindowShown(testWidget);
QApplication::setActiveWindow(testWidget);
#ifdef Q_WS_X11
// to be safe and avoid failing setFocus with window managers
qt_x11_wait_for_window_manager(testWidget);
#endif
QTRY_VERIFY(testWidget->hasFocus());
changed_count = 0;
edited_count = 0;
selection_count = 0;
QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
inputMethodPrivate->testContext = &m_platformInputContext;
}
void tst_QLineEdit::cleanupTestCase()
{
delete testWidget;
QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
inputMethodPrivate->testContext = 0;
}
void tst_QLineEdit::init()
@ -3828,6 +3834,23 @@ void tst_QLineEdit::inputMethod()
testWidget->setEnabled(false);
QApplication::sendEvent(testWidget, &queryEvent);
QCOMPARE(queryEvent.value(Qt::ImEnabled).toBool(), false);
testWidget->setEnabled(true);
// removing focus allows input method to commit preedit
testWidget->setText("");
testWidget->activateWindow();
QTRY_VERIFY(testWidget->hasFocus());
QTRY_COMPARE(qApp->focusObject(), testWidget);
m_platformInputContext.setCommitString("text");
m_platformInputContext.m_commitCallCount = 0;
QList<QInputMethodEvent::Attribute> attributes;
QInputMethodEvent preeditEvent("preedit text", attributes);
QApplication::sendEvent(testWidget, &preeditEvent);
testWidget->clearFocus();
QCOMPARE(m_platformInputContext.m_commitCallCount, 1);
QCOMPARE(testWidget->text(), QString("text"));
}
void tst_QLineEdit::inputMethodSelection()
@ -3866,37 +3889,6 @@ void tst_QLineEdit::inputMethodSelection()
QCOMPARE(selectionSpy.count(), 3);
}
void tst_QLineEdit::inputMethodTentativeCommit()
{
// test that basic tentative commit gets to text property on preedit state
QList<QInputMethodEvent::Attribute> attributes;
QInputMethodEvent event("test", attributes);
event.setTentativeCommitString("test");
QApplication::sendEvent(testWidget, &event);
QCOMPARE(testWidget->text(), QString("test"));
// tentative commit not allowed present in surrounding text
QInputMethodQueryEvent queryEvent(Qt::ImSurroundingText);
QApplication::sendEvent(testWidget, &queryEvent);
QCOMPARE(queryEvent.value(Qt::ImSurroundingText).toString(), QString(""));
// if text with tentative commit does not validate, not allowed to be part of text property
testWidget->setText(""); // ensure input state is reset
QValidator *validator = new QIntValidator(0, 100);
testWidget->setValidator(validator);
QApplication::sendEvent(testWidget, &event);
QCOMPARE(testWidget->text(), QString(""));
testWidget->setValidator(0);
delete validator;
// text remains when focus is removed
testWidget->setText(""); // ensure input state is reset
QApplication::sendEvent(testWidget, &event);
QFocusEvent lostFocus(QEvent::FocusOut);
QApplication::sendEvent(testWidget, &lostFocus);
QCOMPARE(testWidget->text(), QString("test"));
}
QTEST_MAIN(tst_QLineEdit)
#include "tst_qlineedit.moc"

View File

@ -1,7 +1,7 @@
CONFIG += testcase
TARGET = tst_qtextedit
QT += widgets widgets-private gui-private testlib
QT += widgets widgets-private gui-private core-private testlib
INCLUDEPATH += ../
HEADERS +=

View File

@ -62,6 +62,10 @@
#include <qabstracttextdocumentlayout.h>
#include <qtextdocumentfragment.h>
#include "../../../shared/platforminputcontext.h"
#include <private/qinputmethod_p.h>
//Used in copyAvailable
typedef QPair<Qt::Key, Qt::KeyboardModifier> keyPairType;
typedef QList<keyPairType> pairListType;
@ -96,6 +100,8 @@ public:
tst_QTextEdit();
public slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
private slots:
@ -211,6 +217,7 @@ private:
QTextEdit *ed;
qreal rootFrameMargin;
PlatformInputContext m_platformInputContext;
};
bool tst_QTextEdit::nativeClipboardWorking()
@ -372,6 +379,18 @@ public:
tst_QTextEdit::tst_QTextEdit()
{}
void tst_QTextEdit::initTestCase()
{
QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
inputMethodPrivate->testContext = &m_platformInputContext;
}
void tst_QTextEdit::cleanupTestCase()
{
QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
inputMethodPrivate->testContext = 0;
}
void tst_QTextEdit::init()
{
#ifdef Q_OS_WINCE //disable magic for WindowsCE
@ -2360,6 +2379,8 @@ void tst_QTextEdit::bidiLogicalMovement()
void tst_QTextEdit::inputMethodEvent()
{
ed->show();
// test that text change with an input method event triggers change signal
QSignalSpy spy(ed, SIGNAL(textChanged()));
@ -2367,14 +2388,23 @@ void tst_QTextEdit::inputMethodEvent()
event.setCommitString("text");
QApplication::sendEvent(ed, &event);
QCOMPARE(spy.count(), 1);
spy.clear();
QCOMPARE(ed->toPlainText(), QString("text"));
// test that input method gets chance to commit preedit when removing focus
ed->setText("");
QApplication::setActiveWindow(ed);
QTRY_VERIFY(QApplication::focusWindow());
QCOMPARE(qApp->focusObject(), ed);
m_platformInputContext.setCommitString("text");
m_platformInputContext.m_commitCallCount = 0;
QList<QInputMethodEvent::Attribute> attributes;
QInputMethodEvent event2("preedit", attributes);
event2.setTentativeCommitString("string");
QApplication::sendEvent(ed, &event2);
QCOMPARE(spy.count(), 1);
QCOMPARE(ed->toPlainText(), QString("textstring"));
QInputMethodEvent preeditEvent("preedit text", attributes);
QApplication::sendEvent(ed, &preeditEvent);
ed->clearFocus();
QCOMPARE(m_platformInputContext.m_commitCallCount, 1);
QCOMPARE(ed->toPlainText(), QString("text"));
}
void tst_QTextEdit::inputMethodSelection()