hunspellinputmethod.cpp 11.62 KiB
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
** $QT_END_LICENSE$
****************************************************************************/
#include "hunspellinputmethod_p.h"
#include "inputcontext.h"
namespace QtVirtualKeyboard {
/*!
    \class QtVirtualKeyboard::HunspellInputMethod
    \internal
HunspellInputMethod::HunspellInputMethod(HunspellInputMethodPrivate &dd, QObject *parent) :
    AbstractInputMethod(dd, parent)
HunspellInputMethod::HunspellInputMethod(QObject *parent) :
    AbstractInputMethod(*new HunspellInputMethodPrivate(this), parent)
HunspellInputMethod::~HunspellInputMethod()
QList<InputEngine::InputMode> HunspellInputMethod::inputModes(const QString &locale)
    QList<InputEngine::InputMode> result;
    switch (QLocale(locale).script()) {
    case QLocale::GreekScript:
        result.append(InputEngine::Greek);
        break;
    case QLocale::CyrillicScript:
        result.append(InputEngine::Cyrillic);
        break;
    default:
        break;
    result.append(InputEngine::Latin);
    result.append(InputEngine::Numeric);
    return result;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
bool HunspellInputMethod::setInputMode(const QString &locale, InputEngine::InputMode inputMode) { Q_UNUSED(inputMode) Q_D(HunspellInputMethod); return d->createHunspell(locale); } bool HunspellInputMethod::setTextCase(InputEngine::TextCase textCase) { Q_UNUSED(textCase) return true; } bool HunspellInputMethod::keyEvent(Qt::Key key, const QString &text, Qt::KeyboardModifiers modifiers) { Q_UNUSED(modifiers) Q_D(HunspellInputMethod); InputContext *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: if (!d->word.isEmpty()) { d->word.remove(d->word.length() - 1, 1); ic->setPreeditText(d->word); if (d->updateSuggestions()) { emit selectionListChanged(SelectionListModel::WordCandidateList); emit selectionListActiveItemChanged(SelectionListModel::WordCandidateList, d->activeWordIndex); } accept = true; } break; 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)); if (addToWord) { /* Automatic space insertion. */ if (d->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.length()) { QChar lastChar = surroundingText.at(cursorPosition - 1); if (!lastChar.isSpace() && lastChar != Qt::Key_Minus && d->isAutoSpaceAllowed()) { ic->commit(" "); } } } /* Ignore possible call to update() function when sending initial
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
pre-edit text. The update is triggered if the text editor has a selection which the pre-edit text will replace. */ d->ignoreUpdate = d->word.isEmpty(); d->word.append(text); ic->setPreeditText(d->word); d->ignoreUpdate = false; if (d->updateSuggestions()) { emit selectionListChanged(SelectionListModel::WordCandidateList); emit selectionListActiveItemChanged(SelectionListModel::WordCandidateList, d->activeWordIndex); } accept = true; } else if (text.length() > 1) { bool addSpace = !d->word.isEmpty() || d->autoSpaceAllowed; update(); d->autoSpaceAllowed = true; if (addSpace && d->isAutoSpaceAllowed()) ic->commit(" "); ic->commit(text); d->autoSpaceAllowed = addSpace; accept = true; } else { update(); inputContext()->sendKeyClick(key, text, modifiers); d->autoSpaceAllowed = true; accept = true; } } break; } return accept; } QList<SelectionListModel::Type> HunspellInputMethod::selectionLists() { Q_D(const HunspellInputMethod); Qt::InputMethodHints inputMethodHints = inputContext()->inputMethodHints(); if (d->dictionaryState == HunspellInputMethodPrivate::DictionaryNotLoaded || inputMethodHints.testFlag(Qt::ImhNoPredictiveText) || inputMethodHints.testFlag(Qt::ImhHiddenText)) return QList<SelectionListModel::Type>(); return QList<SelectionListModel::Type>() << SelectionListModel::WordCandidateList; } int HunspellInputMethod::selectionListItemCount(SelectionListModel::Type type) { Q_UNUSED(type) Q_D(HunspellInputMethod); return d->wordCandidates.count(); } QVariant HunspellInputMethod::selectionListData(SelectionListModel::Type type, int index, int role) { QVariant result; Q_UNUSED(type) Q_D(HunspellInputMethod); switch (role) { case SelectionListModel::DisplayRole: result = QVariant(d->wordCandidates.at(index)); break; case SelectionListModel::WordCompletionLengthRole: { const QString wordCandidate(d->wordCandidates.at(index)); int wordCompletionLength = wordCandidate.length() - d->word.length(); result.setValue((wordCompletionLength > 0 && wordCandidate.startsWith(d->word)) ? wordCompletionLength : 0); break; } default: result = AbstractInputMethod::selectionListData(type, index, role); break; } return result;
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
} void HunspellInputMethod::selectionListItemSelected(SelectionListModel::Type type, int index) { Q_UNUSED(type) Q_D(HunspellInputMethod); QString finalWord = d->wordCandidates.at(index); reset(); inputContext()->commit(finalWord); d->autoSpaceAllowed = true; } bool HunspellInputMethod::reselect(int cursorPosition, const InputEngine::ReselectFlags &reselectFlags) { Q_D(HunspellInputMethod); Q_ASSERT(d->word.isEmpty()); if (d->dictionaryState == HunspellInputMethodPrivate::DictionaryNotLoaded) return false; InputContext *ic = inputContext(); if (!ic) return false; const QString surroundingText = ic->surroundingText(); int replaceFrom = 0; if (reselectFlags.testFlag(InputEngine::WordBeforeCursor)) { for (int i = cursorPosition - 1; i >= 0; --i) { QChar c = surroundingText.at(i); if (!d->isValidInputChar(c)) break; d->word.insert(0, c); --replaceFrom; } while (replaceFrom < 0 && d->isJoiner(d->word.at(0))) { d->word.remove(0, 1); ++replaceFrom; } } if (reselectFlags.testFlag(InputEngine::WordAtCursor) && replaceFrom == 0) { d->word.clear(); return false; } if (reselectFlags.testFlag(InputEngine::WordAfterCursor)) { for (int i = cursorPosition; i < surroundingText.length(); ++i) { QChar c = surroundingText.at(i); if (!d->isValidInputChar(c)) break; d->word.append(c); } while (replaceFrom > -d->word.length()) { int lastPos = d->word.length() - 1; if (!d->isJoiner(d->word.at(lastPos))) break; d->word.remove(lastPos, 1); } } if (d->word.isEmpty()) return false; if (reselectFlags.testFlag(InputEngine::WordAtCursor) && replaceFrom == -d->word.length()) { d->word.clear(); return false; }
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
if (d->isJoiner(d->word.at(0))) { d->word.clear(); return false; } if (d->isJoiner(d->word.at(d->word.length() - 1))) { d->word.clear(); return false; } ic->setPreeditText(d->word, QList<QInputMethodEvent::Attribute>(), replaceFrom, d->word.length()); d->autoSpaceAllowed = false; if (d->updateSuggestions()) { emit selectionListChanged(SelectionListModel::WordCandidateList); emit selectionListActiveItemChanged(SelectionListModel::WordCandidateList, d->activeWordIndex); } return true; } void HunspellInputMethod::reset() { Q_D(HunspellInputMethod); d->reset(); } void HunspellInputMethod::update() { Q_D(HunspellInputMethod); if (d->ignoreUpdate) return; if (!d->word.isEmpty()) { QString finalWord = d->hasSuggestions() ? d->wordCandidates.at(d->activeWordIndex) : d->word; d->reset(); inputContext()->commit(finalWord); } d->autoSpaceAllowed = false; } 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 if (!d->word.isEmpty() && !d->wordCandidates.isEmpty() && d->wordCandidates.at(0) != d->word) d->wordCandidates.replace(0, d->word); d->activeWordIndex = activeWordIndex; emit selectionListChanged(SelectionListModel::WordCandidateList); 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