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