2007-03-22 10:30:00 -07: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>
|
|
|
|
* Neil Deakin <neil@mozdevgroup.com>
|
|
|
|
* Brett Wilson <brettw@gmail.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"
|
|
|
|
|
2011-08-12 12:12:45 -07:00
|
|
|
#include "nsStyleUtil.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIDOMElement.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsITextServicesDocument.h"
|
|
|
|
#include "nsISpellChecker.h"
|
|
|
|
#include "nsISelection.h"
|
|
|
|
#include "nsIDOMRange.h"
|
|
|
|
#include "nsIEditor.h"
|
2011-08-12 12:12:45 -07:00
|
|
|
#include "nsIHTMLEditor.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "nsIComponentManager.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "nsIChromeRegistry.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
#include "nsReadableUtils.h"
|
|
|
|
#include "nsITextServicesFilter.h"
|
2011-08-12 12:12:45 -07:00
|
|
|
#include "nsUnicharUtils.h"
|
2010-05-14 02:24:41 -07:00
|
|
|
#include "mozilla/Services.h"
|
2011-06-16 17:59:29 -07:00
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
|
|
|
|
using namespace mozilla;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-08-15 10:54:03 -07:00
|
|
|
class UpdateDictionnaryHolder {
|
|
|
|
private:
|
|
|
|
nsEditorSpellCheck* mSpellCheck;
|
|
|
|
public:
|
|
|
|
UpdateDictionnaryHolder(nsEditorSpellCheck* esc): mSpellCheck(esc) {
|
|
|
|
if (mSpellCheck) {
|
|
|
|
mSpellCheck->BeginUpdateDictionary();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
~UpdateDictionnaryHolder() {
|
|
|
|
if (mSpellCheck) {
|
|
|
|
mSpellCheck->EndUpdateDictionary();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-06-02 11:33:47 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEditorSpellCheck)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEditorSpellCheck)
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsEditorSpellCheck)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIEditorSpellCheck)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditorSpellCheck)
|
|
|
|
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsEditorSpellCheck)
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_2(nsEditorSpellCheck,
|
|
|
|
mSpellChecker,
|
|
|
|
mTxtSrvFilter)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsEditorSpellCheck::nsEditorSpellCheck()
|
|
|
|
: mSuggestedWordIndex(0)
|
|
|
|
, mDictionaryIndex(0)
|
2011-08-15 10:54:03 -07:00
|
|
|
, mUpdateDictionaryRunning(PR_FALSE)
|
|
|
|
, mDictWasSetManually(PR_FALSE)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsEditorSpellCheck::~nsEditorSpellCheck()
|
|
|
|
{
|
|
|
|
// Make sure we blow the spellchecker away, just in
|
|
|
|
// case it hasn't been destroyed already.
|
|
|
|
mSpellChecker = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The problem is that if the spell checker does not exist, we can not tell
|
|
|
|
// which dictionaries are installed. This function works around the problem,
|
|
|
|
// allowing callers to ask if we can spell check without actually doing so (and
|
|
|
|
// enabling or disabling UI as necessary). This just creates a spellcheck
|
|
|
|
// object if needed and asks it for the dictionary list.
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::CanSpellCheck(PRBool* _retval)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsISpellChecker> spellChecker;
|
|
|
|
if (! mSpellChecker) {
|
|
|
|
spellChecker = do_CreateInstance(NS_SPELLCHECKER_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
} else {
|
|
|
|
spellChecker = mSpellChecker;
|
|
|
|
}
|
2009-01-18 12:14:14 -08:00
|
|
|
nsTArray<nsString> dictList;
|
2007-03-22 10:30:00 -07:00
|
|
|
rv = spellChecker->GetDictionaryList(&dictList);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2009-01-18 12:14:14 -08:00
|
|
|
*_retval = (dictList.Length() > 0);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::InitSpellChecker(nsIEditor* aEditor, PRBool aEnableSelectionChecking)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// We can spell check with any editor type
|
|
|
|
nsCOMPtr<nsITextServicesDocument>tsDoc =
|
|
|
|
do_CreateInstance("@mozilla.org/textservices/textservicesdocument;1", &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(tsDoc, NS_ERROR_NULL_POINTER);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
tsDoc->SetFilter(mTxtSrvFilter);
|
|
|
|
|
|
|
|
// Pass the editor to the text services document
|
|
|
|
rv = tsDoc->InitWithEditor(aEditor);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (aEnableSelectionChecking) {
|
|
|
|
// Find out if the section is collapsed or not.
|
|
|
|
// If it isn't, we want to spellcheck just the selection.
|
|
|
|
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
|
|
|
|
|
|
rv = aEditor->GetSelection(getter_AddRefs(selection));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
PRInt32 count = 0;
|
|
|
|
|
|
|
|
rv = selection->GetRangeCount(&count);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (count > 0) {
|
|
|
|
nsCOMPtr<nsIDOMRange> range;
|
|
|
|
|
|
|
|
rv = selection->GetRangeAt(0, getter_AddRefs(range));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRBool collapsed = PR_FALSE;
|
|
|
|
rv = range->GetCollapsed(&collapsed);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (!collapsed) {
|
|
|
|
// We don't want to touch the range in the selection,
|
|
|
|
// so create a new copy of it.
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMRange> rangeBounds;
|
|
|
|
rv = range->CloneRange(getter_AddRefs(rangeBounds));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
NS_ENSURE_TRUE(rangeBounds, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
// Make sure the new range spans complete words.
|
|
|
|
|
|
|
|
rv = tsDoc->ExpandRangeToWordBoundaries(rangeBounds);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Now tell the text services that you only want
|
|
|
|
// to iterate over the text in this range.
|
|
|
|
|
|
|
|
rv = tsDoc->SetExtent(rangeBounds);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mSpellChecker = do_CreateInstance(NS_SPELLCHECKER_CONTRACTID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NULL_POINTER);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
rv = mSpellChecker->SetDocument(tsDoc, PR_TRUE);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2011-08-12 12:12:45 -07:00
|
|
|
// do not fail if UpdateCurrentDictionary fails because this method may
|
|
|
|
// succeed later.
|
|
|
|
UpdateCurrentDictionary(aEditor);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetNextMisspelledWord(PRUnichar **aNextMisspelledWord)
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsAutoString nextMisspelledWord;
|
|
|
|
|
|
|
|
DeleteSuggestedWordList();
|
2008-02-28 07:28:37 -08:00
|
|
|
// Beware! This may flush notifications via synchronous
|
|
|
|
// ScrollSelectionIntoView.
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv = mSpellChecker->NextMisspelledWord(nextMisspelledWord,
|
|
|
|
&mSuggestedWordList);
|
|
|
|
|
|
|
|
*aNextMisspelledWord = ToNewUnicode(nextMisspelledWord);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetSuggestedWord(PRUnichar **aSuggestedWord)
|
|
|
|
{
|
|
|
|
nsAutoString word;
|
2009-01-18 12:14:14 -08:00
|
|
|
if ( mSuggestedWordIndex < PRInt32(mSuggestedWordList.Length()))
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-01-18 12:14:14 -08:00
|
|
|
*aSuggestedWord = ToNewUnicode(mSuggestedWordList[mSuggestedWordIndex]);
|
2007-03-22 10:30:00 -07:00
|
|
|
mSuggestedWordIndex++;
|
|
|
|
} else {
|
|
|
|
// A blank string signals that there are no more strings
|
2009-01-18 12:14:14 -08:00
|
|
|
*aSuggestedWord = ToNewUnicode(EmptyString());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::CheckCurrentWord(const PRUnichar *aSuggestedWord,
|
|
|
|
PRBool *aIsMisspelled)
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
DeleteSuggestedWordList();
|
|
|
|
return mSpellChecker->CheckWord(nsDependentString(aSuggestedWord),
|
|
|
|
aIsMisspelled, &mSuggestedWordList);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::CheckCurrentWordNoSuggest(const PRUnichar *aSuggestedWord,
|
|
|
|
PRBool *aIsMisspelled)
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return mSpellChecker->CheckWord(nsDependentString(aSuggestedWord),
|
|
|
|
aIsMisspelled, nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::ReplaceWord(const PRUnichar *aMisspelledWord,
|
|
|
|
const PRUnichar *aReplaceWord,
|
|
|
|
PRBool allOccurrences)
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return mSpellChecker->Replace(nsDependentString(aMisspelledWord),
|
|
|
|
nsDependentString(aReplaceWord), allOccurrences);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::IgnoreWordAllOccurrences(const PRUnichar *aWord)
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return mSpellChecker->IgnoreAll(nsDependentString(aWord));
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetPersonalDictionary()
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// We can spell check with any editor type
|
|
|
|
mDictionaryList.Clear();
|
|
|
|
mDictionaryIndex = 0;
|
|
|
|
return mSpellChecker->GetPersonalDictionary(&mDictionaryList);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetPersonalDictionaryWord(PRUnichar **aDictionaryWord)
|
|
|
|
{
|
2009-01-18 12:14:14 -08:00
|
|
|
if ( mDictionaryIndex < PRInt32( mDictionaryList.Length()))
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-01-18 12:14:14 -08:00
|
|
|
*aDictionaryWord = ToNewUnicode(mDictionaryList[mDictionaryIndex]);
|
2007-03-22 10:30:00 -07:00
|
|
|
mDictionaryIndex++;
|
|
|
|
} else {
|
|
|
|
// A blank string signals that there are no more strings
|
2009-01-18 12:14:14 -08:00
|
|
|
*aDictionaryWord = ToNewUnicode(EmptyString());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::AddWordToDictionary(const PRUnichar *aWord)
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return mSpellChecker->AddWordToPersonalDictionary(nsDependentString(aWord));
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::RemoveWordFromDictionary(const PRUnichar *aWord)
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return mSpellChecker->RemoveWordFromPersonalDictionary(nsDependentString(aWord));
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetDictionaryList(PRUnichar ***aDictionaryList, PRUint32 *aCount)
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(aDictionaryList && aCount, NS_ERROR_NULL_POINTER);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
*aDictionaryList = 0;
|
|
|
|
*aCount = 0;
|
|
|
|
|
2009-01-18 12:14:14 -08:00
|
|
|
nsTArray<nsString> dictList;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsresult rv = mSpellChecker->GetDictionaryList(&dictList);
|
|
|
|
|
2010-06-17 13:44:35 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRUnichar **tmpPtr = 0;
|
|
|
|
|
2009-01-18 12:14:14 -08:00
|
|
|
if (dictList.Length() < 1)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// If there are no dictionaries, return an array containing
|
|
|
|
// one element and a count of one.
|
|
|
|
|
|
|
|
tmpPtr = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *));
|
|
|
|
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(tmpPtr, NS_ERROR_OUT_OF_MEMORY);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
*tmpPtr = 0;
|
|
|
|
*aDictionaryList = tmpPtr;
|
|
|
|
*aCount = 0;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-01-18 12:14:14 -08:00
|
|
|
tmpPtr = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * dictList.Length());
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(tmpPtr, NS_ERROR_OUT_OF_MEMORY);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
*aDictionaryList = tmpPtr;
|
2009-01-18 12:14:14 -08:00
|
|
|
*aCount = dictList.Length();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRUint32 i;
|
|
|
|
|
|
|
|
for (i = 0; i < *aCount; i++)
|
|
|
|
{
|
2009-01-18 12:14:14 -08:00
|
|
|
tmpPtr[i] = ToNewUnicode(dictList[i]);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::GetCurrentDictionary(PRUnichar **aDictionary)
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(aDictionary, NS_ERROR_NULL_POINTER);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
*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)
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(aDictionary, NS_ERROR_NULL_POINTER);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-08-15 10:54:03 -07:00
|
|
|
if (!mUpdateDictionaryRunning) {
|
|
|
|
mDictWasSetManually = PR_TRUE;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
return mSpellChecker->SetCurrentDictionary(nsDependentString(aDictionary));
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::UninitSpellChecker()
|
|
|
|
{
|
2010-06-17 13:40:48 -07:00
|
|
|
NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Cleanup - kill the spell checker
|
|
|
|
DeleteSuggestedWordList();
|
|
|
|
mDictionaryList.Clear();
|
|
|
|
mDictionaryIndex = 0;
|
|
|
|
mSpellChecker = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-08-15 10:54:03 -07:00
|
|
|
// Save the last set dictionary to the user's preferences.
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::SaveDefaultDictionary()
|
|
|
|
{
|
2011-08-15 10:54:03 -07:00
|
|
|
if (!mDictWasSetManually) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2011-06-16 17:59:29 -07:00
|
|
|
PRUnichar *dictName = nsnull;
|
|
|
|
nsresult rv = GetCurrentDictionary(&dictName);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2011-06-16 17:59:29 -07:00
|
|
|
if (NS_SUCCEEDED(rv) && dictName && *dictName) {
|
|
|
|
rv = Preferences::SetString("spellchecker.dictionary", dictName);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2011-06-16 17:59:29 -07:00
|
|
|
|
|
|
|
if (dictName) {
|
|
|
|
nsMemory::Free(dictName);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* void setFilter (in nsITextServicesFilter filter); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::SetFilter(nsITextServicesFilter *filter)
|
|
|
|
{
|
|
|
|
mTxtSrvFilter = filter;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsEditorSpellCheck::DeleteSuggestedWordList()
|
|
|
|
{
|
|
|
|
mSuggestedWordList.Clear();
|
|
|
|
mSuggestedWordIndex = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2011-08-12 12:12:45 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditor* aEditor)
|
|
|
|
{
|
2011-08-15 10:54:03 -07:00
|
|
|
if (mDictWasSetManually) { // user has set dictionary manually; we better not change it.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-08-12 12:12:45 -07:00
|
|
|
nsresult rv;
|
|
|
|
|
2011-08-15 10:54:03 -07:00
|
|
|
UpdateDictionnaryHolder holder(this);
|
|
|
|
|
2011-08-12 12:12:45 -07:00
|
|
|
// Tell the spellchecker what dictionary to use:
|
|
|
|
nsAutoString dictName;
|
|
|
|
|
|
|
|
// First, try to get language with html5 algorithm
|
|
|
|
nsAutoString editorLang;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> rootContent;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(aEditor);
|
|
|
|
if (htmlEditor) {
|
|
|
|
rootContent = htmlEditor->GetActiveEditingHost();
|
|
|
|
} else {
|
|
|
|
nsCOMPtr<nsIDOMElement> rootElement;
|
|
|
|
rv = aEditor->GetRootElement(getter_AddRefs(rootElement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rootContent = do_QueryInterface(rootElement);
|
|
|
|
}
|
|
|
|
NS_ENSURE_TRUE(rootContent, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
rootContent->GetLang(editorLang);
|
|
|
|
|
|
|
|
if (editorLang.IsEmpty()) {
|
|
|
|
nsCOMPtr<nsIDocument> doc = rootContent->GetCurrentDoc();
|
|
|
|
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
|
|
|
doc->GetContentLanguage(editorLang);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!editorLang.IsEmpty()) {
|
|
|
|
dictName.Assign(editorLang);
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, get language from preferences
|
|
|
|
if (dictName.IsEmpty()) {
|
|
|
|
dictName.Assign(Preferences::GetLocalizedString("spellchecker.dictionary"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (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 =
|
|
|
|
mozilla::services::GetXULChromeRegistryService();
|
|
|
|
|
|
|
|
if (packageRegistry) {
|
|
|
|
nsCAutoString utf8DictName;
|
|
|
|
rv = packageRegistry->GetSelectedLocale(NS_LITERAL_CSTRING("global"),
|
|
|
|
utf8DictName);
|
|
|
|
AppendUTF8toUTF16(utf8DictName, dictName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SetCurrentDictionary(NS_LITERAL_STRING("").get());
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && !dictName.IsEmpty()) {
|
|
|
|
rv = SetCurrentDictionary(dictName.get());
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// required dictionary was not available. Try to get a dictionary
|
|
|
|
// matching at least language part of dictName: If required dictionary is
|
|
|
|
// "aa-bb", we try "aa", then we try any available dictionary aa-XX
|
|
|
|
nsAutoString langCode;
|
|
|
|
PRInt32 dashIdx = dictName.FindChar('-');
|
|
|
|
if (dashIdx != -1) {
|
|
|
|
langCode.Assign(Substring(dictName, 0, dashIdx));
|
|
|
|
// try to use langCode
|
|
|
|
rv = SetCurrentDictionary(langCode.get());
|
|
|
|
} else {
|
|
|
|
langCode.Assign(dictName);
|
|
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// loop over avaible dictionaries; if we find one with required
|
|
|
|
// language, use it
|
|
|
|
nsTArray<nsString> dictList;
|
|
|
|
rv = mSpellChecker->GetDictionaryList(&dictList);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsDefaultStringComparator comparator;
|
|
|
|
PRInt32 i, count = dictList.Length();
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
nsAutoString dictStr(dictList.ElementAt(i));
|
|
|
|
if (nsStyleUtil::DashMatchCompare(dictStr, langCode, comparator) &&
|
|
|
|
NS_SUCCEEDED(SetCurrentDictionary(dictStr.get()))) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have not set dictionary, and the editable element doesn't have a
|
|
|
|
// lang attribute, we try to get a dictionary. First try, en-US. If it does
|
|
|
|
// not work, pick the first one.
|
|
|
|
if (editorLang.IsEmpty()) {
|
2011-08-15 10:54:03 -07:00
|
|
|
nsAutoString currentDictionary;
|
|
|
|
rv = mSpellChecker->GetCurrentDictionary(currentDictionary);
|
|
|
|
if (NS_FAILED(rv) || currentDictionary.IsEmpty()) {
|
2011-08-12 12:12:45 -07:00
|
|
|
rv = SetCurrentDictionary(NS_LITERAL_STRING("en-US").get());
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
nsTArray<nsString> dictList;
|
|
|
|
rv = mSpellChecker->GetDictionaryList(&dictList);
|
|
|
|
if (NS_SUCCEEDED(rv) && dictList.Length() > 0) {
|
|
|
|
SetCurrentDictionary(dictList[0].get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If an error was thrown while setting the dictionary, 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;
|
|
|
|
}
|