From 9c66ac87fd46db3987e60ae50989b2497099480b Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Fri, 20 Jan 2012 18:06:32 +0100 Subject: STORM-276 Basic spellchecking framework --- indra/cmake/Copy3rdPartyLibs.cmake | 3 + indra/cmake/ViewerMiscLibs.cmake | 1 + indra/llui/CMakeLists.txt | 3 + indra/llui/llmenugl.cpp | 6 +- indra/llui/llmenugl.h | 6 +- indra/llui/llspellcheck.cpp | 345 ++++++++++++++++++++++++++++++++ indra/llui/llspellcheck.h | 77 +++++++ indra/llui/llspellcheckmenuhandler.h | 46 +++++ indra/newview/app_settings/settings.xml | 22 ++ indra/newview/llappviewer.cpp | 14 ++ indra/newview/llstartup.cpp | 1 + indra/newview/llviewercontrol.cpp | 24 +++ indra/newview/llviewermenu.cpp | 86 ++++++++ indra/newview/llviewermenu.h | 1 + indra/newview/viewer_manifest.py | 8 + 15 files changed, 641 insertions(+), 2 deletions(-) create mode 100644 indra/llui/llspellcheck.cpp create mode 100644 indra/llui/llspellcheck.h create mode 100644 indra/llui/llspellcheckmenuhandler.h (limited to 'indra') diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 394db362b1..ebeae3e5be 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -41,6 +41,7 @@ if(WINDOWS) libeay32.dll libcollada14dom22-d.dll glod.dll + libhunspell.dll ) set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") @@ -53,6 +54,7 @@ if(WINDOWS) libeay32.dll libcollada14dom22.dll glod.dll + libhunspell.dll ) if(USE_GOOGLE_PERFTOOLS) @@ -215,6 +217,7 @@ elseif(DARWIN) libllqtwebkit.dylib libminizip.a libndofdev.dylib + libhunspell-1.3.dylib libexception_handler.dylib libcollada14dom.dylib ) diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake index df013b1665..f907181929 100644 --- a/indra/cmake/ViewerMiscLibs.cmake +++ b/indra/cmake/ViewerMiscLibs.cmake @@ -2,6 +2,7 @@ include(Prebuilt) if (NOT STANDALONE) + use_prebuilt_binary(libhunspell) use_prebuilt_binary(libuuid) use_prebuilt_binary(slvoice) use_prebuilt_binary(fontconfig) diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 772f173f17..1377336bb4 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -87,6 +87,7 @@ set(llui_SOURCE_FILES llsearcheditor.cpp llslider.cpp llsliderctrl.cpp + llspellcheck.cpp llspinctrl.cpp llstatbar.cpp llstatgraph.cpp @@ -192,6 +193,8 @@ set(llui_HEADER_FILES llsdparam.h llsliderctrl.h llslider.h + llspellcheck.h + llspellcheckmenuhandler.h llspinctrl.h llstatbar.h llstatgraph.h diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 95ecbb1c94..2a65262bbb 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -3854,7 +3854,7 @@ void LLContextMenu::setVisible(BOOL visible) } // Takes cursor position in screen space? -void LLContextMenu::show(S32 x, S32 y) +void LLContextMenu::show(S32 x, S32 y, LLView* spawning_view) { if (getChildList()->empty()) { @@ -3908,6 +3908,10 @@ void LLContextMenu::show(S32 x, S32 y) setRect(rect); arrange(); + if (spawning_view) + mSpawningViewHandle = spawning_view->getHandle(); + else + mSpawningViewHandle.markDead(); LLView::setVisible(TRUE); } diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 36f3ba34b9..67b3e1fbe6 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -670,7 +670,7 @@ public: virtual void draw (); - virtual void show (S32 x, S32 y); + virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); virtual void hide (); virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); @@ -683,10 +683,14 @@ public: LLHandle getHandle() { return getDerivedHandle(); } + LLView* getSpawningView() const { return mSpawningViewHandle.get(); } + void setSpawningView(LLHandle spawning_view) { mSpawningViewHandle = spawning_view; } + protected: BOOL mHoveredAnyItem; LLMenuItemGL* mHoverItem; LLRootHandle mHandle; + LLHandle mSpawningViewHandle; }; diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp new file mode 100644 index 0000000000..433ca02852 --- /dev/null +++ b/indra/llui/llspellcheck.cpp @@ -0,0 +1,345 @@ +/** + * @file llspellcheck.cpp + * @brief Spell checking functionality + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lldir.h" +#include "llsdserialize.h" + +#include "llspellcheck.h" +#if LL_WINDOWS + #include + #pragma comment(lib, "libhunspell.lib") +#else + #include +#endif + +static const std::string DICT_DIR = "dictionaries"; +static const std::string DICT_CUSTOM_SUFFIX = "_custom"; +static const std::string DICT_IGNORE_SUFFIX = "_ignore"; + +LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal; + +LLSpellChecker::LLSpellChecker() + : mHunspell(NULL) +{ + // Load initial dictionary information + refreshDictionaryMap(); +} + +LLSpellChecker::~LLSpellChecker() +{ + delete mHunspell; +} + +bool LLSpellChecker::checkSpelling(const std::string& word) const +{ + if ( (!mHunspell) || (word.length() < 3) || (0 != mHunspell->spell(word.c_str())) ) + { + return true; + } + if (mIgnoreList.size() > 0) + { + std::string word_lower(word); + LLStringUtil::toLower(word_lower); + return (mIgnoreList.end() != std::find(mIgnoreList.begin(), mIgnoreList.end(), word_lower)); + } + return false; +} + +S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector& suggestions) const +{ + 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(); +} + +const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_name) const +{ + for (LLSD::array_const_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) + { + const LLSD& dict_entry = *it; + if (dict_name == dict_entry["language"].asString()) + return dict_entry; + } + return LLSD(); +} + +void LLSpellChecker::refreshDictionaryMap() +{ + const std::string app_path = getDictionaryAppPath(); + const std::string user_path = getDictionaryUserPath(); + + // Load dictionary information (file name, friendly name, ...) + llifstream user_map(user_path + "dictionaries.xml", std::ios::binary); + if ( (!user_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(mDictMap, user_map)) || (0 == mDictMap.size()) ) + { + llifstream app_map(app_path + "dictionaries.xml", std::ios::binary); + if ( (!app_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(mDictMap, app_map)) || (0 == mDictMap.size()) ) + return; + } + + // Look for installed dictionaries + std::string tmp_app_path, tmp_user_path; + for (LLSD::array_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it) + { + LLSD& sdDict = *it; + tmp_app_path = (sdDict.has("name")) ? app_path + sdDict["name"].asString() : LLStringUtil::null; + tmp_user_path = (sdDict.has("name")) ? user_path + sdDict["name"].asString() : LLStringUtil::null; + sdDict["installed"] = + (!tmp_app_path.empty()) && + ( ((gDirUtilp->fileExists(tmp_user_path + ".aff")) && (gDirUtilp->fileExists(tmp_user_path + ".dic"))) || + ((gDirUtilp->fileExists(tmp_app_path + ".aff")) && (gDirUtilp->fileExists(tmp_app_path + ".dic"))) ); + sdDict["has_custom"] = (!tmp_user_path.empty()) && (gDirUtilp->fileExists(tmp_user_path + DICT_CUSTOM_SUFFIX + ".dic")); + sdDict["has_ignore"] = (!tmp_user_path.empty()) && (gDirUtilp->fileExists(tmp_user_path + DICT_IGNORE_SUFFIX + ".dic")); + } +} + +void LLSpellChecker::addToCustomDictionary(const std::string& word) +{ + if (mHunspell) + { + mHunspell->add(word.c_str()); + } + addToDictFile(getDictionaryUserPath() + mDictFile + DICT_CUSTOM_SUFFIX + ".dic", word); + sSettingsChangeSignal(); +} + +void LLSpellChecker::addToIgnoreList(const std::string& word) +{ + std::string word_lower(word); + LLStringUtil::toLower(word_lower); + if (mIgnoreList.end() != std::find(mIgnoreList.begin(), mIgnoreList.end(), word_lower)) + { + mIgnoreList.push_back(word_lower); + addToDictFile(getDictionaryUserPath() + mDictFile + DICT_IGNORE_SUFFIX + ".dic", word_lower); + sSettingsChangeSignal(); + } +} + +void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::string& word) +{ + std::vector word_list; + + if (gDirUtilp->fileExists(dict_path)) + { + llifstream file_in(dict_path, std::ios::in); + if (file_in.is_open()) + { + std::string word; int line_num = 0; + while (getline(file_in, word)) + { + // Skip over the first line since that's just a line count + if (0 != line_num) + word_list.push_back(word); + line_num++; + } + } + else + { + // TODO: show error message? + return; + } + } + + word_list.push_back(word); + + llofstream file_out(dict_path, std::ios::out | std::ios::trunc); + if (file_out.is_open()) + { + file_out << word_list.size() << std::endl; + for (std::vector::const_iterator itWord = word_list.begin(); itWord != word_list.end(); ++itWord) + file_out << *itWord << std::endl; + file_out.close(); + } +} + +void LLSpellChecker::setSecondaryDictionaries(std::list dict_list) +{ + if (!getUseSpellCheck()) + { + return; + } + + // Check if we're only adding secondary dictionaries, or removing them + std::list dict_add(llmax(dict_list.size(), mDictSecondary.size())), dict_rem(llmax(dict_list.size(), mDictSecondary.size())); + dict_list.sort(); + mDictSecondary.sort(); + std::list::iterator end_added = std::set_difference(dict_list.begin(), dict_list.end(), mDictSecondary.begin(), mDictSecondary.end(), dict_add.begin()); + std::list::iterator end_removed = std::set_difference(mDictSecondary.begin(), mDictSecondary.end(), dict_list.begin(), dict_list.end(), dict_rem.begin()); + + if (end_removed != dict_rem.begin()) // We can't remove secondary dictionaries so we need to recreate the Hunspell instance + { + mDictSecondary = dict_list; + + std::string dict_name = mDictName; + initHunspell(dict_name); + } + else if (end_added != dict_add.begin()) // Add the new secondary dictionaries one by one + { + const std::string app_path = getDictionaryAppPath(); + const std::string user_path = getDictionaryUserPath(); + for (std::list::const_iterator it_added = dict_add.begin(); it_added != end_added; ++it_added) + { + 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) +{ + if (mHunspell) + { + delete mHunspell; + mHunspell = NULL; + mDictName.clear(); + mDictFile.clear(); + mIgnoreList.clear(); + } + + const LLSD dict_entry = (!dict_name.empty()) ? getDictionaryData(dict_name) : LLSD(); + if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) + { + sSettingsChangeSignal(); + return; + } + + const std::string app_path = getDictionaryAppPath(); + const std::string user_path = getDictionaryUserPath(); + if (dict_entry.has("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; + mDictFile = dict_entry["name"].asString(); + + if (dict_entry["has_custom"].asBoolean()) + { + const std::string filename_dic = user_path + mDictFile + DICT_CUSTOM_SUFFIX + ".dic"; + mHunspell->add_dic(filename_dic.c_str()); + } + + if (dict_entry["has_ignore"].asBoolean()) + { + llifstream file_in(user_path + mDictFile + DICT_IGNORE_SUFFIX + ".dic", std::ios::in); + if (file_in.is_open()) + { + std::string word; int idxLine = 0; + while (getline(file_in, word)) + { + // Skip over the first line since that's just a line count + if (0 != idxLine) + { + LLStringUtil::toLower(word); + mIgnoreList.push_back(word); + } + idxLine++; + } + } + } + + for (std::list::const_iterator it = mDictSecondary.begin(); it != mDictSecondary.end(); ++it) + { + 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()); + } + } + + sSettingsChangeSignal(); +} + +// static +const std::string LLSpellChecker::getDictionaryAppPath() +{ + std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, DICT_DIR, ""); + return dict_path; +} + +// static +const std::string LLSpellChecker::getDictionaryUserPath() +{ + std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, DICT_DIR, ""); + if (!gDirUtilp->fileExists(dict_path)) + { + LLFile::mkdir(dict_path); + } + return dict_path; +} + +// static +bool LLSpellChecker::getUseSpellCheck() +{ + return (LLSpellChecker::instanceExists()) && (LLSpellChecker::instance().mHunspell); +} + +// 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) +{ + if ( (((dict_name.empty()) && (getUseSpellCheck())) || (!dict_name.empty())) && + (LLSpellChecker::instance().mDictName != dict_name) ) + { + LLSpellChecker::instance().initHunspell(dict_name); + } +} diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h new file mode 100644 index 0000000000..affdac2907 --- /dev/null +++ b/indra/llui/llspellcheck.h @@ -0,0 +1,77 @@ +/** + * @file llspellcheck.h + * @brief Spell checking functionality + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLSPELLCHECK_H +#define LLSPELLCHECK_H + +#include "llsingleton.h" +#include + +class Hunspell; + +class LLSpellChecker : public LLSingleton +{ + friend class LLSingleton; +protected: + LLSpellChecker(); + ~LLSpellChecker(); + +public: + void addToCustomDictionary(const std::string& word); + void addToIgnoreList(const std::string& word); + bool checkSpelling(const std::string& word) const; + S32 getSuggestions(const std::string& word, std::vector& suggestions) const; + +public: + const LLSD getDictionaryData(const std::string& dict_name) const; + const LLSD& getDictionaryMap() const { return mDictMap; } + void refreshDictionaryMap(); + void setSecondaryDictionaries(std::list dictList); +protected: + void addToDictFile(const std::string& dict_path, const std::string& word); + void initHunspell(const std::string& dict_name); + +public: + static const std::string getDictionaryAppPath(); + static const std::string getDictionaryUserPath(); + static bool getUseSpellCheck(); + static void setUseSpellCheck(const std::string& dict_name); + + typedef boost::signals2::signal settings_change_signal_t; + static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb); + +protected: + Hunspell* mHunspell; + std::string mDictName; + std::string mDictFile; + LLSD mDictMap; + std::list mDictSecondary; + std::vector mIgnoreList; + + static settings_change_signal_t sSettingsChangeSignal; +}; + +#endif // LLSPELLCHECK_H diff --git a/indra/llui/llspellcheckmenuhandler.h b/indra/llui/llspellcheckmenuhandler.h new file mode 100644 index 0000000000..d5c95bad39 --- /dev/null +++ b/indra/llui/llspellcheckmenuhandler.h @@ -0,0 +1,46 @@ +/** + * @file llspellcheckmenuhandler.h + * @brief Interface used by spell check menu handling + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLSPELLCHECKMENUHANDLER_H +#define LLSPELLCHECKMENUHANDLER_H + +class LLSpellCheckMenuHandler +{ +public: + virtual bool getSpellCheck() const { return false; } + + virtual const std::string& getSuggestion(U32 index) const { return LLStringUtil::null; } + virtual U32 getSuggestionCount() const { return 0; } + virtual void replaceWithSuggestion(U32 index){} + + virtual void addToDictionary() {} + virtual bool canAddToDictionary() const { return false; } + + virtual void addToIgnore() {} + virtual bool canAddToIgnore() const { return false; } +}; + +#endif // LLSPELLCHECKMENUHANDLER_H diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 1ea623791d..1ad3ee1dd1 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12082,6 +12082,28 @@ Value 10.0 + SpellCheck + + Comment + Enable spellchecking on line and text editors + Persist + 1 + Type + Boolean + Value + 1 + + SpellCheckDictionary + + Comment + Current primary and secondary dictionaries used for spell checking + Persist + 1 + Type + String + Value + English (United States) + UseNewWalkRun Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 0861fe85a8..698f2469a3 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -91,6 +91,7 @@ #include "llsecondlifeurls.h" #include "llupdaterservice.h" #include "llcallfloater.h" +#include "llspellcheck.h" // Linden library includes #include "llavatarnamecache.h" @@ -112,6 +113,7 @@ // Third party library includes #include #include +#include @@ -2488,6 +2490,18 @@ bool LLAppViewer::initConfiguration() //gDirUtilp->setSkinFolder("default"); } + if (gSavedSettings.getBOOL("SpellCheck")) + { + std::list dict_list; + boost::split(dict_list, gSavedSettings.getString("SpellCheckDictionary"), boost::is_any_of(std::string(","))); + if (!dict_list.empty()) + { + LLSpellChecker::setUseSpellCheck(dict_list.front()); + dict_list.pop_front(); + LLSpellChecker::instance().setSecondaryDictionaries(dict_list); + } + } + mYieldTime = gSavedSettings.getS32("YieldTime"); // Read skin/branding settings if specified. diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 7e02a41e7e..89360778d1 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -739,6 +739,7 @@ bool idle_startup() { display_startup(); initialize_edit_menu(); + initialize_spellcheck_menu(); display_startup(); init_menus(); display_startup(); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 093b84413a..7b6dbfaa0b 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -71,8 +71,12 @@ #include "llpaneloutfitsinventory.h" #include "llpanellogin.h" #include "llpaneltopinfobar.h" +#include "llspellcheck.h" #include "llupdaterservice.h" +// Third party library includes +#include + #ifdef TOGGLE_HACKED_GODLIKE_VIEWER BOOL gHackGodmode = FALSE; #endif @@ -498,6 +502,24 @@ bool handleForceShowGrid(const LLSD& newvalue) return true; } +bool handleSpellCheckChanged() +{ + if (gSavedSettings.getBOOL("SpellCheck")) + { + std::list dict_list; + boost::split(dict_list, gSavedSettings.getString("SpellCheckDictionary"), boost::is_any_of(std::string(","))); + if (!dict_list.empty()) + { + LLSpellChecker::setUseSpellCheck(dict_list.front()); + dict_list.pop_front(); + LLSpellChecker::instance().setSecondaryDictionaries(dict_list); + return true; + } + } + LLSpellChecker::setUseSpellCheck(LLStringUtil::null); + return true; +} + bool toggle_agent_pause(const LLSD& newvalue) { if ( newvalue.asBoolean() ) @@ -704,6 +726,8 @@ void settings_setup_listeners() gSavedSettings.getControl("UpdaterServiceSetting")->getSignal()->connect(boost::bind(&toggle_updater_service_active, _2)); gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2)); gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2)); + gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&handleSpellCheckChanged)); + gSavedSettings.getControl("SpellCheckDictionary")->getSignal()->connect(boost::bind(&handleSpellCheckChanged)); } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 0104d35e53..2a11f3cc16 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -81,6 +81,7 @@ #include "llrootview.h" #include "llsceneview.h" #include "llselectmgr.h" +#include "llspellcheckmenuhandler.h" #include "llstatusbar.h" #include "lltextureview.h" #include "lltoolcomp.h" @@ -4984,6 +4985,78 @@ class LLEditDelete : public view_listener_t } }; +void handle_spellcheck_replace_with_suggestion(const LLUICtrl* ctrl, const LLSD& param) +{ + const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) + { + return; + } + + U32 index = 0; + if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) + { + return; + } + + spellcheck_handler->replaceWithSuggestion(index); +} + +bool visible_spellcheck_suggestion(LLUICtrl* ctrl, const LLSD& param) +{ + LLMenuItemGL* item = dynamic_cast(ctrl); + const LLContextMenu* menu = (item) ? dynamic_cast(item->getParent()) : NULL; + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) + { + return false; + } + + U32 index = 0; + if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) + { + return false; + } + + item->setLabel(spellcheck_handler->getSuggestion(index)); + return true; +} + +void handle_spellcheck_add_to_dictionary(const LLUICtrl* ctrl) +{ + const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + if ( (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()) ) + { + spellcheck_handler->addToDictionary(); + } +} + +bool enable_spellcheck_add_to_dictionary(const LLUICtrl* ctrl) +{ + const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + return (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()); +} + +void handle_spellcheck_add_to_ignore(const LLUICtrl* ctrl) +{ + const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + if ( (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()) ) + { + spellcheck_handler->addToIgnore(); + } +} + +bool enable_spellcheck_add_to_ignore(const LLUICtrl* ctrl) +{ + const LLContextMenu* menu = dynamic_cast(ctrl->getParent()); + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast(menu->getSpawningView()) : NULL; + return (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()); +} + bool enable_object_delete() { bool new_value = @@ -7933,6 +8006,19 @@ void initialize_edit_menu() } +void initialize_spellcheck_menu() +{ + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); + + commit.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); + enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2)); + commit.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); + enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1)); + commit.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); + enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1)); +} + void initialize_menus() { // A parameterized event handler used as ctrl-8/9/0 zoom controls below. diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 87cb4efbc4..8c40762865 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -39,6 +39,7 @@ class LLObjectSelection; class LLSelectNode; void initialize_edit_menu(); +void initialize_spellcheck_menu(); void init_menus(); void cleanup_menus(); diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 0931c4ec9b..1b732676e4 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -91,6 +91,8 @@ class ViewerManifest(LLManifest): # ... and the entire windlight directory self.path("windlight") + # ... and the pre-installed spell checking dictionaries + self.path("dictionaries") self.end_prefix("app_settings") if self.prefix(src="character"): @@ -393,6 +395,9 @@ class WindowsManifest(ViewerManifest): self.path("ssleay32.dll") self.path("libeay32.dll") + # Hunspell + self.path("libhunspell.dll") + # For google-perftools tcmalloc allocator. try: if self.args['configuration'].lower() == 'debug': @@ -659,6 +664,7 @@ class DarwinManifest(ViewerManifest): # copy additional libs in /Contents/MacOS/ self.path("../packages/lib/release/libndofdev.dylib", dst="Resources/libndofdev.dylib") + self.path("../packages/lib/release/libhunspell-1.3.dylib", dst="Resources/libhunspell-1.3.dylib") self.path("../viewer_components/updater/scripts/darwin/update_install", "MacOS/update_install") @@ -1053,6 +1059,8 @@ class Linux_i686Manifest(LinuxManifest): self.path("libopenjpeg.so.1.4.0") self.path("libopenjpeg.so.1") self.path("libopenjpeg.so") + self.path("libhunspell-1.3.so") + self.path("libhunspell-1.3.so.0") self.path("libalut.so") self.path("libopenal.so", "libopenal.so.1") self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname -- cgit v1.2.3 From f0d1afc2266e13b4f36f750ba5e721e427caf7b8 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Fri, 20 Jan 2012 18:07:35 +0100 Subject: STORM-276 Added spellcheck functionality to the LLLineEditor control --- indra/llcommon/llstring.h | 3 + indra/llui/lllineeditor.cpp | 217 ++++++++++++++++++++- indra/llui/lllineeditor.h | 29 ++- .../skins/default/xui/en/menu_text_editor.xml | 79 ++++++++ 4 files changed, 324 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 7e41e787b5..3a27badb5a 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -182,6 +182,9 @@ public: static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } static bool isPunct(llwchar a) { return iswpunct(a) != 0; } + static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } + static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } + static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 06dfc90d83..5479c080bd 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -45,6 +45,7 @@ #include "llkeyboard.h" #include "llrect.h" #include "llresmgr.h" +#include "llspellcheck.h" #include "llstring.h" #include "llwindow.h" #include "llui.h" @@ -65,6 +66,7 @@ const S32 SCROLL_INCREMENT_ADD = 0; // make space for typing const S32 SCROLL_INCREMENT_DEL = 4; // make space for baskspacing const F32 AUTO_SCROLL_TIME = 0.05f; const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. *TODO: make this equal to the double click interval? +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and showing spell checking feedback for the word the cursor is on const std::string PASSWORD_ASTERISK( "\xE2\x80\xA2" ); // U+2022 BULLET @@ -88,6 +90,7 @@ LLLineEditor::Params::Params() background_image_focused("background_image_focused"), select_on_focus("select_on_focus", false), revert_on_esc("revert_on_esc", true), + spellcheck("spellcheck", false), commit_on_focus_lost("commit_on_focus_lost", true), ignore_tab("ignore_tab", true), is_password("is_password", false), @@ -134,6 +137,9 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mIgnoreArrowKeys( FALSE ), mIgnoreTab( p.ignore_tab ), mDrawAsterixes( p.is_password ), + mSpellCheck( p.spellcheck ), + mSpellCheckStart(-1), + mSpellCheckEnd(-1), mSelectAllonFocusReceived( p.select_on_focus ), mSelectAllonCommit( TRUE ), mPassDelete(FALSE), @@ -177,6 +183,12 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) updateTextPadding(); setCursor(mText.length()); + if (mSpellCheck) + { + LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLLineEditor::onSpellCheckSettingsChange, this)); + } + mSpellCheckTimer.reset(); + setPrevalidateInput(p.prevalidate_input_callback()); setPrevalidate(p.prevalidate_callback()); @@ -519,6 +531,94 @@ void LLLineEditor::selectAll() updatePrimary(); } +bool LLLineEditor::getSpellCheck() const +{ + return (LLSpellChecker::getUseSpellCheck()) && (!mReadOnly) && (mSpellCheck); +} + +const std::string& LLLineEditor::getSuggestion(U32 index) const +{ + return (index < mSuggestionList.size()) ? mSuggestionList[index] : LLStringUtil::null; +} + +U32 LLLineEditor::getSuggestionCount() const +{ + return mSuggestionList.size(); +} + +void LLLineEditor::replaceWithSuggestion(U32 index) +{ + for (std::list >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) + { + deselect(); + + // Delete the misspelled word + mText.erase(it->first, it->second - it->first); + + // Insert the suggestion in its place + LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]); + mText.insert(it->first, suggestion); + setCursor(it->first + (S32)suggestion.length()); + + break; + } + } + mSpellCheckStart = mSpellCheckEnd = -1; +} + +void LLLineEditor::addToDictionary() +{ + if (canAddToDictionary()) + { + LLSpellChecker::instance().addToCustomDictionary(getMisspelledWord(mCursorPos)); + } +} + +bool LLLineEditor::canAddToDictionary() const +{ + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); +} + +void LLLineEditor::addToIgnore() +{ + if (canAddToIgnore()) + { + LLSpellChecker::instance().addToIgnoreList(getMisspelledWord(mCursorPos)); + } +} + +bool LLLineEditor::canAddToIgnore() const +{ + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); +} + +std::string LLLineEditor::getMisspelledWord(U32 pos) const +{ + for (std::list >::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; +} + +bool LLLineEditor::isMisspelledWord(U32 pos) const +{ + for (std::list >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= pos) && (it->second >= pos) ) + return true; + } + return false; +} + +void LLLineEditor::onSpellCheckSettingsChange() +{ + // Recheck the spelling on every change + mSpellCheckStart = mSpellCheckEnd = -1; +} BOOL LLLineEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { @@ -1453,6 +1553,10 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask ) { mKeystrokeCallback(this); } + if ( (!selection_modified) && (KEY_BACKSPACE == key) ) + { + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); + } } } } @@ -1510,6 +1614,7 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char) // We'll have to do something about this if something ever changes! - Doug mKeystrokeCallback( this ); } + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } } return handled; @@ -1560,6 +1665,7 @@ void LLLineEditor::doDelete() { mKeystrokeCallback( this ); } + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } } } @@ -1756,7 +1862,7 @@ void LLLineEditor::draw() if( (rendered_pixels_right < (F32)mTextRightEdge) && (rendered_text < text_len) ) { // unselected, right side - mGLFont->render( + rendered_text += mGLFont->render( mText, mScrollHPos + rendered_text, rendered_pixels_right, text_bottom, text_color, @@ -1770,7 +1876,7 @@ void LLLineEditor::draw() } else { - mGLFont->render( + rendered_text = mGLFont->render( mText, mScrollHPos, rendered_pixels_right, text_bottom, text_color, @@ -1785,6 +1891,80 @@ void LLLineEditor::draw() mBorder->setVisible(FALSE); // no more programmatic art. #endif + if ( (getSpellCheck()) && (mText.length() > 2) ) + { + // Calculate start and end indices for the first and last visible word + U32 start = prevWordPos(mScrollHPos), end = nextWordPos(mScrollHPos + rendered_text); + + if ( (mSpellCheckStart != start) || (mSpellCheckEnd = end) ) + { + const LLWString& text = mText.getWString().substr(start, end); + + // 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(); + while (word_start < text.length()) + { + // Find the end of the current word (special case handling for "'" when it's used as a contraction) + word_end = word_start + 1; + while ( (word_end < text.length()) && + ((LLWStringUtil::isPartOfWord(text[word_end])) || + ((L'\'' == text[word_end]) && (word_end + 1 < text.length()) && + (LLStringOps::isAlnum(text[word_end - 1])) && (LLStringOps::isAlnum(text[word_end + 1])))) ) + { + 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(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; + mSpellCheckEnd = end; + } + + // Draw squiggly lines under any (visible) misspelled words + for (std::list >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + // 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; + + gGL.color4ub(255, 0, 0, 200); + while (pxStart < pxEnd) + { + gl_line_2d(pxStart, text_bottom - 2, pxStart + 3, text_bottom + 1); + gl_line_2d(pxStart + 3, text_bottom + 1, pxStart + 6, text_bottom - 2); + pxStart += 6; + } + } + } + // If we're editing... if( hasFocus()) { @@ -2242,6 +2422,7 @@ void LLLineEditor::updatePreedit(const LLWString &preedit_string, { mKeystrokeCallback( this ); } + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const @@ -2393,7 +2574,37 @@ void LLLineEditor::showContextMenu(S32 x, S32 y) S32 screen_x, screen_y; localPointToScreen(x, y, &screen_x, &screen_y); - menu->show(screen_x, screen_y); + + if (hasSelection()) + { + if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + deselect(); + else + setCursor(llmax(mSelectionStart, mSelectionEnd)); + } + else + { + setCursorAtLocalPos(x); + } + + bool use_spellcheck = getSpellCheck(), is_misspelled = false; + if (use_spellcheck) + { + mSuggestionList.clear(); + + // If the cursor is on a misspelled word, retrieve suggestions for it + std::string misspelled_word = getMisspelledWord(mCursorPos); + if ((is_misspelled = !misspelled_word.empty()) == true) + { + LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); + } + } + + menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); + menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); + menu->show(screen_x, screen_y, this); } } diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 2518dbe3c7..9513274f21 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -40,6 +40,7 @@ #include "llframetimer.h" #include "lleditmenuhandler.h" +#include "llspellcheckmenuhandler.h" #include "lluictrl.h" #include "lluiimage.h" #include "lluistring.h" @@ -54,7 +55,7 @@ class LLButton; class LLContextMenu; class LLLineEditor -: public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor +: public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor, public LLSpellCheckMenuHandler { public: @@ -86,6 +87,7 @@ public: Optional select_on_focus, revert_on_esc, + spellcheck, commit_on_focus_lost, ignore_tab, is_password; @@ -146,6 +148,24 @@ public: virtual void deselect(); virtual BOOL canDeselect() const; + // LLSpellCheckMenuHandler overrides + /*virtual*/ bool getSpellCheck() const; + + /*virtual*/ const std::string& getSuggestion(U32 index) const; + /*virtual*/ U32 getSuggestionCount() const; + /*virtual*/ void replaceWithSuggestion(U32 index); + + /*virtual*/ void addToDictionary(); + /*virtual*/ bool canAddToDictionary() const; + + /*virtual*/ void addToIgnore(); + /*virtual*/ bool canAddToIgnore() const; + + // Spell checking helper functions + std::string getMisspelledWord(U32 pos) const; + bool isMisspelledWord(U32 pos) const; + void onSpellCheckSettingsChange(); + // view overrides virtual void draw(); virtual void reshape(S32 width,S32 height,BOOL called_from_parent=TRUE); @@ -322,6 +342,13 @@ protected: S32 mLastSelectionStart; S32 mLastSelectionEnd; + bool mSpellCheck; + S32 mSpellCheckStart; + S32 mSpellCheckEnd; + LLTimer mSpellCheckTimer; + std::list > mMisspellRanges; + std::vector mSuggestionList; + LLTextValidate::validate_func_t mPrevalidateFunc; LLTextValidate::validate_func_t mPrevalidateInputFunc; diff --git a/indra/newview/skins/default/xui/en/menu_text_editor.xml b/indra/newview/skins/default/xui/en/menu_text_editor.xml index fe8489166b..70b40dd89b 100644 --- a/indra/newview/skins/default/xui/en/menu_text_editor.xml +++ b/indra/newview/skins/default/xui/en/menu_text_editor.xml @@ -1,6 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Mon, 23 Jan 2012 19:22:47 +0100 Subject: STORM-276 Added missing library includes --- indra/newview/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indra') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6b2fe1e45a..bb0c4a9979 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -71,6 +71,7 @@ include_directories( ${LLLOGIN_INCLUDE_DIRS} ${UPDATER_INCLUDE_DIRS} ${LIBS_PREBUILT_DIR}/include/collada + ${LIBS_PREBUILD_DIR}/include/hunspell ${OPENAL_LIB_INCLUDE_DIRS} ${LIBS_PREBUILT_DIR}/include/collada/1.4 ) @@ -1566,6 +1567,9 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcp100.dll ${SHARED_LIB_STAGING_DIR}/Debug/msvcr100d.dll ${SHARED_LIB_STAGING_DIR}/Debug/msvcp100d.dll + ${SHARED_LIB_STAGING_DIR}/Release/libhunspell.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libhunspell.dll + ${SHARED_LIB_STAGING_DIR}/Debug/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/SLVoice.exe ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp.dll @@ -1745,6 +1749,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${NDOF_LIBRARY} + ${HUNSPELL_LIBRARY} ${viewer_LIBRARIES} ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} -- cgit v1.2.3 From b81bf4f6f182e6345889d70140b34b15cbfb8d27 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Mon, 23 Jan 2012 19:31:47 +0100 Subject: STORM-276 Enabled spellchecking on selective line editors --- indra/newview/skins/default/xui/en/floater_chat_bar.xml | 1 + indra/newview/skins/default/xui/en/floater_im_session.xml | 1 + indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml | 1 + 3 files changed, 3 insertions(+) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_chat_bar.xml b/indra/newview/skins/default/xui/en/floater_chat_bar.xml index 63992462b3..32a2c26cf0 100644 --- a/indra/newview/skins/default/xui/en/floater_chat_bar.xml +++ b/indra/newview/skins/default/xui/en/floater_chat_bar.xml @@ -46,6 +46,7 @@ left="0" max_length_bytes="1023" name="chat_box" + spellcheck="true" text_pad_left="5" text_pad_right="25" tool_tip="Press Enter to say, Ctrl+Enter to shout" diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index a2739a8339..2f3788ec3d 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -84,6 +84,7 @@ label="To" layout="bottomleft" name="chat_editor" + spellcheck="true" tab_group="3" width="249"> diff --git a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml index 21c627cdfb..6bc9c48729 100644 --- a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml @@ -19,6 +19,7 @@ left="0" max_length_bytes="1023" name="chat_box" + spellcheck="true" text_pad_left="5" text_pad_right="25" tool_tip="Press Enter to say, Ctrl+Enter to shout" -- cgit v1.2.3 From a9d11219779473c7d0c06bd0e56b0f068a487ad0 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Fri, 3 Feb 2012 15:20:34 +0100 Subject: STORM-276 Added spellcheck functionality to the LLTextEditor control --- indra/llui/lltextbase.cpp | 209 +++++++++++++++++++++++++++++++++++++++++++- indra/llui/lltextbase.h | 31 ++++++- indra/llui/lltexteditor.cpp | 34 ++++++- 3 files changed, 271 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 0040be45c7..7eee1d39c4 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -32,6 +32,7 @@ #include "lllocalcliprect.h" #include "llmenugl.h" #include "llscrollcontainer.h" +#include "llspellcheck.h" #include "llstl.h" #include "lltextparser.h" #include "lltextutil.h" @@ -155,6 +156,7 @@ LLTextBase::Params::Params() plain_text("plain_text",false), track_end("track_end", false), read_only("read_only", false), + spellcheck("spellcheck", false), v_pad("v_pad", 0), h_pad("h_pad", 0), clip("clip", true), @@ -181,6 +183,9 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mFontShadow(p.font_shadow), mPopupMenu(NULL), mReadOnly(p.read_only), + mSpellCheck(p.spellcheck), + mSpellCheckStart(-1), + mSpellCheckEnd(-1), mCursorColor(p.cursor_color), mFgColor(p.text_color), mBorderVisible( p.border_visible ), @@ -246,6 +251,12 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) addChild(mDocumentView); } + if (mSpellCheck) + { + LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLTextBase::onSpellCheckSettingsChange, this)); + } + mSpellCheckTimer.reset(); + createDefaultSegment(); updateRects(); @@ -530,8 +541,86 @@ void LLTextBase::drawText() return; } + // Perform spell check if needed + if ( (getSpellCheck()) && (getWText().length() > 2) ) + { + // Calculate start and end indices for the spell checking range + S32 start = line_start, end = getLineEnd(last_line); + + if ( (mSpellCheckStart != start) || (mSpellCheckEnd != end) ) + { + const LLWString& wstrText = getWText(); + mMisspellRanges.clear(); + + segment_set_t::iterator seg_it = getSegIterContaining(start); + while (mSegments.end() != seg_it) + { + LLTextSegmentPtr text_segment = *seg_it; + if ( (text_segment.isNull()) || (text_segment->getStart() >= end) ) + { + break; + } + + if (!text_segment->canEdit()) + { + ++seg_it; + continue; + } + + // Combine adjoining text segments into one + U32 seg_start = text_segment->getStart(), seg_end = llmin(text_segment->getEnd(), end); + while (mSegments.end() != ++seg_it) + { + text_segment = *seg_it; + if ( (text_segment.isNull()) || (!text_segment->canEdit()) || (text_segment->getStart() >= end) ) + { + break; + } + seg_end = llmin(text_segment->getEnd(), end); + } + + // 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) + { + // Find the end of the current word (special case handling for "'" when it's used as a contraction) + word_end = word_start + 1; + while ( (word_end < seg_end) && + ((LLWStringUtil::isPartOfWord(wstrText[word_end])) || + ((L'\'' == wstrText[word_end]) && + (LLStringOps::isAlnum(wstrText[word_end - 1])) && (LLStringOps::isAlnum(wstrText[word_end + 1])))) ) + { + 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)); + if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) ) + { + mMisspellRanges.push_back(std::pair(word_start, word_end)); + } + + // Find the start of the next word + word_start = word_end + 1; + while ( (word_start < seg_end) && (!LLWStringUtil::isPartOfWord(wstrText[word_start])) ) + word_start++; + } + } + + mSpellCheckStart = start; + mSpellCheckEnd = end; + } + } + LLTextSegmentPtr cur_segment = *seg_iter; + std::list >::const_iterator misspell_it = std::lower_bound(mMisspellRanges.begin(), mMisspellRanges.end(), std::pair(line_start, 0)); for (S32 cur_line = first_line; cur_line < last_line; cur_line++) { S32 next_line = cur_line + 1; @@ -566,7 +655,8 @@ void LLTextBase::drawText() cur_segment = *seg_iter; } - S32 clipped_end = llmin( line_end, cur_segment->getEnd() ) - cur_segment->getStart(); + S32 seg_end = llmin(line_end, cur_segment->getEnd()); + S32 clipped_end = seg_end - cur_segment->getStart(); if (mUseEllipses // using ellipses && clipped_end == line_end // last segment on line @@ -578,6 +668,35 @@ void LLTextBase::drawText() text_rect.mRight -= 2; } + // Draw squiggly lines under any visible misspelled words + while ( (mMisspellRanges.end() != misspell_it) && (misspell_it->first < seg_end) && (misspell_it->second > seg_start) ) + { + // Skip the current word if the user is still busy editing it + if ( (!mSpellCheckTimer.hasExpired()) && (misspell_it->first <= (U32)mCursorPos) && (misspell_it->second >= (U32)mCursorPos) ) + continue; + + S32 squiggle_start = 0, squiggle_end = 0, pony = 0; + cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_it->first - seg_start, squiggle_start, pony); + cur_segment->getDimensions(misspell_it->first - cur_segment->getStart(), misspell_it->second - misspell_it->first, squiggle_end, pony); + squiggle_start += text_rect.mLeft; + + pony = (squiggle_end + 3) / 6; + squiggle_start += squiggle_end / 2 - pony * 3; + squiggle_end = squiggle_start + pony * 6; + + gGL.color4ub(255, 0, 0, 200); + while (squiggle_start < squiggle_end) + { + gl_line_2d(squiggle_start, text_rect.mBottom - 2, squiggle_start + 3, text_rect.mBottom + 1); + gl_line_2d(squiggle_start + 3, text_rect.mBottom + 1, squiggle_start + 6, text_rect.mBottom - 2); + squiggle_start += 6; + } + + if (misspell_it->second > seg_end) + break; + ++misspell_it; + } + text_rect.mLeft = (S32)(cur_segment->draw(seg_start - cur_segment->getStart(), clipped_end, selection_left, selection_right, text_rect)); seg_start = clipped_end + cur_segment->getStart(); @@ -1103,6 +1222,94 @@ void LLTextBase::deselect() mIsSelecting = FALSE; } +bool LLTextBase::getSpellCheck() const +{ + return (LLSpellChecker::getUseSpellCheck()) && (!mReadOnly) && (mSpellCheck); +} + +const std::string& LLTextBase::getSuggestion(U32 index) const +{ + return (index < mSuggestionList.size()) ? mSuggestionList[index] : LLStringUtil::null; +} + +U32 LLTextBase::getSuggestionCount() const +{ + return mSuggestionList.size(); +} + +void LLTextBase::replaceWithSuggestion(U32 index) +{ + for (std::list >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) + { + deselect(); + + // Delete the misspelled word + removeStringNoUndo(it->first, it->second - it->first); + + // Insert the suggestion in its place + LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]); + insertStringNoUndo(it->first, utf8str_to_wstring(mSuggestionList[index])); + setCursorPos(it->first + (S32)suggestion.length()); + + break; + } + } + mSpellCheckStart = mSpellCheckEnd = -1; +} + +void LLTextBase::addToDictionary() +{ + if (canAddToDictionary()) + { + LLSpellChecker::instance().addToCustomDictionary(getMisspelledWord(mCursorPos)); + } +} + +bool LLTextBase::canAddToDictionary() const +{ + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); +} + +void LLTextBase::addToIgnore() +{ + if (canAddToIgnore()) + { + LLSpellChecker::instance().addToIgnoreList(getMisspelledWord(mCursorPos)); + } +} + +bool LLTextBase::canAddToIgnore() const +{ + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); +} + +std::string LLTextBase::getMisspelledWord(U32 pos) const +{ + for (std::list >::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; +} + +bool LLTextBase::isMisspelledWord(U32 pos) const +{ + for (std::list >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= pos) && (it->second >= pos) ) + return true; + } + return false; +} + +void LLTextBase::onSpellCheckSettingsChange() +{ + // Recheck the spelling on every change + mSpellCheckStart = mSpellCheckEnd = -1; +} // Sets the scrollbar from the cursor position void LLTextBase::updateScrollFromCursor() diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 0549141b72..90b147cee1 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -30,6 +30,7 @@ #include "v4color.h" #include "lleditmenuhandler.h" +#include "llspellcheckmenuhandler.h" #include "llstyle.h" #include "llkeywords.h" #include "llpanel.h" @@ -230,7 +231,8 @@ typedef LLPointer LLTextSegmentPtr; /// class LLTextBase : public LLUICtrl, - protected LLEditMenuHandler + protected LLEditMenuHandler, + public LLSpellCheckMenuHandler { public: friend class LLTextSegment; @@ -259,6 +261,7 @@ public: border_visible, track_end, read_only, + spellcheck, allow_scroll, plain_text, wrap, @@ -311,6 +314,24 @@ public: /*virtual*/ BOOL canDeselect() const; /*virtual*/ void deselect(); + // LLSpellCheckMenuHandler overrides + /*virtual*/ bool getSpellCheck() const; + + /*virtual*/ const std::string& getSuggestion(U32 index) const; + /*virtual*/ U32 getSuggestionCount() const; + /*virtual*/ void replaceWithSuggestion(U32 index); + + /*virtual*/ void addToDictionary(); + /*virtual*/ bool canAddToDictionary() const; + + /*virtual*/ void addToIgnore(); + /*virtual*/ bool canAddToIgnore() const; + + // Spell checking helper functions + std::string getMisspelledWord(U32 pos) const; + bool isMisspelledWord(U32 pos) const; + void onSpellCheckSettingsChange(); + // used by LLTextSegment layout code bool getWordWrap() { return mWordWrap; } bool getUseEllipses() { return mUseEllipses; } @@ -540,6 +561,14 @@ protected: BOOL mIsSelecting; // Are we in the middle of a drag-select? + // spell checking + bool mSpellCheck; + S32 mSpellCheckStart; + S32 mSpellCheckEnd; + LLTimer mSpellCheckTimer; + std::list > mMisspellRanges; + std::vector mSuggestionList; + // configuration S32 mHPad; // padding on left of text S32 mVPad; // padding above text diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 3a23ce1cac..c5957838ba 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -54,6 +54,7 @@ #include "llwindow.h" #include "lltextparser.h" #include "llscrollcontainer.h" +#include "llspellcheck.h" #include "llpanel.h" #include "llurlregistry.h" #include "lltooltip.h" @@ -77,6 +78,7 @@ template class LLTextEditor* LLView::getChild( const S32 UI_TEXTEDITOR_LINE_NUMBER_MARGIN = 32; const S32 UI_TEXTEDITOR_LINE_NUMBER_DIGITS = 4; const S32 SPACES_PER_TAB = 4; +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on /////////////////////////////////////////////////////////////////// @@ -1961,7 +1963,34 @@ void LLTextEditor::showContextMenu(S32 x, S32 y) S32 screen_x, screen_y; localPointToScreen(x, y, &screen_x, &screen_y); - mContextMenu->show(screen_x, screen_y); + + setCursorAtLocalPos(x, y, false); + if (hasSelection()) + { + if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + deselect(); + else + setCursorPos(llmax(mSelectionStart, mSelectionEnd)); + } + + bool use_spellcheck = getSpellCheck(), is_misspelled = false; + if (use_spellcheck) + { + mSuggestionList.clear(); + + // If the cursor is on a misspelled word, retrieve suggestions for it + std::string misspelled_word = getMisspelledWord(mCursorPos); + if ((is_misspelled = !misspelled_word.empty()) == true) + { + LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); + } + } + + mContextMenu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); + mContextMenu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); + mContextMenu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); + mContextMenu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); + mContextMenu->show(screen_x, screen_y, this); } @@ -2846,6 +2875,9 @@ void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& cal void LLTextEditor::onKeyStroke() { mKeystrokeSignal(this); + + mSpellCheckStart = mSpellCheckEnd = -1; + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } //virtual -- cgit v1.2.3 From 41e11a508379d8f6d2b95f835d2df9f4e2bbea01 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Fri, 3 Feb 2012 15:34:52 +0100 Subject: STORM-276 FIXED Selecting a character in a line editor and replacing it doesn't trigger a spell check --- indra/llui/lllineeditor.cpp | 53 ++++++++++++++++++++------------------------- indra/llui/lllineeditor.h | 1 + 2 files changed, 24 insertions(+), 30 deletions(-) (limited to 'indra') diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 5479c080bd..e67753292e 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -66,7 +66,7 @@ const S32 SCROLL_INCREMENT_ADD = 0; // make space for typing const S32 SCROLL_INCREMENT_DEL = 4; // make space for baskspacing const F32 AUTO_SCROLL_TIME = 0.05f; const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. *TODO: make this equal to the double click interval? -const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and showing spell checking feedback for the word the cursor is on +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on const std::string PASSWORD_ASTERISK( "\xE2\x80\xA2" ); // U+2022 BULLET @@ -1158,9 +1158,8 @@ void LLLineEditor::cut() LLUI::reportBadKeystroke(); } else - if( mKeystrokeCallback ) { - mKeystrokeCallback( this ); + onKeystroke(); } } } @@ -1294,9 +1293,8 @@ void LLLineEditor::pasteHelper(bool is_primary) LLUI::reportBadKeystroke(); } else - if( mKeystrokeCallback ) { - mKeystrokeCallback( this ); + onKeystroke(); } } } @@ -1549,10 +1547,7 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask ) // Notify owner if requested if (!need_to_rollback && handled) { - if (mKeystrokeCallback) - { - mKeystrokeCallback(this); - } + onKeystroke(); if ( (!selection_modified) && (KEY_BACKSPACE == key) ) { mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); @@ -1608,12 +1603,10 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char) // Notify owner if requested if( !need_to_rollback && handled ) { - if( mKeystrokeCallback ) - { - // HACK! The only usage of this callback doesn't do anything with the character. - // We'll have to do something about this if something ever changes! - Doug - mKeystrokeCallback( this ); - } + // HACK! The only usage of this callback doesn't do anything with the character. + // We'll have to do something about this if something ever changes! - Doug + onKeystroke(); + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } } @@ -1643,9 +1636,7 @@ void LLLineEditor::doDelete() if (!prevalidateInput(text_to_delete)) { - if( mKeystrokeCallback ) - mKeystrokeCallback( this ); - + onKeystroke(); return; } setCursor(getCursor() + 1); @@ -1661,10 +1652,8 @@ void LLLineEditor::doDelete() } else { - if( mKeystrokeCallback ) - { - mKeystrokeCallback( this ); - } + onKeystroke(); + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } } @@ -2296,6 +2285,15 @@ void LLLineEditor::setSelectAllonFocusReceived(BOOL b) mSelectAllonFocusReceived = b; } +void LLLineEditor::onKeystroke() +{ + if (mKeystrokeCallback) + { + mKeystrokeCallback(this); + } + + mSpellCheckStart = mSpellCheckEnd = -1; +} void LLLineEditor::setKeystrokeCallback(callback_t callback, void* user_data) { @@ -2418,10 +2416,8 @@ void LLLineEditor::updatePreedit(const LLWString &preedit_string, // Update of the preedit should be caused by some key strokes. mKeystrokeTimer.reset(); - if( mKeystrokeCallback ) - { - mKeystrokeCallback( this ); - } + onKeystroke(); + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } @@ -2575,6 +2571,7 @@ void LLLineEditor::showContextMenu(S32 x, S32 y) S32 screen_x, screen_y; localPointToScreen(x, y, &screen_x, &screen_y); + setCursorAtLocalPos(x); if (hasSelection()) { if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) @@ -2582,10 +2579,6 @@ void LLLineEditor::showContextMenu(S32 x, S32 y) else setCursor(llmax(mSelectionStart, mSelectionEnd)); } - else - { - setCursorAtLocalPos(x); - } bool use_spellcheck = getSpellCheck(), is_misspelled = false; if (use_spellcheck) diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 9513274f21..40f931ecc1 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -243,6 +243,7 @@ public: void setSelectAllonFocusReceived(BOOL b); void setSelectAllonCommit(BOOL b) { mSelectAllonCommit = b; } + void onKeystroke(); typedef boost::function callback_t; void setKeystrokeCallback(callback_t callback, void* user_data); -- cgit v1.2.3 From 49e0c38ee85214eb7d0e7e995d1a380ee2f60720 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Fri, 3 Feb 2012 19:45:00 +0100 Subject: STORM-276 Added preferences panel --- indra/llui/lllineeditor.cpp | 1 + indra/llui/llspellcheck.cpp | 12 +- indra/llui/llspellcheck.h | 29 +++-- indra/llui/lltextbase.cpp | 1 + indra/newview/llfloaterpreference.cpp | 95 +++++++++++++++ indra/newview/llfloaterpreference.h | 2 + indra/newview/skins/default/textures/textures.xml | 2 + .../skins/default/textures/widgets/Arrow_Left.png | Bin 0 -> 311 bytes .../skins/default/textures/widgets/Arrow_Right.png | Bin 0 -> 313 bytes .../skins/default/xui/en/floater_preferences.xml | 6 + .../xui/en/panel_preferences_spellcheck.xml | 132 +++++++++++++++++++++ 11 files changed, 261 insertions(+), 19 deletions(-) create mode 100644 indra/newview/skins/default/textures/widgets/Arrow_Left.png create mode 100644 indra/newview/skins/default/textures/widgets/Arrow_Right.png create mode 100644 indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml (limited to 'indra') diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index e67753292e..42cfc4cae9 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -617,6 +617,7 @@ bool LLLineEditor::isMisspelledWord(U32 pos) const void LLLineEditor::onSpellCheckSettingsChange() { // Recheck the spelling on every change + mMisspellRanges.clear(); mSpellCheckStart = mSpellCheckEnd = -1; } diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp index 433ca02852..65207144f8 100644 --- a/indra/llui/llspellcheck.cpp +++ b/indra/llui/llspellcheck.cpp @@ -186,7 +186,7 @@ void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::stri } } -void LLSpellChecker::setSecondaryDictionaries(std::list dict_list) +void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list) { if (!getUseSpellCheck()) { @@ -194,11 +194,11 @@ void LLSpellChecker::setSecondaryDictionaries(std::list dict_list) } // Check if we're only adding secondary dictionaries, or removing them - std::list dict_add(llmax(dict_list.size(), mDictSecondary.size())), dict_rem(llmax(dict_list.size(), mDictSecondary.size())); + dict_list_t dict_add(llmax(dict_list.size(), mDictSecondary.size())), dict_rem(llmax(dict_list.size(), mDictSecondary.size())); dict_list.sort(); mDictSecondary.sort(); - std::list::iterator end_added = std::set_difference(dict_list.begin(), dict_list.end(), mDictSecondary.begin(), mDictSecondary.end(), dict_add.begin()); - std::list::iterator end_removed = std::set_difference(mDictSecondary.begin(), mDictSecondary.end(), dict_list.begin(), dict_list.end(), dict_rem.begin()); + dict_list_t::iterator end_added = std::set_difference(dict_list.begin(), dict_list.end(), mDictSecondary.begin(), mDictSecondary.end(), dict_add.begin()); + dict_list_t::iterator end_removed = std::set_difference(mDictSecondary.begin(), mDictSecondary.end(), dict_list.begin(), dict_list.end(), dict_rem.begin()); if (end_removed != dict_rem.begin()) // We can't remove secondary dictionaries so we need to recreate the Hunspell instance { @@ -211,7 +211,7 @@ void LLSpellChecker::setSecondaryDictionaries(std::list dict_list) { const std::string app_path = getDictionaryAppPath(); const std::string user_path = getDictionaryUserPath(); - for (std::list::const_iterator it_added = dict_add.begin(); it_added != end_added; ++it_added) + for (dict_list_t::const_iterator it_added = dict_add.begin(); it_added != end_added; ++it_added) { const LLSD dict_entry = getDictionaryData(*it_added); if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) @@ -287,7 +287,7 @@ void LLSpellChecker::initHunspell(const std::string& dict_name) } } - for (std::list::const_iterator it = mDictSecondary.begin(); it != mDictSecondary.end(); ++it) + for (dict_list_t::const_iterator it = mDictSecondary.begin(); it != mDictSecondary.end(); ++it) { const LLSD dict_entry = getDictionaryData(*it); if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h index affdac2907..8351655b49 100644 --- a/indra/llui/llspellcheck.h +++ b/indra/llui/llspellcheck.h @@ -44,17 +44,20 @@ public: void addToIgnoreList(const std::string& word); bool checkSpelling(const std::string& word) const; S32 getSuggestions(const std::string& word, std::vector& suggestions) const; - -public: - const LLSD getDictionaryData(const std::string& dict_name) const; - const LLSD& getDictionaryMap() const { return mDictMap; } - void refreshDictionaryMap(); - void setSecondaryDictionaries(std::list dictList); protected: - void addToDictFile(const std::string& dict_path, const std::string& word); - void initHunspell(const std::string& dict_name); + void addToDictFile(const std::string& dict_path, const std::string& word); + void initHunspell(const std::string& dict_name); public: + typedef std::list dict_list_t; + + const std::string& getActiveDictionary() const { return mDictName; } + const LLSD getDictionaryData(const std::string& dict_name) const; + const LLSD& getDictionaryMap() const { return mDictMap; } + const dict_list_t& getSecondaryDictionaries() const { return mDictSecondary; } + void refreshDictionaryMap(); + void setSecondaryDictionaries(dict_list_t dict_list); + static const std::string getDictionaryAppPath(); static const std::string getDictionaryUserPath(); static bool getUseSpellCheck(); @@ -64,11 +67,11 @@ public: static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb); protected: - Hunspell* mHunspell; - std::string mDictName; - std::string mDictFile; - LLSD mDictMap; - std::list mDictSecondary; + Hunspell* mHunspell; + std::string mDictName; + std::string mDictFile; + LLSD mDictMap; + dict_list_t mDictSecondary; std::vector mIgnoreList; static settings_change_signal_t sSettingsChangeSignal; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 7eee1d39c4..2231d9b983 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1308,6 +1308,7 @@ bool LLTextBase::isMisspelledWord(U32 pos) const void LLTextBase::onSpellCheckSettingsChange() { // Recheck the spelling on every change + mMisspellRanges.clear(); mSpellCheckStart = mSpellCheckEnd = -1; } diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index a333989e7e..29b07d2479 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -66,6 +66,7 @@ #include "llsky.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" +#include "llspellcheck.h" #include "llsliderctrl.h" #include "lltabcontainer.h" #include "lltrans.h" @@ -110,6 +111,8 @@ #include "lllogininstance.h" // to check if logged in yet #include "llsdserialize.h" +#include + const F32 MAX_USER_FAR_CLIP = 512.f; const F32 MIN_USER_FAR_CLIP = 64.f; const F32 BANDWIDTH_UPDATER_TIMEOUT = 0.5f; @@ -445,6 +448,9 @@ BOOL LLFloaterPreference::postBuild() getChild("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); + getChild("btn_spellcheck_moveleft")->setCommitCallback(boost::bind(&LLFloaterPreference::onClickDictMove, this, "list_spellcheck_active", "list_spellcheck_available")); + getChild("btn_spellcheck_moveright")->setCommitCallback(boost::bind(&LLFloaterPreference::onClickDictMove, this, "list_spellcheck_available", "list_spellcheck_active")); + // if floater is opened before login set default localized busy message if (LLStartUp::getStartupState() < STATE_STARTED) { @@ -577,6 +583,19 @@ void LLFloaterPreference::apply() } } + if (hasChild("check_spellcheck"), TRUE) + { + LLScrollListCtrl* list_ctrl = findChild("list_spellcheck_active"); + std::vector list_items = list_ctrl->getAllData(); + + std::list list_dict; + list_dict.push_back(LLSpellChecker::instance().getActiveDictionary()); + for (std::vector::const_iterator item_it = list_items.begin(); item_it != list_items.end(); ++item_it) + list_dict.push_back((*item_it)->getColumn(0)->getValue().asString()); + + gSavedSettings.setString("SpellCheckDictionary", boost::join(list_dict, ",")); + } + saveAvatarProperties(); if (mClickActionDirty) @@ -687,6 +706,8 @@ void LLFloaterPreference::onOpen(const LLSD& key) // Load (double-)click to walk/teleport settings. updateClickActionControls(); + buildDictLists(); + // Enabled/disabled popups, might have been changed by user actions // while preferences floater was closed. buildPopupLists(); @@ -865,6 +886,25 @@ void LLFloaterPreference::onNameTagOpacityChange(const LLSD& newvalue) } } +void LLFloaterPreference::onClickDictMove(const std::string& from, const std::string& to) +{ + LLScrollListCtrl* from_ctrl = findChild(from); + LLScrollListCtrl* to_ctrl = findChild(to); + + LLSD row; + row["columns"][0]["column"] = "name"; + row["columns"][0]["font"]["name"] = "SANSSERIF_SMALL"; + row["columns"][0]["font"]["style"] = "NORMAL"; + + std::vector sel_items = from_ctrl->getAllSelected(); + for (std::vector::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) + { + row["columns"][0]["value"] = (*sel_it)->getColumn(0)->getValue(); + to_ctrl->addElement(row); + } + from_ctrl->deleteSelectedItems(); +} + void LLFloaterPreference::onClickSetCache() { std::string cur_name(gSavedSettings.getString("CacheLocation")); @@ -930,6 +970,61 @@ void LLFloaterPreference::refreshSkin(void* data) self->getChild("skin_selection", true)->setValue(sSkin); } +void LLFloaterPreference::buildDictLists() +{ + LLComboBox* dict_combo = findChild("combo_spellcheck_dict"); + dict_combo->clearRows(); + + LLScrollListCtrl* active_ctrl = findChild("list_spellcheck_active"); + active_ctrl->clearRows(); + + LLScrollListCtrl* avail_ctrl = findChild("list_spellcheck_available"); + avail_ctrl->clearRows(); + + if (LLSpellChecker::getUseSpellCheck()) + { + // Populate the main dictionary combobox + const LLSD& dict_map = LLSpellChecker::instance().getDictionaryMap(); + if (dict_map.size()) + { + 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")) ) + dict_combo->add(dict["language"].asString()); + } + dict_combo->selectByValue(LLSpellChecker::instance().getActiveDictionary()); + } + + LLSD row; + row["columns"][0]["column"] = "name"; + row["columns"][0]["font"]["name"] = "SANSSERIF_SMALL"; + row["columns"][0]["font"]["style"] = "NORMAL"; + + // Populate the active dictionary list + LLSpellChecker::dict_list_t active_list = LLSpellChecker::instance().getSecondaryDictionaries(); + 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; + active_ctrl->addElement(row); + } + active_list.push_back(LLSpellChecker::instance().getActiveDictionary()); + + // Populate the available dictionary list + 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())) ) + { + row["columns"][0]["value"] = dict["language"].asString(); + avail_ctrl->addElement(row); + } + } + } +} void LLFloaterPreference::buildPopupLists() { diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 7ee3294478..cd258b5614 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -121,6 +121,7 @@ public: void setCacheLocation(const LLStringExplicit& location); + void onClickDictMove(const std::string& from, const std::string& to); void onClickSetCache(); void onClickResetCache(); void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata); @@ -160,6 +161,7 @@ public: void applyUIColor(LLUICtrl* ctrl, const LLSD& param); void getUIColor(LLUICtrl* ctrl, const LLSD& param); + void buildDictLists(); void buildPopupLists(); static void refreshSkin(void* data); private: diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 8702ebde2a..bc0363014a 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -54,6 +54,8 @@ with the same filename but different name + + diff --git a/indra/newview/skins/default/textures/widgets/Arrow_Left.png b/indra/newview/skins/default/textures/widgets/Arrow_Left.png new file mode 100644 index 0000000000..a424282839 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Arrow_Left.png differ diff --git a/indra/newview/skins/default/textures/widgets/Arrow_Right.png b/indra/newview/skins/default/textures/widgets/Arrow_Right.png new file mode 100644 index 0000000000..e32bee8f34 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Arrow_Right.png differ diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml index 402868bb97..eebc3a9cca 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences.xml @@ -120,6 +120,12 @@ layout="topleft" help_topic="preferences_advanced1_tab" name="advanced1" /> + diff --git a/indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml b/indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml new file mode 100644 index 0000000000..9b5d429846 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml @@ -0,0 +1,132 @@ + + + + + Main dictionary : + + + + + Additional dictionaries : + + + Available + + + Active + + + + + + + -- cgit v1.2.3 From 2114e88cd1291ef1dba4b79bcdcca4b2d134262f Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Fri, 3 Feb 2012 19:51:18 +0100 Subject: STORM-276 Enabled spell checking on notecards, picks and group notices --- indra/newview/skins/default/xui/en/floater_preview_notecard.xml | 1 + indra/newview/skins/default/xui/en/panel_edit_pick.xml | 1 + indra/newview/skins/default/xui/en/panel_group_notices.xml | 4 ++++ 3 files changed, 6 insertions(+) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml index be3b2d179d..2e1c8ce670 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml @@ -70,6 +70,7 @@ max_length="65536" name="Notecard Editor" parse_urls="false" + spellcheck="true" tab_group="1" top="46" width="392" diff --git a/indra/newview/skins/default/xui/en/panel_edit_pick.xml b/indra/newview/skins/default/xui/en/panel_edit_pick.xml index 2ec2e03e8c..6d0be7fdec 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_pick.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_pick.xml @@ -134,6 +134,7 @@ top_pad="2" max_length="1023" name="pick_desc" + spellcheck="true" text_color="black" word_wrap="true" /> @@ -309,6 +311,7 @@ Maximum 200 per group daily left_pad="3" max_length_bytes="63" name="view_subject" + spellcheck="true" top_delta="-1" visible="false" width="200" /> @@ -333,6 +336,7 @@ Maximum 200 per group daily right="-1" max_length="511" name="view_message" + spellcheck="true" top_delta="-40" width="313" word_wrap="true" /> -- cgit v1.2.3 From 60e39343b17f29c65e8a60a415f7ed83ff069a12 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Tue, 14 Feb 2012 21:48:22 +0100 Subject: STORM-276 Reworked the spell check preferences to be more robust and less error-prone --- indra/llui/llspellcheck.cpp | 20 +++- indra/llui/llspellcheck.h | 14 ++- indra/newview/llfloaterpreference.cpp | 121 +++++++++++++-------- indra/newview/llfloaterpreference.h | 2 +- .../xui/en/panel_preferences_spellcheck.xml | 4 + 5 files changed, 104 insertions(+), 57 deletions(-) (limited to 'indra') diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp index 65207144f8..46df44cdba 100644 --- a/indra/llui/llspellcheck.cpp +++ b/indra/llui/llspellcheck.cpp @@ -41,6 +41,7 @@ static const std::string DICT_DIR = "dictionaries"; static const std::string DICT_CUSTOM_SUFFIX = "_custom"; static const std::string DICT_IGNORE_SUFFIX = "_ignore"; +LLSD LLSpellChecker::sDictMap; LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal; LLSpellChecker::LLSpellChecker() @@ -86,9 +87,10 @@ S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector class Hunspell; -class LLSpellChecker : public LLSingleton +class LLSpellChecker : public LLSingleton, public LLInitClass { friend class LLSingleton; + friend class LLInitClass; protected: LLSpellChecker(); ~LLSpellChecker(); @@ -52,28 +54,30 @@ public: typedef std::list dict_list_t; const std::string& getActiveDictionary() const { return mDictName; } - const LLSD getDictionaryData(const std::string& dict_name) const; - const LLSD& getDictionaryMap() const { return mDictMap; } const dict_list_t& getSecondaryDictionaries() const { return mDictSecondary; } - void refreshDictionaryMap(); void setSecondaryDictionaries(dict_list_t dict_list); static const std::string getDictionaryAppPath(); static const std::string getDictionaryUserPath(); + static const LLSD getDictionaryData(const std::string& dict_name); + static const LLSD& getDictionaryMap() { return sDictMap; } static bool getUseSpellCheck(); + static void refreshDictionaryMap(); static void setUseSpellCheck(const std::string& dict_name); typedef boost::signals2::signal settings_change_signal_t; static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb); +protected: + static void initClass(); protected: Hunspell* mHunspell; std::string mDictName; std::string mDictFile; - LLSD mDictMap; dict_list_t mDictSecondary; std::vector mIgnoreList; + static LLSD sDictMap; static settings_change_signal_t sSettingsChangeSignal; }; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 29b07d2479..c41488ce91 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -448,6 +448,8 @@ BOOL LLFloaterPreference::postBuild() getChild("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); + gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterPreference::refreshDictLists, this, false)); + getChild("combo_spellcheck_dict")->setCommitCallback(boost::bind(&LLFloaterPreference::refreshDictLists, this, false)); getChild("btn_spellcheck_moveleft")->setCommitCallback(boost::bind(&LLFloaterPreference::onClickDictMove, this, "list_spellcheck_active", "list_spellcheck_available")); getChild("btn_spellcheck_moveright")->setCommitCallback(boost::bind(&LLFloaterPreference::onClickDictMove, this, "list_spellcheck_available", "list_spellcheck_active")); @@ -585,14 +587,19 @@ void LLFloaterPreference::apply() if (hasChild("check_spellcheck"), TRUE) { - LLScrollListCtrl* list_ctrl = findChild("list_spellcheck_active"); - std::vector list_items = list_ctrl->getAllData(); - std::list list_dict; - list_dict.push_back(LLSpellChecker::instance().getActiveDictionary()); - for (std::vector::const_iterator item_it = list_items.begin(); item_it != list_items.end(); ++item_it) - list_dict.push_back((*item_it)->getColumn(0)->getValue().asString()); + LLComboBox* dict_combo = findChild("combo_spellcheck_dict"); + const std::string dict_name = dict_combo->getSelectedItemLabel(); + if (!dict_name.empty()) + { + list_dict.push_back(dict_name); + + LLScrollListCtrl* list_ctrl = findChild("list_spellcheck_active"); + std::vector list_items = list_ctrl->getAllData(); + for (std::vector::const_iterator item_it = list_items.begin(); item_it != list_items.end(); ++item_it) + list_dict.push_back((*item_it)->getColumn(0)->getValue().asString()); + } gSavedSettings.setString("SpellCheckDictionary", boost::join(list_dict, ",")); } @@ -706,7 +713,7 @@ void LLFloaterPreference::onOpen(const LLSD& key) // Load (double-)click to walk/teleport settings. updateClickActionControls(); - buildDictLists(); + refreshDictLists(true); // Enabled/disabled popups, might have been changed by user actions // while preferences floater was closed. @@ -970,58 +977,80 @@ void LLFloaterPreference::refreshSkin(void* data) self->getChild("skin_selection", true)->setValue(sSkin); } -void LLFloaterPreference::buildDictLists() +void LLFloaterPreference::refreshDictLists(bool from_settings) { + bool enabled = gSavedSettings.getBOOL("SpellCheck"); + getChild("btn_spellcheck_moveleft")->setEnabled(enabled); + getChild("btn_spellcheck_moveright")->setEnabled(enabled); + + // Populate the dictionary combobox LLComboBox* dict_combo = findChild("combo_spellcheck_dict"); + std::string dict_cur = dict_combo->getSelectedItemLabel(); + if ((dict_cur.empty() || from_settings) && (LLSpellChecker::getUseSpellCheck())) + dict_cur = LLSpellChecker::instance().getActiveDictionary(); dict_combo->clearRows(); + dict_combo->setEnabled(enabled); - LLScrollListCtrl* active_ctrl = findChild("list_spellcheck_active"); - active_ctrl->clearRows(); + const LLSD& dict_map = LLSpellChecker::getDictionaryMap(); + if (dict_map.size()) + { + 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")) ) + dict_combo->add(dict["language"].asString()); + } + if (!dict_combo->selectByValue(dict_cur)) + dict_combo->clear(); + } + // Populate the available and active dictionary list LLScrollListCtrl* avail_ctrl = findChild("list_spellcheck_available"); - avail_ctrl->clearRows(); + LLScrollListCtrl* active_ctrl = findChild("list_spellcheck_active"); - if (LLSpellChecker::getUseSpellCheck()) + LLSpellChecker::dict_list_t active_list; + if ( ((!avail_ctrl->getItemCount()) && (!active_ctrl->getItemCount())) || (from_settings) ) { - // Populate the main dictionary combobox - const LLSD& dict_map = LLSpellChecker::instance().getDictionaryMap(); - if (dict_map.size()) + if (LLSpellChecker::getUseSpellCheck()) + active_list = LLSpellChecker::instance().getSecondaryDictionaries(); + } + else + { + std::vector active_items = active_ctrl->getAllData(); + for (std::vector::const_iterator item_it = active_items.begin(); item_it != active_items.end(); ++item_it) { - 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")) ) - dict_combo->add(dict["language"].asString()); - } - dict_combo->selectByValue(LLSpellChecker::instance().getActiveDictionary()); + std::string dict = (*item_it)->getColumn(0)->getValue().asString(); + if (dict_cur != dict) + active_list.push_back(dict); } + } - LLSD row; - row["columns"][0]["column"] = "name"; - row["columns"][0]["font"]["name"] = "SANSSERIF_SMALL"; - row["columns"][0]["font"]["style"] = "NORMAL"; - - // Populate the active dictionary list - LLSpellChecker::dict_list_t active_list = LLSpellChecker::instance().getSecondaryDictionaries(); - 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; - active_ctrl->addElement(row); - } - active_list.push_back(LLSpellChecker::instance().getActiveDictionary()); + LLSD row; + row["columns"][0]["column"] = "name"; + row["columns"][0]["font"]["name"] = "SANSSERIF_SMALL"; + row["columns"][0]["font"]["style"] = "NORMAL"; - // Populate the available dictionary list - avail_ctrl->sortByColumnIndex(0, true); - for (LLSD::array_const_iterator dict_it = dict_map.beginArray(); dict_it != dict_map.endArray(); ++dict_it) + 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; + active_ctrl->addElement(row); + } + 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 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())) ) - { - row["columns"][0]["value"] = dict["language"].asString(); - avail_ctrl->addElement(row); - } + row["columns"][0]["value"] = dict["language"].asString(); + avail_ctrl->addElement(row); } } } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index cd258b5614..f75f71cc3d 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -161,8 +161,8 @@ public: void applyUIColor(LLUICtrl* ctrl, const LLSD& param); void getUIColor(LLUICtrl* ctrl, const LLSD& param); - void buildDictLists(); void buildPopupLists(); + void refreshDictLists(bool from_settings); static void refreshSkin(void* data); private: static std::string sSkin; diff --git a/indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml b/indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml index 9b5d429846..f1b16c5d0d 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml @@ -86,6 +86,7 @@ Active Date: Tue, 14 Feb 2012 21:57:58 +0100 Subject: STORM-276 FIXED Typing in an LLTextEditor freezes the viewer --- indra/llui/lltextbase.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 2231d9b983..2d7516a1cd 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -552,7 +552,7 @@ void LLTextBase::drawText() const LLWString& wstrText = getWText(); mMisspellRanges.clear(); - segment_set_t::iterator seg_it = getSegIterContaining(start); + segment_set_t::const_iterator seg_it = getSegIterContaining(start); while (mSegments.end() != seg_it) { LLTextSegmentPtr text_segment = *seg_it; @@ -673,7 +673,10 @@ void LLTextBase::drawText() { // Skip the current word if the user is still busy editing it if ( (!mSpellCheckTimer.hasExpired()) && (misspell_it->first <= (U32)mCursorPos) && (misspell_it->second >= (U32)mCursorPos) ) + { + ++misspell_it; continue; + } S32 squiggle_start = 0, squiggle_end = 0, pony = 0; cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_it->first - seg_start, squiggle_start, pony); -- cgit v1.2.3 From 9c792e337695b904e4f52fce83b293a2e97fdeaf Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Tue, 14 Feb 2012 22:33:28 +0100 Subject: STORM-276 FIXED Misspellings that span multiple lines don't have their squiggly lines drawn correctly --- indra/llui/lltextbase.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 2d7516a1cd..ce405cd4a4 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -678,9 +678,10 @@ void LLTextBase::drawText() continue; } + U32 misspell_start = llmax(misspell_it->first, seg_start), misspell_end = llmin(misspell_it->second, seg_end); S32 squiggle_start = 0, squiggle_end = 0, pony = 0; - cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_it->first - seg_start, squiggle_start, pony); - cur_segment->getDimensions(misspell_it->first - cur_segment->getStart(), misspell_it->second - misspell_it->first, squiggle_end, pony); + cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_start - seg_start, squiggle_start, pony); + cur_segment->getDimensions(misspell_start - cur_segment->getStart(), misspell_end - misspell_start, squiggle_end, pony); squiggle_start += text_rect.mLeft; pony = (squiggle_end + 3) / 6; -- cgit v1.2.3 From e615660823e680e824d2db0f1a59917597e64a13 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Thu, 9 Feb 2012 22:02:32 +0100 Subject: STORM-276 Differentiate between primary and secondary dictionaries --- indra/llui/llspellcheck.cpp | 6 ++---- indra/newview/llfloaterpreference.cpp | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'indra') diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp index 46df44cdba..aa39e21a96 100644 --- a/indra/llui/llspellcheck.cpp +++ b/indra/llui/llspellcheck.cpp @@ -122,9 +122,7 @@ void LLSpellChecker::refreshDictionaryMap() tmp_app_path = (sdDict.has("name")) ? app_path + sdDict["name"].asString() : LLStringUtil::null; tmp_user_path = (sdDict.has("name")) ? user_path + sdDict["name"].asString() : LLStringUtil::null; sdDict["installed"] = - (!tmp_app_path.empty()) && - ( ((gDirUtilp->fileExists(tmp_user_path + ".aff")) && (gDirUtilp->fileExists(tmp_user_path + ".dic"))) || - ((gDirUtilp->fileExists(tmp_app_path + ".aff")) && (gDirUtilp->fileExists(tmp_app_path + ".dic"))) ); + (!tmp_app_path.empty()) && ((gDirUtilp->fileExists(tmp_user_path + ".dic")) || (gDirUtilp->fileExists(tmp_app_path + ".dic"))); sdDict["has_custom"] = (!tmp_user_path.empty()) && (gDirUtilp->fileExists(tmp_user_path + DICT_CUSTOM_SUFFIX + ".dic")); sdDict["has_ignore"] = (!tmp_user_path.empty()) && (gDirUtilp->fileExists(tmp_user_path + DICT_IGNORE_SUFFIX + ".dic")); } @@ -243,7 +241,7 @@ void LLSpellChecker::initHunspell(const std::string& dict_name) } const LLSD dict_entry = (!dict_name.empty()) ? getDictionaryData(dict_name) : LLSD(); - if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) + if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) || (!dict_entry["is_primary"].asBoolean())) { sSettingsChangeSignal(); return; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index c41488ce91..c444d2bb6f 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -997,7 +997,7 @@ void LLFloaterPreference::refreshDictLists(bool from_settings) 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")) ) + if ( (dict["installed"].asBoolean()) && (dict["is_primary"].asBoolean()) && (dict.has("language")) ) dict_combo->add(dict["language"].asString()); } if (!dict_combo->selectByValue(dict_cur)) -- cgit v1.2.3 From 59bfc3f608bed806e03898b833a0fda9f95d42b9 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Sun, 25 Mar 2012 19:50:46 +0200 Subject: Minor fix for GCC --- indra/llui/lllineeditor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 42cfc4cae9..0dc381231d 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1948,8 +1948,8 @@ void LLLineEditor::draw() gGL.color4ub(255, 0, 0, 200); while (pxStart < pxEnd) { - gl_line_2d(pxStart, text_bottom - 2, pxStart + 3, text_bottom + 1); - gl_line_2d(pxStart + 3, text_bottom + 1, pxStart + 6, text_bottom - 2); + gl_line_2d(pxStart, (S32)text_bottom - 2, pxStart + 3, (S32)text_bottom + 1); + gl_line_2d(pxStart + 3, (S32)text_bottom + 1, pxStart + 6, (S32)text_bottom - 2); pxStart += 6; } } -- cgit v1.2.3 From 2587f6d9d8167bb29491ff681dcd133eb28aba67 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Thu, 29 Mar 2012 18:25:48 +0200 Subject: Minor fix for GCC --- indra/newview/llappviewer.cpp | 3 ++- indra/newview/llviewercontrol.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 5a68cd531e..fac5416aab 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2502,7 +2502,8 @@ bool LLAppViewer::initConfiguration() if (gSavedSettings.getBOOL("SpellCheck")) { std::list dict_list; - boost::split(dict_list, gSavedSettings.getString("SpellCheckDictionary"), boost::is_any_of(std::string(","))); + std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary"); + boost::split(dict_list, dict_setting, boost::is_any_of(std::string(","))); if (!dict_list.empty()) { LLSpellChecker::setUseSpellCheck(dict_list.front()); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 7b6dbfaa0b..d7168a401c 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -507,7 +507,8 @@ bool handleSpellCheckChanged() if (gSavedSettings.getBOOL("SpellCheck")) { std::list dict_list; - boost::split(dict_list, gSavedSettings.getString("SpellCheckDictionary"), boost::is_any_of(std::string(","))); + std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary"); + boost::split(dict_list, dict_setting, boost::is_any_of(std::string(","))); if (!dict_list.empty()) { LLSpellChecker::setUseSpellCheck(dict_list.front()); -- cgit v1.2.3 From e60dac5ce486f55fe69949a6a3a2949d4f868193 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Thu, 29 Mar 2012 21:07:09 +0200 Subject: STORM-276 Added dictionaries.xml and the Second Life glossary dictionary (enabled by default) --- .../app_settings/dictionaries/dictionaries.xml | 45 ++++ indra/newview/app_settings/dictionaries/sl.dic | 226 +++++++++++++++++++++ indra/newview/app_settings/settings.xml | 2 +- 3 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 indra/newview/app_settings/dictionaries/dictionaries.xml create mode 100644 indra/newview/app_settings/dictionaries/sl.dic (limited to 'indra') diff --git a/indra/newview/app_settings/dictionaries/dictionaries.xml b/indra/newview/app_settings/dictionaries/dictionaries.xml new file mode 100644 index 0000000000..0ba959766b --- /dev/null +++ b/indra/newview/app_settings/dictionaries/dictionaries.xml @@ -0,0 +1,45 @@ + + + + + name + en_gb + is_primary + 1 + language + English (United Kingdom) + + + name + en_us + is_primary + 1 + language + English (United States) + + + name + es_es + is_primary + 1 + language + Español (España) + + + name + pt_br + is_primary + 1 + language + Português (Brasil) + + + name + sl + is_primary + 0 + language + Second Life Glossary + + + diff --git a/indra/newview/app_settings/dictionaries/sl.dic b/indra/newview/app_settings/dictionaries/sl.dic new file mode 100644 index 0000000000..06decad74b --- /dev/null +++ b/indra/newview/app_settings/dictionaries/sl.dic @@ -0,0 +1,226 @@ +225 +account +aditi +adult +agent +agni +alpha +alt +animation +AR +asset +attachment +autoreturn +avatar +avie +baked +ban +banlines +banlist +BDSM +beacon +bling +block +blog +blogger +bodyparts +bot +box +build +busy +cache +cage +camp +campie +Catznip +chim +classified +client +coalesced +collar +collision +combat +community +concierge +conference +continent +contribution +coordinate +copy +covenant +CS +damage +damage-enabled +death +deed +detach +displayname +Dolphin +drama +drop +estate +event +face +facelight +favorites +FIC +Firestorm +flexible +flexiprim +floater +fly +flycam +FMOD +follower +forums +freebie +freeze +friendship +fullperm +furry +gadget +general +gesture +goo +grid +gridnaut +griefer +griefing +ground +group +GSLR +GUI +Havok +hippo +hippotropolis +home +homestead +host +HUD +IM +impostors +Imprudence +indra +infohub +inspector +inventory +invisiprim +inworld +island +item +JIRA +JPEG2000 +Kakadu +KDU +kick +L$ +lag +land +landmark +LDPW +liaison +library +limits +linden +LindeX +link +linkset +live +lock +log +machinima +mainland +mainlanders +map +marketplace +mature +media +mega +megaprim +mentor +mesh +minimap +mini-map +moderate +modify +mono +morph +MOTD +mouselook +mouseview +move +mute +neko +newbie +non-physical +notecard +NPIOF +object +occlusion +off-world +officer +offline +ogg +online +ONSR +openspace +orbiter +orientation +parcel +particles +partner +permission +PG +phantom +Phoenix +physics +pick +poofer +position +premium +prim +primitar +primitive +profile +quaternion +Radegast +region +relog +resi +resident +return +rez +rezday +RLV +RLVa +roleplay +run +ruth +script +sculpted +sculptie +sculpty +shout +sim +simulator +Singularity +skin +SLEX +SLurl +snapshot +stipend +telehub +teleport +terraform +texture +tier +TOS +transfer +unlink +username +UUID +vendor +viewer +walk +whisper +windlight diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e15822ed1f..7dc06cda0e 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12168,7 +12168,7 @@ Type String Value - English (United States) + English (United States),Second Life Glossary UseNewWalkRun -- cgit v1.2.3 From 5f32e6493ed4f8b9b480da857f487fa21f32bd64 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Fri, 30 Mar 2012 14:09:39 -0400 Subject: convert line endings on sl.dic for coding standards compliance --- indra/newview/app_settings/dictionaries/sl.dic | 452 ++++++++++++------------- 1 file changed, 226 insertions(+), 226 deletions(-) (limited to 'indra') diff --git a/indra/newview/app_settings/dictionaries/sl.dic b/indra/newview/app_settings/dictionaries/sl.dic index 06decad74b..57e9dd06cd 100644 --- a/indra/newview/app_settings/dictionaries/sl.dic +++ b/indra/newview/app_settings/dictionaries/sl.dic @@ -1,226 +1,226 @@ -225 -account -aditi -adult -agent -agni -alpha -alt -animation -AR -asset -attachment -autoreturn -avatar -avie -baked -ban -banlines -banlist -BDSM -beacon -bling -block -blog -blogger -bodyparts -bot -box -build -busy -cache -cage -camp -campie -Catznip -chim -classified -client -coalesced -collar -collision -combat -community -concierge -conference -continent -contribution -coordinate -copy -covenant -CS -damage -damage-enabled -death -deed -detach -displayname -Dolphin -drama -drop -estate -event -face -facelight -favorites -FIC -Firestorm -flexible -flexiprim -floater -fly -flycam -FMOD -follower -forums -freebie -freeze -friendship -fullperm -furry -gadget -general -gesture -goo -grid -gridnaut -griefer -griefing -ground -group -GSLR -GUI -Havok -hippo -hippotropolis -home -homestead -host -HUD -IM -impostors -Imprudence -indra -infohub -inspector -inventory -invisiprim -inworld -island -item -JIRA -JPEG2000 -Kakadu -KDU -kick -L$ -lag -land -landmark -LDPW -liaison -library -limits -linden -LindeX -link -linkset -live -lock -log -machinima -mainland -mainlanders -map -marketplace -mature -media -mega -megaprim -mentor -mesh -minimap -mini-map -moderate -modify -mono -morph -MOTD -mouselook -mouseview -move -mute -neko -newbie -non-physical -notecard -NPIOF -object -occlusion -off-world -officer -offline -ogg -online -ONSR -openspace -orbiter -orientation -parcel -particles -partner -permission -PG -phantom -Phoenix -physics -pick -poofer -position -premium -prim -primitar -primitive -profile -quaternion -Radegast -region -relog -resi -resident -return -rez -rezday -RLV -RLVa -roleplay -run -ruth -script -sculpted -sculptie -sculpty -shout -sim -simulator -Singularity -skin -SLEX -SLurl -snapshot -stipend -telehub -teleport -terraform -texture -tier -TOS -transfer -unlink -username -UUID -vendor -viewer -walk -whisper -windlight +225 +account +aditi +adult +agent +agni +alpha +alt +animation +AR +asset +attachment +autoreturn +avatar +avie +baked +ban +banlines +banlist +BDSM +beacon +bling +block +blog +blogger +bodyparts +bot +box +build +busy +cache +cage +camp +campie +Catznip +chim +classified +client +coalesced +collar +collision +combat +community +concierge +conference +continent +contribution +coordinate +copy +covenant +CS +damage +damage-enabled +death +deed +detach +displayname +Dolphin +drama +drop +estate +event +face +facelight +favorites +FIC +Firestorm +flexible +flexiprim +floater +fly +flycam +FMOD +follower +forums +freebie +freeze +friendship +fullperm +furry +gadget +general +gesture +goo +grid +gridnaut +griefer +griefing +ground +group +GSLR +GUI +Havok +hippo +hippotropolis +home +homestead +host +HUD +IM +impostors +Imprudence +indra +infohub +inspector +inventory +invisiprim +inworld +island +item +JIRA +JPEG2000 +Kakadu +KDU +kick +L$ +lag +land +landmark +LDPW +liaison +library +limits +linden +LindeX +link +linkset +live +lock +log +machinima +mainland +mainlanders +map +marketplace +mature +media +mega +megaprim +mentor +mesh +minimap +mini-map +moderate +modify +mono +morph +MOTD +mouselook +mouseview +move +mute +neko +newbie +non-physical +notecard +NPIOF +object +occlusion +off-world +officer +offline +ogg +online +ONSR +openspace +orbiter +orientation +parcel +particles +partner +permission +PG +phantom +Phoenix +physics +pick +poofer +position +premium +prim +primitar +primitive +profile +quaternion +Radegast +region +relog +resi +resident +return +rez +rezday +RLV +RLVa +roleplay +run +ruth +script +sculpted +sculptie +sculpty +shout +sim +simulator +Singularity +skin +SLEX +SLurl +snapshot +stipend +telehub +teleport +terraform +texture +tier +TOS +transfer +unlink +username +UUID +vendor +viewer +walk +whisper +windlight -- cgit v1.2.3 From 3af3d5e83c81ecfa77735e6811470d1aa0f705da Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Fri, 30 Mar 2012 15:07:46 -0400 Subject: move all dictionaries to the prebuilt package, and install from there --- .../app_settings/dictionaries/dictionaries.xml | 45 ---- indra/newview/app_settings/dictionaries/sl.dic | 226 --------------------- indra/newview/viewer_manifest.py | 2 +- 3 files changed, 1 insertion(+), 272 deletions(-) delete mode 100644 indra/newview/app_settings/dictionaries/dictionaries.xml delete mode 100644 indra/newview/app_settings/dictionaries/sl.dic (limited to 'indra') diff --git a/indra/newview/app_settings/dictionaries/dictionaries.xml b/indra/newview/app_settings/dictionaries/dictionaries.xml deleted file mode 100644 index 0ba959766b..0000000000 --- a/indra/newview/app_settings/dictionaries/dictionaries.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - name - en_gb - is_primary - 1 - language - English (United Kingdom) - - - name - en_us - is_primary - 1 - language - English (United States) - - - name - es_es - is_primary - 1 - language - Español (España) - - - name - pt_br - is_primary - 1 - language - Português (Brasil) - - - name - sl - is_primary - 0 - language - Second Life Glossary - - - diff --git a/indra/newview/app_settings/dictionaries/sl.dic b/indra/newview/app_settings/dictionaries/sl.dic deleted file mode 100644 index 57e9dd06cd..0000000000 --- a/indra/newview/app_settings/dictionaries/sl.dic +++ /dev/null @@ -1,226 +0,0 @@ -225 -account -aditi -adult -agent -agni -alpha -alt -animation -AR -asset -attachment -autoreturn -avatar -avie -baked -ban -banlines -banlist -BDSM -beacon -bling -block -blog -blogger -bodyparts -bot -box -build -busy -cache -cage -camp -campie -Catznip -chim -classified -client -coalesced -collar -collision -combat -community -concierge -conference -continent -contribution -coordinate -copy -covenant -CS -damage -damage-enabled -death -deed -detach -displayname -Dolphin -drama -drop -estate -event -face -facelight -favorites -FIC -Firestorm -flexible -flexiprim -floater -fly -flycam -FMOD -follower -forums -freebie -freeze -friendship -fullperm -furry -gadget -general -gesture -goo -grid -gridnaut -griefer -griefing -ground -group -GSLR -GUI -Havok -hippo -hippotropolis -home -homestead -host -HUD -IM -impostors -Imprudence -indra -infohub -inspector -inventory -invisiprim -inworld -island -item -JIRA -JPEG2000 -Kakadu -KDU -kick -L$ -lag -land -landmark -LDPW -liaison -library -limits -linden -LindeX -link -linkset -live -lock -log -machinima -mainland -mainlanders -map -marketplace -mature -media -mega -megaprim -mentor -mesh -minimap -mini-map -moderate -modify -mono -morph -MOTD -mouselook -mouseview -move -mute -neko -newbie -non-physical -notecard -NPIOF -object -occlusion -off-world -officer -offline -ogg -online -ONSR -openspace -orbiter -orientation -parcel -particles -partner -permission -PG -phantom -Phoenix -physics -pick -poofer -position -premium -prim -primitar -primitive -profile -quaternion -Radegast -region -relog -resi -resident -return -rez -rezday -RLV -RLVa -roleplay -run -ruth -script -sculpted -sculptie -sculpty -shout -sim -simulator -Singularity -skin -SLEX -SLurl -snapshot -stipend -telehub -teleport -terraform -texture -tier -TOS -transfer -unlink -username -UUID -vendor -viewer -walk -whisper -windlight diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 1b732676e4..a59b763910 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -92,7 +92,7 @@ class ViewerManifest(LLManifest): # ... and the entire windlight directory self.path("windlight") # ... and the pre-installed spell checking dictionaries - self.path("dictionaries") + self.path("../../packages/dictionaries", dst="dictionaries") self.end_prefix("app_settings") if self.prefix(src="character"): -- cgit v1.2.3 From 63196a9c08c94ced5bb9ff5b9e623564d956bcd8 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Tue, 10 Apr 2012 15:57:39 -0400 Subject: add hunspell libs --- indra/llui/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra') diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 1377336bb4..2208a2f327 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -25,6 +25,7 @@ include_directories( ${LLVFS_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LLXUIXML_INCLUDE_DIRS} + ${LIBS_PREBUILD_DIR}/include/hunspell ) set(llui_SOURCE_FILES @@ -252,6 +253,7 @@ add_library (llui ${llui_SOURCE_FILES}) # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level target_link_libraries(llui + ${HUNSPELL_LIBRARY} ${LLMESSAGE_LIBRARIES} ${LLRENDER_LIBRARIES} ${LLWINDOW_LIBRARIES} -- cgit v1.2.3 From 51ceacbb45802209c36c555c03eeeb2f5fd1d3b4 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Wed, 11 Apr 2012 12:14:35 -0400 Subject: fix ordering problem in libraries? --- indra/llui/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 2208a2f327..d0fd37a5b4 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -253,7 +253,6 @@ add_library (llui ${llui_SOURCE_FILES}) # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level target_link_libraries(llui - ${HUNSPELL_LIBRARY} ${LLMESSAGE_LIBRARIES} ${LLRENDER_LIBRARIES} ${LLWINDOW_LIBRARIES} @@ -263,6 +262,7 @@ target_link_libraries(llui ${LLXUIXML_LIBRARIES} ${LLXML_LIBRARIES} ${LLMATH_LIBRARIES} + ${HUNSPELL_LIBRARY} ${LLCOMMON_LIBRARIES} # must be after llimage, llwindow, llrender ) -- cgit v1.2.3 From cf370a8dcde5ae77c27aa4fdd105d399c60c3d53 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Wed, 11 Apr 2012 13:31:06 -0400 Subject: add hunspell libraries in unit test build --- indra/integration_tests/llui_libtest/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra') diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt index 1180460f4b..ba6b318cb8 100644 --- a/indra/integration_tests/llui_libtest/CMakeLists.txt +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -33,6 +33,7 @@ include_directories( ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LLXUIXML_INCLUDE_DIRS} + ${LIBS_PREBUILD_DIR}/include/hunspell ) set(llui_libtest_SOURCE_FILES @@ -80,6 +81,7 @@ target_link_libraries(llui_libtest ${LLIMAGEJ2COJ_LIBRARIES} ${OS_LIBRARIES} ${GOOGLE_PERFTOOLS_LIBRARIES} + ${HUNSPELL_LIBRARY} ) if (WINDOWS) -- cgit v1.2.3 From 6d050cad618493b7881ea6d0073e64ba732b6352 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Fri, 10 Feb 2012 16:25:55 +0100 Subject: - fixed : Hunspell linking issues --- indra/cmake/CMakeLists.txt | 1 + indra/cmake/FindHUNSPELL.cmake | 38 ++++++++++++++++++++++++++++++++++++++ indra/cmake/Hunspell.cmake | 21 +++++++++++++++++++++ indra/newview/CMakeLists.txt | 1 + 4 files changed, 61 insertions(+) create mode 100644 indra/cmake/FindHUNSPELL.cmake create mode 100644 indra/cmake/Hunspell.cmake (limited to 'indra') diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 279d577a27..9b836aac5f 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -37,6 +37,7 @@ set(cmake_SOURCE_FILES GLOD.cmake GStreamer010Plugin.cmake GooglePerfTools.cmake + Hunspell.cmake JPEG.cmake LLAddBuildTest.cmake LLAudio.cmake diff --git a/indra/cmake/FindHUNSPELL.cmake b/indra/cmake/FindHUNSPELL.cmake new file mode 100644 index 0000000000..d411bdb9e5 --- /dev/null +++ b/indra/cmake/FindHUNSPELL.cmake @@ -0,0 +1,38 @@ +# -*- cmake -*- + +# - Find HUNSPELL +# This module defines +# HUNSPELL_INCLUDE_DIR, where to find libhunspell.h, etc. +# HUNSPELL_LIBRARY, the library needed to use HUNSPELL. +# HUNSPELL_FOUND, If false, do not try to use HUNSPELL. + +find_path(HUNSPELL_INCLUDE_DIR hunspell.h + PATH_SUFFIXES hunspell + ) + +set(HUNSPELL_NAMES ${HUNSPELL_NAMES} libhunspell-1.3 libhunspell) +find_library(HUNSPELL_LIBRARY + NAMES ${HUNSPELL_NAMES} + ) + +if (HUNSPELL_LIBRARY AND HUNSPELL_INCLUDE_DIR) + set(HUNSPELL_FOUND "YES") +else (HUNSPELL_LIBRARY AND HUNSPELL_INCLUDE_DIR) + set(HUNSPELL_FOUND "NO") +endif (HUNSPELL_LIBRARY AND HUNSPELL_INCLUDE_DIR) + + +if (HUNSPELL_FOUND) + if (NOT HUNSPELL_FIND_QUIETLY) + message(STATUS "Found Hunspell: Library in '${HUNSPELL_LIBRARY}' and header in '${HUNSPELL_INCLUDE_DIR}' ") + endif (NOT HUNSPELL_FIND_QUIETLY) +else (HUNSPELL_FOUND) + if (HUNSPELL_FIND_REQUIRED) + message(FATAL_ERROR " * * *\nCould not find HUNSPELL library! * * *") + endif (HUNSPELL_FIND_REQUIRED) +endif (HUNSPELL_FOUND) + +mark_as_advanced( + HUNSPELL_LIBRARY + HUNSPELL_INCLUDE_DIR + ) diff --git a/indra/cmake/Hunspell.cmake b/indra/cmake/Hunspell.cmake new file mode 100644 index 0000000000..def2198c93 --- /dev/null +++ b/indra/cmake/Hunspell.cmake @@ -0,0 +1,21 @@ +# -*- cmake -*- +include(Prebuilt) + +set(HUNSPELL_FIND_QUIETLY ON) +set(HUNSPELL_FIND_REQUIRED ON) + +if (STANDALONE) + include(FindHUNSPELL) +else (STANDALONE) + use_prebuilt_binary(libhunspell) + if (WINDOWS) + set(HUNSPELL_LIBRARY libhunspell) + set(HUNSPELL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/hunspell) + elseif(DARWIN) + set(HUNSPELL_LIBRARY hunspell-1.3) + set(HUNSPELL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/hunspell) + else() + set(HUNSPELL_LIBRARY hunspell-1.3) + set(HUNSPELL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/hunspell) + endif() +endif (STANDALONE) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 0ec3e0e08a..fed9ea6790 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -13,6 +13,7 @@ include(EXPAT) include(FMOD) include(OPENAL) include(FindOpenGL) +include(Hunspell) include(JsonCpp) include(LLAudio) include(LLCharacter) -- cgit v1.2.3 From 8f0bd4b388ac74d5528fbbb83527e173c5624eec Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Fri, 13 Apr 2012 15:33:39 -0400 Subject: add cmake configuration for hunspell to llui integration test --- indra/integration_tests/llui_libtest/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'indra') diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt index ba6b318cb8..4332261739 100644 --- a/indra/integration_tests/llui_libtest/CMakeLists.txt +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -19,6 +19,7 @@ include(LLUI) include(LLVFS) # ugh, needed for LLDir include(LLXML) include(LLXUIXML) +include(Hunspell) include(Linking) # include(Tut) -- cgit v1.2.3 From f28ee5bd4f6c82e8113c4cb413f163594c047fee Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Fri, 13 Apr 2012 16:23:22 -0400 Subject: try a different path for the dictionaries package? --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index a59b763910..5c9c7395c8 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -92,7 +92,7 @@ class ViewerManifest(LLManifest): # ... and the entire windlight directory self.path("windlight") # ... and the pre-installed spell checking dictionaries - self.path("../../packages/dictionaries", dst="dictionaries") + self.path("../packages/dictionaries", dst="dictionaries") self.end_prefix("app_settings") if self.prefix(src="character"): -- cgit v1.2.3 From 83717183c57121167b671f7bdcc4ab3122b95846 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Fri, 13 Apr 2012 17:25:52 -0400 Subject: yet another path for the dictionaries package... --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 5c9c7395c8..f6245fedfb 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -92,7 +92,7 @@ class ViewerManifest(LLManifest): # ... and the entire windlight directory self.path("windlight") # ... and the pre-installed spell checking dictionaries - self.path("../packages/dictionaries", dst="dictionaries") + self.path("../../../packages/dictionaries", dst="dictionaries") self.end_prefix("app_settings") if self.prefix(src="character"): -- cgit v1.2.3 From 1055edb9ea67d645325fc5bbc01a9ec1e0238ed0 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Wed, 18 Apr 2012 19:25:25 -0700 Subject: add logging to diagnose path problem --- indra/newview/viewer_manifest.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index f6245fedfb..d2cd644175 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -92,7 +92,10 @@ class ViewerManifest(LLManifest): # ... and the entire windlight directory self.path("windlight") # ... and the pre-installed spell checking dictionaries - self.path("../../../packages/dictionaries", dst="dictionaries") + dictdir = os.path.join(os.pardir, os.pardir, self.args['configuration'], 'packages/dictionaries') + print "Trying dictionary relative to %s with %s" % (get_build_prefix(), dictdir); + self.path(src=dictdir, + dst="dictionaries") self.end_prefix("app_settings") if self.prefix(src="character"): -- cgit v1.2.3 From df38250c3c6bae08b36fac7b12a8238a805e46a3 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Wed, 18 Apr 2012 20:17:07 -0700 Subject: fix logging to diagnose path problem --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index d2cd644175..c88dbd97b1 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -93,7 +93,7 @@ class ViewerManifest(LLManifest): self.path("windlight") # ... and the pre-installed spell checking dictionaries dictdir = os.path.join(os.pardir, os.pardir, self.args['configuration'], 'packages/dictionaries') - print "Trying dictionary relative to %s with %s" % (get_build_prefix(), dictdir); + print "Trying dictionary relative to %s with %s" % (self.get_build_prefix(), dictdir); self.path(src=dictdir, dst="dictionaries") self.end_prefix("app_settings") -- cgit v1.2.3 From a167b551843d64e9765075100fb278c2a5e8809c Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Wed, 18 Apr 2012 22:32:35 -0700 Subject: rearrange dictionary copying --- indra/newview/viewer_manifest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index c88dbd97b1..5f687f3ac7 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -51,6 +51,11 @@ class ViewerManifest(LLManifest): self.exclude("*.svn*") self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") self.path(src="../../etc/message.xml", dst="app_settings/message.xml") + # add the pre-installed spell checking dictionaries + dictdir = os.path.join(os.pardir, 'packages', 'dictionaries') + print "Trying dictionary relative to %s with %s" % (self.get_src_prefix(), dictdir); + self.path(src=dictdir, + dst=os.path.join("app_settings","dictionaries") if self.is_packaging_viewer(): if self.prefix(src="app_settings"): @@ -91,11 +96,6 @@ class ViewerManifest(LLManifest): # ... and the entire windlight directory self.path("windlight") - # ... and the pre-installed spell checking dictionaries - dictdir = os.path.join(os.pardir, os.pardir, self.args['configuration'], 'packages/dictionaries') - print "Trying dictionary relative to %s with %s" % (self.get_build_prefix(), dictdir); - self.path(src=dictdir, - dst="dictionaries") self.end_prefix("app_settings") if self.prefix(src="character"): -- cgit v1.2.3 From b02132f927c29187e1031f38ef8884f86f115132 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Thu, 19 Apr 2012 05:08:19 -0700 Subject: missing paren in dictionary copying --- indra/newview/viewer_manifest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 5f687f3ac7..7c0358311b 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -51,11 +51,11 @@ class ViewerManifest(LLManifest): self.exclude("*.svn*") self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") self.path(src="../../etc/message.xml", dst="app_settings/message.xml") + # add the pre-installed spell checking dictionaries dictdir = os.path.join(os.pardir, 'packages', 'dictionaries') - print "Trying dictionary relative to %s with %s" % (self.get_src_prefix(), dictdir); - self.path(src=dictdir, - dst=os.path.join("app_settings","dictionaries") + print "Trying dictionaries relative to %s with %s" % (self.get_src_prefix(), dictdir) + self.path(src=dictdir, dst=os.path.join("app_settings","dictionaries")) if self.is_packaging_viewer(): if self.prefix(src="app_settings"): -- cgit v1.2.3 From 9e477c595c893b4bfe1f84cf0f5ef426eb751555 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Thu, 19 Apr 2012 05:55:00 -0700 Subject: try forcing use of build prefix to copy dictionaries --- indra/newview/viewer_manifest.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 7c0358311b..cc55e1512b 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -52,11 +52,6 @@ class ViewerManifest(LLManifest): self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") self.path(src="../../etc/message.xml", dst="app_settings/message.xml") - # add the pre-installed spell checking dictionaries - dictdir = os.path.join(os.pardir, 'packages', 'dictionaries') - print "Trying dictionaries relative to %s with %s" % (self.get_src_prefix(), dictdir) - self.path(src=dictdir, dst=os.path.join("app_settings","dictionaries")) - if self.is_packaging_viewer(): if self.prefix(src="app_settings"): self.exclude("logcontrol.xml") @@ -96,6 +91,14 @@ class ViewerManifest(LLManifest): # ... and the entire windlight directory self.path("windlight") + + # ... and the pre-installed spell checking dictionaries + pkgdir = os.path.join(self.get_build_prefix(), 'packages') + print "Trying to change src to %s" % (pkgdir); + if self.prefix(src=pkgdir,dst=""): + print "Trying dictionaries relative to %s with %s" % (self.get_src_prefix(), "dictionaries"); + self.path("dictionaries") + self.end_prefix(pkgdir) self.end_prefix("app_settings") if self.prefix(src="character"): -- cgit v1.2.3 From c6e095a32630aa2554f7e63cc9688bb063f9461a Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Thu, 19 Apr 2012 06:53:26 -0700 Subject: use build directory argument directly --- indra/newview/viewer_manifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index cc55e1512b..86d542029a 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -92,8 +92,8 @@ class ViewerManifest(LLManifest): # ... and the entire windlight directory self.path("windlight") - # ... and the pre-installed spell checking dictionaries - pkgdir = os.path.join(self.get_build_prefix(), 'packages') + # ... and the included spell checking dictionaries + pkgdir = os.path.join(self.args['build'], 'packages') print "Trying to change src to %s" % (pkgdir); if self.prefix(src=pkgdir,dst=""): print "Trying dictionaries relative to %s with %s" % (self.get_src_prefix(), "dictionaries"); -- cgit v1.2.3 From 2862efc36791855d002d75039905c83a8e0b7236 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Thu, 19 Apr 2012 07:55:39 -0700 Subject: reference packages relative to newview --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 86d542029a..fb1c88340f 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -93,7 +93,7 @@ class ViewerManifest(LLManifest): self.path("windlight") # ... and the included spell checking dictionaries - pkgdir = os.path.join(self.args['build'], 'packages') + pkgdir = os.path.join(self.args['build'], os.pardir(), 'packages') print "Trying to change src to %s" % (pkgdir); if self.prefix(src=pkgdir,dst=""): print "Trying dictionaries relative to %s with %s" % (self.get_src_prefix(), "dictionaries"); -- cgit v1.2.3 From 3dfa725c5bdf16da75d3820422d2ce5263df19a8 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Thu, 19 Apr 2012 08:31:09 -0700 Subject: grumble relative grumble python grumble --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index fb1c88340f..7a3619ccd8 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -93,7 +93,7 @@ class ViewerManifest(LLManifest): self.path("windlight") # ... and the included spell checking dictionaries - pkgdir = os.path.join(self.args['build'], os.pardir(), 'packages') + pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') print "Trying to change src to %s" % (pkgdir); if self.prefix(src=pkgdir,dst=""): print "Trying dictionaries relative to %s with %s" % (self.get_src_prefix(), "dictionaries"); -- cgit v1.2.3 From e02bf8f90dba7cd7ac8874d7ee1baf782397784f Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Mon, 23 Apr 2012 14:00:25 -0400 Subject: add dictionaries to the Hunspell.cmake so that it gets installed --- indra/cmake/Hunspell.cmake | 1 + 1 file changed, 1 insertion(+) (limited to 'indra') diff --git a/indra/cmake/Hunspell.cmake b/indra/cmake/Hunspell.cmake index def2198c93..24cf41f4e4 100644 --- a/indra/cmake/Hunspell.cmake +++ b/indra/cmake/Hunspell.cmake @@ -8,6 +8,7 @@ if (STANDALONE) include(FindHUNSPELL) else (STANDALONE) use_prebuilt_binary(libhunspell) + use_prebuilt_binary(dictionaries) if (WINDOWS) set(HUNSPELL_LIBRARY libhunspell) set(HUNSPELL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/hunspell) -- cgit v1.2.3 From 01cd6614484a38b974c2bbd692ccd3e0b1b2fc58 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Mon, 23 Apr 2012 15:52:15 -0400 Subject: remove debugging prints around packaging the dictionaries --- indra/newview/viewer_manifest.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 7a3619ccd8..56933bbd21 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -94,11 +94,10 @@ class ViewerManifest(LLManifest): # ... and the included spell checking dictionaries pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') - print "Trying to change src to %s" % (pkgdir); if self.prefix(src=pkgdir,dst=""): - print "Trying dictionaries relative to %s with %s" % (self.get_src_prefix(), "dictionaries"); self.path("dictionaries") self.end_prefix(pkgdir) + self.end_prefix("app_settings") if self.prefix(src="character"): -- cgit v1.2.3 From b93c9d8ba0792b6f63776301dc60a2ac8a4453ca Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Mon, 23 Apr 2012 16:01:45 -0400 Subject: correct mac hunspell lib name, try simpler reference to dictionaries --- indra/newview/viewer_manifest.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 56933bbd21..8fe39bafdd 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -93,10 +93,11 @@ class ViewerManifest(LLManifest): self.path("windlight") # ... and the included spell checking dictionaries - pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') - if self.prefix(src=pkgdir,dst=""): - self.path("dictionaries") - self.end_prefix(pkgdir) + #pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') + #if self.prefix(src=pkgdir,dst=""): + # self.path("dictionaries") + # self.end_prefix(pkgdir) + self.path(src="../packages/dictionaries", dst="dictionaries") self.end_prefix("app_settings") @@ -669,7 +670,7 @@ class DarwinManifest(ViewerManifest): # copy additional libs in /Contents/MacOS/ self.path("../packages/lib/release/libndofdev.dylib", dst="Resources/libndofdev.dylib") - self.path("../packages/lib/release/libhunspell-1.3.dylib", dst="Resources/libhunspell-1.3.dylib") + self.path("../packages/lib/release/libhunspell-1.3.0.dylib", dst="Resources/libhunspell-1.3.0.dylib") self.path("../viewer_components/updater/scripts/darwin/update_install", "MacOS/update_install") -- cgit v1.2.3 From 22d84a68335528d00ce61ec84583eb55f32a3545 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Mon, 23 Apr 2012 16:39:09 -0400 Subject: go back to the more elaborate way to find dictionaries (the way that works) --- indra/newview/viewer_manifest.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'indra') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 8fe39bafdd..58522c091d 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -93,11 +93,10 @@ class ViewerManifest(LLManifest): self.path("windlight") # ... and the included spell checking dictionaries - #pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') - #if self.prefix(src=pkgdir,dst=""): - # self.path("dictionaries") - # self.end_prefix(pkgdir) - self.path(src="../packages/dictionaries", dst="dictionaries") + pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') + if self.prefix(src=pkgdir,dst=""): + self.path("dictionaries") + self.end_prefix(pkgdir) self.end_prefix("app_settings") -- cgit v1.2.3 From 7bcfd3a4ae824d973802b1431a13e91eee18c89a Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Mon, 23 Apr 2012 17:27:54 -0400 Subject: fix version number of the libhunspell dylib in another place --- indra/cmake/Copy3rdPartyLibs.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index ebeae3e5be..6765d36ba3 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -217,7 +217,7 @@ elseif(DARWIN) libllqtwebkit.dylib libminizip.a libndofdev.dylib - libhunspell-1.3.dylib + libhunspell-1.3.0.dylib libexception_handler.dylib libcollada14dom.dylib ) -- cgit v1.2.3 From 9b64464d02918307048be6fe5f0b784010d38bf8 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Wed, 25 Apr 2012 12:27:34 -0400 Subject: more attempts to fix the hunspell lib for Mac --- indra/cmake/Copy3rdPartyLibs.cmake | 11 ++++++----- indra/cmake/FindHUNSPELL.cmake | 2 +- indra/cmake/Hunspell.cmake | 10 +++++----- 3 files changed, 12 insertions(+), 11 deletions(-) (limited to 'indra') diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 6765d36ba3..224e0a8b51 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -214,12 +214,12 @@ elseif(DARWIN) libexpat.1.5.2.dylib libexpat.dylib libGLOD.dylib - libllqtwebkit.dylib - libminizip.a + libllqtwebkit.dylib + libminizip.a libndofdev.dylib libhunspell-1.3.0.dylib libexception_handler.dylib - libcollada14dom.dylib + libcollada14dom.dylib ) # fmod is statically linked on darwin @@ -260,14 +260,15 @@ elseif(LINUX) libdb-5.1.so libexpat.so libexpat.so.1 - libglod.so + libglod.so libgmock_main.so libgmock.so.0 libgmodule-2.0.so libgobject-2.0.so libgtest_main.so libgtest.so.0 - libminizip.so + libhunspell-1.3.so.0.0.0 + libminizip.so libopenal.so libopenjpeg.so libssl.so diff --git a/indra/cmake/FindHUNSPELL.cmake b/indra/cmake/FindHUNSPELL.cmake index d411bdb9e5..6faf22959c 100644 --- a/indra/cmake/FindHUNSPELL.cmake +++ b/indra/cmake/FindHUNSPELL.cmake @@ -10,7 +10,7 @@ find_path(HUNSPELL_INCLUDE_DIR hunspell.h PATH_SUFFIXES hunspell ) -set(HUNSPELL_NAMES ${HUNSPELL_NAMES} libhunspell-1.3 libhunspell) +set(HUNSPELL_NAMES ${HUNSPELL_NAMES} libhunspell-1.3.0 libhunspell) find_library(HUNSPELL_LIBRARY NAMES ${HUNSPELL_NAMES} ) diff --git a/indra/cmake/Hunspell.cmake b/indra/cmake/Hunspell.cmake index 24cf41f4e4..0c9cf93316 100644 --- a/indra/cmake/Hunspell.cmake +++ b/indra/cmake/Hunspell.cmake @@ -8,15 +8,15 @@ if (STANDALONE) include(FindHUNSPELL) else (STANDALONE) use_prebuilt_binary(libhunspell) - use_prebuilt_binary(dictionaries) if (WINDOWS) set(HUNSPELL_LIBRARY libhunspell) - set(HUNSPELL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/hunspell) elseif(DARWIN) + set(HUNSPELL_LIBRARY hunspell-1.3.0) + elseif(LINUX) set(HUNSPELL_LIBRARY hunspell-1.3) - set(HUNSPELL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/hunspell) else() - set(HUNSPELL_LIBRARY hunspell-1.3) - set(HUNSPELL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/hunspell) + message(FATAL_ERROR "Invalid platform") endif() + set(HUNSPELL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/hunspell) + use_prebuilt_binary(dictionaries) endif (STANDALONE) -- cgit v1.2.3 From 34e7226ac88e14d4cfed6bc0d63da215afe0ac88 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Tue, 15 May 2012 13:13:44 +0200 Subject: STORM-276 FIXED Squiggles overflow line editor height when font size is set to large - Also reduced squiggle width from 6 to 4 and prevented running past the end of a word --- indra/llrender/llfontgl.cpp | 10 ++++++++++ indra/llrender/llfontgl.h | 2 ++ indra/llui/lllineeditor.cpp | 15 +++++++++++---- indra/llui/lltextbase.cpp | 11 +++++++---- 4 files changed, 30 insertions(+), 8 deletions(-) (limited to 'indra') diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index fccbf37a8d..4dc2fcd714 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -422,6 +422,16 @@ S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y } // font metrics - override for LLFontFreetype that returns units of virtual pixels +F32 LLFontGL::getAscenderHeight() const +{ + return mFontFreetype->getAscenderHeight() / sScaleY; +} + +F32 LLFontGL::getDescenderHeight() const +{ + return mFontFreetype->getDescenderHeight() / sScaleY; +} + S32 LLFontGL::getLineHeight() const { return llceil(mFontFreetype->getAscenderHeight() / sScaleY) + llceil(mFontFreetype->getDescenderHeight() / sScaleY); diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 74bdbb43e7..5ed5d2c4eb 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -115,6 +115,8 @@ public: S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const; // font metrics - override for LLFontFreetype that returns units of virtual pixels + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; S32 getLineHeight() const; S32 getWidth(const std::string& utf8text) const; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index f119b0d9bc..d87b9d930c 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1727,6 +1727,10 @@ void LLLineEditor::draw() background.stretch( -mBorderThickness ); S32 lineeditor_v_pad = (background.getHeight() - mGLFont->getLineHeight()) / 2; + if (mSpellCheck) + { + lineeditor_v_pad += 1; + } drawBackground(); @@ -1945,12 +1949,15 @@ void LLLineEditor::draw() if (pxEnd > pxWidth) pxEnd = pxWidth; + S32 pxBottom = (S32)(text_bottom + mGLFont->getDescenderHeight()); + gGL.color4ub(255, 0, 0, 200); - while (pxStart < pxEnd) + while (pxStart + 1 < pxEnd) { - gl_line_2d(pxStart, (S32)text_bottom - 2, pxStart + 3, (S32)text_bottom + 1); - gl_line_2d(pxStart + 3, (S32)text_bottom + 1, pxStart + 6, (S32)text_bottom - 2); - pxStart += 6; + 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; } } } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 990c442b73..4db1efdd20 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -688,12 +688,15 @@ void LLTextBase::drawText() squiggle_start += squiggle_end / 2 - pony * 3; squiggle_end = squiggle_start + pony * 6; + S32 squiggle_bottom = text_rect.mBottom + (S32)cur_segment->getStyle()->getFont()->getDescenderHeight(); + gGL.color4ub(255, 0, 0, 200); - while (squiggle_start < squiggle_end) + while (squiggle_start + 1 < squiggle_end) { - gl_line_2d(squiggle_start, text_rect.mBottom - 2, squiggle_start + 3, text_rect.mBottom + 1); - gl_line_2d(squiggle_start + 3, text_rect.mBottom + 1, squiggle_start + 6, text_rect.mBottom - 2); - squiggle_start += 6; + 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) -- cgit v1.2.3 From 8199cc997aeaccc72b5bd5389ded8afc7b9c379c Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Tue, 15 May 2012 14:09:13 +0200 Subject: STORM-276 FIXED Right-to-left line editor selection becomes invisible if the cursor moves --- indra/llui/lllineeditor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index d87b9d930c..83527ae5ad 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1805,14 +1805,14 @@ void LLLineEditor::draw() { S32 select_left; S32 select_right; - if( mSelectionStart < getCursor() ) + if (mSelectionStart < mSelectionEnd) { select_left = mSelectionStart; - select_right = getCursor(); + select_right = mSelectionEnd; } else { - select_left = getCursor(); + select_left = mSelectionEnd; select_right = mSelectionStart; } -- cgit v1.2.3 From 53222ef517b97249df1e1a6db2e29c0d86b2e773 Mon Sep 17 00:00:00 2001 From: Kitty Barnett Date: Thu, 31 May 2012 02:56:42 +0200 Subject: STORM-276 Match preferences look to that of the auto-replace functionality in STORM-1738 --- indra/newview/CMakeLists.txt | 2 + indra/newview/llfloaterpreference.cpp | 131 +-------------- indra/newview/llfloaterpreference.h | 3 +- indra/newview/llfloaterspellchecksettings.cpp | 179 +++++++++++++++++++++ indra/newview/llfloaterspellchecksettings.h | 48 ++++++ indra/newview/llviewerfloaterreg.cpp | 2 + .../skins/default/xui/en/floater_preferences.xml | 6 - .../skins/default/xui/en/floater_spellcheck.xml | 175 ++++++++++++++++++++ .../default/xui/en/panel_preferences_chat.xml | 11 ++ .../xui/en/panel_preferences_spellcheck.xml | 136 ---------------- 10 files changed, 424 insertions(+), 269 deletions(-) create mode 100644 indra/newview/llfloaterspellchecksettings.cpp create mode 100644 indra/newview/llfloaterspellchecksettings.h create mode 100644 indra/newview/skins/default/xui/en/floater_spellcheck.xml delete mode 100644 indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml (limited to 'indra') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8a6c88222b..b83f32c28e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -236,6 +236,7 @@ set(viewer_SOURCE_FILES llfloatersidepanelcontainer.cpp llfloatersnapshot.cpp llfloatersounddevices.cpp + llfloaterspellchecksettings.cpp llfloatertelehub.cpp llfloatertestinspectors.cpp llfloatertestlistview.cpp @@ -792,6 +793,7 @@ set(viewer_HEADER_FILES llfloatersidepanelcontainer.h llfloatersnapshot.h llfloatersounddevices.h + llfloaterspellchecksettings.h llfloatertelehub.h llfloatertestinspectors.h llfloatertestlistview.h diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index c096537de6..ae9a4a9876 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -66,7 +66,6 @@ #include "llsky.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" -#include "llspellcheck.h" #include "llsliderctrl.h" #include "lltabcontainer.h" #include "lltrans.h" @@ -111,8 +110,6 @@ #include "lllogininstance.h" // to check if logged in yet #include "llsdserialize.h" -#include - const F32 MAX_USER_FAR_CLIP = 512.f; const F32 MIN_USER_FAR_CLIP = 64.f; const F32 BANDWIDTH_UPDATER_TIMEOUT = 0.5f; @@ -349,6 +346,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this)); mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this)); mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); + mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); sSkin = gSavedSettings.getString("SkinCurrent"); @@ -448,11 +446,6 @@ BOOL LLFloaterPreference::postBuild() getChild("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this)); - gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterPreference::refreshDictLists, this, false)); - getChild("combo_spellcheck_dict")->setCommitCallback(boost::bind(&LLFloaterPreference::refreshDictLists, this, false)); - getChild("btn_spellcheck_moveleft")->setCommitCallback(boost::bind(&LLFloaterPreference::onClickDictMove, this, "list_spellcheck_active", "list_spellcheck_available")); - getChild("btn_spellcheck_moveright")->setCommitCallback(boost::bind(&LLFloaterPreference::onClickDictMove, this, "list_spellcheck_available", "list_spellcheck_active")); - // if floater is opened before login set default localized busy message if (LLStartUp::getStartupState() < STATE_STARTED) { @@ -585,24 +578,6 @@ void LLFloaterPreference::apply() } } - if (hasChild("check_spellcheck"), TRUE) - { - std::list list_dict; - - LLComboBox* dict_combo = findChild("combo_spellcheck_dict"); - const std::string dict_name = dict_combo->getSelectedItemLabel(); - if (!dict_name.empty()) - { - list_dict.push_back(dict_name); - - LLScrollListCtrl* list_ctrl = findChild("list_spellcheck_active"); - std::vector list_items = list_ctrl->getAllData(); - for (std::vector::const_iterator item_it = list_items.begin(); item_it != list_items.end(); ++item_it) - list_dict.push_back((*item_it)->getColumn(0)->getValue().asString()); - } - gSavedSettings.setString("SpellCheckDictionary", boost::join(list_dict, ",")); - } - saveAvatarProperties(); if (mClickActionDirty) @@ -713,8 +688,6 @@ void LLFloaterPreference::onOpen(const LLSD& key) // Load (double-)click to walk/teleport settings. updateClickActionControls(); - refreshDictLists(true); - // Enabled/disabled popups, might have been changed by user actions // while preferences floater was closed. buildPopupLists(); @@ -894,25 +867,6 @@ void LLFloaterPreference::onNameTagOpacityChange(const LLSD& newvalue) } } -void LLFloaterPreference::onClickDictMove(const std::string& from, const std::string& to) -{ - LLScrollListCtrl* from_ctrl = findChild(from); - LLScrollListCtrl* to_ctrl = findChild(to); - - LLSD row; - row["columns"][0]["column"] = "name"; - row["columns"][0]["font"]["name"] = "SANSSERIF_SMALL"; - row["columns"][0]["font"]["style"] = "NORMAL"; - - std::vector sel_items = from_ctrl->getAllSelected(); - for (std::vector::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) - { - row["columns"][0]["value"] = (*sel_it)->getColumn(0)->getValue(); - to_ctrl->addElement(row); - } - from_ctrl->deleteSelectedItems(); -} - void LLFloaterPreference::onClickSetCache() { std::string cur_name(gSavedSettings.getString("CacheLocation")); @@ -978,84 +932,6 @@ void LLFloaterPreference::refreshSkin(void* data) self->getChild("skin_selection", true)->setValue(sSkin); } -void LLFloaterPreference::refreshDictLists(bool from_settings) -{ - bool enabled = gSavedSettings.getBOOL("SpellCheck"); - getChild("btn_spellcheck_moveleft")->setEnabled(enabled); - getChild("btn_spellcheck_moveright")->setEnabled(enabled); - - // Populate the dictionary combobox - LLComboBox* dict_combo = findChild("combo_spellcheck_dict"); - std::string dict_cur = dict_combo->getSelectedItemLabel(); - if ((dict_cur.empty() || from_settings) && (LLSpellChecker::getUseSpellCheck())) - dict_cur = LLSpellChecker::instance().getActiveDictionary(); - dict_combo->clearRows(); - dict_combo->setEnabled(enabled); - - const LLSD& dict_map = LLSpellChecker::getDictionaryMap(); - if (dict_map.size()) - { - 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["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 - LLScrollListCtrl* avail_ctrl = findChild("list_spellcheck_available"); - LLScrollListCtrl* active_ctrl = findChild("list_spellcheck_active"); - - LLSpellChecker::dict_list_t active_list; - if ( ((!avail_ctrl->getItemCount()) && (!active_ctrl->getItemCount())) || (from_settings) ) - { - if (LLSpellChecker::getUseSpellCheck()) - active_list = LLSpellChecker::instance().getSecondaryDictionaries(); - } - else - { - std::vector active_items = active_ctrl->getAllData(); - for (std::vector::const_iterator item_it = active_items.begin(); item_it != active_items.end(); ++item_it) - { - std::string dict = (*item_it)->getColumn(0)->getValue().asString(); - if (dict_cur != dict) - active_list.push_back(dict); - } - } - - LLSD row; - row["columns"][0]["column"] = "name"; - row["columns"][0]["font"]["name"] = "SANSSERIF_SMALL"; - row["columns"][0]["font"]["style"] = "NORMAL"; - - 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; - active_ctrl->addElement(row); - } - 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())) ) - { - row["columns"][0]["value"] = dict["language"].asString(); - avail_ctrl->addElement(row); - } - } -} - void LLFloaterPreference::buildPopupLists() { LLScrollListCtrl& disabled_popups = @@ -1639,6 +1515,11 @@ void LLFloaterPreference::onClickTranslationSettings() LLFloaterReg::showInstance("prefs_translation"); } +void LLFloaterPreference::onClickSpellChecker() +{ + LLFloaterReg::showInstance("prefs_spellchecker"); +} + void LLFloaterPreference::onClickActionChange() { mClickActionDirty = true; diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index af10af7f48..669099ad7b 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -121,7 +121,6 @@ public: void setCacheLocation(const LLStringExplicit& location); - void onClickDictMove(const std::string& from, const std::string& to); void onClickSetCache(); void onClickResetCache(); void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata); @@ -158,11 +157,11 @@ public: void onClickBlockList(); void onClickProxySettings(); void onClickTranslationSettings(); + void onClickSpellChecker(); void applyUIColor(LLUICtrl* ctrl, const LLSD& param); void getUIColor(LLUICtrl* ctrl, const LLSD& param); void buildPopupLists(); - void refreshDictLists(bool from_settings); static void refreshSkin(void* data); private: static std::string sSkin; diff --git a/indra/newview/llfloaterspellchecksettings.cpp b/indra/newview/llfloaterspellchecksettings.cpp new file mode 100644 index 0000000000..ff5afc8169 --- /dev/null +++ b/indra/newview/llfloaterspellchecksettings.cpp @@ -0,0 +1,179 @@ +/** + * @file llfloaterspellchecksettings.h + * @brief Spell checker settings floater + * +* $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llcombobox.h" +#include "llfloaterspellchecksettings.h" +#include "llscrolllistctrl.h" +#include "llspellcheck.h" +#include "llviewercontrol.h" + +#include + +LLFloaterSpellCheckerSettings::LLFloaterSpellCheckerSettings(const LLSD& key) + : LLFloater(key) +{ +} + +BOOL LLFloaterSpellCheckerSettings::postBuild(void) +{ + gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaryLists, this, false)); + getChild("spellcheck_main_combo")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaryLists, this, false)); + getChild("spellcheck_moveleft_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onClickDictMove, this, "spellcheck_active_list", "spellcheck_available_list")); + getChild("spellcheck_moveright_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onClickDictMove, this, "spellcheck_available_list", "spellcheck_active_list")); + getChild("spellcheck_ok")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onOK, this)); + getChild("spellcheck_cancel")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onCancel, this)); + + return true; +} + +void LLFloaterSpellCheckerSettings::onCancel() +{ + closeFloater(false); +} + +void LLFloaterSpellCheckerSettings::onClickDictMove(const std::string& from, const std::string& to) +{ + LLScrollListCtrl* from_ctrl = findChild(from); + LLScrollListCtrl* to_ctrl = findChild(to); + + LLSD row; + row["columns"][0]["column"] = "name"; + row["columns"][0]["font"]["name"] = "SANSSERIF_SMALL"; + row["columns"][0]["font"]["style"] = "NORMAL"; + + std::vector sel_items = from_ctrl->getAllSelected(); + for (std::vector::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) + { + row["columns"][0]["value"] = (*sel_it)->getColumn(0)->getValue(); + to_ctrl->addElement(row); + } + from_ctrl->deleteSelectedItems(); +} + +void LLFloaterSpellCheckerSettings::onOK() +{ + std::list list_dict; + + LLComboBox* dict_combo = findChild("spellcheck_main_combo"); + const std::string dict_name = dict_combo->getSelectedItemLabel(); + if (!dict_name.empty()) + { + list_dict.push_back(dict_name); + + LLScrollListCtrl* list_ctrl = findChild("spellcheck_active_list"); + std::vector list_items = list_ctrl->getAllData(); + for (std::vector::const_iterator item_it = list_items.begin(); item_it != list_items.end(); ++item_it) + list_dict.push_back((*item_it)->getColumn(0)->getValue().asString()); + } + gSavedSettings.setString("SpellCheckDictionary", boost::join(list_dict, ",")); + + closeFloater(false); +} + +void LLFloaterSpellCheckerSettings::onOpen(const LLSD& key) +{ + refreshDictionaryLists(true); +} + +void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings) +{ + bool enabled = gSavedSettings.getBOOL("SpellCheck"); + getChild("spellcheck_moveleft_btn")->setEnabled(enabled); + getChild("spellcheck_moveright_btn")->setEnabled(enabled); + + // Populate the dictionary combobox + LLComboBox* dict_combo = findChild("spellcheck_main_combo"); + std::string dict_cur = dict_combo->getSelectedItemLabel(); + if ((dict_cur.empty() || from_settings) && (LLSpellChecker::getUseSpellCheck())) + dict_cur = LLSpellChecker::instance().getActiveDictionary(); + dict_combo->clearRows(); + dict_combo->setEnabled(enabled); + + const LLSD& dict_map = LLSpellChecker::getDictionaryMap(); + if (dict_map.size()) + { + 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["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 + LLScrollListCtrl* avail_ctrl = findChild("spellcheck_available_list"); + LLScrollListCtrl* active_ctrl = findChild("spellcheck_active_list"); + + LLSpellChecker::dict_list_t active_list; + if ( ((!avail_ctrl->getItemCount()) && (!active_ctrl->getItemCount())) || (from_settings) ) + { + if (LLSpellChecker::getUseSpellCheck()) + active_list = LLSpellChecker::instance().getSecondaryDictionaries(); + } + else + { + std::vector active_items = active_ctrl->getAllData(); + for (std::vector::const_iterator item_it = active_items.begin(); item_it != active_items.end(); ++item_it) + { + std::string dict = (*item_it)->getColumn(0)->getValue().asString(); + if (dict_cur != dict) + active_list.push_back(dict); + } + } + + LLSD row; + row["columns"][0]["column"] = "name"; + row["columns"][0]["font"]["name"] = "SANSSERIF_SMALL"; + row["columns"][0]["font"]["style"] = "NORMAL"; + + 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; + active_ctrl->addElement(row); + } + 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())) ) + { + row["columns"][0]["value"] = dict["language"].asString(); + avail_ctrl->addElement(row); + } + } +} diff --git a/indra/newview/llfloaterspellchecksettings.h b/indra/newview/llfloaterspellchecksettings.h new file mode 100644 index 0000000000..33c376fff6 --- /dev/null +++ b/indra/newview/llfloaterspellchecksettings.h @@ -0,0 +1,48 @@ +/** + * @file llfloaterspellchecksettings.h + * @brief Spell checker settings floater + * +* $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLFLOATERAUTOREPLACESETTINGS_H +#define LLFLOATERAUTOREPLACESETTINGS_H + +#include "llfloater.h" + +class LLFloaterSpellCheckerSettings : public LLFloater +{ +public: + LLFloaterSpellCheckerSettings(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + +protected: + void onCancel(); + void onClickDictMove(const std::string& from, const std::string& to); + void onOK(); + void onSave(); + void refreshDictionaryLists(bool from_settings); +}; + +#endif // LLFLOATERAUTOREPLACESETTINGS_H diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 7fdaac68c8..e9ce04fd3f 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -100,6 +100,7 @@ #include "llfloatersidepanelcontainer.h" #include "llfloatersnapshot.h" #include "llfloatersounddevices.h" +#include "llfloaterspellchecksettings.h" #include "llfloatertelehub.h" #include "llfloatertestinspectors.h" #include "llfloatertestlistview.h" @@ -248,6 +249,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("prefs_hardware_settings", "floater_hardware_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("perm_prefs", "floater_perm_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("picks", "floater_picks.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/skins/default/xui/en/floater_preferences.xml b/indra/newview/skins/default/xui/en/floater_preferences.xml index 9433866c4d..bd6faf4ed8 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences.xml @@ -120,12 +120,6 @@ layout="topleft" help_topic="preferences_advanced1_tab" name="advanced1" /> - diff --git a/indra/newview/skins/default/xui/en/floater_spellcheck.xml b/indra/newview/skins/default/xui/en/floater_spellcheck.xml new file mode 100644 index 0000000000..bd3f60cf4a --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_spellcheck.xml @@ -0,0 +1,175 @@ + + + + + + Main dictionary : + + + + Additional dictionaries : + + + Available + + + Active + + + + + + + + \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml b/indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml deleted file mode 100644 index f1b16c5d0d..0000000000 --- a/indra/newview/skins/default/xui/en/panel_preferences_spellcheck.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - - - Main dictionary : - - - - - Additional dictionaries : - - - Available - - - Active - - - - - - - -- cgit v1.2.3