From bd03fbc3ce9a3294254f11f09a06add0e255e535 Mon Sep 17 00:00:00 2001 From: Rodrigo Braz Monteiro Date: Sat, 14 Apr 2007 15:26:46 +0000 Subject: [PATCH] Spell checker dialog is complete. Originally committed to SVN as r1076. --- aegisub/ass_dialogue.h | 5 +- aegisub/dialog_spellchecker.cpp | 160 ++++++++++++++++++++++++++++- aegisub/dialog_spellchecker.h | 12 ++- aegisub/frame_main_events.cpp | 2 +- aegisub/subs_edit_ctrl.cpp | 173 ++++++-------------------------- aegisub/subs_edit_ctrl.h | 1 - aegisub/utils.cpp | 71 +++++++++++++ aegisub/utils.h | 12 +++ 8 files changed, 283 insertions(+), 153 deletions(-) diff --git a/aegisub/ass_dialogue.h b/aegisub/ass_dialogue.h index cfba97696..3a28c505f 100644 --- a/aegisub/ass_dialogue.h +++ b/aegisub/ass_dialogue.h @@ -181,11 +181,12 @@ public: bool Parse(wxString data,int version=1); // Parses raw ASS data into everything else void ParseASSTags(); // Parses text to generate block information (doesn't update data) void ParseSRTTags(); // Converts tags to ass format and calls ParseASSTags+UpdateData + void ClearBlocks(); // Clear all blocks, ALWAYS call this after you're done processing tags + + void ProcessParameters(void (*callback)(wxString,int,AssOverrideParameter*,void *userData),void *userData=NULL); // Callback to process parameters void ConvertTagsToSRT(); // Converts tags to SRT format void StripTags(); // Strips all tags from the text void StripTag(wxString tagName);// Strips a specific tag from the text - void ClearBlocks(); // Clear all blocks, ALWAYS call this after you're done processing tags - void ProcessParameters(void (*callback)(wxString,int,AssOverrideParameter*,void *userData),void *userData=NULL); // Callback to process parameters wxString GetStrippedText(); // Gets text without tags void UpdateData(); // Updates raw data from current values + text diff --git a/aegisub/dialog_spellchecker.cpp b/aegisub/dialog_spellchecker.cpp index 5041b7e38..fe43469d4 100644 --- a/aegisub/dialog_spellchecker.cpp +++ b/aegisub/dialog_spellchecker.cpp @@ -39,6 +39,12 @@ // Headers #include "dialog_spellchecker.h" #include "spellchecker.h" +#include "subs_grid.h" +#include "frame_main.h" +#include "ass_file.h" +#include "ass_dialogue.h" +#include "utils.h" +#include "subs_edit_box.h" /////// @@ -58,7 +64,7 @@ DialogSpellChecker::DialogSpellChecker(wxFrame *parent) : wxDialog(parent, -1, _T("Spell Checker"), wxDefaultPosition, wxDefaultSize) { // Top sizer - origWord = new wxTextCtrl(this,-1,_T("original")); + origWord = new wxTextCtrl(this,-1,_T("original"),wxDefaultPosition,wxDefaultSize,wxTE_READONLY); replaceWord = new wxTextCtrl(this,-1,_T("replace with")); wxFlexGridSizer *topSizer = new wxFlexGridSizer(2,2,5,5); topSizer->Add(new wxStaticText(this,-1,_("Misspelled word:")),0,wxALIGN_CENTER_VERTICAL); @@ -103,14 +109,116 @@ DialogSpellChecker::DialogSpellChecker(wxFrame *parent) } // Go to first match - FindNext(0,0); + SubtitlesGrid *grid = ((FrameMain*)GetParent())->SubsBox; + wxArrayInt sel = grid->GetSelection(); + firstLine = (sel.Count()>0) ? sel[0] : 0; + bool hasTypos = FindNext(firstLine,0); + + // File is already OK + if (!hasTypos) { + wxMessageBox(_("Aegisub has found no spelling mistakes in this script."),_("Spell checking complete.")); + Destroy(); + return; + } + + // Show + ShowModal(); +} + + +////////////// +// Destructor +DialogSpellChecker::~DialogSpellChecker() { + if (spellchecker) delete spellchecker; } /////////////////// // Find next match -void DialogSpellChecker::FindNext(int startLine,int startPos) { +bool DialogSpellChecker::FindNext(int startLine,int startPos) { + // Set start + if (startLine != -1) lastLine = startLine; + if (startPos != -1) lastPos = 0; + // Get grid + SubtitlesGrid *grid = ((FrameMain*)GetParent())->SubsBox; + int rows = grid->GetRows(); + + // Loop through lines + for (int i=lastLine;iGetDialogue(curLine); + + // Find list of words in it + IntPairVector results; + GetWordBoundaries(diag->Text,results); + + // Look for spelling mistakes + for (size_t j=0;jText.Mid(s,e-s); + + // Check if it's on auto ignore + if (autoIgnore.Index(word) != wxNOT_FOUND) continue; + + // Mistake + if (!spellchecker->CheckWord(word)) { + // Set word + wordStart = s; + wordEnd = e; + lastLine = i; + lastPos = e; + + // Auto replace? + if (autoReplace.find(word) != autoReplace.end()) { + // lol mad h4x + replaceWord->SetValue(autoReplace[word]); + Replace(); + goto startFindNextOuterLoop; + } + + // Proceed normally + SetWord(word); + return true; + } + } + + // Go to next + lastPos = 0; + } + + // None found + return false; +} + + +//////////// +// Set word +void DialogSpellChecker::SetWord(wxString word) { + // Get list of suggestions + wxArrayString sugs = spellchecker->GetSuggestions(word); + + // Set fields + origWord->SetValue(word); + replaceWord->SetValue((sugs.Count()>0)? sugs[0] : word); + + // Set suggestions list + suggestList->Clear(); + for (size_t i=0;iAppend(sugs[i]); + + // Show word on the main program interface + SubtitlesGrid *grid = ((FrameMain*)GetParent())->SubsBox; + int line = lastLine % grid->GetRows(); + grid->SelectRow(line,false); + grid->MakeCellVisible(line,0); + grid->editBox->SetToLine(line); + grid->editBox->TextEdit->SetSelectionU(wordStart,wordEnd); + grid->EndBatch(); } @@ -136,28 +244,74 @@ void DialogSpellChecker::OnClose(wxCommandEvent &event) { /////////// // Replace void DialogSpellChecker::OnReplace(wxCommandEvent &event) { + Replace(); + FindOrDie(); } ////////////////////// // Replace all errors void DialogSpellChecker::OnReplaceAll(wxCommandEvent &event) { + // Add word to autoreplace list + autoReplace[origWord->GetValue()] = replaceWord->GetValue(); + + // Replace + Replace(); + FindOrDie(); } ///////////////////// // Ignore this error void DialogSpellChecker::OnIgnore(wxCommandEvent &event) { + // Next + FindOrDie(); } ///////////////////// // Ignore all errors void DialogSpellChecker::OnIgnoreAll(wxCommandEvent &event) { + // Add word to autoignore list + autoIgnore.Add(origWord->GetValue()); + + // Next + FindOrDie(); } ///////////////////// // Add to dictionary void DialogSpellChecker::OnAdd(wxCommandEvent &event) { + spellchecker->AddWord(origWord->GetValue()); + FindOrDie(); +} + + +/////////////////////////////////////////////// +// Goes to next... if it can't find one, close +bool DialogSpellChecker::FindOrDie() { + if (!FindNext()) { + wxMessageBox(_("Aegisub has finished checking spelling of this script."),_("Spell checking complete.")); + Destroy(); + return false; + } + return true; +} + + +/////////// +// Replace +void DialogSpellChecker::Replace() { + // Get dialog + SubtitlesGrid *grid = ((FrameMain*)GetParent())->SubsBox; + AssDialogue *diag = grid->GetDialogue(lastLine % grid->GetRows()); + + // Replace + diag->Text = diag->Text.Left(wordStart) + replaceWord->GetValue() + diag->Text.Mid(wordEnd); + lastPos = wordStart + replaceWord->GetValue().Length(); + + // Commit + grid->ass->FlagAsModified(_("Spell check replace")); + grid->CommitChanges(); } diff --git a/aegisub/dialog_spellchecker.h b/aegisub/dialog_spellchecker.h index 50918494a..e196804ff 100644 --- a/aegisub/dialog_spellchecker.h +++ b/aegisub/dialog_spellchecker.h @@ -38,6 +38,7 @@ /////////// // Headers #include +#include ////////////// @@ -51,14 +52,22 @@ class DialogSpellChecker : public wxDialog { private: SpellChecker *spellchecker; + std::map autoReplace; + wxArrayString autoIgnore; + + int wordStart,wordEnd; int lastLine; int lastPos; + int firstLine; wxTextCtrl *origWord; wxTextCtrl *replaceWord; wxListBox *suggestList; - void FindNext(int startLine=-1,int startPos=-1); + bool FindOrDie(); + bool FindNext(int startLine=-1,int startPos=-1); + void SetWord(wxString word); + void Replace(); void OnClose(wxCommandEvent &event); void OnReplace(wxCommandEvent &event); @@ -69,5 +78,6 @@ private: public: DialogSpellChecker(wxFrame *parent); + ~DialogSpellChecker(); DECLARE_EVENT_TABLE() }; diff --git a/aegisub/frame_main_events.cpp b/aegisub/frame_main_events.cpp index d4246b8a7..1360d31dd 100644 --- a/aegisub/frame_main_events.cpp +++ b/aegisub/frame_main_events.cpp @@ -888,7 +888,7 @@ void FrameMain::OnOpenTranslation(wxCommandEvent& WXUNUSED(event)) { void FrameMain::OnOpenSpellCheck (wxCommandEvent &event) { VideoContext::Get()->Stop(); DialogSpellChecker *spell = new DialogSpellChecker(this); - spell->Show(); + //spell->ShowModal(); } diff --git a/aegisub/subs_edit_ctrl.cpp b/aegisub/subs_edit_ctrl.cpp index ba7524c02..98010c4f7 100644 --- a/aegisub/subs_edit_ctrl.cpp +++ b/aegisub/subs_edit_ctrl.cpp @@ -74,13 +74,6 @@ SubsTextEditCtrl::SubsTextEditCtrl(wxWindow* parent, wxWindowID id, const wxStri // Set thesaurus thesaurus = Thesaurus::GetThesaurus(); - // Delimiters - delim = _T(" .,;:!?-(){}[]\"/\\"); - wxChar temp = 0xBF; - delim += temp; - temp = 0xA1; - delim += temp; - // Prototypes for call tips tipProtoN = -1; proto.Add(_T("move(x1,y1,x2,y2)")); @@ -660,85 +653,46 @@ void SubsTextEditCtrl::StyleSpellCheck(int start, int len) { // See if it has a spellchecker if (!spellchecker) return; - // Variables - wxChar cur; + // Results wxString text = GetText(); - int curPos; - int lastpos = -1; - int end = start+len; - int depth = 0; - if (len < 0) end = text.Length(); - wxArrayInt startPos; - wxArrayInt endPos; - bool isDelim; - - // Scan - for (int i=start;iCheckWord(curWord)) { // Get length before it - int utf8len = GetUnicodePosition(startPos[i]); + int utf8len = GetUnicodePosition(s); // Set styling StartStyling(utf8len,32); - SetUnicodeStyling(startPos[i],endPos[i]-startPos[i],32); + SetUnicodeStyling(s,e-s,32); + } + } +} + + +////////////////////////////////////// +// Get boundaries of word at position +void SubsTextEditCtrl::GetBoundsOfWordAtPosition(int pos,int &_start,int &_end) { + // Results + IntPairVector results; + GetWordBoundaries(GetText(),results); + + // Get boundaries + int count = results.size(); + for (int i=0;i= pos) { + _start = results[i].first; + _end = results[i].second-1; + return; } } } @@ -988,77 +942,6 @@ void SubsTextEditCtrl::ShowPopupMenu(int activePos) { } -////////////////////////////////////// -// Get boundaries of word at position -void SubsTextEditCtrl::GetBoundsOfWordAtPosition(int pos,int &_start,int &_end) { - // Variables - wxString text = GetText(); - int len = text.Length(); - int lastDelimBefore = -1; - int firstDelimAfter = len; - wxChar cur,next; - int depth=0; - - // Scan for delimiters - for (int i=0;i= pos) { - firstDelimAfter = i; - break; - } - depth++; - } - if (cur == '}') { - if (i < pos) { - lastDelimBefore = i; - } - depth--; - } - if (depth != 0) { - // Picked a location in invalid depth - if (pos == i) { - lastDelimBefore = -1; - firstDelimAfter = 0; - break; - } - continue; - } - - // Line breaks - if (cur == '\\' && (next == 'N' || next == 'n' || next == 'h')) { - // Before - if (i < pos) { - i++; - lastDelimBefore = i; - continue; - } - } - - // Check for delimiters - if (delim.Find(cur) != wxNOT_FOUND) { - // Before - if (i < pos) lastDelimBefore = i; - - // After - else { - firstDelimAfter = i; - break; - } - } - } - - // Set start and end - _start = lastDelimBefore+1; - _end = firstDelimAfter-1; -} - - ////////////////////////////////// // Get word at specified position wxString SubsTextEditCtrl::GetWordAtPosition(int pos) { diff --git a/aegisub/subs_edit_ctrl.h b/aegisub/subs_edit_ctrl.h index cddfdf49a..bab4d7299 100644 --- a/aegisub/subs_edit_ctrl.h +++ b/aegisub/subs_edit_ctrl.h @@ -57,7 +57,6 @@ private: SpellChecker *spellchecker; Thesaurus *thesaurus; - wxString delim; wxString currentWord; wxArrayString sugs; wxArrayString thesSugs; diff --git a/aegisub/utils.cpp b/aegisub/utils.cpp index af091b422..a8978e6a9 100644 --- a/aegisub/utils.cpp +++ b/aegisub/utils.cpp @@ -212,3 +212,74 @@ int SmallestPowerOf2(int x) { x++; return x; } + + +/////////////////////// +// Get word boundaries +void GetWordBoundaries(const wxString text,IntPairVector &results,int start,int end) { + // Variables + wxChar cur; + int curPos; + int lastpos = -1; + int depth = 0; + if (end < 0) end = text.Length(); + bool isDelim; + + // Delimiters + wxString delim = _T(" .,;:!?-(){}[]\"/\\"); + wxChar temp = 0xBF; + delim += temp; + temp = 0xA1; + delim += temp; + + // Scan + for (int i=start;i(lastpos+1,curPos)); + } + continue; + } + } + + // Decrease depth + if (cur == '}') { + depth--; + if (depth == 0) { + lastpos = i; + continue; + } + } + + // Wrong depth + if (depth != 0) continue; + + // Check if it is \n or \N + if (cur == '\\' && i < end-1 && (text[i+1] == 'N' || text[i+1] == 'n' || text[i+1] == 'h')) { + isDelim = true; + i++; + } + + // Check for standard delimiters + if (delim.Find(cur) != wxNOT_FOUND) { + isDelim = true; + } + + // Is delimiter? + if (isDelim) { + if (lastpos+1 != curPos) { + results.push_back(std::pair(lastpos+1,curPos)); + } + lastpos = i; + } + } +} diff --git a/aegisub/utils.h b/aegisub/utils.h index 5a03ffda0..3a5fea253 100644 --- a/aegisub/utils.h +++ b/aegisub/utils.h @@ -37,6 +37,17 @@ #pragma once +/////////// +// Headers +#include +#include + + +//////////// +// Typedefs +typedef std::vector > IntPairVector; + + /////////////////////// // Function prototypes #ifndef __LINUX__ @@ -55,6 +66,7 @@ wxString IntegerToString(int value); wxString PrettySize(int bytes); wxMenuItem *AppendBitmapMenuItem (wxMenu* parentMenu,int id,wxString text,wxString help,wxBitmap bmp,int pos=-1); int SmallestPowerOf2(int x); +void GetWordBoundaries(const wxString text,IntPairVector &results,int start=0,int end=-1); //////////