presentation/SpellService.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QHash> | ||
| 4 | #include <QObject> | ||
| 5 | #include <QUrl> | ||
| 6 | #include <QStringList> | ||
| 7 | #include <memory> | ||
| 8 | |||
| 9 | namespace Sonnet { | ||
| 10 | class Speller; | ||
| 11 | } | ||
| 12 | |||
| 13 | // Sprint 108 Phase 4 (S108.4.2, D-11): spell checking for the composer | ||
| 14 | // through KF6 Sonnet (its Hunspell plugin and the system's dictionaries). | ||
| 15 | // Built without Sonnet, or without any dictionary installed, available() | ||
| 16 | // is false and the composer shows no spelling at all. | ||
| 17 | // | ||
| 18 | // Languages are Sonnet's codes ("de_DE", "en_US"); bestLanguage() maps a | ||
| 19 | // message language ("de", "en-GB") to an installed one. One speller per | ||
| 20 | // language, created on first use; GUI thread. | ||
| 21 | class SpellService final : public QObject { | ||
| 22 | Q_OBJECT | ||
| 23 | Q_PROPERTY(bool available READ available CONSTANT) | ||
| 24 | Q_PROPERTY(QVariantList languages READ languageChoices CONSTANT) | ||
| 25 | // §4.15: where the user guide says which dictionary packages to install. | ||
| 26 | Q_PROPERTY(QUrl helpUrl READ helpUrl CONSTANT) | ||
| 27 | |||
| 28 | public: | ||
| 29 | explicit SpellService(QObject *parent = nullptr); | ||
| 30 | ~SpellService() override; | ||
| 31 | |||
| 32 |
1/1✓ Branch 2 → 3 taken 1666 times.
|
1666 | bool available() const { return !languages().isEmpty(); } |
| 33 | ✗ | static QUrl helpUrl() { | |
| 34 | ✗ | return QUrl(QStringLiteral("https://git.jdsoft.de/jens/qmailjd/-/blob/main/docs/user/TROUBLESHOOTING.md#spell-checking")); | |
| 35 | } | ||
| 36 | // Loaded on first use, not at start-up (Sonnet loads its plugins then). | ||
| 37 | QStringList languages() const; | ||
| 38 | // [{code, name}] for the language chip. | ||
| 39 | QVariantList languageChoices() const; | ||
| 40 | Q_INVOKABLE QString bestLanguage(const QString &preferred) const; | ||
| 41 | bool isMisspelled(const QString &word, const QString &language); | ||
| 42 | QStringList suggestions(const QString &word, const QString &language, int maximum = 6); | ||
| 43 | // D-12: the installed language a text is written in (Sonnet's guesser | ||
| 44 | // over the installed languages); "" below two words or for no match. | ||
| 45 | QString guess(const QString &text) const; | ||
| 46 | // The personal dictionary (Sonnet's own, kept across sessions). | ||
| 47 | void addToDictionary(const QString &word, const QString &language); | ||
| 48 | |||
| 49 | private: | ||
| 50 | mutable QStringList m_languages; | ||
| 51 | mutable bool m_loaded = false; | ||
| 52 | // language → word → misspelled (the answers already given). | ||
| 53 | QHash<QString, QHash<QString, bool>> m_known; | ||
| 54 | static constexpr qsizetype KnownWordsLimit = 50000; | ||
| 55 | QHash<QString, std::shared_ptr<Sonnet::Speller>> m_spellers; | ||
| 56 | Sonnet::Speller *speller(const QString &language); | ||
| 57 | }; | ||
| 58 |