xref: /trunk/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