xref: /trunk/main/linguistic/source/hyphdsp.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
230     MutexGuard  aGuard( GetLinguMutex() );
231 
232     Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) );
233     Locale *pLocales = aLocales.getArray();
234     HyphSvcByLangMap_t::const_iterator aIt;
235     for (aIt = aSvcMap.begin();  aIt != aSvcMap.end();  ++aIt)
236     {
237         *pLocales++ = CreateLocale( aIt->first );
238     }
239     return aLocales;
240 }
241 
242 
hasLocale(const Locale & rLocale)243 sal_Bool SAL_CALL HyphenatorDispatcher::hasLocale(const Locale& rLocale)
244 {
245     MutexGuard  aGuard( GetLinguMutex() );
246     HyphSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LocaleToLanguage( rLocale ) ) );
247     return aIt != aSvcMap.end();
248 }
249 
250 
251 Reference< XHyphenatedWord > SAL_CALL
hyphenate(const OUString & rWord,const Locale & rLocale,sal_Int16 nMaxLeading,const PropertyValues & rProperties)252     HyphenatorDispatcher::hyphenate(
253             const OUString& rWord, const Locale& rLocale, sal_Int16 nMaxLeading,
254             const PropertyValues& rProperties )
255 {
256     MutexGuard  aGuard( GetLinguMutex() );
257 
258     Reference< XHyphenatedWord >    xRes;
259 
260     sal_Int32 nWordLen = rWord.getLength();
261     sal_Int16 nLanguage = LocaleToLanguage( rLocale );
262     if (nLanguage == LANGUAGE_NONE  || !nWordLen ||
263         nMaxLeading == 0 || nMaxLeading == nWordLen)
264         return xRes;
265 
266     // search for entry with that language
267     HyphSvcByLangMap_t::iterator    aIt( aSvcMap.find( nLanguage ) );
268     LangSvcEntries_Hyph     *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
269 
270     sal_Bool bWordModified = sal_False;
271     if (!pEntry || (nMaxLeading < 0 || nMaxLeading > nWordLen))
272     {
273 #ifdef LINGU_EXCEPTIONS
274         throw IllegalArgumentException();
275 #else
276         return NULL;
277 #endif
278     }
279     else
280     {
281         OUString aChkWord( rWord );
282 
283         // replace typographical apostrophe by ascii apostrophe
284         String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
285         DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpected length of quotation mark" );
286         if (aSingleQuote.Len())
287             aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
288 
289         bWordModified |= RemoveHyphens( aChkWord );
290         if (IsIgnoreControlChars( rProperties, GetPropSet() ))
291             bWordModified |= RemoveControlChars( aChkWord );
292         sal_Int16 nChkMaxLeading = (sal_Int16) GetPosInWordToCheck( rWord, nMaxLeading );
293 
294         // check for results from (positive) dictionaries which have precedence!
295         Reference< XDictionaryEntry > xEntry;
296 
297         if (GetDicList().is()  &&  IsUseDicList( rProperties, GetPropSet() ))
298         {
299             xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
300                         sal_True, sal_False );
301         }
302 
303         if (xEntry.is())
304         {
305             //! because queryDictionaryEntry (in the end DictionaryNeo::getEntry)
306             //! does not distinguish between "XYZ" and "XYZ." in order to avoid
307             //! to require them as different entry we have to supply the
308             //! original word here as well so it can be used in th result
309             //! otherwise a strange effect may occur (see #i22591#)
310             xRes = buildHyphWord( rWord, xEntry, nLanguage, nChkMaxLeading );
311         }
312         else
313         {
314             sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
315             DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
316                     "lng : index out of range");
317 
318             sal_Int32 i = 0;
319             Reference< XHyphenator > xHyph;
320             if (pEntry->aSvcRefs.getLength() > 0)
321                 xHyph = pEntry->aSvcRefs[0];
322 
323             // try already instantiated service
324             if (i <= pEntry->nLastTriedSvcIndex)
325             {
326                 if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
327                     xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading,
328                                             rProperties );
329                 ++i;
330             }
331             else if (pEntry->nLastTriedSvcIndex < nLen - 1)
332             // instantiate services and try it
333             {
334 //                const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
335                 Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
336 
337                 Reference< XMultiServiceFactory >  xMgr( getProcessServiceFactory() );
338                 if (xMgr.is())
339                 {
340                     // build service initialization argument
341                     Sequence< Any > aArgs(2);
342                     aArgs.getArray()[0] <<= GetPropSet();
343                     //! The dispatcher searches the dictionary-list
344                     //! thus the service needs not to now about it
345                     //aArgs.getArray()[1] <<= GetDicList();
346 
347                     // create specific service via it's implementation name
348                     try
349                     {
350                         xHyph = Reference< XHyphenator >(
351                                 xMgr->createInstanceWithArguments(
352                                 pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
353                     }
354                     catch (uno::Exception &)
355                     {
356                         DBG_ASSERT( 0, "createInstanceWithArguments failed" );
357                     }
358                     pRef [i] = xHyph;
359 
360                     Reference< XLinguServiceEventBroadcaster >
361                             xBroadcaster( xHyph, UNO_QUERY );
362                     if (xBroadcaster.is())
363                         rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
364 
365                     if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
366                         xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading,
367                                                 rProperties );
368 
369                     pEntry->nLastTriedSvcIndex = (sal_Int16) i;
370                     ++i;
371 
372                     // if language is not supported by the services
373                     // remove it from the list.
374                     if (xHyph.is()  &&  !xHyph->hasLocale( rLocale ))
375                         aSvcMap.erase( nLanguage );
376                 }
377             }
378         }   // if (xEntry.is())
379     }
380 
381     if (bWordModified  &&  xRes.is())
382         xRes = RebuildHyphensAndControlChars( rWord, xRes );
383 
384     if (xRes.is()  &&  xRes->getWord() != rWord)
385     {
386         xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(),
387                                    xRes->getHyphenatedWord(),
388                                    xRes->getHyphenPos() );
389     }
390 
391     return xRes;
392 }
393 
394 
395 Reference< XHyphenatedWord > SAL_CALL
queryAlternativeSpelling(const OUString & rWord,const Locale & rLocale,sal_Int16 nIndex,const PropertyValues & rProperties)396     HyphenatorDispatcher::queryAlternativeSpelling(
397             const OUString& rWord, const Locale& rLocale, sal_Int16 nIndex,
398             const PropertyValues& rProperties )
399 {
400     MutexGuard  aGuard( GetLinguMutex() );
401 
402     Reference< XHyphenatedWord >    xRes;
403 
404     sal_Int32 nWordLen = rWord.getLength();
405     sal_Int16 nLanguage = LocaleToLanguage( rLocale );
406     if (nLanguage == LANGUAGE_NONE  || !nWordLen)
407         return xRes;
408 
409     // search for entry with that language
410     HyphSvcByLangMap_t::iterator    aIt( aSvcMap.find( nLanguage ) );
411     LangSvcEntries_Hyph     *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
412 
413     sal_Bool bWordModified = sal_False;
414     if (!pEntry || !(0 <= nIndex && nIndex <= nWordLen - 2))
415     {
416 #ifdef LINGU_EXCEPTIONS
417         throw IllegalArgumentException();
418 #else
419         return NULL;
420 #endif
421     }
422     else
423     {
424         OUString aChkWord( rWord );
425 
426         // replace typographical apostrophe by ascii apostrophe
427         String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
428         DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpected length of quotation mark" );
429         if (aSingleQuote.Len())
430             aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
431 
432         bWordModified |= RemoveHyphens( aChkWord );
433         if (IsIgnoreControlChars( rProperties, GetPropSet() ))
434             bWordModified |= RemoveControlChars( aChkWord );
435         sal_Int16 nChkIndex = (sal_Int16) GetPosInWordToCheck( rWord, nIndex );
436 
437         // check for results from (positive) dictionaries which have precedence!
438         Reference< XDictionaryEntry > xEntry;
439 
440         if (GetDicList().is()  &&  IsUseDicList( rProperties, GetPropSet() ))
441         {
442             xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
443                         sal_True, sal_False );
444         }
445 
446         if (xEntry.is())
447         {
448             //! alternative spellings not yet supported by dictionaries
449         }
450         else
451         {
452             sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
453             DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
454                     "lng : index out of range");
455 
456             sal_Int32 i = 0;
457             Reference< XHyphenator > xHyph;
458             if (pEntry->aSvcRefs.getLength() > 0)
459                 xHyph = pEntry->aSvcRefs[0];
460 
461             // try already instantiated service
462             if (i <= pEntry->nLastTriedSvcIndex)
463             {
464                 if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
465                     xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale,
466                                 nChkIndex, rProperties );
467                 ++i;
468             }
469             else if (pEntry->nLastTriedSvcIndex < nLen - 1)
470             // instantiate services and try it
471             {
472 //                const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
473                 Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
474 
475                 Reference< XMultiServiceFactory >  xMgr( getProcessServiceFactory() );
476                 if (xMgr.is())
477                 {
478                     // build service initialization argument
479                     Sequence< Any > aArgs(2);
480                     aArgs.getArray()[0] <<= GetPropSet();
481                     //! The dispatcher searches the dictionary-list
482                     //! thus the service needs not to now about it
483                     //aArgs.getArray()[1] <<= GetDicList();
484 
485                     // create specific service via it's implementation name
486                     try
487                     {
488                         xHyph = Reference< XHyphenator >(
489                                 xMgr->createInstanceWithArguments(
490                                 pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
491                     }
492                     catch (uno::Exception &)
493                     {
494                         DBG_ASSERT( 0, "createInstanceWithArguments failed" );
495                     }
496                     pRef [i] = xHyph;
497 
498                     Reference< XLinguServiceEventBroadcaster >
499                             xBroadcaster( xHyph, UNO_QUERY );
500                     if (xBroadcaster.is())
501                         rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
502 
503                     if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
504                         xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale,
505                                     nChkIndex, rProperties );
506 
507                     pEntry->nLastTriedSvcIndex = (sal_Int16) i;
508                     ++i;
509 
510                     // if language is not supported by the services
511                     // remove it from the list.
512                     if (xHyph.is()  &&  !xHyph->hasLocale( rLocale ))
513                         aSvcMap.erase( nLanguage );
514                 }
515             }
516         }   // if (xEntry.is())
517     }
518 
519     if (bWordModified  &&  xRes.is())
520         xRes = RebuildHyphensAndControlChars( rWord, xRes );
521 
522     if (xRes.is()  &&  xRes->getWord() != rWord)
523     {
524         xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(),
525                                    xRes->getHyphenatedWord(),
526                                    xRes->getHyphenPos() );
527     }
528 
529     return xRes;
530 }
531 
532 
533 Reference< XPossibleHyphens > SAL_CALL
createPossibleHyphens(const OUString & rWord,const Locale & rLocale,const PropertyValues & rProperties)534     HyphenatorDispatcher::createPossibleHyphens(
535             const OUString& rWord, const Locale& rLocale,
536             const PropertyValues& rProperties )
537 {
538     MutexGuard  aGuard( GetLinguMutex() );
539 
540     Reference< XPossibleHyphens >   xRes;
541 
542     sal_Int16 nLanguage = LocaleToLanguage( rLocale );
543     if (nLanguage == LANGUAGE_NONE  || !rWord.getLength())
544         return xRes;
545 
546     // search for entry with that language
547     HyphSvcByLangMap_t::iterator    aIt( aSvcMap.find( nLanguage ) );
548     LangSvcEntries_Hyph     *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
549 
550     if (!pEntry)
551     {
552 #ifdef LINGU_EXCEPTIONS
553         throw IllegalArgumentException();
554 #endif
555     }
556     else
557     {
558         OUString aChkWord( rWord );
559 
560         // replace typographical apostrophe by ascii apostrophe
561         String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
562         DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpected length of quotation mark" );
563         if (aSingleQuote.Len())
564             aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
565 
566         RemoveHyphens( aChkWord );
567         if (IsIgnoreControlChars( rProperties, GetPropSet() ))
568             RemoveControlChars( aChkWord );
569 
570         // check for results from (positive) dictionaries which have precedence!
571         Reference< XDictionaryEntry > xEntry;
572 
573         if (GetDicList().is()  &&  IsUseDicList( rProperties, GetPropSet() ))
574         {
575             xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
576                         sal_True, sal_False );
577         }
578 
579         if (xEntry.is())
580         {
581             xRes = buildPossHyphens( xEntry, nLanguage );
582         }
583         else
584         {
585             sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
586             DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
587                     "lng : index out of range");
588 
589             sal_Int32 i = 0;
590             Reference< XHyphenator > xHyph;
591             if (pEntry->aSvcRefs.getLength() > 0)
592                 xHyph = pEntry->aSvcRefs[0];
593 
594             // try already instantiated service
595             if (i <= pEntry->nLastTriedSvcIndex)
596             {
597                 if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
598                     xRes = xHyph->createPossibleHyphens( aChkWord, rLocale,
599                                 rProperties );
600                 ++i;
601             }
602             else if (pEntry->nLastTriedSvcIndex < nLen - 1)
603             // instantiate services and try it
604             {
605 //                const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
606                 Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
607 
608                 Reference< XMultiServiceFactory >  xMgr( getProcessServiceFactory() );
609                 if (xMgr.is())
610                 {
611                     // build service initialization argument
612                     Sequence< Any > aArgs(2);
613                     aArgs.getArray()[0] <<= GetPropSet();
614                     //! The dispatcher searches the dictionary-list
615                     //! thus the service needs not to now about it
616                     //aArgs.getArray()[1] <<= GetDicList();
617 
618                     // create specific service via it's implementation name
619                     try
620                     {
621                         xHyph = Reference< XHyphenator >(
622                                 xMgr->createInstanceWithArguments(
623                                 pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
624                     }
625                     catch (uno::Exception &)
626                     {
627                         DBG_ASSERT( 0, "createWithArguments failed" );
628                     }
629                     pRef [i] = xHyph;
630 
631                     Reference< XLinguServiceEventBroadcaster >
632                             xBroadcaster( xHyph, UNO_QUERY );
633                     if (xBroadcaster.is())
634                         rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
635 
636                     if (xHyph.is()  &&  xHyph->hasLocale( rLocale ))
637                     xRes = xHyph->createPossibleHyphens( aChkWord, rLocale,
638                                 rProperties );
639 
640                     pEntry->nLastTriedSvcIndex = (sal_Int16) i;
641                     ++i;
642 
643                     // if language is not supported by the services
644                     // remove it from the list.
645                     if (xHyph.is()  &&  !xHyph->hasLocale( rLocale ))
646                         aSvcMap.erase( nLanguage );
647                 }
648             }
649         }   // if (xEntry.is())
650     }
651 
652     if (xRes.is()  &&  xRes->getWord() != rWord)
653     {
654         xRes = new PossibleHyphens( rWord, nLanguage,
655                                     xRes->getPossibleHyphens(),
656                                     xRes->getHyphenationPositions() );
657     }
658 
659     return xRes;
660 }
661 
662 
SetServiceList(const Locale & rLocale,const Sequence<OUString> & rSvcImplNames)663 void HyphenatorDispatcher::SetServiceList( const Locale &rLocale,
664         const Sequence< OUString > &rSvcImplNames )
665 {
666     MutexGuard  aGuard( GetLinguMutex() );
667 
668     sal_Int16 nLanguage = LocaleToLanguage( rLocale );
669 
670     sal_Int32 nLen = rSvcImplNames.getLength();
671     if (0 == nLen)
672         // remove entry
673         aSvcMap.erase( nLanguage );
674     else
675     {
676         // modify/add entry
677         LangSvcEntries_Hyph *pEntry = aSvcMap[ nLanguage ].get();
678         // only one hypenator can be in use for a language...
679         //const OUString &rSvcImplName = rSvcImplNames.getConstArray()[0];
680         if (pEntry)
681         {
682             pEntry->Clear();
683             pEntry->aSvcImplNames = rSvcImplNames;
684             pEntry->aSvcImplNames.realloc(1);
685             pEntry->aSvcRefs  = Sequence< Reference < XHyphenator > > ( 1 );
686         }
687         else
688         {
689             boost::shared_ptr< LangSvcEntries_Hyph > pTmpEntry( new LangSvcEntries_Hyph( rSvcImplNames[0] ) );
690             pTmpEntry->aSvcRefs = Sequence< Reference < XHyphenator > >( 1 );
691             aSvcMap[ nLanguage ] = pTmpEntry;
692         }
693     }
694 }
695 
696 
697 Sequence< OUString >
GetServiceList(const Locale & rLocale) const698     HyphenatorDispatcher::GetServiceList( const Locale &rLocale ) const
699 {
700     MutexGuard  aGuard( GetLinguMutex() );
701 
702     Sequence< OUString > aRes;
703 
704     // search for entry with that language and use data from that
705     sal_Int16 nLanguage = LocaleToLanguage( rLocale );
706     HyphenatorDispatcher            *pThis = (HyphenatorDispatcher *) this;
707     const HyphSvcByLangMap_t::iterator  aIt( pThis->aSvcMap.find( nLanguage ) );
708     const LangSvcEntries_Hyph       *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
709     if (pEntry)
710     {
711         aRes = pEntry->aSvcImplNames;
712         if (aRes.getLength() > 0)
713             aRes.realloc(1);
714     }
715 
716     return aRes;
717 }
718 
719 
GetDspType() const720 LinguDispatcher::DspType HyphenatorDispatcher::GetDspType() const
721 {
722     return DSP_HYPH;
723 }
724 
725 
726 ///////////////////////////////////////////////////////////////////////////
727