diff options
Diffstat (limited to 'src/plugins/hunspell/module/hunspellinputmethod.cpp')
-rw-r--r-- | src/plugins/hunspell/module/hunspellinputmethod.cpp | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/src/plugins/hunspell/module/hunspellinputmethod.cpp b/src/plugins/hunspell/module/hunspellinputmethod.cpp new file mode 100644 index 00000000..a066c927 --- /dev/null +++ b/src/plugins/hunspell/module/hunspellinputmethod.cpp @@ -0,0 +1,350 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "hunspellinputmethod_p.h" +#include <QtVirtualKeyboard/qvirtualkeyboardinputcontext.h> +#include <QLoggingCategory> + +QT_BEGIN_NAMESPACE +namespace QtVirtualKeyboard { + +Q_LOGGING_CATEGORY(lcHunspell, "qt.virtualkeyboard.hunspell") + +/*! + \class QtVirtualKeyboard::HunspellInputMethod + \internal +*/ + +HunspellInputMethod::HunspellInputMethod(HunspellInputMethodPrivate &dd, QObject *parent) : + QVirtualKeyboardAbstractInputMethod(dd, parent) +{ +} + +HunspellInputMethod::HunspellInputMethod(QObject *parent) : + QVirtualKeyboardAbstractInputMethod(*new HunspellInputMethodPrivate(this), parent) +{ +} + +HunspellInputMethod::~HunspellInputMethod() +{ +} + +QList<QVirtualKeyboardInputEngine::InputMode> HunspellInputMethod::inputModes(const QString &locale) +{ + QList<QVirtualKeyboardInputEngine::InputMode> result; + switch (QLocale(locale).script()) { + case QLocale::GreekScript: + result.append(QVirtualKeyboardInputEngine::InputMode::Greek); + break; + case QLocale::CyrillicScript: + result.append(QVirtualKeyboardInputEngine::InputMode::Cyrillic); + break; + case QLocale::ArabicScript: + result.append(QVirtualKeyboardInputEngine::InputMode::Arabic); + break; + case QLocale::HebrewScript: + result.append(QVirtualKeyboardInputEngine::InputMode::Hebrew); + break; + default: + break; + } + result.append(QVirtualKeyboardInputEngine::InputMode::Latin); + result.append(QVirtualKeyboardInputEngine::InputMode::Numeric); + return result; +} + +bool HunspellInputMethod::setInputMode(const QString &locale, QVirtualKeyboardInputEngine::InputMode inputMode) +{ + Q_UNUSED(inputMode); + Q_D(HunspellInputMethod); + return d->createHunspell(locale); +} + +bool HunspellInputMethod::setTextCase(QVirtualKeyboardInputEngine::TextCase textCase) +{ + Q_UNUSED(textCase); + return true; +} + +bool HunspellInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::KeyboardModifiers modifiers) +{ + Q_D(HunspellInputMethod); + QVirtualKeyboardInputContext *ic = inputContext(); + Qt::InputMethodHints inputMethodHints = ic->inputMethodHints(); + bool accept = false; + switch (key) { + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Tab: + case Qt::Key_Space: + update(); + break; + case Qt::Key_Backspace: + { + QString word = d->wordCandidates.wordAt(0); + if (!word.isEmpty()) { + word.remove(word.size() - 1, 1); + ic->setPreeditText(word); + if (!word.isEmpty()) { + d->wordCandidates.updateWord(0, word); + if (d->updateSuggestions()) { + emit selectionListChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList); + emit selectionListActiveItemChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList, d->wordCandidates.index()); + } + } else { + d->reset(); + } + accept = true; + } + break; + } + default: + if (inputMethodHints.testFlag(Qt::ImhNoPredictiveText)) + break; + if (d->dictionaryState == HunspellInputMethodPrivate::DictionaryNotLoaded) { + update(); + break; + } + if (text.size() > 0) { + QChar c = text.at(0); + QString word = d->wordCandidates.wordAt(0); + bool addToWord = d->isValidInputChar(c) && (!word.isEmpty() || !d->isJoiner(c)); + if (addToWord) { + QString newText = text; + /* Automatic space insertion. */ + if (word.isEmpty()) { + QString surroundingText = ic->surroundingText(); + int cursorPosition = ic->cursorPosition(); + /* Rules for automatic space insertion: + - Surrounding text is not empty + - Cursor is at the end of the line + - No space before the cursor + - No spefic characters before the cursor; minus and apostrophe + */ + if (!surroundingText.isEmpty() && cursorPosition == surroundingText.size()) { + QChar lastChar = surroundingText.at(cursorPosition - 1); + if (!lastChar.isSpace() && + lastChar != QLatin1Char(Qt::Key_Minus) && + d->isAutoSpaceAllowed()) { + // auto-insertion of space might trigger auto-capitalization + bool wasShiftActive = ic->isShiftActive(); + ic->commit(QLatin1String(" ")); + if (ic->isShiftActive() && !wasShiftActive) + newText = newText.toUpper(); + } + } + } + /* Ignore possible call to update() function when sending initial + pre-edit text. The update is triggered if the text editor has + a selection which the pre-edit text will replace. + */ + d->ignoreUpdate = word.isEmpty(); + word.append(newText); + d->wordCandidates.updateWord(0, word); + ic->setPreeditText(word); + d->ignoreUpdate = false; + if (d->updateSuggestions()) { + emit selectionListChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList); + emit selectionListActiveItemChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList, d->wordCandidates.index()); + } + accept = true; + } else if (text.size() > 1) { + bool addSpace = !word.isEmpty() || d->autoSpaceAllowed; + update(); + d->autoSpaceAllowed = true; + if (addSpace && d->isAutoSpaceAllowed()) + ic->commit(QLatin1String(" ")); + ic->commit(text); + d->autoSpaceAllowed = addSpace; + accept = true; + } else { + update(); + inputContext()->sendKeyClick(key, text, modifiers); + d->autoSpaceAllowed = true; + accept = true; + } + } + break; + } + return accept; +} + +QList<QVirtualKeyboardSelectionListModel::Type> HunspellInputMethod::selectionLists() +{ + Q_D(const HunspellInputMethod); + QVirtualKeyboardInputContext *ic = inputContext(); + if (!ic) + return QList<QVirtualKeyboardSelectionListModel::Type>(); + Qt::InputMethodHints inputMethodHints = ic->inputMethodHints(); + if (d->dictionaryState == HunspellInputMethodPrivate::DictionaryNotLoaded || inputMethodHints.testFlag(Qt::ImhNoPredictiveText) || inputMethodHints.testFlag(Qt::ImhHiddenText)) + return QList<QVirtualKeyboardSelectionListModel::Type>(); + return QList<QVirtualKeyboardSelectionListModel::Type>() << QVirtualKeyboardSelectionListModel::Type::WordCandidateList; +} + +int HunspellInputMethod::selectionListItemCount(QVirtualKeyboardSelectionListModel::Type type) +{ + Q_UNUSED(type); + Q_D(HunspellInputMethod); + return d->wordCandidates.size(); +} + +QVariant HunspellInputMethod::selectionListData(QVirtualKeyboardSelectionListModel::Type type, int index, QVirtualKeyboardSelectionListModel::Role role) +{ + QVariant result; + Q_D(HunspellInputMethod); + switch (role) { + case QVirtualKeyboardSelectionListModel::Role::Display: + result = QVariant(d->wordCandidates.wordAt(index)); + break; + case QVirtualKeyboardSelectionListModel::Role::WordCompletionLength: + { + const QString wordCandidate(d->wordCandidates.wordAt(index)); + const QString word(d->wordCandidates.wordAt(0)); + int wordCompletionLength = wordCandidate.size() - word.size(); + result.setValue((wordCompletionLength > 0 && wordCandidate.startsWith(word)) ? wordCompletionLength : 0); + break; + } + case QVirtualKeyboardSelectionListModel::Role::Dictionary: + { + const QString wordCandidate(d->wordCandidates.wordAt(index)); + QVirtualKeyboardSelectionListModel::DictionaryType dictionaryType = + d->userDictionaryWords && d->userDictionaryWords->contains(wordCandidate) ? + QVirtualKeyboardSelectionListModel::DictionaryType::User : QVirtualKeyboardSelectionListModel::DictionaryType::Default; + result = QVariant(static_cast<int>(dictionaryType)); + break; + } + case QVirtualKeyboardSelectionListModel::Role::CanRemoveSuggestion: + result.setValue(index > 0 && d->wordCandidates.wordFlagsAt(index).testFlag(HunspellWordList::SpellCheckOk)); + break; + default: + result = QVirtualKeyboardAbstractInputMethod::selectionListData(type, index, role); + break; + } + return result; +} + +void HunspellInputMethod::selectionListItemSelected(QVirtualKeyboardSelectionListModel::Type type, int index) +{ + Q_UNUSED(type); + Q_D(HunspellInputMethod); + d->wordCandidates.setIndex(index); + d->addToDictionary(); + QString finalWord = d->wordCandidates.wordAt(index); + reset(); + inputContext()->commit(finalWord); + d->autoSpaceAllowed = true; +} + +bool HunspellInputMethod::selectionListRemoveItem(QVirtualKeyboardSelectionListModel::Type type, int index) +{ + Q_D(HunspellInputMethod); + Q_UNUSED(type); + + if (index <= 0 || index >= d->wordCandidates.size()) + return false; + + QString word = d->wordCandidates.wordAt(index); + d->removeFromDictionary(word); + + return true; +} + +bool HunspellInputMethod::reselect(int cursorPosition, const QVirtualKeyboardInputEngine::ReselectFlags &reselectFlags) +{ + Q_D(HunspellInputMethod); + QString word(d->wordCandidates.wordAt(0)); + Q_ASSERT(word.isEmpty()); + + if (d->dictionaryState == HunspellInputMethodPrivate::DictionaryNotLoaded) + return false; + + QVirtualKeyboardInputContext *ic = inputContext(); + if (!ic) + return false; + + const QString surroundingText = ic->surroundingText(); + int replaceFrom = 0; + + if (reselectFlags.testFlag(QVirtualKeyboardInputEngine::ReselectFlag::WordBeforeCursor)) { + for (int i = cursorPosition - 1; i >= 0; --i) { + QChar c = surroundingText.at(i); + if (!d->isValidInputChar(c)) + break; + word.insert(0, c); + --replaceFrom; + } + + while (replaceFrom < 0 && d->isJoiner(word.at(0))) { + word.remove(0, 1); + ++replaceFrom; + } + } + + if (reselectFlags.testFlag(QVirtualKeyboardInputEngine::ReselectFlag::WordAtCursor) && replaceFrom == 0) + return false; + + if (reselectFlags.testFlag(QVirtualKeyboardInputEngine::ReselectFlag::WordAfterCursor)) { + for (int i = cursorPosition; i < surroundingText.size(); ++i) { + QChar c = surroundingText.at(i); + if (!d->isValidInputChar(c)) + break; + word.append(c); + } + + while (replaceFrom > -word.size()) { + int lastPos = word.size() - 1; + if (!d->isJoiner(word.at(lastPos))) + break; + word.remove(lastPos, 1); + } + } + + if (word.isEmpty()) + return false; + + if (reselectFlags.testFlag(QVirtualKeyboardInputEngine::ReselectFlag::WordAtCursor) && replaceFrom == -word.size()) + return false; + + if (d->isJoiner(word.at(0))) + return false; + + if (d->isJoiner(word.at(word.size() - 1))) + return false; + + d->wordCandidates.updateWord(0, word); + ic->setPreeditText(word, QList<QInputMethodEvent::Attribute>(), replaceFrom, word.size()); + + d->autoSpaceAllowed = false; + if (d->updateSuggestions()) { + emit selectionListChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList); + emit selectionListActiveItemChanged(QVirtualKeyboardSelectionListModel::Type::WordCandidateList, d->wordCandidates.index()); + } + + return true; +} + +void HunspellInputMethod::reset() +{ + Q_D(HunspellInputMethod); + d->reset(); +} + +void HunspellInputMethod::update() +{ + Q_D(HunspellInputMethod); + if (d->ignoreUpdate) + return; + + QString finalWord; + if (!d->wordCandidates.isEmpty()) { + d->addToDictionary(); + finalWord = d->wordCandidates.wordAt(d->wordCandidates.index()); + } + d->reset(); + if (!finalWord.isEmpty()) + inputContext()->commit(finalWord); + d->autoSpaceAllowed = false; +} + +} // namespace QtVirtualKeyboard +QT_END_NAMESPACE |