diff options
-rwxr-xr-x | BuildTools/InstallSwiftDependencies.sh | 10 | ||||
-rw-r--r-- | BuildTools/SCons/SConscript.boot | 2 | ||||
-rw-r--r-- | SwifTools/HunspellChecker.cpp | 146 | ||||
-rw-r--r-- | SwifTools/HunspellChecker.h | 28 | ||||
-rw-r--r-- | SwifTools/MacOSXChecker.h | 7 | ||||
-rw-r--r-- | SwifTools/MacOSXChecker.mm | 16 | ||||
-rw-r--r-- | SwifTools/SpellChecker.h | 16 | ||||
-rw-r--r-- | SwifTools/SpellCheckerFactory.cpp | 18 | ||||
-rw-r--r-- | SwifTools/SpellCheckerFactory.h | 2 | ||||
-rw-r--r-- | Swift/Controllers/SettingConstants.cpp | 6 | ||||
-rw-r--r-- | Swift/Controllers/SettingConstants.h | 6 | ||||
-rw-r--r-- | Swift/QtUI/QtSpellCheckerWindow.cpp | 77 | ||||
-rw-r--r-- | Swift/QtUI/QtSpellCheckerWindow.h | 18 | ||||
-rw-r--r-- | Swift/QtUI/QtSpellCheckerWindow.ui | 45 | ||||
-rw-r--r-- | Swift/QtUI/QtTextEdit.cpp | 22 |
15 files changed, 265 insertions, 154 deletions
diff --git a/BuildTools/InstallSwiftDependencies.sh b/BuildTools/InstallSwiftDependencies.sh index 2c1570f..391efe2 100755 --- a/BuildTools/InstallSwiftDependencies.sh +++ b/BuildTools/InstallSwiftDependencies.sh @@ -10,20 +10,20 @@ then SYSTEM_DISTRO=$(lsb_release -i -s) if [ "$SYSTEM_DISTRO" == "Debian" ] then - sudo apt-get install pkg-config libssl-dev qt5-default libqt5x11extras5-dev libqt5webkit5-dev qtmultimedia5-dev qttools5-dev-tools libminiupnpc-dev libnatpmp-dev + sudo apt-get install pkg-config libssl-dev qt5-default libqt5x11extras5-dev libqt5webkit5-dev qtmultimedia5-dev qttools5-dev-tools libminiupnpc-dev libnatpmp-dev libhunspell-dev elif [ "$SYSTEM_DISTRO" == "Ubuntu" ] then - sudo apt-get install pkg-config libssl-dev qt5-default libqt5x11extras5-dev libqt5webkit5-dev qtmultimedia5-dev qttools5-dev-tools + sudo apt-get install pkg-config libssl-dev qt5-default libqt5x11extras5-dev libqt5webkit5-dev qtmultimedia5-dev qttools5-dev-tools libhunspell-dev elif [ "$SYSTEM_DISTRO" == "Arch" ] then - sudo pacman -S qt5-base qt5-x11extras qt5-webkit qt5-multimedia qt5-tools + sudo pacman -S qt5-base qt5-x11extras qt5-webkit qt5-multimedia qt5-tools hunspell elif [ "$SYSTEM_DISTRO" == "openSUSE project" ] then - sudo zypper in pkg-config libopenssl-devel libQt5Core-devel libQt5WebKit5-devel libQt5WebKitWidgets-devel libqt5-qtmultimedia-devel libqt5-qtx11extras-devel libqt5-qttools-devel libQt5Gui-devel libQt5Network-devel libQt5DBus-devel python-xml + sudo zypper in pkg-config libopenssl-devel libQt5Core-devel libQt5WebKit5-devel libQt5WebKitWidgets-devel libqt5-qtmultimedia-devel libqt5-qtx11extras-devel libqt5-qttools-devel libQt5Gui-devel libQt5Network-devel libQt5DBus-devel python-xml hunspell-devel elif [ "$SYSTEM_DISTRO" == "Fedora" ] then sudo dnf groups install "C Development Tools and Libraries" - sudo dnf install openssl-devel qt5-qtbase-devel qt5-linguist qt5-qtwebkit-devel qt5-qtmultimedia-devel qt5-qtx11extras-devel + sudo dnf install openssl-devel qt5-qtbase-devel qt5-linguist qt5-qtwebkit-devel qt5-qtmultimedia-devel qt5-qtx11extras-devel hunspell-devel else echo "Unsupported Linux distribution." fi diff --git a/BuildTools/SCons/SConscript.boot b/BuildTools/SCons/SConscript.boot index c335934..13a49b8 100644 --- a/BuildTools/SCons/SConscript.boot +++ b/BuildTools/SCons/SConscript.boot @@ -48,7 +48,7 @@ vars.Add("openssl_libnames", "Comma-separated openssl library names to override vars.Add("openssl_include", "Location of OpenSSL include files (if not under (openssl)/include)", None) vars.Add("openssl_libdir", "Location of OpenSSL library files (if not under (openssl)/lib)", None) vars.Add(PackageVariable("hunspell_prefix", "Hunspell location", False)) -vars.Add(BoolVariable("hunspell_enable", "Build with Hunspell support", False)) +vars.Add(BoolVariable("hunspell_enable", "Build with Hunspell support", True)) vars.Add(PathVariable("boost_includedir", "Boost headers location", None, PathVariable.PathAccept)) vars.Add(PathVariable("boost_libdir", "Boost library location", None, PathVariable.PathAccept)) vars.Add(BoolVariable("boost_bundled_enable", "Allow use of bundled Boost as last resort", "true")) diff --git a/SwifTools/HunspellChecker.cpp b/SwifTools/HunspellChecker.cpp index fb1a5d6..1de369b 100644 --- a/SwifTools/HunspellChecker.cpp +++ b/SwifTools/HunspellChecker.cpp @@ -15,47 +15,151 @@ #include <algorithm> #include <boost/algorithm/string.hpp> +#include <boost/filesystem.hpp> +#include <boost/regex.hpp> #include <hunspell/hunspell.hxx> +#include <Swiften/Base/Log.h> + namespace Swift { -HunspellChecker::HunspellChecker(const char* affix_path, const char* dictionary_path) { - speller_ = new Hunspell(affix_path, dictionary_path); +static std::vector<std::string> recursiveFileSearch(const std::vector<std::string>& paths, const boost::regex& regex) { + std::vector<std::string> matches; + + for (auto& path : paths) { + if (boost::filesystem::exists(path)) { + boost::cmatch what; + for (auto filename : boost::make_iterator_range(boost::filesystem::directory_iterator(path), boost::filesystem::directory_iterator())) { + if (boost::filesystem::is_regular_file(filename) && boost::regex_match(filename.path().c_str(), what, regex)) { + matches.push_back(filename.path().string()); + } + } + } + } + return matches; +} + +HunspellChecker::HunspellChecker() { } HunspellChecker::~HunspellChecker() { - delete speller_; +} + +std::vector<std::string> HunspellChecker::hunspellDictionaryPaths() const { + // The following list of paths comes from the source of the Hunspell command line tool. + std::vector<std::string> paths = { + "/usr/share/hunspell", + "/usr/share/myspell", + "/usr/share/myspell/dicts", + "/Library/Spelling", + "/opt/openoffice.org/basis3.0/share/dict/ooo", + "/usr/lib/openoffice.org/basis3.0/share/dict/ooo", + "/opt/openoffice.org2.4/share/dict/ooo", + "/usr/lib/openoffice.org2.4/share/dict/ooo", + "/opt/openoffice.org2.3/share/dict/ooo", + "/usr/lib/openoffice.org2.3/share/dict/ooo", + "/opt/openoffice.org2.2/share/dict/ooo", + "/usr/lib/openoffice.org2.2/share/dict/ooo", + "/opt/openoffice.org2.1/share/dict/ooo", + "/usr/lib/openoffice.org2.1/share/dict/ooo", + "/opt/openoffice.org2.0/share/dict/ooo", + "/usr/lib/openoffice.org2.0/share/dict/ooo" + }; + + if (std::getenv("DICPATH")) { + std::string dicpathEnvironment(std::getenv("DICPATH")); + std::vector<std::string> dicpaths; + boost::split(dicpaths,dicpathEnvironment,boost::is_any_of(":")); + paths.insert(paths.begin(), dicpaths.begin(), dicpaths.end()); + } + + return paths; +} + +bool HunspellChecker::isAutomaticallyDetectingLanguage() { + return false; +} + +void HunspellChecker::setActiveLanguage(const std::string& language) { + auto dictionaries = detectedDictionaries(); + if (dictionaries.find(language) != dictionaries.end()) { + SWIFT_LOG(debug) << "Initialized Hunspell with dic,aff files " << dictionaries[language].dicPath << " , " << dictionaries[language].affPath << std::endl; + speller_ = std::unique_ptr<Hunspell>(new Hunspell(dictionaries[language].affPath.c_str(), dictionaries[language].dicPath.c_str())); + activeLangauge_ = language; + } + else { + SWIFT_LOG(warning) << "Unsupported language '" << language << "'" << std::endl; + } +} + +std::string HunspellChecker::activeLanguage() const { + return activeLangauge_.get_value_or(""); +} + +std::vector<std::string> HunspellChecker::supportedLanguages() const { + std::vector<std::string> languages; + + for (const auto& n : detectedDictionaries()) { + languages.push_back(n.first); + } + + return languages; +} + +std::unordered_map<std::string, HunspellChecker::Dictionary> HunspellChecker::detectedDictionaries() const { + std::unordered_map<std::string, HunspellChecker::Dictionary> dictionaries; + + auto dictionaryFiles = recursiveFileSearch(hunspellDictionaryPaths(), boost::regex(".*\\.dic$")); + for (const auto& dictionary : dictionaryFiles) { + std::string correspondingAffixPath = dictionary; + boost::replace_last(correspondingAffixPath, ".dic", ".aff"); + if (boost::filesystem::is_regular_file(correspondingAffixPath)) { + auto filenameWithoutExtension = boost::filesystem::basename(dictionary); + dictionaries[filenameWithoutExtension] = {dictionary, correspondingAffixPath}; + } + } + + return dictionaries; } bool HunspellChecker::isCorrect(const std::string& word) { - return speller_->spell(word.c_str()); + if (speller_) { + return speller_->spell(word.c_str()); + } + else { + return true; + } } void HunspellChecker::getSuggestions(const std::string& word, std::vector<std::string>& list) { - char **suggestList = NULL; - int words_returned = 0; - if (!word.empty()) { - words_returned = speller_->suggest(&suggestList, word.c_str()); - if (suggestList != NULL) { - for (int i = 0; i < words_returned; ++i) { - list.push_back(suggestList[i]); - free(suggestList[i]); + if (speller_) { + char **suggestList = NULL; + int words_returned = 0; + if (!word.empty()) { + words_returned = speller_->suggest(&suggestList, word.c_str()); + if (suggestList != NULL) { + for (int i = 0; i < words_returned; ++i) { + list.push_back(suggestList[i]); + free(suggestList[i]); + } + free(suggestList); } - free(suggestList); } } } void HunspellChecker::checkFragment(const std::string& fragment, PositionPairList& misspelledPositions) { - if (!fragment.empty()) { - parser_->check(fragment, misspelledPositions); - for (PositionPairList::iterator it = misspelledPositions.begin(); it != misspelledPositions.end();) { - if (isCorrect(fragment.substr(boost::get<0>(*it), boost::get<1>(*it) - boost::get<0>(*it)))) { - it = misspelledPositions.erase(it); - } - else { - ++it; + if (speller_) { + if (!fragment.empty()) { + parser_.check(fragment, misspelledPositions); + for (PositionPairList::iterator it = misspelledPositions.begin(); it != misspelledPositions.end();) { + if (isCorrect(fragment.substr(boost::get<0>(*it), boost::get<1>(*it) - boost::get<0>(*it)))) { + it = misspelledPositions.erase(it); + } + else { + ++it; + } } } } diff --git a/SwifTools/HunspellChecker.h b/SwifTools/HunspellChecker.h index 076b468..2d4831e 100644 --- a/SwifTools/HunspellChecker.h +++ b/SwifTools/HunspellChecker.h @@ -12,10 +12,13 @@ #pragma once +#include <memory> +#include <string> +#include <unordered_map> #include <vector> #include <boost/algorithm/string.hpp> -#include <boost/tuple/tuple.hpp> +#include <boost/optional.hpp> #include <SwifTools/SpellChecker.h> @@ -24,12 +27,31 @@ class Hunspell; namespace Swift { class HunspellChecker : public SpellChecker { public: - HunspellChecker(const char* affix_path, const char* dict_path); + HunspellChecker(); virtual ~HunspellChecker(); + + virtual bool isAutomaticallyDetectingLanguage(); + + virtual void setActiveLanguage(const std::string& language); + virtual std::string activeLanguage() const; + virtual std::vector<std::string> supportedLanguages() const; + virtual bool isCorrect(const std::string& word); virtual void getSuggestions(const std::string& word, std::vector<std::string>& list); virtual void checkFragment(const std::string& fragment, PositionPairList& misspelledPositions); + private: - Hunspell* speller_; + struct Dictionary { + std::string dicPath; + std::string affPath; + }; + + std::unordered_map<std::string, Dictionary> detectedDictionaries() const; + std::vector<std::string> hunspellDictionaryPaths() const; + + private: + std::unique_ptr<Hunspell> speller_; + boost::optional<std::string> activeLangauge_; + }; } diff --git a/SwifTools/MacOSXChecker.h b/SwifTools/MacOSXChecker.h index be9a32a..7587c99 100644 --- a/SwifTools/MacOSXChecker.h +++ b/SwifTools/MacOSXChecker.h @@ -23,6 +23,13 @@ namespace Swift { public: MacOSXChecker(); virtual ~MacOSXChecker(); + + virtual bool isAutomaticallyDetectingLanguage(); + + virtual void setActiveLanguage(const std::string& language); + virtual std::string activeLanguage() const; + virtual std::vector<std::string> supportedLanguages() const; + virtual bool isCorrect(const std::string& word); virtual void getSuggestions(const std::string& word, std::vector<std::string>& list); virtual void checkFragment(const std::string& fragment, PositionPairList& misspelledPositions); diff --git a/SwifTools/MacOSXChecker.mm b/SwifTools/MacOSXChecker.mm index 5f4f9c3..519f06c 100644 --- a/SwifTools/MacOSXChecker.mm +++ b/SwifTools/MacOSXChecker.mm @@ -13,6 +13,7 @@ #include <SwifTools/MacOSXChecker.h> #include <algorithm> +#include <cassert> #include <boost/algorithm/string.hpp> @@ -33,6 +34,21 @@ bool MacOSXChecker::isCorrect(const std::string& /*word*/) { return false; } +bool MacOSXChecker::isAutomaticallyDetectingLanguage() { + return true; +} + +void MacOSXChecker::setActiveLanguage(const std::string& /*language*/) { + assert(false); +} + +std::string MacOSXChecker::activeLanguage() const { + assert(false); +} +std::vector<std::string> MacOSXChecker::supportedLanguages() const { + assert(false); +} + void MacOSXChecker::getSuggestions(const std::string& word, std::vector<std::string>& list) { NSSpellChecker* spellChecker = [NSSpellChecker sharedSpellChecker]; NSString* wordString = [[NSString alloc] initWithUTF8String: word.c_str()]; diff --git a/SwifTools/SpellChecker.h b/SwifTools/SpellChecker.h index 415d3f6..664fc63 100644 --- a/SwifTools/SpellChecker.h +++ b/SwifTools/SpellChecker.h @@ -14,24 +14,28 @@ #include <vector> -#include <boost/algorithm/string.hpp> -#include <boost/tuple/tuple.hpp> - #include <SwifTools/SpellParser.h> namespace Swift { class SpellChecker { public: SpellChecker() { - parser_ = new SpellParser(); } + virtual ~SpellChecker() { - delete parser_; } + + virtual bool isAutomaticallyDetectingLanguage() = 0; + + virtual void setActiveLanguage(const std::string& language) = 0; + virtual std::string activeLanguage() const = 0; + virtual std::vector<std::string> supportedLanguages() const = 0; + virtual bool isCorrect(const std::string& word) = 0; virtual void getSuggestions(const std::string& word, std::vector<std::string>& list) = 0; virtual void checkFragment(const std::string& fragment, PositionPairList& misspelledPositions) = 0; + protected: - SpellParser *parser_; + SpellParser parser_; }; } diff --git a/SwifTools/SpellCheckerFactory.cpp b/SwifTools/SpellCheckerFactory.cpp index e53447e..bfd3d4a 100644 --- a/SwifTools/SpellCheckerFactory.cpp +++ b/SwifTools/SpellCheckerFactory.cpp @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #include <boost/filesystem/operations.hpp> #include <SwifTools/SpellChecker.h> @@ -23,17 +29,11 @@ SpellCheckerFactory::SpellCheckerFactory() { } #ifdef HAVE_HUNSPELL -SpellChecker* SpellCheckerFactory::createSpellChecker(const std::string& dictFile) { - std::string affixFile(dictFile); - boost::replace_all(affixFile, ".dic", ".aff"); - if ((boost::filesystem::exists(dictFile)) && (boost::filesystem::exists(affixFile))) { - return new HunspellChecker(affixFile.c_str(), dictFile.c_str()); - } - // If dictionaries don't exist disable the checker - return NULL; +SpellChecker* SpellCheckerFactory::createSpellChecker() { + return new HunspellChecker(); } #elif defined(SWIFTEN_PLATFORM_MACOSX) -SpellChecker* SpellCheckerFactory::createSpellChecker(const std::string& /*dictFile*/) { +SpellChecker* SpellCheckerFactory::createSpellChecker() { return new MacOSXChecker(); } #endif diff --git a/SwifTools/SpellCheckerFactory.h b/SwifTools/SpellCheckerFactory.h index 2e1711a..eb2ade6 100644 --- a/SwifTools/SpellCheckerFactory.h +++ b/SwifTools/SpellCheckerFactory.h @@ -28,6 +28,6 @@ namespace Swift { class SpellCheckerFactory { public: SpellCheckerFactory(); - SpellChecker* createSpellChecker(const std::string& dictFile); + SpellChecker* createSpellChecker(); }; } diff --git a/Swift/Controllers/SettingConstants.cpp b/Swift/Controllers/SettingConstants.cpp index 9807abc..d9766cf 100644 --- a/Swift/Controllers/SettingConstants.cpp +++ b/Swift/Controllers/SettingConstants.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Isode Limited. + * Copyright (c) 2012-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -21,9 +21,7 @@ const SettingsProvider::Setting<std::string> SettingConstants::EXPANDED_ROSTER_G const SettingsProvider::Setting<bool> SettingConstants::PLAY_SOUNDS("playSounds", true); const SettingsProvider::Setting<std::string> SettingConstants::HIGHLIGHT_RULES("highlightRules", "@"); const SettingsProvider::Setting<bool> SettingConstants::SPELL_CHECKER("spellChecker", false); -const SettingsProvider::Setting<std::string> SettingConstants::DICT_PATH("dictPath", "/usr/share/myspell/dicts/"); -const SettingsProvider::Setting<std::string> SettingConstants::PERSONAL_DICT_PATH("personaldictPath", "/home/"); -const SettingsProvider::Setting<std::string> SettingConstants::DICT_FILE("dictFile", "en_US.dic"); +const SettingsProvider::Setting<std::string> SettingConstants::SPELL_CHECKER_LANGUAGE("spellCheckerLanguage", "en_US"); const SettingsProvider::Setting<std::string> SettingConstants::INVITE_AUTO_ACCEPT_MODE("inviteAutoAcceptMode", "presence"); const SettingsProvider::Setting<std::string> SettingConstants::TRELLIS_GRID_SIZE("trellisGridSize", ""); const SettingsProvider::Setting<std::string> SettingConstants::TRELLIS_GRID_POSITIONS("trellisGridPositions", ""); diff --git a/Swift/Controllers/SettingConstants.h b/Swift/Controllers/SettingConstants.h index 9343b7b..ace481b 100644 --- a/Swift/Controllers/SettingConstants.h +++ b/Swift/Controllers/SettingConstants.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 Isode Limited. + * Copyright (c) 2012-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -58,9 +58,7 @@ namespace Swift { */ static const SettingsProvider::Setting<std::string> HIGHLIGHT_RULES; static const SettingsProvider::Setting<bool> SPELL_CHECKER; - static const SettingsProvider::Setting<std::string> DICT_PATH; - static const SettingsProvider::Setting<std::string> PERSONAL_DICT_PATH; - static const SettingsProvider::Setting<std::string> DICT_FILE; + static const SettingsProvider::Setting<std::string> SPELL_CHECKER_LANGUAGE; /** * The #INVITE_AUTO_ACCEPT_MODE setting specifies how to handle invites to chat rooms. * diff --git a/Swift/QtUI/QtSpellCheckerWindow.cpp b/Swift/QtUI/QtSpellCheckerWindow.cpp index 9232b19..ed7e7e8 100644 --- a/Swift/QtUI/QtSpellCheckerWindow.cpp +++ b/Swift/QtUI/QtSpellCheckerWindow.cpp @@ -18,6 +18,8 @@ #include <QStringList> #include <QTimer> +#include <Swiften/Base/Log.h> + #include <Swift/Controllers/SettingConstants.h> #include <Swift/Controllers/Settings/SettingsProvider.h> @@ -38,7 +40,6 @@ QtSpellCheckerWindow::QtSpellCheckerWindow(SettingsProvider* settings, QWidget* connect(ui_.spellChecker, SIGNAL(toggled(bool)), this, SLOT(handleChecker(bool))); connect(ui_.cancel, SIGNAL(clicked()), this, SLOT(handleCancel())); connect(ui_.apply, SIGNAL(clicked()), this, SLOT(handleApply())); - connect(ui_.pathButton, SIGNAL(clicked()), this, SLOT(handlePathButton())); setFromSettings(); } @@ -48,27 +49,39 @@ void QtSpellCheckerWindow::shrinkWindow() { void QtSpellCheckerWindow::setFromSettings() { ui_.spellChecker->setChecked(settings_->getSetting(SettingConstants::SPELL_CHECKER)); - ui_.pathContent->setText(P2QSTRING(settings_->getSetting(SettingConstants::DICT_PATH))); - ui_.currentLanguageValue->setText(P2QSTRING(settings_->getSetting(SettingConstants::DICT_FILE))); - std::string currentPath = settings_->getSetting(SettingConstants::DICT_PATH); - QString filename = "*.dic"; - QDir dictDirectory = QDir(P2QSTRING(currentPath)); - QStringList files = dictDirectory.entryList(QStringList(filename), QDir::Files); - showFiles(files); setEnabled(settings_->getSetting(SettingConstants::SPELL_CHECKER)); } +void QtSpellCheckerWindow::setSupportedLanguages(const std::vector<std::string>& languages) { + languageItems_.clear(); + ui_.languageView->clear(); + for (const auto& shortLang : languages) { + auto locale = QLocale(P2QSTRING(shortLang)); + auto label = QString("%1 ( %2 )").arg(locale.nativeLanguageName(), locale.nativeCountryName()); + + QListWidgetItem* item = new QListWidgetItem(label); + item->setData(Qt::UserRole, P2QSTRING(shortLang)); + languageItems_[shortLang] = item; + ui_.languageView->addItem(item); + } +} + +void QtSpellCheckerWindow::setActiveLanguage(const std::string& language) { + SWIFT_LOG_ASSERT(languageItems_.find(language) != languageItems_.end(), warning) << "Language '" << language << "' is not available." << std::endl; + if (languageItems_.find(language) != languageItems_.end()) { + languageItems_[language]->setSelected(true); + } +} + +void QtSpellCheckerWindow::setAutomaticallyIdentifiesLanguage(bool isAutomaticallyIdentifying) { + ui_.languageView->setHidden(isAutomaticallyIdentifying); +} + void QtSpellCheckerWindow::handleChecker(bool state) { setEnabled(state); } void QtSpellCheckerWindow::setEnabled(bool state) { - ui_.pathContent->setEnabled(state); - ui_.languageView->setEnabled(state); - ui_.pathButton->setEnabled(state); - ui_.pathLabel->setEnabled(state); - ui_.currentLanguage->setEnabled(state); - ui_.currentLanguageValue->setEnabled(state); ui_.language->setEnabled(state); } @@ -76,7 +89,7 @@ void QtSpellCheckerWindow::handleApply() { settings_->storeSetting(SettingConstants::SPELL_CHECKER, ui_.spellChecker->isChecked()); QList<QListWidgetItem* > selectedLanguage = ui_.languageView->selectedItems(); if (!selectedLanguage.empty()) { - settings_->storeSetting(SettingConstants::DICT_FILE, Q2PSTRING((selectedLanguage.first())->text())); + settings_->storeSetting(SettingConstants::SPELL_CHECKER_LANGUAGE, Q2PSTRING(selectedLanguage.first()->data(Qt::UserRole).toString())); } this->done(0); } @@ -85,38 +98,4 @@ void QtSpellCheckerWindow::handleCancel() { this->done(0); } -void QtSpellCheckerWindow::handlePathButton() { - std::string currentPath = settings_->getSetting(SettingConstants::DICT_PATH); - QString dirpath = QFileDialog::getExistingDirectory(this, tr("Dictionary Path"), P2QSTRING(currentPath)); - if (dirpath != P2QSTRING(currentPath)) { - ui_.languageView->clear(); - settings_->storeSetting(SettingConstants::DICT_FILE, ""); - ui_.currentLanguageValue->setText(" "); - } - if (!dirpath.isEmpty()) { - if (!dirpath.endsWith("/")) { - dirpath.append("/"); - } - settings_->storeSetting(SettingConstants::DICT_PATH, Q2PSTRING(dirpath)); - QDir dictDirectory = QDir(dirpath); - ui_.pathContent->setText(dirpath); - QString filename = "*.dic"; - QStringList files = dictDirectory.entryList(QStringList(filename), QDir::Files); - showFiles(files); - } -} - -void QtSpellCheckerWindow::handlePersonalPathButton() { - std::string currentPath = settings_->getSetting(SettingConstants::PERSONAL_DICT_PATH); - QString filename = QFileDialog::getOpenFileName(this, tr("Select Personal Dictionary"), P2QSTRING(currentPath), tr("(*.dic")); - settings_->storeSetting(SettingConstants::PERSONAL_DICT_PATH, Q2PSTRING(filename)); -} - -void QtSpellCheckerWindow::showFiles(const QStringList& files) { - ui_.languageView->clear(); - for (int i = 0; i < files.size(); ++i) { - ui_.languageView->insertItem(i, files[i]); - } -} - } diff --git a/Swift/QtUI/QtSpellCheckerWindow.h b/Swift/QtUI/QtSpellCheckerWindow.h index 846dcbb..86ebd40 100644 --- a/Swift/QtUI/QtSpellCheckerWindow.h +++ b/Swift/QtUI/QtSpellCheckerWindow.h @@ -12,29 +12,41 @@ #pragma once +#include <string> +#include <unordered_map> +#include <vector> + #include <QDialog> #include <Swift/QtUI/ui_QtSpellCheckerWindow.h> +class QListWidgetItem; + namespace Swift { class SettingsProvider; class QtSpellCheckerWindow : public QDialog, protected Ui::QtSpellCheckerWindow { Q_OBJECT public: QtSpellCheckerWindow(SettingsProvider* settings, QWidget* parent = nullptr); + + void setSupportedLanguages(const std::vector<std::string>& languages); + void setActiveLanguage(const std::string& language); + void setAutomaticallyIdentifiesLanguage(bool isAutomaticallyIdentifying); + public slots: void handleChecker(bool state); void handleCancel(); - void handlePathButton(); - void handlePersonalPathButton(); void handleApply(); + private slots: void shrinkWindow(); + private: void setEnabled(bool state); void setFromSettings(); - void showFiles(const QStringList& files); + SettingsProvider* settings_; Ui::QtSpellCheckerWindow ui_; + std::unordered_map<std::string, QListWidgetItem*> languageItems_; }; } diff --git a/Swift/QtUI/QtSpellCheckerWindow.ui b/Swift/QtUI/QtSpellCheckerWindow.ui index b7f5161..dcb70fa 100644 --- a/Swift/QtUI/QtSpellCheckerWindow.ui +++ b/Swift/QtUI/QtSpellCheckerWindow.ui @@ -25,45 +25,6 @@ <widget class="QWidget" name="hunspellOptions" native="true"> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QLabel" name="pathLabel"> - <property name="text"> - <string>Dictionary Path:</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="pathContent"/> - </item> - <item> - <widget class="QPushButton" name="pathButton"> - <property name="text"> - <string>Change</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QLabel" name="currentLanguage"> - <property name="text"> - <string>Current Language:</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="currentLanguageValue"> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> <layout class="QHBoxLayout" name="horizontalLayout_4"> <item> <widget class="QLabel" name="language"> @@ -73,7 +34,11 @@ </widget> </item> <item> - <widget class="QListWidget" name="languageView"/> + <widget class="QListWidget" name="languageView"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + </widget> </item> </layout> </item> diff --git a/Swift/QtUI/QtTextEdit.cpp b/Swift/QtUI/QtTextEdit.cpp index 846dcbc..3143192 100644 --- a/Swift/QtUI/QtTextEdit.cpp +++ b/Swift/QtUI/QtTextEdit.cpp @@ -179,17 +179,17 @@ void QtTextEdit::addSuggestions(QMenu* menu, QContextMenuEvent* event) #ifdef HAVE_SPELLCHECKER -void QtTextEdit::setUpSpellChecker() -{ +void QtTextEdit::setUpSpellChecker() { delete highlighter_; highlighter_ = nullptr; delete checker_; checker_ = nullptr; if (settings_->getSetting(SettingConstants::SPELL_CHECKER)) { - std::string dictPath = settings_->getSetting(SettingConstants::DICT_PATH); - std::string dictFile = settings_->getSetting(SettingConstants::DICT_FILE); - checker_ = SpellCheckerFactory().createSpellChecker(dictPath + dictFile); + checker_ = SpellCheckerFactory().createSpellChecker(); if (checker_) { + if (!checker_->isAutomaticallyDetectingLanguage()) { + checker_->setActiveLanguage(settings_->getSetting(SettingConstants::SPELL_CHECKER_LANGUAGE)); + } highlighter_ = new QtSpellCheckHighlighter(document(), checker_); } else { @@ -213,12 +213,18 @@ void QtTextEdit::spellCheckerSettingsWindow() { spellCheckerWindow_->raise(); spellCheckerWindow_->activateWindow(); } + if (checker_) { + spellCheckerWindow_->setAutomaticallyIdentifiesLanguage(checker_->isAutomaticallyDetectingLanguage()); + if (!checker_->isAutomaticallyDetectingLanguage()) { + spellCheckerWindow_->setSupportedLanguages(checker_->supportedLanguages()); + spellCheckerWindow_->setActiveLanguage(checker_->activeLanguage()); + } + } } void QtTextEdit::handleSettingChanged(const std::string& settings) { - if (settings == SettingConstants::SPELL_CHECKER.getKey() - || settings == SettingConstants::DICT_PATH.getKey() - || settings == SettingConstants::DICT_FILE.getKey()) { + if (settings == SettingConstants::SPELL_CHECKER.getKey() || + settings == SettingConstants::SPELL_CHECKER_LANGUAGE.getKey()) { #ifdef HAVE_SPELLCHECKER setUpSpellChecker(); if (highlighter_) { |