From d96d3d525677ae5bebab1908394854b8fb79cdfb Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Mon, 11 Jun 2012 17:37:06 +0200 Subject: STORM-276 Added the ability to remove (user-installed) dictionaries --- indra/llui/llspellcheck.cpp | 103 ++++++++++++++++++--- indra/llui/llspellcheck.h | 13 ++- indra/newview/llfloaterspellchecksettings.cpp | 25 ++++- indra/newview/llfloaterspellchecksettings.h | 2 + .../skins/default/xui/en/floater_spellcheck.xml | 35 ++++--- 5 files changed, 147 insertions(+), 31 deletions(-) (limited to 'indra') diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp index 8b3ca50c29..887714d720 100644 --- a/indra/llui/llspellcheck.cpp +++ b/indra/llui/llspellcheck.cpp @@ -41,6 +41,9 @@ static const std::string DICT_DIR = "dictionaries"; static const std::string DICT_CUSTOM_SUFFIX = "_custom"; static const std::string DICT_IGNORE_SUFFIX = "_ignore"; +static const std::string DICT_FILE_MAIN = "dictionaries.xml"; +static const std::string DICT_FILE_USER = "user_dictionaries.xml"; + LLSD LLSpellChecker::sDictMap; LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal; @@ -141,10 +144,10 @@ void LLSpellChecker::refreshDictionaryMap() const std::string user_path = getDictionaryUserPath(); // Load dictionary information (file name, friendly name, ...) - llifstream user_file(user_path + "dictionaries.xml", std::ios::binary); + llifstream user_file(user_path + DICT_FILE_MAIN, std::ios::binary); if ( (!user_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_file)) || (0 == sDictMap.size()) ) { - llifstream app_file(app_path + "dictionaries.xml", std::ios::binary); + llifstream app_file(app_path + DICT_FILE_MAIN, std::ios::binary); if ( (!app_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_file)) || (0 == sDictMap.size()) ) { return; @@ -152,7 +155,7 @@ void LLSpellChecker::refreshDictionaryMap() } // Load user installed dictionary information - llifstream custom_file(user_path + "user_dictionaries.xml", std::ios::binary); + llifstream custom_file(user_path + DICT_FILE_USER, std::ios::binary); if (custom_file.is_open()) { LLSD custom_dict_map; @@ -245,6 +248,13 @@ void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::stri } } +bool LLSpellChecker::isActiveDictionary(const std::string& dict_language) const +{ + return + (mDictLanguage == dict_language) || + (mDictSecondary.end() != std::find(mDictSecondary.begin(), mDictSecondary.end(), dict_language)); +} + void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list) { if (!getUseSpellCheck()) @@ -263,8 +273,8 @@ void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list) { mDictSecondary = dict_list; - std::string dict_name = mDictName; - initHunspell(dict_name); + std::string dict_language = mDictLanguage; + initHunspell(dict_language); } else if (end_added != dict_add.begin()) // Add the new secondary dictionaries one by one { @@ -293,18 +303,18 @@ void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list) } } -void LLSpellChecker::initHunspell(const std::string& dict_name) +void LLSpellChecker::initHunspell(const std::string& dict_language) { if (mHunspell) { delete mHunspell; mHunspell = NULL; - mDictName.clear(); + mDictLanguage.clear(); mDictFile.clear(); mIgnoreList.clear(); } - const LLSD dict_entry = (!dict_name.empty()) ? getDictionaryData(dict_name) : LLSD(); + const LLSD dict_entry = (!dict_language.empty()) ? getDictionaryData(dict_language) : LLSD(); if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) || (!dict_entry["is_primary"].asBoolean())) { sSettingsChangeSignal(); @@ -330,7 +340,7 @@ void LLSpellChecker::initHunspell(const std::string& dict_name) return; } - mDictName = dict_name; + mDictLanguage = dict_language; mDictFile = dict_entry["name"].asString(); if (dict_entry["has_custom"].asBoolean()) @@ -405,6 +415,73 @@ bool LLSpellChecker::getUseSpellCheck() return (LLSpellChecker::instanceExists()) && (LLSpellChecker::instance().mHunspell); } +// static +bool LLSpellChecker::canRemoveDictionary(const std::string& dict_language) +{ + // Only user-installed inactive dictionaries can be removed + const LLSD dict_info = getDictionaryData(dict_language); + return + (dict_info["user_installed"].asBoolean()) && + ( (!getUseSpellCheck()) || (!LLSpellChecker::instance().isActiveDictionary(dict_language)) ); +} + +// static +void LLSpellChecker::removeDictionary(const std::string& dict_language) +{ + if (!canRemoveDictionary(dict_language)) + { + return; + } + + LLSD dict_map = loadUserDictionaryMap(); + for (LLSD::array_const_iterator it = dict_map.beginArray(); it != dict_map.endArray(); ++it) + { + const LLSD& dict_info = *it; + if (dict_info["language"].asString() == dict_language) + { + const std::string dict_dic = getDictionaryUserPath() + dict_info["name"].asString() + ".dic"; + if (gDirUtilp->fileExists(dict_dic)) + { + LLFile::remove(dict_dic); + } + const std::string dict_aff = getDictionaryUserPath() + dict_info["name"].asString() + ".aff"; + if (gDirUtilp->fileExists(dict_aff)) + { + LLFile::remove(dict_aff); + } + dict_map.erase(it - dict_map.beginArray()); + break; + } + } + saveUserDictionaryMap(dict_map); + + refreshDictionaryMap(); +} + +// static +LLSD LLSpellChecker::loadUserDictionaryMap() +{ + LLSD dict_map; + llifstream dict_file(getDictionaryUserPath() + DICT_FILE_USER, std::ios::binary); + if (dict_file.is_open()) + { + LLSDSerialize::fromXMLDocument(dict_map, dict_file); + dict_file.close(); + } + return dict_map; +} + +// static +void LLSpellChecker::saveUserDictionaryMap(const LLSD& dict_map) +{ + llofstream dict_file(getDictionaryUserPath() + DICT_FILE_USER, std::ios::trunc); + if (dict_file.is_open()) + { + LLSDSerialize::toPrettyXML(dict_map, dict_file); + dict_file.close(); + } +} + // static boost::signals2::connection LLSpellChecker::setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb) { @@ -412,12 +489,12 @@ boost::signals2::connection LLSpellChecker::setSettingsChangeCallback(const sett } // static -void LLSpellChecker::setUseSpellCheck(const std::string& dict_name) +void LLSpellChecker::setUseSpellCheck(const std::string& dict_language) { - if ( (((dict_name.empty()) && (getUseSpellCheck())) || (!dict_name.empty())) && - (LLSpellChecker::instance().mDictName != dict_name) ) + if ( (((dict_language.empty()) && (getUseSpellCheck())) || (!dict_language.empty())) && + (LLSpellChecker::instance().mDictLanguage != dict_language) ) { - LLSpellChecker::instance().initHunspell(dict_name); + LLSpellChecker::instance().initHunspell(dict_language); } } diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h index 776565b20a..4ab80195ea 100644 --- a/indra/llui/llspellcheck.h +++ b/indra/llui/llspellcheck.h @@ -48,15 +48,17 @@ public: S32 getSuggestions(const std::string& word, std::vector& suggestions) const; protected: void addToDictFile(const std::string& dict_path, const std::string& word); - void initHunspell(const std::string& dict_name); + void initHunspell(const std::string& dict_language); public: typedef std::list dict_list_t; - const std::string& getActiveDictionary() const { return mDictName; } + const std::string& getPrimaryDictionary() const { return mDictLanguage; } const dict_list_t& getSecondaryDictionaries() const { return mDictSecondary; } + bool isActiveDictionary(const std::string& dict_language) const; void setSecondaryDictionaries(dict_list_t dict_list); + static bool canRemoveDictionary(const std::string& dict_language); static const std::string getDictionaryAppPath(); static const std::string getDictionaryUserPath(); static const LLSD getDictionaryData(const std::string& dict_language); @@ -64,9 +66,12 @@ public: static bool getUseSpellCheck(); static bool hasDictionary(const std::string& dict_language, bool check_installed = false); static void refreshDictionaryMap(); - static void setUseSpellCheck(const std::string& dict_name); + static void removeDictionary(const std::string& dict_language); + static void setUseSpellCheck(const std::string& dict_language); protected: + static LLSD loadUserDictionaryMap(); static void setDictionaryData(const LLSD& dict_info); + static void saveUserDictionaryMap(const LLSD& dict_map); public: typedef boost::signals2::signal settings_change_signal_t; @@ -76,7 +81,7 @@ protected: protected: Hunspell* mHunspell; - std::string mDictName; + std::string mDictLanguage; std::string mDictFile; dict_list_t mDictSecondary; std::vector mIgnoreList; diff --git a/indra/newview/llfloaterspellchecksettings.cpp b/indra/newview/llfloaterspellchecksettings.cpp index 0b4f08c327..059a28fbcd 100644 --- a/indra/newview/llfloaterspellchecksettings.cpp +++ b/indra/newview/llfloaterspellchecksettings.cpp @@ -46,10 +46,24 @@ LLFloaterSpellCheckerSettings::LLFloaterSpellCheckerSettings(const LLSD& key) { } +void LLFloaterSpellCheckerSettings::draw() +{ + LLFloater::draw(); + + std::vector sel_items = getChild("spellcheck_available_list")->getAllSelected(); + bool enable_remove = !sel_items.empty(); + for (std::vector::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) + { + enable_remove &= LLSpellChecker::canRemoveDictionary((*sel_it)->getValue().asString()); + } + getChild("spellcheck_remove_btn")->setEnabled(enable_remove); +} + BOOL LLFloaterSpellCheckerSettings::postBuild(void) { gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaries, this, false)); LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange, this)); + getChild("spellcheck_remove_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnRemove, this)); getChild("spellcheck_import_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnImport, this)); getChild("spellcheck_main_combo")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaries, this, false)); getChild("spellcheck_moveleft_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_active_list", "spellcheck_available_list")); @@ -121,6 +135,15 @@ void LLFloaterSpellCheckerSettings::onOpen(const LLSD& key) refreshDictionaries(true); } +void LLFloaterSpellCheckerSettings::onBtnRemove() +{ + std::vector sel_items = getChild("spellcheck_available_list")->getAllSelected(); + for (std::vector::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) + { + LLSpellChecker::instance().removeDictionary((*sel_it)->getValue().asString()); + } +} + void LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange() { refreshDictionaries(true); @@ -137,7 +160,7 @@ void LLFloaterSpellCheckerSettings::refreshDictionaries(bool from_settings) std::string dict_cur = dict_combo->getSelectedItemLabel(); if ((dict_cur.empty() || from_settings) && (LLSpellChecker::getUseSpellCheck())) { - dict_cur = LLSpellChecker::instance().getActiveDictionary(); + dict_cur = LLSpellChecker::instance().getPrimaryDictionary(); } dict_combo->clearRows(); dict_combo->setEnabled(enabled); diff --git a/indra/newview/llfloaterspellchecksettings.h b/indra/newview/llfloaterspellchecksettings.h index da3239bca3..67bd260048 100644 --- a/indra/newview/llfloaterspellchecksettings.h +++ b/indra/newview/llfloaterspellchecksettings.h @@ -34,6 +34,7 @@ class LLFloaterSpellCheckerSettings : public LLFloater public: LLFloaterSpellCheckerSettings(const LLSD& key); + /*virtual*/ void draw(); /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); @@ -42,6 +43,7 @@ protected: void onBtnImport(); void onBtnMove(const std::string& from, const std::string& to); void onBtnOK(); + void onBtnRemove(); void onSpellCheckSettingsChange(); void refreshDictionaries(bool from_settings); }; diff --git a/indra/newview/skins/default/xui/en/floater_spellcheck.xml b/indra/newview/skins/default/xui/en/floater_spellcheck.xml index 91639ed0da..786b830ad9 100644 --- a/indra/newview/skins/default/xui/en/floater_spellcheck.xml +++ b/indra/newview/skins/default/xui/en/floater_spellcheck.xml @@ -3,10 +3,10 @@ border="true" can_close="true" can_minimize="true" - bottom="275" + bottom="300" left="300" can_resize="false" - height="330" + height="355" width="490" name="spellcheck_floater" title="Spell Checker Settings"> @@ -53,16 +53,6 @@ top_pad="-15" width="175" /> -