Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
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>
29 : #include <com/sun/star/linguistic2/ProofreadingIterator.hpp>
30 :
31 : #include <unotools/lingucfg.hxx>
32 : #include <comphelper/processfactory.hxx>
33 : #include <i18nlangtag/lang.h>
34 : #include <i18nlangtag/languagetag.hxx>
35 : #include <cppuhelper/factory.hxx>
36 : #include <cppuhelper/supportsservice.hxx>
37 : #include <boost/checked_delete.hpp>
38 : #include <boost/noncopyable.hpp>
39 :
40 : #include "lngsvcmgr.hxx"
41 : #include "lngopt.hxx"
42 : #include "lngreg.hxx"
43 : #include "linguistic/misc.hxx"
44 : #include "spelldsp.hxx"
45 : #include "hyphdsp.hxx"
46 : #include "thesdsp.hxx"
47 : #include "gciterator.hxx"
48 :
49 : using namespace com::sun::star;
50 : using namespace linguistic;
51 :
52 : uno::Sequence< OUString > static GetLangSvcList( const uno::Any &rVal );
53 : uno::Sequence< OUString > static GetLangSvc( const uno::Any &rVal );
54 :
55 384 : static bool lcl_SeqHasString( const uno::Sequence< OUString > &rSeq, const OUString &rText )
56 : {
57 384 : bool bRes = false;
58 :
59 384 : sal_Int32 nLen = rSeq.getLength();
60 384 : if (nLen == 0 || rText.isEmpty())
61 0 : return bRes;
62 :
63 384 : const OUString *pSeq = rSeq.getConstArray();
64 1776 : for (sal_Int32 i = 0; i < nLen && !bRes; ++i)
65 : {
66 1392 : if (rText == pSeq[i])
67 384 : bRes = true;
68 : }
69 384 : return bRes;
70 : }
71 :
72 :
73 308 : static uno::Sequence< lang::Locale > GetAvailLocales(
74 : const uno::Sequence< OUString > &rSvcImplNames )
75 : {
76 308 : uno::Sequence< lang::Locale > aRes;
77 :
78 616 : uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
79 308 : sal_Int32 nNames = rSvcImplNames.getLength();
80 308 : if( nNames )
81 : {
82 129 : std::set< LanguageType > aLanguages;
83 :
84 : //! since we're going to create one-instance services we have to
85 : //! supply their arguments even if we would not need them here...
86 258 : uno::Sequence< uno::Any > aArgs(2);
87 129 : aArgs.getArray()[0] <<= GetLinguProperties();
88 :
89 : // check all services for the supported languages and new
90 : // languages to the result
91 129 : const OUString *pImplNames = rSvcImplNames.getConstArray();
92 : sal_Int32 i;
93 :
94 258 : for (i = 0; i < nNames; ++i)
95 : {
96 129 : uno::Reference< linguistic2::XSupportedLocales > xSuppLoc;
97 : try
98 : {
99 387 : xSuppLoc = uno::Reference< linguistic2::XSupportedLocales >(
100 258 : xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
101 258 : pImplNames[i], aArgs, xContext ),
102 129 : uno::UNO_QUERY );
103 : }
104 0 : catch (uno::Exception &)
105 : {
106 : SAL_WARN( "linguistic", "createInstanceWithArguments failed" );
107 : }
108 :
109 129 : if (xSuppLoc.is())
110 : {
111 129 : uno::Sequence< lang::Locale > aLoc( xSuppLoc->getLocales() );
112 129 : sal_Int32 nLoc = aLoc.getLength();
113 473 : for (sal_Int32 k = 0; k < nLoc; ++k)
114 : {
115 344 : const lang::Locale *pLoc = aLoc.getConstArray();
116 344 : LanguageType nLang = LinguLocaleToLanguage( pLoc[k] );
117 :
118 : // language not already added?
119 344 : if (aLanguages.find( nLang ) == aLanguages.end())
120 344 : aLanguages.insert( nLang );
121 129 : }
122 : }
123 : else
124 : {
125 : SAL_WARN( "linguistic", "interface not supported by service" );
126 : }
127 129 : }
128 :
129 : // build return sequence
130 129 : sal_Int32 nLanguages = static_cast< sal_Int32 >(aLanguages.size());
131 129 : aRes.realloc( nLanguages );
132 129 : lang::Locale *pRes = aRes.getArray();
133 129 : std::set< LanguageType >::const_iterator aIt( aLanguages.begin() );
134 473 : for (i = 0; aIt != aLanguages.end(); ++aIt, ++i)
135 : {
136 344 : LanguageType nLang = *aIt;
137 344 : pRes[i] = LanguageTag::convertToLocale( nLang );
138 129 : }
139 : }
140 :
141 616 : return aRes;
142 : }
143 :
144 :
145 127 : struct SvcInfo
146 : {
147 : const OUString aSvcImplName;
148 : const uno::Sequence< sal_Int16 > aSuppLanguages;
149 :
150 129 : SvcInfo( const OUString &rSvcImplName,
151 : const uno::Sequence< sal_Int16 > &rSuppLanguages ) :
152 : aSvcImplName (rSvcImplName),
153 129 : aSuppLanguages (rSuppLanguages)
154 : {
155 129 : }
156 :
157 : bool HasLanguage( sal_Int16 nLanguage ) const;
158 : };
159 :
160 :
161 384 : bool SvcInfo::HasLanguage( sal_Int16 nLanguage ) const
162 : {
163 384 : sal_Int32 nCnt = aSuppLanguages.getLength();
164 384 : const sal_Int16 *pLang = aSuppLanguages.getConstArray();
165 : sal_Int32 i;
166 :
167 1392 : for ( i = 0; i < nCnt; ++i)
168 : {
169 1392 : if (nLanguage == pLang[i])
170 384 : break;
171 : }
172 384 : return i < nCnt;
173 : }
174 :
175 104 : class LngSvcMgrListenerHelper :
176 : public cppu::WeakImplHelper2
177 : <
178 : linguistic2::XLinguServiceEventListener,
179 : linguistic2::XDictionaryListEventListener
180 : >,
181 : private boost::noncopyable
182 : {
183 : LngSvcMgr &rMyManager;
184 :
185 : ::cppu::OInterfaceContainerHelper aLngSvcMgrListeners;
186 : ::cppu::OInterfaceContainerHelper aLngSvcEvtBroadcasters;
187 : uno::Reference< linguistic2::XSearchableDictionaryList > xDicList;
188 :
189 : sal_Int16 nCombinedLngSvcEvt;
190 :
191 : void LaunchEvent( sal_Int16 nLngSvcEvtFlags );
192 :
193 : long Timeout();
194 :
195 : public:
196 : LngSvcMgrListenerHelper( LngSvcMgr &rLngSvcMgr,
197 : const uno::Reference< linguistic2::XSearchableDictionaryList > &rxDicList );
198 :
199 : // lang::XEventListener
200 : virtual void SAL_CALL
201 : disposing( const lang::EventObject& rSource )
202 : throw(uno::RuntimeException, std::exception) SAL_OVERRIDE;
203 :
204 : // linguistic2::XLinguServiceEventListener
205 : virtual void SAL_CALL
206 : processLinguServiceEvent( const linguistic2::LinguServiceEvent& aLngSvcEvent )
207 : throw(uno::RuntimeException, std::exception) SAL_OVERRIDE;
208 :
209 : // linguistic2::XDictionaryListEventListener
210 : virtual void SAL_CALL
211 : processDictionaryListEvent(
212 : const linguistic2::DictionaryListEvent& rDicListEvent )
213 : throw(uno::RuntimeException, std::exception) SAL_OVERRIDE;
214 :
215 : inline bool AddLngSvcMgrListener(
216 : const uno::Reference< lang::XEventListener >& rxListener );
217 : inline bool RemoveLngSvcMgrListener(
218 : const uno::Reference< lang::XEventListener >& rxListener );
219 : void DisposeAndClear( const lang::EventObject &rEvtObj );
220 : bool AddLngSvcEvtBroadcaster(
221 : const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
222 : bool RemoveLngSvcEvtBroadcaster(
223 : const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
224 :
225 : void AddLngSvcEvt( sal_Int16 nLngSvcEvt );
226 : };
227 :
228 :
229 53 : LngSvcMgrListenerHelper::LngSvcMgrListenerHelper(
230 : LngSvcMgr &rLngSvcMgr,
231 : const uno::Reference< linguistic2::XSearchableDictionaryList > &rxDicList ) :
232 : rMyManager ( rLngSvcMgr ),
233 53 : aLngSvcMgrListeners ( GetLinguMutex() ),
234 53 : aLngSvcEvtBroadcasters ( GetLinguMutex() ),
235 159 : xDicList ( rxDicList )
236 : {
237 53 : if (xDicList.is())
238 : {
239 53 : xDicList->addDictionaryListEventListener(
240 53 : static_cast<linguistic2::XDictionaryListEventListener *>(this), sal_False );
241 : }
242 :
243 53 : nCombinedLngSvcEvt = 0;
244 53 : }
245 :
246 :
247 0 : void SAL_CALL LngSvcMgrListenerHelper::disposing( const lang::EventObject& rSource )
248 : throw(uno::RuntimeException, std::exception)
249 : {
250 0 : osl::MutexGuard aGuard( GetLinguMutex() );
251 :
252 0 : uno::Reference< uno::XInterface > xRef( rSource.Source );
253 0 : if ( xRef.is() )
254 : {
255 0 : aLngSvcMgrListeners .removeInterface( xRef );
256 0 : aLngSvcEvtBroadcasters.removeInterface( xRef );
257 0 : if (xDicList == xRef)
258 0 : xDicList = 0;
259 0 : }
260 0 : }
261 :
262 0 : long LngSvcMgrListenerHelper::Timeout()
263 : {
264 0 : osl::MutexGuard aGuard( GetLinguMutex() );
265 :
266 : {
267 : // change event source to LinguServiceManager since the listeners
268 : // probably do not know (and need not to know) about the specific
269 : // SpellChecker's or Hyphenator's.
270 : linguistic2::LinguServiceEvent aEvtObj(
271 0 : static_cast<com::sun::star::linguistic2::XLinguServiceManager*>(&rMyManager), nCombinedLngSvcEvt );
272 0 : nCombinedLngSvcEvt = 0;
273 :
274 0 : if (rMyManager.pSpellDsp)
275 0 : rMyManager.pSpellDsp->FlushSpellCache();
276 :
277 : // pass event on to linguistic2::XLinguServiceEventListener's
278 0 : cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
279 0 : while (aIt.hasMoreElements())
280 : {
281 0 : uno::Reference< linguistic2::XLinguServiceEventListener > xRef( aIt.next(), uno::UNO_QUERY );
282 0 : if (xRef.is())
283 0 : xRef->processLinguServiceEvent( aEvtObj );
284 0 : }
285 : }
286 0 : return 0;
287 : }
288 :
289 :
290 0 : void LngSvcMgrListenerHelper::AddLngSvcEvt( sal_Int16 nLngSvcEvt )
291 : {
292 0 : nCombinedLngSvcEvt |= nLngSvcEvt;
293 0 : Timeout();
294 0 : }
295 :
296 :
297 : void SAL_CALL
298 0 : LngSvcMgrListenerHelper::processLinguServiceEvent(
299 : const linguistic2::LinguServiceEvent& rLngSvcEvent )
300 : throw(uno::RuntimeException, std::exception)
301 : {
302 0 : osl::MutexGuard aGuard( GetLinguMutex() );
303 0 : AddLngSvcEvt( rLngSvcEvent.nEvent );
304 0 : }
305 :
306 :
307 : void SAL_CALL
308 1 : LngSvcMgrListenerHelper::processDictionaryListEvent(
309 : const linguistic2::DictionaryListEvent& rDicListEvent )
310 : throw(uno::RuntimeException, std::exception)
311 : {
312 1 : osl::MutexGuard aGuard( GetLinguMutex() );
313 :
314 1 : sal_Int16 nDlEvt = rDicListEvent.nCondensedEvent;
315 1 : if (0 == nDlEvt)
316 1 : return;
317 :
318 : // we do keep the original event source here though...
319 :
320 : // pass event on to linguistic2::XDictionaryListEventListener's
321 2 : cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
322 3 : while (aIt.hasMoreElements())
323 : {
324 1 : uno::Reference< linguistic2::XDictionaryListEventListener > xRef( aIt.next(), uno::UNO_QUERY );
325 1 : if (xRef.is())
326 0 : xRef->processDictionaryListEvent( rDicListEvent );
327 1 : }
328 :
329 : // "translate" DictionaryList event into linguistic2::LinguServiceEvent
330 1 : sal_Int16 nLngSvcEvt = 0;
331 : sal_Int16 nSpellCorrectFlags =
332 : linguistic2::DictionaryListEventFlags::ADD_NEG_ENTRY |
333 : linguistic2::DictionaryListEventFlags::DEL_POS_ENTRY |
334 : linguistic2::DictionaryListEventFlags::ACTIVATE_NEG_DIC |
335 1 : linguistic2::DictionaryListEventFlags::DEACTIVATE_POS_DIC;
336 1 : if (0 != (nDlEvt & nSpellCorrectFlags))
337 0 : nLngSvcEvt |= linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN;
338 :
339 : sal_Int16 nSpellWrongFlags =
340 : linguistic2::DictionaryListEventFlags::ADD_POS_ENTRY |
341 : linguistic2::DictionaryListEventFlags::DEL_NEG_ENTRY |
342 : linguistic2::DictionaryListEventFlags::ACTIVATE_POS_DIC |
343 1 : linguistic2::DictionaryListEventFlags::DEACTIVATE_NEG_DIC;
344 1 : if (0 != (nDlEvt & nSpellWrongFlags))
345 1 : nLngSvcEvt |= linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN;
346 :
347 : sal_Int16 nHyphenateFlags =
348 : linguistic2::DictionaryListEventFlags::ADD_POS_ENTRY |
349 : linguistic2::DictionaryListEventFlags::DEL_POS_ENTRY |
350 : linguistic2::DictionaryListEventFlags::ACTIVATE_POS_DIC |
351 1 : linguistic2::DictionaryListEventFlags::ACTIVATE_NEG_DIC;
352 1 : if (0 != (nDlEvt & nHyphenateFlags))
353 1 : nLngSvcEvt |= linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN;
354 :
355 1 : if (rMyManager.pSpellDsp)
356 0 : rMyManager.pSpellDsp->FlushSpellCache();
357 1 : if (nLngSvcEvt)
358 2 : LaunchEvent( nLngSvcEvt );
359 : }
360 :
361 :
362 1 : void LngSvcMgrListenerHelper::LaunchEvent( sal_Int16 nLngSvcEvtFlags )
363 : {
364 : linguistic2::LinguServiceEvent aEvt(
365 1 : static_cast<com::sun::star::linguistic2::XLinguServiceManager*>(&rMyManager), nLngSvcEvtFlags );
366 :
367 : // pass event on to linguistic2::XLinguServiceEventListener's
368 2 : cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
369 3 : while (aIt.hasMoreElements())
370 : {
371 1 : uno::Reference< linguistic2::XLinguServiceEventListener > xRef( aIt.next(), uno::UNO_QUERY );
372 1 : if (xRef.is())
373 1 : xRef->processLinguServiceEvent( aEvt );
374 2 : }
375 1 : }
376 :
377 :
378 42 : inline bool LngSvcMgrListenerHelper::AddLngSvcMgrListener(
379 : const uno::Reference< lang::XEventListener >& rxListener )
380 : {
381 42 : aLngSvcMgrListeners.addInterface( rxListener );
382 42 : return true;
383 : }
384 :
385 :
386 0 : inline bool LngSvcMgrListenerHelper::RemoveLngSvcMgrListener(
387 : const uno::Reference< lang::XEventListener >& rxListener )
388 : {
389 0 : aLngSvcMgrListeners.removeInterface( rxListener );
390 0 : return true;
391 : }
392 :
393 :
394 53 : void LngSvcMgrListenerHelper::DisposeAndClear( const lang::EventObject &rEvtObj )
395 : {
396 : // call "disposing" for all listeners and clear list
397 53 : aLngSvcMgrListeners .disposeAndClear( rEvtObj );
398 :
399 : // remove references to this object hold by the broadcasters
400 53 : cppu::OInterfaceIteratorHelper aIt( aLngSvcEvtBroadcasters );
401 138 : while (aIt.hasMoreElements())
402 : {
403 32 : uno::Reference< linguistic2::XLinguServiceEventBroadcaster > xRef( aIt.next(), uno::UNO_QUERY );
404 32 : if (xRef.is())
405 32 : RemoveLngSvcEvtBroadcaster( xRef );
406 32 : }
407 :
408 : // remove reference to this object hold by the dictionary-list
409 53 : if (xDicList.is())
410 : {
411 53 : xDicList->removeDictionaryListEventListener(
412 53 : static_cast<linguistic2::XDictionaryListEventListener *>(this) );
413 53 : xDicList = 0;
414 53 : }
415 53 : }
416 :
417 :
418 32 : bool LngSvcMgrListenerHelper::AddLngSvcEvtBroadcaster(
419 : const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
420 : {
421 32 : bool bRes = false;
422 32 : if (rxBroadcaster.is())
423 : {
424 32 : aLngSvcEvtBroadcasters.addInterface( rxBroadcaster );
425 32 : rxBroadcaster->addLinguServiceEventListener(
426 32 : static_cast<linguistic2::XLinguServiceEventListener *>(this) );
427 : }
428 32 : return bRes;
429 : }
430 :
431 :
432 32 : bool LngSvcMgrListenerHelper::RemoveLngSvcEvtBroadcaster(
433 : const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
434 : {
435 32 : bool bRes = false;
436 32 : if (rxBroadcaster.is())
437 : {
438 32 : aLngSvcEvtBroadcasters.removeInterface( rxBroadcaster );
439 32 : rxBroadcaster->removeLinguServiceEventListener(
440 32 : static_cast<linguistic2::XLinguServiceEventListener *>(this) );
441 : }
442 32 : return bRes;
443 : }
444 :
445 :
446 :
447 :
448 77 : LngSvcMgr::LngSvcMgr()
449 : : utl::ConfigItem("Office.Linguistic")
450 77 : , aEvtListeners(GetLinguMutex())
451 : {
452 77 : bDisposing = false;
453 :
454 77 : pSpellDsp = 0;
455 77 : pGrammarDsp = 0;
456 77 : pHyphDsp = 0;
457 77 : pThesDsp = 0;
458 :
459 77 : pAvailSpellSvcs = 0;
460 77 : pAvailGrammarSvcs = 0;
461 77 : pAvailHyphSvcs = 0;
462 77 : pAvailThesSvcs = 0;
463 77 : pListenerHelper = 0;
464 :
465 : // request notify events when properties (i.e. something in the subtree) changes
466 77 : uno::Sequence< OUString > aNames(4);
467 77 : OUString *pNames = aNames.getArray();
468 77 : pNames[0] = "ServiceManager/SpellCheckerList";
469 77 : pNames[1] = "ServiceManager/GrammarCheckerList";
470 77 : pNames[2] = "ServiceManager/HyphenatorList";
471 77 : pNames[3] = "ServiceManager/ThesaurusList";
472 77 : EnableNotification( aNames );
473 :
474 77 : UpdateAll();
475 :
476 77 : aUpdateIdle.SetPriority(SchedulerPriority::LOWEST);
477 77 : aUpdateIdle.SetIdleHdl(LINK(this, LngSvcMgr, updateAndBroadcast));
478 :
479 : // request to be notified if an extension has been added/removed
480 154 : uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
481 :
482 154 : uno::Reference<deployment::XExtensionManager> xExtensionManager;
483 : try {
484 77 : xExtensionManager = deployment::ExtensionManager::get(xContext);
485 32 : } catch ( const uno::DeploymentException & ) {
486 : SAL_WARN( "linguistic", "no extension manager - should fire on mobile only" );
487 0 : } catch ( const deployment::DeploymentException & ) {
488 : SAL_WARN( "linguistic", "no extension manager - should fire on mobile only" );
489 : }
490 77 : if (xExtensionManager.is())
491 : {
492 45 : xMB = uno::Reference<util::XModifyBroadcaster>(xExtensionManager, uno::UNO_QUERY_THROW);
493 :
494 45 : uno::Reference<util::XModifyListener> xListener(this);
495 45 : xMB->addModifyListener( xListener );
496 77 : }
497 77 : }
498 :
499 : // ::com::sun::star::util::XModifyListener
500 0 : void LngSvcMgr::modified(const lang::EventObject&)
501 : throw(uno::RuntimeException, std::exception)
502 : {
503 0 : osl::MutexGuard aGuard(GetLinguMutex());
504 : //assume that if an extension has been added/removed that
505 : //it might be a dictionary extension, so drop our cache
506 :
507 0 : clearSvcInfoArray(pAvailSpellSvcs);
508 0 : clearSvcInfoArray(pAvailGrammarSvcs);
509 0 : clearSvcInfoArray(pAvailHyphSvcs);
510 0 : clearSvcInfoArray(pAvailThesSvcs);
511 :
512 : //schedule in an update to execute in the main thread
513 0 : aUpdateIdle.Start();
514 0 : }
515 :
516 : //run update, and inform everyone that dictionaries (may) have changed, this
517 : //needs to be run in the main thread because
518 : //utl::ConfigChangeListener_Impl::changesOccurred grabs the SolarMutex and we
519 : //get notified that an extension was added from an extension manager thread
520 0 : IMPL_LINK_NOARG_TYPED(LngSvcMgr, updateAndBroadcast, Idle *, void)
521 : {
522 0 : osl::MutexGuard aGuard( GetLinguMutex() );
523 :
524 0 : UpdateAll();
525 :
526 0 : if (pListenerHelper)
527 : {
528 : pListenerHelper->AddLngSvcEvt(
529 : linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN |
530 : linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN |
531 : linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN |
532 0 : linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN );
533 0 : }
534 0 : }
535 :
536 118 : void LngSvcMgr::stopListening()
537 : {
538 118 : osl::MutexGuard aGuard(GetLinguMutex());
539 :
540 118 : if (xMB.is())
541 : {
542 : try
543 : {
544 45 : uno::Reference<util::XModifyListener> xListener(this);
545 90 : xMB->removeModifyListener(xListener);
546 : }
547 45 : catch (const uno::Exception&)
548 : {
549 : }
550 :
551 45 : xMB.clear();
552 118 : }
553 118 : }
554 :
555 45 : void LngSvcMgr::disposing(const lang::EventObject&)
556 : throw (uno::RuntimeException, std::exception)
557 : {
558 45 : stopListening();
559 45 : }
560 :
561 636 : void LngSvcMgr::clearSvcInfoArray(SvcInfoArray* &rpInfo)
562 : {
563 636 : delete rpInfo;
564 636 : rpInfo = NULL;
565 636 : }
566 :
567 219 : LngSvcMgr::~LngSvcMgr()
568 : {
569 73 : stopListening();
570 :
571 : // memory for pSpellDsp, pHyphDsp, pThesDsp, pListenerHelper
572 : // will be freed in the destructor of the respective Reference's
573 : // xSpellDsp, xGrammarDsp, xHyphDsp, xThesDsp
574 :
575 73 : clearSvcInfoArray(pAvailSpellSvcs);
576 73 : clearSvcInfoArray(pAvailGrammarSvcs);
577 73 : clearSvcInfoArray(pAvailHyphSvcs);
578 73 : clearSvcInfoArray(pAvailThesSvcs);
579 146 : }
580 :
581 : namespace
582 : {
583 : using lang::Locale;
584 : using uno::Any;
585 : using uno::Sequence;
586 :
587 1072 : bool lcl_FindEntry( const OUString &rEntry, const Sequence< OUString > &rCfgSvcs )
588 : {
589 1072 : sal_Int32 nRes = -1;
590 1072 : sal_Int32 nEntries = rCfgSvcs.getLength();
591 1072 : const OUString *pEntry = rCfgSvcs.getConstArray();
592 1641 : for (sal_Int32 i = 0; i < nEntries && nRes == -1; ++i)
593 : {
594 569 : if (rEntry == pEntry[i])
595 120 : nRes = i;
596 : }
597 1072 : return nRes != -1;
598 : }
599 :
600 344 : Sequence< OUString > lcl_GetLastFoundSvcs(
601 : SvtLinguConfig &rCfg,
602 : const OUString &rLastFoundList ,
603 : const Locale &rAvailLocale )
604 : {
605 344 : Sequence< OUString > aRes;
606 :
607 688 : OUString aCfgLocaleStr( LanguageTag::convertToBcp47( rAvailLocale ) );
608 :
609 688 : Sequence< OUString > aNodeNames( rCfg.GetNodeNames(rLastFoundList) );
610 344 : bool bFound = lcl_FindEntry( aCfgLocaleStr, aNodeNames);
611 :
612 344 : if (bFound)
613 : {
614 40 : Sequence< OUString > aNames(1);
615 40 : OUString &rNodeName = aNames.getArray()[0];
616 40 : rNodeName = rLastFoundList;
617 40 : rNodeName += OUString( (sal_Unicode)'/' );
618 40 : rNodeName += aCfgLocaleStr;
619 80 : Sequence< Any > aValues( rCfg.GetProperties( aNames ) );
620 40 : if (aValues.getLength())
621 : {
622 : SAL_WARN_IF( aValues.getLength() != 1, "linguistic", "unexpected length of sequence" );
623 40 : Sequence< OUString > aSvcImplNames;
624 40 : if (aValues.getConstArray()[0] >>= aSvcImplNames)
625 40 : aRes = aSvcImplNames;
626 : else
627 : {
628 : SAL_WARN( "linguistic", "type mismatch" );
629 40 : }
630 40 : }
631 : }
632 :
633 688 : return aRes;
634 : }
635 :
636 40 : Sequence< OUString > lcl_RemoveMissingEntries(
637 : const Sequence< OUString > &rCfgSvcs,
638 : const Sequence< OUString > &rAvailSvcs )
639 : {
640 40 : Sequence< OUString > aRes( rCfgSvcs.getLength() );
641 40 : OUString *pRes = aRes.getArray();
642 40 : sal_Int32 nCnt = 0;
643 :
644 40 : sal_Int32 nEntries = rCfgSvcs.getLength();
645 40 : const OUString *pEntry = rCfgSvcs.getConstArray();
646 80 : for (sal_Int32 i = 0; i < nEntries; ++i)
647 : {
648 40 : if (!pEntry[i].isEmpty() && lcl_FindEntry( pEntry[i], rAvailSvcs ))
649 40 : pRes[ nCnt++ ] = pEntry[i];
650 : }
651 :
652 40 : aRes.realloc( nCnt );
653 40 : return aRes;
654 : }
655 :
656 344 : Sequence< OUString > lcl_GetNewEntries(
657 : const Sequence< OUString > &rLastFoundSvcs,
658 : const Sequence< OUString > &rAvailSvcs )
659 : {
660 344 : sal_Int32 nLen = rAvailSvcs.getLength();
661 344 : Sequence< OUString > aRes( nLen );
662 344 : OUString *pRes = aRes.getArray();
663 344 : sal_Int32 nCnt = 0;
664 :
665 344 : const OUString *pEntry = rAvailSvcs.getConstArray();
666 688 : for (sal_Int32 i = 0; i < nLen; ++i)
667 : {
668 344 : if (!pEntry[i].isEmpty() && !lcl_FindEntry( pEntry[i], rLastFoundSvcs ))
669 304 : pRes[ nCnt++ ] = pEntry[i];
670 : }
671 :
672 344 : aRes.realloc( nCnt );
673 344 : return aRes;
674 : }
675 :
676 344 : Sequence< OUString > lcl_MergeSeq(
677 : const Sequence< OUString > &rCfgSvcs,
678 : const Sequence< OUString > &rNewSvcs )
679 : {
680 344 : Sequence< OUString > aRes( rCfgSvcs.getLength() + rNewSvcs.getLength() );
681 344 : OUString *pRes = aRes.getArray();
682 344 : sal_Int32 nCnt = 0;
683 :
684 1032 : for (sal_Int32 k = 0; k < 2; ++k)
685 : {
686 : // add previously configuerd service first and append
687 : // new found services at the end
688 688 : const Sequence< OUString > &rSeq = k == 0 ? rCfgSvcs : rNewSvcs;
689 :
690 688 : sal_Int32 nLen = rSeq.getLength();
691 688 : const OUString *pEntry = rSeq.getConstArray();
692 1032 : for (sal_Int32 i = 0; i < nLen; ++i)
693 : {
694 344 : if (!pEntry[i].isEmpty() && !lcl_FindEntry( pEntry[i], aRes ))
695 344 : pRes[ nCnt++ ] = pEntry[i];
696 : }
697 : }
698 :
699 344 : aRes.realloc( nCnt );
700 344 : return aRes;
701 : }
702 : }
703 :
704 77 : void LngSvcMgr::UpdateAll()
705 : {
706 : using beans::PropertyValue;
707 : using lang::Locale;
708 : using uno::Sequence;
709 :
710 : typedef OUString OUstring_t;
711 : typedef Sequence< OUString > Sequence_OUString_t;
712 : typedef std::map< OUstring_t, Sequence_OUString_t > list_entry_map_t;
713 :
714 77 : SvtLinguConfig aCfg;
715 :
716 77 : const int nNumServices = 4;
717 77 : const sal_Char * apServices[nNumServices] = { SN_SPELLCHECKER, SN_GRAMMARCHECKER, SN_HYPHENATOR, SN_THESAURUS };
718 77 : const sal_Char * apCurLists[nNumServices] = { "ServiceManager/SpellCheckerList", "ServiceManager/GrammarCheckerList", "ServiceManager/HyphenatorList", "ServiceManager/ThesaurusList" };
719 77 : const sal_Char * apLastFoundLists[nNumServices] = { "ServiceManager/LastFoundSpellCheckers", "ServiceManager/LastFoundGrammarCheckers", "ServiceManager/LastFoundHyphenators", "ServiceManager/LastFoundThesauri" };
720 :
721 : // usage of indices as above: 0 = spell checker, 1 = grammar checker, 2 = hyphenator, 3 = thesaurus
722 154 : std::vector< list_entry_map_t > aLastFoundSvcs(nNumServices);
723 154 : std::vector< list_entry_map_t > aCurSvcs(nNumServices);
724 :
725 385 : for (int k = 0; k < nNumServices; ++k)
726 : {
727 308 : OUString aService( OUString::createFromAscii( apServices[k] ) );
728 616 : OUString aActiveList( OUString::createFromAscii( apCurLists[k] ) );
729 616 : OUString aLastFoundList( OUString::createFromAscii( apLastFoundLists[k] ) );
730 : sal_Int32 i;
731 :
732 :
733 : // remove configured but not available language/services entries
734 :
735 616 : Sequence< OUString > aNodeNames( aCfg.GetNodeNames( aActiveList ) ); // list of configured locales
736 308 : sal_Int32 nNodeNames = aNodeNames.getLength();
737 308 : const OUString *pNodeName = aNodeNames.getConstArray();
738 348 : for (i = 0; i < nNodeNames; ++i)
739 : {
740 40 : Locale aLocale( (LanguageTag(pNodeName[i])).getLocale() );
741 80 : Sequence< OUString > aCfgSvcs( getConfiguredServices( aService, aLocale ));
742 80 : Sequence< OUString > aAvailSvcs( getAvailableServices( aService, aLocale ));
743 :
744 40 : aCfgSvcs = lcl_RemoveMissingEntries( aCfgSvcs, aAvailSvcs );
745 :
746 40 : aCurSvcs[k][ pNodeName[i] ] = aCfgSvcs;
747 40 : }
748 :
749 :
750 : // add new available language/service entries
751 : // and
752 : // set last found services to currently available ones
753 :
754 616 : Sequence< Locale > aAvailLocales( getAvailableLocales(aService) );
755 308 : sal_Int32 nAvailLocales = aAvailLocales.getLength();
756 308 : const Locale *pAvailLocale = aAvailLocales.getConstArray();
757 652 : for (i = 0; i < nAvailLocales; ++i)
758 : {
759 344 : OUString aCfgLocaleStr( (LanguageTag(pAvailLocale[i])).getBcp47() );
760 :
761 688 : Sequence< OUString > aAvailSvcs( getAvailableServices( aService, pAvailLocale[i] ));
762 :
763 344 : aLastFoundSvcs[k][ aCfgLocaleStr ] = aAvailSvcs;
764 :
765 : Sequence< OUString > aLastSvcs(
766 688 : lcl_GetLastFoundSvcs( aCfg, aLastFoundList , pAvailLocale[i] ));
767 : Sequence< OUString > aNewSvcs =
768 688 : lcl_GetNewEntries( aLastSvcs, aAvailSvcs );
769 :
770 688 : Sequence< OUString > aCfgSvcs( aCurSvcs[k][ aCfgLocaleStr ] );
771 :
772 : // merge services list (previously configured to be listed first).
773 344 : aCfgSvcs = lcl_MergeSeq( aCfgSvcs, aNewSvcs );
774 :
775 344 : aCurSvcs[k][ aCfgLocaleStr ] = aCfgSvcs;
776 344 : }
777 308 : }
778 :
779 :
780 : // write new data back to configuration
781 :
782 385 : for (int k = 0; k < nNumServices; ++k)
783 : {
784 924 : for (int i = 0; i < 2; ++i)
785 : {
786 616 : const sal_Char *pSubNodeName = (i == 0) ? apCurLists[k] : apLastFoundLists[k];
787 616 : OUString aSubNodeName( OUString::createFromAscii(pSubNodeName) );
788 :
789 616 : list_entry_map_t &rCurMap = (i == 0) ? aCurSvcs[k] : aLastFoundSvcs[k];
790 616 : list_entry_map_t::const_iterator aIt( rCurMap.begin() );
791 616 : sal_Int32 nVals = static_cast< sal_Int32 >( rCurMap.size() );
792 1232 : Sequence< PropertyValue > aNewValues( nVals );
793 616 : PropertyValue *pNewValue = aNewValues.getArray();
794 1920 : while (aIt != rCurMap.end())
795 : {
796 688 : OUString aCfgEntryName( aSubNodeName );
797 688 : aCfgEntryName += OUString( (sal_Unicode) '/' );
798 688 : aCfgEntryName += (*aIt).first;
799 :
800 688 : pNewValue->Name = aCfgEntryName;
801 688 : pNewValue->Value <<= (*aIt).second;
802 688 : ++pNewValue;
803 688 : ++aIt;
804 688 : }
805 : OSL_ENSURE( pNewValue - aNewValues.getArray() == nVals,
806 : "possible mismatch of sequence size and property number" );
807 :
808 : {
809 : // add new or replace existing entries.
810 616 : bool bRes = aCfg.ReplaceSetProperties( aSubNodeName, aNewValues );
811 616 : if (!bRes)
812 : {
813 : #if OSL_DEBUG_LEVEL > 1
814 : SAL_WARN( "linguistic", "failed to set new configuration values" );
815 : #endif
816 : }
817 : }
818 616 : }
819 77 : }
820 :
821 : //The new settings in the configuration get applied ! because we are
822 : //listening to the configuration for changes of the relevant ! properties
823 : //and Notify applies the new settings.
824 77 : }
825 :
826 86 : void LngSvcMgr::Notify( const uno::Sequence< OUString > &rPropertyNames )
827 : {
828 86 : const OUString aSpellCheckerList( "ServiceManager/SpellCheckerList" );
829 172 : const OUString aGrammarCheckerList( "ServiceManager/GrammarCheckerList" );
830 172 : const OUString aHyphenatorList( "ServiceManager/HyphenatorList" );
831 172 : const OUString aThesaurusList( "ServiceManager/ThesaurusList" );
832 :
833 172 : const uno::Sequence< OUString > aSpellCheckerListEntries( GetNodeNames( aSpellCheckerList ) );
834 172 : const uno::Sequence< OUString > aGrammarCheckerListEntries( GetNodeNames( aGrammarCheckerList ) );
835 172 : const uno::Sequence< OUString > aHyphenatorListEntries( GetNodeNames( aHyphenatorList ) );
836 172 : const uno::Sequence< OUString > aThesaurusListEntries( GetNodeNames( aThesaurusList ) );
837 :
838 172 : uno::Sequence< uno::Any > aValues;
839 172 : uno::Sequence< OUString > aNames( 1 );
840 86 : OUString *pNames = aNames.getArray();
841 :
842 86 : sal_Int32 nLen = rPropertyNames.getLength();
843 86 : const OUString *pPropertyNames = rPropertyNames.getConstArray();
844 430 : for (sal_Int32 i = 0; i < nLen; ++i)
845 : {
846 : // property names look like
847 : // "ServiceManager/ThesaurusList/de-CH"
848 :
849 344 : const OUString &rName = pPropertyNames[i];
850 : sal_Int32 nKeyStart;
851 344 : nKeyStart = rName.lastIndexOf( '/' );
852 344 : OUString aKeyText;
853 344 : if (nKeyStart != -1)
854 344 : aKeyText = rName.copy( nKeyStart + 1 );
855 : SAL_WARN_IF( aKeyText.isEmpty(), "linguistic", "unexpected key (lang::Locale) string" );
856 344 : if (rName.startsWith( aSpellCheckerList ))
857 : {
858 301 : osl::MutexGuard aGuard(GetLinguMutex());
859 :
860 : // delete old cached data, needs to be acquired new on demand
861 301 : clearSvcInfoArray(pAvailSpellSvcs);
862 :
863 602 : OUString aNode( aSpellCheckerList );
864 301 : if (lcl_SeqHasString( aSpellCheckerListEntries, aKeyText ))
865 : {
866 301 : OUString aPropName( aNode );
867 301 : aPropName += OUString( (sal_Unicode) '/' );
868 301 : aPropName += aKeyText;
869 301 : pNames[0] = aPropName;
870 301 : aValues = /*aCfg.*/GetProperties( aNames );
871 602 : uno::Sequence< OUString > aSvcImplNames;
872 301 : if (aValues.getLength())
873 301 : aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
874 :
875 301 : LanguageType nLang = LANGUAGE_NONE;
876 301 : if (!aKeyText.isEmpty())
877 301 : nLang = LanguageTag::convertToLanguageTypeWithFallback( aKeyText );
878 :
879 301 : GetSpellCheckerDsp_Impl( false ); // don't set service list, it will be done below
880 602 : pSpellDsp->SetServiceList( LanguageTag::convertToLocale(nLang), aSvcImplNames );
881 301 : }
882 : }
883 43 : else if (rName.startsWith( aGrammarCheckerList ))
884 : {
885 0 : osl::MutexGuard aGuard(GetLinguMutex());
886 :
887 : // delete old cached data, needs to be acquired new on demand
888 0 : clearSvcInfoArray(pAvailGrammarSvcs);
889 :
890 0 : OUString aNode( aGrammarCheckerList );
891 0 : if (lcl_SeqHasString( aGrammarCheckerListEntries, aKeyText ))
892 : {
893 0 : OUString aPropName( aNode );
894 0 : aPropName += OUString( (sal_Unicode) '/' );
895 0 : aPropName += aKeyText;
896 0 : pNames[0] = aPropName;
897 0 : aValues = /*aCfg.*/GetProperties( aNames );
898 0 : uno::Sequence< OUString > aSvcImplNames;
899 0 : if (aValues.getLength())
900 0 : aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
901 :
902 0 : LanguageType nLang = LANGUAGE_NONE;
903 0 : if (!aKeyText.isEmpty())
904 0 : nLang = LanguageTag::convertToLanguageTypeWithFallback( aKeyText );
905 :
906 0 : if (SvtLinguConfig().HasGrammarChecker())
907 : {
908 0 : GetGrammarCheckerDsp_Impl( false ); // don't set service list, it will be done below
909 0 : pGrammarDsp->SetServiceList( LanguageTag::convertToLocale(nLang), aSvcImplNames );
910 0 : }
911 0 : }
912 : }
913 43 : else if (rName.startsWith( aHyphenatorList ))
914 : {
915 43 : osl::MutexGuard aGuard(GetLinguMutex());
916 :
917 : // delete old cached data, needs to be acquired new on demand
918 43 : clearSvcInfoArray(pAvailHyphSvcs);
919 :
920 86 : OUString aNode( aHyphenatorList );
921 43 : if (lcl_SeqHasString( aHyphenatorListEntries, aKeyText ))
922 : {
923 43 : OUString aPropName( aNode );
924 43 : aPropName += OUString( (sal_Unicode) '/' );
925 43 : aPropName += aKeyText;
926 43 : pNames[0] = aPropName;
927 43 : aValues = /*aCfg.*/GetProperties( aNames );
928 86 : uno::Sequence< OUString > aSvcImplNames;
929 43 : if (aValues.getLength())
930 43 : aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
931 :
932 43 : LanguageType nLang = LANGUAGE_NONE;
933 43 : if (!aKeyText.isEmpty())
934 43 : nLang = LanguageTag::convertToLanguageTypeWithFallback( aKeyText );
935 :
936 43 : GetHyphenatorDsp_Impl( false ); // don't set service list, it will be done below
937 86 : pHyphDsp->SetServiceList( LanguageTag::convertToLocale(nLang), aSvcImplNames );
938 43 : }
939 : }
940 0 : else if (rName.startsWith( aThesaurusList ))
941 : {
942 0 : osl::MutexGuard aGuard(GetLinguMutex());
943 :
944 : // delete old cached data, needs to be acquired new on demand
945 0 : clearSvcInfoArray(pAvailThesSvcs);
946 :
947 0 : OUString aNode( aThesaurusList );
948 0 : if (lcl_SeqHasString( aThesaurusListEntries, aKeyText ))
949 : {
950 0 : OUString aPropName( aNode );
951 0 : aPropName += OUString( (sal_Unicode) '/' );
952 0 : aPropName += aKeyText;
953 0 : pNames[0] = aPropName;
954 0 : aValues = /*aCfg.*/GetProperties( aNames );
955 0 : uno::Sequence< OUString > aSvcImplNames;
956 0 : if (aValues.getLength())
957 0 : aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
958 :
959 0 : LanguageType nLang = LANGUAGE_NONE;
960 0 : if (!aKeyText.isEmpty())
961 0 : nLang = LanguageTag::convertToLanguageTypeWithFallback( aKeyText );
962 :
963 0 : GetThesaurusDsp_Impl( false ); // don't set service list, it will be done below
964 0 : pThesDsp->SetServiceList( LanguageTag::convertToLocale(nLang), aSvcImplNames );
965 0 : }
966 : }
967 : else
968 : {
969 : SAL_WARN( "linguistic", "nofified for unexpected property" );
970 : }
971 430 : }
972 86 : }
973 :
974 :
975 0 : void LngSvcMgr::ImplCommit()
976 : {
977 : // everything necessary should have already been done by 'SaveCfgSvcs'
978 : // called from within 'setConfiguredServices'.
979 : // Also this class usually exits only when the Office is being shutdown.
980 0 : }
981 :
982 :
983 53 : void LngSvcMgr::GetListenerHelper_Impl()
984 : {
985 53 : if (!pListenerHelper)
986 : {
987 53 : pListenerHelper = new LngSvcMgrListenerHelper( *this, linguistic::GetDictionaryList() );
988 53 : xListenerHelper = static_cast<linguistic2::XLinguServiceEventListener *>(pListenerHelper);
989 : }
990 53 : }
991 :
992 :
993 314 : void LngSvcMgr::GetSpellCheckerDsp_Impl( bool bSetSvcList )
994 : {
995 314 : if (!pSpellDsp)
996 : {
997 56 : pSpellDsp = new SpellCheckerDispatcher( *this );
998 56 : xSpellDsp = pSpellDsp;
999 56 : if (bSetSvcList)
1000 13 : SetCfgServiceLists( *pSpellDsp );
1001 : }
1002 314 : }
1003 :
1004 :
1005 0 : void LngSvcMgr::GetGrammarCheckerDsp_Impl( bool bSetSvcList )
1006 : {
1007 0 : if (!pGrammarDsp && SvtLinguConfig().HasGrammarChecker())
1008 : {
1009 : //! since the grammar checking iterator needs to be a one instance service
1010 : //! we need to create it the correct way!
1011 0 : uno::Reference< linguistic2::XProofreadingIterator > xGCI;
1012 : try
1013 : {
1014 0 : xGCI = linguistic2::ProofreadingIterator::create( comphelper::getProcessComponentContext() );
1015 : }
1016 0 : catch (const uno::Exception &)
1017 : {
1018 : }
1019 : SAL_WARN_IF( !xGCI.is(), "linguistic", "instantiating grammar checking iterator failed" );
1020 :
1021 0 : if (xGCI.is())
1022 : {
1023 0 : pGrammarDsp = dynamic_cast< GrammarCheckingIterator * >(xGCI.get());
1024 0 : xGrammarDsp = xGCI;
1025 : SAL_WARN_IF( pGrammarDsp == NULL, "linguistic", "failed to get implementation" );
1026 0 : if (bSetSvcList && pGrammarDsp)
1027 0 : SetCfgServiceLists( *pGrammarDsp );
1028 0 : }
1029 : }
1030 0 : }
1031 :
1032 :
1033 74 : void LngSvcMgr::GetHyphenatorDsp_Impl( bool bSetSvcList )
1034 : {
1035 74 : if (!pHyphDsp)
1036 : {
1037 74 : pHyphDsp = new HyphenatorDispatcher( *this );
1038 74 : xHyphDsp = pHyphDsp;
1039 74 : if (bSetSvcList)
1040 31 : SetCfgServiceLists( *pHyphDsp );
1041 : }
1042 74 : }
1043 :
1044 :
1045 0 : void LngSvcMgr::GetThesaurusDsp_Impl( bool bSetSvcList )
1046 : {
1047 0 : if (!pThesDsp)
1048 : {
1049 0 : pThesDsp = new ThesaurusDispatcher;
1050 0 : xThesDsp = pThesDsp;
1051 0 : if (bSetSvcList)
1052 0 : SetCfgServiceLists( *pThesDsp );
1053 : }
1054 0 : }
1055 :
1056 :
1057 413 : void LngSvcMgr::GetAvailableSpellSvcs_Impl()
1058 : {
1059 413 : if (!pAvailSpellSvcs)
1060 : {
1061 77 : pAvailSpellSvcs = new SvcInfoArray;
1062 :
1063 77 : uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
1064 :
1065 154 : uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xContext->getServiceManager(), uno::UNO_QUERY );
1066 154 : uno::Reference< container::XEnumeration > xEnum;
1067 77 : if (xEnumAccess.is())
1068 77 : xEnum = xEnumAccess->createContentEnumeration( SN_SPELLCHECKER );
1069 :
1070 77 : if (xEnum.is())
1071 : {
1072 197 : while (xEnum->hasMoreElements())
1073 : {
1074 43 : uno::Any aCurrent = xEnum->nextElement();
1075 86 : uno::Reference< lang::XSingleComponentFactory > xCompFactory;
1076 86 : uno::Reference< lang::XSingleServiceFactory > xFactory;
1077 :
1078 86 : uno::Reference< linguistic2::XSpellChecker > xSvc;
1079 43 : xCompFactory.set(aCurrent, css::uno::UNO_QUERY);
1080 43 : if (!xCompFactory.is())
1081 : {
1082 0 : xFactory.set(aCurrent, css::uno::UNO_QUERY);
1083 : }
1084 43 : if ( xCompFactory.is() || xFactory.is() )
1085 : {
1086 : try
1087 : {
1088 43 : xSvc = uno::Reference< linguistic2::XSpellChecker >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
1089 : }
1090 0 : catch (const uno::Exception &)
1091 : {
1092 : SAL_WARN( "linguistic", "createInstance failed" );
1093 : }
1094 : }
1095 :
1096 43 : if (xSvc.is())
1097 : {
1098 43 : OUString aImplName;
1099 86 : uno::Sequence< sal_Int16 > aLanguages;
1100 86 : uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
1101 43 : if (xInfo.is())
1102 43 : aImplName = xInfo->getImplementationName();
1103 : SAL_WARN_IF( aImplName.isEmpty(), "linguistic", "empty implementation name" );
1104 86 : uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
1105 : SAL_WARN_IF( !xSuppLoc.is(), "linguistic", "interfaces not supported" );
1106 43 : if (xSuppLoc.is()) {
1107 43 : uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
1108 43 : aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
1109 : }
1110 :
1111 86 : pAvailSpellSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
1112 : }
1113 43 : }
1114 77 : }
1115 : }
1116 413 : }
1117 :
1118 :
1119 77 : void LngSvcMgr::GetAvailableGrammarSvcs_Impl()
1120 : {
1121 77 : if (!pAvailGrammarSvcs)
1122 : {
1123 77 : pAvailGrammarSvcs = new SvcInfoArray;
1124 :
1125 77 : uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
1126 :
1127 154 : uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xContext->getServiceManager(), uno::UNO_QUERY );
1128 154 : uno::Reference< container::XEnumeration > xEnum;
1129 77 : if (xEnumAccess.is())
1130 77 : xEnum = xEnumAccess->createContentEnumeration( SN_GRAMMARCHECKER );
1131 :
1132 77 : if (xEnum.is())
1133 : {
1134 154 : while (xEnum->hasMoreElements())
1135 : {
1136 0 : uno::Any aCurrent = xEnum->nextElement();
1137 0 : uno::Reference< lang::XSingleComponentFactory > xCompFactory;
1138 0 : uno::Reference< lang::XSingleServiceFactory > xFactory;
1139 :
1140 0 : uno::Reference< linguistic2::XProofreader > xSvc;
1141 0 : xCompFactory.set(aCurrent, css::uno::UNO_QUERY);
1142 0 : if (!xCompFactory.is())
1143 : {
1144 0 : xFactory.set(aCurrent, css::uno::UNO_QUERY);
1145 : }
1146 0 : if ( xCompFactory.is() || xFactory.is() )
1147 : {
1148 : try
1149 : {
1150 0 : xSvc = uno::Reference< linguistic2::XProofreader >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
1151 : }
1152 0 : catch (const uno::Exception &)
1153 : {
1154 : SAL_WARN( "linguistic", "createInstance failed" );
1155 : }
1156 : }
1157 :
1158 0 : if (xSvc.is() && pAvailGrammarSvcs)
1159 : {
1160 0 : OUString aImplName;
1161 0 : uno::Sequence< sal_Int16 > aLanguages;
1162 0 : uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
1163 0 : if (xInfo.is())
1164 0 : aImplName = xInfo->getImplementationName();
1165 : SAL_WARN_IF( aImplName.isEmpty(), "linguistic", "empty implementation name" );
1166 0 : uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
1167 : SAL_WARN_IF( !xSuppLoc.is(), "linguistic", "interfaces not supported" );
1168 0 : if (xSuppLoc.is())
1169 : {
1170 0 : uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
1171 0 : aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
1172 : }
1173 :
1174 0 : pAvailGrammarSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
1175 : }
1176 0 : }
1177 77 : }
1178 : }
1179 77 : }
1180 :
1181 :
1182 125 : void LngSvcMgr::GetAvailableHyphSvcs_Impl()
1183 : {
1184 125 : if (!pAvailHyphSvcs)
1185 : {
1186 77 : pAvailHyphSvcs = new SvcInfoArray;
1187 77 : uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
1188 :
1189 154 : uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xContext->getServiceManager(), uno::UNO_QUERY );
1190 154 : uno::Reference< container::XEnumeration > xEnum;
1191 77 : if (xEnumAccess.is())
1192 77 : xEnum = xEnumAccess->createContentEnumeration( SN_HYPHENATOR );
1193 :
1194 77 : if (xEnum.is())
1195 : {
1196 197 : while (xEnum->hasMoreElements())
1197 : {
1198 43 : uno::Any aCurrent = xEnum->nextElement();
1199 86 : uno::Reference< lang::XSingleComponentFactory > xCompFactory;
1200 86 : uno::Reference< lang::XSingleServiceFactory > xFactory;
1201 :
1202 86 : uno::Reference< linguistic2::XHyphenator > xSvc;
1203 43 : xCompFactory.set(aCurrent, css::uno::UNO_QUERY);
1204 43 : if (!xCompFactory.is())
1205 : {
1206 0 : xFactory.set(aCurrent, css::uno::UNO_QUERY);
1207 : }
1208 43 : if ( xCompFactory.is() || xFactory.is() )
1209 : {
1210 : try
1211 : {
1212 43 : xSvc = uno::Reference< linguistic2::XHyphenator >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
1213 : }
1214 0 : catch (const uno::Exception &)
1215 : {
1216 : SAL_WARN( "linguistic", "createInstance failed" );
1217 : }
1218 : }
1219 43 : if (xSvc.is())
1220 : {
1221 43 : OUString aImplName;
1222 86 : uno::Sequence< sal_Int16 > aLanguages;
1223 86 : uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
1224 43 : if (xInfo.is())
1225 43 : aImplName = xInfo->getImplementationName();
1226 : SAL_WARN_IF( aImplName.isEmpty(), "linguistic", "empty implementation name" );
1227 86 : uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
1228 : SAL_WARN_IF( !xSuppLoc.is(), "linguistic", "interfaces not supported" );
1229 43 : if (xSuppLoc.is())
1230 : {
1231 43 : uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
1232 43 : aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
1233 : }
1234 86 : pAvailHyphSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
1235 : }
1236 43 : }
1237 77 : }
1238 : }
1239 125 : }
1240 :
1241 :
1242 77 : void LngSvcMgr::GetAvailableThesSvcs_Impl()
1243 : {
1244 77 : if (!pAvailThesSvcs)
1245 : {
1246 77 : pAvailThesSvcs = new SvcInfoArray;
1247 :
1248 77 : uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
1249 :
1250 154 : uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xContext->getServiceManager(), uno::UNO_QUERY );
1251 154 : uno::Reference< container::XEnumeration > xEnum;
1252 77 : if (xEnumAccess.is())
1253 77 : xEnum = xEnumAccess->createContentEnumeration( SN_THESAURUS );
1254 :
1255 77 : if (xEnum.is())
1256 : {
1257 197 : while (xEnum->hasMoreElements())
1258 : {
1259 43 : uno::Any aCurrent = xEnum->nextElement();
1260 86 : uno::Reference< lang::XSingleComponentFactory > xCompFactory;
1261 86 : uno::Reference< lang::XSingleServiceFactory > xFactory;
1262 :
1263 86 : uno::Reference< linguistic2::XThesaurus > xSvc;
1264 43 : xCompFactory.set(aCurrent, css::uno::UNO_QUERY);
1265 43 : if (!xCompFactory.is())
1266 : {
1267 0 : xFactory.set(aCurrent, css::uno::UNO_QUERY);
1268 : }
1269 43 : if ( xCompFactory.is() || xFactory.is() )
1270 : {
1271 : try
1272 : {
1273 43 : xSvc = uno::Reference< linguistic2::XThesaurus >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
1274 : }
1275 0 : catch (const uno::Exception &)
1276 : {
1277 : SAL_WARN( "linguistic", "createInstance failed" );
1278 : }
1279 : }
1280 43 : if (xSvc.is())
1281 : {
1282 43 : OUString aImplName;
1283 86 : uno::Sequence< sal_Int16 > aLanguages;
1284 86 : uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
1285 43 : if (xInfo.is())
1286 43 : aImplName = xInfo->getImplementationName();
1287 : SAL_WARN_IF( aImplName.isEmpty(), "linguistic", "empty implementation name" );
1288 86 : uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
1289 : SAL_WARN_IF( !xSuppLoc.is(), "linguistic", "interfaces not supported" );
1290 43 : if (xSuppLoc.is())
1291 : {
1292 43 : uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
1293 43 : aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
1294 : }
1295 :
1296 86 : pAvailThesSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
1297 : }
1298 43 : }
1299 77 : }
1300 : }
1301 77 : }
1302 :
1303 :
1304 13 : void LngSvcMgr::SetCfgServiceLists( SpellCheckerDispatcher &rSpellDsp )
1305 : {
1306 : SAL_INFO( "linguistic", "linguistic: LngSvcMgr::SetCfgServiceLists - Spell" );
1307 :
1308 13 : OUString aNode("ServiceManager/SpellCheckerList");
1309 26 : uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1310 13 : OUString *pNames = aNames.getArray();
1311 13 : sal_Int32 nLen = aNames.getLength();
1312 :
1313 : // append path prefix need for 'GetProperties' call below
1314 26 : OUString aPrefix( aNode );
1315 13 : aPrefix += "/";
1316 13 : for (int i = 0; i < nLen; ++i)
1317 : {
1318 0 : OUString aTmp( aPrefix );
1319 0 : aTmp += pNames[i];
1320 0 : pNames[i] = aTmp;
1321 0 : }
1322 :
1323 26 : uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1324 13 : if (nLen && nLen == aValues.getLength())
1325 : {
1326 0 : const uno::Any *pValues = aValues.getConstArray();
1327 0 : for (sal_Int32 i = 0; i < nLen; ++i)
1328 : {
1329 0 : uno::Sequence< OUString > aSvcImplNames;
1330 0 : if (pValues[i] >>= aSvcImplNames)
1331 : {
1332 0 : OUString aLocaleStr( pNames[i] );
1333 0 : sal_Int32 nSeparatorPos = aLocaleStr.lastIndexOf( '/' );
1334 0 : aLocaleStr = aLocaleStr.copy( nSeparatorPos + 1 );
1335 0 : rSpellDsp.SetServiceList( LanguageTag::convertToLocale(aLocaleStr), aSvcImplNames );
1336 : }
1337 0 : }
1338 13 : }
1339 13 : }
1340 :
1341 :
1342 0 : void LngSvcMgr::SetCfgServiceLists( GrammarCheckingIterator &rGrammarDsp )
1343 : {
1344 : SAL_INFO( "linguistic", "linguistic: LngSvcMgr::SetCfgServiceLists - Grammar" );
1345 :
1346 0 : OUString aNode("ServiceManager/GrammarCheckerList");
1347 0 : uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1348 0 : OUString *pNames = aNames.getArray();
1349 0 : sal_Int32 nLen = aNames.getLength();
1350 :
1351 : // append path prefix need for 'GetProperties' call below
1352 0 : OUString aPrefix( aNode );
1353 0 : aPrefix += "/";
1354 0 : for (int i = 0; i < nLen; ++i)
1355 : {
1356 0 : OUString aTmp( aPrefix );
1357 0 : aTmp += pNames[i];
1358 0 : pNames[i] = aTmp;
1359 0 : }
1360 :
1361 0 : uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1362 0 : if (nLen && nLen == aValues.getLength())
1363 : {
1364 0 : const uno::Any *pValues = aValues.getConstArray();
1365 0 : for (sal_Int32 i = 0; i < nLen; ++i)
1366 : {
1367 0 : uno::Sequence< OUString > aSvcImplNames;
1368 0 : if (pValues[i] >>= aSvcImplNames)
1369 : {
1370 : // there should only be one grammar checker in use per language...
1371 0 : if (aSvcImplNames.getLength() > 1)
1372 0 : aSvcImplNames.realloc(1);
1373 :
1374 0 : OUString aLocaleStr( pNames[i] );
1375 0 : sal_Int32 nSeparatorPos = aLocaleStr.lastIndexOf( '/' );
1376 0 : aLocaleStr = aLocaleStr.copy( nSeparatorPos + 1 );
1377 0 : rGrammarDsp.SetServiceList( LanguageTag::convertToLocale(aLocaleStr), aSvcImplNames );
1378 : }
1379 0 : }
1380 0 : }
1381 0 : }
1382 :
1383 :
1384 31 : void LngSvcMgr::SetCfgServiceLists( HyphenatorDispatcher &rHyphDsp )
1385 : {
1386 : SAL_INFO( "linguistic", "linguistic: LngSvcMgr::SetCfgServiceLists - Hyph" );
1387 :
1388 31 : OUString aNode("ServiceManager/HyphenatorList");
1389 62 : uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1390 31 : OUString *pNames = aNames.getArray();
1391 31 : sal_Int32 nLen = aNames.getLength();
1392 :
1393 : // append path prefix need for 'GetProperties' call below
1394 62 : OUString aPrefix( aNode );
1395 31 : aPrefix += "/";
1396 31 : for (int i = 0; i < nLen; ++i)
1397 : {
1398 0 : OUString aTmp( aPrefix );
1399 0 : aTmp += pNames[i];
1400 0 : pNames[i] = aTmp;
1401 0 : }
1402 :
1403 62 : uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1404 31 : if (nLen && nLen == aValues.getLength())
1405 : {
1406 0 : const uno::Any *pValues = aValues.getConstArray();
1407 0 : for (sal_Int32 i = 0; i < nLen; ++i)
1408 : {
1409 0 : uno::Sequence< OUString > aSvcImplNames;
1410 0 : if (pValues[i] >>= aSvcImplNames)
1411 : {
1412 : // there should only be one hyphenator in use per language...
1413 0 : if (aSvcImplNames.getLength() > 1)
1414 0 : aSvcImplNames.realloc(1);
1415 :
1416 0 : OUString aLocaleStr( pNames[i] );
1417 0 : sal_Int32 nSeparatorPos = aLocaleStr.lastIndexOf( '/' );
1418 0 : aLocaleStr = aLocaleStr.copy( nSeparatorPos + 1 );
1419 0 : rHyphDsp.SetServiceList( LanguageTag::convertToLocale(aLocaleStr), aSvcImplNames );
1420 : }
1421 0 : }
1422 31 : }
1423 31 : }
1424 :
1425 :
1426 0 : void LngSvcMgr::SetCfgServiceLists( ThesaurusDispatcher &rThesDsp )
1427 : {
1428 : SAL_INFO( "linguistic", "linguistic: LngSvcMgr::SetCfgServiceLists - Thes" );
1429 :
1430 0 : OUString aNode("ServiceManager/ThesaurusList");
1431 0 : uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
1432 0 : OUString *pNames = aNames.getArray();
1433 0 : sal_Int32 nLen = aNames.getLength();
1434 :
1435 : // append path prefix need for 'GetProperties' call below
1436 0 : OUString aPrefix( aNode );
1437 0 : aPrefix += "/";
1438 0 : for (int i = 0; i < nLen; ++i)
1439 : {
1440 0 : OUString aTmp( aPrefix );
1441 0 : aTmp += pNames[i];
1442 0 : pNames[i] = aTmp;
1443 0 : }
1444 :
1445 0 : uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
1446 0 : if (nLen && nLen == aValues.getLength())
1447 : {
1448 0 : const uno::Any *pValues = aValues.getConstArray();
1449 0 : for (sal_Int32 i = 0; i < nLen; ++i)
1450 : {
1451 0 : uno::Sequence< OUString > aSvcImplNames;
1452 0 : if (pValues[i] >>= aSvcImplNames)
1453 : {
1454 0 : OUString aLocaleStr( pNames[i] );
1455 0 : sal_Int32 nSeparatorPos = aLocaleStr.lastIndexOf( '/' );
1456 0 : aLocaleStr = aLocaleStr.copy( nSeparatorPos + 1 );
1457 0 : rThesDsp.SetServiceList( LanguageTag::convertToLocale(aLocaleStr), aSvcImplNames );
1458 : }
1459 0 : }
1460 0 : }
1461 0 : }
1462 :
1463 :
1464 : uno::Reference< linguistic2::XSpellChecker > SAL_CALL
1465 41 : LngSvcMgr::getSpellChecker()
1466 : throw(uno::RuntimeException, std::exception)
1467 : {
1468 41 : osl::MutexGuard aGuard( GetLinguMutex() );
1469 : #if OSL_DEBUG_LEVEL > 1
1470 : getAvailableLocales( SN_SPELLCHECKER );
1471 : #endif
1472 :
1473 41 : uno::Reference< linguistic2::XSpellChecker > xRes;
1474 41 : if (!bDisposing)
1475 : {
1476 41 : if (!xSpellDsp.is())
1477 13 : GetSpellCheckerDsp_Impl();
1478 41 : xRes = xSpellDsp;
1479 : }
1480 41 : return xRes;
1481 : }
1482 :
1483 :
1484 : uno::Reference< linguistic2::XHyphenator > SAL_CALL
1485 27161 : LngSvcMgr::getHyphenator()
1486 : throw(uno::RuntimeException, std::exception)
1487 : {
1488 27161 : osl::MutexGuard aGuard( GetLinguMutex() );
1489 : #if OSL_DEBUG_LEVEL > 1
1490 : getAvailableLocales( SN_HYPHENATOR );
1491 : #endif
1492 :
1493 27161 : uno::Reference< linguistic2::XHyphenator > xRes;
1494 27161 : if (!bDisposing)
1495 : {
1496 27161 : if (!xHyphDsp.is())
1497 31 : GetHyphenatorDsp_Impl();
1498 27161 : xRes = xHyphDsp;
1499 : }
1500 27161 : return xRes;
1501 : }
1502 :
1503 :
1504 : uno::Reference< linguistic2::XThesaurus > SAL_CALL
1505 0 : LngSvcMgr::getThesaurus()
1506 : throw(uno::RuntimeException, std::exception)
1507 : {
1508 0 : osl::MutexGuard aGuard( GetLinguMutex() );
1509 : #if OSL_DEBUG_LEVEL > 1
1510 : getAvailableLocales( SN_THESAURUS );
1511 : #endif
1512 :
1513 0 : uno::Reference< linguistic2::XThesaurus > xRes;
1514 0 : if (!bDisposing)
1515 : {
1516 0 : if (!xThesDsp.is())
1517 0 : GetThesaurusDsp_Impl();
1518 0 : xRes = xThesDsp;
1519 : }
1520 0 : return xRes;
1521 : }
1522 :
1523 :
1524 : sal_Bool SAL_CALL
1525 42 : LngSvcMgr::addLinguServiceManagerListener(
1526 : const uno::Reference< lang::XEventListener >& xListener )
1527 : throw(uno::RuntimeException, std::exception)
1528 : {
1529 42 : osl::MutexGuard aGuard( GetLinguMutex() );
1530 :
1531 42 : bool bRes = false;
1532 42 : if (!bDisposing && xListener.is())
1533 : {
1534 42 : if (!pListenerHelper)
1535 38 : GetListenerHelper_Impl();
1536 42 : bRes = pListenerHelper->AddLngSvcMgrListener( xListener );
1537 : }
1538 42 : return bRes;
1539 : }
1540 :
1541 :
1542 : sal_Bool SAL_CALL
1543 0 : LngSvcMgr::removeLinguServiceManagerListener(
1544 : const uno::Reference< lang::XEventListener >& xListener )
1545 : throw(uno::RuntimeException, std::exception)
1546 : {
1547 0 : osl::MutexGuard aGuard( GetLinguMutex() );
1548 :
1549 0 : bool bRes = false;
1550 0 : if (!bDisposing && xListener.is())
1551 : {
1552 : DBG_ASSERT( pListenerHelper, "listener removed without being added" );
1553 0 : if (!pListenerHelper)
1554 0 : GetListenerHelper_Impl();
1555 0 : bRes = pListenerHelper->RemoveLngSvcMgrListener( xListener );
1556 : }
1557 0 : return bRes;
1558 : }
1559 :
1560 :
1561 : uno::Sequence< OUString > SAL_CALL
1562 692 : LngSvcMgr::getAvailableServices(
1563 : const OUString& rServiceName,
1564 : const lang::Locale& rLocale )
1565 : throw(uno::RuntimeException,
1566 : std::exception)
1567 : {
1568 692 : osl::MutexGuard aGuard( GetLinguMutex() );
1569 :
1570 692 : uno::Sequence< OUString > aRes;
1571 692 : const SvcInfoArray *pInfoArray = 0;
1572 :
1573 692 : if (rServiceName == SN_SPELLCHECKER)
1574 : {
1575 413 : GetAvailableSpellSvcs_Impl();
1576 413 : pInfoArray = pAvailSpellSvcs;
1577 : }
1578 279 : else if (rServiceName == SN_GRAMMARCHECKER)
1579 : {
1580 77 : GetAvailableGrammarSvcs_Impl();
1581 77 : pInfoArray = pAvailGrammarSvcs;
1582 : }
1583 202 : else if (rServiceName == SN_HYPHENATOR)
1584 : {
1585 125 : GetAvailableHyphSvcs_Impl();
1586 125 : pInfoArray = pAvailHyphSvcs;
1587 : }
1588 77 : else if (rServiceName == SN_THESAURUS)
1589 : {
1590 77 : GetAvailableThesSvcs_Impl();
1591 77 : pInfoArray = pAvailThesSvcs;
1592 : }
1593 :
1594 692 : if (pInfoArray)
1595 : {
1596 : // resize to max number of entries
1597 692 : size_t nMaxCnt = pInfoArray->size();
1598 692 : aRes.realloc( nMaxCnt );
1599 692 : OUString *pImplName = aRes.getArray();
1600 :
1601 692 : sal_uInt16 nCnt = 0;
1602 692 : LanguageType nLanguage = LinguLocaleToLanguage( rLocale );
1603 1205 : for (size_t i = 0; i < nMaxCnt; ++i)
1604 : {
1605 513 : const SvcInfo &rInfo = (*pInfoArray)[i];
1606 1026 : if (LinguIsUnspecified( nLanguage )
1607 513 : || rInfo.HasLanguage( nLanguage ))
1608 : {
1609 513 : pImplName[ nCnt++ ] = rInfo.aSvcImplName;
1610 : }
1611 : }
1612 :
1613 : // resize to actual number of entries
1614 692 : if (nCnt != nMaxCnt)
1615 0 : aRes.realloc( nCnt );
1616 : }
1617 :
1618 692 : return aRes;
1619 : }
1620 :
1621 :
1622 : uno::Sequence< lang::Locale > SAL_CALL
1623 308 : LngSvcMgr::getAvailableLocales(
1624 : const OUString& rServiceName )
1625 : throw(uno::RuntimeException, std::exception)
1626 : {
1627 308 : osl::MutexGuard aGuard( GetLinguMutex() );
1628 :
1629 308 : uno::Sequence< lang::Locale > aRes;
1630 :
1631 308 : uno::Sequence< lang::Locale > *pAvailLocales = NULL;
1632 308 : if (rServiceName == SN_SPELLCHECKER)
1633 77 : pAvailLocales = &aAvailSpellLocales;
1634 231 : else if (rServiceName == SN_GRAMMARCHECKER)
1635 77 : pAvailLocales = &aAvailGrammarLocales;
1636 154 : else if (rServiceName == SN_HYPHENATOR)
1637 77 : pAvailLocales = &aAvailHyphLocales;
1638 77 : else if (rServiceName == SN_THESAURUS)
1639 77 : pAvailLocales = &aAvailThesLocales;
1640 :
1641 : // Nowadays (with OOo lingu in SO) we want to know immediately about
1642 : // new downloaded dictionaries and have them ready right away if the Tools/Options...
1643 : // is used to activate them. Thus we can not rely anymore on buffered data.
1644 308 : if (pAvailLocales)
1645 : {
1646 308 : *pAvailLocales = GetAvailLocales(getAvailableServices(rServiceName, lang::Locale()));
1647 308 : aRes = *pAvailLocales;
1648 : }
1649 :
1650 308 : return aRes;
1651 : }
1652 :
1653 0 : static bool IsEqSvcList( const uno::Sequence< OUString > &rList1,
1654 : const uno::Sequence< OUString > &rList2 )
1655 : {
1656 : // returns sal_True iff both sequences are equal
1657 :
1658 0 : bool bRes = false;
1659 0 : sal_Int32 nLen = rList1.getLength();
1660 0 : if (rList2.getLength() == nLen)
1661 : {
1662 0 : const OUString *pStr1 = rList1.getConstArray();
1663 0 : const OUString *pStr2 = rList2.getConstArray();
1664 0 : bRes = true;
1665 0 : for (sal_Int32 i = 0; i < nLen && bRes; ++i)
1666 : {
1667 0 : if (*pStr1++ != *pStr2++)
1668 0 : bRes = false;
1669 : }
1670 : }
1671 0 : return bRes;
1672 : }
1673 :
1674 :
1675 : void SAL_CALL
1676 0 : LngSvcMgr::setConfiguredServices(
1677 : const OUString& rServiceName,
1678 : const lang::Locale& rLocale,
1679 : const uno::Sequence< OUString >& rServiceImplNames )
1680 : throw(uno::RuntimeException, std::exception)
1681 : {
1682 : SAL_INFO( "linguistic", "linguistic: LngSvcMgr::setConfiguredServices" );
1683 :
1684 0 : osl::MutexGuard aGuard( GetLinguMutex() );
1685 :
1686 : #if OSL_DEBUG_LEVEL > 1
1687 : #endif
1688 :
1689 0 : LanguageType nLanguage = LinguLocaleToLanguage( rLocale );
1690 0 : if (!LinguIsUnspecified( nLanguage))
1691 : {
1692 0 : if (rServiceName == SN_SPELLCHECKER)
1693 : {
1694 0 : if (!xSpellDsp.is())
1695 0 : GetSpellCheckerDsp_Impl();
1696 : bool bChanged = !IsEqSvcList( rServiceImplNames,
1697 0 : pSpellDsp->GetServiceList( rLocale ) );
1698 0 : if (bChanged)
1699 : {
1700 0 : pSpellDsp->SetServiceList( rLocale, rServiceImplNames );
1701 0 : SaveCfgSvcs( OUString(SN_SPELLCHECKER) );
1702 :
1703 0 : if (pListenerHelper && bChanged)
1704 : pListenerHelper->AddLngSvcEvt(
1705 : linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN |
1706 0 : linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN );
1707 : }
1708 : }
1709 0 : else if (rServiceName == SN_GRAMMARCHECKER)
1710 : {
1711 0 : if (!xGrammarDsp.is())
1712 0 : GetGrammarCheckerDsp_Impl();
1713 : bool bChanged = !IsEqSvcList( rServiceImplNames,
1714 0 : pGrammarDsp->GetServiceList( rLocale ) );
1715 0 : if (bChanged)
1716 : {
1717 0 : pGrammarDsp->SetServiceList( rLocale, rServiceImplNames );
1718 0 : SaveCfgSvcs( OUString(SN_GRAMMARCHECKER) );
1719 :
1720 0 : if (pListenerHelper && bChanged)
1721 : pListenerHelper->AddLngSvcEvt(
1722 0 : linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN );
1723 : }
1724 : }
1725 0 : else if (rServiceName == SN_HYPHENATOR)
1726 : {
1727 0 : if (!xHyphDsp.is())
1728 0 : GetHyphenatorDsp_Impl();
1729 : bool bChanged = !IsEqSvcList( rServiceImplNames,
1730 0 : pHyphDsp->GetServiceList( rLocale ) );
1731 0 : if (bChanged)
1732 : {
1733 0 : pHyphDsp->SetServiceList( rLocale, rServiceImplNames );
1734 0 : SaveCfgSvcs( OUString(SN_HYPHENATOR) );
1735 :
1736 0 : if (pListenerHelper && bChanged)
1737 : pListenerHelper->AddLngSvcEvt(
1738 0 : linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN );
1739 : }
1740 : }
1741 0 : else if (rServiceName == SN_THESAURUS)
1742 : {
1743 0 : if (!xThesDsp.is())
1744 0 : GetThesaurusDsp_Impl();
1745 : bool bChanged = !IsEqSvcList( rServiceImplNames,
1746 0 : pThesDsp->GetServiceList( rLocale ) );
1747 0 : if (bChanged)
1748 : {
1749 0 : pThesDsp->SetServiceList( rLocale, rServiceImplNames );
1750 0 : SaveCfgSvcs( OUString(SN_THESAURUS) );
1751 : }
1752 : }
1753 0 : }
1754 0 : }
1755 :
1756 :
1757 0 : bool LngSvcMgr::SaveCfgSvcs( const OUString &rServiceName )
1758 : {
1759 : SAL_INFO( "linguistic", "linguistic: LngSvcMgr::SaveCfgSvcs" );
1760 :
1761 0 : bool bRes = false;
1762 :
1763 0 : LinguDispatcher *pDsp = 0;
1764 0 : uno::Sequence< lang::Locale > aLocales;
1765 :
1766 0 : if (rServiceName == SN_SPELLCHECKER)
1767 : {
1768 0 : if (!pSpellDsp)
1769 0 : GetSpellCheckerDsp_Impl();
1770 0 : pDsp = pSpellDsp;
1771 0 : aLocales = getAvailableLocales( SN_SPELLCHECKER );
1772 : }
1773 0 : else if (rServiceName == SN_GRAMMARCHECKER)
1774 : {
1775 0 : if (!pGrammarDsp)
1776 0 : GetGrammarCheckerDsp_Impl();
1777 0 : pDsp = pGrammarDsp;
1778 0 : aLocales = getAvailableLocales( SN_GRAMMARCHECKER );
1779 : }
1780 0 : else if (rServiceName == SN_HYPHENATOR)
1781 : {
1782 0 : if (!pHyphDsp)
1783 0 : GetHyphenatorDsp_Impl();
1784 0 : pDsp = pHyphDsp;
1785 0 : aLocales = getAvailableLocales( SN_HYPHENATOR );
1786 : }
1787 0 : else if (rServiceName == SN_THESAURUS)
1788 : {
1789 0 : if (!pThesDsp)
1790 0 : GetThesaurusDsp_Impl();
1791 0 : pDsp = pThesDsp;
1792 0 : aLocales = getAvailableLocales( SN_THESAURUS );
1793 : }
1794 :
1795 0 : if (pDsp && aLocales.getLength())
1796 : {
1797 0 : sal_Int32 nLen = aLocales.getLength();
1798 0 : const lang::Locale *pLocale = aLocales.getConstArray();
1799 :
1800 0 : uno::Sequence< beans::PropertyValue > aValues( nLen );
1801 0 : beans::PropertyValue *pValues = aValues.getArray();
1802 0 : beans::PropertyValue *pValue = pValues;
1803 :
1804 : // get node name to be used
1805 0 : const char *pNodeName = NULL;
1806 0 : if (pDsp == pSpellDsp)
1807 0 : pNodeName = "ServiceManager/SpellCheckerList";
1808 0 : else if (pDsp == pGrammarDsp)
1809 0 : pNodeName = "ServiceManager/GrammarCheckerList";
1810 0 : else if (pDsp == pHyphDsp)
1811 0 : pNodeName = "ServiceManager/HyphenatorList";
1812 0 : else if (pDsp == pThesDsp)
1813 0 : pNodeName = "ServiceManager/ThesaurusList";
1814 : else
1815 : {
1816 : SAL_WARN( "linguistic", "node name missing" );
1817 : }
1818 0 : OUString aNodeName( OUString::createFromAscii(pNodeName) );
1819 :
1820 0 : for (sal_Int32 i = 0; i < nLen; ++i)
1821 : {
1822 0 : uno::Sequence< OUString > aSvcImplNames;
1823 0 : aSvcImplNames = pDsp->GetServiceList( pLocale[i] );
1824 :
1825 : // build value to be written back to configuration
1826 0 : uno::Any aCfgAny;
1827 0 : if ((pDsp == pHyphDsp || pDsp == pGrammarDsp) && aSvcImplNames.getLength() > 1)
1828 0 : aSvcImplNames.realloc(1); // there should be only one entry for hyphenators or grammar checkers (because they are not chained)
1829 0 : aCfgAny <<= aSvcImplNames;
1830 : DBG_ASSERT( aCfgAny.hasValue(), "missing value for 'Any' type" );
1831 :
1832 0 : OUString aCfgLocaleStr( (LanguageTag(pLocale[i])).getBcp47() );
1833 0 : pValue->Value = aCfgAny;
1834 0 : pValue->Name = aNodeName;
1835 0 : pValue->Name += OUString( (sal_Unicode) '/' );
1836 0 : pValue->Name += aCfgLocaleStr;
1837 0 : pValue++;
1838 0 : }
1839 : {
1840 : SAL_INFO( "linguistic", "linguistic: LngSvcMgr::SaveCfgSvcs - ReplaceSetProperties" );
1841 : // change, add new or replace existing entries.
1842 0 : bRes |= /*aCfg.*/ReplaceSetProperties( aNodeName, aValues );
1843 0 : }
1844 : }
1845 :
1846 0 : return bRes;
1847 : }
1848 :
1849 :
1850 336 : static uno::Sequence< OUString > GetLangSvcList( const uno::Any &rVal )
1851 : {
1852 336 : uno::Sequence< OUString > aRes;
1853 :
1854 336 : if (rVal.hasValue())
1855 : {
1856 336 : rVal >>= aRes;
1857 : #if OSL_DEBUG_LEVEL > 1
1858 : sal_Int32 nSvcs = aRes.getLength();
1859 : if (nSvcs)
1860 : {
1861 : const OUString *pSvcName = aRes.getConstArray();
1862 : for (sal_Int32 j = 0; j < nSvcs; ++j)
1863 : {
1864 : OUString aImplName( pSvcName[j] );
1865 : SAL_WARN_IF( aImplName.isEmpty(), "linguistic", "service impl-name missing" );
1866 : }
1867 : }
1868 : #endif
1869 : }
1870 :
1871 336 : return aRes;
1872 : }
1873 :
1874 :
1875 48 : static uno::Sequence< OUString > GetLangSvc( const uno::Any &rVal )
1876 : {
1877 48 : uno::Sequence< OUString > aRes;
1878 48 : if (!rVal.hasValue())
1879 0 : return aRes;
1880 :
1881 : // allowing for a sequence here as well (even though it should only
1882 : // be a string) makes coding easier in other places since one needs
1883 : // not make a special case for writing a string only and not a
1884 : // sequence of strings.
1885 48 : if (rVal >>= aRes)
1886 : {
1887 : // but only the first string should be used.
1888 48 : if (aRes.getLength() > 1)
1889 0 : aRes.realloc(1);
1890 : }
1891 : else
1892 : {
1893 0 : OUString aImplName;
1894 0 : if ((rVal >>= aImplName) && !aImplName.isEmpty())
1895 : {
1896 0 : aRes.realloc(1);
1897 0 : aRes.getArray()[0] = aImplName;
1898 : }
1899 : else
1900 : {
1901 : SAL_WARN( "linguistic", "GetLangSvc: unexpected type encountered" );
1902 0 : }
1903 : }
1904 :
1905 48 : return aRes;
1906 : }
1907 :
1908 :
1909 :
1910 : uno::Sequence< OUString > SAL_CALL
1911 40 : LngSvcMgr::getConfiguredServices(
1912 : const OUString& rServiceName,
1913 : const lang::Locale& rLocale )
1914 : throw(uno::RuntimeException, std::exception)
1915 : {
1916 40 : osl::MutexGuard aGuard( GetLinguMutex() );
1917 :
1918 40 : uno::Sequence< OUString > aSvcImplNames;
1919 :
1920 80 : OUString aCfgLocale( LanguageTag::convertToBcp47( rLocale) );
1921 :
1922 80 : uno::Sequence< uno::Any > aValues;
1923 80 : uno::Sequence< OUString > aNames( 1 );
1924 40 : OUString *pNames = aNames.getArray();
1925 40 : if ( rServiceName == SN_SPELLCHECKER )
1926 : {
1927 35 : OUString aNode( "ServiceManager/SpellCheckerList");
1928 70 : const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1929 35 : if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1930 : {
1931 35 : OUString aPropName( aNode );
1932 35 : aPropName += OUString( (sal_Unicode) '/' );
1933 35 : aPropName += aCfgLocale;
1934 35 : pNames[0] = aPropName;
1935 35 : aValues = /*aCfg.*/GetProperties( aNames );
1936 35 : if (aValues.getLength())
1937 35 : aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
1938 35 : }
1939 : }
1940 5 : else if ( rServiceName == SN_GRAMMARCHECKER )
1941 : {
1942 0 : OUString aNode( "ServiceManager/GrammarCheckerList");
1943 0 : const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1944 0 : if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1945 : {
1946 0 : OUString aPropName( aNode );
1947 0 : aPropName += OUString( (sal_Unicode) '/' );
1948 0 : aPropName += aCfgLocale;
1949 0 : pNames[0] = aPropName;
1950 0 : aValues = /*aCfg.*/GetProperties( aNames );
1951 0 : if (aValues.getLength())
1952 0 : aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
1953 0 : }
1954 : }
1955 5 : else if ( rServiceName == SN_HYPHENATOR )
1956 : {
1957 5 : OUString aNode( "ServiceManager/HyphenatorList");
1958 10 : const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1959 5 : if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1960 : {
1961 5 : OUString aPropName( aNode );
1962 5 : aPropName += OUString( (sal_Unicode) '/' );
1963 5 : aPropName += aCfgLocale;
1964 5 : pNames[0] = aPropName;
1965 5 : aValues = /*aCfg.*/GetProperties( aNames );
1966 5 : if (aValues.getLength())
1967 5 : aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
1968 5 : }
1969 : }
1970 0 : else if ( rServiceName == SN_THESAURUS )
1971 : {
1972 0 : OUString aNode( "ServiceManager/ThesaurusList");
1973 0 : const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
1974 0 : if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
1975 : {
1976 0 : OUString aPropName( aNode );
1977 0 : aPropName += OUString( (sal_Unicode) '/' );
1978 0 : aPropName += aCfgLocale;
1979 0 : pNames[0] = aPropName;
1980 0 : aValues = /*aCfg.*/GetProperties( aNames );
1981 0 : if (aValues.getLength())
1982 0 : aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
1983 0 : }
1984 : }
1985 :
1986 : #if OSL_DEBUG_LEVEL > 1
1987 : const OUString *pImplNames = aSvcImplNames.getConstArray();
1988 : (void) pImplNames;
1989 : #endif
1990 80 : return aSvcImplNames;
1991 : }
1992 :
1993 :
1994 : void SAL_CALL
1995 78 : LngSvcMgr::dispose()
1996 : throw(uno::RuntimeException, std::exception)
1997 : {
1998 78 : osl::MutexGuard aGuard( GetLinguMutex() );
1999 :
2000 78 : if (!bDisposing)
2001 : {
2002 77 : bDisposing = true;
2003 :
2004 : // require listeners to release this object
2005 77 : lang::EventObject aEvtObj( static_cast<XLinguServiceManager*>(this) );
2006 77 : aEvtListeners.disposeAndClear( aEvtObj );
2007 :
2008 77 : if (pListenerHelper)
2009 53 : pListenerHelper->DisposeAndClear( aEvtObj );
2010 78 : }
2011 78 : }
2012 :
2013 :
2014 : void SAL_CALL
2015 0 : LngSvcMgr::addEventListener(
2016 : const uno::Reference< lang::XEventListener >& xListener )
2017 : throw(uno::RuntimeException, std::exception)
2018 : {
2019 0 : osl::MutexGuard aGuard( GetLinguMutex() );
2020 :
2021 0 : if (!bDisposing && xListener.is())
2022 : {
2023 0 : aEvtListeners.addInterface( xListener );
2024 0 : }
2025 0 : }
2026 :
2027 :
2028 : void SAL_CALL
2029 0 : LngSvcMgr::removeEventListener(
2030 : const uno::Reference< lang::XEventListener >& xListener )
2031 : throw(uno::RuntimeException, std::exception)
2032 : {
2033 0 : osl::MutexGuard aGuard( GetLinguMutex() );
2034 :
2035 0 : if (xListener.is())
2036 : {
2037 0 : aEvtListeners.removeInterface( xListener );
2038 0 : }
2039 0 : }
2040 :
2041 :
2042 32 : bool LngSvcMgr::AddLngSvcEvtBroadcaster(
2043 : const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
2044 : {
2045 32 : bool bRes = false;
2046 32 : if (rxBroadcaster.is())
2047 : {
2048 32 : if (!pListenerHelper)
2049 15 : GetListenerHelper_Impl();
2050 32 : bRes = pListenerHelper->AddLngSvcEvtBroadcaster( rxBroadcaster );
2051 : }
2052 32 : return bRes;
2053 : }
2054 :
2055 :
2056 : OUString SAL_CALL
2057 1 : LngSvcMgr::getImplementationName()
2058 : throw(uno::RuntimeException, std::exception)
2059 : {
2060 1 : osl::MutexGuard aGuard( GetLinguMutex() );
2061 1 : return getImplementationName_Static();
2062 : }
2063 :
2064 :
2065 : sal_Bool SAL_CALL
2066 0 : LngSvcMgr::supportsService( const OUString& ServiceName )
2067 : throw(uno::RuntimeException, std::exception)
2068 : {
2069 0 : return cppu::supportsService(this, ServiceName);
2070 : }
2071 :
2072 :
2073 : uno::Sequence< OUString > SAL_CALL
2074 1 : LngSvcMgr::getSupportedServiceNames()
2075 : throw(uno::RuntimeException, std::exception)
2076 : {
2077 1 : osl::MutexGuard aGuard( GetLinguMutex() );
2078 1 : return getSupportedServiceNames_Static();
2079 : }
2080 :
2081 :
2082 78 : uno::Sequence< OUString > LngSvcMgr::getSupportedServiceNames_Static()
2083 : throw()
2084 : {
2085 78 : osl::MutexGuard aGuard( GetLinguMutex() );
2086 :
2087 78 : uno::Sequence< OUString > aSNS( 1 ); // more than 1 service possible
2088 78 : aSNS.getArray()[0] = "com.sun.star.linguistic2.LinguServiceManager";
2089 78 : return aSNS;
2090 : }
2091 :
2092 :
2093 77 : uno::Reference< uno::XInterface > SAL_CALL LngSvcMgr_CreateInstance(
2094 : const uno::Reference< lang::XMultiServiceFactory > & /*rSMgr*/ )
2095 : throw(uno::Exception)
2096 : {
2097 77 : uno::Reference< uno::XInterface > xService = static_cast<cppu::OWeakObject*>(new LngSvcMgr);
2098 77 : return xService;
2099 : }
2100 :
2101 190 : void * SAL_CALL LngSvcMgr_getFactory(
2102 : const sal_Char * pImplName,
2103 : lang::XMultiServiceFactory * pServiceManager,
2104 : void * /*pRegistryKey*/ )
2105 : {
2106 :
2107 190 : void * pRet = 0;
2108 190 : if ( LngSvcMgr::getImplementationName_Static().equalsAscii( pImplName ) )
2109 : {
2110 : uno::Reference< lang::XSingleServiceFactory > xFactory =
2111 : cppu::createOneInstanceFactory(
2112 : pServiceManager,
2113 : LngSvcMgr::getImplementationName_Static(),
2114 : LngSvcMgr_CreateInstance,
2115 77 : LngSvcMgr::getSupportedServiceNames_Static());
2116 : // acquire, because we return an interface pointer instead of a reference
2117 77 : xFactory->acquire();
2118 77 : pRet = xFactory.get();
2119 : }
2120 190 : return pRet;
2121 : }
2122 :
2123 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|