forked from mia/Aegisub
Only enable the Remove Word button when the word can be removed. Updates #1184.
This commit is contained in:
parent
fe630e052b
commit
835f7c0f78
5 changed files with 63 additions and 88 deletions
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue