2002-10-11 23:46:57 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code..
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2002
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Kin Blas <kin@netscape.com>
|
|
|
|
* Akkana Peck <akkana@netscape.com>
|
|
|
|
* Charley Manske <cmanske@netscape.com>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "nsEditorSpellCheck.h"
|
|
|
|
|
|
|
|
#include "nsTextServicesCID.h"
|
|
|
|
#include "nsITextServicesDocument.h"
|
|
|
|
#include "nsISpellChecker.h"
|
|
|
|
|
|
|
|
#include "nsIComponentManager.h"
|
|
|
|
#include "nsXPIDLString.h"
|
2002-11-23 01:26:58 +00:00
|
|
|
#include "nsIPrefBranch.h"
|
|
|
|
#include "nsIPrefService.h"
|
|
|
|
#include "nsISupportsPrimitives.h"
|
2002-10-11 23:46:57 +00:00
|
|
|
#include "nsIServiceManagerUtils.h"
|
|
|
|
#include "nsIChromeRegistry.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
#include "nsReadableUtils.h"
|
2002-12-10 15:03:04 +00:00
|
|
|
#include "nsComposeTxtSrvFilter.h"
|
2002-10-11 23:46:57 +00:00
|
|
|
|
|
|
|
static NS_DEFINE_CID(kCTextServicesDocumentCID, NS_TEXTSERVICESDOCUMENT_CID);
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS1(nsEditorSpellCheck, nsIEditorSpellCheck);
|
|
|
|
|
|
|
|
nsEditorSpellCheck::nsEditorSpellCheck()
|
|
|
|
: mSuggestedWordIndex(0)
|
|
|
|
, mDictionaryIndex(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsEditorSpellCheck::~nsEditorSpellCheck()
|
|
|
|
{
|
|
|
|
// Make sure we blow the spellchecker away, just in
|
|
|
|
// case it hasn't been destroyed already.
|
|
|
|
mSpellChecker = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::InitSpellChecker(nsIEditor* editor)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// We can spell check with any editor type
|
|
|
|
nsCOMPtr<nsITextServicesDocument>tsDoc;
|
|
|
|
rv = nsComponentManager::CreateInstance(kCTextServicesDocumentCID,
|
|
|
|
nsnull,
|
|
|
|
NS_GET_IID(nsITextServicesDocument),
|
|
|
|
(void **)getter_AddRefs(tsDoc));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (!tsDoc)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
2002-12-10 15:03:04 +00:00
|
|
|
tsDoc->SetFilter(mTxtSrvFilter);
|
|
|
|
|
2002-10-11 23:46:57 +00:00
|
|
|
// Pass the editor to the text services document
|
|
|
|
rv = tsDoc->InitWithEditor(editor);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = nsComponentManager::CreateInstance(NS_SPELLCHECKER_CONTRACTID,
|
|
|
|
nsnull,
|
|
|
|
NS_GET_IID(nsISpellChecker),
|
|
|
|
(void **)getter_AddRefs(mSpellChecker));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
rv = mSpellChecker->SetDocument(tsDoc, PR_TRUE);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Tell the spellchecker what dictionary to use:
|
|
|
|
|
|
|
|
nsXPIDLString dictName;
|
|
|
|
|
2002-11-23 01:26:58 +00:00
|
|
|
nsCOMPtr<nsIPrefBranch> prefBranch =
|
|
|
|
do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
2002-10-11 23:46:57 +00:00
|
|
|
|
2002-11-23 01:26:58 +00:00
|
|
|
if (NS_SUCCEEDED(rv) && prefBranch) {
|
|
|
|
nsCOMPtr<nsISupportsString> prefString;
|
|
|
|
rv = prefBranch->GetComplexValue("spellchecker.dictionary",
|
|
|
|
NS_GET_IID(nsISupportsString),
|
|
|
|
getter_AddRefs(prefString));
|
|
|
|
if (prefString) {
|
|
|
|
prefString->ToString(getter_Copies(dictName));
|
|
|
|
}
|
|
|
|
}
|
2002-10-11 23:46:57 +00:00
|
|
|
|
|
|
|
if (NS_FAILED(rv) || dictName.IsEmpty())
|
|
|
|
{
|
|
|
|
// Prefs didn't give us a dictionary name, so just get the current
|
|
|
|
// locale and use that as the default dictionary name!
|
|
|
|
|
|
|
|
nsCOMPtr<nsIXULChromeRegistry> packageRegistry =
|
|
|
|
do_GetService(NS_CHROMEREGISTRY_CONTRACTID, &rv);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && packageRegistry) {
|
|
|
|
nsCAutoString utf8DictName;
|
|
|
|
rv = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("navigator"),
|
|
|
|
utf8DictName);
|
|
|
|
dictName = NS_ConvertUTF8toUCS2(utf8DictName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && !dictName.IsEmpty())
|
|
|
|
SetCurrentDictionary(dictName.get());
|
|
|
|
|
|
|
|
// If an error was thrown while checking the dictionary pref, just
|
|
|
|
// fail silently so that the spellchecker dialog is allowed to come
|
|
|
|
// up. The user can manually reset the language to their choice on
|
|
|
|
// the dialog if it is wrong.
|
|
|
|
|
|
|
|
DeleteSuggestedWordList();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetNextMisspelledWord(PRUnichar **aNextMisspelledWord)
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
nsAutoString nextMisspelledWord;
|
|
|
|
|
|
|
|
DeleteSuggestedWordList();
|
|
|
|
nsresult rv = mSpellChecker->NextMisspelledWord(&nextMisspelledWord,
|
|
|
|
&mSuggestedWordList);
|
|
|
|
|
|
|
|
*aNextMisspelledWord = ToNewUnicode(nextMisspelledWord);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetSuggestedWord(PRUnichar **aSuggestedWord)
|
|
|
|
{
|
|
|
|
nsAutoString word;
|
|
|
|
if ( mSuggestedWordIndex < mSuggestedWordList.Count())
|
|
|
|
{
|
|
|
|
mSuggestedWordList.StringAt(mSuggestedWordIndex, word);
|
|
|
|
mSuggestedWordIndex++;
|
|
|
|
} else {
|
|
|
|
// A blank string signals that there are no more strings
|
|
|
|
word.SetLength(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
*aSuggestedWord = ToNewUnicode(word);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::CheckCurrentWord(const PRUnichar *aSuggestedWord,
|
|
|
|
PRBool *aIsMisspelled)
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
nsAutoString suggestedWord(aSuggestedWord);
|
|
|
|
DeleteSuggestedWordList();
|
|
|
|
return mSpellChecker->CheckWord(&suggestedWord, aIsMisspelled,
|
|
|
|
&mSuggestedWordList);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::ReplaceWord(const PRUnichar *aMisspelledWord,
|
|
|
|
const PRUnichar *aReplaceWord,
|
|
|
|
PRBool allOccurrences)
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
nsAutoString misspelledWord(aMisspelledWord);
|
|
|
|
nsAutoString replaceWord(aReplaceWord);
|
|
|
|
return mSpellChecker->Replace(&misspelledWord, &replaceWord, allOccurrences);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::IgnoreWordAllOccurrences(const PRUnichar *aWord)
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
nsAutoString word(aWord);
|
|
|
|
return mSpellChecker->IgnoreAll(&word);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetPersonalDictionary()
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
// We can spell check with any editor type
|
|
|
|
mDictionaryList.Clear();
|
|
|
|
mDictionaryIndex = 0;
|
|
|
|
return mSpellChecker->GetPersonalDictionary(&mDictionaryList);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetPersonalDictionaryWord(PRUnichar **aDictionaryWord)
|
|
|
|
{
|
|
|
|
nsAutoString word;
|
|
|
|
if ( mDictionaryIndex < mDictionaryList.Count())
|
|
|
|
{
|
|
|
|
mDictionaryList.StringAt(mDictionaryIndex, word);
|
|
|
|
mDictionaryIndex++;
|
|
|
|
} else {
|
|
|
|
// A blank string signals that there are no more strings
|
|
|
|
word.SetLength(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
*aDictionaryWord = ToNewUnicode(word);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::AddWordToDictionary(const PRUnichar *aWord)
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
nsAutoString word(aWord);
|
|
|
|
return mSpellChecker->AddWordToPersonalDictionary(&word);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::RemoveWordFromDictionary(const PRUnichar *aWord)
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
nsAutoString word(aWord);
|
|
|
|
return mSpellChecker->RemoveWordFromPersonalDictionary(&word);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetDictionaryList(PRUnichar ***aDictionaryList, PRUint32 *aCount)
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
if (!aDictionaryList || !aCount)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
*aDictionaryList = 0;
|
|
|
|
*aCount = 0;
|
|
|
|
|
|
|
|
nsStringArray dictList;
|
|
|
|
|
|
|
|
nsresult rv = mSpellChecker->GetDictionaryList(&dictList);
|
|
|
|
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
PRUnichar **tmpPtr = 0;
|
|
|
|
|
|
|
|
if (dictList.Count() < 1)
|
|
|
|
{
|
|
|
|
// If there are no dictionaries, return an array containing
|
|
|
|
// one element and a count of one.
|
|
|
|
|
|
|
|
tmpPtr = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *));
|
|
|
|
|
|
|
|
if (!tmpPtr)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
*tmpPtr = 0;
|
|
|
|
*aDictionaryList = tmpPtr;
|
|
|
|
*aCount = 0;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpPtr = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * dictList.Count());
|
|
|
|
|
|
|
|
if (!tmpPtr)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
*aDictionaryList = tmpPtr;
|
|
|
|
*aCount = dictList.Count();
|
|
|
|
|
|
|
|
nsAutoString dictStr;
|
|
|
|
|
|
|
|
PRUint32 i;
|
|
|
|
|
|
|
|
for (i = 0; i < *aCount; i++)
|
|
|
|
{
|
|
|
|
dictList.StringAt(i, dictStr);
|
|
|
|
tmpPtr[i] = ToNewUnicode(dictStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetCurrentDictionary(PRUnichar **aDictionary)
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
if (!aDictionary)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
*aDictionary = 0;
|
|
|
|
|
|
|
|
nsAutoString dictStr;
|
|
|
|
nsresult rv = mSpellChecker->GetCurrentDictionary(&dictStr);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
*aDictionary = ToNewUnicode(dictStr);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::SetCurrentDictionary(const PRUnichar *aDictionary)
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
if (!aDictionary)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsAutoString dictStr(aDictionary);
|
|
|
|
return mSpellChecker->SetCurrentDictionary(&dictStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::UninitSpellChecker()
|
|
|
|
{
|
|
|
|
if (!mSpellChecker)
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
|
|
|
|
// Save the last used dictionary to the user's preferences.
|
|
|
|
nsresult rv;
|
2002-11-23 01:26:58 +00:00
|
|
|
nsCOMPtr<nsIPrefBranch> prefBranch =
|
|
|
|
do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
2002-10-11 23:46:57 +00:00
|
|
|
|
2002-11-23 01:26:58 +00:00
|
|
|
if (NS_SUCCEEDED(rv) && prefBranch)
|
2002-10-11 23:46:57 +00:00
|
|
|
{
|
|
|
|
PRUnichar *dictName = nsnull;
|
|
|
|
|
|
|
|
rv = GetCurrentDictionary(&dictName);
|
|
|
|
|
2002-11-23 01:26:58 +00:00
|
|
|
if (NS_SUCCEEDED(rv) && dictName && *dictName) {
|
|
|
|
nsCOMPtr<nsISupportsString> prefString =
|
|
|
|
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && prefString) {
|
|
|
|
prefString->SetData(nsDependentString(dictName));
|
|
|
|
rv = prefBranch->SetComplexValue("spellchecker.dictionary",
|
|
|
|
NS_GET_IID(nsISupportsString),
|
|
|
|
prefString);
|
|
|
|
}
|
|
|
|
}
|
2002-10-11 23:46:57 +00:00
|
|
|
|
|
|
|
if (dictName)
|
|
|
|
nsMemory::Free(dictName);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cleanup - kill the spell checker
|
|
|
|
DeleteSuggestedWordList();
|
|
|
|
mDictionaryList.Clear();
|
|
|
|
mDictionaryIndex = 0;
|
|
|
|
mSpellChecker = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-12-10 15:03:04 +00:00
|
|
|
/* void setFilter (in nsITextServicesFilter filter); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::SetFilter(nsITextServicesFilter *filter)
|
|
|
|
{
|
|
|
|
mTxtSrvFilter = filter;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-10-11 23:46:57 +00:00
|
|
|
nsresult
|
|
|
|
nsEditorSpellCheck::DeleteSuggestedWordList()
|
|
|
|
{
|
|
|
|
mSuggestedWordList.Clear();
|
|
|
|
mSuggestedWordIndex = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|