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" RelativePath="..\..\libaegisub\include\libaegisub\signal.h"
> >
</File> </File>
<File
RelativePath="..\..\libaegisub\include\libaegisub\spellchecker.h"
>
</File>
<File <File
RelativePath="..\..\libaegisub\include\libaegisub\thesaurus.h" 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); transform(map->begin(), map->end(), std::back_inserter(work), lagi_wxString);
return work; 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 #ifndef AGI_PRE
#include <string> #include <string>
#include <vector>
#include <wx/colour.h> #include <wx/colour.h>
#include <wx/arrstr.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 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); } 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 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()); } inline std::string from_wx(wxString const& str) { return std::string(str.utf8_str()); }

View file

@ -48,6 +48,7 @@
#include "utils.h" #include "utils.h"
#include <libaegisub/exception.h> #include <libaegisub/exception.h>
#include <libaegisub/spellchecker.h>
static void save_skip_comments(wxCommandEvent &evt) { static void save_skip_comments(wxCommandEvent &evt) {
OPT_SET("Tool/Spell Checker/Skip Comments")->SetBool(!!evt.GetInt()); 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"); throw agi::UserCancelException("No spellchecker available");
} }
dictionary_lang_codes = spellchecker->GetLanguageList(); dictionary_lang_codes = to_wx(spellchecker->GetLanguageList());
if (dictionary_lang_codes.empty()) { if (dictionary_lang_codes.empty()) {
wxMessageBox("No spellchecker dictionaries available.", "Error", wxOK | wxICON_ERROR | wxCENTER); wxMessageBox("No spellchecker dictionaries available.", "Error", wxOK | wxICON_ERROR | wxCENTER);
throw agi::UserCancelException("No spellchecker dictionaries available"); throw agi::UserCancelException("No spellchecker dictionaries available");
@ -183,7 +184,7 @@ void DialogSpellChecker::OnIgnoreAll(wxCommandEvent&) {
} }
void DialogSpellChecker::OnAdd(wxCommandEvent&) { void DialogSpellChecker::OnAdd(wxCommandEvent&) {
spellchecker->AddWord(orig_word->GetValue()); spellchecker->AddWord(from_wx(orig_word->GetValue()));
FindNext(); FindNext();
} }
@ -256,7 +257,7 @@ bool DialogSpellChecker::CheckLine(AssDialogue *active_line, int start_pos, int
word_end = results[j].second + shift; word_end = results[j].second + shift;
wxString word = active_line->Text.Mid(word_start, word_end - word_start); 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); std::map<wxString, wxString>::const_iterator auto_rep = auto_replace.find(word);
if (auto_rep == auto_replace.end()) { if (auto_rep == auto_replace.end()) {
@ -294,7 +295,7 @@ void DialogSpellChecker::Replace() {
void DialogSpellChecker::SetWord(wxString const& word) { void DialogSpellChecker::SetWord(wxString const& word) {
orig_word->SetValue(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); replace_word->SetValue(suggestions.size() ? suggestions[0] : word);
suggest_list->Clear(); suggest_list->Clear();
suggest_list->Append(suggestions); suggest_list->Append(suggestions);
@ -302,5 +303,5 @@ void DialogSpellChecker::SetWord(wxString const& word) {
context->textSelectionController->SetSelection(word_start, word_end); context->textSelectionController->SetSelection(word_start, word_end);
context->textSelectionController->SetInsertionPoint(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 <set>
#include <wx/dialog.h> #include <wx/dialog.h>
#include <wx/arrstr.h>
#endif #endif
#include <libaegisub/scoped_ptr.h> #include <libaegisub/scoped_ptr.h>
namespace agi { struct Context; } namespace agi { struct Context; }
namespace agi { class SpellChecker; }
class AssDialogue; class AssDialogue;
class SpellChecker;
class wxButton; class wxButton;
class wxCheckBox; class wxCheckBox;
class wxComboBox; class wxComboBox;
@ -44,7 +45,7 @@ class wxTextCtrl;
/// DOCME /// DOCME
class DialogSpellChecker : public wxDialog { class DialogSpellChecker : public wxDialog {
agi::Context *context; ///< The project context 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 /// Words which the user has indicated should always be corrected
std::map<wxString,wxString> auto_replace; std::map<wxString,wxString> auto_replace;

View file

@ -1,81 +1,30 @@
// Copyright (c) 2006, Rodrigo Braz Monteiro // Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
// All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Permission to use, copy, modify, and distribute this software for any
// modification, are permitted provided that the following conditions are met: // 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, // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// this list of conditions and the following disclaimer. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// * Redistributions in binary form must reproduce the above copyright notice, // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// this list of conditions and the following disclaimer in the documentation // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// and/or other materials provided with the distribution. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// * Neither the name of the Aegisub Group nor the names of its contributors // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// may be used to endorse or promote products derived from this software // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
// //
// Aegisub Project http://www.aegisub.org/ // Aegisub Project http://www.aegisub.org/
/// @file spellchecker.h /// @file spellchecker.h
/// @brief Declaration of base-class for spell checkers /// @brief Declaration of factory for spell checkers
/// @ingroup main_headers spelling /// @ingroup main_headers spelling
/// ///
#pragma once
#ifndef AGI_PRE
#include <wx/arrstr.h>
#include <wx/string.h>
#endif
#include "factory_manager.h" #include "factory_manager.h"
/// @class SpellChecker namespace agi { class SpellChecker; }
/// @brief DOCME
/// class SpellCheckerFactory : public Factory0<agi::SpellChecker> {
/// DOCME
class SpellChecker {
public: public:
/// @brief DOCME static agi::SpellChecker *GetSpellChecker();
///
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 void RegisterProviders(); static void RegisterProviders();
}; };

View file

@ -42,11 +42,7 @@
#include "include/aegisub/spellchecker.h" #include "include/aegisub/spellchecker.h"
#include "main.h" #include "main.h"
/// @brief Get spell checker agi::SpellChecker *SpellCheckerFactory::GetSpellChecker() {
/// @return
///
SpellChecker *SpellCheckerFactory::GetSpellChecker() {
// List of providers
std::vector<std::string> list = GetClasses(OPT_GET("Tool/Spell Checker/Backend")->GetString()); std::vector<std::string> list = GetClasses(OPT_GET("Tool/Spell Checker/Backend")->GetString());
if (list.empty()) return NULL; if (list.empty()) return NULL;
@ -54,7 +50,7 @@ SpellChecker *SpellCheckerFactory::GetSpellChecker() {
wxString error; wxString error;
for (unsigned int i=0;i<list.size();i++) { for (unsigned int i=0;i<list.size();i++) {
try { try {
SpellChecker *checker = Create(list[i]); agi::SpellChecker *checker = Create(list[i]);
if (checker) return checker; if (checker) return checker;
} }
catch (wxString const& err) { error += list[i] + " factory: " + err + "\n"; } 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"; } catch (...) { error += list[i] + " factory: Unknown error\n"; }
} }
// Failed
throw error; throw error;
} }
/// @brief Register all providers
///
void SpellCheckerFactory::RegisterProviders() { void SpellCheckerFactory::RegisterProviders() {
#ifdef WITH_HUNSPELL #ifdef WITH_HUNSPELL
Register<HunspellSpellChecker>("Hunspell"); Register<HunspellSpellChecker>("Hunspell");
#endif #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> // Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
// All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Permission to use, copy, modify, and distribute this software for any
// modification, are permitted provided that the following conditions are met: // 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, // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// this list of conditions and the following disclaimer. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// * Redistributions in binary form must reproduce the above copyright notice, // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// this list of conditions and the following disclaimer in the documentation // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// and/or other materials provided with the distribution. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// * Neither the name of the Aegisub Group nor the names of its contributors // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// may be used to endorse or promote products derived from this software // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
//
// Aegisub Project http://www.aegisub.org/
/// @file spellchecker_hunspell.cpp /// @file spellchecker_hunspell.cpp
/// @brief Hunspell-based spell checker implementation /// @brief Hunspell-based spell checker implementation
@ -68,10 +54,10 @@ HunspellSpellChecker::HunspellSpellChecker()
HunspellSpellChecker::~HunspellSpellChecker() { HunspellSpellChecker::~HunspellSpellChecker() {
} }
bool HunspellSpellChecker::CanAddWord(wxString word) { bool HunspellSpellChecker::CanAddWord(std::string const& word) {
if (!hunspell) return false; if (!hunspell) return false;
try { try {
conv->Convert(STD_STR(word)); conv->Convert(word);
return true; return true;
} }
catch (agi::charset::ConvError const&) { 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; if (!hunspell) return;
std::string sword = STD_STR(word);
// Add it to the in-memory dictionary // 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; std::set<std::string> words;
@ -110,7 +94,7 @@ void HunspellSpellChecker::AddWord(wxString word) {
} }
// Add the word // Add the word
words.insert(sword); words.insert(word);
// Write the new dictionary // Write the new dictionary
{ {
@ -126,29 +110,28 @@ void HunspellSpellChecker::AddWord(wxString word) {
lang_listener.Unblock(); lang_listener.Unblock();
} }
bool HunspellSpellChecker::CheckWord(wxString word) { bool HunspellSpellChecker::CheckWord(std::string const& word) {
if (!hunspell) return true; if (!hunspell) return true;
try { 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&) { catch (agi::charset::ConvError const&) {
return false; return false;
} }
} }
wxArrayString HunspellSpellChecker::GetSuggestions(wxString word) { std::vector<std::string> HunspellSpellChecker::GetSuggestions(std::string const& word) {
wxArrayString suggestions; std::vector<std::string> suggestions;
if (!hunspell) return suggestions; if (!hunspell) return suggestions;
// Grab raw from Hunspell
char **results; 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); suggestions.reserve(n);
// Convert each // Convert suggestions to UTF-8
for (int i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
try { try {
suggestions.Add(lagi_wxString(rconv->Convert(results[i]))); suggestions.push_back(rconv->Convert(results[i]));
} }
catch (agi::charset::ConvError const&) { catch (agi::charset::ConvError const&) {
// Shouldn't ever actually happen... // Shouldn't ever actually happen...
@ -161,7 +144,7 @@ wxArrayString HunspellSpellChecker::GetSuggestions(wxString word) {
return suggestions; return suggestions;
} }
wxArrayString HunspellSpellChecker::GetLanguageList() { std::vector<std::string> HunspellSpellChecker::GetLanguageList() {
if (!languages.empty()) return languages; if (!languages.empty()) return languages;
wxArrayString dic, aff; wxArrayString dic, aff;
@ -172,12 +155,12 @@ wxArrayString HunspellSpellChecker::GetLanguageList() {
wxDir::GetAllFiles(path, &dic, "*.dic", wxDIR_FILES); wxDir::GetAllFiles(path, &dic, "*.dic", wxDIR_FILES);
wxDir::GetAllFiles(path, &aff, "*.aff", 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)) { if (wxFileName::DirExists(path)) {
wxDir::GetAllFiles(path, &dic, "*.dic", wxDIR_FILES); wxDir::GetAllFiles(path, &dic, "*.dic", wxDIR_FILES);
wxDir::GetAllFiles(path, &aff, "*.aff", wxDIR_FILES); wxDir::GetAllFiles(path, &aff, "*.aff", wxDIR_FILES);
} }
if (aff.empty()) return wxArrayString(); if (aff.empty()) return std::vector<std::string>();
dic.Sort(); dic.Sort();
aff.Sort(); aff.Sort();
@ -194,7 +177,7 @@ wxArrayString HunspellSpellChecker::GetLanguageList() {
else { else {
// Don't insert a language twice if it's in both the user dir and // Don't insert a language twice if it's in both the user dir and
// the app's dir // 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()) if (languages.empty() || name != languages.back())
languages.push_back(name); languages.push_back(name);
++i; ++i;
@ -210,7 +193,7 @@ void HunspellSpellChecker::OnLanguageChanged() {
std::string language = OPT_GET("Tool/Spell Checker/Language")->GetString(); std::string language = OPT_GET("Tool/Spell Checker/Language")->GetString();
if (language.empty()) return; 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"); wxString dataDicRoot = StandardPaths::DecodePath("?data/dictionaries");
// If the user has a dic/aff pair in their dictionary path for this language // 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 // Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
// All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Permission to use, copy, modify, and distribute this software for any
// modification, are permitted provided that the following conditions are met: // 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, // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// this list of conditions and the following disclaimer. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// * Redistributions in binary form must reproduce the above copyright notice, // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// this list of conditions and the following disclaimer in the documentation // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// and/or other materials provided with the distribution. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// * Neither the name of the Aegisub Group nor the names of its contributors // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// may be used to endorse or promote products derived from this software // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
// //
// Aegisub Project http://www.aegisub.org/ // Aegisub Project http://www.aegisub.org/
@ -34,22 +21,16 @@
#ifdef WITH_HUNSPELL #ifdef WITH_HUNSPELL
#include "include/aegisub/spellchecker.h" #include <libaegisub/spellchecker.h>
#include <libaegisub/scoped_ptr.h> #include <libaegisub/scoped_ptr.h>
#include <libaegisub/signal.h> #include <libaegisub/signal.h>
namespace agi { namespace agi { namespace charset { class IconvWrapper; } }
namespace charset {
class IconvWrapper;
}
}
class Hunspell; class Hunspell;
/// @class HunspellSpellChecker /// @brief Hunspell-based spell checker implementation
/// @brief Hunspell spell checker class HunspellSpellChecker : public agi::SpellChecker {
///
class HunspellSpellChecker : public SpellChecker {
/// Hunspell instance /// Hunspell instance
agi::scoped_ptr<Hunspell> hunspell; agi::scoped_ptr<Hunspell> hunspell;
@ -58,7 +39,7 @@ class HunspellSpellChecker : public SpellChecker {
agi::scoped_ptr<agi::charset::IconvWrapper> rconv; agi::scoped_ptr<agi::charset::IconvWrapper> rconv;
/// Languages which we have dictionaries for /// Languages which we have dictionaries for
wxArrayString languages; std::vector<std::string> languages;
/// Path to user-local dictionary. /// Path to user-local dictionary.
wxString userDicPath; wxString userDicPath;
@ -77,27 +58,11 @@ public:
HunspellSpellChecker(); HunspellSpellChecker();
~HunspellSpellChecker(); ~HunspellSpellChecker();
/// @brief Add word to dictionary void AddWord(std::string const& word);
/// @param word Word to add. bool CanAddWord(std::string const& word);
void AddWord(wxString word); bool CheckWord(std::string const& word);
std::vector<std::string> GetSuggestions(std::string const& word);
/// @brief Can add to dictionary? std::vector<std::string> GetLanguageList();
/// @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();
}; };
#endif #endif

View file

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

View file

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

View file

@ -1,29 +1,16 @@
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org> // Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
// All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Permission to use, copy, modify, and distribute this software for any
// modification, are permitted provided that the following conditions are met: // 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, // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// this list of conditions and the following disclaimer. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// * Redistributions in binary form must reproduce the above copyright notice, // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// this list of conditions and the following disclaimer in the documentation // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// and/or other materials provided with the distribution. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// * Neither the name of the Aegisub Group nor the names of its contributors // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// may be used to endorse or promote products derived from this software // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
// //
// Aegisub Project http://www.aegisub.org/ // Aegisub Project http://www.aegisub.org/
@ -43,6 +30,7 @@
#include <libaegisub/log.h> #include <libaegisub/log.h>
#include <libaegisub/thesaurus.h> #include <libaegisub/thesaurus.h>
#include <libaegisub/util.h>
#include "compat.h" #include "compat.h"
#include "main.h" #include "main.h"
@ -59,12 +47,13 @@ Thesaurus::~Thesaurus() {
// Explicit empty destructor needed for scoped_ptr with incomplete types // 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; 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; if (!languages.empty()) return languages;
wxArrayString idx, dat; wxArrayString idx, dat;
@ -97,7 +86,7 @@ wxArrayString Thesaurus::GetLanguageList() const {
else { else {
// Don't insert a language twice if it's in both the user dir and // Don't insert a language twice if it's in both the user dir and
// the app's dir // 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()) if (languages.empty() || name != languages.back())
languages.push_back(name); languages.push_back(name);
++i; ++i;

View file

@ -1,29 +1,16 @@
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org> // Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
// All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Permission to use, copy, modify, and distribute this software for any
// modification, are permitted provided that the following conditions are met: // 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, // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// this list of conditions and the following disclaimer. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// * Redistributions in binary form must reproduce the above copyright notice, // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// this list of conditions and the following disclaimer in the documentation // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// and/or other materials provided with the distribution. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// * Neither the name of the Aegisub Group nor the names of its contributors // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// may be used to endorse or promote products derived from this software // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 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.
// //
// Aegisub Project http://www.aegisub.org/ // Aegisub Project http://www.aegisub.org/
@ -33,10 +20,8 @@
/// ///
#ifndef AGI_PRE #ifndef AGI_PRE
#include <string>
#include <vector> #include <vector>
#include <wx/arrstr.h>
#include <wx/string.h>
#endif #endif
#include <libaegisub/scoped_ptr.h> #include <libaegisub/scoped_ptr.h>
@ -50,7 +35,7 @@ class Thesaurus {
/// The actual thesarus implementation /// The actual thesarus implementation
agi::scoped_ptr<agi::Thesaurus> impl; agi::scoped_ptr<agi::Thesaurus> impl;
/// A cached list of languages available /// A cached list of languages available
mutable wxArrayString languages; mutable std::vector<std::string> languages;
/// Thesaurus language change slot /// Thesaurus language change slot
agi::signal::Connection lang_listener; 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 /// Get a list of synonyms for a word, grouped by possible meanings of the word
/// @param word Word to get synonyms for /// @param word Word to get synonyms for
/// @param[out] result Output list /// @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 /// Get a list of language codes which thesauri are available for
wxArrayString GetLanguageList() const; std::vector<std::string> GetLanguageList() const;
}; };