STORM-276 Added the ability to remove (user-installed) dictionaries

master
Kitty Barnett 2012-06-11 17:37:06 +02:00
parent 45b00642aa
commit d96d3d5256
5 changed files with 147 additions and 31 deletions

View File

@ -41,6 +41,9 @@ static const std::string DICT_DIR = "dictionaries";
static const std::string DICT_CUSTOM_SUFFIX = "_custom";
static const std::string DICT_IGNORE_SUFFIX = "_ignore";
static const std::string DICT_FILE_MAIN = "dictionaries.xml";
static const std::string DICT_FILE_USER = "user_dictionaries.xml";
LLSD LLSpellChecker::sDictMap;
LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal;
@ -141,10 +144,10 @@ void LLSpellChecker::refreshDictionaryMap()
const std::string user_path = getDictionaryUserPath();
// Load dictionary information (file name, friendly name, ...)
llifstream user_file(user_path + "dictionaries.xml", std::ios::binary);
llifstream user_file(user_path + DICT_FILE_MAIN, std::ios::binary);
if ( (!user_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_file)) || (0 == sDictMap.size()) )
{
llifstream app_file(app_path + "dictionaries.xml", std::ios::binary);
llifstream app_file(app_path + DICT_FILE_MAIN, std::ios::binary);
if ( (!app_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_file)) || (0 == sDictMap.size()) )
{
return;
@ -152,7 +155,7 @@ void LLSpellChecker::refreshDictionaryMap()
}
// Load user installed dictionary information
llifstream custom_file(user_path + "user_dictionaries.xml", std::ios::binary);
llifstream custom_file(user_path + DICT_FILE_USER, std::ios::binary);
if (custom_file.is_open())
{
LLSD custom_dict_map;
@ -245,6 +248,13 @@ void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::stri
}
}
bool LLSpellChecker::isActiveDictionary(const std::string& dict_language) const
{
return
(mDictLanguage == dict_language) ||
(mDictSecondary.end() != std::find(mDictSecondary.begin(), mDictSecondary.end(), dict_language));
}
void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list)
{
if (!getUseSpellCheck())
@ -263,8 +273,8 @@ void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list)
{
mDictSecondary = dict_list;
std::string dict_name = mDictName;
initHunspell(dict_name);
std::string dict_language = mDictLanguage;
initHunspell(dict_language);
}
else if (end_added != dict_add.begin()) // Add the new secondary dictionaries one by one
{
@ -293,18 +303,18 @@ void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list)
}
}
void LLSpellChecker::initHunspell(const std::string& dict_name)
void LLSpellChecker::initHunspell(const std::string& dict_language)
{
if (mHunspell)
{
delete mHunspell;
mHunspell = NULL;
mDictName.clear();
mDictLanguage.clear();
mDictFile.clear();
mIgnoreList.clear();
}
const LLSD dict_entry = (!dict_name.empty()) ? getDictionaryData(dict_name) : LLSD();
const LLSD dict_entry = (!dict_language.empty()) ? getDictionaryData(dict_language) : LLSD();
if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) || (!dict_entry["is_primary"].asBoolean()))
{
sSettingsChangeSignal();
@ -330,7 +340,7 @@ void LLSpellChecker::initHunspell(const std::string& dict_name)
return;
}
mDictName = dict_name;
mDictLanguage = dict_language;
mDictFile = dict_entry["name"].asString();
if (dict_entry["has_custom"].asBoolean())
@ -405,6 +415,73 @@ bool LLSpellChecker::getUseSpellCheck()
return (LLSpellChecker::instanceExists()) && (LLSpellChecker::instance().mHunspell);
}
// static
bool LLSpellChecker::canRemoveDictionary(const std::string& dict_language)
{
// Only user-installed inactive dictionaries can be removed
const LLSD dict_info = getDictionaryData(dict_language);
return
(dict_info["user_installed"].asBoolean()) &&
( (!getUseSpellCheck()) || (!LLSpellChecker::instance().isActiveDictionary(dict_language)) );
}
// static
void LLSpellChecker::removeDictionary(const std::string& dict_language)
{
if (!canRemoveDictionary(dict_language))
{
return;
}
LLSD dict_map = loadUserDictionaryMap();
for (LLSD::array_const_iterator it = dict_map.beginArray(); it != dict_map.endArray(); ++it)
{
const LLSD& dict_info = *it;
if (dict_info["language"].asString() == dict_language)
{
const std::string dict_dic = getDictionaryUserPath() + dict_info["name"].asString() + ".dic";
if (gDirUtilp->fileExists(dict_dic))
{
LLFile::remove(dict_dic);
}
const std::string dict_aff = getDictionaryUserPath() + dict_info["name"].asString() + ".aff";
if (gDirUtilp->fileExists(dict_aff))
{
LLFile::remove(dict_aff);
}
dict_map.erase(it - dict_map.beginArray());
break;
}
}
saveUserDictionaryMap(dict_map);
refreshDictionaryMap();
}
// static
LLSD LLSpellChecker::loadUserDictionaryMap()
{
LLSD dict_map;
llifstream dict_file(getDictionaryUserPath() + DICT_FILE_USER, std::ios::binary);
if (dict_file.is_open())
{
LLSDSerialize::fromXMLDocument(dict_map, dict_file);
dict_file.close();
}
return dict_map;
}
// static
void LLSpellChecker::saveUserDictionaryMap(const LLSD& dict_map)
{
llofstream dict_file(getDictionaryUserPath() + DICT_FILE_USER, std::ios::trunc);
if (dict_file.is_open())
{
LLSDSerialize::toPrettyXML(dict_map, dict_file);
dict_file.close();
}
}
// static
boost::signals2::connection LLSpellChecker::setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb)
{
@ -412,12 +489,12 @@ boost::signals2::connection LLSpellChecker::setSettingsChangeCallback(const sett
}
// static
void LLSpellChecker::setUseSpellCheck(const std::string& dict_name)
void LLSpellChecker::setUseSpellCheck(const std::string& dict_language)
{
if ( (((dict_name.empty()) && (getUseSpellCheck())) || (!dict_name.empty())) &&
(LLSpellChecker::instance().mDictName != dict_name) )
if ( (((dict_language.empty()) && (getUseSpellCheck())) || (!dict_language.empty())) &&
(LLSpellChecker::instance().mDictLanguage != dict_language) )
{
LLSpellChecker::instance().initHunspell(dict_name);
LLSpellChecker::instance().initHunspell(dict_language);
}
}

View File

@ -48,15 +48,17 @@ 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);
@ -64,9 +66,12 @@ public:
static bool getUseSpellCheck();
static bool hasDictionary(const std::string& dict_language, bool check_installed = false);
static void refreshDictionaryMap();
static void setUseSpellCheck(const std::string& dict_name);
static void removeDictionary(const std::string& dict_language);
static void setUseSpellCheck(const std::string& dict_language);
protected:
static LLSD loadUserDictionaryMap();
static void setDictionaryData(const LLSD& dict_info);
static void saveUserDictionaryMap(const LLSD& dict_map);
public:
typedef boost::signals2::signal<void()> settings_change_signal_t;
@ -76,7 +81,7 @@ protected:
protected:
Hunspell* mHunspell;
std::string mDictName;
std::string mDictLanguage;
std::string mDictFile;
dict_list_t mDictSecondary;
std::vector<std::string> mIgnoreList;

