merge spelling changes for UI review
commit
eb227e4dbc
|
|
@ -24,6 +24,7 @@ indra/lib/mono/indra/*.exe
|
|||
indra/lib/mono/indra/*.pdb
|
||||
indra/lib/python/eventlet/
|
||||
indra/llwindow/glh/glh_linear.h
|
||||
indra/newview/app_settings/dictionaries
|
||||
indra/newview/app_settings/mozilla
|
||||
indra/newview/app_settings/mozilla-runtime-*
|
||||
indra/newview/app_settings/mozilla_debug
|
||||
|
|
|
|||
|
|
@ -599,7 +599,9 @@ std::string LLLineEditor::getMisspelledWord(U32 pos) const
|
|||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
if ( (it->first <= pos) && (it->second >= pos) )
|
||||
{
|
||||
return wstring_to_utf8str(mText.getWString().substr(it->first, it->second - it->first));
|
||||
}
|
||||
}
|
||||
return LLStringUtil::null;
|
||||
}
|
||||
|
|
@ -609,7 +611,9 @@ bool LLLineEditor::isMisspelledWord(U32 pos) const
|
|||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
if ( (it->first <= pos) && (it->second >= pos) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1896,7 +1900,9 @@ void LLLineEditor::draw()
|
|||
// Find the start of the first word
|
||||
U32 word_start = 0, word_end = 0;
|
||||
while ( (word_start < text.length()) && (!LLStringOps::isAlpha(text[word_start])) )
|
||||
{
|
||||
word_start++;
|
||||
}
|
||||
|
||||
// Iterate over all words in the text block and check them one by one
|
||||
mMisspellRanges.clear();
|
||||
|
|
@ -1912,17 +1918,23 @@ void LLLineEditor::draw()
|
|||
word_end++;
|
||||
}
|
||||
if (word_end > text.length())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't process words shorter than 3 characters
|
||||
std::string word = wstring_to_utf8str(text.substr(word_start, word_end - word_start));
|
||||
if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) )
|
||||
{
|
||||
mMisspellRanges.push_back(std::pair<U32, U32>(start + word_start, start + word_end));
|
||||
}
|
||||
|
||||
// Find the start of the next word
|
||||
word_start = word_end + 1;
|
||||
while ( (word_start < text.length()) && (!LLWStringUtil::isPartOfWord(text[word_start])) )
|
||||
{
|
||||
word_start++;
|
||||
}
|
||||
}
|
||||
|
||||
mSpellCheckStart = start;
|
||||
|
|
@ -1934,19 +1946,27 @@ void LLLineEditor::draw()
|
|||
{
|
||||
// Skip over words that aren't (partially) visible
|
||||
if ( ((it->first < start) && (it->second < start)) || (it->first > end) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip the current word if the user is still busy editing it
|
||||
if ( (!mSpellCheckTimer.hasExpired()) && (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
S32 pxWidth = getRect().getWidth();
|
||||
S32 pxStart = findPixelNearestPos(it->first - getCursor());
|
||||
if (pxStart > pxWidth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
S32 pxEnd = findPixelNearestPos(it->second - getCursor());
|
||||
if (pxEnd > pxWidth)
|
||||
{
|
||||
pxEnd = pxWidth;
|
||||
}
|
||||
|
||||
S32 pxBottom = (S32)(text_bottom + mGLFont->getDescenderHeight());
|
||||
|
||||
|
|
@ -1955,7 +1975,9 @@ void LLLineEditor::draw()
|
|||
{
|
||||
gl_line_2d(pxStart, pxBottom, pxStart + 2, pxBottom - 2);
|
||||
if (pxStart + 3 < pxEnd)
|
||||
{
|
||||
gl_line_2d(pxStart + 2, pxBottom - 3, pxStart + 4, pxBottom - 1);
|
||||
}
|
||||
pxStart += 4;
|
||||
}
|
||||
}
|
||||
|
|
@ -2582,9 +2604,13 @@ void LLLineEditor::showContextMenu(S32 x, S32 y)
|
|||
if (hasSelection())
|
||||
{
|
||||
if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) )
|
||||
{
|
||||
deselect();
|
||||
}
|
||||
else
|
||||
{
|
||||
setCursor(llmax(mSelectionStart, mSelectionEnd));
|
||||
}
|
||||
}
|
||||
|
||||
bool use_spellcheck = getSpellCheck(), is_misspelled = false;
|
||||
|
|
|
|||
|
|
@ -3909,9 +3909,13 @@ void LLContextMenu::show(S32 x, S32 y, LLView* spawning_view)
|
|||
arrange();
|
||||
|
||||
if (spawning_view)
|
||||
{
|
||||
mSpawningViewHandle = spawning_view->getHandle();
|
||||
}
|
||||
else
|
||||
{
|
||||
mSpawningViewHandle.markDead();
|
||||
}
|
||||
LLView::setVisible(TRUE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ static const std::string DICT_DIR = "dictionaries";
|
|||
static const std::string DICT_CUSTOM_SUFFIX = "_custom";
|
||||
static const std::string DICT_IGNORE_SUFFIX = "_ignore";
|
||||
|
||||
static const std::string DICT_FILE_MAIN = "dictionaries.xml";
|
||||
static const std::string DICT_FILE_USER = "user_dictionaries.xml";
|
||||
|
||||
LLSD LLSpellChecker::sDictMap;
|
||||
LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal;
|
||||
|
||||
|
|
@ -75,13 +78,17 @@ S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector<std::str
|
|||
{
|
||||
suggestions.clear();
|
||||
if ( (!mHunspell) || (word.length() < 3) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char** suggestion_list; int suggestion_cnt = 0;
|
||||
if ( (suggestion_cnt = mHunspell->suggest(&suggestion_list, word.c_str())) != 0 )
|
||||
{
|
||||
for (int suggestion_index = 0; suggestion_index < suggestion_cnt; suggestion_index++)
|
||||
{
|
||||
suggestions.push_back(suggestion_list[suggestion_index]);
|
||||
}
|
||||
mHunspell->free_list(&suggestion_list, suggestion_cnt);
|
||||
}
|
||||
return suggestions.size();
|
||||
|
|
@ -94,17 +101,28 @@ const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_language)
|
|||
{
|
||||
const LLSD& dict_entry = *it;
|
||||
if (dict_language == dict_entry["language"].asString())
|
||||
{
|
||||
return dict_entry;
|
||||
}
|
||||
}
|
||||
return LLSD();
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLSpellChecker::hasDictionary(const std::string& dict_language, bool check_installed)
|
||||
{
|
||||
const LLSD dict_info = getDictionaryData(dict_language);
|
||||
return dict_info.has("language") && ( (!check_installed) || (dict_info["installed"].asBoolean()) );
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::setDictionaryData(const LLSD& dict_info)
|
||||
{
|
||||
const std::string dict_language = dict_info["language"].asString();
|
||||
if (dict_language.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
|
||||
{
|
||||
|
|
@ -126,22 +144,28 @@ void LLSpellChecker::refreshDictionaryMap()
|
|||
const std::string user_path = getDictionaryUserPath();
|
||||
|
||||
// Load dictionary information (file name, friendly name, ...)
|
||||
llifstream user_file(user_path + "dictionaries.xml", std::ios::binary);
|
||||
llifstream user_file(user_path + DICT_FILE_MAIN, std::ios::binary);
|
||||
if ( (!user_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_file)) || (0 == sDictMap.size()) )
|
||||
{
|
||||
llifstream app_file(app_path + "dictionaries.xml", std::ios::binary);
|
||||
llifstream app_file(app_path + DICT_FILE_MAIN, std::ios::binary);
|
||||
if ( (!app_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_file)) || (0 == sDictMap.size()) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Load user installed dictionary information
|
||||
llifstream custom_file(user_path + "user_dictionaries.xml", std::ios::binary);
|
||||
llifstream custom_file(user_path + DICT_FILE_USER, std::ios::binary);
|
||||
if (custom_file.is_open())
|
||||
{
|
||||
LLSD custom_dict_map;
|
||||
LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file);
|
||||
for (LLSD::array_const_iterator it = custom_dict_map.beginArray(); it != custom_dict_map.endArray(); ++it)
|
||||
setDictionaryData(*it);
|
||||
for (LLSD::array_iterator it = custom_dict_map.beginArray(); it != custom_dict_map.endArray(); ++it)
|
||||
{
|
||||
LLSD& dict_info = *it;
|
||||
dict_info["user_installed"] = true;
|
||||
setDictionaryData(dict_info);
|
||||
}
|
||||
custom_file.close();
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +221,9 @@ void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::stri
|
|||
{
|
||||
// Skip over the first line since that's just a line count
|
||||
if (0 != line_num)
|
||||
{
|
||||
word_list.push_back(word);
|
||||
}
|
||||
line_num++;
|
||||
}
|
||||
}
|
||||
|
|
@ -215,11 +241,20 @@ void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::stri
|
|||
{
|
||||
file_out << word_list.size() << std::endl;
|
||||
for (std::vector<std::string>::const_iterator itWord = word_list.begin(); itWord != word_list.end(); ++itWord)
|
||||
{
|
||||
file_out << *itWord << std::endl;
|
||||
}
|
||||
file_out.close();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLSpellChecker::isActiveDictionary(const std::string& dict_language) const
|
||||
{
|
||||
return
|
||||
(mDictLanguage == dict_language) ||
|
||||
(mDictSecondary.end() != std::find(mDictSecondary.begin(), mDictSecondary.end(), dict_language));
|
||||
}
|
||||
|
||||
void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list)
|
||||
{
|
||||
if (!getUseSpellCheck())
|
||||
|
|
@ -238,8 +273,8 @@ void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list)
|
|||
{
|
||||
mDictSecondary = dict_list;
|
||||
|
||||
std::string dict_name = mDictName;
|
||||
initHunspell(dict_name);
|
||||
std::string dict_language = mDictLanguage;
|
||||
initHunspell(dict_language);
|
||||
}
|
||||
else if (end_added != dict_add.begin()) // Add the new secondary dictionaries one by one
|
||||
{
|
||||
|
|
@ -249,31 +284,37 @@ void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list)
|
|||
{
|
||||
const LLSD dict_entry = getDictionaryData(*it_added);
|
||||
if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string strFileDic = dict_entry["name"].asString() + ".dic";
|
||||
if (gDirUtilp->fileExists(user_path + strFileDic))
|
||||
{
|
||||
mHunspell->add_dic((user_path + strFileDic).c_str());
|
||||
}
|
||||
else if (gDirUtilp->fileExists(app_path + strFileDic))
|
||||
{
|
||||
mHunspell->add_dic((app_path + strFileDic).c_str());
|
||||
}
|
||||
}
|
||||
mDictSecondary = dict_list;
|
||||
sSettingsChangeSignal();
|
||||
}
|
||||
}
|
||||
|
||||
void LLSpellChecker::initHunspell(const std::string& dict_name)
|
||||
void LLSpellChecker::initHunspell(const std::string& dict_language)
|
||||
{
|
||||
if (mHunspell)
|
||||
{
|
||||
delete mHunspell;
|
||||
mHunspell = NULL;
|
||||
mDictName.clear();
|
||||
mDictLanguage.clear();
|
||||
mDictFile.clear();
|
||||
mIgnoreList.clear();
|
||||
}
|
||||
|
||||
const LLSD dict_entry = (!dict_name.empty()) ? getDictionaryData(dict_name) : LLSD();
|
||||
const LLSD dict_entry = (!dict_language.empty()) ? getDictionaryData(dict_language) : LLSD();
|
||||
if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) || (!dict_entry["is_primary"].asBoolean()))
|
||||
{
|
||||
sSettingsChangeSignal();
|
||||
|
|
@ -287,13 +328,19 @@ void LLSpellChecker::initHunspell(const std::string& dict_name)
|
|||
const std::string filename_aff = dict_entry["name"].asString() + ".aff";
|
||||
const std::string filename_dic = dict_entry["name"].asString() + ".dic";
|
||||
if ( (gDirUtilp->fileExists(user_path + filename_aff)) && (gDirUtilp->fileExists(user_path + filename_dic)) )
|
||||
{
|
||||
mHunspell = new Hunspell((user_path + filename_aff).c_str(), (user_path + filename_dic).c_str());
|
||||
}
|
||||
else if ( (gDirUtilp->fileExists(app_path + filename_aff)) && (gDirUtilp->fileExists(app_path + filename_dic)) )
|
||||
{
|
||||
mHunspell = new Hunspell((app_path + filename_aff).c_str(), (app_path + filename_dic).c_str());
|
||||
}
|
||||
if (!mHunspell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mDictName = dict_name;
|
||||
mDictLanguage = dict_language;
|
||||
mDictFile = dict_entry["name"].asString();
|
||||
|
||||
if (dict_entry["has_custom"].asBoolean())
|
||||
|
|
@ -325,13 +372,19 @@ void LLSpellChecker::initHunspell(const std::string& dict_name)
|
|||
{
|
||||
const LLSD dict_entry = getDictionaryData(*it);
|
||||
if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string filename_dic = dict_entry["name"].asString() + ".dic";
|
||||
if (gDirUtilp->fileExists(user_path + filename_dic))
|
||||
{
|
||||
mHunspell->add_dic((user_path + filename_dic).c_str());
|
||||
}
|
||||
else if (gDirUtilp->fileExists(app_path + filename_dic))
|
||||
{
|
||||
mHunspell->add_dic((app_path + filename_dic).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -362,6 +415,73 @@ bool LLSpellChecker::getUseSpellCheck()
|
|||
return (LLSpellChecker::instanceExists()) && (LLSpellChecker::instance().mHunspell);
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLSpellChecker::canRemoveDictionary(const std::string& dict_language)
|
||||
{
|
||||
// Only user-installed inactive dictionaries can be removed
|
||||
const LLSD dict_info = getDictionaryData(dict_language);
|
||||
return
|
||||
(dict_info["user_installed"].asBoolean()) &&
|
||||
( (!getUseSpellCheck()) || (!LLSpellChecker::instance().isActiveDictionary(dict_language)) );
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::removeDictionary(const std::string& dict_language)
|
||||
{
|
||||
if (!canRemoveDictionary(dict_language))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLSD dict_map = loadUserDictionaryMap();
|
||||
for (LLSD::array_const_iterator it = dict_map.beginArray(); it != dict_map.endArray(); ++it)
|
||||
{
|
||||
const LLSD& dict_info = *it;
|
||||
if (dict_info["language"].asString() == dict_language)
|
||||
{
|
||||
const std::string dict_dic = getDictionaryUserPath() + dict_info["name"].asString() + ".dic";
|
||||
if (gDirUtilp->fileExists(dict_dic))
|
||||
{
|
||||
LLFile::remove(dict_dic);
|
||||
}
|
||||
const std::string dict_aff = getDictionaryUserPath() + dict_info["name"].asString() + ".aff";
|
||||
if (gDirUtilp->fileExists(dict_aff))
|
||||
{
|
||||
LLFile::remove(dict_aff);
|
||||
}
|
||||
dict_map.erase(it - dict_map.beginArray());
|
||||
break;
|
||||
}
|
||||
}
|
||||
saveUserDictionaryMap(dict_map);
|
||||
|
||||
refreshDictionaryMap();
|
||||
}
|
||||
|
||||
// static
|
||||
LLSD LLSpellChecker::loadUserDictionaryMap()
|
||||
{
|
||||
LLSD dict_map;
|
||||
llifstream dict_file(getDictionaryUserPath() + DICT_FILE_USER, std::ios::binary);
|
||||
if (dict_file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXMLDocument(dict_map, dict_file);
|
||||
dict_file.close();
|
||||
}
|
||||
return dict_map;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::saveUserDictionaryMap(const LLSD& dict_map)
|
||||
{
|
||||
llofstream dict_file(getDictionaryUserPath() + DICT_FILE_USER, std::ios::trunc);
|
||||
if (dict_file.is_open())
|
||||
{
|
||||
LLSDSerialize::toPrettyXML(dict_map, dict_file);
|
||||
dict_file.close();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
boost::signals2::connection LLSpellChecker::setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb)
|
||||
{
|
||||
|
|
@ -369,12 +489,12 @@ boost::signals2::connection LLSpellChecker::setSettingsChangeCallback(const sett
|
|||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::setUseSpellCheck(const std::string& dict_name)
|
||||
void LLSpellChecker::setUseSpellCheck(const std::string& dict_language)
|
||||
{
|
||||
if ( (((dict_name.empty()) && (getUseSpellCheck())) || (!dict_name.empty())) &&
|
||||
(LLSpellChecker::instance().mDictName != dict_name) )
|
||||
if ( (((dict_language.empty()) && (getUseSpellCheck())) || (!dict_language.empty())) &&
|
||||
(LLSpellChecker::instance().mDictLanguage != dict_language) )
|
||||
{
|
||||
LLSpellChecker::instance().initHunspell(dict_name);
|
||||
LLSpellChecker::instance().initHunspell(dict_language);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,5 +502,7 @@ void LLSpellChecker::setUseSpellCheck(const std::string& dict_name)
|
|||
void LLSpellChecker::initClass()
|
||||
{
|
||||
if (sDictMap.isUndefined())
|
||||
{
|
||||
refreshDictionaryMap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,24 +48,30 @@ public:
|
|||
S32 getSuggestions(const std::string& word, std::vector<std::string>& suggestions) const;
|
||||
protected:
|
||||
void addToDictFile(const std::string& dict_path, const std::string& word);
|
||||
void initHunspell(const std::string& dict_name);
|
||||
void initHunspell(const std::string& dict_language);
|
||||
|
||||
public:
|
||||
typedef std::list<std::string> dict_list_t;
|
||||
|
||||
const std::string& getActiveDictionary() const { return mDictName; }
|
||||
const std::string& getPrimaryDictionary() const { return mDictLanguage; }
|
||||
const dict_list_t& getSecondaryDictionaries() const { return mDictSecondary; }
|
||||
bool isActiveDictionary(const std::string& dict_language) const;
|
||||
void setSecondaryDictionaries(dict_list_t dict_list);
|
||||
|
||||
static bool canRemoveDictionary(const std::string& dict_language);
|
||||
static const std::string getDictionaryAppPath();
|
||||
static const std::string getDictionaryUserPath();
|
||||
static const LLSD getDictionaryData(const std::string& dict_language);
|
||||
static const LLSD& getDictionaryMap() { return sDictMap; }
|
||||
static bool getUseSpellCheck();
|
||||
static bool hasDictionary(const std::string& dict_language, bool check_installed = false);
|
||||
static void refreshDictionaryMap();
|
||||
static void setUseSpellCheck(const std::string& dict_name);
|
||||
static void removeDictionary(const std::string& dict_language);
|
||||
static void setUseSpellCheck(const std::string& dict_language);
|
||||
protected:
|
||||
static LLSD loadUserDictionaryMap();
|
||||
static void setDictionaryData(const LLSD& dict_info);
|
||||
static void saveUserDictionaryMap(const LLSD& dict_map);
|
||||
|
||||
public:
|
||||
typedef boost::signals2::signal<void()> settings_change_signal_t;
|
||||
|
|
@ -75,7 +81,7 @@ protected:
|
|||
|
||||
protected:
|
||||
Hunspell* mHunspell;
|
||||
std::string mDictName;
|
||||
std::string mDictLanguage;
|
||||
std::string mDictFile;
|
||||
dict_list_t mDictSecondary;
|
||||
std::vector<std::string> mIgnoreList;
|
||||
|
|
|
|||
|
|
@ -582,7 +582,9 @@ void LLTextBase::drawText()
|
|||
// Find the start of the first word
|
||||
U32 word_start = seg_start, word_end = -1;
|
||||
while ( (word_start < wstrText.length()) && (!LLStringOps::isAlpha(wstrText[word_start])) )
|
||||
{
|
||||
word_start++;
|
||||
}
|
||||
|
||||
// Iterate over all words in the text block and check them one by one
|
||||
while (word_start < seg_end)
|
||||
|
|
@ -597,7 +599,9 @@ void LLTextBase::drawText()
|
|||
word_end++;
|
||||
}
|
||||
if (word_end > seg_end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't process words shorter than 3 characters
|
||||
std::string word = wstring_to_utf8str(wstrText.substr(word_start, word_end - word_start));
|
||||
|
|
@ -609,7 +613,9 @@ void LLTextBase::drawText()
|
|||
// Find the start of the next word
|
||||
word_start = word_end + 1;
|
||||
while ( (word_start < seg_end) && (!LLWStringUtil::isPartOfWord(wstrText[word_start])) )
|
||||
{
|
||||
word_start++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -695,12 +701,16 @@ void LLTextBase::drawText()
|
|||
{
|
||||
gl_line_2d(squiggle_start, squiggle_bottom, squiggle_start + 2, squiggle_bottom - 2);
|
||||
if (squiggle_start + 3 < squiggle_end)
|
||||
{
|
||||
gl_line_2d(squiggle_start + 2, squiggle_bottom - 3, squiggle_start + 4, squiggle_bottom - 1);
|
||||
}
|
||||
squiggle_start += 4;
|
||||
}
|
||||
|
||||
if (misspell_it->second > seg_end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++misspell_it;
|
||||
}
|
||||
|
||||
|
|
@ -1297,7 +1307,9 @@ std::string LLTextBase::getMisspelledWord(U32 pos) const
|
|||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
if ( (it->first <= pos) && (it->second >= pos) )
|
||||
{
|
||||
return wstring_to_utf8str(getWText().substr(it->first, it->second - it->first));
|
||||
}
|
||||
}
|
||||
return LLStringUtil::null;
|
||||
}
|
||||
|
|
@ -1307,7 +1319,9 @@ bool LLTextBase::isMisspelledWord(U32 pos) const
|
|||
for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it)
|
||||
{
|
||||
if ( (it->first <= pos) && (it->second >= pos) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1960,9 +1960,13 @@ void LLTextEditor::showContextMenu(S32 x, S32 y)
|
|||
if (hasSelection())
|
||||
{
|
||||
if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) )
|
||||
{
|
||||
deselect();
|
||||
}
|
||||
else
|
||||
{
|
||||
setCursorPos(llmax(mSelectionStart, mSelectionEnd));
|
||||
}
|
||||
}
|
||||
|
||||
bool use_spellcheck = getSpellCheck(), is_misspelled = false;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "llscrolllistctrl.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llspellcheck.h"
|
||||
#include "lltrans.h"
|
||||
#include "llviewercontrol.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
|
@ -45,12 +46,26 @@ LLFloaterSpellCheckerSettings::LLFloaterSpellCheckerSettings(const LLSD& key)
|
|||
{
|
||||
}
|
||||
|
||||
void LLFloaterSpellCheckerSettings::draw()
|
||||
{
|
||||
LLFloater::draw();
|
||||
|
||||
std::vector<LLScrollListItem*> sel_items = getChild<LLScrollListCtrl>("spellcheck_available_list")->getAllSelected();
|
||||
bool enable_remove = !sel_items.empty();
|
||||
for (std::vector<LLScrollListItem*>::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it)
|
||||
{
|
||||
enable_remove &= LLSpellChecker::canRemoveDictionary((*sel_it)->getValue().asString());
|
||||
}
|
||||
getChild<LLUICtrl>("spellcheck_remove_btn")->setEnabled(enable_remove);
|
||||
}
|
||||
|
||||
BOOL LLFloaterSpellCheckerSettings::postBuild(void)
|
||||
{
|
||||
gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaryLists, this, false));
|
||||
gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaries, this, false));
|
||||
LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange, this));
|
||||
getChild<LLUICtrl>("spellcheck_remove_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnRemove, this));
|
||||
getChild<LLUICtrl>("spellcheck_import_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnImport, this));
|
||||
getChild<LLUICtrl>("spellcheck_main_combo")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaryLists, this, false));
|
||||
getChild<LLUICtrl>("spellcheck_main_combo")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaries, this, false));
|
||||
getChild<LLUICtrl>("spellcheck_moveleft_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_active_list", "spellcheck_available_list"));
|
||||
getChild<LLUICtrl>("spellcheck_moveright_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_available_list", "spellcheck_active_list"));
|
||||
getChild<LLUICtrl>("spellcheck_ok")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnOK, this));
|
||||
|
|
@ -82,6 +97,7 @@ void LLFloaterSpellCheckerSettings::onBtnMove(const std::string& from, const std
|
|||
std::vector<LLScrollListItem*> sel_items = from_ctrl->getAllSelected();
|
||||
for (std::vector<LLScrollListItem*>::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it)
|
||||
{
|
||||
row["value"] = (*sel_it)->getValue();
|
||||
row["columns"][0]["value"] = (*sel_it)->getColumn(0)->getValue();
|
||||
to_ctrl->addElement(row);
|
||||
}
|
||||
|
|
@ -101,7 +117,13 @@ void LLFloaterSpellCheckerSettings::onBtnOK()
|
|||
LLScrollListCtrl* list_ctrl = findChild<LLScrollListCtrl>("spellcheck_active_list");
|
||||
std::vector<LLScrollListItem*> list_items = list_ctrl->getAllData();
|
||||
for (std::vector<LLScrollListItem*>::const_iterator item_it = list_items.begin(); item_it != list_items.end(); ++item_it)
|
||||
list_dict.push_back((*item_it)->getColumn(0)->getValue().asString());
|
||||
{
|
||||
const std::string language = (*item_it)->getValue().asString();
|
||||
if (LLSpellChecker::hasDictionary(language, true))
|
||||
{
|
||||
list_dict.push_back(language);
|
||||
}
|
||||
}
|
||||
}
|
||||
gSavedSettings.setString("SpellCheckDictionary", boost::join(list_dict, ","));
|
||||
|
||||
|
|
@ -110,15 +132,24 @@ void LLFloaterSpellCheckerSettings::onBtnOK()
|
|||
|
||||
void LLFloaterSpellCheckerSettings::onOpen(const LLSD& key)
|
||||
{
|
||||
refreshDictionaryLists(true);
|
||||
refreshDictionaries(true);
|
||||
}
|
||||
|
||||
void LLFloaterSpellCheckerSettings::onBtnRemove()
|
||||
{
|
||||
std::vector<LLScrollListItem*> sel_items = getChild<LLScrollListCtrl>("spellcheck_available_list")->getAllSelected();
|
||||
for (std::vector<LLScrollListItem*>::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it)
|
||||
{
|
||||
LLSpellChecker::instance().removeDictionary((*sel_it)->getValue().asString());
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange()
|
||||
{
|
||||
refreshDictionaryLists(true);
|
||||
refreshDictionaries(true);
|
||||
}
|
||||
|
||||
void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings)
|
||||
void LLFloaterSpellCheckerSettings::refreshDictionaries(bool from_settings)
|
||||
{
|
||||
bool enabled = gSavedSettings.getBOOL("SpellCheck");
|
||||
getChild<LLUICtrl>("spellcheck_moveleft_btn")->setEnabled(enabled);
|
||||
|
|
@ -128,7 +159,9 @@ void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings)
|
|||
LLComboBox* dict_combo = findChild<LLComboBox>("spellcheck_main_combo");
|
||||
std::string dict_cur = dict_combo->getSelectedItemLabel();
|
||||
if ((dict_cur.empty() || from_settings) && (LLSpellChecker::getUseSpellCheck()))
|
||||
dict_cur = LLSpellChecker::instance().getActiveDictionary();
|
||||
{
|
||||
dict_cur = LLSpellChecker::instance().getPrimaryDictionary();
|
||||
}
|
||||
dict_combo->clearRows();
|
||||
dict_combo->setEnabled(enabled);
|
||||
|
||||
|
|
@ -139,10 +172,14 @@ void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings)
|
|||
{
|
||||
const LLSD& dict = *dict_it;
|
||||
if ( (dict["installed"].asBoolean()) && (dict["is_primary"].asBoolean()) && (dict.has("language")) )
|
||||
{
|
||||
dict_combo->add(dict["language"].asString());
|
||||
}
|
||||
}
|
||||
if (!dict_combo->selectByValue(dict_cur))
|
||||
{
|
||||
dict_combo->clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the available and active dictionary list
|
||||
|
|
@ -153,16 +190,20 @@ void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings)
|
|||
if ( ((!avail_ctrl->getItemCount()) && (!active_ctrl->getItemCount())) || (from_settings) )
|
||||
{
|
||||
if (LLSpellChecker::getUseSpellCheck())
|
||||
{
|
||||
active_list = LLSpellChecker::instance().getSecondaryDictionaries();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<LLScrollListItem*> active_items = active_ctrl->getAllData();
|
||||
for (std::vector<LLScrollListItem*>::const_iterator item_it = active_items.begin(); item_it != active_items.end(); ++item_it)
|
||||
{
|
||||
std::string dict = (*item_it)->getColumn(0)->getValue().asString();
|
||||
std::string dict = (*item_it)->getValue().asString();
|
||||
if (dict_cur != dict)
|
||||
{
|
||||
active_list.push_back(dict);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -173,27 +214,31 @@ void LLFloaterSpellCheckerSettings::refreshDictionaryLists(bool from_settings)
|
|||
|
||||
active_ctrl->clearRows();
|
||||
active_ctrl->setEnabled(enabled);
|
||||
active_ctrl->sortByColumnIndex(0, true);
|
||||
for (LLSpellChecker::dict_list_t::const_iterator it = active_list.begin(); it != active_list.end(); ++it)
|
||||
{
|
||||
row["columns"][0]["value"] = *it;
|
||||
const std::string language = *it;
|
||||
const LLSD dict = LLSpellChecker::getDictionaryData(language);
|
||||
row["value"] = language;
|
||||
row["columns"][0]["value"] = (!dict["user_installed"].asBoolean()) ? language : language + " " + LLTrans::getString("UserDictionary");
|
||||
active_ctrl->addElement(row);
|
||||
}
|
||||
active_ctrl->sortByColumnIndex(0, true);
|
||||
active_list.push_back(dict_cur);
|
||||
|
||||
avail_ctrl->clearRows();
|
||||
avail_ctrl->setEnabled(enabled);
|
||||
avail_ctrl->sortByColumnIndex(0, true);
|
||||
for (LLSD::array_const_iterator dict_it = dict_map.beginArray(); dict_it != dict_map.endArray(); ++dict_it)
|
||||
{
|
||||
const LLSD& dict = *dict_it;
|
||||
if ( (dict["installed"].asBoolean()) && (dict.has("language")) &&
|
||||
(active_list.end() == std::find(active_list.begin(), active_list.end(), dict["language"].asString())) )
|
||||
const std::string language = dict["language"].asString();
|
||||
if ( (dict["installed"].asBoolean()) && (active_list.end() == std::find(active_list.begin(), active_list.end(), language)) )
|
||||
{
|
||||
row["columns"][0]["value"] = dict["language"].asString();
|
||||
row["value"] = language;
|
||||
row["columns"][0]["value"] = (!dict["user_installed"].asBoolean()) ? language : language + " " + LLTrans::getString("UserDictionary");
|
||||
avail_ctrl->addElement(row);
|
||||
}
|
||||
}
|
||||
avail_ctrl->sortByColumnIndex(0, true);
|
||||
}
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class LLFloaterSpellCheckerSettings : public LLFloater
|
|||
public:
|
||||
LLFloaterSpellCheckerSettings(const LLSD& key);
|
||||
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ void onOpen(const LLSD& key);
|
||||
|
||||
|
|
@ -42,8 +43,9 @@ protected:
|
|||
void onBtnImport();
|
||||
void onBtnMove(const std::string& from, const std::string& to);
|
||||
void onBtnOK();
|
||||
void onBtnRemove();
|
||||
void onSpellCheckSettingsChange();
|
||||
void refreshDictionaryLists(bool from_settings);
|
||||
void refreshDictionaries(bool from_settings);
|
||||
};
|
||||
|
||||
class LLFloaterSpellCheckerImport : public LLFloater
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
border="true"
|
||||
can_close="true"
|
||||
can_minimize="true"
|
||||
bottom="275"
|
||||
bottom="300"
|
||||
left="300"
|
||||
can_resize="false"
|
||||
height="330"
|
||||
height="355"
|
||||
width="490"
|
||||
name="spellcheck_floater"
|
||||
title="Spell Checker Settings">
|
||||
|
|
@ -53,16 +53,6 @@
|
|||
top_pad="-15"
|
||||
width="175"
|
||||
/>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="23"
|
||||
label="Import"
|
||||
label_selected="Import"
|
||||
layout="topleft"
|
||||
left_pad="5"
|
||||
name="spellcheck_import_btn"
|
||||
top_delta="0"
|
||||
width="75" />
|
||||
<text
|
||||
enabled_control="SpellCheck"
|
||||
follows="top|left"
|
||||
|
|
@ -148,6 +138,25 @@
|
|||
top_pad="-105"
|
||||
width="175"
|
||||
/>
|
||||
<button
|
||||
enabled="false"
|
||||
follows="left|top"
|
||||
height="23"
|
||||
label="Remove"
|
||||
layout="topleft"
|
||||
left="55"
|
||||
name="spellcheck_remove_btn"
|
||||
top_pad="5"
|
||||
width="80" />
|
||||
<button
|
||||
follows="left|top"
|
||||
height="23"
|
||||
label="Import..."
|
||||
layout="topleft"
|
||||
left_pad="15"
|
||||
name="spellcheck_import_btn"
|
||||
top_delta="0"
|
||||
width="80" />
|
||||
<view_border
|
||||
top_pad="10"
|
||||
left="2"
|
||||
|
|
@ -159,7 +168,7 @@
|
|||
mouse_opaque="false"
|
||||
name="divisor4"/>
|
||||
<button
|
||||
top_pad="10"
|
||||
top_pad="8"
|
||||
right="380"
|
||||
height="22"
|
||||
width="90"
|
||||
|
|
|
|||
|
|
@ -3758,4 +3758,7 @@ Try enclosing path to the editor with double quotes.
|
|||
<string name="snapshot_quality_high">High</string>
|
||||
<string name="snapshot_quality_very_high">Very High</string>
|
||||
|
||||
<!-- Spell check settings floater -->
|
||||
<string name="UserDictionary">[User]</string>
|
||||
|
||||
</strings>
|
||||
|
|
|
|||
Loading…
Reference in New Issue