Only enable the Remove Word button when the word can be removed. Updates #1184.

This commit is contained in:
Thomas Goyne 2012-12-21 15:59:25 -08:00
parent fe630e052b
commit 835f7c0f78
5 changed files with 63 additions and 88 deletions

View File

@ -37,6 +37,11 @@ public:
/// @return Whether or not word can be added
virtual bool CanAddWord(std::string const& word)=0;
/// Can the word be removed from the current dictionary?
/// @param word Word to check
/// @return Whether or not word can be removed
virtual bool CanRemoveWord(std::string const& word)=0;
/// Check if the given word is spelled correctly
/// @param word Word to check
/// @return Whether or not the word is valid

View File

@ -80,6 +80,10 @@ DialogSpellChecker::DialogSpellChecker(agi::Context *context)
current_word_sizer->Add(new wxStaticText(this, -1, _("Replace with:")), 0, wxALIGN_CENTER_VERTICAL);
current_word_sizer->Add(replace_word = new wxTextCtrl(this, -1, ""), wxSizerFlags(1).Expand());
replace_word->Bind(wxEVT_COMMAND_TEXT_UPDATED, [=](wxCommandEvent&) {
remove_button->Enable(spellchecker->CanRemoveWord(from_wx(replace_word->GetValue())));
});
// List of suggested corrections
suggest_list = new wxListBox(this, -1, wxDefaultPosition, wxSize(300, 150));
suggest_list->Bind(wxEVT_COMMAND_LISTBOX_SELECTED, &DialogSpellChecker::OnChangeSuggestion, this);
@ -132,19 +136,32 @@ DialogSpellChecker::DialogSpellChecker(agi::Context *context)
button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogSpellChecker::OnReplace, this);
actions_sizer->Add(button = new wxButton(this, -1, _("Replace &all")), button_flags);
button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogSpellChecker::OnReplaceAll, this);
button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [=](wxCommandEvent&) {
auto_replace[from_wx(orig_word->GetValue())] = from_wx(replace_word->GetValue());
Replace();
FindNext();
});
actions_sizer->Add(button = new wxButton(this, -1, _("&Ignore")), button_flags);
button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [=](wxCommandEvent&) { FindNext(); });
actions_sizer->Add(button = new wxButton(this, -1, _("Ignore a&ll")), button_flags);
button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogSpellChecker::OnIgnoreAll, this);
button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [=](wxCommandEvent&) {
auto_ignore.insert(from_wx(orig_word->GetValue()));
FindNext();
});
actions_sizer->Add(add_button = new wxButton(this, -1, _("Add to &dictionary")), button_flags);
add_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogSpellChecker::OnAdd, this);
add_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [=](wxCommandEvent&) {
spellchecker->AddWord(from_wx(orig_word->GetValue()));
FindNext();
});
actions_sizer->Add(remove_button = new wxButton(this, -1, _("Remove fro&m dictionary")), button_flags);
remove_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &DialogSpellChecker::OnRemove, this);
remove_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, [=](wxCommandEvent&) {
spellchecker->RemoveWord(from_wx(replace_word->GetValue()));
SetWord(from_wx(orig_word->GetValue()));
});
actions_sizer->Add(new HelpButton(this, "Spell Checker"), button_flags);
@ -166,30 +183,6 @@ void DialogSpellChecker::OnReplace(wxCommandEvent&) {
FindNext();
}
void DialogSpellChecker::OnReplaceAll(wxCommandEvent&) {
auto_replace[from_wx(orig_word->GetValue())] = from_wx(replace_word->GetValue());
Replace();
FindNext();
}
void DialogSpellChecker::OnIgnoreAll(wxCommandEvent&) {
auto_ignore.insert(from_wx(orig_word->GetValue()));
FindNext();
}
void DialogSpellChecker::OnAdd(wxCommandEvent&) {
spellchecker->AddWord(from_wx(orig_word->GetValue()));
FindNext();
}
void DialogSpellChecker::OnRemove(wxCommandEvent&) {
// TODO pop-up dialog
spellchecker->RemoveWord(from_wx(replace_word->GetValue()));
FindNext();
}
void DialogSpellChecker::OnChangeLanguage(wxCommandEvent&) {
wxString code = dictionary_lang_codes[language->GetSelection()];
OPT_SET("Tool/Spell Checker/Language")->SetString(STD_STR(code));

View File

@ -85,10 +85,6 @@ class DialogSpellChecker : public wxDialog {
void OnChangeSuggestion(wxCommandEvent&);
void OnReplace(wxCommandEvent&);
void OnReplaceAll(wxCommandEvent&);
void OnIgnoreAll(wxCommandEvent&);
void OnAdd(wxCommandEvent&);
void OnRemove(wxCommandEvent&);
public:
DialogSpellChecker(agi::Context *context);

View File

@ -63,25 +63,19 @@ bool HunspellSpellChecker::CanAddWord(std::string const& word) {
}
}
bool HunspellSpellChecker::CanRemoveWord(std::string const& word) {
return !!customWords.count(word);
}
void HunspellSpellChecker::AddWord(std::string const& word) {
if (!hunspell) return;
// Add it to the in-memory dictionary
hunspell->add(conv->Convert(word).c_str());
std::set<std::string> words;
try {
ReadUserDictionary(words);
}
catch (agi::FileNotFoundError&) {
LOG_I("dictionary/hunspell/add") << "User dictionary not found; creating it";
}
// Add the word
words.insert(word);
WriteUserDictionary(words);
if (customWords.insert(word).second)
WriteUserDictionary();
}
void HunspellSpellChecker::RemoveWord(std::string const& word) {
@ -90,26 +84,17 @@ void HunspellSpellChecker::RemoveWord(std::string const& word) {
// Remove it from the in-memory dictionary
hunspell->remove(conv->Convert(word).c_str());
std::set<std::string> words;
auto word_iter = customWords.find(word);
if (word_iter != customWords.end()) {
customWords.erase(word_iter);
try {
ReadUserDictionary(words);
}
catch (agi::FileNotFoundError&) {
LOG_I("dictionary/hunspell/remove") << "User dictionary not found; nothing to remove";
return;
}
auto word_iter = words.find(word);
if (word_iter != words.end()) {
words.erase(word_iter);
WriteUserDictionary(words);
WriteUserDictionary();
}
}
void HunspellSpellChecker::ReadUserDictionary(std::set<std::string> &words)
{
void HunspellSpellChecker::ReadUserDictionary() {
customWords.clear();
// Ensure that the path exists
wxFileName fn(userDicPath);
if (!fn.DirExists()) {
@ -118,21 +103,19 @@ void HunspellSpellChecker::ReadUserDictionary(std::set<std::string> &words)
// Read the old contents of the user's dictionary
else {
agi::scoped_ptr<std::istream> stream(agi::io::Open(STD_STR(userDicPath)));
remove_copy_if(
++agi::line_iterator<std::string>(*stream),
agi::line_iterator<std::string>(),
inserter(words, words.end()),
[](std::string const& str) { return str.empty(); });
copy_if(
++agi::line_iterator<std::string>(*stream), agi::line_iterator<std::string>(),
inserter(customWords, customWords.end()),
[](std::string const& str) { return !str.empty(); });
}
}
void HunspellSpellChecker::WriteUserDictionary(std::set<std::string> const& words)
{
void HunspellSpellChecker::WriteUserDictionary() {
// Write the new dictionary
{
agi::io::Save writer(STD_STR(userDicPath));
writer.Get() << words.size() << "\n";
copy(words.begin(), words.end(), std::ostream_iterator<std::string>(writer.Get(), "\n"));
writer.Get() << customWords.size() << "\n";
copy(customWords.begin(), customWords.end(), std::ostream_iterator<std::string>(writer.Get(), "\n"));
}
// Announce a language change so that any other spellcheckers reload the
@ -252,24 +235,16 @@ void HunspellSpellChecker::OnLanguageChanged() {
conv.reset(new agi::charset::IconvWrapper("utf-8", hunspell->get_dic_encoding()));
rconv.reset(new agi::charset::IconvWrapper(hunspell->get_dic_encoding(), "utf-8"));
try {
agi::scoped_ptr<std::istream> stream(agi::io::Open(STD_STR(userDicPath)));
agi::line_iterator<std::string> userDic(*stream);
agi::line_iterator<std::string> end;
++userDic; // skip entry count line
for (; userDic != end; ++userDic) {
if (userDic->empty()) continue;
try {
hunspell->add(conv->Convert(*userDic).c_str());
}
catch (agi::charset::ConvError const&) {
// Normally this shouldn't happen, but some versions of Aegisub
// wrote words in the wrong charset
}
ReadUserDictionary();
for (auto const& word : customWords) {
try {
hunspell->add(conv->Convert(word).c_str());
}
catch (agi::charset::ConvError const&) {
// Normally this shouldn't happen, but some versions of Aegisub
// wrote words in the wrong charset
}
}
catch (agi::Exception const&) {
// File doesn't exist or we don't have permission to read it
}
}

View File

@ -26,6 +26,8 @@
#include <libaegisub/scoped_ptr.h>
#include <libaegisub/signal.h>
#include <set>
#include <wx/string.h>
namespace agi { namespace charset { class IconvWrapper; } }
@ -46,6 +48,9 @@ class HunspellSpellChecker : public agi::SpellChecker {
/// Path to user-local dictionary.
wxString userDicPath;
/// Words in the custom user dictionary
std::set<std::string> customWords;
/// Dictionary language change connection
agi::signal::Connection lang_listener;
/// Dictionary language change handler
@ -57,9 +62,9 @@ class HunspellSpellChecker : public agi::SpellChecker {
void OnPathChanged();
/// Load words from custom dictionary
void ReadUserDictionary(std::set<std::string> &words);
void ReadUserDictionary();
/// Save words to custom dictionary
void WriteUserDictionary(std::set<std::string> const& words);
void WriteUserDictionary();
public:
HunspellSpellChecker();
@ -68,6 +73,7 @@ public:
void AddWord(std::string const& word);
void RemoveWord(std::string const& word);
bool CanAddWord(std::string const& word);
bool CanRemoveWord(std::string const& word);
bool CheckWord(std::string const& word);
std::vector<std::string> GetSuggestions(std::string const& word);
std::vector<std::string> GetLanguageList();