QGuiApplication::focusObject() to replace QInputPanel::inputItem()

* Deprecated QInputPanel::inputWindow() which is already
  just returning QGuiApplication::activeWindow()
* Deprecated QInputPanel::inputItem() and introduced
  QGuiApplication::focusObject(). Input methods can check
  input method support by Qt::ImEnabled query.

Change-Id: I70a9c1c3f79aadb75c839d0489a9428f7a221df5
Reviewed-by: Joona Petrell <joona.t.petrell@nokia.com>
bb10
Pekka Vuorela 2012-01-20 17:57:21 +02:00 committed by Qt by Nokia
parent e7d0d54084
commit dd565d2d4c
10 changed files with 204 additions and 5 deletions

View File

@ -196,6 +196,24 @@ QWindow *QGuiApplication::focusWindow()
return QGuiApplicationPrivate::focus_window;
}
/*!
\fn QGuiApplication::focusObjectChanged(QObject *focusObject)
This signal is emitted when final receiver of events tied to focus is changed.
\sa focusObject()
*/
/*!
Returns the QObject in currently active window that will be final receiver of events
tied focus, such as key events.
*/
QObject *QGuiApplication::focusObject()
{
if (focusWindow())
return focusWindow()->focusObject();
return 0;
}
QWindowList QGuiApplication::topLevelWindows()
{
return QGuiApplicationPrivate::window_list;
@ -792,9 +810,13 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate
if (previous == QGuiApplicationPrivate::focus_window)
return;
QObject *previousFocusObject = previous ? previous->focusObject() : 0;
if (previous) {
QFocusEvent focusOut(QEvent::FocusOut);
QCoreApplication::sendSpontaneousEvent(previous, &focusOut);
QObject::disconnect(previous, SIGNAL(focusObjectChanged(QObject*)),
qApp, SIGNAL(focusObjectChanged(QObject*)));
} else {
QEvent appActivate(QEvent::ApplicationActivate);
qApp->sendSpontaneousEvent(qApp, &appActivate);
@ -803,6 +825,8 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate
if (QGuiApplicationPrivate::focus_window) {
QFocusEvent focusIn(QEvent::FocusIn);
QCoreApplication::sendSpontaneousEvent(QGuiApplicationPrivate::focus_window, &focusIn);
QObject::connect(QGuiApplicationPrivate::focus_window, SIGNAL(focusObjectChanged(QObject*)),
qApp, SIGNAL(focusObjectChanged(QObject*)));
} else {
QEvent appActivate(QEvent::ApplicationDeactivate);
qApp->sendSpontaneousEvent(qApp, &appActivate);
@ -810,6 +834,9 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate
if (self)
self->notifyActiveWindowChange(previous);
if (previousFocusObject != qApp->focusObject())
emit qApp->focusObjectChanged(qApp->focusObject());
}
void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent *wse)

View File

@ -88,6 +88,7 @@ public:
static QT_DEPRECATED QWindow *activeWindow() { return focusWindow(); }
#endif
static QWindow *focusWindow();
static QObject *focusObject();
static QScreen *primaryScreen();
static QList<QScreen *> screens();
@ -133,6 +134,7 @@ Q_SIGNALS:
void fontDatabaseChanged();
void screenAdded(QScreen *screen);
void lastWindowClosed();
void focusObjectChanged(QObject *focusObject);
protected:
bool event(QEvent *);

View File

@ -41,6 +41,8 @@
#include <qinputpanel.h>
#include <private/qinputpanel_p.h>
#include <qguiapplication.h>
#include <qtimer.h>
QT_BEGIN_NAMESPACE
@ -50,6 +52,8 @@ QT_BEGIN_NAMESPACE
QInputPanel::QInputPanel()
: QObject(*new QInputPanelPrivate)
{
// might be instantiated before QGuiApplication is fully done, need to connect later
QTimer::singleShot(0, this, SLOT(q_connectFocusObject()));
}
/*!
@ -74,6 +78,7 @@ QInputPanel::~QInputPanel()
/*!
\property QInputPanel::inputItem
\brief Focused item that accepts text input
\obsolete
Input item is set and unset by the focused window. In QML Scene Graph this is done by
QQuickCanvas and the input item is either TextInput or TextEdit element. Any QObject can
@ -101,6 +106,8 @@ void QInputPanel::setInputItem(QObject *inputItem)
/*!
Returns the currently focused window containing the input item.
\obsolete
*/
QWindow *QInputPanel::inputWindow() const
{
@ -288,8 +295,8 @@ void QInputPanel::update(Qt::InputMethodQueries queries)
{
Q_D(QInputPanel);
if (!d->inputItem)
return;
if (queries & Qt::ImEnabled)
d->q_checkFocusObject(qApp->focusObject());
QPlatformInputContext *ic = d->platformInputContext();
if (ic)
@ -342,6 +349,28 @@ void QInputPanel::invokeAction(Action a, int cursorPosition)
ic->invokeAction(a, cursorPosition);
}
// temporary handlers for updating focus item based on application focus
void QInputPanelPrivate::q_connectFocusObject()
{
Q_Q(QInputPanel);
QObject::connect(qApp, SIGNAL(focusObjectChanged(QObject*)),
q, SLOT(q_checkFocusObject(QObject*)));
q_checkFocusObject(qApp->focusObject());
}
void QInputPanelPrivate::q_checkFocusObject(QObject *object)
{
Q_Q(QInputPanel);
bool enabled = false;
if (object) {
QInputMethodQueryEvent query(Qt::ImEnabled);
QGuiApplication::sendEvent(object, &query);
enabled = query.value(Qt::ImEnabled).toBool();
}
q->setInputItem(enabled ? object : 0);
}
QT_END_NAMESPACE
#include "moc_qinputpanel.cpp"

View File

@ -68,11 +68,11 @@ class Q_GUI_EXPORT QInputPanel : public QObject
Q_ENUMS(Action)
public:
QObject *inputItem() const;
void setInputItem(QObject *inputItemChanged);
QT_DEPRECATED QObject *inputItem() const;
QT_DEPRECATED void setInputItem(QObject *inputItemChanged);
// the window containing the editor
QWindow *inputWindow() const;
QT_DEPRECATED QWindow *inputWindow() const;
QTransform inputItemTransform() const;
void setInputItemTransform(const QTransform &transform);
@ -121,6 +121,9 @@ private:
friend class QPlatformInputContext;
QInputPanel();
~QInputPanel();
Q_PRIVATE_SLOT(d_func(), void q_connectFocusObject());
Q_PRIVATE_SLOT(d_func(), void q_checkFocusObject(QObject* object));
};
QT_END_NAMESPACE

View File

@ -55,6 +55,8 @@ QT_BEGIN_NAMESPACE
class QInputPanelPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QInputPanel)
public:
inline QInputPanelPrivate() : testContext(0)
{}
@ -66,6 +68,8 @@ public:
{
return inputPanel->d_func();
}
void q_connectFocusObject();
void q_checkFocusObject(QObject *object);
QTransform inputItemTransform;
QWeakPointer<QObject> inputItem;

