blob: a16fc57e65ea2981b9ce55ea65a8cbfbc7bd3ba4 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_linguistic.hxx"
#include <com/sun/star/registry/XRegistryKey.hpp>
#include <com/sun/star/container/XContentEnumerationAccess.hpp>
#include <com/sun/star/container/XEnumeration.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/linguistic2/XSupportedLocales.hpp>
#include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
#include <com/sun/star/linguistic2/LinguServiceEventFlags.hpp>
#include <tools/solar.h>
#include <unotools/lingucfg.hxx>
#include <unotools/processfactory.hxx>
#include <i18npool/lang.h>
#include <i18npool/mslangid.hxx>
#include <cppuhelper/factory.hxx>
#include <comphelper/extract.hxx>
#include <rtl/logfile.hxx>
#include <boost/checked_delete.hpp>
#include "lngsvcmgr.hxx"
#include "lngopt.hxx"
#include "linguistic/misc.hxx"
#include "spelldsp.hxx"
#include "hyphdsp.hxx"
#include "thesdsp.hxx"
#include "gciterator.hxx"
using namespace com::sun::star;
using namespace linguistic;
using ::rtl::OUString;
// forward declarations
uno::Sequence< OUString > static GetLangSvcList( const uno::Any &rVal );
uno::Sequence< OUString > static GetLangSvc( const uno::Any &rVal );
///////////////////////////////////////////////////////////////////////////
static sal_Bool lcl_SeqHasString( const uno::Sequence< OUString > &rSeq, const OUString &rText )
{
sal_Bool bRes = sal_False;
sal_Int32 nLen = rSeq.getLength();
if (nLen == 0 || rText.getLength() == 0)
return bRes;
const OUString *pSeq = rSeq.getConstArray();
for (sal_Int32 i = 0; i < nLen && !bRes; ++i)
{
if (rText == pSeq[i])
bRes = sal_True;
}
return bRes;
}
///////////////////////////////////////////////////////////////////////////
static uno::Sequence< lang::Locale > GetAvailLocales(
const uno::Sequence< OUString > &rSvcImplNames )
{
uno::Sequence< lang::Locale > aRes;
uno::Reference< lang::XMultiServiceFactory > xFac( utl::getProcessServiceFactory() );
sal_Int32 nNames = rSvcImplNames.getLength();
if (nNames && xFac.is())
{
std::set< LanguageType > aLanguages;
//! since we're going to create one-instance services we have to
//! supply their arguments even if we would not need them here...
uno::Sequence< uno::Any > aArgs(2);
aArgs.getArray()[0] <<= GetLinguProperties();
// check all services for the supported languages and new
// languages to the result
const OUString *pImplNames = rSvcImplNames.getConstArray();
sal_Int32 i;
for (i = 0; i < nNames; ++i)
{
uno::Reference< linguistic2::XSupportedLocales > xSuppLoc;
try
{
xSuppLoc = uno::Reference< linguistic2::XSupportedLocales >(
xFac->createInstanceWithArguments( pImplNames[i], aArgs ), uno::UNO_QUERY );
}
catch (uno::Exception &)
{
DBG_ASSERT( 0, "createInstanceWithArguments failed" );
}
if (xSuppLoc.is())
{
uno::Sequence< lang::Locale > aLoc( xSuppLoc->getLocales() );
sal_Int32 nLoc = aLoc.getLength();
for (sal_Int32 k = 0; k < nLoc; ++k)
{
const lang::Locale *pLoc = aLoc.getConstArray();
LanguageType nLang = LocaleToLanguage( pLoc[k] );
// language not already added?
if (aLanguages.find( nLang ) == aLanguages.end())
aLanguages.insert( nLang );
}
}
else
{
DBG_ASSERT( 0, "interface not supported by service" );
}
}
// build return sequence
sal_Int32 nLanguages = static_cast< sal_Int32 >(aLanguages.size());
aRes.realloc( nLanguages );
lang::Locale *pRes = aRes.getArray();
std::set< LanguageType >::const_iterator aIt( aLanguages.begin() );
for (i = 0; aIt != aLanguages.end(); ++aIt, ++i)
{
LanguageType nLang = *aIt;
pRes[i] = CreateLocale( nLang );
}
}
return aRes;
}
///////////////////////////////////////////////////////////////////////////
struct SvcInfo
{
const OUString aSvcImplName;
const uno::Sequence< sal_Int16 > aSuppLanguages;
SvcInfo( const OUString &rSvcImplName,
const uno::Sequence< sal_Int16 > &rSuppLanguages ) :
aSvcImplName (rSvcImplName),
aSuppLanguages (rSuppLanguages)
{
}
sal_Bool HasLanguage( sal_Int16 nLanguage ) const;
};
sal_Bool SvcInfo::HasLanguage( sal_Int16 nLanguage ) const
{
sal_Int32 nCnt = aSuppLanguages.getLength();
const sal_Int16 *pLang = aSuppLanguages.getConstArray();
sal_Int32 i;
for ( i = 0; i < nCnt; ++i)
{
if (nLanguage == pLang[i])
break;
}
return i < nCnt;
}
///////////////////////////////////////////////////////////////////////////
void LngSvcMgr::SetAvailableCfgServiceLists( LinguDispatcher &rDispatcher,
const SvcInfoArray &rAvailSvcs )
{
// get list of nodenames to look at for their service list
const char *pEntryName = 0;
sal_Bool bHasLangSvcList = sal_True;
switch (rDispatcher.GetDspType())
{
case LinguDispatcher::DSP_SPELL : pEntryName = "ServiceManager/SpellCheckerList"; break;
case LinguDispatcher::DSP_GRAMMAR : pEntryName = "ServiceManager/GrammarCheckerList";
bHasLangSvcList = sal_False;
break;
case LinguDispatcher::DSP_HYPH : pEntryName = "ServiceManager/HyphenatorList";
bHasLangSvcList = sal_False;
break;
case LinguDispatcher::DSP_THES : pEntryName = "ServiceManager/ThesaurusList"; break;
default :
DBG_ASSERT( 0, "unexpected case" );
}
String aNode( String::CreateFromAscii( pEntryName ) );
uno::Sequence < OUString > aNodeNames( /*aCfg.*/GetNodeNames( aNode ) );
sal_Int32 nLen = aNodeNames.getLength();
const OUString *pNodeNames = aNodeNames.getConstArray();
for (sal_Int32 i = 0; i < nLen; ++i)
{
uno::Sequence< OUString > aSvcImplNames;
uno::Sequence< OUString > aNames( 1 );
OUString *pNames = aNames.getArray();
OUString aPropName( aNode );
aPropName += OUString::valueOf( (sal_Unicode) '/' );
aPropName += pNodeNames[i];
pNames[0] = aPropName;
uno::Sequence< uno::Any > aValues = /*aCfg.*/GetProperties( aNames );
if (aValues.getLength())
{
// get list of configured service names for the
// current node (language)
const uno::Any &rValue = aValues.getConstArray()[0];
if (bHasLangSvcList)
aSvcImplNames = GetLangSvcList( rValue );
else
aSvcImplNames = GetLangSvc( rValue );
sal_Int32 nSvcs = aSvcImplNames.getLength();
if (nSvcs)
{
const OUString *pImplNames = aSvcImplNames.getConstArray();
LanguageType nLang = MsLangId::convertIsoStringToLanguage( pNodeNames[i] );
// build list of available services from those
sal_Int32 nCnt = 0;
uno::Sequence< OUString > aAvailSvcs( nSvcs );
OUString *pAvailSvcs = aAvailSvcs.getArray();
for (sal_Int32 k = 0; k < nSvcs; ++k)
{
// check for availability of the service
size_t nAvailSvcs = rAvailSvcs.size();
for (size_t m = 0; m < nAvailSvcs; ++m)
{
const SvcInfo &rSvcInfo = *rAvailSvcs[m];
if (rSvcInfo.aSvcImplName == pImplNames[k] &&
rSvcInfo.HasLanguage( nLang ))
{
pAvailSvcs[ nCnt++ ] = rSvcInfo.aSvcImplName;
break;
}
}
}
if (nCnt)
{
aAvailSvcs.realloc( nCnt );
rDispatcher.SetServiceList( CreateLocale( nLang ), aAvailSvcs );
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////
class LngSvcMgrListenerHelper :
public cppu::WeakImplHelper2
<
linguistic2::XLinguServiceEventListener,
linguistic2::XDictionaryListEventListener
>
{
LngSvcMgr &rMyManager;
// Timer aLaunchTimer;
//cppu::OMultiTypeInterfaceContainerHelper aListeners;
::cppu::OInterfaceContainerHelper aLngSvcMgrListeners;
::cppu::OInterfaceContainerHelper aLngSvcEvtBroadcasters;
uno::Reference< linguistic2::XDictionaryList > xDicList;
uno::Reference< uno::XInterface > xMyEvtObj;
sal_Int16 nCombinedLngSvcEvt;
// disallow copy-constructor and assignment-operator for now
LngSvcMgrListenerHelper(const LngSvcMgrListenerHelper &);
LngSvcMgrListenerHelper & operator = (const LngSvcMgrListenerHelper &);
void LaunchEvent( sal_Int16 nLngSvcEvtFlags );
// DECL_LINK( TimeOut, Timer* );
long Timeout();
public:
LngSvcMgrListenerHelper( LngSvcMgr &rLngSvcMgr,
const uno::Reference< uno::XInterface > &rxSource,
const uno::Reference< linguistic2::XDictionaryList > &rxDicList );
// lang::XEventListener
virtual void SAL_CALL
disposing( const lang::EventObject& rSource )
throw(uno::RuntimeException);
// linguistic2::XLinguServiceEventListener
virtual void SAL_CALL
processLinguServiceEvent( const linguistic2::LinguServiceEvent& aLngSvcEvent )
throw(uno::RuntimeException);
// linguistic2::XDictionaryListEventListener
virtual void SAL_CALL
processDictionaryListEvent(
const linguistic2::DictionaryListEvent& rDicListEvent )
throw(uno::RuntimeException);
inline sal_Bool AddLngSvcMgrListener(
const uno::Reference< lang::XEventListener >& rxListener );
inline sal_Bool RemoveLngSvcMgrListener(
const uno::Reference< lang::XEventListener >& rxListener );
void DisposeAndClear( const lang::EventObject &rEvtObj );
sal_Bool AddLngSvcEvtBroadcaster(
const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
sal_Bool RemoveLngSvcEvtBroadcaster(
const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
void AddLngSvcEvt( sal_Int16 nLngSvcEvt );
};
LngSvcMgrListenerHelper::LngSvcMgrListenerHelper(
LngSvcMgr &rLngSvcMgr,
const uno::Reference< uno::XInterface > &rxSource,
const uno::Reference< linguistic2::XDictionaryList > &rxDicList ) :
rMyManager ( rLngSvcMgr ),
aLngSvcMgrListeners ( GetLinguMutex() ),
aLngSvcEvtBroadcasters ( GetLinguMutex() ),
xDicList ( rxDicList ),
xMyEvtObj ( rxSource )
{
if (xDicList.is())
{
xDicList->addDictionaryListEventListener(
(linguistic2::XDictionaryListEventListener *) this, sal_False );
}
//! The timer is used to 'sum up' different events in order to reduce the
//! number of events forwarded.
//! (This may happen already if a property was changed that has several
//! listeners, and each of them is launching an event of it's own!)
//! Thus this behaviour is necessary to avoid unecessary actions of
//! this objects listeners!
// aLaunchTimer.SetTimeout( 2000 );
// aLaunchTimer.SetTimeoutHdl( LINK( this, LngSvcMgrListenerHelper, TimeOut ) );
nCombinedLngSvcEvt = 0;
}
void SAL_CALL LngSvcMgrListenerHelper::disposing( const lang::EventObject& rSource )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
uno::Reference< uno::XInterface > xRef( rSource.Source );
if ( xRef.is() )
{
aLngSvcMgrListeners .removeInterface( xRef );
aLngSvcEvtBroadcasters.removeInterface( xRef );
if (xDicList == xRef)
xDicList = 0;
}
}
//IMPL_LINK( LngSvcMgrListenerHelper, TimeOut, Timer*, pTimer )
long LngSvcMgrListenerHelper::Timeout()
{
osl::MutexGuard aGuard( GetLinguMutex() );
// if (&aLaunchTimer == pTimer)
{
// change event source to LinguServiceManager since the listeners
// probably do not know (and need not to know) about the specific
// SpellChecker's or Hyphenator's.
linguistic2::LinguServiceEvent aEvtObj( xMyEvtObj, nCombinedLngSvcEvt );
nCombinedLngSvcEvt = 0;
if (rMyManager.pSpellDsp)
rMyManager.pSpellDsp->FlushSpellCache();
// pass event on to linguistic2::XLinguServiceEventListener's
cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
while (aIt.hasMoreElements())
{
uno::Reference< linguistic2::XLinguServiceEventListener > xRef( aIt.next(), uno::UNO_QUERY );
if (xRef.is())
xRef->processLinguServiceEvent( aEvtObj );
}
}
return 0;
}
void LngSvcMgrListenerHelper::AddLngSvcEvt( sal_Int16 nLngSvcEvt )
{
nCombinedLngSvcEvt |= nLngSvcEvt;
// aLaunchTimer.Start();
Timeout();
}
void SAL_CALL
LngSvcMgrListenerHelper::processLinguServiceEvent(
const linguistic2::LinguServiceEvent& rLngSvcEvent )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
AddLngSvcEvt( rLngSvcEvent.nEvent );
}
void SAL_CALL
LngSvcMgrListenerHelper::processDictionaryListEvent(
const linguistic2::DictionaryListEvent& rDicListEvent )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
sal_Int16 nDlEvt = rDicListEvent.nCondensedEvent;
if (0 == nDlEvt)
return;
// we do keep the original event source here though...
// pass event on to linguistic2::XDictionaryListEventListener's
cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
while (aIt.hasMoreElements())
{
uno::Reference< linguistic2::XDictionaryListEventListener > xRef( aIt.next(), uno::UNO_QUERY );
if (xRef.is())
xRef->processDictionaryListEvent( rDicListEvent );
}
//
// "translate" DictionaryList event into linguistic2::LinguServiceEvent
//
sal_Int16 nLngSvcEvt = 0;
//
sal_Int16 nSpellCorrectFlags =
linguistic2::DictionaryListEventFlags::ADD_NEG_ENTRY |
linguistic2::DictionaryListEventFlags::DEL_POS_ENTRY |
linguistic2::DictionaryListEventFlags::ACTIVATE_NEG_DIC |
linguistic2::DictionaryListEventFlags::DEACTIVATE_POS_DIC;
if (0 != (nDlEvt & nSpellCorrectFlags))
nLngSvcEvt |= linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN;
//
sal_Int16 nSpellWrongFlags =
linguistic2::DictionaryListEventFlags::ADD_POS_ENTRY |
linguistic2::DictionaryListEventFlags::DEL_NEG_ENTRY |
linguistic2::DictionaryListEventFlags::ACTIVATE_POS_DIC |
linguistic2::DictionaryListEventFlags::DEACTIVATE_NEG_DIC;
if (0 != (nDlEvt & nSpellWrongFlags))
nLngSvcEvt |= linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN;
//
sal_Int16 nHyphenateFlags =
linguistic2::DictionaryListEventFlags::ADD_POS_ENTRY |
linguistic2::DictionaryListEventFlags::DEL_POS_ENTRY |
linguistic2::DictionaryListEventFlags::ACTIVATE_POS_DIC |
linguistic2::DictionaryListEventFlags::ACTIVATE_NEG_DIC;
if (0 != (nDlEvt & nHyphenateFlags))
nLngSvcEvt |= linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN;
if (rMyManager.pSpellDsp)
rMyManager.pSpellDsp->FlushSpellCache();
if (nLngSvcEvt)
LaunchEvent( nLngSvcEvt );
}
void LngSvcMgrListenerHelper::LaunchEvent( sal_Int16 nLngSvcEvtFlags )
{
linguistic2::LinguServiceEvent aEvt( xMyEvtObj, nLngSvcEvtFlags );
// pass event on to linguistic2::XLinguServiceEventListener's
cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
while (aIt.hasMoreElements())
{
uno::Reference< linguistic2::XLinguServiceEventListener > xRef( aIt.next(), uno::UNO_QUERY );
if (xRef.is())
xRef->processLinguServiceEvent( aEvt );
}
}
inline sal_Bool LngSvcMgrListenerHelper::AddLngSvcMgrListener(
const uno::Reference< lang::XEventListener >& rxListener )
{
aLngSvcMgrListeners.addInterface( rxListener );
return sal_True;
}
inline sal_Bool LngSvcMgrListenerHelper::RemoveLngSvcMgrListener(
const uno::Reference< lang::XEventListener >& rxListener )
{
aLngSvcMgrListeners.removeInterface( rxListener );
return sal_True;
}
void LngSvcMgrListenerHelper::DisposeAndClear( const lang::EventObject &rEvtObj )
{
// call "disposing" for all listeners and clear list
aLngSvcMgrListeners .disposeAndClear( rEvtObj );
// remove references to this object hold by the broadcasters
cppu::OInterfaceIteratorHelper aIt( aLngSvcEvtBroadcasters );
while (aIt.hasMoreElements())
{
uno::Reference< linguistic2::XLinguServiceEventBroadcaster > xRef( aIt.next(), uno::UNO_QUERY );
if (xRef.is())
RemoveLngSvcEvtBroadcaster( xRef );
}
// remove refernce to this object hold by the dictionary-list
if (xDicList.is())
{
xDicList->removeDictionaryListEventListener(
(linguistic2::XDictionaryListEventListener *) this );
xDicList = 0;
}
}
sal_Bool LngSvcMgrListenerHelper::AddLngSvcEvtBroadcaster(
const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
{
sal_Bool bRes = sal_False;
if (rxBroadcaster.is())
{
aLngSvcEvtBroadcasters.addInterface( rxBroadcaster );
rxBroadcaster->addLinguServiceEventListener(
(linguistic2::XLinguServiceEventListener *) this );
}
return bRes;
}
sal_Bool LngSvcMgrListenerHelper::RemoveLngSvcEvtBroadcaster(
const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
{
sal_Bool bRes = sal_False;
if (rxBroadcaster.is())
{
aLngSvcEvtBroadcasters.removeInterface( rxBroadcaster );
rxBroadcaster->removeLinguServiceEventListener(
(linguistic2::XLinguServiceEventListener *) this );
}
return bRes;
}
///////////////////////////////////////////////////////////////////////////
LngSvcMgr::LngSvcMgr() :
utl::ConfigItem( String::CreateFromAscii( "Office.Linguistic" ) ),
aEvtListeners ( GetLinguMutex() )
{
bHasAvailSpellLocales =
bHasAvailGrammarLocales =
bHasAvailHyphLocales =
bHasAvailThesLocales =
bDisposing = sal_False;
pSpellDsp = 0;
pGrammarDsp = 0;
pHyphDsp = 0;
pThesDsp = 0;
pAvailSpellSvcs = 0;
pAvailGrammarSvcs = 0;
pAvailHyphSvcs = 0;
pAvailThesSvcs = 0;
pListenerHelper = 0;
// request notify events when properties (i.e. something in the subtree) changes
uno::Sequence< OUString > aNames(4);
OUString *pNames = aNames.getArray();
pNames[0] = A2OU( "ServiceManager/SpellCheckerList" );
pNames[1] = A2OU( "ServiceManager/GrammarCheckerList" );
pNames[2] = A2OU( "ServiceManager/HyphenatorList" );
pNames[3] = A2OU( "ServiceManager/ThesaurusList" );
EnableNotification( aNames );
}
void LngSvcMgr::clearSvcInfoArray(SvcInfoArray* pInfo)
{
if (pInfo)
{
std::for_each(pInfo->begin(), pInfo->end(), boost::checked_deleter<SvcInfo>());
delete pInfo;
}
}
LngSvcMgr::~LngSvcMgr()
{
// memory for pSpellDsp, pHyphDsp, pThesDsp, pListenerHelper
// will be freed in the destructor of the respective Reference's
// xSpellDsp, xGrammarDsp, xHyphDsp, xThesDsp
clearSvcInfoArray(pAvailSpellSvcs);
clearSvcInfoArray(pAvailGrammarSvcs);
clearSvcInfoArray(pAvailHyphSvcs);
clearSvcInfoArray(pAvailThesSvcs);
}
void LngSvcMgr::Notify( const uno::Sequence< OUString > &rPropertyNames )
{
const OUString aSpellCheckerList( A2OU("ServiceManager/SpellCheckerList") );
const OUString aGrammarCheckerList( A2OU("ServiceManager/GrammarCheckerList") );
const OUString aHyphenatorList( A2OU("ServiceManager/HyphenatorList") );
const OUString aThesaurusList( A2OU("ServiceManager/ThesaurusList") );
const uno::Sequence< OUString > aSpellCheckerListEntries( GetNodeNames( aSpellCheckerList ) );
const uno::Sequence< OUString > aGrammarCheckerListEntries( GetNodeNames( aGrammarCheckerList ) );
const uno::Sequence< OUString > aHyphenatorListEntries( GetNodeNames( aHyphenatorList ) );
const uno::Sequence< OUString > aThesaurusListEntries( GetNodeNames( aThesaurusList ) );
uno::Sequence< uno::Any > aValues;
uno::Sequence< OUString > aNames( 1 );
OUString *pNames = aNames.getArray();
sal_Int32 nLen = rPropertyNames.getLength();
const OUString *pPropertyNames = rPropertyNames.getConstArray();
for (sal_Int32 i = 0; i < nLen; ++i)
{
// property names look like
// "ServiceManager/ThesaurusList/de-CH"
const OUString &rName = pPropertyNames[i];
sal_Int32 nKeyStart;
nKeyStart = rName.lastIndexOf( '/' );
OUString aKeyText;
if (nKeyStart != -1)
aKeyText = rName.copy( nKeyStart + 1 );
DBG_ASSERT( aKeyText.getLength() != 0, "unexpected key (lang::Locale) string" );
if (0 == rName.compareTo( aSpellCheckerList, aSpellCheckerList.getLength() ))
{
// delete old cached data, needs to be acquired new on demand
clearSvcInfoArray(pAvailSpellSvcs); pAvailSpellSvcs = 0;
OUString aNode( aSpellCheckerList );
if (lcl_SeqHasString( aSpellCheckerListEntries, aKeyText ))
{
OUString aPropName( aNode );
aPropName += OUString::valueOf( (sal_Unicode) '/' );
aPropName += aKeyText;
pNames[0] = aPropName;
aValues = /*aCfg.*/GetProperties( aNames );
uno::Sequence< OUString > aSvcImplNames;
if (aValues.getLength())
aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
LanguageType nLang = LANGUAGE_NONE;
if (0 != aKeyText.getLength())
nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
GetSpellCheckerDsp_Impl( sal_False ); // don't set service list, it will be done below
pSpellDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
}
}
else if (0 == rName.compareTo( aGrammarCheckerList, aGrammarCheckerList.getLength() ))
{
// delete old cached data, needs to be acquired new on demand
clearSvcInfoArray(pAvailGrammarSvcs); pAvailGrammarSvcs = 0;
OUString aNode( aGrammarCheckerList );
if (lcl_SeqHasString( aGrammarCheckerListEntries, aKeyText ))
{
OUString aPropName( aNode );
aPropName += OUString::valueOf( (sal_Unicode) '/' );
aPropName += aKeyText;
pNames[0] = aPropName;
aValues = /*aCfg.*/GetProperties( aNames );
uno::Sequence< OUString > aSvcImplNames;
if (aValues.getLength())
aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
LanguageType nLang = LANGUAGE_NONE;
if (0 != aKeyText.getLength())
nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
if (SvtLinguConfig().HasGrammarChecker())
{
GetGrammarCheckerDsp_Impl( sal_False ); // don't set service list, it will be done below
pGrammarDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
}
}
}
else if (0 == rName.compareTo( aHyphenatorList, aHyphenatorList.getLength() ))
{
// delete old cached data, needs to be acquired new on demand
clearSvcInfoArray(pAvailHyphSvcs); pAvailHyphSvcs = 0;
OUString aNode( aHyphenatorList );
if (lcl_SeqHasString( aHyphenatorListEntries, aKeyText ))
{
OUString aPropName( aNode );
aPropName += OUString::valueOf( (sal_Unicode) '/' );
aPropName += aKeyText;
pNames[0] = aPropName;
aValues = /*aCfg.*/GetProperties( aNames );
uno::Sequence< OUString > aSvcImplNames;
if (aValues.getLength())
aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
LanguageType nLang = LANGUAGE_NONE;
if (0 != aKeyText.getLength())
nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
GetHyphenatorDsp_Impl( sal_False ); // don't set service list, it will be done below
pHyphDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
}
}
else if (0 == rName.compareTo( aThesaurusList, aThesaurusList.getLength() ))
{
// delete old cached data, needs to be acquired new on demand
clearSvcInfoArray(pAvailThesSvcs); pAvailThesSvcs = 0;
OUString aNode( aThesaurusList );
if (lcl_SeqHasString( aThesaurusListEntries, aKeyText ))
{
OUString aPropName( aNode );
aPropName += OUString::valueOf( (sal_Unicode) '/' );
aPropName += aKeyText;
pNames[0] = aPropName;
aValues = /*aCfg.*/GetProperties( aNames );
uno::Sequence< OUString > aSvcImplNames;
if (aValues.getLength())
aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
LanguageType nLang = LANGUAGE_NONE;
if (0 != aKeyText.getLength())
nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
GetThesaurusDsp_Impl( sal_False ); // don't set service list, it will be done below
pThesDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
}
}
else
{
DBG_ASSERT( 0, "nofified for unexpected property" );
}
}
}
void LngSvcMgr::Commit()
{
// everything necessary should have already been done by 'SaveCfgSvcs'
// called from within 'setConfiguredServices'.
// Also this class usually exits only when the Office i sbeing shutdown.
}
void LngSvcMgr::GetListenerHelper_Impl()
{
if (!pListenerHelper)
{
pListenerHelper = new LngSvcMgrListenerHelper( *this,
(XLinguServiceManager *) this, linguistic::GetDictionaryList() );
xListenerHelper = (linguistic2::XLinguServiceEventListener *) pListenerHelper;
}
}
void LngSvcMgr::GetSpellCheckerDsp_Impl( sal_Bool bSetSvcList )
{
if (!pSpellDsp)
{
pSpellDsp = new SpellCheckerDispatcher( *this );
xSpellDsp = pSpellDsp;
if (bSetSvcList)
SetCfgServiceLists( *pSpellDsp );
}
}
void LngSvcMgr::GetGrammarCheckerDsp_Impl( sal_Bool bSetSvcList )
{
if (!pGrammarDsp && SvtLinguConfig().HasGrammarChecker())
{
//! since the grammar checking iterator needs to be a one instance service
//! we need to create it the correct way!
uno::Reference< linguistic2::XProofreadingIterator > xGCI;
try
{
uno::Reference< lang::XMultiServiceFactory > xMgr(
utl::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
xGCI = uno::Reference< linguistic2::XProofreadingIterator >(
xMgr->createInstance( A2OU( SN_GRAMMARCHECKINGITERATOR ) ), uno::UNO_QUERY_THROW );
}
catch (uno::Exception &)
{
}
DBG_ASSERT( xGCI.is(), "instantiating grammar checking iterator failed" );
if (xGCI.is())
{
pGrammarDsp = dynamic_cast< GrammarCheckingIterator * >(xGCI.get());
xGrammarDsp = xGCI;
DBG_ASSERT( pGrammarDsp, "failed to get implementation" );
if (bSetSvcList)
SetCfgServiceLists( *pGrammarDsp );
}
}
}
void LngSvcMgr::GetHyphenatorDsp_Impl( sal_Bool bSetSvcList )
{
if (!pHyphDsp)
{
pHyphDsp = new HyphenatorDispatcher( *this );
xHyphDsp = pHyphDsp;
if (bSetSvcList)
SetCfgServiceLists( *pHyphDsp );
}
}
void LngSvcMgr::GetThesaurusDsp_Impl( sal_Bool bSetSvcList )
{
if (!pThesDsp)
{
pThesDsp = new ThesaurusDispatcher;
xThesDsp = pThesDsp;
if (bSetSvcList)
SetCfgServiceLists( *pThesDsp );
}
}
void LngSvcMgr::GetAvailableSpellSvcs_Impl()
{
if (!pAvailSpellSvcs)
{
pAvailSpellSvcs = new SvcInfoArray;
uno::Reference< lang::XMultiServiceFactory > xFac( utl::getProcessServiceFactory() );
if (xFac.is())
{
uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
uno::Reference< container::XEnumeration > xEnum;
if (xEnumAccess.is())
xEnum = xEnumAccess->createContentEnumeration(
A2OU( SN_SPELLCHECKER ) );
if (xEnum.is())
{
while (xEnum->hasMoreElements())
{
uno::Any aCurrent = xEnum->nextElement();
uno::Reference< lang::XSingleComponentFactory > xCompFactory;
uno::Reference< lang::XSingleServiceFactory > xFactory;
uno::Reference< linguistic2::XSpellChecker > xSvc;
if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
{
try
{
uno::Reference < uno::XComponentContext > xContext;
uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
xSvc = uno::Reference< linguistic2::XSpellChecker >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
}
catch (uno::Exception &rEx)
{
(void) rEx;
DBG_ASSERT( 0, "createInstance failed" );
}
}
if (xSvc.is())
{
OUString aImplName;
uno::Sequence< sal_Int16 > aLanguages;
uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
if (xInfo.is())
aImplName = xInfo->getImplementationName();
DBG_ASSERT( aImplName.getLength(),
"empty implementation name" );
uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
if (xSuppLoc.is()) {
uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
}
pAvailSpellSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
}
}
}
}
}
}
void LngSvcMgr::GetAvailableGrammarSvcs_Impl()
{
if (!pAvailGrammarSvcs)
{
pAvailGrammarSvcs = new SvcInfoArray;
uno::Reference< lang::XMultiServiceFactory > xFac( utl::getProcessServiceFactory() );
if (xFac.is())
{
uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
uno::Reference< container::XEnumeration > xEnum;
if (xEnumAccess.is())
xEnum = xEnumAccess->createContentEnumeration(
A2OU( SN_GRAMMARCHECKER ) );
if (xEnum.is())
{
while (xEnum->hasMoreElements())
{
uno::Any aCurrent = xEnum->nextElement();
uno::Reference< lang::XSingleComponentFactory > xCompFactory;
uno::Reference< lang::XSingleServiceFactory > xFactory;
uno::Reference< linguistic2::XProofreader > xSvc;
if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
{
try
{
uno::Reference < uno::XComponentContext > xContext;
uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
xSvc = uno::Reference< linguistic2::XProofreader >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
}
catch (uno::Exception &rEx)
{
(void) rEx;
DBG_ASSERT( 0, "createInstance failed" );
}
}
if (xSvc.is())
{
OUString aImplName;
uno::Sequence< sal_Int16 > aLanguages;
uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
if (xInfo.is())
aImplName = xInfo->getImplementationName();
DBG_ASSERT( aImplName.getLength(),
"empty implementation name" );
uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
if (xSuppLoc.is()) {
uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
}
pAvailGrammarSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
}
}
}
}
}
}
void LngSvcMgr::GetAvailableHyphSvcs_Impl()
{
if (!pAvailHyphSvcs)
{
pAvailHyphSvcs = new SvcInfoArray;
uno::Reference< lang::XMultiServiceFactory > xFac( utl::getProcessServiceFactory() );
if (xFac.is())
{
uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
uno::Reference< container::XEnumeration > xEnum;
if (xEnumAccess.is())
xEnum = xEnumAccess->createContentEnumeration( A2OU( SN_HYPHENATOR ) );
if (xEnum.is())
{
while (xEnum->hasMoreElements())
{
uno::Any aCurrent = xEnum->nextElement();
uno::Reference< lang::XSingleComponentFactory > xCompFactory;
uno::Reference< lang::XSingleServiceFactory > xFactory;
uno::Reference< linguistic2::XHyphenator > xSvc;
if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
{
try
{
uno::Reference < uno::XComponentContext > xContext;
uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
xSvc = uno::Reference< linguistic2::XHyphenator >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
}
catch (uno::Exception &rEx)
{
(void) rEx;
DBG_ASSERT( 0, "createInstance failed" );
}
}
if (xSvc.is())
{
OUString aImplName;
uno::Sequence< sal_Int16 > aLanguages;
uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
if (xInfo.is())
aImplName = xInfo->getImplementationName();
DBG_ASSERT( aImplName.getLength(),
"empty implementation name" );
uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
if (xSuppLoc.is()) {
uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
}
pAvailHyphSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
}
}
}
}
}
}
void LngSvcMgr::GetAvailableThesSvcs_Impl()
{
if (!pAvailThesSvcs)
{
pAvailThesSvcs = new SvcInfoArray;
uno::Reference< lang::XMultiServiceFactory > xFac( utl::getProcessServiceFactory() );
if (xFac.is())
{
uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
uno::Reference< container::XEnumeration > xEnum;
if (xEnumAccess.is())
xEnum = xEnumAccess->createContentEnumeration(
A2OU( SN_THESAURUS ) );
if (xEnum.is())
{
while (xEnum->hasMoreElements())
{
uno::Any aCurrent = xEnum->nextElement();
uno::Reference< lang::XSingleComponentFactory > xCompFactory;
uno::Reference< lang::XSingleServiceFactory > xFactory;
uno::Reference< linguistic2::XThesaurus > xSvc;
if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
{
try
{
uno::Reference < uno::XComponentContext > xContext;
uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
xSvc = uno::Reference< linguistic2::XThesaurus >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
}
catch (uno::Exception &rEx)
{
(void) rEx;
DBG_ASSERT( 0, "createInstance failed" );
}
}
if (xSvc.is())
{
OUString aImplName;
uno::Sequence< sal_Int16 > aLanguages;
uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
if (xInfo.is())
aImplName = xInfo->getImplementationName();
DBG_ASSERT( aImplName.getLength(),
"empty implementation name" );
uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
if (xSuppLoc.is()) {
uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
}
pAvailThesSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
}
}
}
}
}
}
void LngSvcMgr::SetCfgServiceLists( SpellCheckerDispatcher &rSpellDsp )
{
RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Spell" );
String aNode( String::CreateFromAscii( "ServiceManager/SpellCheckerList" ) );
uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
OUString *pNames = aNames.getArray();
sal_Int32 nLen = aNames.getLength();
// append path prefix need for 'GetProperties' call below
String aPrefix( aNode );
aPrefix.Append( (sal_Unicode) '/' );
for (int i = 0; i < nLen; ++i)
{
OUString aTmp( aPrefix );
aTmp += pNames[i];
pNames[i] = aTmp;
}
uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
if (nLen && nLen == aValues.getLength())
{
const uno::Any *pValues = aValues.getConstArray();
for (sal_Int32 i = 0; i < nLen; ++i)
{
uno::Sequence< OUString > aSvcImplNames;
if (pValues[i] >>= aSvcImplNames)
{
#if OSL_DEBUG_LEVEL > 1
// sal_Int32 nSvcs = aSvcImplNames.getLength();
// const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
#endif
String aLocaleStr( pNames[i] );
xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
rSpellDsp.SetServiceList( aLocale, aSvcImplNames );
}
}
}
}
void LngSvcMgr::SetCfgServiceLists( GrammarCheckingIterator &rGrammarDsp )
{
RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Grammar" );
String aNode( String::CreateFromAscii( "ServiceManager/GrammarCheckerList" ) );
uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
OUString *pNames = aNames.getArray();
sal_Int32 nLen = aNames.getLength();
// append path prefix need for 'GetProperties' call below
String aPrefix( aNode );
aPrefix.Append( (sal_Unicode) '/' );
for (int i = 0; i < nLen; ++i)
{
OUString aTmp( aPrefix );
aTmp += pNames[i];
pNames[i] = aTmp;
}
uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
if (nLen && nLen == aValues.getLength())
{
const uno::Any *pValues = aValues.getConstArray();
for (sal_Int32 i = 0; i < nLen; ++i)
{
uno::Sequence< OUString > aSvcImplNames;
if (pValues[i] >>= aSvcImplNames)
{
// there should only be one grammar checker in use per language...
if (aSvcImplNames.getLength() > 1)
aSvcImplNames.realloc(1);
#if OSL_DEBUG_LEVEL > 1
// sal_Int32 nSvcs = aSvcImplNames.getLength();
// const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
#endif
String aLocaleStr( pNames[i] );
xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
rGrammarDsp.SetServiceList( aLocale, aSvcImplNames );
}
}
}
}
void LngSvcMgr::SetCfgServiceLists( HyphenatorDispatcher &rHyphDsp )
{
RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Hyph" );
String aNode( String::CreateFromAscii( "ServiceManager/HyphenatorList" ) );
uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
OUString *pNames = aNames.getArray();
sal_Int32 nLen = aNames.getLength();
// append path prefix need for 'GetProperties' call below
String aPrefix( aNode );
aPrefix.Append( (sal_Unicode) '/' );
for (int i = 0; i < nLen; ++i)
{
OUString aTmp( aPrefix );
aTmp += pNames[i];
pNames[i] = aTmp;
}
uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
if (nLen && nLen == aValues.getLength())
{
const uno::Any *pValues = aValues.getConstArray();
for (sal_Int32 i = 0; i < nLen; ++i)
{
uno::Sequence< OUString > aSvcImplNames;
if (pValues[i] >>= aSvcImplNames)
{
// there should only be one hyphenator in use per language...
if (aSvcImplNames.getLength() > 1)
aSvcImplNames.realloc(1);
#if OSL_DEBUG_LEVEL > 1
// sal_Int32 nSvcs = aSvcImplNames.getLength();
// const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
#endif
String aLocaleStr( pNames[i] );
xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
rHyphDsp.SetServiceList( aLocale, aSvcImplNames );
}
}
}
}
void LngSvcMgr::SetCfgServiceLists( ThesaurusDispatcher &rThesDsp )
{
RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Thes" );
String aNode( String::CreateFromAscii( "ServiceManager/ThesaurusList" ) );
uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
OUString *pNames = aNames.getArray();
sal_Int32 nLen = aNames.getLength();
// append path prefix need for 'GetProperties' call below
String aPrefix( aNode );
aPrefix.Append( (sal_Unicode) '/' );
for (int i = 0; i < nLen; ++i)
{
OUString aTmp( aPrefix );
aTmp += pNames[i];
pNames[i] = aTmp;
}
uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
if (nLen && nLen == aValues.getLength())
{
const uno::Any *pValues = aValues.getConstArray();
for (sal_Int32 i = 0; i < nLen; ++i)
{
uno::Sequence< OUString > aSvcImplNames;
if (pValues[i] >>= aSvcImplNames)
{
#if OSL_DEBUG_LEVEL > 1
// sal_Int32 nSvcs = aSvcImplNames.getLength();
// const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
#endif
String aLocaleStr( pNames[i] );
xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
rThesDsp.SetServiceList( aLocale, aSvcImplNames );
}
}
}
}
uno::Reference< linguistic2::XSpellChecker > SAL_CALL
LngSvcMgr::getSpellChecker()
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
#if OSL_DEBUG_LEVEL > 1
getAvailableLocales( A2OU( SN_SPELLCHECKER ));
#endif
uno::Reference< linguistic2::XSpellChecker > xRes;
if (!bDisposing)
{
if (!xSpellDsp.is())
GetSpellCheckerDsp_Impl();
xRes = xSpellDsp;
}
return xRes;
}
uno::Reference< linguistic2::XHyphenator > SAL_CALL
LngSvcMgr::getHyphenator()
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
#if OSL_DEBUG_LEVEL > 1
getAvailableLocales( A2OU( SN_HYPHENATOR ));
#endif
uno::Reference< linguistic2::XHyphenator > xRes;
if (!bDisposing)
{
if (!xHyphDsp.is())
GetHyphenatorDsp_Impl();
xRes = xHyphDsp;
}
return xRes;
}
uno::Reference< linguistic2::XThesaurus > SAL_CALL
LngSvcMgr::getThesaurus()
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
#if OSL_DEBUG_LEVEL > 1
getAvailableLocales( A2OU( SN_THESAURUS ));
#endif
uno::Reference< linguistic2::XThesaurus > xRes;
if (!bDisposing)
{
if (!xThesDsp.is())
GetThesaurusDsp_Impl();
xRes = xThesDsp;
}
return xRes;
}
sal_Bool SAL_CALL
LngSvcMgr::addLinguServiceManagerListener(
const uno::Reference< lang::XEventListener >& xListener )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
sal_Bool bRes = sal_False;
if (!bDisposing && xListener.is())
{
if (!pListenerHelper)
GetListenerHelper_Impl();
bRes = pListenerHelper->AddLngSvcMgrListener( xListener );
}
return bRes;
}
sal_Bool SAL_CALL
LngSvcMgr::removeLinguServiceManagerListener(
const uno::Reference< lang::XEventListener >& xListener )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
sal_Bool bRes = sal_False;
if (!bDisposing && xListener.is())
{
DBG_ASSERT( pListenerHelper, "listener removed without being added" );
if (!pListenerHelper)
GetListenerHelper_Impl();
bRes = pListenerHelper->RemoveLngSvcMgrListener( xListener );
}
return bRes;
}
uno::Sequence< OUString > SAL_CALL
LngSvcMgr::getAvailableServices(
const OUString& rServiceName,
const lang::Locale& rLocale )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
uno::Sequence< OUString > aRes;
const SvcInfoArray *pInfoArray = 0;
if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
{
// don't used cached data here (force re-evaluation in order to have downloaded dictionaries
// already found without the need to restart the office
clearSvcInfoArray(pAvailSpellSvcs); pAvailSpellSvcs = 0;
GetAvailableSpellSvcs_Impl();
pInfoArray = pAvailSpellSvcs;
}
else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
{
// don't clear cache as it makes start with some extentions so slow it looks
// like a freeze (a restart is needed anyway after grammar checker installation),
// see https://issues.apache.org/ooo/show_bug.cgi?id=116409
//clearSvcInfoArray(pAvailGrammarSvcs); pAvailGrammarSvcs = 0;
GetAvailableGrammarSvcs_Impl();
pInfoArray = pAvailGrammarSvcs;
}
else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
{
// don't used cached data here (force re-evaluation in order to have downloaded dictionaries
// already found without the need to restart the office
clearSvcInfoArray(pAvailHyphSvcs); pAvailHyphSvcs = 0;
GetAvailableHyphSvcs_Impl();
pInfoArray = pAvailHyphSvcs;
}
else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
{
// don't used cached data here (force re-evaluation in order to have downloaded dictionaries
// already found without the need to restart the office
clearSvcInfoArray(pAvailThesSvcs); pAvailThesSvcs = 0;
GetAvailableThesSvcs_Impl();
pInfoArray = pAvailThesSvcs;
}
if (pInfoArray)
{
// resize to max number of entries
size_t nMaxCnt = pInfoArray->size();
aRes.realloc( nMaxCnt );
OUString *pImplName = aRes.getArray();
sal_uInt16 nCnt = 0;
LanguageType nLanguage = LocaleToLanguage( rLocale );
for (size_t i = 0; i < nMaxCnt; ++i)
{
const SvcInfo *pInfo = (*pInfoArray)[i];
if (LANGUAGE_NONE == nLanguage
|| (pInfo && pInfo->HasLanguage( nLanguage )))
{
pImplName[ nCnt++ ] = pInfo->aSvcImplName;
}
}
// resize to actual number of entries
if (nCnt != nMaxCnt)
aRes.realloc( nCnt );
}
return aRes;
}
uno::Sequence< lang::Locale > SAL_CALL
LngSvcMgr::getAvailableLocales(
const OUString& rServiceName )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
uno::Sequence< lang::Locale > aRes;
uno::Sequence< lang::Locale > *pAvailLocales = NULL;
sal_Bool *pHasAvailLocales = NULL;
if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
{
pAvailLocales = &aAvailSpellLocales;
pHasAvailLocales = &bHasAvailSpellLocales;
}
else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
{
pAvailLocales = &aAvailGrammarLocales;
pHasAvailLocales = &bHasAvailGrammarLocales;
}
else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
{
pAvailLocales = &aAvailHyphLocales;
pHasAvailLocales = &bHasAvailHyphLocales;
}
else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
{
pAvailLocales = &aAvailThesLocales;
pHasAvailLocales = &bHasAvailThesLocales;
}
// about pHasAvailLocales: nowadays (with OOo lingu in SO) we want to know immediately about
// new downloaded dictionaries and have them ready right away if the Tools/Options...
// is used to activate them. Thus we can not rely anymore on buffered data.
if (pAvailLocales /*&& pHasAvailLocales */)
{
// if (!*pHasAvailLocales)
// {
*pAvailLocales = GetAvailLocales(
getAvailableServices( rServiceName, lang::Locale() ) );
// *pHasAvailLocales = sal_True;
// }
aRes = *pAvailLocales;
}
return aRes;
}
static sal_Bool IsEqSvcList( const uno::Sequence< OUString > &rList1,
const uno::Sequence< OUString > &rList2 )
{
// returns sal_True iff both sequences are equal
sal_Bool bRes = sal_False;
sal_Int32 nLen = rList1.getLength();
if (rList2.getLength() == nLen)
{
const OUString *pStr1 = rList1.getConstArray();
const OUString *pStr2 = rList2.getConstArray();
bRes = sal_True;
for (sal_Int32 i = 0; i < nLen && bRes; ++i)
{
if (*pStr1++ != *pStr2++)
bRes = sal_False;
}
}
return bRes;
}
void SAL_CALL
LngSvcMgr::setConfiguredServices(
const OUString& rServiceName,
const lang::Locale& rLocale,
const uno::Sequence< OUString >& rServiceImplNames )
throw(uno::RuntimeException)
{
RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::setConfiguredServices" );
osl::MutexGuard aGuard( GetLinguMutex() );
#if OSL_DEBUG_LEVEL > 1
// const OUString *pImplNames = rServiceImplNames.getConstArray();
#endif
LanguageType nLanguage = LocaleToLanguage( rLocale );
if (LANGUAGE_NONE != nLanguage)
{
if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
{
if (!xSpellDsp.is())
GetSpellCheckerDsp_Impl();
sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
pSpellDsp->GetServiceList( rLocale ) );
if (bChanged)
{
pSpellDsp->SetServiceList( rLocale, rServiceImplNames );
SaveCfgSvcs( A2OU( SN_SPELLCHECKER ) );
if (pListenerHelper && bChanged)
pListenerHelper->AddLngSvcEvt(
linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN |
linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN );
}
}
else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
{
if (!xGrammarDsp.is())
GetGrammarCheckerDsp_Impl();
sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
pGrammarDsp->GetServiceList( rLocale ) );
if (bChanged)
{
pGrammarDsp->SetServiceList( rLocale, rServiceImplNames );
SaveCfgSvcs( A2OU( SN_GRAMMARCHECKER ) );
if (pListenerHelper && bChanged)
pListenerHelper->AddLngSvcEvt(
linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN );
}
}
else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
{
if (!xHyphDsp.is())
GetHyphenatorDsp_Impl();
sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
pHyphDsp->GetServiceList( rLocale ) );
if (bChanged)
{
pHyphDsp->SetServiceList( rLocale, rServiceImplNames );
SaveCfgSvcs( A2OU( SN_HYPHENATOR ) );
if (pListenerHelper && bChanged)
pListenerHelper->AddLngSvcEvt(
linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN );
}
}
else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
{
if (!xThesDsp.is())
GetThesaurusDsp_Impl();
sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
pThesDsp->GetServiceList( rLocale ) );
if (bChanged)
{
pThesDsp->SetServiceList( rLocale, rServiceImplNames );
SaveCfgSvcs( A2OU( SN_THESAURUS ) );
}
}
}
}
sal_Bool LngSvcMgr::SaveCfgSvcs( const String &rServiceName )
{
RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SaveCfgSvcs" );
sal_Bool bRes = sal_False;
LinguDispatcher *pDsp = 0;
uno::Sequence< lang::Locale > aLocales;
if (0 == rServiceName.CompareToAscii( SN_SPELLCHECKER ))
{
if (!pSpellDsp)
GetSpellCheckerDsp_Impl();
pDsp = pSpellDsp;
aLocales = getAvailableLocales( A2OU( SN_SPELLCHECKER ) );
}
else if (0 == rServiceName.CompareToAscii( SN_GRAMMARCHECKER ))
{
if (!pGrammarDsp)
GetGrammarCheckerDsp_Impl();
pDsp = pGrammarDsp;
aLocales = getAvailableLocales( A2OU( SN_GRAMMARCHECKER ) );
}
else if (0 == rServiceName.CompareToAscii( SN_HYPHENATOR ))
{
if (!pHyphDsp)
GetHyphenatorDsp_Impl();
pDsp = pHyphDsp;
aLocales = getAvailableLocales( A2OU( SN_HYPHENATOR ) );
}
else if (0 == rServiceName.CompareToAscii( SN_THESAURUS ))
{
if (!pThesDsp)
GetThesaurusDsp_Impl();
pDsp = pThesDsp;
aLocales = getAvailableLocales( A2OU( SN_THESAURUS ) );
}
if (pDsp && aLocales.getLength())
{
sal_Int32 nLen = aLocales.getLength();
const lang::Locale *pLocale = aLocales.getConstArray();
uno::Sequence< beans::PropertyValue > aValues( nLen );
beans::PropertyValue *pValues = aValues.getArray();
beans::PropertyValue *pValue = pValues;
// get node name to be used
const char *pNodeName = NULL;
if (pDsp == pSpellDsp)
pNodeName = "ServiceManager/SpellCheckerList";
else if (pDsp == pGrammarDsp)
pNodeName = "ServiceManager/GrammarCheckerList";
else if (pDsp == pHyphDsp)
pNodeName = "ServiceManager/HyphenatorList";
else if (pDsp == pThesDsp)
pNodeName = "ServiceManager/ThesaurusList";
else
{
DBG_ASSERT( 0, "node name missing" );
}
OUString aNodeName( A2OU(pNodeName) );
for (sal_Int32 i = 0; i < nLen; ++i)
{
uno::Sequence< OUString > aSvcImplNames;
aSvcImplNames = pDsp->GetServiceList( pLocale[i] );
#if OSL_DEBUG_LEVEL > 1
sal_Int32 nSvcs = aSvcImplNames.getLength();
const OUString *pSvcImplName = aSvcImplNames.getConstArray();
for (sal_Int32 j = 0; j < nSvcs; ++j)
{
OUString aImplName( pSvcImplName[j] );
}
#endif
// build value to be written back to configuration
uno::Any aCfgAny;
if ((pDsp == pHyphDsp || pDsp == pGrammarDsp) && aSvcImplNames.getLength() > 1)
aSvcImplNames.realloc(1); // there should be only one entry for hyphenators or grammar checkers (because they are not chained)
aCfgAny <<= aSvcImplNames;
DBG_ASSERT( aCfgAny.hasValue(), "missing value for 'Any' type" );
OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString(
LocaleToLanguage( pLocale[i] ) ) );
pValue->Value = aCfgAny;
pValue->Name = aNodeName;
pValue->Name += OUString::valueOf( (sal_Unicode) '/' );
pValue->Name += aCfgLocaleStr;
pValue++;
}
{
RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SaveCfgSvcs - ReplaceSetProperties" );
// change, add new or replace existing entries.
bRes |= /*aCfg.*/ReplaceSetProperties( aNodeName, aValues );
}
}
return bRes;
}
static uno::Sequence< OUString > GetLangSvcList( const uno::Any &rVal )
{
uno::Sequence< OUString > aRes;
if (rVal.hasValue())
{
rVal >>= aRes;
#if OSL_DEBUG_LEVEL > 1
sal_Int32 nSvcs = aRes.getLength();
if (nSvcs)
{
const OUString *pSvcName = aRes.getConstArray();
for (sal_Int32 j = 0; j < nSvcs; ++j)
{
OUString aImplName( pSvcName[j] );
DBG_ASSERT( aImplName.getLength(), "service impl-name missing" );
}
}
#endif
}
return aRes;
}
static uno::Sequence< OUString > GetLangSvc( const uno::Any &rVal )
{
uno::Sequence< OUString > aRes;
if (!rVal.hasValue())
return aRes;
// allowing for a sequence here as well (even though it should only
// be a string) makes coding easier in other places since one needs
// not make a special case for writing a string only and not a
// sequence of strings.
if (rVal >>= aRes)
{
// but only the first string should be used.
if (aRes.getLength() > 1)
aRes.realloc(1);
}
else
{
OUString aImplName;
if ((rVal >>= aImplName) && aImplName.getLength() != 0)
{
aRes.realloc(1);
aRes.getArray()[0] = aImplName;
}
else
{
DBG_ASSERT( 0, "GetLangSvc: unexpected type encountered" );
}
}
return aRes;
}
///////////////////////////////////////////////////////////////////////////
uno::Sequence< OUString > SAL_CALL
LngSvcMgr::getConfiguredServices(
const OUString& rServiceName,
const lang::Locale& rLocale )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
uno::Sequence< OUString > aSvcImplNames;
LanguageType nLanguage = LocaleToLanguage( rLocale );
OUString aCfgLocale( MsLangId::convertLanguageToIsoString( nLanguage ) );
uno::Sequence< uno::Any > aValues;
uno::Sequence< OUString > aNames( 1 );
OUString *pNames = aNames.getArray();
if ( 0 == rServiceName.compareToAscii( SN_SPELLCHECKER ) )
{
OUString aNode( OUString::createFromAscii( "ServiceManager/SpellCheckerList" ));
const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
{
OUString aPropName( aNode );
aPropName += OUString::valueOf( (sal_Unicode) '/' );
aPropName += aCfgLocale;
pNames[0] = aPropName;
aValues = /*aCfg.*/GetProperties( aNames );
if (aValues.getLength())
aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
}
}
else if ( 0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ) )
{
OUString aNode( OUString::createFromAscii( "ServiceManager/GrammarCheckerList" ));
const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
{
OUString aPropName( aNode );
aPropName += OUString::valueOf( (sal_Unicode) '/' );
aPropName += aCfgLocale;
pNames[0] = aPropName;
aValues = /*aCfg.*/GetProperties( aNames );
if (aValues.getLength())
aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
}
}
else if ( 0 == rServiceName.compareToAscii( SN_HYPHENATOR ) )
{
OUString aNode( OUString::createFromAscii( "ServiceManager/HyphenatorList" ));
const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
{
OUString aPropName( aNode );
aPropName += OUString::valueOf( (sal_Unicode) '/' );
aPropName += aCfgLocale;
pNames[0] = aPropName;
aValues = /*aCfg.*/GetProperties( aNames );
if (aValues.getLength())
aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
}
}
else if ( 0 == rServiceName.compareToAscii( SN_THESAURUS ) )
{
OUString aNode( OUString::createFromAscii( "ServiceManager/ThesaurusList" ));
const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
{
OUString aPropName( aNode );
aPropName += OUString::valueOf( (sal_Unicode) '/' );
aPropName += aCfgLocale;
pNames[0] = aPropName;
aValues = /*aCfg.*/GetProperties( aNames );
if (aValues.getLength())
aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
}
}
#if OSL_DEBUG_LEVEL > 1
const OUString *pImplNames = aSvcImplNames.getConstArray();
(void) pImplNames;
#endif
return aSvcImplNames;
}
void SAL_CALL
LngSvcMgr::dispose()
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
if (!bDisposing)
{
bDisposing = sal_True;
// require listeners to release this object
lang::EventObject aEvtObj( (XLinguServiceManager *) this );
aEvtListeners.disposeAndClear( aEvtObj );
if (pListenerHelper)
pListenerHelper->DisposeAndClear( aEvtObj );
}
}
void SAL_CALL
LngSvcMgr::addEventListener(
const uno::Reference< lang::XEventListener >& xListener )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
if (!bDisposing && xListener.is())
{
aEvtListeners.addInterface( xListener );
}
}
void SAL_CALL
LngSvcMgr::removeEventListener(
const uno::Reference< lang::XEventListener >& xListener )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
if (xListener.is())
{
aEvtListeners.removeInterface( xListener );
}
}
sal_Bool LngSvcMgr::AddLngSvcEvtBroadcaster(
const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
{
sal_Bool bRes = sal_False;
if (rxBroadcaster.is())
{
if (!pListenerHelper)
GetListenerHelper_Impl();
bRes = pListenerHelper->AddLngSvcEvtBroadcaster( rxBroadcaster );
}
return bRes;
}
sal_Bool LngSvcMgr::RemoveLngSvcEvtBroadcaster(
const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
{
sal_Bool bRes = sal_False;
if (rxBroadcaster.is())
{
DBG_ASSERT( pListenerHelper, "pListenerHelper non existent" );
if (!pListenerHelper)
GetListenerHelper_Impl();
bRes = pListenerHelper->RemoveLngSvcEvtBroadcaster( rxBroadcaster );
}
return bRes;
}
OUString SAL_CALL
LngSvcMgr::getImplementationName()
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
return getImplementationName_Static();
}
sal_Bool SAL_CALL
LngSvcMgr::supportsService( const OUString& ServiceName )
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
uno::Sequence< OUString > aSNL = getSupportedServiceNames();
const OUString * pArray = aSNL.getConstArray();
for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
if( pArray[i] == ServiceName )
return sal_True;
return sal_False;
}
uno::Sequence< OUString > SAL_CALL
LngSvcMgr::getSupportedServiceNames()
throw(uno::RuntimeException)
{
osl::MutexGuard aGuard( GetLinguMutex() );
return getSupportedServiceNames_Static();
}
uno::Sequence< OUString > LngSvcMgr::getSupportedServiceNames_Static()
throw()
{
osl::MutexGuard aGuard( GetLinguMutex() );
uno::Sequence< OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich
aSNS.getArray()[0] = A2OU( SN_LINGU_SERVCICE_MANAGER );
return aSNS;
}
uno::Reference< uno::XInterface > SAL_CALL LngSvcMgr_CreateInstance(
const uno::Reference< lang::XMultiServiceFactory > & /*rSMgr*/ )
throw(uno::Exception)
{
uno::Reference< uno::XInterface > xService = (cppu::OWeakObject*) new LngSvcMgr;
return xService;
}
void * SAL_CALL LngSvcMgr_getFactory(
const sal_Char * pImplName,
lang::XMultiServiceFactory * pServiceManager,
void * /*pRegistryKey*/ )
{
void * pRet = 0;
if ( !LngSvcMgr::getImplementationName_Static().compareToAscii( pImplName ) )
{
uno::Reference< lang::XSingleServiceFactory > xFactory =
cppu::createOneInstanceFactory(
pServiceManager,
LngSvcMgr::getImplementationName_Static(),
LngSvcMgr_CreateInstance,
LngSvcMgr::getSupportedServiceNames_Static());
// acquire, because we return an interface pointer instead of a reference
xFactory->acquire();
pRet = xFactory.get();
}
return pRet;
}
///////////////////////////////////////////////////////////////////////////