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