View File

@ -796,6 +796,13 @@ QAccessibleInterface *QWindow::accessibleRoot() const
return 0;
}
/*!
\fn QWindow::focusObjectChanged(QObject *focusObject)
This signal is emitted when final receiver of events tied to focus is changed.
\sa focusObject()
*/
/*!
Returns the QObject that will be the final receiver of events tied focus, such
as key events.

View File

@ -262,6 +262,8 @@ Q_SIGNALS:
void visibleChanged(bool arg);
void contentOrientationChanged(Qt::ScreenOrientation orientation);
void focusObjectChanged(QObject *object);
private Q_SLOTS:
void screenDestroyed(QObject *screen);

View File

@ -15,3 +15,4 @@ SUBDIRS=\
qshortcut \
qtouchevent \
qwindow \
qguiapplication \

View File

@ -0,0 +1,4 @@
CONFIG += testcase
TARGET = tst_qguiapplication
QT += core gui testlib
SOURCES = tst_qguiapplication.cpp

View File

@ -0,0 +1,120 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <QtGui/QGuiApplication>
#include <QDebug>
class tst_QGuiApplication: public QObject
{
Q_OBJECT
private slots:
void focusObject();
};
class DummyWindow : public QWindow
{
public:
DummyWindow() : m_focusObject(0) {}
virtual QObject *focusObject() const
{
return m_focusObject;
}
void setFocusObject(QObject *object)
{
m_focusObject = object;
emit focusObjectChanged(object);
}
QObject *m_focusObject;
};
void tst_QGuiApplication::focusObject()
{
int argc = 0;
QGuiApplication app(argc, 0);
QObject obj1, obj2, obj3;
DummyWindow window1;
DummyWindow window2;
window1.show();
QSignalSpy spy(&app, SIGNAL(focusObjectChanged(QObject *)));
// verify active window focus propagates to qguiapplication
QTest::qWaitForWindowShown(&window1);
window1.requestActivateWindow();
QTRY_COMPARE(app.focusWindow(), &window1);
window1.setFocusObject(&obj1);
QCOMPARE(app.focusObject(), &obj1);
QCOMPARE(spy.count(), 1);
spy.clear();
window1.setFocusObject(&obj2);
QCOMPARE(app.focusObject(), &obj2);
QCOMPARE(spy.count(), 1);
spy.clear();
window2.setFocusObject(&obj3);
QCOMPARE(app.focusObject(), &obj2); // not yet changed
window2.show();
QTest::qWaitForWindowShown(&window2);
QTRY_COMPARE(app.focusWindow(), &window2);
QCOMPARE(app.focusObject(), &obj3);
QCOMPARE(spy.count(), 1);
// focus change on unfocused window does not show
spy.clear();
window1.setFocusObject(&obj1);
QCOMPARE(spy.count(), 0);
QCOMPARE(app.focusObject(), &obj3);
}
QTEST_APPLESS_MAIN(tst_QGuiApplication)
#include "tst_qguiapplication.moc"