xref: /AOO41X/main/linguistic/source/hyphdsp.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_linguistic.hxx"
30 
31 
32 #include <cppuhelper/factory.hxx>	// helper for factories
33 #include <com/sun/star/registry/XRegistryKey.hpp>
34 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
35 #include <com/sun/star/linguistic2/XHyphenatedWord.hpp>
36 #include <rtl/ustrbuf.hxx>
37 #include <i18npool/lang.h>
38 #include <unotools/localedatawrapper.hxx>
39 #include <tools/debug.hxx>
40 #include <svl/lngmisc.hxx>
41 #include <unotools/processfactory.hxx>
42 #include <osl/mutex.hxx>
43 
44 #include "hyphdsp.hxx"
45 #include "linguistic/hyphdta.hxx"
46 #include "linguistic/lngprops.hxx"
47 #include "lngsvcmgr.hxx"
48 
49 
50 using namespace utl;
51 using namespace osl;
52 using namespace rtl;
53 using namespace com::sun::star;
54 using namespace com::sun::star::beans;
55 using namespace com::sun::star::lang;
56 using namespace com::sun::star::uno;
57 using namespace com::sun::star::linguistic2;
58 using namespace linguistic;
59 
60 ///////////////////////////////////////////////////////////////////////////
61 
62 HyphenatorDispatcher::HyphenatorDispatcher( LngSvcMgr &rLngSvcMgr ) :
63 	rMgr	(rLngSvcMgr)
64 {
65 }
66 
67 
68 HyphenatorDispatcher::~HyphenatorDispatcher()
69 {
70 	ClearSvcList();
71 }
72 
73 
74 void HyphenatorDispatcher::ClearSvcList()
75 {
76 	// release memory for each table entry
77     HyphSvcByLangMap_t aTmp;
78     aSvcMap.swap( aTmp );
79 }
80 
81 
82 Reference<XHyphenatedWord>	HyphenatorDispatcher::buildHyphWord(
83             const OUString rOrigWord,
84 			const Reference<XDictionaryEntry> &xEntry,
85 			sal_Int16 nLang, sal_Int16 nMaxLeading )
86 {
87 	MutexGuard	aGuard( GetLinguMutex() );
88 
89 	Reference< XHyphenatedWord > xRes;
90 
91 	if (xEntry.is())
92 	{
93 		OUString aText( xEntry->getDictionaryWord() );
94 		sal_Int32 nTextLen = aText.getLength();
95 
96 		// trailing '=' means "hyphenation should not be possible"
97 		if (nTextLen > 0  &&  aText[ nTextLen - 1 ] != '=')
98 		{
99 			sal_Int16 nHyphenationPos = -1;
100 
101 			OUStringBuffer aTmp( nTextLen );
102 			sal_Bool  bSkip = sal_False;
103 			sal_Int32 nHyphIdx = -1;
104 			sal_Int32 nLeading = 0;
105 			for (sal_Int32 i = 0;  i < nTextLen;  i++)
106 			{
107 				sal_Unicode cTmp = aText[i];
108 				if (cTmp != '=')
109 				{
110 					aTmp.append( cTmp );
111 					nLeading++;
112 					bSkip = sal_False;
113 					nHyphIdx++;
114 				}
115 				else
116 				{
117 					if (!bSkip  &&  nHyphIdx >= 0)
118 					{
119 						if (nLeading <= nMaxLeading)
120                             nHyphenationPos = (sal_Int16) nHyphIdx;
121 					}
122 					bSkip = sal_True;	//! multiple '=' should count as one only
123 				}
124 			}
125 
126 			if (nHyphenationPos > 0)
127 			{
128 				aText = aTmp.makeStringAndClear();
129 
130 #if OSL_DEBUG_LEVEL > 1
131                 {
132                     if (aText != rOrigWord)
133                     {
134                         // both words should only differ by a having a trailing '.'
135                         // character or not...
136                         OUString aShorter, aLonger;
137                         if (aText.getLength() <= rOrigWord.getLength())
138                         {
139                             aShorter = aText;
140                             aLonger  = rOrigWord;
141                         }
142                         else
143                         {
144                             aShorter = rOrigWord;
145                             aLonger  = aText;
146                         }
147                         xub_StrLen nS = sal::static_int_cast< xub_StrLen >( aShorter.getLength() );
148                         xub_StrLen nL = sal::static_int_cast< xub_StrLen >( aLonger.getLength() );
149                         if (nS > 0 && nL > 0)
150                         {
151                             DBG_ASSERT( (nS + 1 == nL) && aLonger[nL-1] == (sal_Unicode) '.',
152                                 "HyphenatorDispatcher::buildHyphWord: unexpected difference between words!" );
153                         }
154                     }
155                 }
156 #endif
157                 //! take care of #i22591#
158                 aText = rOrigWord;
159 
160                 DBG_ASSERT( aText == rOrigWord, "failed to " );
161                 xRes = new HyphenatedWord( aText, nLang, nHyphenationPos,
162 								aText, nHyphenationPos );
163 			}
164 		}
165 	}
166 
167 	return xRes;
168 }
169 
170 
171 Reference< XPossibleHyphens > HyphenatorDispatcher::buildPossHyphens(
172 			const Reference< XDictionaryEntry > &xEntry, sal_Int16 nLanguage )
173 {
174 	MutexGuard	aGuard( GetLinguMutex() );
175 
176 	Reference<XPossibleHyphens> xRes;
177 
178 	if (xEntry.is())
179 	{
180 		// text with hyphenation info
181 		OUString aText( xEntry->getDictionaryWord() );
182 		sal_Int32 nTextLen = aText.getLength();
183 
184 		// trailing '=' means "hyphenation should not be possible"
185 		if (nTextLen > 0  &&  aText[ nTextLen - 1 ] != '=')
186 		{
187 			// sequence to hold hyphenation positions
188 			Sequence< sal_Int16 > aHyphPos( nTextLen );
189 			sal_Int16 *pPos = aHyphPos.getArray();
190 			sal_Int32 nHyphCount = 0;
191 
192 			OUStringBuffer aTmp( nTextLen );
193 			sal_Bool  bSkip = sal_False;
194 			sal_Int32 nHyphIdx = -1;
195 			for (sal_Int32 i = 0;  i < nTextLen;  i++)
196 			{
197 				sal_Unicode cTmp = aText[i];
198 				if (cTmp != '=')
199 				{
200 					aTmp.append( cTmp );
201 					bSkip = sal_False;
202 					nHyphIdx++;
203 				}
204 				else
205 				{
206 					if (!bSkip  &&  nHyphIdx >= 0)
207                         pPos[ nHyphCount++ ] = (sal_Int16) nHyphIdx;
208 					bSkip = sal_True;	//! multiple '=' should count as one only
209 				}
210 			}
211 
212 			// ignore (multiple) trailing '='
213 			if (bSkip  &&  nHyphIdx >= 0)
214 			{
215 				nHyphCount--;
216 			}
217 			DBG_ASSERT( nHyphCount >= 0, "lng : invalid hyphenation count");
218 
219 			if (nHyphCount > 0)
220 			{
221 				aHyphPos.realloc( nHyphCount );
222 				xRes = new PossibleHyphens( aTmp.makeStringAndClear(), nLanguage,
223 								aText, aHyphPos );
224 			}
225 		}
226 	}
227 
228 	return xRes;
229 }
230 
231 
232 Sequence< Locale > SAL_CALL HyphenatorDispatcher::getLocales()
233 		throw(RuntimeException)
234 {
235 	MutexGuard	aGuard( GetLinguMutex() );
236 
237     Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) );
238     Locale *pLocales = aLocales.getArray();
239     HyphSvcByLangMap_t::const_iterator aIt;
240     for (aIt = aSvcMap.begin();  aIt != aSvcMap.end();  ++aIt)
241     {
242         *pLocales++ = CreateLocale( aIt->first );
243     }
244 	return aLocales;
245 }
246 
247 
248 sal_Bool SAL_CALL HyphenatorDispatcher::hasLocale(const Locale& rLocale)
249 		throw(RuntimeException)
250 {
251 	MutexGuard	aGuard( GetLinguMutex() );
252     HyphSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LocaleToLanguage( rLocale ) ) );
253     return aIt != aSvcMap.end();
254 }
255 
256 
257 Reference< XHyphenatedWord > SAL_CALL
258 	HyphenatorDispatcher::hyphenate(
259 			const OUString& rWord, const Locale& rLocale, sal_Int16 nMaxLeading,
260 			const PropertyValues& rProperties )
261 		throw(IllegalArgumentException, RuntimeException)
262 {
263     MutexGuard	aGuard( GetLinguMutex() );
264 
265 	Reference< XHyphenatedWord >	xRes;
266 
267     sal_Int32 nWordLen = rWord.getLength();
268 	sal_Int16 nLanguage = LocaleToLanguage( rLocale );
269     if (nLanguage == LANGUAGE_NONE  || !nWordLen ||
270         nMaxLeading == 0 || nMaxLeading == nWordLen)
271 		return xRes;
272 
273 	// search for entry with that language
274     HyphSvcByLangMap_t::iterator    aIt( aSvcMap.find( nLanguage ) );
275     LangSvcEntries_Hyph     *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
276 
277 	sal_Bool bWordModified = sal_False;
278     if (!pEntry || (nMaxLeading < 0 || nMaxLeading > nWordLen))
279 	{
280 #ifdef LINGU_EXCEPTIONS
281 		throw IllegalArgumentException();
282 #else
283         return NULL;
284 #endif
285 	}
286 	else
287 	{
288 		OUString aChkWord( rWord );
289 
290         // replace typographical apostroph by ascii apostroph
291         String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
292         DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
293         if (aSingleQuote.Len())
294             aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
295 
296 		bWordModified |= RemoveHyphens( aChkWord );
297 		if (IsIgnoreControlChars( rProperties, GetPropSet() ))
298 			bWordModified |= RemoveControlChars( aChkWord );
299         sal_Int16 nChkMaxLeading = (sal_Int16) GetPosInWordToCheck( rWord, nMaxLeading );
300 
301 		// check for results from (positive) dictionaries which have precedence!
302 		Reference< XDictionaryEntry > xEntry;
303 
304 		if (GetDicList().is()  &&  IsUseDicList( rProperties, GetPropSet() ))
305 		{
306 			xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
307 						sal_True, sal_False );
308 		}
309 
310 		if (xEntry.is())
311 		{
312             //! because queryDictionaryEntry (in the end DictionaryNeo::getEntry)
313             //! does not distinguish betwee "XYZ" and "XYZ." in order to avoid
314             //! to require them as different entry we have to supply the
315             //! original word here as well so it can be used in th result
316             //! otherwise a strange effect may occur (see #i22591#)
317             xRes = buildHyphWord( rWord, xEntry, nLanguage, nChkMaxLeading );
318 		}
319 		else
320 		{
321             sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
322             DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
323 					"lng : index out of range");
324 
325 			sal_Int32 i = 0;
326             Reference< XHyphenator > xHyph;
327             if (pEntry->aSvcRefs.getLength() > 0)
328                 xHyph = pEntry->aSvcRefs[0];
329 
330 			// try already instantiated service
331             if (i <= pEntry->nLastTriedSvcIndex)
332 			{
333                 if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
334                     xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading,
335 											rProperties );
336 				++i;
337 			}
338             else if (pEntry->nLastTriedSvcIndex < nLen - 1)
339 			// instantiate services and try it
340 			{
341 //                const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
342                 Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
343 
344 				Reference< XMultiServiceFactory >  xMgr( getProcessServiceFactory() );
345 				if (xMgr.is())
346 				{
347 					// build service initialization argument
348 					Sequence< Any > aArgs(2);
349 					aArgs.getArray()[0] <<= GetPropSet();
350 					//! The dispatcher searches the dictionary-list
351 					//! thus the service needs not to now about it
352 					//aArgs.getArray()[1] <<= GetDicList();
353 
354 					// create specific service via it's implementation name
355 					try
356 					{
357 						xHyph = Reference< XHyphenator >(
358 								xMgr->createInstanceWithArguments(
359                                 pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
360 					}
361 					catch (uno::Exception &)
362 					{
363                         DBG_ASSERT( 0, "createInstanceWithArguments failed" );
364 					}
365                     pRef [i] = xHyph;
366 
367 					Reference< XLinguServiceEventBroadcaster >
368 							xBroadcaster( xHyph, UNO_QUERY );
369 					if (xBroadcaster.is())
370 						rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
371 
372                     if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
373                         xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading,
374 												rProperties );
375 
376                     pEntry->nLastTriedSvcIndex = (sal_Int16) i;
377 					++i;
378 
379                     // if language is not supported by the services
380                     // remove it from the list.
381                     if (xHyph.is()  &&  !xHyph->hasLocale( rLocale ))
382                         aSvcMap.erase( nLanguage );
383                 }
384 			}
385 		}	// if (xEntry.is())
386 	}
387 
388 	if (bWordModified  &&  xRes.is())
389 		xRes = RebuildHyphensAndControlChars( rWord, xRes );
390 
391     if (xRes.is()  &&  xRes->getWord() != rWord)
392     {
393         xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(),
394                                    xRes->getHyphenatedWord(),
395                                    xRes->getHyphenPos() );
396     }
397 
398 	return xRes;
399 }
400 
401 
402 Reference< XHyphenatedWord > SAL_CALL
403 	HyphenatorDispatcher::queryAlternativeSpelling(
404 			const OUString& rWord, const Locale& rLocale, sal_Int16 nIndex,
405 			const PropertyValues& rProperties )
406 		throw(IllegalArgumentException, RuntimeException)
407 {
408 	MutexGuard	aGuard( GetLinguMutex() );
409 
410 	Reference< XHyphenatedWord >	xRes;
411 
412     sal_Int32 nWordLen = rWord.getLength();
413 	sal_Int16 nLanguage = LocaleToLanguage( rLocale );
414     if (nLanguage == LANGUAGE_NONE  || !nWordLen)
415 		return xRes;
416 
417 	// search for entry with that language
418     HyphSvcByLangMap_t::iterator    aIt( aSvcMap.find( nLanguage ) );
419     LangSvcEntries_Hyph     *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
420 
421 	sal_Bool bWordModified = sal_False;
422     if (!pEntry || !(0 <= nIndex && nIndex <= nWordLen - 2))
423 	{
424 #ifdef LINGU_EXCEPTIONS
425 		throw IllegalArgumentException();
426 #else
427         return NULL;
428 #endif
429 	}
430 	else
431 	{
432         OUString aChkWord( rWord );
433 
434         // replace typographical apostroph by ascii apostroph
435         String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
436         DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
437         if (aSingleQuote.Len())
438             aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
439 
440 		bWordModified |= RemoveHyphens( aChkWord );
441 		if (IsIgnoreControlChars( rProperties, GetPropSet() ))
442 			bWordModified |= RemoveControlChars( aChkWord );
443         sal_Int16 nChkIndex = (sal_Int16) GetPosInWordToCheck( rWord, nIndex );
444 
445 		// check for results from (positive) dictionaries which have precedence!
446 		Reference< XDictionaryEntry > xEntry;
447 
448 		if (GetDicList().is()  &&  IsUseDicList( rProperties, GetPropSet() ))
449 		{
450 			xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
451 						sal_True, sal_False );
452 		}
453 
454 		if (xEntry.is())
455 		{
456 			//! alternative spellings not yet supported by dictionaries
457 		}
458 		else
459 		{
460             sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
461             DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
462 					"lng : index out of range");
463 
464 			sal_Int32 i = 0;
465             Reference< XHyphenator > xHyph;
466             if (pEntry->aSvcRefs.getLength() > 0)
467                 xHyph = pEntry->aSvcRefs[0];
468 
469 			// try already instantiated service
470             if (i <= pEntry->nLastTriedSvcIndex)
471 			{
472                 if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
473                     xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale,
474 								nChkIndex, rProperties );
475 				++i;
476 			}
477             else if (pEntry->nLastTriedSvcIndex < nLen - 1)
478 			// instantiate services and try it
479 			{
480 //                const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
481                 Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
482 
483 				Reference< XMultiServiceFactory >  xMgr( getProcessServiceFactory() );
484 				if (xMgr.is())
485 				{
486 					// build service initialization argument
487 					Sequence< Any > aArgs(2);
488 					aArgs.getArray()[0] <<= GetPropSet();
489 					//! The dispatcher searches the dictionary-list
490 					//! thus the service needs not to now about it
491 					//aArgs.getArray()[1] <<= GetDicList();
492 
493 					// create specific service via it's implementation name
494 					try
495 					{
496 						xHyph = Reference< XHyphenator >(
497 								xMgr->createInstanceWithArguments(
498                                 pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
499 					}
500 					catch (uno::Exception &)
501 					{
502                         DBG_ASSERT( 0, "createInstanceWithArguments failed" );
503 					}
504                     pRef [i] = xHyph;
505 
506 					Reference< XLinguServiceEventBroadcaster >
507 							xBroadcaster( xHyph, UNO_QUERY );
508 					if (xBroadcaster.is())
509 						rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
510 
511                     if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
512                         xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale,
513 									nChkIndex, rProperties );
514 
515                     pEntry->nLastTriedSvcIndex = (sal_Int16) i;
516 					++i;
517 
518                     // if language is not supported by the services
519                     // remove it from the list.
520                     if (xHyph.is()  &&  !xHyph->hasLocale( rLocale ))
521                         aSvcMap.erase( nLanguage );
522 				}
523 			}
524 		}	// if (xEntry.is())
525 	}
526 
527 	if (bWordModified  &&  xRes.is())
528 		xRes = RebuildHyphensAndControlChars( rWord, xRes );
529 
530     if (xRes.is()  &&  xRes->getWord() != rWord)
531     {
532         xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(),
533                                    xRes->getHyphenatedWord(),
534                                    xRes->getHyphenPos() );
535     }
536 
537 	return xRes;
538 }
539 
540 
541 Reference< XPossibleHyphens > SAL_CALL
542 	HyphenatorDispatcher::createPossibleHyphens(
543 			const OUString& rWord, const Locale& rLocale,
544 			const PropertyValues& rProperties )
545 		throw(IllegalArgumentException, RuntimeException)
546 {
547 	MutexGuard	aGuard( GetLinguMutex() );
548 
549 	Reference< XPossibleHyphens >	xRes;
550 
551 	sal_Int16 nLanguage = LocaleToLanguage( rLocale );
552 	if (nLanguage == LANGUAGE_NONE  || !rWord.getLength())
553 		return xRes;
554 
555 	// search for entry with that language
556     HyphSvcByLangMap_t::iterator    aIt( aSvcMap.find( nLanguage ) );
557     LangSvcEntries_Hyph     *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
558 
559 	if (!pEntry)
560 	{
561 #ifdef LINGU_EXCEPTIONS
562 		throw IllegalArgumentException();
563 #endif
564 	}
565 	else
566 	{
567 		OUString aChkWord( rWord );
568 
569         // replace typographical apostroph by ascii apostroph
570         String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
571         DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
572         if (aSingleQuote.Len())
573             aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
574 
575         RemoveHyphens( aChkWord );
576 		if (IsIgnoreControlChars( rProperties, GetPropSet() ))
577 			RemoveControlChars( aChkWord );
578 
579 		// check for results from (positive) dictionaries which have precedence!
580 		Reference< XDictionaryEntry > xEntry;
581 
582 		if (GetDicList().is()  &&  IsUseDicList( rProperties, GetPropSet() ))
583 		{
584 			xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
585 						sal_True, sal_False );
586 		}
587 
588 		if (xEntry.is())
589 		{
590 			xRes = buildPossHyphens( xEntry, nLanguage );
591 		}
592 		else
593 		{
594             sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
595             DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
596 					"lng : index out of range");
597 
598 			sal_Int32 i = 0;
599             Reference< XHyphenator > xHyph;
600             if (pEntry->aSvcRefs.getLength() > 0)
601                 xHyph = pEntry->aSvcRefs[0];
602 
603 			// try already instantiated service
604             if (i <= pEntry->nLastTriedSvcIndex)
605 			{
606                 if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
607                     xRes = xHyph->createPossibleHyphens( aChkWord, rLocale,
608 								rProperties );
609 				++i;
610 			}
611             else if (pEntry->nLastTriedSvcIndex < nLen - 1)
612 			// instantiate services and try it
613 			{
614 //                const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
615                 Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
616 
617 				Reference< XMultiServiceFactory >  xMgr( getProcessServiceFactory() );
618 				if (xMgr.is())
619 				{
620 					// build service initialization argument
621 					Sequence< Any > aArgs(2);
622 					aArgs.getArray()[0] <<= GetPropSet();
623 					//! The dispatcher searches the dictionary-list
624 					//! thus the service needs not to now about it
625 					//aArgs.getArray()[1] <<= GetDicList();
626 
627 					// create specific service via it's implementation name
628 					try
629 					{
630 						xHyph = Reference< XHyphenator >(
631 								xMgr->createInstanceWithArguments(
632                                 pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
633 					}
634 					catch (uno::Exception &)
635 					{
636                         DBG_ASSERT( 0, "createWithArguments failed" );
637 					}
638                     pRef [i] = xHyph;
639 
640 					Reference< XLinguServiceEventBroadcaster >
641 							xBroadcaster( xHyph, UNO_QUERY );
642 					if (xBroadcaster.is())
643 						rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
644 
645                     if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
646                     xRes = xHyph->createPossibleHyphens( aChkWord, rLocale,
647 								rProperties );
648 
649                     pEntry->nLastTriedSvcIndex = (sal_Int16) i;
650 					++i;
651 
652                     // if language is not supported by the services
653                     // remove it from the list.
654                     if (xHyph.is()  &&  !xHyph->hasLocale( rLocale ))
655                         aSvcMap.erase( nLanguage );
656 				}
657 			}
658 		}	// if (xEntry.is())
659 	}
660 
661     if (xRes.is()  &&  xRes->getWord() != rWord)
662     {
663         xRes = new PossibleHyphens( rWord, nLanguage,
664                                     xRes->getPossibleHyphens(),
665                                     xRes->getHyphenationPositions() );
666     }
667 
668 	return xRes;
669 }
670 
671 
672 void HyphenatorDispatcher::SetServiceList( const Locale &rLocale,
673 		const Sequence< OUString > &rSvcImplNames )
674 {
675 	MutexGuard	aGuard( GetLinguMutex() );
676 
677 	sal_Int16 nLanguage = LocaleToLanguage( rLocale );
678 
679     sal_Int32 nLen = rSvcImplNames.getLength();
680     if (0 == nLen)
681         // remove entry
682         aSvcMap.erase( nLanguage );
683     else
684     {
685         // modify/add entry
686         LangSvcEntries_Hyph *pEntry = aSvcMap[ nLanguage ].get();
687 		// only one hypenator can be in use for a language...
688         //const OUString &rSvcImplName = rSvcImplNames.getConstArray()[0];
689         if (pEntry)
690         {
691             pEntry->Clear();
692             pEntry->aSvcImplNames = rSvcImplNames;
693             pEntry->aSvcImplNames.realloc(1);
694             pEntry->aSvcRefs  = Sequence< Reference < XHyphenator > > ( 1 );
695         }
696         else
697         {
698             boost::shared_ptr< LangSvcEntries_Hyph > pTmpEntry( new LangSvcEntries_Hyph( rSvcImplNames[0] ) );
699             pTmpEntry->aSvcRefs = Sequence< Reference < XHyphenator > >( 1 );
700             aSvcMap[ nLanguage ] = pTmpEntry;
701         }
702     }
703 }
704 
705 
706 Sequence< OUString >
707 	HyphenatorDispatcher::GetServiceList( const Locale &rLocale ) const
708 {
709 	MutexGuard	aGuard( GetLinguMutex() );
710 
711     Sequence< OUString > aRes;
712 
713 	// search for entry with that language and use data from that
714 	sal_Int16 nLanguage = LocaleToLanguage( rLocale );
715     HyphenatorDispatcher            *pThis = (HyphenatorDispatcher *) this;
716     const HyphSvcByLangMap_t::iterator  aIt( pThis->aSvcMap.find( nLanguage ) );
717     const LangSvcEntries_Hyph       *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
718 	if (pEntry)
719     {
720         aRes = pEntry->aSvcImplNames;
721         if (aRes.getLength() > 0)
722             aRes.realloc(1);
723     }
724 
725 	return aRes;
726 }
727 
728 
729 LinguDispatcher::DspType HyphenatorDispatcher::GetDspType() const
730 {
731     return DSP_HYPH;
732 }
733 
734 
735 ///////////////////////////////////////////////////////////////////////////
736 
737