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