aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarkko Koivikko <jarkko.koivikko@code-q.fi>2017-01-06 11:14:07 +0200
committerJarkko Koivikko <jarkko.koivikko@code-q.fi>2017-01-20 17:37:41 +0000
commit839a0afec5c39c92ac7221e2c5b6a866d6848382 (patch)
tree12a6bf83805af3cecc2887518d4ce12098dac817
parente2c4fde1804654e449465aee1b9d217e05f06075 (diff)
Automatically hide word candidate list
This change adds support for automatically hiding word candidate list when inactive. This feature includes the following enhancements: - Added new settings: * VirtualKeyboardSettings.wordCandidateList.autoHideDelay * VirtualKeyboardSettings.wordCandidateList.alwaysVisible - Automatic hiding of word candidate list when inactive and when autoHideDelay elapsed. - alwaysVisible setting restores the old functionality. - Added new signal selectionListsChanged() to input method, allowing the input method to dynamically allocate or deallocate selection lists. - HunspellInputMethod does not allocate selection list when dictionary cannot be loaded, or Qt::ImhNoPredictiveText is enabled. Also, it will no longer use pre-edit text in this case. - OpenWnnInputMethod does not allocate selection list if not needed. [ChangeLog] Automatically hide word candidate list when inactive. Change-Id: Ifa95ae8a7c47a96719ffdc2929601ff2ef9c0d2e Reviewed-by: Gordan Markus <gordan.markus@pelagicore.com> Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r--src/virtualkeyboard/abstractinputmethod.cpp18
-rw-r--r--src/virtualkeyboard/abstractinputmethod.h1
-rw-r--r--src/virtualkeyboard/content/components/Keyboard.qml56
-rw-r--r--src/virtualkeyboard/doc/src/qtvirtualkeyboard-index.qdoc4
-rw-r--r--src/virtualkeyboard/hunspellinputmethod.cpp23
-rw-r--r--src/virtualkeyboard/hunspellinputmethod.h1
-rw-r--r--src/virtualkeyboard/hunspellinputmethod_p.cpp8
-rw-r--r--src/virtualkeyboard/hunspellinputmethod_p.h7
-rw-r--r--src/virtualkeyboard/hunspellworker.cpp30
-rw-r--r--src/virtualkeyboard/hunspellworker.h4
-rw-r--r--src/virtualkeyboard/inputengine.cpp67
-rw-r--r--src/virtualkeyboard/inputengine.h1
-rw-r--r--src/virtualkeyboard/inputmethod.cpp20
-rw-r--r--src/virtualkeyboard/openwnninputmethod.cpp24
-rw-r--r--src/virtualkeyboard/plugin.cpp1
-rw-r--r--src/virtualkeyboard/selectionlistmodel.cpp11
-rw-r--r--src/virtualkeyboard/selectionlistmodel.h4
-rw-r--r--src/virtualkeyboard/settings.cpp36
-rw-r--r--src/virtualkeyboard/settings.h8
-rw-r--r--src/virtualkeyboard/styles/styles_plugin.cpp2
-rw-r--r--src/virtualkeyboard/virtualkeyboardsettings.cpp73
-rw-r--r--src/virtualkeyboard/virtualkeyboardsettings.h25
-rw-r--r--tests/auto/inputpanel/data/inputpanel/inputpanel.qml17
-rw-r--r--tests/auto/inputpanel/data/tst_inputpanel.qml43
24 files changed, 412 insertions, 72 deletions
diff --git a/src/virtualkeyboard/abstractinputmethod.cpp b/src/virtualkeyboard/abstractinputmethod.cpp
index 05c60e79..0e53341a 100644
--- a/src/virtualkeyboard/abstractinputmethod.cpp
+++ b/src/virtualkeyboard/abstractinputmethod.cpp
@@ -274,8 +274,13 @@ bool AbstractInputMethod::reselect(int cursorPosition, const InputEngine::Resele
Returns the list of selection lists used by this input method.
This method is called by input engine when the input method is being
- activated. The input method can reserve the selection lists for its use
- by returning a list of selection list types required.
+ activated and every time the input method hints are updated. The input method
+ can reserve selection lists by returning the desired selection list types.
+
+ The input method may request the input engine to update the selection lists
+ at any time by emitting selectionListsChanged() signal. This signal will
+ trigger a call to this method, allowing the input method to update the selection
+ list types.
*/
/*!
@@ -314,4 +319,13 @@ bool AbstractInputMethod::reselect(int cursorPosition, const InputEngine::Resele
in the selection list identified by \a type.
*/
+/*!
+ \fn void AbstractInputMethod::selectionListsChanged()
+ \since QtQuick.VirtualKeyboard 2.2
+
+ The input method emits this signal when the selection list types have
+ changed. This signal will trigger a call to selectionLists() method,
+ allowing the input method to update the selection list types.
+*/
+
} // namespace QtVirtualKeyboard
diff --git a/src/virtualkeyboard/abstractinputmethod.h b/src/virtualkeyboard/abstractinputmethod.h
index 168245de..f3157145 100644
--- a/src/virtualkeyboard/abstractinputmethod.h
+++ b/src/virtualkeyboard/abstractinputmethod.h
@@ -79,6 +79,7 @@ public:
signals:
void selectionListChanged(int type);
void selectionListActiveItemChanged(int type, int index);
+ void selectionListsChanged();
public slots:
virtual void reset();
diff --git a/src/virtualkeyboard/content/components/Keyboard.qml b/src/virtualkeyboard/content/components/Keyboard.qml
index a1430a21..27d66d2a 100644
--- a/src/virtualkeyboard/content/components/Keyboard.qml
+++ b/src/virtualkeyboard/content/components/Keyboard.qml
@@ -31,7 +31,7 @@ import QtQuick 2.0
import QtQuick.Layouts 1.0
import QtQuick.VirtualKeyboard 2.1
import QtQuick.VirtualKeyboard.Styles 2.1
-import QtQuick.VirtualKeyboard.Settings 2.1
+import QtQuick.VirtualKeyboard.Settings 2.2
import Qt.labs.folderlistmodel 2.0
Item {
@@ -82,12 +82,13 @@ Item {
}
width: keyboardBackground.width
- height: wordCandidateView.height + keyboardBackground.height
+ height: keyboardBackground.height + (VirtualKeyboardSettings.wordCandidateList.alwaysVisible ? wordCandidateView.height : 0)
onActiveChanged: {
hideLanguagePopup()
if (active && symbolMode && !preferNumbers)
symbolMode = false
keyboardInputArea.reset()
+ wordCandidateViewAutoHideTimer.stop()
}
onActiveKeyChanged: {
if (InputContext.inputEngine.activeKey !== Qt.Key_unknown)
@@ -465,7 +466,7 @@ Item {
Binding {
target: InputContext
property: "keyboardRectangle"
- value: Qt.rect(keyboard.x, keyboard.y, keyboard.width, keyboard.height)
+ value: Qt.rect(keyboard.x, keyboard.y + wordCandidateView.currentYOffset, keyboard.width, keyboard.height - wordCandidateView.currentYOffset)
when: keyboard.active && !InputContext.animating
}
Binding {
@@ -544,9 +545,15 @@ Item {
id: wordCandidateView
objectName: "wordCandidateView"
clip: true
+ z: -2
+ property bool empty: true
+ readonly property bool visibleCondition: (((!wordCandidateView.empty || wordCandidateViewAutoHideTimer.running) &&
+ InputContext.inputEngine.wordCandidateListVisibleHint) || VirtualKeyboardSettings.wordCandidateList.alwaysVisible) &&
+ keyboard.active
+ readonly property real visibleYOffset: VirtualKeyboardSettings.wordCandidateList.alwaysVisible ? 0 : -height
+ readonly property real currentYOffset: visibleCondition || wordCandidateViewTransition.running ? visibleYOffset : 0
height: Math.round(style.selectionListHeight)
anchors.left: parent.left
- anchors.top: parent.top
anchors.right: parent.right
spacing: 0
orientation: ListView.Horizontal
@@ -564,6 +571,24 @@ Item {
target: wordCandidateView.model ? wordCandidateView.model : null
onActiveItemChanged: wordCandidateView.currentIndex = index
onItemSelected: if (wordCandidateView.currentItem) soundEffect.play(wordCandidateView.currentItem.soundEffect)
+ onCountChanged: {
+ var empty = wordCandidateView.model.count === 0
+ if (empty)
+ wordCandidateViewAutoHideTimer.restart()
+ wordCandidateView.empty = empty
+ }
+ }
+ Connections {
+ target: InputContext
+ onInputItemChanged: wordCandidateViewAutoHideTimer.stop()
+ }
+ Connections {
+ target: InputContext.inputEngine
+ onWordCandidateListVisibleHintChanged: wordCandidateViewAutoHideTimer.stop()
+ }
+ Timer {
+ id: wordCandidateViewAutoHideTimer
+ interval: VirtualKeyboardSettings.wordCandidateList.autoHideDelay
}
Loader {
sourceComponent: style.selectionListBackground
@@ -574,6 +599,27 @@ Item {
id: defaultHighlight
Item {}
}
+ states: State {
+ name: "visible"
+ when: wordCandidateView.visibleCondition
+ PropertyChanges {
+ target: wordCandidateView
+ y: wordCandidateView.visibleYOffset
+ }
+ }
+ transitions: Transition {
+ id: wordCandidateViewTransition
+ to: "visible"
+ enabled: !InputContext.animating && !VirtualKeyboardSettings.wordCandidateList.alwaysVisible
+ reversible: true
+ ParallelAnimation {
+ NumberAnimation {
+ properties: "y"
+ duration: 250
+ easing.type: Easing.InOutQuad
+ }
+ }
+ }
}
Item {
@@ -625,8 +671,8 @@ Item {
id: keyboardBackground
z: -1
anchors.left: parent.left
- anchors.top: wordCandidateView.bottom
anchors.right: parent.right
+ anchors.bottom: parent.bottom
height: keyboardInnerContainer.height
sourceComponent: style.keyboardBackground
diff --git a/src/virtualkeyboard/doc/src/qtvirtualkeyboard-index.qdoc b/src/virtualkeyboard/doc/src/qtvirtualkeyboard-index.qdoc
index 94339df7..4a84c940 100644
--- a/src/virtualkeyboard/doc/src/qtvirtualkeyboard-index.qdoc
+++ b/src/virtualkeyboard/doc/src/qtvirtualkeyboard-index.qdoc
@@ -133,10 +133,10 @@ end.
The QML types can be imported into your application using the following
import statements in your .qml file:
- \badcode
+ \code
import QtQuick.VirtualKeyboard 2.0
import QtQuick.VirtualKeyboard.Styles 2.0
- import QtQuick.VirtualKeyboard.Settings 2.0
+ import QtQuick.VirtualKeyboard.Settings 2.2
\endcode
Styling:
diff --git a/src/virtualkeyboard/hunspellinputmethod.cpp b/src/virtualkeyboard/hunspellinputmethod.cpp
index 5e8be4d3..5cd88c2e 100644
--- a/src/virtualkeyboard/hunspellinputmethod.cpp
+++ b/src/virtualkeyboard/hunspellinputmethod.cpp
@@ -98,6 +98,10 @@ bool HunspellInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::Keyboar
default:
if (inputMethodHints.testFlag(Qt::ImhNoPredictiveText))
break;
+ if (d->dictionaryState == HunspellInputMethodPrivate::DictionaryNotLoaded) {
+ update();
+ break;
+ }
if (text.length() > 0) {
QChar c = text.at(0);
bool addToWord = d->isValidInputChar(c) && (!d->word.isEmpty() || !d->isJoiner(c));
@@ -157,6 +161,10 @@ bool HunspellInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::Keyboar
QList<SelectionListModel::Type> HunspellInputMethod::selectionLists()
{
+ Q_D(const HunspellInputMethod);
+ Qt::InputMethodHints inputMethodHints = inputContext()->inputMethodHints();
+ if (d->dictionaryState != HunspellInputMethodPrivate::DictionaryReady || inputMethodHints.testFlag(Qt::ImhNoPredictiveText) || inputMethodHints.testFlag(Qt::ImhHiddenText))
+ return QList<SelectionListModel::Type>();
return QList<SelectionListModel::Type>() << SelectionListModel::WordCandidateList;
}
@@ -205,6 +213,9 @@ bool HunspellInputMethod::reselect(int cursorPosition, const InputEngine::Resele
Q_D(HunspellInputMethod);
Q_ASSERT(d->word.isEmpty());
+ if (d->dictionaryState == HunspellInputMethodPrivate::DictionaryNotLoaded)
+ return false;
+
InputContext *ic = inputContext();
if (!ic)
return false;
@@ -299,6 +310,10 @@ void HunspellInputMethod::update()
void HunspellInputMethod::updateSuggestions(const QStringList &wordList, int activeWordIndex)
{
Q_D(HunspellInputMethod);
+ if (d->dictionaryState == HunspellInputMethodPrivate::DictionaryNotLoaded) {
+ update();
+ return;
+ }
d->wordCandidates.clear();
d->wordCandidates.append(wordList);
// Make sure the exact match is up-to-date
@@ -309,4 +324,12 @@ void HunspellInputMethod::updateSuggestions(const QStringList &wordList, int act
emit selectionListActiveItemChanged(SelectionListModel::WordCandidateList, d->activeWordIndex);
}
+void HunspellInputMethod::dictionaryLoadCompleted(bool success)
+{
+ Q_D(HunspellInputMethod);
+ d->dictionaryState = success ? HunspellInputMethodPrivate::DictionaryReady :
+ HunspellInputMethodPrivate::DictionaryNotLoaded;
+ emit selectionListsChanged();
+}
+
} // namespace QtVirtualKeyboard
diff --git a/src/virtualkeyboard/hunspellinputmethod.h b/src/virtualkeyboard/hunspellinputmethod.h
index 1aa12dce..9faeff5c 100644
--- a/src/virtualkeyboard/hunspellinputmethod.h
+++ b/src/virtualkeyboard/hunspellinputmethod.h
@@ -64,6 +64,7 @@ public:
protected slots:
void updateSuggestions(const QStringList &wordList, int activeWordIndex);
+ void dictionaryLoadCompleted(bool success);
};
} // namespace QtVirtualKeyboard
diff --git a/src/virtualkeyboard/hunspellinputmethod_p.cpp b/src/virtualkeyboard/hunspellinputmethod_p.cpp
index 34f343d3..2512337d 100644
--- a/src/virtualkeyboard/hunspellinputmethod_p.cpp
+++ b/src/virtualkeyboard/hunspellinputmethod_p.cpp
@@ -53,7 +53,8 @@ HunspellInputMethodPrivate::HunspellInputMethodPrivate(HunspellInputMethod *q_pt
activeWordIndex(-1),
wordCompletionPoint(2),
ignoreUpdate(false),
- autoSpaceAllowed(false)
+ autoSpaceAllowed(false),
+ dictionaryState(DictionaryNotLoaded)
{
if (hunspellWorker)
hunspellWorker->start();
@@ -65,6 +66,7 @@ HunspellInputMethodPrivate::~HunspellInputMethodPrivate()
bool HunspellInputMethodPrivate::createHunspell(const QString &locale)
{
+ Q_Q(HunspellInputMethod);
if (!hunspellWorker)
return false;
if (this->locale != locale) {
@@ -90,6 +92,8 @@ bool HunspellInputMethodPrivate::createHunspell(const QString &locale)
searchPaths.append(defaultPath);
}
QSharedPointer<HunspellLoadDictionaryTask> loadDictionaryTask(new HunspellLoadDictionaryTask(locale, searchPaths));
+ QObject::connect(loadDictionaryTask.data(), &HunspellLoadDictionaryTask::completed, q, &HunspellInputMethod::dictionaryLoadCompleted);
+ dictionaryState = HunspellInputMethodPrivate::DictionaryLoading;
hunspellWorker->addTask(loadDictionaryTask);
this->locale = locale;
}
@@ -110,7 +114,7 @@ void HunspellInputMethodPrivate::reset()
bool HunspellInputMethodPrivate::updateSuggestions()
{
bool wordCandidateListChanged = false;
- if (!word.isEmpty()) {
+ if (!word.isEmpty() && dictionaryState != HunspellInputMethodPrivate::DictionaryNotLoaded) {
if (hunspellWorker)
hunspellWorker->removeAllTasksExcept<HunspellLoadDictionaryTask>();
if (wordCandidates.isEmpty()) {
diff --git a/src/virtualkeyboard/hunspellinputmethod_p.h b/src/virtualkeyboard/hunspellinputmethod_p.h
index 1a56defa..a73273b2 100644
--- a/src/virtualkeyboard/hunspellinputmethod_p.h
+++ b/src/virtualkeyboard/hunspellinputmethod_p.h
@@ -43,6 +43,12 @@ public:
HunspellInputMethodPrivate(HunspellInputMethod *q_ptr);
~HunspellInputMethodPrivate();
+ enum DictionaryState {
+ DictionaryNotLoaded,
+ DictionaryLoading,
+ DictionaryReady
+ };
+
bool createHunspell(const QString &locale);
void reset();
bool updateSuggestions();
@@ -61,6 +67,7 @@ public:
int wordCompletionPoint;
bool ignoreUpdate;
bool autoSpaceAllowed;
+ DictionaryState dictionaryState;
};
} // namespace QtVirtualKeyboard
diff --git a/src/virtualkeyboard/hunspellworker.cpp b/src/virtualkeyboard/hunspellworker.cpp
index 7c325e05..1a6d18ef 100644
--- a/src/virtualkeyboard/hunspellworker.cpp
+++ b/src/virtualkeyboard/hunspellworker.cpp
@@ -88,26 +88,26 @@ void HunspellLoadDictionaryTask::run()
affPath.clear();
}
- if (affPath.isEmpty() || dicPath.isEmpty()) {
+ if (!affPath.isEmpty() && !dicPath.isEmpty()) {
VIRTUALKEYBOARD_DEBUG() << "Hunspell dictionary is missing for the" << locale << "language. Search paths" << searchPaths;
- return;
- }
-
- *hunspellPtr = Hunspell_create(affPath.toUtf8().constData(), dicPath.toUtf8().constData());
- if (*hunspellPtr) {
- /* Make sure the encoding used by the dictionary is supported
- by the QTextCodec.
- */
- if (!QTextCodec::codecForName(Hunspell_get_dic_encoding(*hunspellPtr))) {
- qWarning() << "The Hunspell dictionary" << dicPath << "cannot be used because it uses an unknown text codec" << QString(Hunspell_get_dic_encoding(*hunspellPtr));
- Hunspell_destroy(*hunspellPtr);
- *hunspellPtr = 0;
+ *hunspellPtr = Hunspell_create(affPath.toUtf8().constData(), dicPath.toUtf8().constData());
+ if (*hunspellPtr) {
+ /* Make sure the encoding used by the dictionary is supported
+ by the QTextCodec.
+ */
+ if (!QTextCodec::codecForName(Hunspell_get_dic_encoding(*hunspellPtr))) {
+ qWarning() << "The Hunspell dictionary" << dicPath << "cannot be used because it uses an unknown text codec" << QString(Hunspell_get_dic_encoding(*hunspellPtr));
+ Hunspell_destroy(*hunspellPtr);
+ *hunspellPtr = 0;
+ }
}
- }
#ifdef QT_VIRTUALKEYBOARD_DEBUG
- VIRTUALKEYBOARD_DEBUG() << "HunspellLoadDictionaryTask::run(): time:" << perf.elapsed() << "ms";
+ VIRTUALKEYBOARD_DEBUG() << "HunspellLoadDictionaryTask::run(): time:" << perf.elapsed() << "ms";
#endif
+ }
+
+ emit completed(*hunspellPtr != 0);
}
/*!
diff --git a/src/virtualkeyboard/hunspellworker.h b/src/virtualkeyboard/hunspellworker.h
index 73e2c187..71025b91 100644
--- a/src/virtualkeyboard/hunspellworker.h
+++ b/src/virtualkeyboard/hunspellworker.h
@@ -65,6 +65,10 @@ public:
void run();
+signals:
+ void completed(bool success);
+
+public:
Hunhandle **hunspellPtr;
const QString locale;
const QStringList searchPaths;
diff --git a/src/virtualkeyboard/inputengine.cpp b/src/virtualkeyboard/inputengine.cpp
index f9c447c6..7965f06d 100644
--- a/src/virtualkeyboard/inputengine.cpp
+++ b/src/virtualkeyboard/inputengine.cpp
@@ -157,6 +157,7 @@ InputEngine::InputEngine(InputContext *parent) :
if (d->inputContext) {
connect(d->inputContext, SIGNAL(shiftChanged()), SLOT(shiftChanged()));
connect(d->inputContext, SIGNAL(localeChanged()), SLOT(update()));
+ QObject::connect(d->inputContext, &InputContext::inputMethodHintsChanged, this, &InputEngine::updateSelectionListModels);
}
d->defaultInputMethod = new DefaultInputMethod(this);
if (d->defaultInputMethod)
@@ -364,43 +365,18 @@ void InputEngine::setInputMethod(AbstractInputMethod *inputMethod)
if (d->inputMethod != inputMethod) {
update();
if (d->inputMethod) {
+ QObject::disconnect(d->inputMethod.data(), &AbstractInputMethod::selectionListsChanged, this, &InputEngine::updateSelectionListModels);
d->inputMethod->setInputEngine(0);
}
d->inputMethod = inputMethod;
if (d->inputMethod) {
d->inputMethod->setInputEngine(this);
+ QObject::connect(d->inputMethod.data(), &AbstractInputMethod::selectionListsChanged, this, &InputEngine::updateSelectionListModels);
// Set current text case
d->inputMethod->setTextCase(d->textCase);
- // Allocate selection lists for the input method
- const QList<SelectionListModel::Type> activeSelectionLists = d->inputMethod->selectionLists();
- QList<SelectionListModel::Type> inactiveSelectionLists = d->selectionListModels.keys();
- for (const SelectionListModel::Type &selectionListType : activeSelectionLists) {
- auto it = d->selectionListModels.find(selectionListType);
- if (it == d->selectionListModels.end()) {
- it = d->selectionListModels.insert(selectionListType, new SelectionListModel(this));
- if (selectionListType == SelectionListModel::WordCandidateList) {
- emit wordCandidateListModelChanged();
- }
- }
- it.value()->setDataSource(inputMethod, selectionListType);
- if (selectionListType == SelectionListModel::WordCandidateList) {
- emit wordCandidateListVisibleHintChanged();
- }
- inactiveSelectionLists.removeAll(selectionListType);
- }
-
- // Deallocate inactive selection lists
- for (const SelectionListModel::Type &selectionListType : qAsConst(inactiveSelectionLists)) {
- const auto it = d->selectionListModels.constFind(selectionListType);
- if (it != d->selectionListModels.cend()) {
- it.value()->setDataSource(0, selectionListType);
- if (selectionListType == SelectionListModel::WordCandidateList) {
- emit wordCandidateListVisibleHintChanged();
- }
- }
- }
+ updateSelectionListModels();
}
emit inputMethodChanged();
emit inputModesChanged();
@@ -644,6 +620,41 @@ void InputEngine::shiftChanged()
/*!
\internal
*/
+void InputEngine::updateSelectionListModels()
+{
+ Q_D(InputEngine);
+ QList<SelectionListModel::Type> inactiveSelectionLists = d->selectionListModels.keys();
+ if (d->inputMethod) {
+ // Allocate selection lists for the input method
+ const QList<SelectionListModel::Type> activeSelectionLists = d->inputMethod->selectionLists();
+ for (const SelectionListModel::Type &selectionListType : activeSelectionLists) {
+ auto it = d->selectionListModels.find(selectionListType);
+ if (it == d->selectionListModels.end()) {
+ it = d->selectionListModels.insert(selectionListType, new SelectionListModel(this));
+ if (selectionListType == SelectionListModel::WordCandidateList)
+ emit wordCandidateListModelChanged();
+ }
+ it.value()->setDataSource(d->inputMethod, selectionListType);
+ if (selectionListType == SelectionListModel::WordCandidateList)
+ emit wordCandidateListVisibleHintChanged();
+ inactiveSelectionLists.removeAll(selectionListType);
+ }
+ }
+
+ // Deallocate inactive selection lists
+ for (const SelectionListModel::Type &selectionListType : qAsConst(inactiveSelectionLists)) {
+ const auto it = d->selectionListModels.constFind(selectionListType);
+ if (it != d->selectionListModels.cend()) {
+ it.value()->setDataSource(0, selectionListType);
+ if (selectionListType == SelectionListModel::WordCandidateList)
+ emit wordCandidateListVisibleHintChanged();
+ }
+ }
+}
+
+/*!
+ \internal
+*/
void InputEngine::timerEvent(QTimerEvent *timerEvent)
{
Q_D(InputEngine);
diff --git a/src/virtualkeyboard/inputengine.h b/src/virtualkeyboard/inputengine.h
index 266541fb..7551d754 100644
--- a/src/virtualkeyboard/inputengine.h
+++ b/src/virtualkeyboard/inputengine.h
@@ -136,6 +136,7 @@ private slots:
void reset();
void update();
void shiftChanged();
+ void updateSelectionListModels();
protected:
void timerEvent(QTimerEvent *timerEvent);
diff --git a/src/virtualkeyboard/inputmethod.cpp b/src/virtualkeyboard/inputmethod.cpp
index 7c91ab2f..b9e120ff 100644
--- a/src/virtualkeyboard/inputmethod.cpp
+++ b/src/virtualkeyboard/inputmethod.cpp
@@ -121,9 +121,14 @@ namespace QtVirtualKeyboard {
Returns the list of selection types used for this input method.
- This method is called by the input engine when the input method is being
- activated. The input method can reserve the selection lists for its use
- by returning a list of selection list types required.
+ This method is called by input engine when the input method is being
+ activated and every time the input method hints are updated. The input method
+ can reserve selection lists by returning the desired selection list types.
+
+ The input method may request the input engine to update the selection lists
+ at any time by emitting selectionListsChanged() signal. This signal will
+ trigger a call to this method, allowing the input method to update the selection
+ list types.
*/
/*!
@@ -163,6 +168,15 @@ namespace QtVirtualKeyboard {
*/
/*!
+ \qmlsignal InputMethod::selectionListsChanged()
+ \since QtQuick.VirtualKeyboard 2.2
+
+ The input method emits this signal when the selection list types have
+ changed. This signal will trigger a call to selectionLists() method,
+ allowing the input method to update the selection list types.
+*/
+
+/*!
\qmlmethod list<int> InputMethod::patternRecognitionModes()
\since QtQuick.VirtualKeyboard 2.0
diff --git a/src/virtualkeyboard/openwnninputmethod.cpp b/src/virtualkeyboard/openwnninputmethod.cpp
index 8e5a1aaa..cb5a88f9 100644
--- a/src/virtualkeyboard/openwnninputmethod.cpp
+++ b/src/virtualkeyboard/openwnninputmethod.cpp
@@ -356,7 +356,7 @@ public:
void fitInputType()
{
- enablePrediction = true;
+ Q_Q(OpenWnnInputMethod);
enableConverter = true;
Qt::InputMethodHints inputMethodHints = inputEngine->inputContext()->inputMethodHints();
@@ -370,13 +370,17 @@ public:
enableConverter = false;
}
- if (inputMethodHints.testFlag(Qt::ImhHiddenText) ||
- inputMethodHints.testFlag(Qt::ImhSensitiveData)) {
- enablePrediction = false;
- }
-
- if (inputMethodHints.testFlag(Qt::ImhNoPredictiveText)) {
- enablePrediction = false;
+ if (inputMode != InputEngine::Hiragana ||
+ inputMethodHints.testFlag(Qt::ImhHiddenText) ||
+ inputMethodHints.testFlag(Qt::ImhSensitiveData) ||
+ inputMethodHints.testFlag(Qt::ImhNoPredictiveText)) {
+ if (enablePrediction) {
+ enablePrediction = false;
+ emit q->selectionListsChanged();
+ }
+ } else if (inputMode == InputEngine::Hiragana && !enablePrediction) {
+ enablePrediction = true;
+ emit q->selectionListsChanged();
}
activeConvertType = CONVERT_TYPE_NONE;
@@ -640,6 +644,7 @@ bool OpenWnnInputMethod::setInputMode(const QString &locale, InputEngine::InputM
break;
}
d->inputMode = inputMode;
+ d->fitInputType();
return true;
}
@@ -758,6 +763,9 @@ bool OpenWnnInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::Keyboard
QList<SelectionListModel::Type> OpenWnnInputMethod::selectionLists()
{
+ Q_D(OpenWnnInputMethod);
+ if (!d->enablePrediction)
+ return QList<SelectionListModel::Type>();
return QList<SelectionListModel::Type>() << SelectionListModel::WordCandidateList;
}
diff --git a/src/virtualkeyboard/plugin.cpp b/src/virtualkeyboard/plugin.cpp
index 9b3bd3b7..5349e735 100644
--- a/src/virtualkeyboard/plugin.cpp
+++ b/src/virtualkeyboard/plugin.cpp
@@ -187,6 +187,7 @@ QPlatformInputContext *QVirtualKeyboardPlugin::create(const QString &system, con
qmlRegisterSingletonType<VirtualKeyboardSettings>(pluginSettingsUri, 1, 2, "VirtualKeyboardSettings", VirtualKeyboardSettings::registerSettingsModule);
qmlRegisterSingletonType<VirtualKeyboardSettings>(pluginSettingsUri, 2, 0, "VirtualKeyboardSettings", VirtualKeyboardSettings::registerSettingsModule);
qmlRegisterSingletonType<VirtualKeyboardSettings>(pluginSettingsUri, 2, 1, "VirtualKeyboardSettings", VirtualKeyboardSettings::registerSettingsModule);
+ qmlRegisterUncreatableType<WordCandidateListSettings>(pluginSettingsUri, 2, 2, "WordCandidateListSettings", QLatin1String("Cannot create word candidate list settings"));
const QString path(QStringLiteral("qrc:///QtQuick/VirtualKeyboard/content/"));
qmlRegisterType(QUrl(path + QLatin1String("InputPanel.qml")), pluginUri, 1, 0, "InputPanel");
diff --git a/src/virtualkeyboard/selectionlistmodel.cpp b/src/virtualkeyboard/selectionlistmodel.cpp
index 88f79ff7..5d3ac375 100644
--- a/src/virtualkeyboard/selectionlistmodel.cpp
+++ b/src/virtualkeyboard/selectionlistmodel.cpp
@@ -192,6 +192,15 @@ QHash<int,QByteArray> SelectionListModel::roleNames() const
return d->roles;
}
+/*!
+ \internal
+*/
+int SelectionListModel::count() const
+{
+ Q_D(const SelectionListModel);
+ return d->rowCount;
+}
+
/*! \qmlmethod void SelectionListModel::selectItem(int index)
This method should be called when the user selects an item at position
@@ -249,6 +258,8 @@ void SelectionListModel::selectionListChanged(int type)
d->rowCount = 0;
endResetModel();
}
+ if (d->rowCount != oldCount)
+ emit countChanged();
}
}
diff --git a/src/virtualkeyboard/selectionlistmodel.h b/src/virtualkeyboard/selectionlistmodel.h
index e78e64d4..47153558 100644
--- a/src/virtualkeyboard/selectionlistmodel.h
+++ b/src/virtualkeyboard/selectionlistmodel.h
@@ -44,6 +44,7 @@ class SelectionListModel : public QAbstractListModel
Q_ENUMS(Type)
Q_ENUMS(Role)
Q_DECLARE_PRIVATE(SelectionListModel)
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
explicit SelectionListModel(QObject *parent = 0);
@@ -65,10 +66,13 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QHash<int,QByteArray> roleNames() const;
+ int count() const;
+
Q_INVOKABLE void selectItem(int index);
Q_INVOKABLE QVariant dataAt(int index, int role = Qt::DisplayRole) const;
signals:
+ void countChanged();
void activeItemChanged(int index);
void itemSelected(int index);
diff --git a/src/virtualkeyboard/settings.cpp b/src/virtualkeyboard/settings.cpp
index f01c506d..55faca8c 100644
--- a/src/virtualkeyboard/settings.cpp
+++ b/src/virtualkeyboard/settings.cpp
@@ -42,7 +42,9 @@ public:
locale(),
availableLocales(),
activeLocales(),
- layoutPath()
+ layoutPath(),
+ wclAutoHideDelay(5000),
+ wclAlwaysVisible(false)
{}
QString style;
@@ -51,6 +53,8 @@ public:
QStringList availableLocales;
QStringList activeLocales;
QUrl layoutPath;
+ int wclAutoHideDelay;
+ bool wclAlwaysVisible;
};
static QScopedPointer<Settings> s_settingsInstance;
@@ -162,4 +166,34 @@ void Settings::setLayoutPath(const QUrl &layoutPath)
}
}
+int Settings::wclAutoHideDelay() const
+{
+ Q_D(const Settings);
+ return d->wclAutoHideDelay;
+}
+
+void Settings::setWclAutoHideDelay(int wclAutoHideDelay)
+{
+ Q_D(Settings);
+ if (d->wclAutoHideDelay != wclAutoHideDelay) {
+ d->wclAutoHideDelay = wclAutoHideDelay;
+ emit wclAutoHideDelayChanged();
+ }
+}
+
+bool Settings::wclAlwaysVisible() const
+{
+ Q_D(const Settings);
+ return d->wclAlwaysVisible;
+}
+
+void Settings::setWclAlwaysVisible(bool wclAlwaysVisible)
+{
+ Q_D(Settings);
+ if (d->wclAlwaysVisible != wclAlwaysVisible) {
+ d->wclAlwaysVisible = wclAlwaysVisible;
+ emit wclAlwaysVisibleChanged();
+ }
+}
+
} // namespace QtVirtualKeyboard
diff --git a/src/virtualkeyboard/settings.h b/src/virtualkeyboard/settings.h
index eeeff7e4..3bc65fbb 100644
--- a/src/virtualkeyboard/settings.h
+++ b/src/virtualkeyboard/settings.h
@@ -66,6 +66,12 @@ public:
QUrl layoutPath() const;
void setLayoutPath(const QUrl &layoutPath);
+ int wclAutoHideDelay() const;
+ void setWclAutoHideDelay(int wclAutoHideDelay);
+
+ bool wclAlwaysVisible() const;
+ void setWclAlwaysVisible(bool wclAlwaysVisible);
+
signals:
void styleChanged();
void styleNameChanged();
@@ -73,6 +79,8 @@ signals:
void availableLocalesChanged();
void activeLocalesChanged();
void layoutPathChanged();
+ void wclAutoHideDelayChanged();
+ void wclAlwaysVisibleChanged();
};
} // namespace QtVirtualKeyboard
diff --git a/src/virtualkeyboard/styles/styles_plugin.cpp b/src/virtualkeyboard/styles/styles_plugin.cpp
index 975ab401..d6e17f5c 100644
--- a/src/virtualkeyboard/styles/styles_plugin.cpp
+++ b/src/virtualkeyboard/styles/styles_plugin.cpp
@@ -43,7 +43,7 @@
The QML types can be imported into your application using the following
import statements in your .qml file:
- \badcode
+ \code
import QtQuick.VirtualKeyboard.Styles 2.0
\endcode
*/
diff --git a/src/virtualkeyboard/virtualkeyboardsettings.cpp b/src/virtualkeyboard/virtualkeyboardsettings.cpp
index 97554001..bb832a2e 100644
--- a/src/virtualkeyboard/virtualkeyboardsettings.cpp
+++ b/src/virtualkeyboard/virtualkeyboardsettings.cpp
@@ -42,7 +42,8 @@ class VirtualKeyboardSettingsPrivate : public QObjectPrivate
public:
VirtualKeyboardSettingsPrivate() :
QObjectPrivate(),
- engine() {}
+ engine()
+ {}
QString buildStyleImportPath(const QString &path, const QString &name) const
{
@@ -90,10 +91,11 @@ public:
}
QPointer<QQmlEngine> engine;
+ WordCandidateListSettings wordCandidateListSettings;
};
/*!
- \qmlmodule QtQuick.VirtualKeyboard.Settings 2.0
+ \qmlmodule QtQuick.VirtualKeyboard.Settings 2.2
\title Qt Quick Virtual Keyboard Settings QML Types
\ingroup qmlmodules
@@ -102,8 +104,8 @@ public:
The QML types can be imported into your application using the following
import statements in your .qml file:
- \badcode
- import QtQuick.VirtualKeyboard.Settings 2.0
+ \code
+ import QtQuick.VirtualKeyboard.Settings 2.2
\endcode
*/
@@ -161,6 +163,8 @@ VirtualKeyboardSettings::VirtualKeyboardSettings(QQmlEngine *engine) :
connect(settings, SIGNAL(availableLocalesChanged()), SIGNAL(availableLocalesChanged()));
connect(settings, SIGNAL(activeLocalesChanged()), SIGNAL(activeLocalesChanged()));
connect(settings, SIGNAL(layoutPathChanged()), SIGNAL(layoutPathChanged()));
+ connect(settings, SIGNAL(wclAutoHideDelayChanged()), &d->wordCandidateListSettings, SIGNAL(autoHideDelayChanged()));
+ connect(settings, SIGNAL(wclAlwaysVisibleChanged()), &d->wordCandidateListSettings, SIGNAL(alwaysVisibleChanged()));
}
/*!
@@ -267,6 +271,12 @@ QStringList VirtualKeyboardSettings::activeLocales() const
return Settings::instance()->activeLocales();
}
+WordCandidateListSettings *VirtualKeyboardSettings::wordCandidateList() const
+{
+ Q_D(const VirtualKeyboardSettings);
+ return const_cast<WordCandidateListSettings *>(&d->wordCandidateListSettings);
+}
+
void VirtualKeyboardSettings::resetStyle()
{
Q_D(VirtualKeyboardSettings);
@@ -346,4 +356,59 @@ void VirtualKeyboardSettings::resetStyle()
used to limit the list of available languages in the application lifetime.
*/
+/*!
+ \since QtQuick.VirtualKeyboard.Settings 2.2
+ \qmlpropertygroup QtQuick.VirtualKeyboard::VirtualKeyboardSettings::wordCandidateList
+ \qmlproperty int QtQuick.VirtualKeyboard::VirtualKeyboardSettings::wordCandidateList.autoHideDelay
+ \qmlproperty bool QtQuick.VirtualKeyboard::VirtualKeyboardSettings::wordCandidateList.alwaysVisible
+
+ \table
+ \header
+ \li Name
+ \li Description
+ \row
+ \li autoHideDelay
+ \li This property defines the delay, in milliseconds, after which the
+ word candidate list is hidden if empty.
+
+ If the value is \c 0, the list is immediately hidden when cleared.
+
+ If the value is \c -1, the list is visible until input focus
+ changes, or the input panel is hidden.
+
+ The default value is \c 5000 milliseconds.
+ \row
+ \li alwaysVisible
+ \li This property defines whether the word candidate list should always
+ remain visible.
+
+ The default value is \c false.
+ \endtable
+*/
+
+WordCandidateListSettings::WordCandidateListSettings(QObject *parent) :
+ QObject(parent)
+{
+}
+
+int WordCandidateListSettings::autoHideDelay() const
+{
+ return Settings::instance()->wclAutoHideDelay();
+}
+
+void WordCandidateListSettings::setAutoHideDelay(int autoHideDelay)
+{
+ Settings::instance()->setWclAutoHideDelay(autoHideDelay);
+}
+
+bool WordCandidateListSettings::alwaysVisible() const
+{
+ return Settings::instance()->wclAlwaysVisible();
+}
+
+void WordCandidateListSettings::setAlwaysVisible(bool alwaysVisible)
+{
+ Settings::instance()->setWclAlwaysVisible(alwaysVisible);
+}
+
} // namespace QtVirtualKeyboard
diff --git a/src/virtualkeyboard/virtualkeyboardsettings.h b/src/virtualkeyboard/virtualkeyboardsettings.h
index b4eae869..397746e0 100644
--- a/src/virtualkeyboard/virtualkeyboardsettings.h
+++ b/src/virtualkeyboard/virtualkeyboardsettings.h
@@ -34,6 +34,7 @@
namespace QtVirtualKeyboard {
+class WordCandidateListSettings;
class VirtualKeyboardSettingsPrivate;
class VirtualKeyboardSettings : public QObject
@@ -46,6 +47,7 @@ class VirtualKeyboardSettings : public QObject
Q_PROPERTY(QString locale READ locale WRITE setLocale NOTIFY localeChanged)
Q_PROPERTY(QStringList availableLocales READ availableLocales NOTIFY availableLocalesChanged)
Q_PROPERTY(QStringList activeLocales READ activeLocales WRITE setActiveLocales NOTIFY activeLocalesChanged)
+ Q_PROPERTY(WordCandidateListSettings *wordCandidateList READ wordCandidateList CONSTANT)
public:
static QObject *registerSettingsModule(QQmlEngine *engine, QJSEngine *jsEngine);
@@ -68,6 +70,8 @@ public:
void setActiveLocales(const QStringList &activeLocales);
QStringList activeLocales() const;
+ WordCandidateListSettings *wordCandidateList() const;
+
signals:
void styleChanged();
void styleNameChanged();
@@ -81,6 +85,27 @@ private:
void resetLayoutPath();
};
+class WordCandidateListSettings : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int autoHideDelay READ autoHideDelay WRITE setAutoHideDelay NOTIFY autoHideDelayChanged)
+ Q_PROPERTY(bool alwaysVisible READ alwaysVisible WRITE setAlwaysVisible NOTIFY alwaysVisibleChanged)
+
+ explicit WordCandidateListSettings(QObject *parent = 0);
+ friend class VirtualKeyboardSettingsPrivate;
+
+public:
+ int autoHideDelay() const;
+ void setAutoHideDelay(int autoHideDelay);
+
+ bool alwaysVisible() const;
+ void setAlwaysVisible(bool alwaysVisible);
+
+signals:
+ void autoHideDelayChanged();
+ void alwaysVisibleChanged();
+};
+
}
#endif // VIRTUALKEYBOARDSETTINGS_H
diff --git a/tests/auto/inputpanel/data/inputpanel/inputpanel.qml b/tests/auto/inputpanel/data/inputpanel/inputpanel.qml
index 1fb37d74..034150be 100644
--- a/tests/auto/inputpanel/data/inputpanel/inputpanel.qml
+++ b/tests/auto/inputpanel/data/inputpanel/inputpanel.qml
@@ -30,7 +30,7 @@
import QtTest 1.0
import QtQuick 2.0
import QtQuick.VirtualKeyboard 2.1
-import QtQuick.VirtualKeyboard.Settings 2.1
+import QtQuick.VirtualKeyboard.Settings 2.2
import "handwriting.js" as Handwriting
import "utils.js" as Utils
@@ -83,6 +83,7 @@ InputPanel {
property alias soundEffectSpy: soundEffectSpy
property alias inputMethodResultSpy: inputMethodResultSpy
property alias wordCandidateListChangedSpy: wordCandidateListChangedSpy
+ property alias wordCandidateListVisibleSpy: wordCandidateListVisibleSpy
property alias shiftStateSpy: shiftStateSpy
signal inputMethodResult(var text)
@@ -164,6 +165,12 @@ InputPanel {
}
SignalSpy {
+ id: wordCandidateListVisibleSpy
+ target: wordCandidateView
+ signalName: "onVisibleConditionChanged"
+ }
+
+ SignalSpy {
id: shiftStateSpy
target: InputContext
signalName: "onShiftChanged"
@@ -207,6 +214,14 @@ InputPanel {
VirtualKeyboardSettings.activeLocales = activeLocales
}
+ function setWclAutoHideDelay(wclAutoHideDelay) {
+ VirtualKeyboardSettings.wordCandidateList.autoHideDelay = wclAutoHideDelay
+ }
+
+ function setWclAlwaysVisible(wclAlwaysVisible) {
+ VirtualKeyboardSettings.wordCandidateList.alwaysVisible = wclAlwaysVisible
+ }
+
function mapInputMode(inputModeName) {
if (inputModeName === "Latin")
return InputEngine.Latin
diff --git a/tests/auto/inputpanel/data/tst_inputpanel.qml b/tests/auto/inputpanel/data/tst_inputpanel.qml
index 9cc1fedb..ffe88cc8 100644
--- a/tests/auto/inputpanel/data/tst_inputpanel.qml
+++ b/tests/auto/inputpanel/data/tst_inputpanel.qml
@@ -78,6 +78,8 @@ Rectangle {
}
function prepareTest(data) {
+ inputPanel.setWclAutoHideDelay(data !== undefined && data.hasOwnProperty("wclAutoHideDelay") ? data.wclAutoHideDelay : 5000)
+ inputPanel.setWclAlwaysVisible(data !== undefined && data.hasOwnProperty("wclAlwaysVisible") && data.wclAlwaysVisible)
container.forceActiveFocus()
if (data !== undefined && data.hasOwnProperty("initText")) {
textInput.text = data.initText
@@ -172,6 +174,14 @@ Rectangle {
property var locale: VirtualKeyboardSettings.locale; \
property var availableLocales: VirtualKeyboardSettings.availableLocales; \
property var activeLocales: VirtualKeyboardSettings.activeLocales }" },
+ { qml: "import QtQuick 2.7; \
+ import QtQuick.VirtualKeyboard.Settings 2.2; \
+ Item { property var styleName: VirtualKeyboardSettings.styleName; \
+ property var locale: VirtualKeyboardSettings.locale; \
+ property var availableLocales: VirtualKeyboardSettings.availableLocales; \
+ property var activeLocales: VirtualKeyboardSettings.activeLocales; \
+ property var wclAutoHideDelay: VirtualKeyboardSettings.wordCandidateList.autoHideDelay; \
+ property var wclAlwaysVisible: VirtualKeyboardSettings.wordCandidateList.alwaysVisible; }" },
]
}
@@ -1569,5 +1579,38 @@ Rectangle {
compare(languagePopupList.visible, false)
}
+
+ function test_wclAutoHide_data() {
+ return [
+ { wclAutoHideDelay: 100, wclAlwaysVisible: false },
+ { wclAutoHideDelay: 0, wclAlwaysVisible: true },
+ { wclAutoHideDelay: 0, wclAlwaysVisible: false },
+ ]
+ }
+
+ function test_wclAutoHide(data) {
+ prepareTest(data)
+ inputPanel.wordCandidateListChangedSpy.clear()
+ Qt.inputMethod.show()
+ waitForRendering(inputPanel)
+ compare(inputPanel.wordCandidateView.visibleCondition, data.wclAlwaysVisible)
+ inputPanel.virtualKeyClick("a")
+ inputPanel.virtualKeyClick("u")
+ inputPanel.virtualKeyClick("t")
+ inputPanel.virtualKeyClick("o")
+ waitForRendering(inputPanel)
+ if (!inputPanel.wordCandidateListVisibleHint)
+ skip("Prediction/spell correction not enabled")
+ inputPanel.wordCandidateListChangedSpy.wait(1000)
+ compare(inputPanel.wordCandidateView.visibleCondition, true)
+ inputPanel.wordCandidateListVisibleSpy.clear()
+ inputPanel.selectionListSelectCurrentItem()
+ if (data.wclAlwaysVisible)
+ wait(data.wclAutoHideDelay + 250)
+ else
+ inputPanel.wordCandidateListVisibleSpy.wait(data.wclAutoHideDelay + 500)
+ waitForRendering(inputPanel)
+ compare(inputPanel.wordCandidateView.visibleCondition, data.wclAlwaysVisible)
+ }
}
}