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>
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 102 : HyphenatorDispatcher::HyphenatorDispatcher( LngSvcMgr &rLngSvcMgr ) :
48 102 : rMgr (rLngSvcMgr)
49 : {
50 102 : }
51 :
52 :
53 294 : HyphenatorDispatcher::~HyphenatorDispatcher()
54 : {
55 98 : ClearSvcList();
56 196 : }
57 :
58 :
59 98 : void HyphenatorDispatcher::ClearSvcList()
60 : {
61 : // release memory for each table entry
62 98 : HyphSvcByLangMap_t aTmp;
63 98 : aSvcMap.swap( aTmp );
64 98 : }
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 ] != '=' && aText[ nTextLen - 1 ] != '[')
83 : {
84 0 : sal_Int16 nHyphenationPos = -1;
85 0 : sal_Int32 nHyphenPos = -1;
86 0 : sal_Int16 nOrigHyphPos = -1;
87 :
88 0 : OUStringBuffer aTmp( nTextLen );
89 0 : bool bSkip = false;
90 0 : bool bSkip2 = false;
91 0 : sal_Int32 nHyphIdx = -1;
92 0 : sal_Int32 nLeading = 0;
93 0 : for (sal_Int32 i = 0; i < nTextLen; i++)
94 : {
95 0 : sal_Unicode cTmp = aText[i];
96 0 : if (cTmp == '[' || cTmp == ']')
97 0 : bSkip2 = !bSkip2;
98 0 : if (cTmp != '=' && !bSkip2 && cTmp != ']')
99 : {
100 0 : aTmp.append( cTmp );
101 0 : nLeading++;
102 0 : bSkip = false;
103 0 : nHyphIdx++;
104 : }
105 : else
106 : {
107 0 : if (!bSkip && nHyphIdx >= 0)
108 : {
109 0 : if (nLeading <= nMaxLeading) {
110 0 : nHyphenationPos = (sal_Int16) nHyphIdx;
111 0 : nOrigHyphPos = i;
112 : }
113 : }
114 0 : bSkip = true; //! multiple '=' should count as one only
115 : }
116 : }
117 :
118 0 : if (nHyphenationPos > 0)
119 : {
120 :
121 : #if OSL_DEBUG_LEVEL > 1
122 : {
123 : if (aTmp.toString() != rOrigWord)
124 : {
125 : // both words should only differ by a having a trailing '.'
126 : // character or not...
127 : OUString aShorter, aLonger;
128 : if (aTmp.getLength() <= rOrigWord.getLength())
129 : {
130 : aShorter = aTmp.toString();
131 : aLonger = rOrigWord;
132 : }
133 : else
134 : {
135 : aShorter = rOrigWord;
136 : aLonger = aTmp.toString();
137 : }
138 : sal_Int32 nS = aShorter.getLength();
139 : sal_Int32 nL = aLonger.getLength();
140 : if (nS > 0 && nL > 0)
141 : {
142 : DBG_ASSERT( (nS + 1 == nL) && aLonger[nL-1] == '.',
143 : "HyphenatorDispatcher::buildHyphWord: unexpected difference between words!" );
144 : }
145 : }
146 : }
147 : #endif
148 0 : if (aText[ nOrigHyphPos ] == '[') // alternative hyphenation
149 : {
150 0 : sal_Int16 split = 0;
151 0 : sal_Unicode c = aText [ nOrigHyphPos + 1 ];
152 0 : sal_Int32 endhyphpat = aText.indexOf( ']', nOrigHyphPos );
153 0 : if ('0' <= c && c <= '9')
154 : {
155 0 : split = c - '0';
156 0 : nOrigHyphPos++;
157 : }
158 0 : if (endhyphpat > -1)
159 : {
160 0 : OUStringBuffer aTmp2 ( aTmp.copy(0, std::max (nHyphenationPos + 1 - split, 0) ) );
161 0 : aTmp2.append( aText.copy( nOrigHyphPos + 1, endhyphpat - nOrigHyphPos - 1) );
162 0 : nHyphenPos = aTmp2.getLength();
163 0 : aTmp2.append( aTmp.copy( nHyphenationPos + 1 ) );
164 : //! take care of #i22591#
165 0 : if (rOrigWord[ rOrigWord.getLength() - 1 ] == '.')
166 0 : aTmp2.append( '.' );
167 0 : aText = aTmp2.makeStringAndClear();
168 : }
169 : }
170 0 : if (nHyphenPos == -1)
171 0 : aText = rOrigWord;
172 :
173 0 : xRes = new HyphenatedWord( rOrigWord, nLang, nHyphenationPos,
174 0 : aText, (nHyphenPos > -1) ? nHyphenPos - 1 : nHyphenationPos);
175 0 : }
176 0 : }
177 : }
178 :
179 0 : return xRes;
180 : }
181 :
182 :
183 0 : Reference< XPossibleHyphens > HyphenatorDispatcher::buildPossHyphens(
184 : const Reference< XDictionaryEntry > &xEntry, sal_Int16 nLanguage )
185 : {
186 0 : MutexGuard aGuard( GetLinguMutex() );
187 :
188 0 : Reference<XPossibleHyphens> xRes;
189 :
190 0 : if (xEntry.is())
191 : {
192 : // text with hyphenation info
193 0 : OUString aText( xEntry->getDictionaryWord() );
194 0 : sal_Int32 nTextLen = aText.getLength();
195 :
196 : // trailing '=' means "hyphenation should not be possible"
197 0 : if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=' && aText[ nTextLen - 1 ] != '[')
198 : {
199 : // sequence to hold hyphenation positions
200 0 : Sequence< sal_Int16 > aHyphPos( nTextLen );
201 0 : sal_Int16 *pPos = aHyphPos.getArray();
202 0 : sal_Int32 nHyphCount = 0;
203 :
204 0 : OUStringBuffer aTmp( nTextLen );
205 0 : bool bSkip = false;
206 0 : bool bSkip2 = false;
207 0 : sal_Int32 nHyphIdx = -1;
208 0 : for (sal_Int32 i = 0; i < nTextLen; i++)
209 : {
210 0 : sal_Unicode cTmp = aText[i];
211 0 : if (cTmp == '[' || cTmp == ']')
212 0 : bSkip2 = !bSkip2;
213 0 : if (cTmp != '=' && !bSkip2 && cTmp != ']')
214 : {
215 0 : aTmp.append( cTmp );
216 0 : bSkip = false;
217 0 : nHyphIdx++;
218 : }
219 : else
220 : {
221 0 : if (!bSkip && nHyphIdx >= 0)
222 0 : pPos[ nHyphCount++ ] = (sal_Int16) nHyphIdx;
223 0 : bSkip = true; //! multiple '=' should count as one only
224 : }
225 : }
226 :
227 : // ignore (multiple) trailing '='
228 0 : if (bSkip && nHyphIdx >= 0)
229 : {
230 0 : nHyphCount--;
231 : }
232 : DBG_ASSERT( nHyphCount >= 0, "lng : invalid hyphenation count");
233 :
234 0 : if (nHyphCount > 0)
235 : {
236 0 : aHyphPos.realloc( nHyphCount );
237 0 : xRes = new PossibleHyphens( aTmp.makeStringAndClear(), nLanguage,
238 0 : aText, aHyphPos );
239 0 : }
240 0 : }
241 : }
242 :
243 0 : return xRes;
244 : }
245 :
246 :
247 0 : Sequence< Locale > SAL_CALL HyphenatorDispatcher::getLocales()
248 : throw(RuntimeException, std::exception)
249 : {
250 0 : MutexGuard aGuard( GetLinguMutex() );
251 :
252 0 : Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) );
253 0 : Locale *pLocales = aLocales.getArray();
254 0 : HyphSvcByLangMap_t::const_iterator aIt;
255 0 : for (aIt = aSvcMap.begin(); aIt != aSvcMap.end(); ++aIt)
256 : {
257 0 : *pLocales++ = LanguageTag::convertToLocale( aIt->first );
258 : }
259 0 : return aLocales;
260 : }
261 :
262 :
263 0 : sal_Bool SAL_CALL HyphenatorDispatcher::hasLocale(const Locale& rLocale)
264 : throw(RuntimeException, std::exception)
265 : {
266 0 : MutexGuard aGuard( GetLinguMutex() );
267 0 : HyphSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LinguLocaleToLanguage( rLocale ) ) );
268 0 : return aIt != aSvcMap.end();
269 : }
270 :
271 :
272 : Reference< XHyphenatedWord > SAL_CALL
273 66884 : HyphenatorDispatcher::hyphenate(
274 : const OUString& rWord, const Locale& rLocale, sal_Int16 nMaxLeading,
275 : const PropertyValues& rProperties )
276 : throw(IllegalArgumentException, RuntimeException, std::exception)
277 : {
278 66884 : MutexGuard aGuard( GetLinguMutex() );
279 :
280 133768 : Reference< XHyphenatedWord > xRes;
281 :
282 66884 : sal_Int32 nWordLen = rWord.getLength();
283 66884 : sal_Int16 nLanguage = LinguLocaleToLanguage( rLocale );
284 200652 : if (LinguIsUnspecified(nLanguage) || !nWordLen ||
285 131319 : nMaxLeading == 0 || nMaxLeading == nWordLen)
286 2535 : return xRes;
287 :
288 : // search for entry with that language
289 64349 : HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
290 64349 : LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
291 :
292 64349 : bool bWordModified = false;
293 64349 : if (!pEntry || (nMaxLeading < 0 || nMaxLeading > nWordLen))
294 : {
295 42747 : return NULL;
296 : }
297 : else
298 : {
299 21602 : OUString aChkWord( rWord );
300 :
301 : // replace typographical apostroph by ascii apostroph
302 43204 : OUString aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
303 : DBG_ASSERT( 1 == aSingleQuote.getLength(), "unexpectend length of quotation mark" );
304 21602 : if (!aSingleQuote.isEmpty())
305 21602 : aChkWord = aChkWord.replace( aSingleQuote[0], '\'' );
306 :
307 21602 : bWordModified |= RemoveHyphens( aChkWord );
308 21602 : if (IsIgnoreControlChars( rProperties, GetPropSet() ))
309 21602 : bWordModified |= RemoveControlChars( aChkWord );
310 21602 : sal_Int16 nChkMaxLeading = (sal_Int16) GetPosInWordToCheck( rWord, nMaxLeading );
311 :
312 : // check for results from (positive) dictionaries which have precedence!
313 43204 : Reference< XDictionaryEntry > xEntry;
314 :
315 21602 : if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
316 : {
317 64806 : xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
318 43204 : sal_True, sal_False );
319 : }
320 :
321 21602 : if (xEntry.is())
322 : {
323 : //! because queryDictionaryEntry (in the end DictionaryNeo::getEntry)
324 : //! does not distinguish betwee "XYZ" and "XYZ." in order to avoid
325 : //! to require them as different entry we have to supply the
326 : //! original word here as well so it can be used in th result
327 : //! otherwise a strange effect may occur (see #i22591#)
328 0 : xRes = buildHyphWord( rWord, xEntry, nLanguage, nChkMaxLeading );
329 : }
330 : else
331 : {
332 21602 : sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
333 : DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
334 : "lng : index out of range");
335 :
336 21602 : sal_Int32 i = 0;
337 21602 : Reference< XHyphenator > xHyph;
338 21602 : if (pEntry->aSvcRefs.getLength() > 0)
339 21602 : xHyph = pEntry->aSvcRefs[0];
340 :
341 : // try already instantiated service
342 21602 : if (i <= pEntry->nLastTriedSvcIndex)
343 : {
344 21592 : if (xHyph.is() && xHyph->hasLocale( rLocale ))
345 64776 : xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading,
346 43184 : rProperties );
347 21592 : ++i;
348 : }
349 10 : else if (pEntry->nLastTriedSvcIndex < nLen - 1)
350 : // instantiate services and try it
351 : {
352 10 : Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
353 :
354 : Reference< XComponentContext > xContext(
355 10 : comphelper::getProcessComponentContext() );
356 :
357 : // build service initialization argument
358 20 : Sequence< Any > aArgs(2);
359 10 : aArgs.getArray()[0] <<= GetPropSet();
360 :
361 : // create specific service via it's implementation name
362 : try
363 : {
364 20 : xHyph = Reference< XHyphenator >(
365 20 : xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
366 10 : pEntry->aSvcImplNames[0], aArgs, xContext ),
367 10 : UNO_QUERY );
368 : }
369 0 : catch (uno::Exception &)
370 : {
371 : DBG_ASSERT( false, "createInstanceWithArguments failed" );
372 : }
373 10 : pRef [i] = xHyph;
374 :
375 : Reference< XLinguServiceEventBroadcaster >
376 20 : xBroadcaster( xHyph, UNO_QUERY );
377 10 : if (xBroadcaster.is())
378 10 : rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
379 :
380 10 : if (xHyph.is() && xHyph->hasLocale( rLocale ))
381 30 : xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading,
382 20 : rProperties );
383 :
384 10 : pEntry->nLastTriedSvcIndex = (sal_Int16) i;
385 10 : ++i;
386 :
387 : // if language is not supported by the services
388 : // remove it from the list.
389 10 : if (xHyph.is() && !xHyph->hasLocale( rLocale ))
390 10 : aSvcMap.erase( nLanguage );
391 21602 : }
392 21602 : } // if (xEntry.is())
393 : }
394 :
395 21602 : if (bWordModified && xRes.is())
396 0 : xRes = RebuildHyphensAndControlChars( rWord, xRes );
397 :
398 21602 : if (xRes.is() && xRes->getWord() != rWord)
399 : {
400 0 : xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(),
401 0 : xRes->getHyphenatedWord(),
402 0 : xRes->getHyphenPos() );
403 : }
404 :
405 88486 : return xRes;
406 : }
407 :
408 :
409 : Reference< XHyphenatedWord > SAL_CALL
410 0 : HyphenatorDispatcher::queryAlternativeSpelling(
411 : const OUString& rWord, const Locale& rLocale, sal_Int16 nIndex,
412 : const PropertyValues& rProperties )
413 : throw(IllegalArgumentException, RuntimeException, std::exception)
414 : {
415 0 : MutexGuard aGuard( GetLinguMutex() );
416 :
417 0 : Reference< XHyphenatedWord > xRes;
418 :
419 0 : sal_Int32 nWordLen = rWord.getLength();
420 0 : sal_Int16 nLanguage = LinguLocaleToLanguage( rLocale );
421 0 : if (LinguIsUnspecified(nLanguage) || !nWordLen)
422 0 : return xRes;
423 :
424 : // search for entry with that language
425 0 : HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
426 0 : LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
427 :
428 0 : bool bWordModified = false;
429 0 : if (!pEntry || !(0 <= nIndex && nIndex <= nWordLen - 2))
430 : {
431 0 : return NULL;
432 : }
433 : else
434 : {
435 0 : OUString aChkWord( rWord );
436 :
437 : // replace typographical apostroph by ascii apostroph
438 0 : OUString aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
439 : DBG_ASSERT( 1 == aSingleQuote.getLength(), "unexpectend length of quotation mark" );
440 0 : if (!aSingleQuote.isEmpty())
441 0 : aChkWord = aChkWord.replace( aSingleQuote[0], '\'' );
442 :
443 0 : bWordModified |= RemoveHyphens( aChkWord );
444 0 : if (IsIgnoreControlChars( rProperties, GetPropSet() ))
445 0 : bWordModified |= RemoveControlChars( aChkWord );
446 0 : sal_Int16 nChkIndex = (sal_Int16) GetPosInWordToCheck( rWord, nIndex );
447 :
448 : // check for results from (positive) dictionaries which have precedence!
449 0 : Reference< XDictionaryEntry > xEntry;
450 :
451 0 : if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
452 : {
453 0 : xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
454 0 : sal_True, sal_False );
455 : }
456 :
457 0 : if (xEntry.is())
458 : {
459 0 : xRes = buildHyphWord(aChkWord, xEntry, nLanguage, nIndex + 1);
460 0 : if (xRes.is() && xRes->isAlternativeSpelling() && xRes->getHyphenationPos() == nIndex)
461 0 : return xRes;
462 : }
463 : else
464 : {
465 0 : sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
466 : DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
467 : "lng : index out of range");
468 :
469 0 : sal_Int32 i = 0;
470 0 : Reference< XHyphenator > xHyph;
471 0 : if (pEntry->aSvcRefs.getLength() > 0)
472 0 : xHyph = pEntry->aSvcRefs[0];
473 :
474 : // try already instantiated service
475 0 : if (i <= pEntry->nLastTriedSvcIndex)
476 : {
477 0 : if (xHyph.is() && xHyph->hasLocale( rLocale ))
478 0 : xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale,
479 0 : nChkIndex, rProperties );
480 0 : ++i;
481 : }
482 0 : else if (pEntry->nLastTriedSvcIndex < nLen - 1)
483 : // instantiate services and try it
484 : {
485 0 : Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
486 :
487 : Reference< XComponentContext > xContext(
488 0 : comphelper::getProcessComponentContext() );
489 :
490 : // build service initialization argument
491 0 : Sequence< Any > aArgs(2);
492 0 : aArgs.getArray()[0] <<= GetPropSet();
493 :
494 : // create specific service via it's implementation name
495 : try
496 : {
497 0 : xHyph = Reference< XHyphenator >(
498 0 : xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
499 0 : pEntry->aSvcImplNames[0], aArgs, xContext ), UNO_QUERY );
500 : }
501 0 : catch (uno::Exception &)
502 : {
503 : DBG_ASSERT( false, "createInstanceWithArguments failed" );
504 : }
505 0 : pRef [i] = xHyph;
506 :
507 : Reference< XLinguServiceEventBroadcaster >
508 0 : xBroadcaster( xHyph, UNO_QUERY );
509 0 : if (xBroadcaster.is())
510 0 : rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
511 :
512 0 : if (xHyph.is() && xHyph->hasLocale( rLocale ))
513 0 : xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale,
514 0 : nChkIndex, rProperties );
515 :
516 0 : pEntry->nLastTriedSvcIndex = (sal_Int16) i;
517 0 : ++i;
518 :
519 : // if language is not supported by the services
520 : // remove it from the list.
521 0 : if (xHyph.is() && !xHyph->hasLocale( rLocale ))
522 0 : aSvcMap.erase( nLanguage );
523 0 : }
524 0 : } // if (xEntry.is())
525 : }
526 :
527 0 : if (bWordModified && xRes.is())
528 0 : xRes = RebuildHyphensAndControlChars( rWord, xRes );
529 :
530 0 : if (xRes.is() && xRes->getWord() != rWord)
531 : {
532 0 : xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(),
533 0 : xRes->getHyphenatedWord(),
534 0 : xRes->getHyphenPos() );
535 : }
536 :
537 0 : return xRes;
538 : }
539 :
540 :
541 : Reference< XPossibleHyphens > SAL_CALL
542 0 : HyphenatorDispatcher::createPossibleHyphens(
543 : const OUString& rWord, const Locale& rLocale,
544 : const PropertyValues& rProperties )
545 : throw(IllegalArgumentException, RuntimeException, std::exception)
546 : {
547 0 : MutexGuard aGuard( GetLinguMutex() );
548 :
549 0 : Reference< XPossibleHyphens > xRes;
550 :
551 0 : sal_Int16 nLanguage = LinguLocaleToLanguage( rLocale );
552 0 : if (LinguIsUnspecified(nLanguage) || rWord.isEmpty())
553 0 : return xRes;
554 :
555 : // search for entry with that language
556 0 : HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
557 0 : LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
558 :
559 0 : if (pEntry)
560 : {
561 0 : OUString aChkWord( rWord );
562 :
563 : // replace typographical apostroph by ascii apostroph
564 0 : OUString aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
565 : DBG_ASSERT( 1 == aSingleQuote.getLength(), "unexpectend length of quotation mark" );
566 0 : if (!aSingleQuote.isEmpty())
567 0 : aChkWord = aChkWord.replace( aSingleQuote[0], '\'' );
568 :
569 0 : RemoveHyphens( aChkWord );
570 0 : if (IsIgnoreControlChars( rProperties, GetPropSet() ))
571 0 : RemoveControlChars( aChkWord );
572 :
573 : // check for results from (positive) dictionaries which have precedence!
574 0 : Reference< XDictionaryEntry > xEntry;
575 :
576 0 : if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
577 : {
578 0 : xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
579 0 : sal_True, sal_False );
580 : }
581 :
582 0 : if (xEntry.is())
583 : {
584 0 : xRes = buildPossHyphens( xEntry, nLanguage );
585 : }
586 : else
587 : {
588 0 : sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
589 : DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
590 : "lng : index out of range");
591 :
592 0 : sal_Int32 i = 0;
593 0 : Reference< XHyphenator > xHyph;
594 0 : if (pEntry->aSvcRefs.getLength() > 0)
595 0 : xHyph = pEntry->aSvcRefs[0];
596 :
597 : // try already instantiated service
598 0 : if (i <= pEntry->nLastTriedSvcIndex)
599 : {
600 0 : if (xHyph.is() && xHyph->hasLocale( rLocale ))
601 0 : xRes = xHyph->createPossibleHyphens( aChkWord, rLocale,
602 0 : rProperties );
603 0 : ++i;
604 : }
605 0 : else if (pEntry->nLastTriedSvcIndex < nLen - 1)
606 : // instantiate services and try it
607 : {
608 0 : Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
609 :
610 : Reference< XComponentContext > xContext(
611 0 : comphelper::getProcessComponentContext() );
612 :
613 : // build service initialization argument
614 0 : Sequence< Any > aArgs(2);
615 0 : aArgs.getArray()[0] <<= GetPropSet();
616 :
617 : // create specific service via it's implementation name
618 : try
619 : {
620 0 : xHyph = Reference< XHyphenator >(
621 0 : xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
622 0 : pEntry->aSvcImplNames[0], aArgs, xContext ),
623 0 : UNO_QUERY );
624 : }
625 0 : catch (uno::Exception &)
626 : {
627 : DBG_ASSERT( false, "createWithArguments failed" );
628 : }
629 0 : pRef [i] = xHyph;
630 :
631 : Reference< XLinguServiceEventBroadcaster >
632 0 : xBroadcaster( xHyph, UNO_QUERY );
633 0 : if (xBroadcaster.is())
634 0 : rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
635 :
636 0 : if (xHyph.is() && xHyph->hasLocale( rLocale ))
637 0 : xRes = xHyph->createPossibleHyphens( aChkWord, rLocale, rProperties );
638 :
639 0 : pEntry->nLastTriedSvcIndex = (sal_Int16) i;
640 0 : ++i;
641 :
642 : // if language is not supported by the services
643 : // remove it from the list.
644 0 : if (xHyph.is() && !xHyph->hasLocale( rLocale ))
645 0 : aSvcMap.erase( nLanguage );
646 0 : }
647 0 : } // if (xEntry.is())
648 : }
649 :
650 0 : if (xRes.is() && xRes->getWord() != rWord)
651 : {
652 0 : xRes = new PossibleHyphens( rWord, nLanguage,
653 0 : xRes->getPossibleHyphens(),
654 0 : xRes->getHyphenationPositions() );
655 : }
656 :
657 0 : return xRes;
658 : }
659 :
660 :
661 1012 : void HyphenatorDispatcher::SetServiceList( const Locale &rLocale,
662 : const Sequence< OUString > &rSvcImplNames )
663 : {
664 1012 : MutexGuard aGuard( GetLinguMutex() );
665 :
666 1012 : sal_Int16 nLanguage = LinguLocaleToLanguage( rLocale );
667 :
668 1012 : sal_Int32 nLen = rSvcImplNames.getLength();
669 1012 : if (0 == nLen)
670 : // remove entry
671 0 : aSvcMap.erase( nLanguage );
672 : else
673 : {
674 : // modify/add entry
675 1012 : LangSvcEntries_Hyph *pEntry = aSvcMap[ nLanguage ].get();
676 1012 : if (pEntry)
677 : {
678 176 : pEntry->Clear();
679 176 : pEntry->aSvcImplNames = rSvcImplNames;
680 176 : pEntry->aSvcImplNames.realloc(1);
681 176 : pEntry->aSvcRefs = Sequence< Reference < XHyphenator > > ( 1 );
682 : }
683 : else
684 : {
685 836 : boost::shared_ptr< LangSvcEntries_Hyph > pTmpEntry( new LangSvcEntries_Hyph( rSvcImplNames[0] ) );
686 836 : pTmpEntry->aSvcRefs = Sequence< Reference < XHyphenator > >( 1 );
687 836 : aSvcMap[ nLanguage ] = pTmpEntry;
688 : }
689 1012 : }
690 1012 : }
691 :
692 :
693 : Sequence< OUString >
694 0 : HyphenatorDispatcher::GetServiceList( const Locale &rLocale ) const
695 : {
696 0 : MutexGuard aGuard( GetLinguMutex() );
697 :
698 0 : Sequence< OUString > aRes;
699 :
700 : // search for entry with that language and use data from that
701 0 : sal_Int16 nLanguage = LinguLocaleToLanguage( rLocale );
702 0 : const HyphSvcByLangMap_t::const_iterator aIt( aSvcMap.find( nLanguage ) );
703 0 : const LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
704 0 : if (pEntry)
705 : {
706 0 : aRes = pEntry->aSvcImplNames;
707 0 : if (aRes.getLength() > 0)
708 0 : aRes.realloc(1);
709 : }
710 :
711 0 : return aRes;
712 : }
713 :
714 :
715 0 : LinguDispatcher::DspType HyphenatorDispatcher::GetDspType() const
716 : {
717 0 : return DSP_HYPH;
718 : }
719 :
720 :
721 :
722 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|