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