View File

@ -46,10 +46,24 @@ 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::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::refreshDictionaries, this, false));
getChild<LLUICtrl>("spellcheck_moveleft_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_active_list", "spellcheck_available_list"));
@ -121,6 +135,15 @@ void LLFloaterSpellCheckerSettings::onOpen(const LLSD& key)
refreshDictionaries(true);
}
void LLFloaterSpellCheckerSettings::onBtnRemove()
{
std::vector<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()
{
refreshDictionaries(true);
@ -137,7 +160,7 @@ void LLFloaterSpellCheckerSettings::refreshDictionaries(bool from_settings)
std::string dict_cur = dict_combo->getSelectedItemLabel();
if ((dict_cur.empty() || from_settings) && (LLSpellChecker::getUseSpellCheck()))
{
dict_cur = LLSpellChecker::instance().getActiveDictionary();
dict_cur = LLSpellChecker::instance().getPrimaryDictionary();
}
dict_combo->clearRows();
dict_combo->setEnabled(enabled);

View File

@ -34,6 +34,7 @@ class LLFloaterSpellCheckerSettings : public LLFloater
public:
LLFloaterSpellCheckerSettings(const LLSD& key);
/*virtual*/ void draw();
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
@ -42,6 +43,7 @@ protected:
void onBtnImport();
void onBtnMove(const std::string& from, const std::string& to);
void onBtnOK();
void onBtnRemove();
void onSpellCheckSettingsChange();
void refreshDictionaries(bool from_settings);
};

View File

@ -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"