2011-09-15 07:16:41 +02:00
|
|
|
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
|
2007-04-14 03:02:21 +02:00
|
|
|
//
|
2011-09-15 07:16:41 +02:00
|
|
|
// Permission to use, copy, modify, and distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
|
|
// copyright notice and this permission notice appear in all copies.
|
2007-04-14 03:02:21 +02:00
|
|
|
//
|
2011-09-15 07:16:41 +02:00
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
2007-04-14 03:02:21 +02:00
|
|
|
//
|
2009-07-29 07:43:02 +02:00
|
|
|
// Aegisub Project http://www.aegisub.org/
|
|
|
|
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "ass_dialogue.h"
|
|
|
|
#include "ass_file.h"
|
2010-05-21 03:13:36 +02:00
|
|
|
#include "compat.h"
|
2014-05-22 21:07:15 +02:00
|
|
|
#include "dialog_manager.h"
|
2008-01-13 22:54:31 +01:00
|
|
|
#include "help_button.h"
|
2011-01-16 08:16:13 +01:00
|
|
|
#include "include/aegisub/context.h"
|
2010-08-02 08:31:38 +02:00
|
|
|
#include "include/aegisub/spellchecker.h"
|
2011-09-15 07:17:07 +02:00
|
|
|
#include "libresrc/libresrc.h"
|
2013-01-07 02:50:09 +01:00
|
|
|
#include "options.h"
|
2011-09-15 07:17:07 +02:00
|
|
|
#include "selection_controller.h"
|
2012-10-08 16:32:51 +02:00
|
|
|
#include "text_selection_controller.h"
|
2007-04-14 03:02:21 +02:00
|
|
|
|
2012-11-07 01:26:00 +01:00
|
|
|
#include <libaegisub/ass/dialogue_parser.h>
|
2012-05-18 16:01:56 +02:00
|
|
|
#include <libaegisub/exception.h>
|
2012-10-30 16:59:47 +01:00
|
|
|
#include <libaegisub/spellchecker.h>
|
2012-05-18 16:01:56 +02:00
|
|
|
|
2013-05-07 03:36:06 +02:00
|
|
|
#include <boost/locale/conversion.hpp>
|
2014-05-22 21:07:15 +02:00
|
|
|
#include <map>
|
|
|
|
#include <memory>
|
|
|
|
#include <set>
|
|
|
|
#include <wx/arrstr.h>
|
2012-12-13 03:07:53 +01:00
|
|
|
#include <wx/checkbox.h>
|
|
|
|
#include <wx/combobox.h>
|
2014-05-22 21:07:15 +02:00
|
|
|
#include <wx/dialog.h>
|
2012-12-13 03:07:53 +01:00
|
|
|
#include <wx/intl.h>
|
|
|
|
#include <wx/listbox.h>
|
|
|
|
#include <wx/msgdlg.h>
|
|
|
|
#include <wx/sizer.h>
|
|
|
|
#include <wx/stattext.h>
|
|
|
|
#include <wx/textctrl.h>
|
|
|
|
|
2014-05-22 21:07:15 +02:00
|
|
|
namespace {
|
|
|
|
class DialogSpellChecker final : public wxDialog {
|
|
|
|
agi::Context *context; ///< The project context
|
|
|
|
std::unique_ptr<agi::SpellChecker> spellchecker; ///< The spellchecking engine
|
|
|
|
|
|
|
|
/// Words which the user has indicated should always be corrected
|
|
|
|
std::map<std::string, std::string> auto_replace;
|
|
|
|
|
|
|
|
/// Words which the user has temporarily added to the dictionary
|
|
|
|
std::set<std::string> auto_ignore;
|
|
|
|
|
|
|
|
/// Dictionaries available
|
|
|
|
wxArrayString dictionary_lang_codes;
|
|
|
|
|
|
|
|
int word_start; ///< Start index of the current misspelled word
|
|
|
|
int word_len; ///< Length of the current misspelled word
|
|
|
|
|
|
|
|
wxTextCtrl *orig_word; ///< The word being corrected
|
|
|
|
wxTextCtrl *replace_word; ///< The replacement that will be used if "Replace" is clicked
|
|
|
|
wxListBox *suggest_list; ///< The list of suggested replacements
|
|
|
|
|
|
|
|
wxComboBox *language; ///< The list of available languages
|
|
|
|
wxButton *add_button; ///< Add word to currently active dictionary
|
|
|
|
wxButton *remove_button; ///< Remove word from currently active dictionary
|
|
|
|
|
|
|
|
AssDialogue *start_line = nullptr; ///< The first line checked
|
|
|
|
AssDialogue *active_line = nullptr; ///< The most recently checked line
|
|
|
|
bool has_looped = false; ///< Has the search already looped from the end to beginning?
|
|
|
|
|
|
|
|
/// Find the next misspelled word and close the dialog if there are none
|
|
|
|
/// @return Are there any more misspelled words?
|
|
|
|
bool FindNext();
|
|
|
|
|
|
|
|
/// Check a single line for misspellings
|
|
|
|
/// @param active_line Line to check
|
|
|
|
/// @param start_pos Index in the line to start at
|
|
|
|
/// @param[in,out] commit_id Commit id for coalescing autoreplace commits
|
|
|
|
/// @return Was a misspelling found?
|
|
|
|
bool CheckLine(AssDialogue *active_line, int start_pos, int *commit_id);
|
|
|
|
|
|
|
|
/// Set the current word to be corrected
|
|
|
|
void SetWord(std::string const& word);
|
|
|
|
/// Correct the currently selected word
|
|
|
|
void Replace();
|
|
|
|
|
|
|
|
void OnChangeLanguage(wxCommandEvent&);
|
|
|
|
void OnChangeSuggestion(wxCommandEvent&);
|
|
|
|
|
|
|
|
void OnReplace(wxCommandEvent&);
|
|
|
|
|
|
|
|
public:
|
|
|
|
DialogSpellChecker(agi::Context *context);
|
|
|
|
};
|
|
|
|
|
2011-01-16 08:16:13 +01:00
|
|
|
DialogSpellChecker::DialogSpellChecker(agi::Context *context)
|
2011-09-15 07:16:41 +02:00
|
|
|
: wxDialog(context->parent, -1, _("Spell Checker"))
|
2011-01-16 08:16:13 +01:00
|
|
|
, context(context)
|
2011-09-15 07:16:41 +02:00
|
|
|
, spellchecker(SpellCheckerFactory::GetSpellChecker())
|
2007-04-14 03:02:21 +02:00
|
|
|
{
|
2012-04-03 22:40:24 +02:00
|
|
|
SetIcon(GETICON(spellcheck_toolbutton_16));
|
2007-07-05 01:09:40 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
wxSizer *main_sizer = new wxBoxSizer(wxVERTICAL);
|
2007-04-14 18:08:50 +02:00
|
|
|
|
2013-11-21 18:13:36 +01:00
|
|
|
auto current_word_sizer = new wxFlexGridSizer(2, 5, 5);
|
2011-09-15 07:16:41 +02:00
|
|
|
main_sizer->Add(current_word_sizer, wxSizerFlags().Expand().Border(wxALL, 5));
|
2007-04-14 18:08:50 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
wxSizer *bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
|
|
main_sizer->Add(bottom_sizer, wxSizerFlags().Expand().Border(~wxTOP & wxALL, 5));
|
2007-04-14 03:02:21 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
wxSizer *bottom_left_sizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
bottom_sizer->Add(bottom_left_sizer, wxSizerFlags().Expand().Border(wxRIGHT, 5));
|
2007-04-14 17:26:46 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
wxSizer *actions_sizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
bottom_sizer->Add(actions_sizer, wxSizerFlags().Expand());
|
2007-04-14 17:26:46 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
// Misspelled word and currently selected correction
|
|
|
|
current_word_sizer->AddGrowableCol(1, 1);
|
|
|
|
current_word_sizer->Add(new wxStaticText(this, -1, _("Misspelled word:")), 0, wxALIGN_CENTER_VERTICAL);
|
2012-01-08 02:05:25 +01:00
|
|
|
current_word_sizer->Add(orig_word = new wxTextCtrl(this, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_READONLY), wxSizerFlags(1).Expand());
|
2011-09-15 07:16:41 +02:00
|
|
|
current_word_sizer->Add(new wxStaticText(this, -1, _("Replace with:")), 0, wxALIGN_CENTER_VERTICAL);
|
2012-01-08 02:05:25 +01:00
|
|
|
current_word_sizer->Add(replace_word = new wxTextCtrl(this, -1, ""), wxSizerFlags(1).Expand());
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
|
2013-12-12 03:25:13 +01:00
|
|
|
replace_word->Bind(wxEVT_TEXT, [=](wxCommandEvent&) {
|
2012-12-22 00:59:25 +01:00
|
|
|
remove_button->Enable(spellchecker->CanRemoveWord(from_wx(replace_word->GetValue())));
|
|
|
|
});
|
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
// List of suggested corrections
|
|
|
|
suggest_list = new wxListBox(this, -1, wxDefaultPosition, wxSize(300, 150));
|
2013-12-12 03:25:13 +01:00
|
|
|
suggest_list->Bind(wxEVT_LISTBOX, &DialogSpellChecker::OnChangeSuggestion, this);
|
|
|
|
suggest_list->Bind(wxEVT_LISTBOX_DCLICK, &DialogSpellChecker::OnReplace, this);
|
2011-09-15 07:16:41 +02:00
|
|
|
bottom_left_sizer->Add(suggest_list, wxSizerFlags(1).Expand());
|
2007-04-14 03:02:21 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
// List of supported spellchecker languages
|
|
|
|
{
|
2014-11-04 17:27:36 +01:00
|
|
|
if (!spellchecker) {
|
2012-03-29 01:59:19 +02:00
|
|
|
wxMessageBox("No spellchecker available.", "Error", wxOK | wxICON_ERROR | wxCENTER);
|
2012-05-18 16:01:56 +02:00
|
|
|
throw agi::UserCancelException("No spellchecker available");
|
2011-09-15 07:16:41 +02:00
|
|
|
}
|
2007-04-14 03:02:21 +02:00
|
|
|
|
2012-10-30 16:59:47 +01:00
|
|
|
dictionary_lang_codes = to_wx(spellchecker->GetLanguageList());
|
2011-09-15 07:16:41 +02:00
|
|
|
if (dictionary_lang_codes.empty()) {
|
2012-03-29 01:59:19 +02:00
|
|
|
wxMessageBox("No spellchecker dictionaries available.", "Error", wxOK | wxICON_ERROR | wxCENTER);
|
2012-05-18 16:01:56 +02:00
|
|
|
throw agi::UserCancelException("No spellchecker dictionaries available");
|
2011-09-15 07:16:41 +02:00
|
|
|
}
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
wxArrayString language_names(dictionary_lang_codes);
|
|
|
|
for (size_t i = 0; i < dictionary_lang_codes.size(); ++i) {
|
|
|
|
if (const wxLanguageInfo *info = wxLocale::FindLanguageInfo(dictionary_lang_codes[i]))
|
|
|
|
language_names[i] = info->Description;
|
2007-04-14 17:26:46 +02:00
|
|
|
}
|
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
language = new wxComboBox(this, -1, "", wxDefaultPosition, wxDefaultSize, language_names, wxCB_DROPDOWN | wxCB_READONLY);
|
2012-12-23 00:18:38 +01:00
|
|
|
wxString cur_lang = to_wx(OPT_GET("Tool/Spell Checker/Language")->GetString());
|
2011-09-15 07:16:41 +02:00
|
|
|
int cur_lang_index = dictionary_lang_codes.Index(cur_lang);
|
|
|
|
if (cur_lang_index == wxNOT_FOUND) cur_lang_index = dictionary_lang_codes.Index("en");
|
|
|
|
if (cur_lang_index == wxNOT_FOUND) cur_lang_index = dictionary_lang_codes.Index("en_US");
|
|
|
|
if (cur_lang_index == wxNOT_FOUND) cur_lang_index = 0;
|
|
|
|
language->SetSelection(cur_lang_index);
|
2013-12-12 03:25:13 +01:00
|
|
|
language->Bind(wxEVT_COMBOBOX, &DialogSpellChecker::OnChangeLanguage, this);
|
2011-09-15 07:16:41 +02:00
|
|
|
|
|
|
|
bottom_left_sizer->Add(language, wxSizerFlags().Expand().Border(wxTOP, 5));
|
2007-04-14 17:26:46 +02:00
|
|
|
}
|
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
{
|
2016-03-12 23:38:39 +01:00
|
|
|
wxSizerFlags button_flags = wxSizerFlags().Expand().Border(wxBOTTOM, 5);
|
2007-04-14 17:26:46 +02:00
|
|
|
|
2013-05-07 03:36:06 +02:00
|
|
|
auto make_checkbox = [&](wxString const& text, const char *opt) {
|
|
|
|
auto checkbox = new wxCheckBox(this, -1, text);
|
|
|
|
actions_sizer->Add(checkbox, button_flags);
|
|
|
|
checkbox->SetValue(OPT_GET(opt)->GetBool());
|
2013-12-12 03:25:13 +01:00
|
|
|
checkbox->Bind(wxEVT_CHECKBOX,
|
2013-05-07 03:36:06 +02:00
|
|
|
[=](wxCommandEvent &evt) { OPT_SET(opt)->SetBool(!!evt.GetInt()); });
|
|
|
|
};
|
|
|
|
|
|
|
|
make_checkbox(_("&Skip Comments"), "Tool/Spell Checker/Skip Comments");
|
|
|
|
make_checkbox(_("Ignore &UPPERCASE words"), "Tool/Spell Checker/Skip Uppercase");
|
2012-01-26 21:51:08 +01:00
|
|
|
|
|
|
|
wxButton *button;
|
|
|
|
|
2011-11-18 19:49:09 +01:00
|
|
|
actions_sizer->Add(button = new wxButton(this, -1, _("&Replace")), button_flags);
|
2013-12-12 03:25:13 +01:00
|
|
|
button->Bind(wxEVT_BUTTON, &DialogSpellChecker::OnReplace, this);
|
2007-04-14 17:26:46 +02:00
|
|
|
|
2011-11-18 19:49:09 +01:00
|
|
|
actions_sizer->Add(button = new wxButton(this, -1, _("Replace &all")), button_flags);
|
2013-12-12 03:25:13 +01:00
|
|
|
button->Bind(wxEVT_BUTTON, [=](wxCommandEvent&) {
|
2012-12-22 00:59:25 +01:00
|
|
|
auto_replace[from_wx(orig_word->GetValue())] = from_wx(replace_word->GetValue());
|
|
|
|
Replace();
|
|
|
|
FindNext();
|
|
|
|
});
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
|
2011-11-18 19:49:09 +01:00
|
|
|
actions_sizer->Add(button = new wxButton(this, -1, _("&Ignore")), button_flags);
|
2013-12-12 03:25:13 +01:00
|
|
|
button->Bind(wxEVT_BUTTON, [=](wxCommandEvent&) { FindNext(); });
|
2007-04-14 03:02:21 +02:00
|
|
|
|
2011-11-18 19:49:09 +01:00
|
|
|
actions_sizer->Add(button = new wxButton(this, -1, _("Ignore a&ll")), button_flags);
|
2013-12-12 03:25:13 +01:00
|
|
|
button->Bind(wxEVT_BUTTON, [=](wxCommandEvent&) {
|
2012-12-22 00:59:25 +01:00
|
|
|
auto_ignore.insert(from_wx(orig_word->GetValue()));
|
|
|
|
FindNext();
|
|
|
|
});
|
2007-04-14 03:02:21 +02:00
|
|
|
|
2011-11-18 19:49:09 +01:00
|
|
|
actions_sizer->Add(add_button = new wxButton(this, -1, _("Add to &dictionary")), button_flags);
|
2013-12-12 03:25:13 +01:00
|
|
|
add_button->Bind(wxEVT_BUTTON, [=](wxCommandEvent&) {
|
2012-12-22 00:59:25 +01:00
|
|
|
spellchecker->AddWord(from_wx(orig_word->GetValue()));
|
|
|
|
FindNext();
|
|
|
|
});
|
2007-04-14 18:08:50 +02:00
|
|
|
|
2012-12-18 17:54:53 +01:00
|
|
|
actions_sizer->Add(remove_button = new wxButton(this, -1, _("Remove fro&m dictionary")), button_flags);
|
2013-12-12 03:25:13 +01:00
|
|
|
remove_button->Bind(wxEVT_BUTTON, [=](wxCommandEvent&) {
|
2012-12-22 00:59:25 +01:00
|
|
|
spellchecker->RemoveWord(from_wx(replace_word->GetValue()));
|
|
|
|
SetWord(from_wx(orig_word->GetValue()));
|
|
|
|
});
|
2012-12-18 17:54:53 +01:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
actions_sizer->Add(new HelpButton(this, "Spell Checker"), button_flags);
|
2007-04-14 03:02:21 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
actions_sizer->Add(new wxButton(this, wxID_CANCEL), button_flags.Border(0));
|
|
|
|
}
|
2007-04-14 03:02:21 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
SetSizerAndFit(main_sizer);
|
|
|
|
CenterOnParent();
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
if (FindNext())
|
|
|
|
Show();
|
|
|
|
}
|
2007-04-14 03:02:21 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
void DialogSpellChecker::OnReplace(wxCommandEvent&) {
|
2007-04-14 17:26:46 +02:00
|
|
|
Replace();
|
2011-09-15 07:16:41 +02:00
|
|
|
FindNext();
|
2007-04-14 03:02:21 +02:00
|
|
|
}
|
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
void DialogSpellChecker::OnChangeLanguage(wxCommandEvent&) {
|
|
|
|
wxString code = dictionary_lang_codes[language->GetSelection()];
|
2012-12-23 00:18:38 +01:00
|
|
|
OPT_SET("Tool/Spell Checker/Language")->SetString(from_wx(code));
|
2007-04-14 17:26:46 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
FindNext();
|
2007-04-14 17:26:46 +02:00
|
|
|
}
|
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
void DialogSpellChecker::OnChangeSuggestion(wxCommandEvent&) {
|
|
|
|
replace_word->SetValue(suggest_list->GetStringSelection());
|
|
|
|
}
|
2007-04-14 17:26:46 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
bool DialogSpellChecker::FindNext() {
|
2012-02-01 01:47:57 +01:00
|
|
|
AssDialogue *real_active_line = context->selectionController->GetActiveLine();
|
|
|
|
// User has changed the active line; restart search from this position
|
|
|
|
if (real_active_line != active_line) {
|
|
|
|
active_line = real_active_line;
|
|
|
|
has_looped = false;
|
|
|
|
start_line = active_line;
|
|
|
|
}
|
|
|
|
|
2012-10-08 16:32:51 +02:00
|
|
|
int start_pos = context->textSelectionController->GetInsertionPoint();
|
2011-09-15 07:16:41 +02:00
|
|
|
int commit_id = -1;
|
|
|
|
|
|
|
|
if (CheckLine(active_line, start_pos, &commit_id))
|
|
|
|
return true;
|
|
|
|
|
2014-04-04 17:11:09 +02:00
|
|
|
auto it = context->ass->iterator_to(*active_line);
|
2011-09-15 07:16:41 +02:00
|
|
|
|
|
|
|
// Note that it is deliberate that the start line is checked twice, as if
|
|
|
|
// the cursor is past the first misspelled word in the current line, that
|
|
|
|
// word should be hit last
|
|
|
|
while(!has_looped || active_line != start_line) {
|
2014-03-07 19:58:51 +01:00
|
|
|
// Wrap around to the beginning if we hit the end
|
|
|
|
if (++it == context->ass->Events.end()) {
|
|
|
|
it = context->ass->Events.begin();
|
|
|
|
has_looped = true;
|
|
|
|
}
|
2007-04-14 18:08:50 +02:00
|
|
|
|
2014-03-31 05:09:04 +02:00
|
|
|
active_line = &*it;
|
2011-09-15 07:16:41 +02:00
|
|
|
if (CheckLine(active_line, 0, &commit_id))
|
|
|
|
return true;
|
|
|
|
}
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
if (IsShown()) {
|
|
|
|
wxMessageBox(_("Aegisub has finished checking spelling of this script."), _("Spell checking complete."));
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
wxMessageBox(_("Aegisub has found no spelling mistakes in this script."), _("Spell checking complete."));
|
2012-05-18 16:01:56 +02:00
|
|
|
throw agi::UserCancelException("No spelling mistakes");
|
2011-09-15 07:16:41 +02:00
|
|
|
}
|
2007-04-14 18:08:50 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
return false;
|
2007-04-14 18:08:50 +02:00
|
|
|
}
|
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
bool DialogSpellChecker::CheckLine(AssDialogue *active_line, int start_pos, int *commit_id) {
|
2013-05-07 03:36:06 +02:00
|
|
|
if (active_line->Comment && OPT_GET("Tool/Spell Checker/Skip Comments")->GetBool()) return false;
|
2012-01-26 21:51:08 +01:00
|
|
|
|
2013-01-04 16:01:50 +01:00
|
|
|
std::string text = active_line->Text;
|
2012-11-07 01:26:00 +01:00
|
|
|
auto tokens = agi::ass::TokenizeDialogueBody(text);
|
|
|
|
agi::ass::SplitWords(text, tokens);
|
2011-09-15 07:16:41 +02:00
|
|
|
|
2013-05-07 03:36:06 +02:00
|
|
|
bool ignore_uppercase = OPT_GET("Tool/Spell Checker/Skip Uppercase")->GetBool();
|
|
|
|
|
2012-11-07 01:26:00 +01:00
|
|
|
word_start = 0;
|
|
|
|
for (auto const& tok : tokens) {
|
2012-12-13 03:07:53 +01:00
|
|
|
if (tok.type != agi::ass::DialogueTokenType::WORD || word_start < start_pos) {
|
|
|
|
word_start += tok.length;
|
|
|
|
continue;
|
|
|
|
}
|
2011-09-15 07:16:41 +02:00
|
|
|
|
2012-11-07 01:26:00 +01:00
|
|
|
word_len = tok.length;
|
|
|
|
std::string word = text.substr(word_start, word_len);
|
2011-09-15 07:16:41 +02:00
|
|
|
|
2013-05-07 03:36:06 +02:00
|
|
|
if (auto_ignore.count(word) || spellchecker->CheckWord(word) || (ignore_uppercase && word == boost::locale::to_upper(word))) {
|
2012-12-13 03:07:53 +01:00
|
|
|
word_start += tok.length;
|
|
|
|
continue;
|
|
|
|
}
|
2012-11-07 01:26:00 +01:00
|
|
|
|
|
|
|
auto auto_rep = auto_replace.find(word);
|
2011-09-15 07:16:41 +02:00
|
|
|
if (auto_rep == auto_replace.end()) {
|
2012-05-26 18:54:55 +02:00
|
|
|
#ifdef __WXGTK__
|
2012-06-13 17:58:24 +02:00
|
|
|
// http://trac.wxwidgets.org/ticket/14369
|
|
|
|
orig_word->Remove(0, -1);
|
|
|
|
replace_word->Remove(0, -1);
|
2012-05-26 18:54:55 +02:00
|
|
|
#endif
|
|
|
|
|
2013-12-12 00:11:06 +01:00
|
|
|
context->selectionController->SetSelectionAndActive({ active_line }, active_line);
|
2011-09-15 07:16:41 +02:00
|
|
|
SetWord(word);
|
|
|
|
return true;
|
|
|
|
}
|
2007-04-14 18:08:50 +02:00
|
|
|
|
2012-11-07 01:26:00 +01:00
|
|
|
text.replace(word_start, word_len, auto_rep->second);
|
2013-01-04 16:01:50 +01:00
|
|
|
active_line->Text = text;
|
2011-09-15 07:16:41 +02:00
|
|
|
*commit_id = context->ass->Commit(_("spell check replace"), AssFile::COMMIT_DIAG_TEXT, *commit_id);
|
2012-12-13 03:07:53 +01:00
|
|
|
word_start += auto_rep->second.size();
|
2011-09-15 07:16:41 +02:00
|
|
|
}
|
|
|
|
return false;
|
2007-04-14 18:08:50 +02:00
|
|
|
}
|
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
void DialogSpellChecker::Replace() {
|
|
|
|
AssDialogue *active_line = context->selectionController->GetActiveLine();
|
2007-04-14 18:08:50 +02:00
|
|
|
|
2011-09-15 07:16:41 +02:00
|
|
|
// Only replace if the user hasn't changed the selection to something else
|
2013-01-04 16:01:50 +01:00
|
|
|
if (to_wx(active_line->Text.get().substr(word_start, word_len)) == orig_word->GetValue()) {
|
|
|
|
std::string text = active_line->Text;
|
|
|
|
text.replace(word_start, word_len, from_wx(replace_word->GetValue()));
|
2012-12-04 23:35:59 +01:00
|
|
|
active_line->Text = text;
|
2011-09-15 07:16:41 +02:00
|
|
|
context->ass->Commit(_("spell check replace"), AssFile::COMMIT_DIAG_TEXT);
|
2012-10-08 16:32:51 +02:00
|
|
|
context->textSelectionController->SetInsertionPoint(word_start + replace_word->GetValue().size());
|
2011-09-15 07:16:41 +02:00
|
|
|
}
|
2007-04-14 18:08:50 +02:00
|
|
|
}
|
|
|
|
|
2012-11-07 01:26:00 +01:00
|
|
|
void DialogSpellChecker::SetWord(std::string const& word) {
|
|
|
|
orig_word->SetValue(to_wx(word));
|
2007-04-14 18:08:50 +02:00
|
|
|
|
2012-11-07 01:26:00 +01:00
|
|
|
wxArrayString suggestions = to_wx(spellchecker->GetSuggestions(word));
|
|
|
|
replace_word->SetValue(suggestions.size() ? suggestions[0] : to_wx(word));
|
2011-09-15 07:16:41 +02:00
|
|
|
suggest_list->Clear();
|
|
|
|
suggest_list->Append(suggestions);
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
|
2012-11-07 01:26:00 +01:00
|
|
|
context->textSelectionController->SetSelection(word_start, word_start + word_len);
|
|
|
|
context->textSelectionController->SetInsertionPoint(word_start + word_len);
|
2007-04-14 18:08:50 +02:00
|
|
|
|
2012-11-07 01:26:00 +01:00
|
|
|
add_button->Enable(spellchecker->CanAddWord(word));
|
2007-04-14 18:08:50 +02:00
|
|
|
}
|
2014-05-22 21:07:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShowSpellcheckerDialog(agi::Context *c) {
|
|
|
|
c->dialog->Show<DialogSpellChecker>(c);
|
|
|
|
}
|