Move the spellchecker base class to libaegisub

This commit is contained in:
Thomas Goyne 2012-10-30 08:59:47 -07:00
parent 47bafe4b9f
commit 76adcad999
14 changed files with 205 additions and 271 deletions

View File

@ -489,6 +489,10 @@
RelativePath="..\..\libaegisub\include\libaegisub\signal.h"
>
</File>
<File
RelativePath="..\..\libaegisub\include\libaegisub\spellchecker.h"
>
</File>
<File
RelativePath="..\..\libaegisub\include\libaegisub\thesaurus.h"
>

View File

@ -0,0 +1,52 @@
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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.
//
// 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.
//
// Aegisub Project http://www.aegisub.org/
#pragma once
#ifndef LAGI_PRE
#include <string>
#include <vector>
#endif
namespace agi {
class SpellChecker {
public:
virtual ~SpellChecker() { }
/// Add word to the dictionary
/// @param word Word to add
virtual void AddWord(std::string const& word)=0;
/// Can the word be added to the current dictionary?
/// @param word Word to check
/// @return Whether or not word can be added
virtual bool CanAddWord(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
virtual bool CheckWord(std::string const& word)=0;
/// Get possible corrections for a misspelled word
/// @param word Word to get suggestions for
/// @return List of suggestions, if any
virtual std::vector<std::string> GetSuggestions(std::string const& word)=0;
/// Get a list of languages which dictionaries are present for
virtual std::vector<std::string> GetLanguageList()=0;
};
}

View File

@ -12,3 +12,10 @@ wxArrayString lagi_MRU_wxAS(const wxString &list) {
transform(map->begin(), map->end(), std::back_inserter(work), lagi_wxString);
return work;
}
wxArrayString to_wx(std::vector<std::string> const& vec) {
wxArrayString ret;
ret.reserve(vec.size());
transform(vec.begin(), vec.end(), std::back_inserter(ret), lagi_wxString);
return ret;
}

View File

@ -1,5 +1,6 @@
#ifndef AGI_PRE
#include <string>
#include <vector>
#include <wx/colour.h>
#include <wx/arrstr.h>
@ -12,6 +13,7 @@
inline wxColour to_wx(agi::Color color) { return wxColour(color.r, color.g, color.b, 255 - color.a); }
inline wxString to_wx(std::string const& str) { return wxString(str.c_str(), wxConvUTF8); }
wxArrayString to_wx(std::vector<std::string> const& vec);
inline agi::Color from_wx(wxColour color) { return agi::Color(color.Red(), color.Green(), color.Blue(), 255 - color.Alpha()); }
inline std::string from_wx(wxString const& str) { return std::string(str.utf8_str()); }

View File

@ -48,6 +48,7 @@
#include "utils.h"
#include <libaegisub/exception.h>
#include <libaegisub/spellchecker.h>
static void save_skip_comments(wxCommandEvent &evt) {
OPT_SET("Tool/Spell Checker/Skip Comments")->SetBool(!!evt.GetInt());
@ -97,7 +98,7 @@ DialogSpellChecker::DialogSpellChecker(agi::Context *context)
throw agi::UserCancelException("No spellchecker available");
}
dictionary_lang_codes = spellchecker->GetLanguageList();
dictionary_lang_codes = to_wx(spellchecker->GetLanguageList());
if (dictionary_lang_codes.empty()) {
wxMessageBox("No spellchecker dictionaries available.", "Error", wxOK | wxICON_ERROR | wxCENTER);
throw agi::UserCancelException("No spellchecker dictionaries available");
@ -183,7 +184,7 @@ void DialogSpellChecker::OnIgnoreAll(wxCommandEvent&) {
}
void DialogSpellChecker::OnAdd(wxCommandEvent&) {
spellchecker->AddWord(orig_word->GetValue());
spellchecker->AddWord(from_wx(orig_word->GetValue()));
FindNext();
}
@ -256,7 +257,7 @@ bool DialogSpellChecker::CheckLine(AssDialogue *active_line, int start_pos, int
word_end = results[j].second + shift;
wxString word = active_line->Text.Mid(word_start, word_end - word_start);
if (auto_ignore.count(word) || spellchecker->CheckWord(word)) continue;
if (auto_ignore.count(word) || spellchecker->CheckWord(from_wx(word))) continue;
std::map<wxString, wxString>::const_iterator auto_rep = auto_replace.find(word);
if (auto_rep == auto_replace.end()) {
@ -294,7 +295,7 @@ void DialogSpellChecker::Replace() {
void DialogSpellChecker::SetWord(wxString const& word) {
orig_word->SetValue(word);
wxArrayString suggestions = spellchecker->GetSuggestions(word);
wxArrayString suggestions = to_wx(spellchecker->GetSuggestions(from_wx(word)));
replace_word->SetValue(suggestions.size() ? suggestions[0] : word);
suggest_list->Clear();
suggest_list->Append(suggestions);
@ -302,5 +303,5 @@ void DialogSpellChecker::SetWord(wxString const& word) {
context->textSelectionController->SetSelection(word_start, word_end);
context->textSelectionController->SetInsertionPoint(word_end);
add_button->Enable(spellchecker->CanAddWord(word));
add_button->Enable(spellchecker->CanAddWord(from_wx(word)));
}

View File

@ -24,13 +24,14 @@
#include <set>
#include <wx/dialog.h>
#include <wx/arrstr.h>
#endif
#include <libaegisub/scoped_ptr.h>
namespace agi { struct Context; }
namespace agi { class SpellChecker; }
class AssDialogue;
class SpellChecker;
class wxButton;
class wxCheckBox;
class wxComboBox;
@ -44,7 +45,7 @@ class wxTextCtrl;
/// DOCME
class DialogSpellChecker : public wxDialog {
agi::Context *context; ///< The project context
agi::scoped_ptr<SpellChecker> spellchecker; ///< The spellchecking engine
agi::scoped_ptr<agi::SpellChecker> spellchecker; ///< The spellchecking engine
/// Words which the user has indicated should always be corrected
std::map<wxString,wxString> auto_replace;

View File

@ -1,81 +1,30 @@
// Copyright (c) 2006, Rodrigo Braz Monteiro
// All rights reserved.
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 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.
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 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.
//
// Aegisub Project http://www.aegisub.org/
/// @file spellchecker.h
/// @brief Declaration of base-class for spell checkers
/// @brief Declaration of factory for spell checkers
/// @ingroup main_headers spelling
///
#pragma once
#ifndef AGI_PRE
#include <wx/arrstr.h>
#include <wx/string.h>
#endif
#include "factory_manager.h"
/// @class SpellChecker
/// @brief DOCME
///
/// DOCME
class SpellChecker {
namespace agi { class SpellChecker; }
class SpellCheckerFactory : public Factory0<agi::SpellChecker> {
public:
/// @brief DOCME
///
virtual ~SpellChecker() {}
/// @brief DOCME
/// @param word
/// @return
///
virtual void AddWord(wxString word) {}
/// @brief DOCME
/// @param word
/// @return
///
virtual bool CanAddWord(wxString word) { return false; }
virtual bool CheckWord(wxString word)=0;
virtual wxArrayString GetSuggestions(wxString word)=0;
virtual wxArrayString GetLanguageList()=0;
};
/// DOCME
/// @class SpellCheckerFactoryManager
/// @brief DOCME
///
/// DOCME
class SpellCheckerFactory : public Factory0<SpellChecker> {
public:
static SpellChecker *GetSpellChecker();
static agi::SpellChecker *GetSpellChecker();
static void RegisterProviders();
};

View File

@ -42,11 +42,7 @@
#include "include/aegisub/spellchecker.h"
#include "main.h"
/// @brief Get spell checker
/// @return
///
SpellChecker *SpellCheckerFactory::GetSpellChecker() {
// List of providers
agi::SpellChecker *SpellCheckerFactory::GetSpellChecker() {
std::vector<std::string> list = GetClasses(OPT_GET("Tool/Spell Checker/Backend")->GetString());
if (list.empty()) return NULL;
@ -54,7 +50,7 @@ SpellChecker *SpellCheckerFactory::GetSpellChecker() {
wxString error;
for (unsigned int i=0;i<list.size();i++) {
try {
SpellChecker *checker = Create(list[i]);
agi::SpellChecker *checker = Create(list[i]);
if (checker) return checker;
}
catch (wxString const& err) { error += list[i] + " factory: " + err + "\n"; }
@ -62,16 +58,13 @@ SpellChecker *SpellCheckerFactory::GetSpellChecker() {
catch (...) { error += list[i] + " factory: Unknown error\n"; }
}
// Failed
throw error;
}
/// @brief Register all providers
///
void SpellCheckerFactory::RegisterProviders() {
#ifdef WITH_HUNSPELL
Register<HunspellSpellChecker>("Hunspell");
#endif
}
template<> SpellCheckerFactory::map *FactoryBase<SpellChecker *(*)()>::classes = NULL;
template<> SpellCheckerFactory::map *FactoryBase<agi::SpellChecker *(*)()>::classes = NULL;

View File

@ -1,31 +1,17 @@
// Copyright (c) 2010, Thomas Goyne <plorkyeran@aegisub.org>
// All rights reserved.
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 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.
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
// 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.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
/// @file spellchecker_hunspell.cpp
/// @brief Hunspell-based spell checker implementation
@ -68,10 +54,10 @@ HunspellSpellChecker::HunspellSpellChecker()
HunspellSpellChecker::~HunspellSpellChecker() {
}
bool HunspellSpellChecker::CanAddWord(wxString word) {
bool HunspellSpellChecker::CanAddWord(std::string const& word) {
if (!hunspell) return false;
try {
conv->Convert(STD_STR(word));
conv->Convert(word);
return true;
}
catch (agi::charset::ConvError const&) {
@ -79,13 +65,11 @@ bool HunspellSpellChecker::CanAddWord(wxString word) {
}
}
void HunspellSpellChecker::AddWord(wxString word) {
void HunspellSpellChecker::AddWord(std::string const& word) {
if (!hunspell) return;
std::string sword = STD_STR(word);
// Add it to the in-memory dictionary
hunspell->add(conv->Convert(sword).c_str());
hunspell->add(conv->Convert(word).c_str());
std::set<std::string> words;
@ -110,7 +94,7 @@ void HunspellSpellChecker::AddWord(wxString word) {
}
// Add the word
words.insert(sword);
words.insert(word);
// Write the new dictionary
{
@ -126,29 +110,28 @@ void HunspellSpellChecker::AddWord(wxString word) {
lang_listener.Unblock();
}
bool HunspellSpellChecker::CheckWord(wxString word) {
bool HunspellSpellChecker::CheckWord(std::string const& word) {
if (!hunspell) return true;
try {
return hunspell->spell(conv->Convert(STD_STR(word)).c_str()) == 1;
return hunspell->spell(conv->Convert(word).c_str()) == 1;
}
catch (agi::charset::ConvError const&) {
return false;
}
}
wxArrayString HunspellSpellChecker::GetSuggestions(wxString word) {
wxArrayString suggestions;
std::vector<std::string> HunspellSpellChecker::GetSuggestions(std::string const& word) {
std::vector<std::string> suggestions;
if (!hunspell) return suggestions;
// Grab raw from Hunspell
char **results;
int n = hunspell->suggest(&results,conv->Convert(STD_STR(word)).c_str());
int n = hunspell->suggest(&results, conv->Convert(word).c_str());
suggestions.reserve(n);
// Convert each
// Convert suggestions to UTF-8
for (int i = 0; i < n; ++i) {
try {
suggestions.Add(lagi_wxString(rconv->Convert(results[i])));
suggestions.push_back(rconv->Convert(results[i]));
}
catch (agi::charset::ConvError const&) {
// Shouldn't ever actually happen...
@ -161,7 +144,7 @@ wxArrayString HunspellSpellChecker::GetSuggestions(wxString word) {
return suggestions;
}
wxArrayString HunspellSpellChecker::GetLanguageList() {
std::vector<std::string> HunspellSpellChecker::GetLanguageList() {
if (!languages.empty()) return languages;
wxArrayString dic, aff;
@ -172,12 +155,12 @@ wxArrayString HunspellSpellChecker::GetLanguageList() {
wxDir::GetAllFiles(path, &dic, "*.dic", wxDIR_FILES);
wxDir::GetAllFiles(path, &aff, "*.aff", wxDIR_FILES);
}
path = StandardPaths::DecodePath(lagi_wxString(OPT_GET("Path/Dictionary")->GetString()) + "/");
path = StandardPaths::DecodePath(to_wx(OPT_GET("Path/Dictionary")->GetString()) + "/");
if (wxFileName::DirExists(path)) {
wxDir::GetAllFiles(path, &dic, "*.dic", wxDIR_FILES);
wxDir::GetAllFiles(path, &aff, "*.aff", wxDIR_FILES);
}
if (aff.empty()) return wxArrayString();
if (aff.empty()) return std::vector<std::string>();
dic.Sort();
aff.Sort();
@ -194,7 +177,7 @@ wxArrayString HunspellSpellChecker::GetLanguageList() {
else {
// Don't insert a language twice if it's in both the user dir and
// the app's dir
wxString name = wxFileName(aff[j]).GetName();
std::string name = from_wx(wxFileName(aff[j]).GetName());
if (languages.empty() || name != languages.back())
languages.push_back(name);
++i;
@ -210,7 +193,7 @@ void HunspellSpellChecker::OnLanguageChanged() {
std::string language = OPT_GET("Tool/Spell Checker/Language")->GetString();
if (language.empty()) return;
wxString custDicRoot = StandardPaths::DecodePath(lagi_wxString(OPT_GET("Path/Dictionary")->GetString()));
wxString custDicRoot = StandardPaths::DecodePath(to_wx(OPT_GET("Path/Dictionary")->GetString()));
wxString dataDicRoot = StandardPaths::DecodePath("?data/dictionaries");
// If the user has a dic/aff pair in their dictionary path for this language

View File

@ -1,29 +1,16 @@
// Copyright (c) 2008, Rodrigo Braz Monteiro
// All rights reserved.
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 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.
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 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.
//
// Aegisub Project http://www.aegisub.org/
@ -34,22 +21,16 @@
#ifdef WITH_HUNSPELL
#include "include/aegisub/spellchecker.h"
#include <libaegisub/spellchecker.h>
#include <libaegisub/scoped_ptr.h>
#include <libaegisub/signal.h>
namespace agi {
namespace charset {
class IconvWrapper;
}
}
namespace agi { namespace charset { class IconvWrapper; } }
class Hunspell;
/// @class HunspellSpellChecker
/// @brief Hunspell spell checker
///
class HunspellSpellChecker : public SpellChecker {
/// @brief Hunspell-based spell checker implementation
class HunspellSpellChecker : public agi::SpellChecker {
/// Hunspell instance
agi::scoped_ptr<Hunspell> hunspell;
@ -58,7 +39,7 @@ class HunspellSpellChecker : public SpellChecker {
agi::scoped_ptr<agi::charset::IconvWrapper> rconv;
/// Languages which we have dictionaries for
wxArrayString languages;
std::vector<std::string> languages;
/// Path to user-local dictionary.
wxString userDicPath;
@ -77,27 +58,11 @@ public:
HunspellSpellChecker();
~HunspellSpellChecker();
/// @brief Add word to dictionary
/// @param word Word to add.
void AddWord(wxString word);
/// @brief Can add to dictionary?
/// @param word Word to check.
/// @return Whether word can be added or not.
bool CanAddWord(wxString word);
/// @brief Check if the word is valid.
/// @param word Word to check
/// @return Whether word is valid or not.
bool CheckWord(wxString word);
/// @brief Get suggestions for word.
/// @param word Word to get suggestions for
/// @return List of suggestions
wxArrayString GetSuggestions(wxString word);
/// @brief Get a list of languages which dictionaries are present for
wxArrayString GetLanguageList();
void AddWord(std::string const& word);
bool CanAddWord(std::string const& word);
bool CheckWord(std::string const& word);
std::vector<std::string> GetSuggestions(std::string const& word);
std::vector<std::string> GetLanguageList();
};
#endif

View File

@ -58,6 +58,8 @@
#include "thesaurus.h"
#include "utils.h"
#include <libaegisub/spellchecker.h>
/// Event ids
enum {
EDIT_MENU_SPLIT_PRESERVE = 1400,
@ -670,7 +672,7 @@ void SubsTextEditCtrl::StyleSpellCheck() {
wxString curWord = text.Mid(s,e-s);
// Check if it's valid
if (!spellchecker->CheckWord(curWord)) {
if (!spellchecker->CheckWord(from_wx(curWord))) {
StartUnicodeStyling(s,32);
SetUnicodeStyling(s,e-s,32);
}
@ -730,7 +732,7 @@ void SubsTextEditCtrl::OnContextMenu(wxContextMenuEvent &event) {
}
currentWordPos = GetReverseUnicodePosition(activePos);
currentWord = GetWordAtPosition(currentWordPos);
currentWord = from_wx(GetWordAtPosition(currentWordPos));
wxMenu menu;
if (!currentWord.empty()) {
@ -764,9 +766,9 @@ void SubsTextEditCtrl::AddSpellCheckerEntries(wxMenu &menu) {
else {
wxMenu *subMenu = new wxMenu;
for (size_t i = 0; i < sugs.size(); ++i)
subMenu->Append(EDIT_MENU_SUGGESTIONS+i, sugs[i]);
subMenu->Append(EDIT_MENU_SUGGESTIONS+i, to_wx(sugs[i]));
menu.Append(-1, wxString::Format(_("Spell checker suggestions for \"%s\""),currentWord), subMenu);
menu.Append(-1, wxString::Format(_("Spell checker suggestions for \"%s\""), to_wx(currentWord)), subMenu);
}
}
else {
@ -774,17 +776,17 @@ void SubsTextEditCtrl::AddSpellCheckerEntries(wxMenu &menu) {
menu.Append(EDIT_MENU_SUGGESTION,_("No correction suggestions"))->Enable(false);
for (size_t i = 0; i < sugs.size(); ++i)
menu.Append(EDIT_MENU_SUGGESTIONS+i, sugs[i]);
menu.Append(EDIT_MENU_SUGGESTIONS+i, to_wx(sugs[i]));
// Append "add word"
menu.Append(EDIT_MENU_ADD_TO_DICT, wxString::Format(_("Add \"%s\" to dictionary"), currentWord))->Enable(spellchecker->CanAddWord(currentWord));
menu.Append(EDIT_MENU_ADD_TO_DICT, wxString::Format(_("Add \"%s\" to dictionary"), to_wx(currentWord)))->Enable(spellchecker->CanAddWord(currentWord));
}
// Append language list
menu.Append(-1,_("Spell checker language"), GetLanguagesMenu(
EDIT_MENU_DIC_LANGS,
lagi_wxString(OPT_GET("Tool/Spell Checker/Language")->GetString()),
spellchecker->GetLanguageList()));
to_wx(spellchecker->GetLanguageList())));
menu.AppendSeparator();
}
@ -821,7 +823,7 @@ void SubsTextEditCtrl::AddThesaurusEntries(wxMenu &menu) {
}
}
menu.Append(-1, wxString::Format(_("Thesaurus suggestions for \"%s\""), currentWord), thesMenu);
menu.Append(-1, wxString::Format(_("Thesaurus suggestions for \"%s\""), to_wx(currentWord)), thesMenu);
}
else
menu.Append(EDIT_MENU_THESAURUS,_("No thesaurus suggestions"))->Enable(false);
@ -830,7 +832,7 @@ void SubsTextEditCtrl::AddThesaurusEntries(wxMenu &menu) {
menu.Append(-1,_("Thesaurus language"), GetLanguagesMenu(
EDIT_MENU_THES_LANGS,
lagi_wxString(OPT_GET("Tool/Thesaurus/Language")->GetString()),
thesaurus->GetLanguageList()));
to_wx(thesaurus->GetLanguageList())));
menu.AppendSeparator();
}
@ -874,7 +876,7 @@ void SubsTextEditCtrl::OnAddToDictionary(wxCommandEvent &) {
}
void SubsTextEditCtrl::OnUseSuggestion(wxCommandEvent &event) {
wxString suggestion;
std::string suggestion;
int sugIdx = event.GetId() - EDIT_MENU_THESAURUS_SUGS;
if (sugIdx >= 0) {
suggestion = lagi_wxString(thesSugs[sugIdx]);
@ -883,33 +885,32 @@ void SubsTextEditCtrl::OnUseSuggestion(wxCommandEvent &event) {
suggestion = sugs[event.GetId() - EDIT_MENU_SUGGESTIONS];
}
// Stripe suggestion of parenthesis
int pos = suggestion.Find("(");
if (pos != wxNOT_FOUND) {
suggestion = suggestion.Left(pos-1);
}
// Strip suggestion of parenthesis
size_t pos = suggestion.find("(");
if (pos != suggestion.npos)
suggestion.resize(pos - 1);
// Get boundaries of text being replaced
int start, end;
GetBoundsOfWordAtPosition(currentWordPos, start, end);
wxString text = GetText();
SetText(text.Left(std::max(0, start)) + suggestion + text.Mid(end));
SetText(text.Left(std::max(0, start)) + to_wx(suggestion) + text.Mid(end));
// Set selection
SetSelectionU(start,start+suggestion.Length());
SetSelectionU(start, start+suggestion.size());
SetFocus();
}
void SubsTextEditCtrl::OnSetDicLanguage(wxCommandEvent &event) {
wxArrayString langs = spellchecker->GetLanguageList();
std::vector<std::string> langs = spellchecker->GetLanguageList();
int index = event.GetId() - EDIT_MENU_DIC_LANGS - 1;
wxString lang;
std::string lang;
if (index >= 0)
lang = langs[index];
OPT_SET("Tool/Spell Checker/Language")->SetString(STD_STR(lang));
OPT_SET("Tool/Spell Checker/Language")->SetString(lang);
UpdateStyle();
}
@ -917,12 +918,12 @@ void SubsTextEditCtrl::OnSetDicLanguage(wxCommandEvent &event) {
void SubsTextEditCtrl::OnSetThesLanguage(wxCommandEvent &event) {
if (!thesaurus) return;
wxArrayString langs = thesaurus->GetLanguageList();
std::vector<std::string> langs = thesaurus->GetLanguageList();
int index = event.GetId() - EDIT_MENU_THES_LANGS - 1;
wxString lang;
std::string lang;
if (index >= 0) lang = langs[index];
OPT_SET("Tool/Thesaurus/Language")->SetString(STD_STR(lang));
OPT_SET("Tool/Thesaurus/Language")->SetString(lang);
UpdateStyle();
}

View File

@ -41,16 +41,18 @@
#include <libaegisub/scoped_ptr.h>
class SpellChecker;
class SubsEditBox;
class Thesaurus;
namespace agi { struct Context; }
namespace agi {
class SpellChecker;
struct Context;
}
/// @class SubsTextEditCtrl
/// @brief A Scintilla control with spell checking and syntax highlighting
class SubsTextEditCtrl : public ScintillaTextCtrl {
/// Backend spellchecker to use
agi::scoped_ptr<SpellChecker> spellchecker;
agi::scoped_ptr<agi::SpellChecker> spellchecker;
/// Backend thesaurus to use
agi::scoped_ptr<Thesaurus> thesaurus;
@ -59,13 +61,13 @@ class SubsTextEditCtrl : public ScintillaTextCtrl {
agi::Context *context;
/// The word right-clicked on, used for spellchecker replacing
wxString currentWord;
std::string currentWord;
/// The beginning of the word right-clicked on, for spellchecker replacing
int currentWordPos;
/// Spellchecker suggestions for the last right-clicked word
wxArrayString sugs;
std::vector<std::string> sugs;
/// Thesaurus suggestions for the last right-clicked word
std::vector<std::string> thesSugs;

View File

@ -1,29 +1,16 @@
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
// All rights reserved.
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 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.
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 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.
//
// Aegisub Project http://www.aegisub.org/
@ -43,6 +30,7 @@
#include <libaegisub/log.h>
#include <libaegisub/thesaurus.h>
#include <libaegisub/util.h>
#include "compat.h"
#include "main.h"
@ -59,12 +47,13 @@ Thesaurus::~Thesaurus() {
// Explicit empty destructor needed for scoped_ptr with incomplete types
}
void Thesaurus::Lookup(wxString const& word, std::vector<Entry> *result) {
void Thesaurus::Lookup(std::string word, std::vector<Entry> *result) {
if (!impl.get()) return;
impl->Lookup(STD_STR(word.Lower()), result);
agi::util::str_lower(word);
impl->Lookup(word, result);
}
wxArrayString Thesaurus::GetLanguageList() const {
std::vector<std::string> Thesaurus::GetLanguageList() const {
if (!languages.empty()) return languages;
wxArrayString idx, dat;
@ -97,7 +86,7 @@ wxArrayString Thesaurus::GetLanguageList() const {
else {
// Don't insert a language twice if it's in both the user dir and
// the app's dir
wxString name = wxFileName(dat[j]).GetName().Mid(3);
std::string name = from_wx(wxFileName(dat[j]).GetName().Mid(3));
if (languages.empty() || name != languages.back())
languages.push_back(name);
++i;

View File

@ -1,29 +1,16 @@
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
// All rights reserved.
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 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.
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 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.
//
// Aegisub Project http://www.aegisub.org/
@ -33,10 +20,8 @@
///
#ifndef AGI_PRE
#include <string>
#include <vector>
#include <wx/arrstr.h>
#include <wx/string.h>
#endif
#include <libaegisub/scoped_ptr.h>
@ -50,7 +35,7 @@ class Thesaurus {
/// The actual thesarus implementation
agi::scoped_ptr<agi::Thesaurus> impl;
/// A cached list of languages available
mutable wxArrayString languages;
mutable std::vector<std::string> languages;
/// Thesaurus language change slot
agi::signal::Connection lang_listener;
@ -71,8 +56,8 @@ public:
/// Get a list of synonyms for a word, grouped by possible meanings of the word
/// @param word Word to get synonyms for
/// @param[out] result Output list
void Lookup(wxString const& word, std::vector<Entry> *result);
void Lookup(std::string word, std::vector<Entry> *result);
/// Get a list of language codes which thesauri are available for
wxArrayString GetLanguageList() const;
std::vector<std::string> GetLanguageList() const;
};