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