/* AbiSuite * Copyright (C) 2001 Dom Lachowicz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "xap_App.h" #include "xap_Frame.h" #include "xap_Strings.h" #include "spell_manager.h" #include "ut_debugmsg.h" #include "ut_Language.h" #ifdef WITH_ENCHANT #include "enchant_checker.h" typedef EnchantChecker SpellCheckerClass; #else #include "ispell_checker.h" typedef ISpellChecker SpellCheckerClass; #endif /*! * Abstract constructor */ /* protected */ SpellChecker::SpellChecker () { // not used, abstract base class } /*! * Abstract destructor */ /* protected */ SpellChecker::~SpellChecker () { // not used, abstract base class } bool SpellChecker::requestDictionary (const char * szLang) { bool bSuccess = _requestDictionary(szLang); m_BarbarismChecker.load(szLang); return bSuccess; } SpellChecker::SpellCheckResult SpellChecker::checkWord(const UT_UCSChar* word, size_t len) { UT_return_val_if_fail( word, SpellChecker::LOOKUP_SUCCEEDED ); SpellChecker::SpellCheckResult ret = SpellChecker::LOOKUP_FAILED; m_bIsBarbarism = false; m_bIsDictionaryWord = false; if (m_BarbarismChecker.checkWord (word, len)) { UT_DEBUGMSG(("SPELL: spell %p %s barb \"%s\"\n", this, getLanguage().c_str(), UT_UTF8String (word, len).utf8_str())); m_bIsBarbarism = true; return SpellChecker::LOOKUP_FAILED; } // handle hyphenated constructions // we split each construction into the constituent words and check each word // individually -- if they all pass, we consider the whole phrase good, if any fails, // we try the entire hyphenated phrase const UT_uint32 iMaxWords = 10; const UT_UCS4Char * pWords[iMaxWords]; size_t iWordLengths[iMaxWords]; UT_uint32 iWordCount = 0; const UT_UCS4Char * p; UT_uint32 i; // initialise the first word to the start of the string we were given pWords[0] = word; for(i = 0, p = word; i < len; ++i, ++p) { if(*p == '-') { // calculate langth of this word iWordLengths[iWordCount] = p - pWords[iWordCount]; // store the start of next word iWordCount++; pWords[iWordCount] = p+1; } if(iWordCount >= iMaxWords - 1) break; } // compute the length of the last word iWordLengths[iWordCount] = len - (pWords[iWordCount] - word); // NB iWordCount is really 'word count' - 1 after the loop above, hence the <= for(i = 0; i <= iWordCount; ++i) { ret = _checkWord(pWords[i], iWordLengths[i]); if(ret == SpellChecker::LOOKUP_FAILED) break; } if(ret == SpellChecker::LOOKUP_SUCCEEDED) return ret; // try the whole hyphenated phrase ... ret = _checkWord(word, len); return ret; } UT_GenericVector *SpellChecker::suggestWord(const UT_UCSChar* word, size_t len) { UT_GenericVector *pvSugg = _suggestWord(word, len); m_BarbarismChecker.suggestWord(word, len, pvSugg); return pvSugg; } bool SpellChecker::addToCustomDict (const UT_UCSChar *word, size_t len) { return XAP_App::getApp()->addWordToDict (word, len); } void SpellChecker::correctWord (const UT_UCSChar * /*toCorrect*/, size_t /*toCorrectLen*/, const UT_UCSChar * /*correct*/, size_t /*correctLen*/) { } /* static */ void SpellChecker::couldNotLoadDictionary ( const char * szLang ) { XAP_App * pApp = XAP_App::getApp (); XAP_Frame * pFrame = pApp->getLastFocussedFrame (); char szLangName[255]; UT_Language lang; UT_uint32 id = lang.getIndxFromCode(szLang); const gchar* pLang = lang.getNthLangName(id); sprintf(szLangName, "%s [%s]", pLang, szLang); // language name [language_code] UT_String buf (UT_String_sprintf(pApp->getStringSet ()->getValue (XAP_STRING_ID_SPELL_CANTLOAD_DICT), szLangName)); if (pFrame) pFrame->showMessageBox (buf.c_str(), XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK); else { UT_DEBUGMSG(("SpellChecker::could not load dictionary for %s\n", szLang)); } } /***********************************************************************/ /***********************************************************************/ // some arbitrary number for how many language buckets to have by default #define NBUCKETS 3 /*! * Protected constructor * * This (Singleton) class is responsible for creating, handing out, * and destroying instances of the ISpellChecker class */ /* private */ SpellManager::SpellManager () : m_map (NBUCKETS), m_lastDict(0), m_nLoadedDicts(0) { m_missingHashs += "-none-"; } /*! * Destructor */ SpellManager::~SpellManager () { UT_GenericVector *pVec = m_map.enumerate(); UT_ASSERT(pVec); UT_VECTOR_PURGEALL (SpellCheckerClass *, (*pVec)); DELETEP(pVec); } /*! * If an instance already exists it will be returned for you. * If not, one is created and returned for you * \return A valid instance of the SpellManager class */ /* static */ SpellManager & SpellManager::instance () { // Singleton implementation static SpellManager s_instance; return s_instance; } /*! * Request an instance of a dictionary capable of checking the language * Represented by szLang * * \param szLang - The language tag ("en-US") we want to use * \return A valid SpellChecker for 'szLang' on success, or 0 on failure */ SpellChecker * SpellManager::requestDictionary (const char * szLang) { SpellCheckerClass * checker = 0; // Don't try to load hashes we know are missing if (strstr(m_missingHashs.c_str(), szLang)) return 0; // first look up the entry in the hashtable if (m_map.contains (szLang, 0)) { return static_cast(const_cast(m_map.pick (szLang))); } // not found, so insert it checker = new SpellCheckerClass (); checker->setLanguage (szLang); if (checker->requestDictionary (szLang)) { m_map.insert (szLang, static_cast(checker)); m_lastDict = checker; m_nLoadedDicts++; checker->setDictionaryFound(true); } else { checker->setDictionaryFound(false); m_missingHashs += szLang; delete checker; checker = NULL; } return checker; } /*! * Returns the last used dictionary, or 0 * \return The last valid SpellChecker or 0 */ SpellChecker * SpellManager::lastDictionary () const { return m_lastDict; } SpellChecker * SpellManager::getInstance() const { return new SpellCheckerClass (); }