diff options
Diffstat (limited to 'lingucomponent/source/spellcheck')
9 files changed, 2148 insertions, 0 deletions
diff --git a/lingucomponent/source/spellcheck/macosxspell/macreg.cxx b/lingucomponent/source/spellcheck/macosxspell/macreg.cxx new file mode 100644 index 000000000000..b60ffffe42e9 --- /dev/null +++ b/lingucomponent/source/spellcheck/macosxspell/macreg.cxx @@ -0,0 +1,87 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_lingucomponent.hxx" + + +#include <cppuhelper/factory.hxx> // helper for factories +#include <rtl/string.hxx> + +#include <com/sun/star/registry/XRegistryKey.hpp> + +using namespace rtl; +using namespace com::sun::star::lang; +using namespace com::sun::star::registry; + +//////////////////////////////////////// +// declaration of external RegEntry-functions defined by the service objects +// + +extern sal_Bool SAL_CALL MacSpellChecker_writeInfo( + void * /*pServiceManager*/, XRegistryKey * pRegistryKey ); + +extern void * SAL_CALL MacSpellChecker_getFactory( + const sal_Char * pImplName, + XMultiServiceFactory * pServiceManager, + void * /*pRegistryKey*/ ); + +//////////////////////////////////////// +// definition of the two functions that are used to provide the services +// + +extern "C" +{ + +sal_Bool SAL_CALL component_writeInfo( + void * pServiceManager, XRegistryKey * pRegistryKey ) +{ + return MacSpellChecker_writeInfo( pServiceManager, pRegistryKey ); +} + +void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) +{ + void * pRet = NULL; + pRet = MacSpellChecker_getFactory( + pImplName, + reinterpret_cast< XMultiServiceFactory * >( pServiceManager ), + pRegistryKey ); + + return pRet; +} + +} + +/////////////////////////////////////////////////////////////////////////// + diff --git a/lingucomponent/source/spellcheck/macosxspell/macspellimp.cxx b/lingucomponent/source/spellcheck/macosxspell/macspellimp.cxx new file mode 100644 index 000000000000..70996793c186 --- /dev/null +++ b/lingucomponent/source/spellcheck/macosxspell/macspellimp.cxx @@ -0,0 +1,693 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_lingucomponent.hxx" +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> + +#include <com/sun/star/linguistic2/SpellFailure.hpp> +#include <cppuhelper/factory.hxx> // helper for factories +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <tools/debug.hxx> +#include <unotools/processfactory.hxx> +#include <osl/mutex.hxx> + +//#include <hunspell.hxx> +#include <dictmgr.hxx> +#include <macspellimp.hxx> + +//#include <linguistic/lngprops.hxx> +#include <linguistic/spelldta.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/useroptions.hxx> +#include <osl/file.hxx> +#include <rtl/ustrbuf.hxx> + + +using namespace utl; +using namespace osl; +using namespace rtl; +using namespace com::sun::star; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::linguistic2; +using namespace linguistic; +/////////////////////////////////////////////////////////////////////////// +// dbg_dump for development +#if OSL_DEBUG_LEVEL > 1 +#include <rtl/strbuf.hxx> +#include <rtl/ustring.hxx> + +const sal_Char *dbg_dump(const rtl::OString &rStr) +{ + static rtl::OStringBuffer aStr; + + aStr = rtl::OStringBuffer(rStr); + aStr.append(static_cast<char>(0)); + return aStr.getStr(); +} + +const sal_Char *dbg_dump(const rtl::OUString &rStr) +{ + return dbg_dump(rtl::OUStringToOString(rStr, RTL_TEXTENCODING_UTF8)); +} + +const sal_Char *dbg_dump(rtl_String *pStr) +{ + return dbg_dump(rtl::OString(pStr)); +} + +const sal_Char *dbg_dump(rtl_uString *pStr) +{ + return dbg_dump(rtl::OUString(pStr)); +} + +#endif +/////////////////////////////////////////////////////////////////////////// + +MacSpellChecker::MacSpellChecker() : + aEvtListeners ( GetLinguMutex() ) +{ +// aDicts = NULL; + aDEncs = NULL; + aDLocs = NULL; + aDNames = NULL; + bDisposing = FALSE; + pPropHelper = NULL; + numdict = 0; + NSApplicationLoad(); + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + macSpell = [NSSpellChecker sharedSpellChecker]; + macTag = [NSSpellChecker uniqueSpellDocumentTag]; + [pool release]; +} + + +MacSpellChecker::~MacSpellChecker() +{ + // if (aDicts) { + // for (int i = 0; i < numdict; i++) { + // if (aDicts[i]) delete aDicts[i]; + // aDicts[i] = NULL; + // } + // delete[] aDicts; + // } + // aDicts = NULL; + numdict = 0; + if (aDEncs) delete[] aDEncs; + aDEncs = NULL; + if (aDLocs) delete[] aDLocs; + aDLocs = NULL; + if (aDNames) delete[] aDNames; + aDNames = NULL; + if (pPropHelper) + pPropHelper->RemoveAsPropListener(); +} + + +PropertyHelper_Spell & MacSpellChecker::GetPropHelper_Impl() +{ + if (!pPropHelper) + { + Reference< XPropertySet > xPropSet( GetLinguProperties(), UNO_QUERY ); + + pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet ); + xPropHelper = pPropHelper; + pPropHelper->AddAsPropListener(); //! after a reference is established + } + return *pPropHelper; +} + + +Sequence< Locale > SAL_CALL MacSpellChecker::getLocales() + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + // this routine should return the locales supported by the installed + // dictionaries. So here we need to parse both the user edited + // dictionary list and the shared dictionary list + // to see what dictionaries the admin/user has installed + + int numusr; // number of user dictionary entries + int numshr; // number of shared dictionary entries + dictentry * spdict; // shared dict entry pointer + dictentry * updict; // user dict entry pointer + SvtPathOptions aPathOpt; + rtl_TextEncoding aEnc = RTL_TEXTENCODING_UTF8; + + std::vector<objc_object *> postspdict; + //std::vector<dictentry *> postspdict; + std::vector<dictentry *> postupdict; + + + if (!numdict) { + + // invoke a dictionary manager to get the user dictionary list + // TODO How on Mac OS X? + + // invoke a second dictionary manager to get the shared dictionary list + NSArray *aLocales = [NSLocale availableLocaleIdentifiers]; + + //Test for existence of the dictionaries + for (unsigned int i = 0; i < [aLocales count]; i++) + { + if( [macSpell setLanguage:[aLocales objectAtIndex:i] ] ) + { + postspdict.push_back( [ aLocales objectAtIndex:i ] ); + } + } + + numusr = postupdict.size(); + numshr = postspdict.size(); + + // we really should merge these and remove duplicates but since + // users can name their dictionaries anything they want it would + // be impossible to know if a real duplication exists unless we + // add some unique key to each myspell dictionary + numdict = numshr + numusr; + + if (numdict) { + aDLocs = new Locale [numdict]; + aDEncs = new rtl_TextEncoding [numdict]; + aDNames = new OUString [numdict]; + aSuppLocales.realloc(numdict); + Locale * pLocale = aSuppLocales.getArray(); + int numlocs = 0; + int newloc; + int i,j; + int k = 0; + + //first add the user dictionaries + //TODO for MAC? + + // now add the shared dictionaries + for (i = 0; i < numshr; i++) { + NSDictionary *aLocDict = [ NSLocale componentsFromLocaleIdentifier:postspdict[i] ]; + NSString* aLang = [ aLocDict objectForKey:NSLocaleLanguageCode ]; + NSString* aCountry = [ aLocDict objectForKey:NSLocaleCountryCode ]; + OUString lang([aLang cStringUsingEncoding: NSUTF8StringEncoding], [aLang length], aEnc); + OUString country([ aCountry cStringUsingEncoding: NSUTF8StringEncoding], [aCountry length], aEnc); + Locale nLoc( lang, country, OUString() ); + newloc = 1; + //eliminate duplicates (is this needed for MacOS?) + for (j = 0; j < numlocs; j++) { + if (nLoc == pLocale[j]) newloc = 0; + } + if (newloc) { + pLocale[numlocs] = nLoc; + numlocs++; + } + aDLocs[k] = nLoc; + //pointer to Hunspell dictionary - not needed for MAC + //aDicts[k] = NULL; + aDEncs[k] = 0; + // Dictionary file names not valid for Mac Spell + //aDNames[k] = aPathOpt.GetLinguisticPath() + A2OU("/ooo/") + A2OU(postspdict[i]->filename); + k++; + } + + aSuppLocales.realloc(numlocs); + + } else { + /* no dictionary.lst found so register no dictionaries */ + numdict = 0; + //aDicts = NULL; + aDEncs = NULL; + aDLocs = NULL; + aDNames = NULL; + aSuppLocales.realloc(0); + } + + /* de-allocation of memory is handled inside the DictMgr */ + updict = NULL; + spdict = NULL; + + } + + return aSuppLocales; +} + + + +sal_Bool SAL_CALL MacSpellChecker::hasLocale(const Locale& rLocale) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + BOOL bRes = FALSE; + if (!aSuppLocales.getLength()) + getLocales(); + + INT32 nLen = aSuppLocales.getLength(); + for (INT32 i = 0; i < nLen; ++i) + { + const Locale *pLocale = aSuppLocales.getConstArray(); + if (rLocale == pLocale[i]) + { + bRes = TRUE; + break; + } + } + return bRes; +} + + +INT16 MacSpellChecker::GetSpellFailure( const OUString &rWord, const Locale &rLocale ) +{ + rtl_TextEncoding aEnc; + + // initialize a myspell object for each dictionary once + // (note: mutex is held higher up in isValid) + + + INT16 nRes = -1; + + // first handle smart quotes both single and double + OUStringBuffer rBuf(rWord); + sal_Int32 n = rBuf.getLength(); + sal_Unicode c; + for (sal_Int32 ix=0; ix < n; ix++) { + c = rBuf.charAt(ix); + if ((c == 0x201C) || (c == 0x201D)) rBuf.setCharAt(ix,(sal_Unicode)0x0022); + if ((c == 0x2018) || (c == 0x2019)) rBuf.setCharAt(ix,(sal_Unicode)0x0027); + } + OUString nWord(rBuf.makeStringAndClear()); + + if (n) + { + aEnc = 0; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSString* aNSStr = [[NSString alloc] initWithCharacters: nWord.getStr() length: nWord.getLength()]; + NSString* aLang = [[NSString alloc] initWithCharacters: rLocale.Language.getStr() length: rLocale.Language.getLength()]; + if(rLocale.Country.getLength()>0) + { + NSString* aCountry = [[NSString alloc] initWithCharacters: rLocale.Country.getStr() length: rLocale.Country.getLength()]; + NSString* aTag = @"_"; + NSString* aTaggedCountry = [aTag stringByAppendingString:aCountry]; + [aLang autorelease]; + aLang = [aLang stringByAppendingString:aTaggedCountry]; + } + + int aCount; + NSRange range = [macSpell checkSpellingOfString:aNSStr startingAt:0 language:aLang wrap:FALSE inSpellDocumentWithTag:macTag wordCount:&aCount]; + int rVal = 0; + if(range.length>0) + { + rVal = -1; + } + else + { + rVal = 1; + } + [pool release]; + if (rVal != 1) + { + nRes = SpellFailure::SPELLING_ERROR; + } else { + return -1; + } + } + return nRes; +} + + + +sal_Bool SAL_CALL + MacSpellChecker::isValid( const OUString& rWord, const Locale& rLocale, + const PropertyValues& rProperties ) + throw(IllegalArgumentException, RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (rLocale == Locale() || !rWord.getLength()) + return TRUE; + + if (!hasLocale( rLocale )) +#ifdef LINGU_EXCEPTIONS + throw( IllegalArgumentException() ); +#else + return TRUE; +#endif + + // Get property values to be used. + // These are be the default values set in the SN_LINGU_PROPERTIES + // PropertySet which are overridden by the supplied ones from the + // last argument. + // You'll probably like to use a simplier solution than the provided + // one using the PropertyHelper_Spell. + + PropertyHelper_Spell &rHelper = GetPropHelper(); + rHelper.SetTmpPropVals( rProperties ); + + INT16 nFailure = GetSpellFailure( rWord, rLocale ); + if (nFailure != -1) + { + INT16 nLang = LocaleToLanguage( rLocale ); + // postprocess result for errors that should be ignored + if ( (!rHelper.IsSpellUpperCase() && IsUpper( rWord, nLang )) + || (!rHelper.IsSpellWithDigits() && HasDigits( rWord )) + || (!rHelper.IsSpellCapitalization() + && nFailure == SpellFailure::CAPTION_ERROR) + ) + nFailure = -1; + } + + return (nFailure == -1); +} + + +Reference< XSpellAlternatives > + MacSpellChecker::GetProposals( const OUString &rWord, const Locale &rLocale ) +{ + // Retrieves the return values for the 'spell' function call in case + // of a misspelled word. + // Especially it may give a list of suggested (correct) words: + + Reference< XSpellAlternatives > xRes; + // note: mutex is held by higher up by spell which covers both + + INT16 nLang = LocaleToLanguage( rLocale ); + int count; + Sequence< OUString > aStr( 0 ); + + // first handle smart quotes (single and double) + OUStringBuffer rBuf(rWord); + sal_Int32 n = rBuf.getLength(); + sal_Unicode c; + for (sal_Int32 ix=0; ix < n; ix++) { + c = rBuf.charAt(ix); + if ((c == 0x201C) || (c == 0x201D)) rBuf.setCharAt(ix,(sal_Unicode)0x0022); + if ((c == 0x2018) || (c == 0x2019)) rBuf.setCharAt(ix,(sal_Unicode)0x0027); + } + OUString nWord(rBuf.makeStringAndClear()); + + if (n) + { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSString* aNSStr = [[NSString alloc] initWithCharacters: nWord.getStr() length: nWord.getLength()]; + NSString* aLang = [[NSString alloc] initWithCharacters: rLocale.Language.getStr() length: rLocale.Language.getLength() ]; + if(rLocale.Country.getLength()>0) + { + NSString* aCountry = [[NSString alloc] initWithCharacters: rLocale.Country.getStr() length: rLocale.Country.getLength() ]; + NSString* aTag = @"_"; + NSString* aTaggedCountry = [aTag stringByAppendingString:aCountry]; + [aLang autorelease]; + aLang = [aLang stringByAppendingString:aTaggedCountry]; + } + [macSpell setLanguage:aLang]; + NSArray *guesses = [macSpell guessesForWord:aNSStr]; + count = [guesses count]; + if (count) + { + aStr.realloc( count ); + OUString *pStr = aStr.getArray(); + for (int ii=0; ii < count; ii++) + { + // if needed add: if (suglst[ii] == NULL) continue; + NSString* guess = [guesses objectAtIndex:ii]; + OUString cvtwrd((const sal_Unicode*)[guess cStringUsingEncoding:NSUnicodeStringEncoding], (sal_Int32)[guess length]); + pStr[ii] = cvtwrd; + } + } + [pool release]; + } + + // now return an empty alternative for no suggestions or the list of alternatives if some found + SpellAlternatives *pAlt = new SpellAlternatives; + String aTmp(rWord); + pAlt->SetWordLanguage( aTmp, nLang ); + pAlt->SetFailureType( SpellFailure::SPELLING_ERROR ); + pAlt->SetAlternatives( aStr ); + xRes = pAlt; + return xRes; + +} + + + + +Reference< XSpellAlternatives > SAL_CALL + MacSpellChecker::spell( const OUString& rWord, const Locale& rLocale, + const PropertyValues& rProperties ) + throw(IllegalArgumentException, RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (rLocale == Locale() || !rWord.getLength()) + return NULL; + + if (!hasLocale( rLocale )) +#ifdef LINGU_EXCEPTIONS + throw( IllegalArgumentException() ); +#else + return NULL; +#endif + + Reference< XSpellAlternatives > xAlt; + if (!isValid( rWord, rLocale, rProperties )) + { + xAlt = GetProposals( rWord, rLocale ); + } + return xAlt; +} + + +Reference< XInterface > SAL_CALL MacSpellChecker_CreateInstance( + const Reference< XMultiServiceFactory > & /*rSMgr*/ ) + throw(Exception) +{ + + Reference< XInterface > xService = (cppu::OWeakObject*) new MacSpellChecker; + return xService; +} + + +sal_Bool SAL_CALL + MacSpellChecker::addLinguServiceEventListener( + const Reference< XLinguServiceEventListener >& rxLstnr ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + BOOL bRes = FALSE; + if (!bDisposing && rxLstnr.is()) + { + bRes = GetPropHelper().addLinguServiceEventListener( rxLstnr ); + } + return bRes; +} + + +sal_Bool SAL_CALL + MacSpellChecker::removeLinguServiceEventListener( + const Reference< XLinguServiceEventListener >& rxLstnr ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + BOOL bRes = FALSE; + if (!bDisposing && rxLstnr.is()) + { + DBG_ASSERT( xPropHelper.is(), "xPropHelper non existent" ); + bRes = GetPropHelper().removeLinguServiceEventListener( rxLstnr ); + } + return bRes; +} + + +OUString SAL_CALL + MacSpellChecker::getServiceDisplayName( const Locale& /*rLocale*/ ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + return A2OU( "Mac OS X Spell Checker" ); +} + + +void SAL_CALL + MacSpellChecker::initialize( const Sequence< Any >& rArguments ) + throw(Exception, RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!pPropHelper) + { + INT32 nLen = rArguments.getLength(); + if (2 == nLen) + { + Reference< XPropertySet > xPropSet; + rArguments.getConstArray()[0] >>= xPropSet; + //rArguments.getConstArray()[1] >>= xDicList; + + //! Pointer allows for access of the non-UNO functions. + //! And the reference to the UNO-functions while increasing + //! the ref-count and will implicitly free the memory + //! when the object is not longer used. + pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet ); + xPropHelper = pPropHelper; + pPropHelper->AddAsPropListener(); //! after a reference is established + } + else + DBG_ERROR( "wrong number of arguments in sequence" ); + + } +} + + +void SAL_CALL + MacSpellChecker::dispose() + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!bDisposing) + { + bDisposing = TRUE; + EventObject aEvtObj( (XSpellChecker *) this ); + aEvtListeners.disposeAndClear( aEvtObj ); + } +} + + +void SAL_CALL + MacSpellChecker::addEventListener( const Reference< XEventListener >& rxListener ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!bDisposing && rxListener.is()) + aEvtListeners.addInterface( rxListener ); +} + + +void SAL_CALL + MacSpellChecker::removeEventListener( const Reference< XEventListener >& rxListener ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!bDisposing && rxListener.is()) + aEvtListeners.removeInterface( rxListener ); +} + + +/////////////////////////////////////////////////////////////////////////// +// Service specific part +// + +OUString SAL_CALL MacSpellChecker::getImplementationName() + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + return getImplementationName_Static(); +} + + +sal_Bool SAL_CALL MacSpellChecker::supportsService( const OUString& ServiceName ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + Sequence< OUString > aSNL = getSupportedServiceNames(); + const OUString * pArray = aSNL.getConstArray(); + for( INT32 i = 0; i < aSNL.getLength(); i++ ) + if( pArray[i] == ServiceName ) + return TRUE; + return FALSE; +} + + +Sequence< OUString > SAL_CALL MacSpellChecker::getSupportedServiceNames() + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + return getSupportedServiceNames_Static(); +} + + +Sequence< OUString > MacSpellChecker::getSupportedServiceNames_Static() + throw() +{ + MutexGuard aGuard( GetLinguMutex() ); + + Sequence< OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich + aSNS.getArray()[0] = A2OU( SN_SPELLCHECKER ); + return aSNS; +} + + +sal_Bool SAL_CALL MacSpellChecker_writeInfo( + void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey ) +{ + + try + { + String aImpl( '/' ); + aImpl += MacSpellChecker::getImplementationName_Static().getStr(); + aImpl.AppendAscii( "/UNO/SERVICES" ); + Reference< registry::XRegistryKey > xNewKey = + pRegistryKey->createKey( aImpl ); + Sequence< OUString > aServices = + MacSpellChecker::getSupportedServiceNames_Static(); + for( INT32 i = 0; i < aServices.getLength(); i++ ) + xNewKey->createKey( aServices.getConstArray()[i] ); + + return sal_True; + } + catch(Exception &) + { + return sal_False; + } +} + + +void * SAL_CALL MacSpellChecker_getFactory( const sal_Char * pImplName, + XMultiServiceFactory * pServiceManager, void * ) +{ + void * pRet = 0; + if ( !MacSpellChecker::getImplementationName_Static().compareToAscii( pImplName ) ) + { + Reference< XSingleServiceFactory > xFactory = + cppu::createOneInstanceFactory( + pServiceManager, + MacSpellChecker::getImplementationName_Static(), + MacSpellChecker_CreateInstance, + MacSpellChecker::getSupportedServiceNames_Static()); + // acquire, because we return an interface pointer instead of a reference + xFactory->acquire(); + pRet = xFactory.get(); + } + return pRet; +} + + +/////////////////////////////////////////////////////////////////////////// diff --git a/lingucomponent/source/spellcheck/macosxspell/macspellimp.hxx b/lingucomponent/source/spellcheck/macosxspell/macspellimp.hxx new file mode 100644 index 000000000000..b3cfce92fd8b --- /dev/null +++ b/lingucomponent/source/spellcheck/macosxspell/macspellimp.hxx @@ -0,0 +1,193 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _MACSPELLIMP_H_ +#define _MACSPELLIMP_H_ + +#include <uno/lbnames.h> // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type +#include <cppuhelper/implbase1.hxx> // helper for implementations +#include <cppuhelper/implbase6.hxx> // helper for implementations + +#ifdef MACOSX +#include <premac.h> +#include <Carbon/Carbon.h> +#import <Cocoa/Cocoa.h> +#include <postmac.h> +#endif +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceDisplayName.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/linguistic2/XSpellChecker.hpp> +#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> +#include <com/sun/star/linguistic2/XLinguServiceEventBroadcaster.hpp> +#include <tools/table.hxx> + +#include <linguistic/misc.hxx> +#include <linguistic/lngprophelp.hxx> + +#include <lingutil.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::linguistic2; + + +/////////////////////////////////////////////////////////////////////////// + + +class MacSpellChecker : + public cppu::WeakImplHelper6 + < + XSpellChecker, + XLinguServiceEventBroadcaster, + XInitialization, + XComponent, + XServiceInfo, + XServiceDisplayName + > +{ + Sequence< Locale > aSuppLocales; +// Hunspell ** aDicts; + rtl_TextEncoding * aDEncs; + Locale * aDLocs; + OUString * aDNames; + sal_Int32 numdict; + NSSpellChecker * macSpell; + int macTag; //unique tag for this doc + + ::cppu::OInterfaceContainerHelper aEvtListeners; + Reference< XPropertyChangeListener > xPropHelper; + linguistic::PropertyHelper_Spell * pPropHelper; + BOOL bDisposing; + + // disallow copy-constructor and assignment-operator for now + MacSpellChecker(const MacSpellChecker &); + MacSpellChecker & operator = (const MacSpellChecker &); + + linguistic::PropertyHelper_Spell & GetPropHelper_Impl(); + linguistic::PropertyHelper_Spell & GetPropHelper() + { + return pPropHelper ? *pPropHelper : GetPropHelper_Impl(); + } + + INT16 GetSpellFailure( const OUString &rWord, const Locale &rLocale ); + Reference< XSpellAlternatives > + GetProposals( const OUString &rWord, const Locale &rLocale ); + +public: + MacSpellChecker(); + virtual ~MacSpellChecker(); + + // XSupportedLocales (for XSpellChecker) + virtual Sequence< Locale > SAL_CALL + getLocales() + throw(RuntimeException); + virtual sal_Bool SAL_CALL + hasLocale( const Locale& rLocale ) + throw(RuntimeException); + + // XSpellChecker + virtual sal_Bool SAL_CALL + isValid( const OUString& rWord, const Locale& rLocale, + const PropertyValues& rProperties ) + throw(IllegalArgumentException, + RuntimeException); + virtual Reference< XSpellAlternatives > SAL_CALL + spell( const OUString& rWord, const Locale& rLocale, + const PropertyValues& rProperties ) + throw(IllegalArgumentException, + RuntimeException); + + // XLinguServiceEventBroadcaster + virtual sal_Bool SAL_CALL + addLinguServiceEventListener( + const Reference< XLinguServiceEventListener >& rxLstnr ) + throw(RuntimeException); + virtual sal_Bool SAL_CALL + removeLinguServiceEventListener( + const Reference< XLinguServiceEventListener >& rxLstnr ) + throw(RuntimeException); + + // XServiceDisplayName + virtual OUString SAL_CALL + getServiceDisplayName( const Locale& rLocale ) + throw(RuntimeException); + + // XInitialization + virtual void SAL_CALL + initialize( const Sequence< Any >& rArguments ) + throw(Exception, RuntimeException); + + // XComponent + virtual void SAL_CALL + dispose() + throw(RuntimeException); + virtual void SAL_CALL + addEventListener( const Reference< XEventListener >& rxListener ) + throw(RuntimeException); + virtual void SAL_CALL + removeEventListener( const Reference< XEventListener >& rxListener ) + throw(RuntimeException); + + //////////////////////////////////////////////////////////// + // Service specific part + // + + // XServiceInfo + virtual OUString SAL_CALL + getImplementationName() + throw(RuntimeException); + virtual sal_Bool SAL_CALL + supportsService( const OUString& rServiceName ) + throw(RuntimeException); + virtual Sequence< OUString > SAL_CALL + getSupportedServiceNames() + throw(RuntimeException); + + + static inline OUString + getImplementationName_Static() throw(); + static Sequence< OUString > + getSupportedServiceNames_Static() throw(); +}; + +inline OUString MacSpellChecker::getImplementationName_Static() throw() +{ + return A2OU( "org.openoffice.lingu.MacOSXSpellChecker" ); +} + + + +/////////////////////////////////////////////////////////////////////////// + +#endif + diff --git a/lingucomponent/source/spellcheck/macosxspell/makefile.mk b/lingucomponent/source/spellcheck/macosxspell/makefile.mk new file mode 100644 index 000000000000..6414560e0f4a --- /dev/null +++ b/lingucomponent/source/spellcheck/macosxspell/makefile.mk @@ -0,0 +1,93 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. + +PRJNAME = lingucomponent +TARGET = MacOSXSpell +ENABLE_EXCEPTIONS=TRUE +USE_DEFFILE=TRUE + +.IF "$(GUIBASE)"=="aqua" + +#----- Settings --------------------------------------------------------- + +.INCLUDE : settings.mk + +.IF "$(SYSTEM_HUNSPELL)" != "YES" +HUNSPELL_CFLAGS += -I$(SOLARINCDIR)$/hunspell +.ENDIF + +CXXFLAGS += $(HUNSPELL_CFLAGS) +CFLAGSCXX += $(HUNSPELL_CFLAGS) +CFLAGSCC += $(HUNSPELL_CFLAGS) + +# --- Files -------------------------------------------------------- + +CFLAGSCXX+=$(OBJCXXFLAGS) +CFLAGSCXX+=-I..$/..$/lingutil + +EXCEPTIONSFILES= \ + $(SLO)$/macspellimp.obj + + +SLOFILES= \ + $(SLO)$/macreg.obj\ + $(SLO)$/macspellimp.obj + + +SHL1TARGET= $(TARGET)$(DLLPOSTFIX) + +SHL1STDLIBS= \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(VOSLIB) \ + $(TOOLSLIB) \ + $(SVLLIB) \ + $(SALLIB) \ + $(UCBHELPERLIB) \ + $(UNOTOOLSLIB) \ + $(LNGLIB) + +SHL1STDLIBS+= -framework Cocoa + +# build DLL +SHL1LIBS= $(SLB)$/$(TARGET).lib +SHL1IMPLIB= i$(TARGET) +SHL1DEPN= $(SHL1LIBS) +SHL1DEF= $(MISC)$/$(SHL1TARGET).def + +SHL1VERSIONMAP=$(SOLARENV)/src/component.map + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +.ELSE +dummy: + @echo " Nothing to build for GUIBASE=$(GUIBASE)" +.ENDIF diff --git a/lingucomponent/source/spellcheck/spell/exports.dxp b/lingucomponent/source/spellcheck/spell/exports.dxp new file mode 100644 index 000000000000..b0f85bf7bebf --- /dev/null +++ b/lingucomponent/source/spellcheck/spell/exports.dxp @@ -0,0 +1,3 @@ +component_getFactory +component_getImplementationEnvironment +component_writeInfo diff --git a/lingucomponent/source/spellcheck/spell/makefile.mk b/lingucomponent/source/spellcheck/spell/makefile.mk new file mode 100644 index 000000000000..4173d4dbae22 --- /dev/null +++ b/lingucomponent/source/spellcheck/spell/makefile.mk @@ -0,0 +1,87 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. + +PRJNAME = lingucomponent +TARGET = spell +ENABLE_EXCEPTIONS=TRUE +USE_DEFFILE=TRUE + +.IF "$(SYSTEM_HUNSPELL)" != "YES" +HUNSPELL_CFLAGS += -I$(SOLARINCDIR)$/hunspell +.ENDIF + +#----- Settings --------------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- + +CXXFLAGS += -I$(PRJ)$/source$/lingutil $(HUNSPELL_CFLAGS) +CFLAGSCXX += -I$(PRJ)$/source$/lingutil $(HUNSPELL_CFLAGS) +CFLAGSCC += -I$(PRJ)$/source$/lingutil $(HUNSPELL_CFLAGS) + +EXCEPTIONSFILES= \ + $(SLO)$/sspellimp.obj + +SLOFILES= \ + $(SLO)$/sreg.obj\ + $(SLO)$/sspellimp.obj + + +SHL1TARGET= $(TARGET)$(DLLPOSTFIX) + +SHL1STDLIBS= \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(I18NISOLANGLIB) \ + $(TOOLSLIB) \ + $(UNOTOOLSLIB) \ + $(SVLLIB) \ + $(SALLIB) \ + $(LNGLIB) \ + $(ULINGULIB) \ + $(ICUUCLIB) \ + $(HUNSPELLLIB) + +# build DLL +SHL1LIBS= $(SLB)$/$(TARGET).lib $(SLB)$/libulingu.lib +SHL1IMPLIB= i$(TARGET) +SHL1DEPN= $(SHL1LIBS) +SHL1DEF= $(MISC)$/$(SHL1TARGET).def + +SHL1VERSIONMAP=$(SOLARENV)/src/component.map + +# build DEF file +DEF1NAME =$(SHL1TARGET) +DEF1EXPORTFILE= exports.dxp + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + diff --git a/lingucomponent/source/spellcheck/spell/sreg.cxx b/lingucomponent/source/spellcheck/spell/sreg.cxx new file mode 100644 index 000000000000..bd97403c89d6 --- /dev/null +++ b/lingucomponent/source/spellcheck/spell/sreg.cxx @@ -0,0 +1,86 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_lingucomponent.hxx" + + +#include <cppuhelper/factory.hxx> // helper for factories +#include <rtl/string.hxx> + +#include <com/sun/star/registry/XRegistryKey.hpp> + +using namespace rtl; +using namespace com::sun::star::lang; +using namespace com::sun::star::registry; + +//////////////////////////////////////// +// declaration of external RegEntry-functions defined by the service objects +// + +extern sal_Bool SAL_CALL SpellChecker_writeInfo( + void * /*pServiceManager*/, XRegistryKey * pRegistryKey ); + +extern void * SAL_CALL SpellChecker_getFactory( + const sal_Char * pImplName, + XMultiServiceFactory * pServiceManager, + void * /*pRegistryKey*/ ); +//////////////////////////////////////// +// definition of the two functions that are used to provide the services +// + +extern "C" +{ + +sal_Bool SAL_CALL component_writeInfo( + void * pServiceManager, XRegistryKey * pRegistryKey ) +{ + return SpellChecker_writeInfo( pServiceManager, pRegistryKey ); +} + +void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) +{ + void * pRet = NULL; + pRet = SpellChecker_getFactory( + pImplName, + reinterpret_cast< XMultiServiceFactory * >( pServiceManager ), + pRegistryKey ); + + return pRet; +} + +} + +/////////////////////////////////////////////////////////////////////////// + diff --git a/lingucomponent/source/spellcheck/spell/sspellimp.cxx b/lingucomponent/source/spellcheck/spell/sspellimp.cxx new file mode 100644 index 000000000000..0cb6ad8ec3da --- /dev/null +++ b/lingucomponent/source/spellcheck/spell/sspellimp.cxx @@ -0,0 +1,722 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_lingucomponent.hxx" +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> + +#include <com/sun/star/linguistic2/SpellFailure.hpp> +#include <cppuhelper/factory.hxx> // helper for factories +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <tools/debug.hxx> +#include <unotools/processfactory.hxx> +#include <osl/mutex.hxx> + +#include <hunspell.hxx> +#include <dictmgr.hxx> + +#ifndef _SPELLIMP_HXX +#include <sspellimp.hxx> +#endif + +#include <linguistic/lngprops.hxx> +#include <linguistic/spelldta.hxx> +#include <i18npool/mslangid.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/lingucfg.hxx> +#include <unotools/useroptions.hxx> +#include <osl/file.hxx> +#include <rtl/ustrbuf.hxx> + +#include <lingutil.hxx> + +#include <list> +#include <set> +#include <string.h> + +using namespace utl; +using namespace osl; +using namespace rtl; +using namespace com::sun::star; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::linguistic2; +using namespace linguistic; + +// XML-header of SPELLML queries +#define SPELLML_HEADER "<?xml?>" + +/////////////////////////////////////////////////////////////////////////// + +SpellChecker::SpellChecker() : + aEvtListeners ( GetLinguMutex() ) +{ + aDicts = NULL; + aDEncs = NULL; + aDLocs = NULL; + aDNames = NULL; + bDisposing = FALSE; + pPropHelper = NULL; + numdict = 0; +} + + +SpellChecker::~SpellChecker() +{ + if (aDicts) { + for (int i = 0; i < numdict; i++) { + if (aDicts[i]) delete aDicts[i]; + aDicts[i] = NULL; + } + delete[] aDicts; + } + aDicts = NULL; + numdict = 0; + if (aDEncs) delete[] aDEncs; + aDEncs = NULL; + if (aDLocs) delete[] aDLocs; + aDLocs = NULL; + if (aDNames) delete[] aDNames; + aDNames = NULL; + if (pPropHelper) + pPropHelper->RemoveAsPropListener(); +} + + +PropertyHelper_Spell & SpellChecker::GetPropHelper_Impl() +{ + if (!pPropHelper) + { + Reference< XPropertySet > xPropSet( GetLinguProperties(), UNO_QUERY ); + + pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet ); + xPropHelper = pPropHelper; + pPropHelper->AddAsPropListener(); //! after a reference is established + } + return *pPropHelper; +} + + +Sequence< Locale > SAL_CALL SpellChecker::getLocales() + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + // this routine should return the locales supported by the installed + // dictionaries. + + if (!numdict) + { + SvtLinguConfig aLinguCfg; + + // get list of extension dictionaries-to-use + // (or better speaking: the list of dictionaries using the + // new configuration entries). + std::list< SvtLinguConfigDictionaryEntry > aDics; + uno::Sequence< rtl::OUString > aFormatList; + aLinguCfg.GetSupportedDictionaryFormatsFor( A2OU("SpellCheckers"), + A2OU("org.openoffice.lingu.MySpellSpellChecker"), aFormatList ); + sal_Int32 nLen = aFormatList.getLength(); + for (sal_Int32 i = 0; i < nLen; ++i) + { + std::vector< SvtLinguConfigDictionaryEntry > aTmpDic( + aLinguCfg.GetActiveDictionariesByFormat( aFormatList[i] ) ); + aDics.insert( aDics.end(), aTmpDic.begin(), aTmpDic.end() ); + } + + //!! for compatibility with old dictionaries (the ones not using extensions + //!! or new configuration entries, but still using the dictionary.lst file) + //!! Get the list of old style spell checking dictionaries to use... + std::vector< SvtLinguConfigDictionaryEntry > aOldStyleDics( + GetOldStyleDics( "DICT" ) ); + + // to prefer dictionaries with configuration entries we will only + // use those old style dictionaries that add a language that + // is not yet supported by the list od new style dictionaries + MergeNewStyleDicsAndOldStyleDics( aDics, aOldStyleDics ); + + numdict = aDics.size(); + if (numdict) + { + // get supported locales from the dictionaries-to-use... + sal_Int32 k = 0; + std::set< rtl::OUString, lt_rtl_OUString > aLocaleNamesSet; + std::list< SvtLinguConfigDictionaryEntry >::const_iterator aDictIt; + for (aDictIt = aDics.begin(); aDictIt != aDics.end(); ++aDictIt) + { + uno::Sequence< rtl::OUString > aLocaleNames( aDictIt->aLocaleNames ); + sal_Int32 nLen2 = aLocaleNames.getLength(); + for (k = 0; k < nLen2; ++k) + { + aLocaleNamesSet.insert( aLocaleNames[k] ); + } + } + // ... and add them to the resulting sequence + aSuppLocales.realloc( aLocaleNamesSet.size() ); + std::set< rtl::OUString, lt_rtl_OUString >::const_iterator aItB; + k = 0; + for (aItB = aLocaleNamesSet.begin(); aItB != aLocaleNamesSet.end(); ++aItB) + { + Locale aTmp( MsLangId::convertLanguageToLocale( + MsLangId::convertIsoStringToLanguage( *aItB ))); + aSuppLocales[k++] = aTmp; + } + + //! For each dictionary and each locale we need a seperate entry. + //! If this results in more than one dictionary per locale than (for now) + //! it is undefined which dictionary gets used. + //! In the future the implementation should support using several dictionaries + //! for one locale. + numdict = 0; + for (aDictIt = aDics.begin(); aDictIt != aDics.end(); ++aDictIt) + numdict = numdict + aDictIt->aLocaleNames.getLength(); + + // add dictionary information + aDicts = new Hunspell* [numdict]; + aDEncs = new rtl_TextEncoding [numdict]; + aDLocs = new Locale [numdict]; + aDNames = new OUString [numdict]; + k = 0; + for (aDictIt = aDics.begin(); aDictIt != aDics.end(); ++aDictIt) + { + if (aDictIt->aLocaleNames.getLength() > 0 && + aDictIt->aLocations.getLength() > 0) + { + uno::Sequence< rtl::OUString > aLocaleNames( aDictIt->aLocaleNames ); + sal_Int32 nLocales = aLocaleNames.getLength(); + + // currently only one language per dictionary is supported in the actual implementation... + // Thus here we work-around this by adding the same dictionary several times. + // Once for each of it's supported locales. + for (sal_Int32 i = 0; i < nLocales; ++i) + { + aDicts[k] = NULL; + aDEncs[k] = 0; + aDLocs[k] = MsLangId::convertLanguageToLocale( + MsLangId::convertIsoStringToLanguage( aLocaleNames[i] )); + // also both files have to be in the same directory and the + // file names must only differ in the extension (.aff/.dic). + // Thus we use the first location only and strip the extension part. + rtl::OUString aLocation = aDictIt->aLocations[0]; + sal_Int32 nPos = aLocation.lastIndexOf( '.' ); + aLocation = aLocation.copy( 0, nPos ); + aDNames[k] = aLocation; + + ++k; + } + } + } + DBG_ASSERT( k == numdict, "index mismatch?" ); + } + else + { + /* no dictionary found so register no dictionaries */ + numdict = 0; + aDicts = NULL; + aDEncs = NULL; + aDLocs = NULL; + aDNames = NULL; + aSuppLocales.realloc(0); + } + } + + return aSuppLocales; +} + + +sal_Bool SAL_CALL SpellChecker::hasLocale(const Locale& rLocale) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + BOOL bRes = FALSE; + if (!aSuppLocales.getLength()) + getLocales(); + + INT32 nLen = aSuppLocales.getLength(); + for (INT32 i = 0; i < nLen; ++i) + { + const Locale *pLocale = aSuppLocales.getConstArray(); + if (rLocale == pLocale[i]) + { + bRes = TRUE; + break; + } + } + return bRes; +} + +INT16 SpellChecker::GetSpellFailure( const OUString &rWord, const Locale &rLocale ) +{ + Hunspell * pMS; + rtl_TextEncoding aEnc; + + // initialize a myspell object for each dictionary once + // (note: mutex is held higher up in isValid) + + + INT16 nRes = -1; + + // first handle smart quotes both single and double + OUStringBuffer rBuf(rWord); + sal_Int32 n = rBuf.getLength(); + sal_Unicode c; + for (sal_Int32 ix=0; ix < n; ix++) { + c = rBuf.charAt(ix); + if ((c == 0x201C) || (c == 0x201D)) rBuf.setCharAt(ix,(sal_Unicode)0x0022); + if ((c == 0x2018) || (c == 0x2019)) rBuf.setCharAt(ix,(sal_Unicode)0x0027); + } + OUString nWord(rBuf.makeStringAndClear()); + + if (n) + { + for (sal_Int32 i = 0; i < numdict; ++i) { + pMS = NULL; + aEnc = 0; + + if (rLocale == aDLocs[i]) + { + if (!aDicts[i]) + { + OUString dicpath = aDNames[i] + A2OU(".dic"); + OUString affpath = aDNames[i] + A2OU(".aff"); + OUString dict; + OUString aff; + osl::FileBase::getSystemPathFromFileURL(dicpath,dict); + osl::FileBase::getSystemPathFromFileURL(affpath,aff); + OString aTmpaff(OU2ENC(aff,osl_getThreadTextEncoding())); + OString aTmpdict(OU2ENC(dict,osl_getThreadTextEncoding())); + +#if defined(WNT) + // workaround for Windows specifc problem that the + // path length in calls to 'fopen' is limted to somewhat + // about 120+ characters which will usually be exceed when + // using dictionaries as extensions. + aTmpaff = Win_GetShortPathName( aff ); + aTmpdict = Win_GetShortPathName( dict ); +#endif + + aDicts[i] = new Hunspell(aTmpaff.getStr(),aTmpdict.getStr()); + aDEncs[i] = 0; + if (aDicts[i]) { + char * dic_encoding = aDicts[i]->get_dic_encoding(); + aDEncs[i] = rtl_getTextEncodingFromUnixCharset(aDicts[i]->get_dic_encoding()); + if (aDEncs[i] == RTL_TEXTENCODING_DONTKNOW) { + if (strcmp("ISCII-DEVANAGARI", dic_encoding) == 0) { + aDEncs[i] = RTL_TEXTENCODING_ISCII_DEVANAGARI; + } else if (strcmp("UTF-8", dic_encoding) == 0) { + aDEncs[i] = RTL_TEXTENCODING_UTF8; + } + } + } + } + pMS = aDicts[i]; + aEnc = aDEncs[i]; + } + if (pMS) + { + OString aWrd(OU2ENC(nWord,aEnc)); + int rVal = pMS->spell((char*)aWrd.getStr()); + if (rVal != 1) + { + nRes = SpellFailure::SPELLING_ERROR; + } else { + return -1; + } + pMS = NULL; + } + } + } + + return nRes; +} + + +sal_Bool SAL_CALL + SpellChecker::isValid( const OUString& rWord, const Locale& rLocale, + const PropertyValues& rProperties ) + throw(IllegalArgumentException, RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (rLocale == Locale() || !rWord.getLength()) + return TRUE; + + if (!hasLocale( rLocale )) +#ifdef LINGU_EXCEPTIONS + throw( IllegalArgumentException() ); +#else + return TRUE; +#endif + + // Get property values to be used. + // These are be the default values set in the SN_LINGU_PROPERTIES + // PropertySet which are overridden by the supplied ones from the + // last argument. + // You'll probably like to use a simplier solution than the provided + // one using the PropertyHelper_Spell. + + PropertyHelper_Spell &rHelper = GetPropHelper(); + rHelper.SetTmpPropVals( rProperties ); + + INT16 nFailure = GetSpellFailure( rWord, rLocale ); + if (nFailure != -1 && !rWord.match(A2OU(SPELLML_HEADER), 0)) + { + INT16 nLang = LocaleToLanguage( rLocale ); + // postprocess result for errors that should be ignored + if ( (!rHelper.IsSpellUpperCase() && IsUpper( rWord, nLang )) + || (!rHelper.IsSpellWithDigits() && HasDigits( rWord )) + || (!rHelper.IsSpellCapitalization() + && nFailure == SpellFailure::CAPTION_ERROR) + ) + nFailure = -1; + } + + return (nFailure == -1); +} + + +Reference< XSpellAlternatives > + SpellChecker::GetProposals( const OUString &rWord, const Locale &rLocale ) +{ + // Retrieves the return values for the 'spell' function call in case + // of a misspelled word. + // Especially it may give a list of suggested (correct) words: + + Reference< XSpellAlternatives > xRes; + // note: mutex is held by higher up by spell which covers both + + Hunspell* pMS; + rtl_TextEncoding aEnc; + int count; + int numsug = 0; + + // first handle smart quotes (single and double) + OUStringBuffer rBuf(rWord); + sal_Int32 n = rBuf.getLength(); + sal_Unicode c; + for (sal_Int32 ix=0; ix < n; ix++) { + c = rBuf.charAt(ix); + if ((c == 0x201C) || (c == 0x201D)) rBuf.setCharAt(ix,(sal_Unicode)0x0022); + if ((c == 0x2018) || (c == 0x2019)) rBuf.setCharAt(ix,(sal_Unicode)0x0027); + } + OUString nWord(rBuf.makeStringAndClear()); + + if (n) + { + INT16 nLang = LocaleToLanguage( rLocale ); + + Sequence< OUString > aStr( 0 ); + + for (int i =0; i < numdict; i++) { + pMS = NULL; + aEnc = 0; + count = 0; + + if (rLocale == aDLocs[i]) + { + pMS = aDicts[i]; + aEnc = aDEncs[i]; + } + + if (pMS) + { + char ** suglst = NULL; + OString aWrd(OU2ENC(nWord,aEnc)); + count = pMS->suggest(&suglst, (const char *) aWrd.getStr()); + + if (count) { + aStr.realloc( numsug + count ); + OUString *pStr = aStr.getArray(); + for (int ii=0; ii < count; ++ii) + { + OUString cvtwrd(suglst[ii],strlen(suglst[ii]),aEnc); + pStr[numsug + ii] = cvtwrd; + } + pMS->free_list(&suglst, count); + numsug += count; + } + } + } + + // now return an empty alternative for no suggestions or the list of alternatives if some found + SpellAlternatives *pAlt = new SpellAlternatives; + String aTmp(rWord); + pAlt->SetWordLanguage( aTmp, nLang ); + pAlt->SetFailureType( SpellFailure::SPELLING_ERROR ); + pAlt->SetAlternatives( aStr ); + xRes = pAlt; + return xRes; + + } + return xRes; +} + + + + +Reference< XSpellAlternatives > SAL_CALL + SpellChecker::spell( const OUString& rWord, const Locale& rLocale, + const PropertyValues& rProperties ) + throw(IllegalArgumentException, RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (rLocale == Locale() || !rWord.getLength()) + return NULL; + + if (!hasLocale( rLocale )) +#ifdef LINGU_EXCEPTIONS + throw( IllegalArgumentException() ); +#else + return NULL; +#endif + + Reference< XSpellAlternatives > xAlt; + if (!isValid( rWord, rLocale, rProperties )) + { + xAlt = GetProposals( rWord, rLocale ); + } + return xAlt; +} + + +Reference< XInterface > SAL_CALL SpellChecker_CreateInstance( + const Reference< XMultiServiceFactory > & /*rSMgr*/ ) + throw(Exception) +{ + + Reference< XInterface > xService = (cppu::OWeakObject*) new SpellChecker; + return xService; +} + + +sal_Bool SAL_CALL + SpellChecker::addLinguServiceEventListener( + const Reference< XLinguServiceEventListener >& rxLstnr ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + BOOL bRes = FALSE; + if (!bDisposing && rxLstnr.is()) + { + bRes = GetPropHelper().addLinguServiceEventListener( rxLstnr ); + } + return bRes; +} + + +sal_Bool SAL_CALL + SpellChecker::removeLinguServiceEventListener( + const Reference< XLinguServiceEventListener >& rxLstnr ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + BOOL bRes = FALSE; + if (!bDisposing && rxLstnr.is()) + { + DBG_ASSERT( xPropHelper.is(), "xPropHelper non existent" ); + bRes = GetPropHelper().removeLinguServiceEventListener( rxLstnr ); + } + return bRes; +} + + +OUString SAL_CALL + SpellChecker::getServiceDisplayName( const Locale& /*rLocale*/ ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + return A2OU( "Hunspell SpellChecker" ); +} + + +void SAL_CALL + SpellChecker::initialize( const Sequence< Any >& rArguments ) + throw(Exception, RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!pPropHelper) + { + INT32 nLen = rArguments.getLength(); + if (2 == nLen) + { + Reference< XPropertySet > xPropSet; + rArguments.getConstArray()[0] >>= xPropSet; + //rArguments.getConstArray()[1] >>= xDicList; + + //! Pointer allows for access of the non-UNO functions. + //! And the reference to the UNO-functions while increasing + //! the ref-count and will implicitly free the memory + //! when the object is not longer used. + pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet ); + xPropHelper = pPropHelper; + pPropHelper->AddAsPropListener(); //! after a reference is established + } + else { + DBG_ERROR( "wrong number of arguments in sequence" ); + } + + } +} + + +void SAL_CALL + SpellChecker::dispose() + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!bDisposing) + { + bDisposing = TRUE; + EventObject aEvtObj( (XSpellChecker *) this ); + aEvtListeners.disposeAndClear( aEvtObj ); + } +} + + +void SAL_CALL + SpellChecker::addEventListener( const Reference< XEventListener >& rxListener ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!bDisposing && rxListener.is()) + aEvtListeners.addInterface( rxListener ); +} + + +void SAL_CALL + SpellChecker::removeEventListener( const Reference< XEventListener >& rxListener ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + if (!bDisposing && rxListener.is()) + aEvtListeners.removeInterface( rxListener ); +} + + +/////////////////////////////////////////////////////////////////////////// +// Service specific part +// + +OUString SAL_CALL SpellChecker::getImplementationName() + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + return getImplementationName_Static(); +} + + +sal_Bool SAL_CALL SpellChecker::supportsService( const OUString& ServiceName ) + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + Sequence< OUString > aSNL = getSupportedServiceNames(); + const OUString * pArray = aSNL.getConstArray(); + for( INT32 i = 0; i < aSNL.getLength(); i++ ) + if( pArray[i] == ServiceName ) + return TRUE; + return FALSE; +} + + +Sequence< OUString > SAL_CALL SpellChecker::getSupportedServiceNames() + throw(RuntimeException) +{ + MutexGuard aGuard( GetLinguMutex() ); + + return getSupportedServiceNames_Static(); +} + + +Sequence< OUString > SpellChecker::getSupportedServiceNames_Static() + throw() +{ + MutexGuard aGuard( GetLinguMutex() ); + + Sequence< OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich + aSNS.getArray()[0] = A2OU( SN_SPELLCHECKER ); + return aSNS; +} + + +sal_Bool SAL_CALL SpellChecker_writeInfo( + void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey ) +{ + + try + { + String aImpl( '/' ); + aImpl += SpellChecker::getImplementationName_Static().getStr(); + aImpl.AppendAscii( "/UNO/SERVICES" ); + Reference< registry::XRegistryKey > xNewKey = + pRegistryKey->createKey( aImpl ); + Sequence< OUString > aServices = + SpellChecker::getSupportedServiceNames_Static(); + for( INT32 i = 0; i < aServices.getLength(); i++ ) + xNewKey->createKey( aServices.getConstArray()[i] ); + + return sal_True; + } + catch(Exception &) + { + return sal_False; + } +} + + +void * SAL_CALL SpellChecker_getFactory( const sal_Char * pImplName, + XMultiServiceFactory * pServiceManager, void * ) +{ + void * pRet = 0; + if ( !SpellChecker::getImplementationName_Static().compareToAscii( pImplName ) ) + { + Reference< XSingleServiceFactory > xFactory = + cppu::createOneInstanceFactory( + pServiceManager, + SpellChecker::getImplementationName_Static(), + SpellChecker_CreateInstance, + SpellChecker::getSupportedServiceNames_Static()); + // acquire, because we return an interface pointer instead of a reference + xFactory->acquire(); + pRet = xFactory.get(); + } + return pRet; +} + + +/////////////////////////////////////////////////////////////////////////// diff --git a/lingucomponent/source/spellcheck/spell/sspellimp.hxx b/lingucomponent/source/spellcheck/spell/sspellimp.hxx new file mode 100644 index 000000000000..94c57fa8b742 --- /dev/null +++ b/lingucomponent/source/spellcheck/spell/sspellimp.hxx @@ -0,0 +1,184 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _LINGU2_SPELLIMP_HXX_ +#define _LINGU2_SPELLIMP_HXX_ + +#include <uno/lbnames.h> // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type +#include <cppuhelper/implbase1.hxx> // helper for implementations +#include <cppuhelper/implbase6.hxx> // helper for implementations +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceDisplayName.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValues.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/linguistic2/XSpellChecker.hpp> +#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp> +#include <com/sun/star/linguistic2/XLinguServiceEventBroadcaster.hpp> +#include <tools/table.hxx> + +#include <linguistic/misc.hxx> +#include <linguistic/lngprophelp.hxx> + +#include <lingutil.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::linguistic2; + + +/////////////////////////////////////////////////////////////////////////// + + +class SpellChecker : + public cppu::WeakImplHelper6 + < + XSpellChecker, + XLinguServiceEventBroadcaster, + XInitialization, + XComponent, + XServiceInfo, + XServiceDisplayName + > +{ + Sequence< Locale > aSuppLocales; + Hunspell ** aDicts; + rtl_TextEncoding * aDEncs; + Locale * aDLocs; + OUString * aDNames; + sal_Int32 numdict; + + ::cppu::OInterfaceContainerHelper aEvtListeners; + Reference< XPropertyChangeListener > xPropHelper; + linguistic::PropertyHelper_Spell * pPropHelper; + BOOL bDisposing; + + // disallow copy-constructor and assignment-operator for now + SpellChecker(const SpellChecker &); + SpellChecker & operator = (const SpellChecker &); + + linguistic::PropertyHelper_Spell & GetPropHelper_Impl(); + linguistic::PropertyHelper_Spell & GetPropHelper() + { + return pPropHelper ? *pPropHelper : GetPropHelper_Impl(); + } + + INT16 GetSpellFailure( const OUString &rWord, const Locale &rLocale ); + Reference< XSpellAlternatives > + GetProposals( const OUString &rWord, const Locale &rLocale ); + +public: + SpellChecker(); + virtual ~SpellChecker(); + + // XSupportedLocales (for XSpellChecker) + virtual Sequence< Locale > SAL_CALL + getLocales() + throw(RuntimeException); + virtual sal_Bool SAL_CALL + hasLocale( const Locale& rLocale ) + throw(RuntimeException); + + // XSpellChecker + virtual sal_Bool SAL_CALL + isValid( const OUString& rWord, const Locale& rLocale, + const PropertyValues& rProperties ) + throw(IllegalArgumentException, + RuntimeException); + virtual Reference< XSpellAlternatives > SAL_CALL + spell( const OUString& rWord, const Locale& rLocale, + const PropertyValues& rProperties ) + throw(IllegalArgumentException, + RuntimeException); + + // XLinguServiceEventBroadcaster + virtual sal_Bool SAL_CALL + addLinguServiceEventListener( + const Reference< XLinguServiceEventListener >& rxLstnr ) + throw(RuntimeException); + virtual sal_Bool SAL_CALL + removeLinguServiceEventListener( + const Reference< XLinguServiceEventListener >& rxLstnr ) + throw(RuntimeException); + + // XServiceDisplayName + virtual OUString SAL_CALL + getServiceDisplayName( const Locale& rLocale ) + throw(RuntimeException); + + // XInitialization + virtual void SAL_CALL + initialize( const Sequence< Any >& rArguments ) + throw(Exception, RuntimeException); + + // XComponent + virtual void SAL_CALL + dispose() + throw(RuntimeException); + virtual void SAL_CALL + addEventListener( const Reference< XEventListener >& rxListener ) + throw(RuntimeException); + virtual void SAL_CALL + removeEventListener( const Reference< XEventListener >& rxListener ) + throw(RuntimeException); + + //////////////////////////////////////////////////////////// + // Service specific part + // + + // XServiceInfo + virtual OUString SAL_CALL + getImplementationName() + throw(RuntimeException); + virtual sal_Bool SAL_CALL + supportsService( const OUString& rServiceName ) + throw(RuntimeException); + virtual Sequence< OUString > SAL_CALL + getSupportedServiceNames() + throw(RuntimeException); + + + static inline OUString + getImplementationName_Static() throw(); + static Sequence< OUString > + getSupportedServiceNames_Static() throw(); +}; + +inline OUString SpellChecker::getImplementationName_Static() throw() +{ + return A2OU( "org.openoffice.lingu.MySpellSpellChecker" ); +} + + + +/////////////////////////////////////////////////////////////////////////// + +#endif + |