STORM-276 Reworked the spell check preferences to be more robust and less error-prone
parent
2114e88cd1
commit
60e39343b1
|
|
@ -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<std::str
|
|||
return suggestions.size();
|
||||
}
|
||||
|
||||
const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_name) const
|
||||
// static
|
||||
const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_name)
|
||||
{
|
||||
for (LLSD::array_const_iterator it = mDictMap.beginArray(); it != mDictMap.endArray(); ++it)
|
||||
for (LLSD::array_const_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
|
||||
{
|
||||
const LLSD& dict_entry = *it;
|
||||
if (dict_name == dict_entry["language"].asString())
|
||||
|
|
@ -97,6 +99,7 @@ const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_name) const
|
|||
return LLSD();
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::refreshDictionaryMap()
|
||||
{
|
||||
const std::string app_path = getDictionaryAppPath();
|
||||
|
|
@ -104,16 +107,16 @@ void LLSpellChecker::refreshDictionaryMap()
|
|||
|
||||
// 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()) )
|
||||
if ( (!user_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_map)) || (0 == sDictMap.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()) )
|
||||
if ( (!app_map.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_map)) || (0 == sDictMap.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)
|
||||
for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it)
|
||||
{
|
||||
LLSD& sdDict = *it;
|
||||
tmp_app_path = (sdDict.has("name")) ? app_path + sdDict["name"].asString() : LLStringUtil::null;
|
||||
|
|
@ -343,3 +346,10 @@ void LLSpellChecker::setUseSpellCheck(const std::string& dict_name)
|
|||
LLSpellChecker::instance().initHunspell(dict_name);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLSpellChecker::initClass()
|
||||
{
|
||||
if (sDictMap.isUndefined())
|
||||
refreshDictionaryMap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,13 +28,15 @@
|
|||
#define LLSPELLCHECK_H
|
||||
|
||||
#include "llsingleton.h"
|
||||
#include "llui.h"
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class Hunspell;
|
||||
|
||||
class LLSpellChecker : public LLSingleton<LLSpellChecker>
|
||||
class LLSpellChecker : public LLSingleton<LLSpellChecker>, public LLInitClass<LLSpellChecker>
|
||||
{
|
||||
friend class LLSingleton<LLSpellChecker>;
|
||||
friend class LLInitClass<LLSpellChecker>;
|
||||
protected:
|
||||
LLSpellChecker();
|
||||
~LLSpellChecker();
|
||||
|
|
@ -52,28 +54,30 @@ public:
|
|||
typedef std::list<std::string> 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<void()> 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<std::string> mIgnoreList;
|
||||
|
||||
static LLSD sDictMap;
|
||||
static settings_change_signal_t sSettingsChangeSignal;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -448,6 +448,8 @@ BOOL LLFloaterPreference::postBuild()
|
|||
|
||||
getChild<LLComboBox>("language_combobox")->setCommitCallback(boost::bind(&LLFloaterPreference::onLanguageChange, this));
|
||||
|
||||
gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterPreference::refreshDictLists, this, false));
|
||||
getChild<LLUICtrl>("combo_spellcheck_dict")->setCommitCallback(boost::bind(&LLFloaterPreference::refreshDictLists, this, false));
|
||||
getChild<LLUICtrl>("btn_spellcheck_moveleft")->setCommitCallback(boost::bind(&LLFloaterPreference::onClickDictMove, this, "list_spellcheck_active", "list_spellcheck_available"));
|
||||
getChild<LLUICtrl>("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<LLScrollListCtrl>("list_spellcheck_active");
|
||||
std::vector<LLScrollListItem*> list_items = list_ctrl->getAllData();
|
||||
|
||||
std::list<std::string> list_dict;
|
||||
list_dict.push_back(LLSpellChecker::instance().getActiveDictionary());
|
||||
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());
|
||||
|
||||
LLComboBox* dict_combo = findChild<LLComboBox>("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<LLScrollListCtrl>("list_spellcheck_active");
|
||||
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());
|
||||
}
|
||||
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<LLRadioGroup>("skin_selection", true)->setValue(sSkin);
|
||||
}
|
||||
|
||||
void LLFloaterPreference::buildDictLists()
|
||||
void LLFloaterPreference::refreshDictLists(bool from_settings)
|
||||
{
|
||||
bool enabled = gSavedSettings.getBOOL("SpellCheck");
|
||||
getChild<LLUICtrl>("btn_spellcheck_moveleft")->setEnabled(enabled);
|
||||
getChild<LLUICtrl>("btn_spellcheck_moveright")->setEnabled(enabled);
|
||||
|
||||
// Populate the dictionary combobox
|
||||
LLComboBox* dict_combo = findChild<LLComboBox>("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<LLScrollListCtrl>("list_spellcheck_active");
|
||||
active_ctrl->clearRows();
|
||||
|
||||
LLScrollListCtrl* avail_ctrl = findChild<LLScrollListCtrl>("list_spellcheck_available");
|
||||
avail_ctrl->clearRows();
|
||||
|
||||
if (LLSpellChecker::getUseSpellCheck())
|
||||
const LLSD& dict_map = LLSpellChecker::getDictionaryMap();
|
||||
if (dict_map.size())
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
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<LLScrollListCtrl>("list_spellcheck_available");
|
||||
LLScrollListCtrl* active_ctrl = findChild<LLScrollListCtrl>("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<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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
Active
|
||||
</text>
|
||||
<scroll_list
|
||||
enabled_control="SpellCheck"
|
||||
follows="top|left"
|
||||
height="155"
|
||||
layout="topleft"
|
||||
|
|
@ -96,6 +97,7 @@
|
|||
sort_ascending="true"
|
||||
width="175" />
|
||||
<button
|
||||
enabled_control="SpellCheck"
|
||||
follows="top|left"
|
||||
height="26"
|
||||
image_overlay="Arrow_Right"
|
||||
|
|
@ -107,6 +109,7 @@
|
|||
width="25">
|
||||
</button>
|
||||
<button
|
||||
enabled_control="SpellCheck"
|
||||
follows="top|left"
|
||||
height="26"
|
||||
image_overlay="Arrow_Left"
|
||||
|
|
@ -117,6 +120,7 @@
|
|||
width="25">
|
||||
</button>
|
||||
<scroll_list
|
||||
enabled_control="SpellCheck"
|
||||
follows="top|left"
|
||||
height="155"
|
||||
layout="topleft"
|
||||
|
|
|
|||
Loading…
Reference in New Issue