Version 4.0.2.1, tag libreoffice-4.0.2.1
[LibreOffice.git] / linguistic / source / lngsvcmgr.cxx
blobfefef1cdc0094bb5a83127ba7cafc3dc620270dc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <com/sun/star/deployment/ExtensionManager.hpp>
22 #include <com/sun/star/registry/XRegistryKey.hpp>
23 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
24 #include <com/sun/star/container/XEnumeration.hpp>
25 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
26 #include <com/sun/star/linguistic2/XSupportedLocales.hpp>
27 #include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
28 #include <com/sun/star/linguistic2/LinguServiceEventFlags.hpp>
30 #include <tools/solar.h>
31 #include <unotools/lingucfg.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <i18npool/lang.h>
34 #include <i18npool/languagetag.hxx>
35 #include <cppuhelper/factory.hxx>
36 #include <comphelper/extract.hxx>
37 #include <rtl/logfile.hxx>
39 #include <boost/checked_delete.hpp>
41 #include "lngsvcmgr.hxx"
42 #include "lngopt.hxx"
43 #include "linguistic/misc.hxx"
44 #include "spelldsp.hxx"
45 #include "hyphdsp.hxx"
46 #include "thesdsp.hxx"
47 #include "gciterator.hxx"
50 using namespace com::sun::star;
51 using namespace linguistic;
52 using ::rtl::OUString;
54 // forward declarations
55 uno::Sequence< OUString > static GetLangSvcList( const uno::Any &rVal );
56 uno::Sequence< OUString > static GetLangSvc( const uno::Any &rVal );
59 static sal_Bool lcl_SeqHasString( const uno::Sequence< OUString > &rSeq, const OUString &rText )
61 sal_Bool bRes = sal_False;
63 sal_Int32 nLen = rSeq.getLength();
64 if (nLen == 0 || rText.isEmpty())
65 return bRes;
67 const OUString *pSeq = rSeq.getConstArray();
68 for (sal_Int32 i = 0; i < nLen && !bRes; ++i)
70 if (rText == pSeq[i])
71 bRes = sal_True;
73 return bRes;
77 static uno::Sequence< lang::Locale > GetAvailLocales(
78 const uno::Sequence< OUString > &rSvcImplNames )
80 uno::Sequence< lang::Locale > aRes;
82 uno::Reference< lang::XMultiServiceFactory > xFac( comphelper::getProcessServiceFactory() );
83 sal_Int32 nNames = rSvcImplNames.getLength();
84 if (nNames && xFac.is())
86 std::set< LanguageType > aLanguages;
88 //! since we're going to create one-instance services we have to
89 //! supply their arguments even if we would not need them here...
90 uno::Sequence< uno::Any > aArgs(2);
91 aArgs.getArray()[0] <<= GetLinguProperties();
93 // check all services for the supported languages and new
94 // languages to the result
95 const OUString *pImplNames = rSvcImplNames.getConstArray();
96 sal_Int32 i;
98 for (i = 0; i < nNames; ++i)
100 uno::Reference< linguistic2::XSupportedLocales > xSuppLoc;
103 xSuppLoc = uno::Reference< linguistic2::XSupportedLocales >(
104 xFac->createInstanceWithArguments( pImplNames[i], aArgs ), uno::UNO_QUERY );
106 catch (uno::Exception &)
108 DBG_ASSERT( 0, "createInstanceWithArguments failed" );
111 if (xSuppLoc.is())
113 uno::Sequence< lang::Locale > aLoc( xSuppLoc->getLocales() );
114 sal_Int32 nLoc = aLoc.getLength();
115 for (sal_Int32 k = 0; k < nLoc; ++k)
117 const lang::Locale *pLoc = aLoc.getConstArray();
118 LanguageType nLang = LinguLocaleToLanguage( pLoc[k] );
120 // language not already added?
121 if (aLanguages.find( nLang ) == aLanguages.end())
122 aLanguages.insert( nLang );
125 else
127 DBG_ASSERT( 0, "interface not supported by service" );
131 // build return sequence
132 sal_Int32 nLanguages = static_cast< sal_Int32 >(aLanguages.size());
133 aRes.realloc( nLanguages );
134 lang::Locale *pRes = aRes.getArray();
135 std::set< LanguageType >::const_iterator aIt( aLanguages.begin() );
136 for (i = 0; aIt != aLanguages.end(); ++aIt, ++i)
138 LanguageType nLang = *aIt;
139 pRes[i] = LanguageTag( nLang ).getLocale();
143 return aRes;
147 struct SvcInfo
149 const OUString aSvcImplName;
150 const uno::Sequence< sal_Int16 > aSuppLanguages;
152 SvcInfo( const OUString &rSvcImplName,
153 const uno::Sequence< sal_Int16 > &rSuppLanguages ) :
154 aSvcImplName (rSvcImplName),
155 aSuppLanguages (rSuppLanguages)
159 sal_Bool HasLanguage( sal_Int16 nLanguage ) const;
163 sal_Bool SvcInfo::HasLanguage( sal_Int16 nLanguage ) const
165 sal_Int32 nCnt = aSuppLanguages.getLength();
166 const sal_Int16 *pLang = aSuppLanguages.getConstArray();
167 sal_Int32 i;
169 for ( i = 0; i < nCnt; ++i)
171 if (nLanguage == pLang[i])
172 break;
174 return i < nCnt;
177 class LngSvcMgrListenerHelper :
178 public cppu::WeakImplHelper2
180 linguistic2::XLinguServiceEventListener,
181 linguistic2::XDictionaryListEventListener
184 LngSvcMgr &rMyManager;
186 ::cppu::OInterfaceContainerHelper aLngSvcMgrListeners;
187 ::cppu::OInterfaceContainerHelper aLngSvcEvtBroadcasters;
188 uno::Reference< linguistic2::XDictionaryList > xDicList;
190 sal_Int16 nCombinedLngSvcEvt;
192 // disallow copy-constructor and assignment-operator for now
193 LngSvcMgrListenerHelper(const LngSvcMgrListenerHelper &);
194 LngSvcMgrListenerHelper & operator = (const LngSvcMgrListenerHelper &);
196 void LaunchEvent( sal_Int16 nLngSvcEvtFlags );
198 long Timeout();
200 public:
201 LngSvcMgrListenerHelper( LngSvcMgr &rLngSvcMgr,
202 const uno::Reference< linguistic2::XDictionaryList > &rxDicList );
204 // lang::XEventListener
205 virtual void SAL_CALL
206 disposing( const lang::EventObject& rSource )
207 throw(uno::RuntimeException);
209 // linguistic2::XLinguServiceEventListener
210 virtual void SAL_CALL
211 processLinguServiceEvent( const linguistic2::LinguServiceEvent& aLngSvcEvent )
212 throw(uno::RuntimeException);
214 // linguistic2::XDictionaryListEventListener
215 virtual void SAL_CALL
216 processDictionaryListEvent(
217 const linguistic2::DictionaryListEvent& rDicListEvent )
218 throw(uno::RuntimeException);
220 inline sal_Bool AddLngSvcMgrListener(
221 const uno::Reference< lang::XEventListener >& rxListener );
222 inline sal_Bool RemoveLngSvcMgrListener(
223 const uno::Reference< lang::XEventListener >& rxListener );
224 void DisposeAndClear( const lang::EventObject &rEvtObj );
225 sal_Bool AddLngSvcEvtBroadcaster(
226 const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
227 sal_Bool RemoveLngSvcEvtBroadcaster(
228 const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
230 void AddLngSvcEvt( sal_Int16 nLngSvcEvt );
234 LngSvcMgrListenerHelper::LngSvcMgrListenerHelper(
235 LngSvcMgr &rLngSvcMgr,
236 const uno::Reference< linguistic2::XDictionaryList > &rxDicList ) :
237 rMyManager ( rLngSvcMgr ),
238 aLngSvcMgrListeners ( GetLinguMutex() ),
239 aLngSvcEvtBroadcasters ( GetLinguMutex() ),
240 xDicList ( rxDicList )
242 if (xDicList.is())
244 xDicList->addDictionaryListEventListener(
245 (linguistic2::XDictionaryListEventListener *) this, sal_False );
248 nCombinedLngSvcEvt = 0;
252 void SAL_CALL LngSvcMgrListenerHelper::disposing( const lang::EventObject& rSource )
253 throw(uno::RuntimeException)
255 osl::MutexGuard aGuard( GetLinguMutex() );
257 uno::Reference< uno::XInterface > xRef( rSource.Source );
258 if ( xRef.is() )
260 aLngSvcMgrListeners .removeInterface( xRef );
261 aLngSvcEvtBroadcasters.removeInterface( xRef );
262 if (xDicList == xRef)
263 xDicList = 0;
267 long LngSvcMgrListenerHelper::Timeout()
269 osl::MutexGuard aGuard( GetLinguMutex() );
272 // change event source to LinguServiceManager since the listeners
273 // probably do not know (and need not to know) about the specific
274 // SpellChecker's or Hyphenator's.
275 linguistic2::LinguServiceEvent aEvtObj(
276 static_cast<com::sun::star::linguistic2::XLinguServiceManager*>(&rMyManager), nCombinedLngSvcEvt );
277 nCombinedLngSvcEvt = 0;
279 if (rMyManager.pSpellDsp)
280 rMyManager.pSpellDsp->FlushSpellCache();
282 // pass event on to linguistic2::XLinguServiceEventListener's
283 cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
284 while (aIt.hasMoreElements())
286 uno::Reference< linguistic2::XLinguServiceEventListener > xRef( aIt.next(), uno::UNO_QUERY );
287 if (xRef.is())
288 xRef->processLinguServiceEvent( aEvtObj );
291 return 0;
295 void LngSvcMgrListenerHelper::AddLngSvcEvt( sal_Int16 nLngSvcEvt )
297 nCombinedLngSvcEvt |= nLngSvcEvt;
298 Timeout();
302 void SAL_CALL
303 LngSvcMgrListenerHelper::processLinguServiceEvent(
304 const linguistic2::LinguServiceEvent& rLngSvcEvent )
305 throw(uno::RuntimeException)
307 osl::MutexGuard aGuard( GetLinguMutex() );
308 AddLngSvcEvt( rLngSvcEvent.nEvent );
312 void SAL_CALL
313 LngSvcMgrListenerHelper::processDictionaryListEvent(
314 const linguistic2::DictionaryListEvent& rDicListEvent )
315 throw(uno::RuntimeException)
317 osl::MutexGuard aGuard( GetLinguMutex() );
319 sal_Int16 nDlEvt = rDicListEvent.nCondensedEvent;
320 if (0 == nDlEvt)
321 return;
323 // we do keep the original event source here though...
325 // pass event on to linguistic2::XDictionaryListEventListener's
326 cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
327 while (aIt.hasMoreElements())
329 uno::Reference< linguistic2::XDictionaryListEventListener > xRef( aIt.next(), uno::UNO_QUERY );
330 if (xRef.is())
331 xRef->processDictionaryListEvent( rDicListEvent );
334 // "translate" DictionaryList event into linguistic2::LinguServiceEvent
335 sal_Int16 nLngSvcEvt = 0;
336 sal_Int16 nSpellCorrectFlags =
337 linguistic2::DictionaryListEventFlags::ADD_NEG_ENTRY |
338 linguistic2::DictionaryListEventFlags::DEL_POS_ENTRY |
339 linguistic2::DictionaryListEventFlags::ACTIVATE_NEG_DIC |
340 linguistic2::DictionaryListEventFlags::DEACTIVATE_POS_DIC;
341 if (0 != (nDlEvt & nSpellCorrectFlags))
342 nLngSvcEvt |= linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN;
344 sal_Int16 nSpellWrongFlags =
345 linguistic2::DictionaryListEventFlags::ADD_POS_ENTRY |
346 linguistic2::DictionaryListEventFlags::DEL_NEG_ENTRY |
347 linguistic2::DictionaryListEventFlags::ACTIVATE_POS_DIC |
348 linguistic2::DictionaryListEventFlags::DEACTIVATE_NEG_DIC;
349 if (0 != (nDlEvt & nSpellWrongFlags))
350 nLngSvcEvt |= linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN;
352 sal_Int16 nHyphenateFlags =
353 linguistic2::DictionaryListEventFlags::ADD_POS_ENTRY |
354 linguistic2::DictionaryListEventFlags::DEL_POS_ENTRY |
355 linguistic2::DictionaryListEventFlags::ACTIVATE_POS_DIC |
356 linguistic2::DictionaryListEventFlags::ACTIVATE_NEG_DIC;
357 if (0 != (nDlEvt & nHyphenateFlags))
358 nLngSvcEvt |= linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN;
360 if (rMyManager.pSpellDsp)
361 rMyManager.pSpellDsp->FlushSpellCache();
362 if (nLngSvcEvt)
363 LaunchEvent( nLngSvcEvt );
367 void LngSvcMgrListenerHelper::LaunchEvent( sal_Int16 nLngSvcEvtFlags )
369 linguistic2::LinguServiceEvent aEvt(
370 static_cast<com::sun::star::linguistic2::XLinguServiceManager*>(&rMyManager), nLngSvcEvtFlags );
372 // pass event on to linguistic2::XLinguServiceEventListener's
373 cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
374 while (aIt.hasMoreElements())
376 uno::Reference< linguistic2::XLinguServiceEventListener > xRef( aIt.next(), uno::UNO_QUERY );
377 if (xRef.is())
378 xRef->processLinguServiceEvent( aEvt );
383 inline sal_Bool LngSvcMgrListenerHelper::AddLngSvcMgrListener(
384 const uno::Reference< lang::XEventListener >& rxListener )
386 aLngSvcMgrListeners.addInterface( rxListener );
387 return sal_True;
391 inline sal_Bool LngSvcMgrListenerHelper::RemoveLngSvcMgrListener(
392 const uno::Reference< lang::XEventListener >& rxListener )
394 aLngSvcMgrListeners.removeInterface( rxListener );
395 return sal_True;
399 void LngSvcMgrListenerHelper::DisposeAndClear( const lang::EventObject &rEvtObj )
401 // call "disposing" for all listeners and clear list
402 aLngSvcMgrListeners .disposeAndClear( rEvtObj );
404 // remove references to this object hold by the broadcasters
405 cppu::OInterfaceIteratorHelper aIt( aLngSvcEvtBroadcasters );
406 while (aIt.hasMoreElements())
408 uno::Reference< linguistic2::XLinguServiceEventBroadcaster > xRef( aIt.next(), uno::UNO_QUERY );
409 if (xRef.is())
410 RemoveLngSvcEvtBroadcaster( xRef );
413 // remove refernce to this object hold by the dictionary-list
414 if (xDicList.is())
416 xDicList->removeDictionaryListEventListener(
417 (linguistic2::XDictionaryListEventListener *) this );
418 xDicList = 0;
423 sal_Bool LngSvcMgrListenerHelper::AddLngSvcEvtBroadcaster(
424 const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
426 sal_Bool bRes = sal_False;
427 if (rxBroadcaster.is())
429 aLngSvcEvtBroadcasters.addInterface( rxBroadcaster );
430 rxBroadcaster->addLinguServiceEventListener(
431 (linguistic2::XLinguServiceEventListener *) this );
433 return bRes;
437 sal_Bool LngSvcMgrListenerHelper::RemoveLngSvcEvtBroadcaster(
438 const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
440 sal_Bool bRes = sal_False;
441 if (rxBroadcaster.is())
443 aLngSvcEvtBroadcasters.removeInterface( rxBroadcaster );
444 rxBroadcaster->removeLinguServiceEventListener(
445 (linguistic2::XLinguServiceEventListener *) this );
447 return bRes;
453 LngSvcMgr::LngSvcMgr()
454 : utl::ConfigItem("Office.Linguistic")
455 , aEvtListeners(GetLinguMutex())
457 bDisposing = sal_False;
459 pSpellDsp = 0;
460 pGrammarDsp = 0;
461 pHyphDsp = 0;
462 pThesDsp = 0;
464 pAvailSpellSvcs = 0;
465 pAvailGrammarSvcs = 0;
466 pAvailHyphSvcs = 0;
467 pAvailThesSvcs = 0;
468 pListenerHelper = 0;
470 // request notify events when properties (i.e. something in the subtree) changes
471 uno::Sequence< OUString > aNames(4);
472 OUString *pNames = aNames.getArray();
473 pNames[0] = "ServiceManager/SpellCheckerList";
474 pNames[1] = "ServiceManager/GrammarCheckerList";
475 pNames[2] = "ServiceManager/HyphenatorList";
476 pNames[3] = "ServiceManager/ThesaurusList";
477 EnableNotification( aNames );
479 UpdateAll();
481 aUpdateTimer.SetTimeout(500);
482 aUpdateTimer.SetTimeoutHdl(LINK(this, LngSvcMgr, updateAndBroadcast));
484 // request to be notified if an extension has been added/removed
485 uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
487 uno::Reference<deployment::XExtensionManager> xExtensionManager;
488 try {
489 xExtensionManager = deployment::ExtensionManager::get(xContext);
490 } catch ( const uno::DeploymentException & ) {
491 SAL_WARN( "linguistic", "no extension manager - should fire on mobile only" );
492 } catch ( const deployment::DeploymentException & ) {
493 SAL_WARN( "linguistic", "no extension manager - should fire on mobile only" );
495 if (xExtensionManager.is())
497 xMB = uno::Reference<util::XModifyBroadcaster>(xExtensionManager, uno::UNO_QUERY_THROW);
499 uno::Reference<util::XModifyListener> xListener(this);
500 xMB->addModifyListener( xListener );
504 // ::com::sun::star::util::XModifyListener
505 void LngSvcMgr::modified(const lang::EventObject&)
506 throw(uno::RuntimeException)
508 osl::MutexGuard aGuard(GetLinguMutex());
509 //assume that if an extension has been added/removed that
510 //it might be a dictionary extension, so drop our cache
512 clearSvcInfoArray(pAvailSpellSvcs);
513 clearSvcInfoArray(pAvailGrammarSvcs);
514 clearSvcInfoArray(pAvailHyphSvcs);
515 clearSvcInfoArray(pAvailThesSvcs);
517 //schedule in an update to execute in the main thread
518 aUpdateTimer.Start();
521 //run update, and inform everyone that dictionaries (may) have changed, this
522 //needs to be run in the main thread because
523 //utl::ConfigChangeListener_Impl::changesOccurred grabs the SolarMutex and we
524 //get notified that an extension was added from an extension manager thread
525 IMPL_LINK_NOARG(LngSvcMgr, updateAndBroadcast)
527 osl::MutexGuard aGuard( GetLinguMutex() );
529 UpdateAll();
531 if (pListenerHelper)
533 pListenerHelper->AddLngSvcEvt(
534 linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN |
535 linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN |
536 linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN |
537 linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN );
540 return 0;
543 void LngSvcMgr::stopListening()
545 osl::MutexGuard aGuard(GetLinguMutex());
547 if (xMB.is())
551 uno::Reference<util::XModifyListener> xListener(this);
552 xMB->removeModifyListener(xListener);
554 catch (const uno::Exception&)
558 xMB.clear();
562 void LngSvcMgr::disposing(const lang::EventObject&)
563 throw (uno::RuntimeException)
565 stopListening();
568 void LngSvcMgr::clearSvcInfoArray(SvcInfoArray* &rpInfo)
570 delete rpInfo;
571 rpInfo = NULL;
574 LngSvcMgr::~LngSvcMgr()
576 stopListening();
578 // memory for pSpellDsp, pHyphDsp, pThesDsp, pListenerHelper
579 // will be freed in the destructor of the respective Reference's
580 // xSpellDsp, xGrammarDsp, xHyphDsp, xThesDsp
582 clearSvcInfoArray(pAvailSpellSvcs);
583 clearSvcInfoArray(pAvailGrammarSvcs);
584 clearSvcInfoArray(pAvailHyphSvcs);
585 clearSvcInfoArray(pAvailThesSvcs);
588 namespace
590 using lang::Locale;
591 using uno::Any;
592 using uno::Sequence;
594 sal_Bool lcl_FindEntry( const OUString &rEntry, const Sequence< OUString > &rCfgSvcs )
596 sal_Int32 nRes = -1;
597 sal_Int32 nEntries = rCfgSvcs.getLength();
598 const OUString *pEntry = rCfgSvcs.getConstArray();
599 for (sal_Int32 i = 0; i < nEntries && nRes == -1; ++i)
601 if (rEntry == pEntry[i])
602 nRes = i;
604 return nRes != -1;
607 Sequence< OUString > lcl_GetLastFoundSvcs(
608 SvtLinguConfig &rCfg,
609 const OUString &rLastFoundList ,
610 const Locale &rAvailLocale )
612 Sequence< OUString > aRes;
614 OUString aCfgLocaleStr( LanguageTag( rAvailLocale ).getBcp47() );
616 Sequence< OUString > aNodeNames( rCfg.GetNodeNames(rLastFoundList) );
617 sal_Bool bFound = lcl_FindEntry( aCfgLocaleStr, aNodeNames);
619 if (bFound)
621 Sequence< OUString > aNames(1);
622 OUString &rNodeName = aNames.getArray()[0];
623 rNodeName = rLastFoundList;
624 rNodeName += OUString::valueOf( (sal_Unicode)'/' );
625 rNodeName += aCfgLocaleStr;
626 Sequence< Any > aValues( rCfg.GetProperties( aNames ) );
627 if (aValues.getLength())
629 OSL_ENSURE( aValues.getLength() == 1, "unexpected length of sequence" );
630 Sequence< OUString > aSvcImplNames;
631 if (aValues.getConstArray()[0] >>= aSvcImplNames)
632 aRes = aSvcImplNames;
633 else
635 OSL_FAIL( "type mismatch" );
640 return aRes;
643 Sequence< OUString > lcl_RemoveMissingEntries(
644 const Sequence< OUString > &rCfgSvcs,
645 const Sequence< OUString > &rAvailSvcs )
647 Sequence< OUString > aRes( rCfgSvcs.getLength() );
648 OUString *pRes = aRes.getArray();
649 sal_Int32 nCnt = 0;
651 sal_Int32 nEntries = rCfgSvcs.getLength();
652 const OUString *pEntry = rCfgSvcs.getConstArray();
653 for (sal_Int32 i = 0; i < nEntries; ++i)
655 if (!pEntry[i].isEmpty() && lcl_FindEntry( pEntry[i], rAvailSvcs ))
656 pRes[ nCnt++ ] = pEntry[i];
659 aRes.realloc( nCnt );
660 return aRes;
663 Sequence< OUString > lcl_GetNewEntries(
664 const Sequence< OUString > &rLastFoundSvcs,
665 const Sequence< OUString > &rAvailSvcs )
667 sal_Int32 nLen = rAvailSvcs.getLength();
668 Sequence< OUString > aRes( nLen );
669 OUString *pRes = aRes.getArray();
670 sal_Int32 nCnt = 0;
672 const OUString *pEntry = rAvailSvcs.getConstArray();
673 for (sal_Int32 i = 0; i < nLen; ++i)
675 if (!pEntry[i].isEmpty() && !lcl_FindEntry( pEntry[i], rLastFoundSvcs ))
676 pRes[ nCnt++ ] = pEntry[i];
679 aRes.realloc( nCnt );
680 return aRes;
683 Sequence< OUString > lcl_MergeSeq(
684 const Sequence< OUString > &rCfgSvcs,
685 const Sequence< OUString > &rNewSvcs )
687 Sequence< OUString > aRes( rCfgSvcs.getLength() + rNewSvcs.getLength() );
688 OUString *pRes = aRes.getArray();
689 sal_Int32 nCnt = 0;
691 for (sal_Int32 k = 0; k < 2; ++k)
693 // add previously configuerd service first and append
694 // new found services at the end
695 const Sequence< OUString > &rSeq = k == 0 ? rCfgSvcs : rNewSvcs;
697 sal_Int32 nLen = rSeq.getLength();
698 const OUString *pEntry = rSeq.getConstArray();
699 for (sal_Int32 i = 0; i < nLen; ++i)
701 if (!pEntry[i].isEmpty() && !lcl_FindEntry( pEntry[i], aRes ))
702 pRes[ nCnt++ ] = pEntry[i];
706 aRes.realloc( nCnt );
707 return aRes;
711 void LngSvcMgr::UpdateAll()
713 using beans::PropertyValue;
714 using lang::Locale;
715 using uno::Sequence;
717 typedef OUString OUstring_t;
718 typedef Sequence< OUString > Sequence_OUString_t;
719 typedef std::map< OUstring_t, Sequence_OUString_t > list_entry_map_t;
721 SvtLinguConfig aCfg;
723 const int nNumServices = 4;
724 const sal_Char * apServices[nNumServices] = { SN_SPELLCHECKER, SN_GRAMMARCHECKER, SN_HYPHENATOR, SN_THESAURUS };
725 const sal_Char * apCurLists[nNumServices] = { "ServiceManager/SpellCheckerList", "ServiceManager/GrammarCheckerList", "ServiceManager/HyphenatorList", "ServiceManager/ThesaurusList" };
726 const sal_Char * apLastFoundLists[nNumServices] = { "ServiceManager/LastFoundSpellCheckers", "ServiceManager/LastFoundGrammarCheckers", "ServiceManager/LastFoundHyphenators", "ServiceManager/LastFoundThesauri" };
728 // usage of indices as above: 0 = spell checker, 1 = grammar checker, 2 = hyphenator, 3 = thesaurus
729 std::vector< list_entry_map_t > aLastFoundSvcs(nNumServices);
730 std::vector< list_entry_map_t > aCurSvcs(nNumServices);
732 for (int k = 0; k < nNumServices; ++k)
734 OUString aService( ::rtl::OUString::createFromAscii( apServices[k] ) );
735 OUString aActiveList( ::rtl::OUString::createFromAscii( apCurLists[k] ) );
736 OUString aLastFoundList( ::rtl::OUString::createFromAscii( apLastFoundLists[k] ) );
737 sal_Int32 i;
740 // remove configured but not available language/services entries
742 Sequence< OUString > aNodeNames( aCfg.GetNodeNames( aActiveList ) ); // list of configured locales
743 sal_Int32 nNodeNames = aNodeNames.getLength();
744 const OUString *pNodeName = aNodeNames.getConstArray();
745 for (i = 0; i < nNodeNames; ++i)
747 Locale aLocale( (LanguageTag(pNodeName[i])).getLocale() );
748 Sequence< OUString > aCfgSvcs( getConfiguredServices( aService, aLocale ));
749 Sequence< OUString > aAvailSvcs( getAvailableServices( aService, aLocale ));
751 aCfgSvcs = lcl_RemoveMissingEntries( aCfgSvcs, aAvailSvcs );
753 aCurSvcs[k][ pNodeName[i] ] = aCfgSvcs;
757 // add new available language/service entries
758 // and
759 // set last found services to currently available ones
761 Sequence< Locale > aAvailLocales( getAvailableLocales(aService) );
762 sal_Int32 nAvailLocales = aAvailLocales.getLength();
763 const Locale *pAvailLocale = aAvailLocales.getConstArray();
764 for (i = 0; i < nAvailLocales; ++i)
766 OUString aCfgLocaleStr( (LanguageTag(pAvailLocale[i])).getBcp47() );
768 Sequence< OUString > aAvailSvcs( getAvailableServices( aService, pAvailLocale[i] ));
770 aLastFoundSvcs[k][ aCfgLocaleStr ] = aAvailSvcs;
772 Sequence< OUString > aLastSvcs(
773 lcl_GetLastFoundSvcs( aCfg, aLastFoundList , pAvailLocale[i] ));
774 Sequence< OUString > aNewSvcs =
775 lcl_GetNewEntries( aLastSvcs, aAvailSvcs );
777 Sequence< OUString > aCfgSvcs( aCurSvcs[k][ aCfgLocaleStr ] );
779 // merge services list (previously configured to be listed first).
780 aCfgSvcs = lcl_MergeSeq( aCfgSvcs, aNewSvcs );
782 aCurSvcs[k][ aCfgLocaleStr ] = aCfgSvcs;
787 // write new data back to configuration
789 for (int k = 0; k < nNumServices; ++k)
791 for (int i = 0; i < 2; ++i)
793 const sal_Char *pSubNodeName = (i == 0) ? apCurLists[k] : apLastFoundLists[k];
794 OUString aSubNodeName( ::rtl::OUString::createFromAscii(pSubNodeName) );
796 list_entry_map_t &rCurMap = (i == 0) ? aCurSvcs[k] : aLastFoundSvcs[k];
797 list_entry_map_t::const_iterator aIt( rCurMap.begin() );
798 sal_Int32 nVals = static_cast< sal_Int32 >( rCurMap.size() );
799 Sequence< PropertyValue > aNewValues( nVals );
800 PropertyValue *pNewValue = aNewValues.getArray();
801 while (aIt != rCurMap.end())
803 OUString aCfgEntryName( aSubNodeName );
804 aCfgEntryName += OUString::valueOf( (sal_Unicode) '/' );
805 aCfgEntryName += (*aIt).first;
807 pNewValue->Name = aCfgEntryName;
808 pNewValue->Value <<= (*aIt).second;
809 ++pNewValue;
810 ++aIt;
812 OSL_ENSURE( pNewValue - aNewValues.getArray() == nVals,
813 "possible mismatch of sequence size and property number" );
816 // add new or replace existing entries.
817 sal_Bool bRes = aCfg.ReplaceSetProperties( aSubNodeName, aNewValues );
818 if (!bRes)
820 #if OSL_DEBUG_LEVEL > 1
821 OSL_FAIL( "failed to set new configuration values" );
822 #endif
828 //The new settings in the configuration get applied ! because we are
829 //listening to the configuration for changes of the relevant ! properties
830 //and Notify applies the new settings.
833 void LngSvcMgr::Notify( const uno::Sequence< OUString > &rPropertyNames )
835 const OUString aSpellCheckerList( "ServiceManager/SpellCheckerList" );
836 const OUString aGrammarCheckerList( "ServiceManager/GrammarCheckerList" );
837 const OUString aHyphenatorList( "ServiceManager/HyphenatorList" );
838 const OUString aThesaurusList( "ServiceManager/ThesaurusList" );
840 const uno::Sequence< OUString > aSpellCheckerListEntries( GetNodeNames( aSpellCheckerList ) );
841 const uno::Sequence< OUString > aGrammarCheckerListEntries( GetNodeNames( aGrammarCheckerList ) );
842 const uno::Sequence< OUString > aHyphenatorListEntries( GetNodeNames( aHyphenatorList ) );
843 const uno::Sequence< OUString > aThesaurusListEntries( GetNodeNames( aThesaurusList ) );
845 uno::Sequence< uno::Any > aValues;
846 uno::Sequence< OUString > aNames( 1 );
847 OUString *pNames = aNames.getArray();
849 sal_Int32 nLen = rPropertyNames.getLength();
850 const OUString *pPropertyNames = rPropertyNames.getConstArray();
851 for (sal_Int32 i = 0; i < nLen; ++i)
853 // property names look like
854 // "ServiceManager/ThesaurusList/de-CH"
856 const OUString &rName = pPropertyNames[i];
857 sal_Int32 nKeyStart;
858 nKeyStart = rName.lastIndexOf( '/' );
859 OUString aKeyText;
860 if (nKeyStart != -1)
861 aKeyText = rName.copy( nKeyStart + 1 );
862 DBG_ASSERT( !aKeyText.isEmpty(), "unexpected key (lang::Locale) string" );
863 if (0 == rName.compareTo( aSpellCheckerList, aSpellCheckerList.getLength() ))
865 // delete old cached data, needs to be acquired new on demand
866 clearSvcInfoArray(pAvailSpellSvcs);
868 OUString aNode( aSpellCheckerList );
869 if (lcl_SeqHasString( aSpellCheckerListEntries, aKeyText ))
871 OUString aPropName( aNode );
872 aPropName += OUString::valueOf( (sal_Unicode) '/' );
873 aPropName += aKeyText;
874 pNames[0] = aPropName;
875 aValues = /*aCfg.*/GetProperties( aNames );
876 uno::Sequence< OUString > aSvcImplNames;
877 if (aValues.getLength())
878 aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
880 LanguageType nLang = LANGUAGE_NONE;
881 if (!aKeyText.isEmpty())
882 nLang = LanguageTag( aKeyText ).getLanguageType();
884 GetSpellCheckerDsp_Impl( sal_False ); // don't set service list, it will be done below
885 pSpellDsp->SetServiceList( LanguageTag(nLang).getLocale(), aSvcImplNames );
888 else if (0 == rName.compareTo( aGrammarCheckerList, aGrammarCheckerList.getLength() ))
890 // delete old cached data, needs to be acquired new on demand
891 clearSvcInfoArray(pAvailGrammarSvcs);
893 OUString aNode( aGrammarCheckerList );
894 if (lcl_SeqHasString( aGrammarCheckerListEntries, aKeyText ))
896 OUString aPropName( aNode );
897 aPropName += OUString::valueOf( (sal_Unicode) '/' );
898 aPropName += aKeyText;
899 pNames[0] = aPropName;
900 aValues = /*aCfg.*/GetProperties( aNames );
901 uno::Sequence< OUString > aSvcImplNames;
902 if (aValues.getLength())
903 aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
905 LanguageType nLang = LANGUAGE_NONE;
906 if (!aKeyText.isEmpty())
907 nLang = LanguageTag( aKeyText ).getLanguageType();
909 if (SvtLinguConfig().HasGrammarChecker())
911 GetGrammarCheckerDsp_Impl( sal_False ); // don't set service list, it will be done below
912 pGrammarDsp->SetServiceList( LanguageTag(nLang).getLocale(), aSvcImplNames );
916 else if (0 == rName.compareTo( aHyphenatorList, aHyphenatorList.getLength() ))
918 // delete old cached data, needs to be acquired new on demand
919 clearSvcInfoArray(pAvailHyphSvcs);
921 OUString aNode( aHyphenatorList );
922 if (lcl_SeqHasString( aHyphenatorListEntries, aKeyText ))
924 OUString aPropName( aNode );
925 aPropName += OUString::valueOf( (sal_Unicode) '/' );
926 aPropName += aKeyText;
927 pNames[0] = aPropName;
928 aValues = /*aCfg.*/GetProperties( aNames );
929 uno::Sequence< OUString > aSvcImplNames;
930 if (aValues.getLength())
931 aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
933 LanguageType nLang = LANGUAGE_NONE;
934 if (!aKeyText.isEmpty())
935 nLang = LanguageTag( aKeyText ).getLanguageType();
937 GetHyphenatorDsp_Impl( sal_False ); // don't set service list, it will be done below
938 pHyphDsp->SetServiceList( LanguageTag(nLang).getLocale(), aSvcImplNames );
941 else if (0 == rName.compareTo( aThesaurusList, aThesaurusList.getLength() ))
943 // delete old cached data, needs to be acquired new on demand
944 clearSvcInfoArray(pAvailThesSvcs);
946 OUString aNode( aThesaurusList );
947 if (lcl_SeqHasString( aThesaurusListEntries, aKeyText ))
949 OUString aPropName( aNode );
950 aPropName += OUString::valueOf( (sal_Unicode) '/' );
951 aPropName += aKeyText;
952 pNames[0] = aPropName;
953 aValues = /*aCfg.*/GetProperties( aNames );
954 uno::Sequence< OUString > aSvcImplNames;
955 if (aValues.getLength())
956 aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
958 LanguageType nLang = LANGUAGE_NONE;
959 if (!aKeyText.isEmpty())
960 nLang = LanguageTag( aKeyText ).getLanguageType();
962 GetThesaurusDsp_Impl( sal_False ); // don't set service list, it will be done below
963 pThesDsp->SetServiceList( LanguageTag(nLang).getLocale(), aSvcImplNames );
966 else
968 DBG_ASSERT( 0, "nofified for unexpected property" );
974 void LngSvcMgr::Commit()
976 // everything necessary should have already been done by 'SaveCfgSvcs'
977 // called from within 'setConfiguredServices'.
978 // Also this class usually exits only when the Office i sbeing shutdown.
982 void LngSvcMgr::GetListenerHelper_Impl()
984 if (!pListenerHelper)
986 pListenerHelper = new LngSvcMgrListenerHelper( *this, linguistic::GetDictionaryList() );
987 xListenerHelper = (linguistic2::XLinguServiceEventListener *) pListenerHelper;
992 void LngSvcMgr::GetSpellCheckerDsp_Impl( sal_Bool bSetSvcList )
994 if (!pSpellDsp)
996 pSpellDsp = new SpellCheckerDispatcher( *this );
997 xSpellDsp = pSpellDsp;
998 if (bSetSvcList)
999 SetCfgServiceLists( *pSpellDsp );
1004 void LngSvcMgr::GetGrammarCheckerDsp_Impl( sal_Bool bSetSvcList )
1006 if (!pGrammarDsp && SvtLinguConfig().HasGrammarChecker())
1008 //! since the grammar checking iterator needs to be a one instance service
1009 //! we need to create it the correct way!
1010 uno::Reference< linguistic2::XProofreadingIterator > xGCI;
1013 uno::Reference< lang::XMultiServiceFactory > xMgr(
1014 comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
1015 xGCI = uno::Reference< linguistic2::XProofreadingIterator >(
1016 xMgr->createInstance( SN_GRAMMARCHECKINGITERATOR ), uno::UNO_QUERY_THROW );
1018 catch (uno::Exception &)
1021 DBG_ASSERT( xGCI.is(), "instantiating grammar checking iterator failed" );
1023 if (xGCI.is())
1025 pGrammarDsp = dynamic_cast< GrammarCheckingIterator * >(xGCI.get());
1026 xGrammarDsp = xGCI;
1027 DBG_ASSERT( pGrammarDsp, "failed to get implementation" );
1028 if (bSetSvcList)
1029 SetCfgServiceLists( *pGrammarDsp );
1035 void LngSvcMgr::GetHyphenatorDsp_Impl( sal_Bool bSetSvcList )
1037 if (!pHyphDsp)
1039 pHyphDsp = new HyphenatorDispatcher( *this );
1040 xHyphDsp = pHyphDsp;
1041 if (bSetSvcList)
1042 SetCfgServiceLists( *pHyphDsp );
1047 void LngSvcMgr::GetThesaurusDsp_Impl( sal_Bool bSetSvcList )
1049 if (!pThesDsp)
1051 pThesDsp = new ThesaurusDispatcher;
1052 xThesDsp = pThesDsp;
1053 if (bSetSvcList)
1054 SetCfgServiceLists( *pThesDsp );
1059 void LngSvcMgr::GetAvailableSpellSvcs_Impl()
1061 if (!pAvailSpellSvcs)
1063 pAvailSpellSvcs = new SvcInfoArray;
1065 uno::Reference< lang::XMultiServiceFactory > xFac( comphelper::getProcessServiceFactory() );
1066 if (xFac.is())
1068 uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
1069 uno::Reference< container::XEnumeration > xEnum;
1070 if (xEnumAccess.is())
1071 xEnum = xEnumAccess->createContentEnumeration( SN_SPELLCHECKER );
1073 if (xEnum.is())
1075 while (xEnum->hasMoreElements())
1077 uno::Any aCurrent = xEnum->nextElement();
1078 uno::Reference< lang::XSingleComponentFactory > xCompFactory;
1079 uno::Reference< lang::XSingleServiceFactory > xFactory;
1081 uno::Reference< linguistic2::XSpellChecker > xSvc;
1082 if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
1086 uno::Reference < uno::XComponentContext > xContext(
1087 comphelper::getComponentContext( xFac ) );
1088 xSvc = uno::Reference< linguistic2::XSpellChecker >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
1090 catch (const uno::Exception &)
1092 DBG_ASSERT( 0, "createInstance failed" );
1096 if (xSvc.is())
1098 OUString aImplName;
1099 uno::Sequence< sal_Int16 > aLanguages;
1100 uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
1101 if (xInfo.is())
1102 aImplName = xInfo->getImplementationName();
1103 DBG_ASSERT( !aImplName.isEmpty(),
1104 "empty implementation name" );
1105 uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
1106 DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
1107 if (xSuppLoc.is()) {
1108 uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
1109 aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
1112 pAvailSpellSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
1121 void LngSvcMgr::GetAvailableGrammarSvcs_Impl()
1123 if (!pAvailGrammarSvcs)
1125 pAvailGrammarSvcs = new SvcInfoArray;
1127 uno::Reference< lang::XMultiServiceFactory > xFac( comphelper::getProcessServiceFactory() );
1128 if (xFac.is())
1130 uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
1131 uno::Reference< container::XEnumeration > xEnum;
1132 if (xEnumAccess.is())
1133 xEnum = xEnumAccess->createContentEnumeration( SN_GRAMMARCHECKER );
1135 if (xEnum.is())
1137 while (xEnum->hasMoreElements())
1139 uno::Any aCurrent = xEnum->nextElement();
1140 uno::Reference< lang::XSingleComponentFactory > xCompFactory;
1141 uno::Reference< lang::XSingleServiceFactory > xFactory;
1143 uno::Reference< linguistic2::XProofreader > xSvc;
1144 if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
1148 uno::Reference < uno::XComponentContext > xContext(
1149 comphelper::getComponentContext( xFac ) );
1150 xSvc = uno::Reference< linguistic2::XProofreader >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
1152 catch (const uno::Exception &)
1154 DBG_ASSERT( 0, "createInstance failed" );
1158 if (xSvc.is())
1160 OUString aImplName;
1161 uno::Sequence< sal_Int16 > aLanguages;
1162 uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
1163 if (xInfo.is())
1164 aImplName = xInfo->getImplementationName();
1165 DBG_ASSERT( !aImplName.isEmpty(),
1166 "empty implementation name" );
1167 uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
1168 DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
1169 if (xSuppLoc.is()) {
1170 uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
1171 aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
1174 pAvailGrammarSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
1183 void LngSvcMgr::GetAvailableHyphSvcs_Impl()
1185 if (!pAvailHyphSvcs)
1187 pAvailHyphSvcs = new SvcInfoArray;
1188 uno::Reference< lang::XMultiServiceFactory > xFac( comphelper::getProcessServiceFactory() );
1189 if (xFac.is())
1191 uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
1192 uno::Reference< container::XEnumeration > xEnum;
1193 if (xEnumAccess.is())
1194 xEnum = xEnumAccess->createContentEnumeration( SN_HYPHENATOR );
1196 if (xEnum.is())
1198 while (xEnum->hasMoreElements())
1200 uno::Any aCurrent = xEnum->nextElement();
1201 uno::Reference< lang::XSingleComponentFactory > xCompFactory;
1202 uno::Reference< lang::XSingleServiceFactory > xFactory;
1204 uno::Reference< linguistic2::XHyphenator > xSvc;
1205 if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
1209 uno::Reference < uno::XComponentContext > xContext(
1210 comphelper::getComponentContext( xFac ) );
1211 xSvc = uno::Reference< linguistic2::XHyphenator >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
1214 catch (const uno::Exception &)
1216 DBG_ASSERT( 0, "createInstance failed" );
1220 if (xSvc.is())
1222 OUString aImplName;
1223 uno::Sequence< sal_Int16 > aLanguages;
1224 uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
1225 if (xInfo.is())
1226 aImplName = xInfo->getImplementationName();
1227 DBG_ASSERT( !aImplName.isEmpty(),
1228 "empty implementation name" );
1229 uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
1230 DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
1231 if (xSuppLoc.is()) {
1232 uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
1233 aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
1236 pAvailHyphSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
1245 void LngSvcMgr::GetAvailableThesSvcs_Impl()
1247 if (!pAvailThesSvcs)
1249 pAvailThesSvcs = new SvcInfoArray;
1251 uno::Reference< lang::XMultiServiceFactory > xFac( comphelper::getProcessServiceFactory() );
1252 if (xFac.is())
1254 uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
1255 uno::Reference< container::XEnumeration > xEnum;
1256 if (xEnumAccess.is())
1257 xEnum = xEnumAccess->createContentEnumeration( SN_THESAURUS );
1259 if (xEnum.is())
1261 while (xEnum->hasMoreElements())
1263 uno::Any aCurrent = xEnum->nextElement();
1265 uno::Reference< lang::XSingleComponentFactory > xCompFactory;
1266 uno::Reference< lang::XSingleServiceFactory > xFactory;
1268 uno::Reference< linguistic2::XThesaurus > xSvc;
1269 if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
1273 uno::Reference < uno::XComponentContext > xContext(
1274 comphelper::getComponentContext( xFac ) );
1275 xSvc = uno::Reference< linguistic2::XThesaurus >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
1277 catch (const uno::Exception &)
1279 DBG_ASSERT( 0, "createInstance failed" );
1283 if (xSvc.is())
1285 OUString aImplName;
1286 uno::Sequence< sal_Int16 > aLanguages;
1287 uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
1288 if (xInfo.is())
1289 aImplName = xInfo->getImplementationName();
1290 DBG_ASSERT( !aImplName.isEmpty(),
1291 "empty implementation name" );
1292 uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
1293 DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
1294 if (xSuppLoc.is()) {
1295 uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
1296 aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
1299 pAvailThesSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
1308 void LngSvcMgr::SetCfgServiceLists( SpellCheckerDispatcher &rSpellDsp )
1310 RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Spell" );
1312 rtl::OUString aNode("ServiceManager/SpellCheckerList");
1313 uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1314 OUString *pNames = aNames.getArray();
1315 sal_Int32 nLen = aNames.getLength();
1317 // append path prefix need for 'GetProperties' call below
1318 String aPrefix( aNode );
1319 aPrefix.Append( (sal_Unicode) '/' );
1320 for (int i = 0; i < nLen; ++i)
1322 OUString aTmp( aPrefix );
1323 aTmp += pNames[i];
1324 pNames[i] = aTmp;
1327 uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1328 if (nLen && nLen == aValues.getLength())
1330 const uno::Any *pValues = aValues.getConstArray();
1331 for (sal_Int32 i = 0; i < nLen; ++i)
1333 uno::Sequence< OUString > aSvcImplNames;
1334 if (pValues[i] >>= aSvcImplNames)
1336 String aLocaleStr( pNames[i] );
1337 xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
1338 aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
1339 rSpellDsp.SetServiceList( LanguageTag(aLocaleStr).getLocale(), aSvcImplNames );
1346 void LngSvcMgr::SetCfgServiceLists( GrammarCheckingIterator &rGrammarDsp )
1348 RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Grammar" );
1350 rtl::OUString aNode("ServiceManager/GrammarCheckerList");
1351 uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1352 OUString *pNames = aNames.getArray();
1353 sal_Int32 nLen = aNames.getLength();
1355 // append path prefix need for 'GetProperties' call below
1356 String aPrefix( aNode );
1357 aPrefix.Append( (sal_Unicode) '/' );
1358 for (int i = 0; i < nLen; ++i)
1360 OUString aTmp( aPrefix );
1361 aTmp += pNames[i];
1362 pNames[i] = aTmp;
1365 uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1366 if (nLen && nLen == aValues.getLength())
1368 const uno::Any *pValues = aValues.getConstArray();
1369 for (sal_Int32 i = 0; i < nLen; ++i)
1371 uno::Sequence< OUString > aSvcImplNames;
1372 if (pValues[i] >>= aSvcImplNames)
1374 // there should only be one grammar checker in use per language...
1375 if (aSvcImplNames.getLength() > 1)
1376 aSvcImplNames.realloc(1);
1378 String aLocaleStr( pNames[i] );
1379 xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
1380 aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
1381 rGrammarDsp.SetServiceList( LanguageTag(aLocaleStr).getLocale(), aSvcImplNames );
1388 void LngSvcMgr::SetCfgServiceLists( HyphenatorDispatcher &rHyphDsp )
1390 RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Hyph" );
1392 rtl::OUString aNode("ServiceManager/HyphenatorList");
1393 uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1394 OUString *pNames = aNames.getArray();
1395 sal_Int32 nLen = aNames.getLength();
1397 // append path prefix need for 'GetProperties' call below
1398 String aPrefix( aNode );
1399 aPrefix.Append( (sal_Unicode) '/' );
1400 for (int i = 0; i < nLen; ++i)
1402 OUString aTmp( aPrefix );
1403 aTmp += pNames[i];
1404 pNames[i] = aTmp;
1407 uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1408 if (nLen && nLen == aValues.getLength())
1410 const uno::Any *pValues = aValues.getConstArray();
1411 for (sal_Int32 i = 0; i < nLen; ++i)
1413 uno::Sequence< OUString > aSvcImplNames;
1414 if (pValues[i] >>= aSvcImplNames)
1416 // there should only be one hyphenator in use per language...
1417 if (aSvcImplNames.getLength() > 1)
1418 aSvcImplNames.realloc(1);
1420 String aLocaleStr( pNames[i] );
1421 xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
1422 aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
1423 rHyphDsp.SetServiceList( LanguageTag(aLocaleStr).getLocale(), aSvcImplNames );
1430 void LngSvcMgr::SetCfgServiceLists( ThesaurusDispatcher &rThesDsp )
1432 RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Thes" );
1434 rtl::OUString aNode("ServiceManager/ThesaurusList");
1435 uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1436 OUString *pNames = aNames.getArray();
1437 sal_Int32 nLen = aNames.getLength();
1439 // append path prefix need for 'GetProperties' call below
1440 String aPrefix( aNode );
1441 aPrefix.Append( (sal_Unicode) '/' );
1442 for (int i = 0; i < nLen; ++i)
1444 OUString aTmp( aPrefix );
1445 aTmp += pNames[i];
1446 pNames[i] = aTmp;
1449 uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1450 if (nLen && nLen == aValues.getLength())
1452 const uno::Any *pValues = aValues.getConstArray();
1453 for (sal_Int32 i = 0; i < nLen; ++i)
1455 uno::Sequence< OUString > aSvcImplNames;
1456 if (pValues[i] >>= aSvcImplNames)
1458 String aLocaleStr( pNames[i] );
1459 xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
1460 aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
1461 rThesDsp.SetServiceList( LanguageTag(aLocaleStr).getLocale(), aSvcImplNames );
1468 uno::Reference< linguistic2::XSpellChecker > SAL_CALL
1469 LngSvcMgr::getSpellChecker()
1470 throw(uno::RuntimeException)
1472 osl::MutexGuard aGuard( GetLinguMutex() );
1473 #if OSL_DEBUG_LEVEL > 1
1474 getAvailableLocales( SN_SPELLCHECKER );
1475 #endif
1477 uno::Reference< linguistic2::XSpellChecker > xRes;
1478 if (!bDisposing)
1480 if (!xSpellDsp.is())
1481 GetSpellCheckerDsp_Impl();
1482 xRes = xSpellDsp;
1484 return xRes;
1488 uno::Reference< linguistic2::XHyphenator > SAL_CALL
1489 LngSvcMgr::getHyphenator()
1490 throw(uno::RuntimeException)
1492 osl::MutexGuard aGuard( GetLinguMutex() );
1493 #if OSL_DEBUG_LEVEL > 1
1494 getAvailableLocales( SN_HYPHENATOR );
1495 #endif
1497 uno::Reference< linguistic2::XHyphenator > xRes;
1498 if (!bDisposing)
1500 if (!xHyphDsp.is())
1501 GetHyphenatorDsp_Impl();
1502 xRes = xHyphDsp;
1504 return xRes;
1508 uno::Reference< linguistic2::XThesaurus > SAL_CALL
1509 LngSvcMgr::getThesaurus()
1510 throw(uno::RuntimeException)
1512 osl::MutexGuard aGuard( GetLinguMutex() );
1513 #if OSL_DEBUG_LEVEL > 1
1514 getAvailableLocales( SN_THESAURUS );
1515 #endif
1517 uno::Reference< linguistic2::XThesaurus > xRes;
1518 if (!bDisposing)
1520 if (!xThesDsp.is())
1521 GetThesaurusDsp_Impl();
1522 xRes = xThesDsp;
1524 return xRes;
1528 sal_Bool SAL_CALL
1529 LngSvcMgr::addLinguServiceManagerListener(
1530 const uno::Reference< lang::XEventListener >& xListener )
1531 throw(uno::RuntimeException)
1533 osl::MutexGuard aGuard( GetLinguMutex() );
1535 sal_Bool bRes = sal_False;
1536 if (!bDisposing && xListener.is())
1538 if (!pListenerHelper)
1539 GetListenerHelper_Impl();
1540 bRes = pListenerHelper->AddLngSvcMgrListener( xListener );
1542 return bRes;
1546 sal_Bool SAL_CALL
1547 LngSvcMgr::removeLinguServiceManagerListener(
1548 const uno::Reference< lang::XEventListener >& xListener )
1549 throw(uno::RuntimeException)
1551 osl::MutexGuard aGuard( GetLinguMutex() );
1553 sal_Bool bRes = sal_False;
1554 if (!bDisposing && xListener.is())
1556 DBG_ASSERT( pListenerHelper, "listener removed without being added" );
1557 if (!pListenerHelper)
1558 GetListenerHelper_Impl();
1559 bRes = pListenerHelper->RemoveLngSvcMgrListener( xListener );
1561 return bRes;
1565 uno::Sequence< OUString > SAL_CALL
1566 LngSvcMgr::getAvailableServices(
1567 const OUString& rServiceName,
1568 const lang::Locale& rLocale )
1569 throw(uno::RuntimeException)
1571 osl::MutexGuard aGuard( GetLinguMutex() );
1573 uno::Sequence< OUString > aRes;
1574 const SvcInfoArray *pInfoArray = 0;
1576 if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
1578 GetAvailableSpellSvcs_Impl();
1579 pInfoArray = pAvailSpellSvcs;
1581 else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
1583 GetAvailableGrammarSvcs_Impl();
1584 pInfoArray = pAvailGrammarSvcs;
1586 else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
1588 GetAvailableHyphSvcs_Impl();
1589 pInfoArray = pAvailHyphSvcs;
1591 else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
1593 GetAvailableThesSvcs_Impl();
1594 pInfoArray = pAvailThesSvcs;
1597 if (pInfoArray)
1599 // resize to max number of entries
1600 size_t nMaxCnt = pInfoArray->size();
1601 aRes.realloc( nMaxCnt );
1602 OUString *pImplName = aRes.getArray();
1604 sal_uInt16 nCnt = 0;
1605 LanguageType nLanguage = LinguLocaleToLanguage( rLocale );
1606 for (size_t i = 0; i < nMaxCnt; ++i)
1608 const SvcInfo &rInfo = (*pInfoArray)[i];
1609 if (LinguIsUnspecified( nLanguage )
1610 || rInfo.HasLanguage( nLanguage ))
1612 pImplName[ nCnt++ ] = rInfo.aSvcImplName;
1616 // resize to actual number of entries
1617 if (nCnt != nMaxCnt)
1618 aRes.realloc( nCnt );
1621 return aRes;
1625 uno::Sequence< lang::Locale > SAL_CALL
1626 LngSvcMgr::getAvailableLocales(
1627 const OUString& rServiceName )
1628 throw(uno::RuntimeException)
1630 osl::MutexGuard aGuard( GetLinguMutex() );
1632 uno::Sequence< lang::Locale > aRes;
1634 uno::Sequence< lang::Locale > *pAvailLocales = NULL;
1635 if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
1636 pAvailLocales = &aAvailSpellLocales;
1637 else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
1638 pAvailLocales = &aAvailGrammarLocales;
1639 else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
1640 pAvailLocales = &aAvailHyphLocales;
1641 else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
1642 pAvailLocales = &aAvailThesLocales;
1644 // Nowadays (with OOo lingu in SO) we want to know immediately about
1645 // new downloaded dictionaries and have them ready right away if the Tools/Options...
1646 // is used to activate them. Thus we can not rely anymore on buffered data.
1647 if (pAvailLocales)
1649 *pAvailLocales = GetAvailLocales(getAvailableServices(rServiceName, lang::Locale()));
1650 aRes = *pAvailLocales;
1653 return aRes;
1656 static sal_Bool IsEqSvcList( const uno::Sequence< OUString > &rList1,
1657 const uno::Sequence< OUString > &rList2 )
1659 // returns sal_True iff both sequences are equal
1661 sal_Bool bRes = sal_False;
1662 sal_Int32 nLen = rList1.getLength();
1663 if (rList2.getLength() == nLen)
1665 const OUString *pStr1 = rList1.getConstArray();
1666 const OUString *pStr2 = rList2.getConstArray();
1667 bRes = sal_True;
1668 for (sal_Int32 i = 0; i < nLen && bRes; ++i)
1670 if (*pStr1++ != *pStr2++)
1671 bRes = sal_False;
1674 return bRes;
1678 void SAL_CALL
1679 LngSvcMgr::setConfiguredServices(
1680 const OUString& rServiceName,
1681 const lang::Locale& rLocale,
1682 const uno::Sequence< OUString >& rServiceImplNames )
1683 throw(uno::RuntimeException)
1685 RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::setConfiguredServices" );
1687 osl::MutexGuard aGuard( GetLinguMutex() );
1689 #if OSL_DEBUG_LEVEL > 1
1690 #endif
1692 LanguageType nLanguage = LinguLocaleToLanguage( rLocale );
1693 if (!LinguIsUnspecified( nLanguage))
1695 if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
1697 if (!xSpellDsp.is())
1698 GetSpellCheckerDsp_Impl();
1699 sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1700 pSpellDsp->GetServiceList( rLocale ) );
1701 if (bChanged)
1703 pSpellDsp->SetServiceList( rLocale, rServiceImplNames );
1704 SaveCfgSvcs( rtl::OUString(SN_SPELLCHECKER) );
1706 if (pListenerHelper && bChanged)
1707 pListenerHelper->AddLngSvcEvt(
1708 linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN |
1709 linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN );
1712 else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
1714 if (!xGrammarDsp.is())
1715 GetGrammarCheckerDsp_Impl();
1716 sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1717 pGrammarDsp->GetServiceList( rLocale ) );
1718 if (bChanged)
1720 pGrammarDsp->SetServiceList( rLocale, rServiceImplNames );
1721 SaveCfgSvcs( rtl::OUString(SN_GRAMMARCHECKER) );
1723 if (pListenerHelper && bChanged)
1724 pListenerHelper->AddLngSvcEvt(
1725 linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN );
1728 else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
1730 if (!xHyphDsp.is())
1731 GetHyphenatorDsp_Impl();
1732 sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1733 pHyphDsp->GetServiceList( rLocale ) );
1734 if (bChanged)
1736 pHyphDsp->SetServiceList( rLocale, rServiceImplNames );
1737 SaveCfgSvcs( rtl::OUString(SN_HYPHENATOR) );
1739 if (pListenerHelper && bChanged)
1740 pListenerHelper->AddLngSvcEvt(
1741 linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN );
1744 else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
1746 if (!xThesDsp.is())
1747 GetThesaurusDsp_Impl();
1748 sal_Bool bChanged = !IsEqSvcList( rServiceImplNames,
1749 pThesDsp->GetServiceList( rLocale ) );
1750 if (bChanged)
1752 pThesDsp->SetServiceList( rLocale, rServiceImplNames );
1753 SaveCfgSvcs( rtl::OUString(SN_THESAURUS) );
1760 sal_Bool LngSvcMgr::SaveCfgSvcs( const String &rServiceName )
1762 RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SaveCfgSvcs" );
1764 sal_Bool bRes = sal_False;
1766 LinguDispatcher *pDsp = 0;
1767 uno::Sequence< lang::Locale > aLocales;
1769 if (0 == rServiceName.CompareToAscii( SN_SPELLCHECKER ))
1771 if (!pSpellDsp)
1772 GetSpellCheckerDsp_Impl();
1773 pDsp = pSpellDsp;
1774 aLocales = getAvailableLocales( SN_SPELLCHECKER );
1776 else if (0 == rServiceName.CompareToAscii( SN_GRAMMARCHECKER ))
1778 if (!pGrammarDsp)
1779 GetGrammarCheckerDsp_Impl();
1780 pDsp = pGrammarDsp;
1781 aLocales = getAvailableLocales( SN_GRAMMARCHECKER );
1783 else if (0 == rServiceName.CompareToAscii( SN_HYPHENATOR ))
1785 if (!pHyphDsp)
1786 GetHyphenatorDsp_Impl();
1787 pDsp = pHyphDsp;
1788 aLocales = getAvailableLocales( SN_HYPHENATOR );
1790 else if (0 == rServiceName.CompareToAscii( SN_THESAURUS ))
1792 if (!pThesDsp)
1793 GetThesaurusDsp_Impl();
1794 pDsp = pThesDsp;
1795 aLocales = getAvailableLocales( SN_THESAURUS );
1798 if (pDsp && aLocales.getLength())
1800 sal_Int32 nLen = aLocales.getLength();
1801 const lang::Locale *pLocale = aLocales.getConstArray();
1803 uno::Sequence< beans::PropertyValue > aValues( nLen );
1804 beans::PropertyValue *pValues = aValues.getArray();
1805 beans::PropertyValue *pValue = pValues;
1807 // get node name to be used
1808 const char *pNodeName = NULL;
1809 if (pDsp == pSpellDsp)
1810 pNodeName = "ServiceManager/SpellCheckerList";
1811 else if (pDsp == pGrammarDsp)
1812 pNodeName = "ServiceManager/GrammarCheckerList";
1813 else if (pDsp == pHyphDsp)
1814 pNodeName = "ServiceManager/HyphenatorList";
1815 else if (pDsp == pThesDsp)
1816 pNodeName = "ServiceManager/ThesaurusList";
1817 else
1819 DBG_ASSERT( 0, "node name missing" );
1821 OUString aNodeName( ::rtl::OUString::createFromAscii(pNodeName) );
1823 for (sal_Int32 i = 0; i < nLen; ++i)
1825 uno::Sequence< OUString > aSvcImplNames;
1826 aSvcImplNames = pDsp->GetServiceList( pLocale[i] );
1828 #if OSL_DEBUG_LEVEL > 1
1829 sal_Int32 nSvcs = aSvcImplNames.getLength();
1830 const OUString *pSvcImplName = aSvcImplNames.getConstArray();
1831 for (sal_Int32 j = 0; j < nSvcs; ++j)
1833 OUString aImplName( pSvcImplName[j] );
1835 #endif
1836 // build value to be written back to configuration
1837 uno::Any aCfgAny;
1838 if ((pDsp == pHyphDsp || pDsp == pGrammarDsp) && aSvcImplNames.getLength() > 1)
1839 aSvcImplNames.realloc(1); // there should be only one entry for hyphenators or grammar checkers (because they are not chained)
1840 aCfgAny <<= aSvcImplNames;
1841 DBG_ASSERT( aCfgAny.hasValue(), "missing value for 'Any' type" );
1843 OUString aCfgLocaleStr( (LanguageTag(pLocale[i])).getBcp47() );
1844 pValue->Value = aCfgAny;
1845 pValue->Name = aNodeName;
1846 pValue->Name += OUString::valueOf( (sal_Unicode) '/' );
1847 pValue->Name += aCfgLocaleStr;
1848 pValue++;
1851 RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SaveCfgSvcs - ReplaceSetProperties" );
1852 // change, add new or replace existing entries.
1853 bRes |= /*aCfg.*/ReplaceSetProperties( aNodeName, aValues );
1857 return bRes;
1861 static uno::Sequence< OUString > GetLangSvcList( const uno::Any &rVal )
1863 uno::Sequence< OUString > aRes;
1865 if (rVal.hasValue())
1867 rVal >>= aRes;
1868 #if OSL_DEBUG_LEVEL > 1
1869 sal_Int32 nSvcs = aRes.getLength();
1870 if (nSvcs)
1872 const OUString *pSvcName = aRes.getConstArray();
1873 for (sal_Int32 j = 0; j < nSvcs; ++j)
1875 OUString aImplName( pSvcName[j] );
1876 DBG_ASSERT( !aImplName.isEmpty(), "service impl-name missing" );
1879 #endif
1882 return aRes;
1886 static uno::Sequence< OUString > GetLangSvc( const uno::Any &rVal )
1888 uno::Sequence< OUString > aRes;
1889 if (!rVal.hasValue())
1890 return aRes;
1892 // allowing for a sequence here as well (even though it should only
1893 // be a string) makes coding easier in other places since one needs
1894 // not make a special case for writing a string only and not a
1895 // sequence of strings.
1896 if (rVal >>= aRes)
1898 // but only the first string should be used.
1899 if (aRes.getLength() > 1)
1900 aRes.realloc(1);
1902 else
1904 OUString aImplName;
1905 if ((rVal >>= aImplName) && !aImplName.isEmpty())
1907 aRes.realloc(1);
1908 aRes.getArray()[0] = aImplName;
1910 else
1912 DBG_ASSERT( 0, "GetLangSvc: unexpected type encountered" );
1916 return aRes;
1921 uno::Sequence< OUString > SAL_CALL
1922 LngSvcMgr::getConfiguredServices(
1923 const OUString& rServiceName,
1924 const lang::Locale& rLocale )
1925 throw(uno::RuntimeException)
1927 osl::MutexGuard aGuard( GetLinguMutex() );
1929 uno::Sequence< OUString > aSvcImplNames;
1931 OUString aCfgLocale( LanguageTag( rLocale).getBcp47() );
1933 uno::Sequence< uno::Any > aValues;
1934 uno::Sequence< OUString > aNames( 1 );
1935 OUString *pNames = aNames.getArray();
1936 if ( 0 == rServiceName.compareToAscii( SN_SPELLCHECKER ) )
1938 OUString aNode( "ServiceManager/SpellCheckerList");
1939 const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1940 if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1942 OUString aPropName( aNode );
1943 aPropName += OUString::valueOf( (sal_Unicode) '/' );
1944 aPropName += aCfgLocale;
1945 pNames[0] = aPropName;
1946 aValues = /*aCfg.*/GetProperties( aNames );
1947 if (aValues.getLength())
1948 aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
1951 else if ( 0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ) )
1953 OUString aNode( "ServiceManager/GrammarCheckerList");
1954 const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1955 if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1957 OUString aPropName( aNode );
1958 aPropName += OUString::valueOf( (sal_Unicode) '/' );
1959 aPropName += aCfgLocale;
1960 pNames[0] = aPropName;
1961 aValues = /*aCfg.*/GetProperties( aNames );
1962 if (aValues.getLength())
1963 aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
1966 else if ( 0 == rServiceName.compareToAscii( SN_HYPHENATOR ) )
1968 OUString aNode( "ServiceManager/HyphenatorList");
1969 const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1970 if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1972 OUString aPropName( aNode );
1973 aPropName += OUString::valueOf( (sal_Unicode) '/' );
1974 aPropName += aCfgLocale;
1975 pNames[0] = aPropName;
1976 aValues = /*aCfg.*/GetProperties( aNames );
1977 if (aValues.getLength())
1978 aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
1981 else if ( 0 == rServiceName.compareToAscii( SN_THESAURUS ) )
1983 OUString aNode( "ServiceManager/ThesaurusList");
1984 const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1985 if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1987 OUString aPropName( aNode );
1988 aPropName += OUString::valueOf( (sal_Unicode) '/' );
1989 aPropName += aCfgLocale;
1990 pNames[0] = aPropName;
1991 aValues = /*aCfg.*/GetProperties( aNames );
1992 if (aValues.getLength())
1993 aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
1997 #if OSL_DEBUG_LEVEL > 1
1998 const OUString *pImplNames = aSvcImplNames.getConstArray();
1999 (void) pImplNames;
2000 #endif
2001 return aSvcImplNames;
2005 void SAL_CALL
2006 LngSvcMgr::dispose()
2007 throw(uno::RuntimeException)
2009 osl::MutexGuard aGuard( GetLinguMutex() );
2011 if (!bDisposing)
2013 bDisposing = sal_True;
2015 // require listeners to release this object
2016 lang::EventObject aEvtObj( static_cast<XLinguServiceManager*>(this) );
2017 aEvtListeners.disposeAndClear( aEvtObj );
2019 if (pListenerHelper)
2020 pListenerHelper->DisposeAndClear( aEvtObj );
2025 void SAL_CALL
2026 LngSvcMgr::addEventListener(
2027 const uno::Reference< lang::XEventListener >& xListener )
2028 throw(uno::RuntimeException)
2030 osl::MutexGuard aGuard( GetLinguMutex() );
2032 if (!bDisposing && xListener.is())
2034 aEvtListeners.addInterface( xListener );
2039 void SAL_CALL
2040 LngSvcMgr::removeEventListener(
2041 const uno::Reference< lang::XEventListener >& xListener )
2042 throw(uno::RuntimeException)
2044 osl::MutexGuard aGuard( GetLinguMutex() );
2046 if (xListener.is())
2048 aEvtListeners.removeInterface( xListener );
2053 sal_Bool LngSvcMgr::AddLngSvcEvtBroadcaster(
2054 const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
2056 sal_Bool bRes = sal_False;
2057 if (rxBroadcaster.is())
2059 if (!pListenerHelper)
2060 GetListenerHelper_Impl();
2061 bRes = pListenerHelper->AddLngSvcEvtBroadcaster( rxBroadcaster );
2063 return bRes;
2067 OUString SAL_CALL
2068 LngSvcMgr::getImplementationName()
2069 throw(uno::RuntimeException)
2071 osl::MutexGuard aGuard( GetLinguMutex() );
2072 return getImplementationName_Static();
2076 sal_Bool SAL_CALL
2077 LngSvcMgr::supportsService( const OUString& ServiceName )
2078 throw(uno::RuntimeException)
2080 osl::MutexGuard aGuard( GetLinguMutex() );
2082 uno::Sequence< OUString > aSNL = getSupportedServiceNames();
2083 const OUString * pArray = aSNL.getConstArray();
2084 for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
2085 if( pArray[i] == ServiceName )
2086 return sal_True;
2087 return sal_False;
2091 uno::Sequence< OUString > SAL_CALL
2092 LngSvcMgr::getSupportedServiceNames()
2093 throw(uno::RuntimeException)
2095 osl::MutexGuard aGuard( GetLinguMutex() );
2096 return getSupportedServiceNames_Static();
2100 uno::Sequence< OUString > LngSvcMgr::getSupportedServiceNames_Static()
2101 throw()
2103 osl::MutexGuard aGuard( GetLinguMutex() );
2105 uno::Sequence< OUString > aSNS( 1 ); // more than 1 service possible
2106 aSNS.getArray()[0] = "com.sun.star.linguistic2.LinguServiceManager";
2107 return aSNS;
2111 uno::Reference< uno::XInterface > SAL_CALL LngSvcMgr_CreateInstance(
2112 const uno::Reference< lang::XMultiServiceFactory > & /*rSMgr*/ )
2113 throw(uno::Exception)
2115 uno::Reference< uno::XInterface > xService = (cppu::OWeakObject*) new LngSvcMgr;
2116 return xService;
2119 void * SAL_CALL LngSvcMgr_getFactory(
2120 const sal_Char * pImplName,
2121 lang::XMultiServiceFactory * pServiceManager,
2122 void * /*pRegistryKey*/ )
2125 void * pRet = 0;
2126 if ( !LngSvcMgr::getImplementationName_Static().compareToAscii( pImplName ) )
2128 uno::Reference< lang::XSingleServiceFactory > xFactory =
2129 cppu::createOneInstanceFactory(
2130 pServiceManager,
2131 LngSvcMgr::getImplementationName_Static(),
2132 LngSvcMgr_CreateInstance,
2133 LngSvcMgr::getSupportedServiceNames_Static());
2134 // acquire, because we return an interface pointer instead of a reference
2135 xFactory->acquire();
2136 pRet = xFactory.get();
2138 return pRet;
2143 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */