diff options
-rw-r--r-- | .hgignore | 1 | ||||
-rw-r--r-- | indra/llui/lllineeditor.cpp | 26 | ||||
-rw-r--r-- | indra/llui/llmenugl.cpp | 4 | ||||
-rw-r--r-- | indra/llui/llspellcheck.cpp | 152 | ||||
-rw-r--r-- | indra/llui/llspellcheck.h | 14 | ||||
-rw-r--r-- | indra/llui/lltextbase.cpp | 14 | ||||
-rw-r--r-- | indra/llui/lltexteditor.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llfloaterspellchecksettings.cpp | 73 | ||||
-rw-r--r-- | indra/newview/llfloaterspellchecksettings.h | 4 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_spellcheck.xml | 35 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/strings.xml | 3 |
11 files changed, 283 insertions, 47 deletions
@@ -24,6 +24,7 @@ indra/lib/mono/indra/*.exe indra/lib/mono/indra/*.pdb indra/lib/python/eventlet/ indra/llwindow/glh/glh_linear.h +indra/newview/app_settings/dictionaries indra/newview/app_settings/mozilla indra/newview/app_settings/mozilla-runtime-* indra/newview/app_settings/mozilla_debug diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 8fc0465acf..48d49af588 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -599,7 +599,9 @@ std::string LLLineEditor::getMisspelledWord(U32 pos) const for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) { if ( (it->first <= pos) && (it->second >= pos) ) + { return wstring_to_utf8str(mText.getWString().substr(it->first, it->second - it->first)); + } } return LLStringUtil::null; } @@ -609,7 +611,9 @@ bool LLLineEditor::isMisspelledWord(U32 pos) const for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) { if ( (it->first <= pos) && (it->second >= pos) ) + { return true; + } } return false; } @@ -1896,7 +1900,9 @@ void LLLineEditor::draw() // Find the start of the first word U32 word_start = 0, word_end = 0; while ( (word_start < text.length()) && (!LLStringOps::isAlpha(text[word_start])) ) + { word_start++; + } // Iterate over all words in the text block and check them one by one mMisspellRanges.clear(); @@ -1912,17 +1918,23 @@ void LLLineEditor::draw() word_end++; } if (word_end > text.length()) + { break; + } // Don't process words shorter than 3 characters std::string word = wstring_to_utf8str(text.substr(word_start, word_end - word_start)); if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) ) + { mMisspellRanges.push_back(std::pair<U32, U32>(start + word_start, start + word_end)); + } // Find the start of the next word word_start = word_end + 1; while ( (word_start < text.length()) && (!LLWStringUtil::isPartOfWord(text[word_start])) ) + { word_start++; + } } mSpellCheckStart = start; @@ -1934,19 +1946,27 @@ void LLLineEditor::draw() { // Skip over words that aren't (partially) visible if ( ((it->first < start) && (it->second < start)) || (it->first > end) ) + { continue; + } // Skip the current word if the user is still busy editing it if ( (!mSpellCheckTimer.hasExpired()) && (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) + { continue; + } S32 pxWidth = getRect().getWidth(); S32 pxStart = findPixelNearestPos(it->first - getCursor()); if (pxStart > pxWidth) + { continue; + } S32 pxEnd = findPixelNearestPos(it->second - getCursor()); if (pxEnd > pxWidth) + { pxEnd = pxWidth; + } S32 pxBottom = (S32)(text_bottom + mGLFont->getDescenderHeight()); @@ -1955,7 +1975,9 @@ void LLLineEditor::draw() { gl_line_2d(pxStart, pxBottom, pxStart + 2, pxBottom - 2); if (pxStart + 3 < pxEnd) + { gl_line_2d(pxStart + 2, pxBottom - 3, pxStart + 4, pxBottom - 1); + } pxStart += 4; } } @@ -2582,9 +2604,13 @@ void LLLineEditor::showContextMenu(S32 x, S32 y) if (hasSelection()) { if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + { deselect(); + } else + { setCursor(llmax(mSelectionStart, mSelectionEnd)); + } } bool use_spellcheck = getSpellCheck(), is_misspelled = false; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 3c14bf5415..efb9848a90 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -3909,9 +3909,13 @@ void LLContextMenu::show(S32 x, S32 y, LLView* spawning_view) arrange(); if (spawning_view) + { mSpawningViewHandle = spawning_view->getHandle(); + } else + { mSpawningViewHandle.markDead(); + } LLView::setVisible(TRUE); } diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp index 04c8a4fed0..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; @@ -75,13 +78,17 @@ S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector<std::str { suggestions.clear(); if ( (!mHunspell) || (word.length() < 3) ) + { return 0; + } char** suggestion_list; int suggestion_cnt = 0; if ( (suggestion_cnt = mHunspell->suggest(&suggestion_list, word.c_str())) != 0 ) { for (int suggestion_index = 0; suggestion_index < suggestion_cnt; suggestion_index++) + { suggestions.push_back(suggestion_list[suggestion_index]); + } mHunspell->free_list(&suggestion_list, suggestion_cnt); } return suggestions.size(); @@ -94,17 +101,28 @@ const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_language) { const LLSD& dict_entry = *it; if (dict_language == dict_entry["language"].asString()) + { return dict_entry; + } } return LLSD(); } // static +bool LLSpellChecker::hasDictionary(const std::string& dict_language, bool check_installed) +{ + const LLSD dict_info = getDictionaryData(dict_language); + return dict_info.has("language") && ( (!check_installed) || (dict_info["installed"].asBoolean()) ); +} + +// static void LLSpellChecker::setDictionaryData(const LLSD& dict_info) { const std::string dict_language = dict_info["language"].asString(); if (dict_language.empty()) + { return; + } for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it) { @@ -126,22 +144,28 @@ 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; + } } // 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; LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file); - for (LLSD::array_const_iterator it = custom_dict_map.beginArray(); it != custom_dict_map.endArray(); ++it) - setDictionaryData(*it); + for (LLSD::array_iterator it = custom_dict_map.beginArray(); it != custom_dict_map.endArray(); ++it) + { + LLSD& dict_info = *it; + dict_info["user_installed"] = true; + setDictionaryData(dict_info); + } custom_file.close(); } @@ -197,7 +221,9 @@ void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::stri { // Skip over the first line since that's just a line count if (0 != line_num) + { word_list.push_back(word); + } line_num++; } } @@ -215,11 +241,20 @@ void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::stri { file_out << word_list.size() << std::endl; for (std::vector<std::string>::const_iterator itWord = word_list.begin(); itWord != word_list.end(); ++itWord) + { file_out << *itWord << std::endl; + } file_out.close(); } } +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()) @@ -238,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 { @@ -249,31 +284,37 @@ void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list) { const LLSD dict_entry = getDictionaryData(*it_added); if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) + { continue; + } const std::string strFileDic = dict_entry["name"].asString() + ".dic"; if (gDirUtilp->fileExists(user_path + strFileDic)) + { mHunspell->add_dic((user_path + strFileDic).c_str()); + } else if (gDirUtilp->fileExists(app_path + strFileDic)) + { mHunspell->add_dic((app_path + strFileDic).c_str()); + } } mDictSecondary = dict_list; sSettingsChangeSignal(); } } -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(); @@ -287,13 +328,19 @@ void LLSpellChecker::initHunspell(const std::string& dict_name) const std::string filename_aff = dict_entry["name"].asString() + ".aff"; const std::string filename_dic = dict_entry["name"].asString() + ".dic"; if ( (gDirUtilp->fileExists(user_path + filename_aff)) && (gDirUtilp->fileExists(user_path + filename_dic)) ) + { mHunspell = new Hunspell((user_path + filename_aff).c_str(), (user_path + filename_dic).c_str()); + } else if ( (gDirUtilp->fileExists(app_path + filename_aff)) && (gDirUtilp->fileExists(app_path + filename_dic)) ) + { mHunspell = new Hunspell((app_path + filename_aff).c_str(), (app_path + filename_dic).c_str()); + } if (!mHunspell) + { return; + } - mDictName = dict_name; + mDictLanguage = dict_language; mDictFile = dict_entry["name"].asString(); if (dict_entry["has_custom"].asBoolean()) @@ -325,13 +372,19 @@ void LLSpellChecker::initHunspell(const std::string& dict_name) { const LLSD dict_entry = getDictionaryData(*it); if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) + { continue; + } const std::string filename_dic = dict_entry["name"].asString() + ".dic"; if (gDirUtilp->fileExists(user_path + filename_dic)) + { mHunspell->add_dic((user_path + filename_dic).c_str()); + } else if (gDirUtilp->fileExists(app_path + filename_dic)) + { mHunspell->add_dic((app_path + filename_dic).c_str()); + } } } @@ -363,18 +416,85 @@ bool LLSpellChecker::getUseSpellCheck() } // 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) { return sSettingsChangeSignal.connect(cb); } // 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); } } @@ -382,5 +502,7 @@ void LLSpellChecker::setUseSpellCheck(const std::string& dict_name) void LLSpellChecker::initClass() { if (sDictMap.isUndefined()) + { refreshDictionaryMap(); + } } diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h index acb121dd19..4ab80195ea 100644 --- a/indra/llui/llspellcheck.h +++ b/indra/llui/llspellcheck.h @@ -48,24 +48,30 @@ public: S32 getSuggestions(const std::string& word, std::vector<std::string>& 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<std::string> 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); static const LLSD& getDictionaryMap() { return sDictMap; } 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<void()> settings_change_signal_t; @@ -75,7 +81,7 @@ protected: protected: Hunspell* mHunspell; - std::string mDictName; + std::string mDictLanguage; std::string mDictFile; dict_list_t mDictSecondary; std::vector<std::string> mIgnoreList; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 4db1efdd20..5821cc3593 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -582,7 +582,9 @@ void LLTextBase::drawText() // Find the start of the first word U32 word_start = seg_start, word_end = -1; while ( (word_start < wstrText.length()) && (!LLStringOps::isAlpha(wstrText[word_start])) ) + { word_start++; + } // Iterate over all words in the text block and check them one by one while (word_start < seg_end) @@ -597,7 +599,9 @@ void LLTextBase::drawText() word_end++; } if (word_end > seg_end) + { break; + } // Don't process words shorter than 3 characters std::string word = wstring_to_utf8str(wstrText.substr(word_start, word_end - word_start)); @@ -609,7 +613,9 @@ void LLTextBase::drawText() // Find the start of the next word word_start = word_end + 1; while ( (word_start < seg_end) && (!LLWStringUtil::isPartOfWord(wstrText[word_start])) ) + { word_start++; + } } } @@ -695,12 +701,16 @@ void LLTextBase::drawText() { gl_line_2d(squiggle_start, squiggle_bottom, squiggle_start + 2, squiggle_bottom - 2); if (squiggle_start + 3 < squiggle_end) + { gl_line_2d(squiggle_start + 2, squiggle_bottom - 3, squiggle_start + 4, squiggle_bottom - 1); + } squiggle_start += 4; } if (misspell_it->second > seg_end) + { break; + } ++misspell_it; } @@ -1297,7 +1307,9 @@ std::string LLTextBase::getMisspelledWord(U32 pos) const for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) { if ( (it->first <= pos) && (it->second >= pos) ) + { return wstring_to_utf8str(getWText().substr(it->first, it->second - it->first)); + } } return LLStringUtil::null; } @@ -1307,7 +1319,9 @@ bool LLTextBase::isMisspelledWord(U32 pos) const for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) { if ( (it->first <= pos) && (it->second >= pos) ) + { return true; + } } return false; } diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index b860f0b44f..144b6960a1 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1960,9 +1960,13 @@ void LLTextEditor::showContextMenu(S32 x, S32 y) if (hasSelection()) { if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + { deselect(); + } else + { setCursorPos(llmax(mSelectionStart, mSelectionEnd)); + } } bool use_spellcheck = getSpellCheck(), is_misspelled = false; diff --git a/indra/newview/llfloaterspellchecksettings.cpp b/indra/newview/llfloaterspellchecksettings.cpp index 8bf480c4df..059a28fbcd 100644 --- a/indra/newview/llfloaterspellchecksettings.cpp +++ b/indra/newview/llfloaterspellchecksettings.cpp @@ -33,6 +33,7 @@ #include "llscrolllistctrl.h" #include "llsdserialize.h" #include "llspellcheck.h" +#include "lltrans.h" #include "llviewercontrol.h" #include <boost/algorithm/string.hpp> @@ -45,12 +46,26 @@ LLFloaterSpellCheckerSettings::LLFloaterSpellCheckerSettings(const LLSD& key) { } +void LLFloaterSpellCheckerSettings::draw() +{ + LLFloater::draw(); + + std::vector<LLScrollListItem*> sel_items = getChild<LLScrollListCtrl>("spellcheck_available_list")->getAllSelected(); + bool enable_remove = !sel_items.empty(); + for (std::vector<LLScrollListItem*>::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) + { + enable_remove &= LLSpellChecker::canRemoveDictionary((*sel_it)->getValue().asString()); + } + getChild<LLUICtrl>("spellcheck_remove_btn")->setEnabled(enable_remove); +} + BOOL LLFloaterSpellCheckerSettings::postBuild(void) { - gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaryLists, this, false)); + gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaries, this, false)); LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange, this)); + getChild<LLUICtrl>("spellcheck_remove_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnRemove, this)); getChild<LLUICtrl>("spellcheck_import_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnImport, this)); - getChild<LLUICtrl>("spellcheck_main_combo")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaryLists, this, false)); + getChild<LLUICtrl>("spellcheck_main_combo")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaries, this, false)); getChild<LLUICtrl>("spellcheck_moveleft_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_active_list", "spellcheck_available_list")); getChild<LLUICtrl>("spellcheck_moveright_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_available_list", "spellcheck_active_list")); getChild<LLUICtrl>("spellcheck_ok")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnOK, this)); @@ -82,6 +97,7 @@ void LLFloaterSpellCheckerSettings::onBtnMove(const std::string& from, const std std::vector<LLScrollListItem*> sel_items = from_ctrl->getAllSelected(); for (std::vector<LLScrollListItem*>::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) { + row["value"] = (*sel_it)->getValue(); row["columns"][0]["value"] = (*sel_it)->getColumn(0)->getValue(); to_ctrl->addElement(row); } @@ -101,7 +117,13 @@ void LLFloaterSpellCheckerSettings::onBtnOK() LLScrollListCtrl* list_ctrl = findChild<LLScrollListCtrl>("spellcheck_active_list"); std::vector<LLScrollListItem*> list_items = list_ctrl->getAllData(); for (std::vector<LLScrollListItem*>::const_iterator item_it = list_items.begin(); item_it != list_items.end(); ++item_it) - list_dict.push_back((*item_it)->getColumn(0)->getValue().asString()); + { + const std::string language = (*item_it)->getValue().asString(); + if (LLSpellChecker::hasDictionary(language, true)) + { + list_dict.push_back(language); + } + } } gSavedSettings.setString("SpellCheckDictionary", boost::join(list_dict, ",")); @@ -110,15 +132,24 @@ void LLFloaterSpellCheckerSettings::onBtnOK() void LLFloaterSpellCheckerSettings::onOpen(const LLSD& key) { - refreshDictionaryLists(true); + refreshDictionaries(true); +} + +void LLFloaterSpellCheckerSettings::onBtnRemove() +{ + std::vector<LLScrollListItem*> sel_items = getChild<LLScrollListCtrl>("spellcheck_available_list")->getAllSelected(); + for (std::vector<LLScrollListItem*>::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) + { + LLSpellChecker::instance().removeDictionary((*sel_it)->getValue().asString()); + } } void LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange() { - refreshDictionaryLists(true); + refreshDictionaries(true); } -void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings) +void LLFloaterSpellCheckerSettings::refreshDictionaries(bool from_settings) { bool enabled = gSavedSettings.getBOOL("SpellCheck"); getChild<LLUICtrl>("spellcheck_moveleft_btn")->setEnabled(enabled); @@ -128,7 +159,9 @@ void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings) LLComboBox* dict_combo = findChild<LLComboBox>("spellcheck_main_combo"); 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); @@ -139,10 +172,14 @@ void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings) { const LLSD& dict = *dict_it; if ( (dict["installed"].asBoolean()) && (dict["is_primary"].asBoolean()) && (dict.has("language")) ) + { dict_combo->add(dict["language"].asString()); + } } if (!dict_combo->selectByValue(dict_cur)) + { dict_combo->clear(); + } } // Populate the available and active dictionary list @@ -153,16 +190,20 @@ void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings) if ( ((!avail_ctrl->getItemCount()) && (!active_ctrl->getItemCount())) || (from_settings) ) { if (LLSpellChecker::getUseSpellCheck()) + { active_list = LLSpellChecker::instance().getSecondaryDictionaries(); + } } else { std::vector<LLScrollListItem*> active_items = active_ctrl->getAllData(); for (std::vector<LLScrollListItem*>::const_iterator item_it = active_items.begin(); item_it != active_items.end(); ++item_it) { - std::string dict = (*item_it)->getColumn(0)->getValue().asString(); + std::string dict = (*item_it)->getValue().asString(); if (dict_cur != dict) + { active_list.push_back(dict); + } } } @@ -173,27 +214,31 @@ void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings) active_ctrl->clearRows(); active_ctrl->setEnabled(enabled); - active_ctrl->sortByColumnIndex(0, true); for (LLSpellChecker::dict_list_t::const_iterator it = active_list.begin(); it != active_list.end(); ++it) { - row["columns"][0]["value"] = *it; + const std::string language = *it; + const LLSD dict = LLSpellChecker::getDictionaryData(language); + row["value"] = language; + row["columns"][0]["value"] = (!dict["user_installed"].asBoolean()) ? language : language + " " + LLTrans::getString("UserDictionary"); active_ctrl->addElement(row); } + active_ctrl->sortByColumnIndex(0, true); active_list.push_back(dict_cur); avail_ctrl->clearRows(); avail_ctrl->setEnabled(enabled); - avail_ctrl->sortByColumnIndex(0, true); for (LLSD::array_const_iterator dict_it = dict_map.beginArray(); dict_it != dict_map.endArray(); ++dict_it) { const LLSD& dict = *dict_it; - if ( (dict["installed"].asBoolean()) && (dict.has("language")) && - (active_list.end() == std::find(active_list.begin(), active_list.end(), dict["language"].asString())) ) + const std::string language = dict["language"].asString(); + if ( (dict["installed"].asBoolean()) && (active_list.end() == std::find(active_list.begin(), active_list.end(), language)) ) { - row["columns"][0]["value"] = dict["language"].asString(); + row["value"] = language; + row["columns"][0]["value"] = (!dict["user_installed"].asBoolean()) ? language : language + " " + LLTrans::getString("UserDictionary"); avail_ctrl->addElement(row); } } + avail_ctrl->sortByColumnIndex(0, true); } ///---------------------------------------------------------------------------- diff --git a/indra/newview/llfloaterspellchecksettings.h b/indra/newview/llfloaterspellchecksettings.h index 3a4428d4c3..c1c998915f 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,8 +43,9 @@ protected: void onBtnImport(); void onBtnMove(const std::string& from, const std::string& to); void onBtnOK(); + void onBtnRemove(); void onSpellCheckSettingsChange(); - void refreshDictionaryLists(bool from_settings); + void refreshDictionaries(bool from_settings); }; class LLFloaterSpellCheckerImport : public LLFloater 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" /> - <button - follows="left|top" - height="23" - label="Import" - label_selected="Import" - layout="topleft" - left_pad="5" - name="spellcheck_import_btn" - top_delta="0" - width="75" /> <text enabled_control="SpellCheck" follows="top|left" @@ -148,6 +138,25 @@ top_pad="-105" width="175" /> + <button + enabled="false" + follows="left|top" + height="23" + label="Remove" + layout="topleft" + left="55" + name="spellcheck_remove_btn" + top_pad="5" + width="80" /> + <button + follows="left|top" + height="23" + label="Import..." + layout="topleft" + left_pad="15" + name="spellcheck_import_btn" + top_delta="0" + width="80" /> <view_border top_pad="10" left="2" @@ -159,7 +168,7 @@ mouse_opaque="false" name="divisor4"/> <button - top_pad="10" + top_pad="8" right="380" height="22" width="90" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 4b58df595f..79c9f855e8 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3758,4 +3758,7 @@ Try enclosing path to the editor with double quotes. <string name="snapshot_quality_high">High</string> <string name="snapshot_quality_very_high">Very High</string> + <!-- Spell check settings floater --> + <string name="UserDictionary">[User]</string> + </strings> |