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