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 file754
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 <sal/macros.h>
21 : #include <tools/string.hxx>
22 : #include <tools/debug.hxx>
23 : #include <unotools/pathoptions.hxx>
24 : #include <svl/lngmisc.hxx>
25 : #include <ucbhelper/content.hxx>
26 : #include <i18nlangtag/languagetag.hxx>
27 : #include <com/sun/star/beans/XPropertySet.hpp>
28 : #include <com/sun/star/beans/XFastPropertySet.hpp>
29 : #include <com/sun/star/beans/XPropertyChangeListener.hpp>
30 : #include <com/sun/star/beans/PropertyValues.hpp>
31 : #include <com/sun/star/frame/XTerminateListener.hpp>
32 : #include <com/sun/star/frame/Desktop.hpp>
33 : #include <com/sun/star/frame/XStorable.hpp>
34 : #include <com/sun/star/linguistic2/DictionaryType.hpp>
35 : #include <com/sun/star/linguistic2/DictionaryList.hpp>
36 : #include <com/sun/star/linguistic2/LinguProperties.hpp>
37 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
38 : #include <com/sun/star/uno/Sequence.hxx>
39 : #include <com/sun/star/uno/Reference.h>
40 : #include <comphelper/processfactory.hxx>
41 : #include <unotools/localedatawrapper.hxx>
42 : #include <unotools/syslocale.hxx>
43 :
44 : #include <rtl/instance.hxx>
45 :
46 : #include "linguistic/misc.hxx"
47 : #include "defs.hxx"
48 : #include "linguistic/lngprops.hxx"
49 : #include "linguistic/hyphdta.hxx"
50 :
51 : using namespace osl;
52 : using namespace com::sun::star;
53 : using namespace com::sun::star::beans;
54 : using namespace com::sun::star::lang;
55 : using namespace com::sun::star::uno;
56 : using namespace com::sun::star::i18n;
57 : using namespace com::sun::star::linguistic2;
58 :
59 :
60 : namespace linguistic
61 : {
62 :
63 :
64 : //!! multi-thread safe mutex for all platforms !!
65 : struct LinguMutex : public rtl::Static< osl::Mutex, LinguMutex >
66 : {
67 : };
68 :
69 2729133 : osl::Mutex & GetLinguMutex()
70 : {
71 2729133 : return LinguMutex::get();
72 : }
73 :
74 :
75 33371 : LocaleDataWrapper & GetLocaleDataWrapper( sal_Int16 nLang )
76 : {
77 33371 : static LocaleDataWrapper aLclDtaWrp( SvtSysLocale().GetLanguageTag() );
78 :
79 33371 : const LanguageTag &rLcl = aLclDtaWrp.getLoadedLanguageTag();
80 66742 : LanguageTag aLcl( nLang );
81 33371 : if (aLcl != rLcl)
82 0 : aLclDtaWrp.setLanguageTag( aLcl );
83 66742 : return aLclDtaWrp;
84 : }
85 :
86 :
87 318076 : LanguageType LinguLocaleToLanguage( const ::com::sun::star::lang::Locale& rLocale )
88 : {
89 318076 : if ( rLocale.Language.isEmpty() )
90 184 : return LANGUAGE_NONE;
91 317892 : return LanguageTag( rLocale ).getLanguageType();
92 : }
93 :
94 :
95 20 : ::com::sun::star::lang::Locale LinguLanguageToLocale( LanguageType nLanguage )
96 : {
97 20 : if (nLanguage == LANGUAGE_NONE)
98 20 : return ::com::sun::star::lang::Locale();
99 0 : return LanguageTag( nLanguage).getLocale();
100 : }
101 :
102 :
103 224245 : bool LinguIsUnspecified( LanguageType nLanguage )
104 : {
105 224245 : switch (nLanguage)
106 : {
107 : case LANGUAGE_NONE:
108 : case LANGUAGE_UNDETERMINED:
109 : case LANGUAGE_MULTIPLE:
110 111695 : return true;
111 : }
112 112550 : return false;
113 : }
114 :
115 :
116 0 : static inline sal_Int32 Minimum( sal_Int32 n1, sal_Int32 n2, sal_Int32 n3 )
117 : {
118 0 : sal_Int32 nMin = n1 < n2 ? n1 : n2;
119 0 : return nMin < n3 ? nMin : n3;
120 : }
121 :
122 : class IntArray2D
123 : {
124 : private:
125 : sal_Int32 *pData;
126 : int n1, n2;
127 :
128 : public:
129 : IntArray2D( int nDim1, int nDim2 );
130 : ~IntArray2D();
131 :
132 : sal_Int32 & Value( int i, int k );
133 : };
134 :
135 0 : IntArray2D::IntArray2D( int nDim1, int nDim2 )
136 : {
137 0 : n1 = nDim1;
138 0 : n2 = nDim2;
139 0 : pData = new sal_Int32[n1 * n2];
140 0 : }
141 :
142 0 : IntArray2D::~IntArray2D()
143 : {
144 0 : delete[] pData;
145 0 : }
146 :
147 0 : sal_Int32 & IntArray2D::Value( int i, int k )
148 : {
149 : DBG_ASSERT( 0 <= i && i < n1, "first index out of range" );
150 : DBG_ASSERT( 0 <= k && k < n2, "first index out of range" );
151 : DBG_ASSERT( i * n2 + k < n1 * n2, "index out of range" );
152 0 : return pData[ i * n2 + k ];
153 : }
154 :
155 :
156 0 : sal_Int32 LevDistance( const OUString &rTxt1, const OUString &rTxt2 )
157 : {
158 0 : sal_Int32 nLen1 = rTxt1.getLength();
159 0 : sal_Int32 nLen2 = rTxt2.getLength();
160 :
161 0 : if (nLen1 == 0)
162 0 : return nLen2;
163 0 : if (nLen2 == 0)
164 0 : return nLen1;
165 :
166 0 : IntArray2D aData( nLen1 + 1, nLen2 + 1 );
167 :
168 : sal_Int32 i, k;
169 0 : for (i = 0; i <= nLen1; ++i)
170 0 : aData.Value(i, 0) = i;
171 0 : for (k = 0; k <= nLen2; ++k)
172 0 : aData.Value(0, k) = k;
173 0 : for (i = 1; i <= nLen1; ++i)
174 : {
175 0 : for (k = 1; k <= nLen2; ++k)
176 : {
177 0 : sal_Unicode c1i = rTxt1.getStr()[i - 1];
178 0 : sal_Unicode c2k = rTxt2.getStr()[k - 1];
179 0 : sal_Int32 nCost = c1i == c2k ? 0 : 1;
180 0 : sal_Int32 nNew = Minimum( aData.Value(i-1, k ) + 1,
181 0 : aData.Value(i , k-1) + 1,
182 0 : aData.Value(i-1, k-1) + nCost );
183 : // take transposition (exchange with left or right char) in account
184 0 : if (2 < i && 2 < k)
185 : {
186 0 : int nT = aData.Value(i-2, k-2) + 1;
187 0 : if (rTxt1.getStr()[i - 2] != c1i)
188 0 : ++nT;
189 0 : if (rTxt2.getStr()[k - 2] != c2k)
190 0 : ++nT;
191 0 : if (nT < nNew)
192 0 : nNew = nT;
193 : }
194 :
195 0 : aData.Value(i, k) = nNew;
196 : }
197 : }
198 0 : sal_Int32 nDist = aData.Value(nLen1, nLen2);
199 0 : return nDist;
200 : }
201 :
202 :
203 33363 : sal_Bool IsUseDicList( const PropertyValues &rProperties,
204 : const uno::Reference< XPropertySet > &rxProp )
205 : {
206 33363 : sal_Bool bRes = sal_True;
207 :
208 33363 : sal_Int32 nLen = rProperties.getLength();
209 33363 : const PropertyValue *pVal = rProperties.getConstArray();
210 : sal_Int32 i;
211 :
212 33363 : for ( i = 0; i < nLen; ++i)
213 : {
214 0 : if (UPH_IS_USE_DICTIONARY_LIST == pVal[i].Handle)
215 : {
216 0 : pVal[i].Value >>= bRes;
217 0 : break;
218 : }
219 : }
220 33363 : if (i >= nLen) // no temporary value found in 'rProperties'
221 : {
222 33363 : uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
223 33363 : if (xFast.is())
224 33363 : xFast->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST ) >>= bRes;
225 : }
226 :
227 33363 : return bRes;
228 : }
229 :
230 :
231 33363 : sal_Bool IsIgnoreControlChars( const PropertyValues &rProperties,
232 : const uno::Reference< XPropertySet > &rxProp )
233 : {
234 33363 : sal_Bool bRes = sal_True;
235 :
236 33363 : sal_Int32 nLen = rProperties.getLength();
237 33363 : const PropertyValue *pVal = rProperties.getConstArray();
238 : sal_Int32 i;
239 :
240 33363 : for ( i = 0; i < nLen; ++i)
241 : {
242 0 : if (UPH_IS_IGNORE_CONTROL_CHARACTERS == pVal[i].Handle)
243 : {
244 0 : pVal[i].Value >>= bRes;
245 0 : break;
246 : }
247 : }
248 33363 : if (i >= nLen) // no temporary value found in 'rProperties'
249 : {
250 33363 : uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
251 33363 : if (xFast.is())
252 33363 : xFast->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS ) >>= bRes;
253 : }
254 :
255 33363 : return bRes;
256 : }
257 :
258 :
259 0 : static sal_Bool lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry )
260 : {
261 0 : sal_Bool bRes = sal_False;
262 0 : if (xEntry.is())
263 : {
264 : // there has to be (at least one) '=' denoting a hyphenation position
265 : // and it must not be before any character of the word
266 0 : sal_Int32 nIdx = xEntry->getDictionaryWord().indexOf( '=' );
267 0 : bRes = nIdx != -1 && nIdx != 0;
268 : }
269 0 : return bRes;
270 : }
271 :
272 :
273 55930 : uno::Reference< XDictionaryEntry > SearchDicList(
274 : const uno::Reference< XSearchableDictionaryList > &xDicList,
275 : const OUString &rWord, sal_Int16 nLanguage,
276 : sal_Bool bSearchPosDics, sal_Bool bSearchSpellEntry )
277 : {
278 55930 : MutexGuard aGuard( GetLinguMutex() );
279 :
280 55930 : uno::Reference< XDictionaryEntry > xEntry;
281 :
282 55930 : if (!xDicList.is())
283 0 : return xEntry;
284 :
285 : const uno::Sequence< uno::Reference< XDictionary > >
286 111860 : aDics( xDicList->getDictionaries() );
287 : const uno::Reference< XDictionary >
288 55930 : *pDic = aDics.getConstArray();
289 55930 : sal_Int32 nDics = xDicList->getCount();
290 :
291 : sal_Int32 i;
292 279182 : for (i = 0; i < nDics; i++)
293 : {
294 223486 : uno::Reference< XDictionary > axDic( pDic[i], UNO_QUERY );
295 :
296 223486 : DictionaryType eType = axDic->getDictionaryType();
297 223486 : sal_Int16 nLang = LinguLocaleToLanguage( axDic->getLocale() );
298 :
299 670458 : if ( axDic.is() && axDic->isActive()
300 446972 : && (nLang == nLanguage || LinguIsUnspecified( nLang)) )
301 : {
302 : DBG_ASSERT( eType != DictionaryType_MIXED,
303 : "lng : unexpected dictionary type" );
304 :
305 167556 : if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE)
306 167556 : || ( bSearchPosDics && eType == DictionaryType_POSITIVE))
307 : {
308 116499 : if ( (xEntry = axDic->getEntry( rWord )).is() )
309 : {
310 234 : if (bSearchSpellEntry || lcl_HasHyphInfo( xEntry ))
311 234 : break;
312 : }
313 116265 : xEntry = 0;
314 : }
315 : }
316 223252 : }
317 :
318 111860 : return xEntry;
319 : }
320 :
321 :
322 0 : sal_Bool SaveDictionaries( const uno::Reference< XSearchableDictionaryList > &xDicList )
323 : {
324 0 : if (!xDicList.is())
325 0 : return sal_True;
326 :
327 0 : sal_Bool bRet = sal_True;
328 :
329 0 : Sequence< uno::Reference< XDictionary > > aDics( xDicList->getDictionaries() );
330 0 : const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
331 0 : sal_Int32 nCount = aDics.getLength();
332 0 : for (sal_Int32 i = 0; i < nCount; i++)
333 : {
334 : try
335 : {
336 0 : uno::Reference< frame::XStorable > xStor( pDic[i], UNO_QUERY );
337 0 : if (xStor.is())
338 : {
339 0 : if (!xStor->isReadonly() && xStor->hasLocation())
340 0 : xStor->store();
341 0 : }
342 : }
343 0 : catch(uno::Exception &)
344 : {
345 0 : bRet = sal_False;
346 : }
347 : }
348 :
349 0 : return bRet;
350 : }
351 :
352 :
353 0 : sal_uInt8 AddEntryToDic(
354 : uno::Reference< XDictionary > &rxDic,
355 : const OUString &rWord, sal_Bool bIsNeg,
356 : const OUString &rRplcTxt, sal_Int16 /* nRplcLang */,
357 : sal_Bool bStripDot )
358 : {
359 0 : if (!rxDic.is())
360 0 : return DIC_ERR_NOT_EXISTS;
361 :
362 0 : OUString aTmp( rWord );
363 0 : if (bStripDot)
364 : {
365 0 : sal_Int32 nLen = rWord.getLength();
366 0 : if (nLen > 0 && '.' == rWord[ nLen - 1])
367 : {
368 : // remove trailing '.'
369 : // (this is the official way to do this :-( )
370 0 : aTmp = aTmp.copy( 0, nLen - 1 );
371 : }
372 : }
373 0 : sal_Bool bAddOk = rxDic->add( aTmp, bIsNeg, rRplcTxt );
374 :
375 0 : sal_uInt8 nRes = DIC_ERR_NONE;
376 0 : if (!bAddOk)
377 : {
378 0 : if (rxDic->isFull())
379 0 : nRes = DIC_ERR_FULL;
380 : else
381 : {
382 0 : uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
383 0 : if (xStor.is() && xStor->isReadonly())
384 0 : nRes = DIC_ERR_READONLY;
385 : else
386 0 : nRes = DIC_ERR_UNKNOWN;
387 : }
388 : }
389 :
390 0 : return nRes;
391 : }
392 :
393 :
394 : uno::Sequence< sal_Int16 >
395 69 : LocaleSeqToLangSeq( uno::Sequence< Locale > &rLocaleSeq )
396 : {
397 69 : const Locale *pLocale = rLocaleSeq.getConstArray();
398 69 : sal_Int32 nCount = rLocaleSeq.getLength();
399 :
400 69 : uno::Sequence< sal_Int16 > aLangs( nCount );
401 69 : sal_Int16 *pLang = aLangs.getArray();
402 621 : for (sal_Int32 i = 0; i < nCount; ++i)
403 : {
404 552 : pLang[i] = LinguLocaleToLanguage( pLocale[i] );
405 : }
406 :
407 69 : return aLangs;
408 : }
409 :
410 :
411 0 : sal_Bool IsReadOnly( const String &rURL, sal_Bool *pbExist )
412 : {
413 0 : sal_Bool bRes = sal_False;
414 0 : sal_Bool bExists = sal_False;
415 :
416 0 : if (rURL.Len() > 0)
417 : {
418 : try
419 : {
420 0 : uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xCmdEnv;
421 0 : ::ucbhelper::Content aContent( rURL, xCmdEnv, comphelper::getProcessComponentContext() );
422 :
423 0 : bExists = aContent.isDocument();
424 0 : if (bExists)
425 : {
426 0 : Any aAny( aContent.getPropertyValue( "IsReadOnly" ) );
427 0 : aAny >>= bRes;
428 0 : }
429 : }
430 0 : catch (Exception &)
431 : {
432 0 : bRes = sal_True;
433 : }
434 : }
435 :
436 0 : if (pbExist)
437 0 : *pbExist = bExists;
438 0 : return bRes;
439 : }
440 :
441 :
442 :
443 0 : static sal_Bool GetAltSpelling( sal_Int16 &rnChgPos, sal_Int16 &rnChgLen, OUString &rRplc,
444 : uno::Reference< XHyphenatedWord > &rxHyphWord )
445 : {
446 0 : sal_Bool bRes = rxHyphWord->isAlternativeSpelling();
447 0 : if (bRes)
448 : {
449 0 : OUString aWord( rxHyphWord->getWord() ),
450 0 : aHyphenatedWord( rxHyphWord->getHyphenatedWord() );
451 0 : sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
452 : /*sal_Int16 nHyphenPos = rxHyphWord->getHyphenPos()*/;
453 0 : const sal_Unicode *pWord = aWord.getStr(),
454 0 : *pAltWord = aHyphenatedWord.getStr();
455 :
456 : // at least char changes directly left or right to the hyphen
457 : // should(!) be handled properly...
458 : //! nHyphenationPos and nHyphenPos differ at most by 1 (see above)
459 : //! Beware: eg "Schiffahrt" in German (pre spelling reform)
460 : //! proves to be a bit nasty (nChgPosLeft and nChgPosRight overlap
461 : //! to an extend.)
462 :
463 : // find first different char from left
464 0 : sal_Int32 nPosL = 0,
465 0 : nAltPosL = 0;
466 0 : for (sal_Int16 i = 0 ; pWord[ nPosL ] == pAltWord[ nAltPosL ]; nPosL++, nAltPosL++, i++)
467 : {
468 : // restrict changes area beginning to the right to
469 : // the char immediately following the hyphen.
470 : //! serves to insert the additional "f" in "Schiffahrt" at
471 : //! position 5 rather than position 6.
472 0 : if (i >= nHyphenationPos + 1)
473 0 : break;
474 : }
475 :
476 : // find first different char from right
477 0 : sal_Int32 nPosR = aWord.getLength() - 1,
478 0 : nAltPosR = aHyphenatedWord.getLength() - 1;
479 0 : for ( ; nPosR >= nPosL && nAltPosR >= nAltPosL
480 0 : && pWord[ nPosR ] == pAltWord[ nAltPosR ];
481 : nPosR--, nAltPosR--)
482 : ;
483 :
484 0 : rnChgPos = sal::static_int_cast< sal_Int16 >(nPosL);
485 0 : rnChgLen = sal::static_int_cast< sal_Int16 >(nPosR - nPosL + 1);
486 : DBG_ASSERT( rnChgLen >= 0, "nChgLen < 0");
487 :
488 0 : sal_Int32 nTxtStart = nPosL;
489 0 : sal_Int32 nTxtLen = nAltPosL - nPosL + 1;
490 0 : rRplc = aHyphenatedWord.copy( nTxtStart, nTxtLen );
491 : }
492 0 : return bRes;
493 : }
494 :
495 :
496 0 : static sal_Int16 GetOrigWordPos( const OUString &rOrigWord, sal_Int16 nPos )
497 : {
498 0 : sal_Int32 nLen = rOrigWord.getLength();
499 0 : sal_Int32 i = -1;
500 0 : while (nPos >= 0 && i++ < nLen)
501 : {
502 0 : sal_Unicode cChar = rOrigWord[i];
503 0 : sal_Bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
504 0 : if (!bSkip)
505 0 : --nPos;
506 : }
507 0 : return sal::static_int_cast< sal_Int16 >((0 <= i && i < nLen) ? i : -1);
508 : }
509 :
510 :
511 43784 : sal_Int32 GetPosInWordToCheck( const OUString &rTxt, sal_Int32 nPos )
512 : {
513 43784 : sal_Int32 nRes = -1;
514 43784 : sal_Int32 nLen = rTxt.getLength();
515 43784 : if (0 <= nPos && nPos < nLen)
516 : {
517 43784 : nRes = 0;
518 89434 : for (sal_Int32 i = 0; i < nPos; ++i)
519 : {
520 45650 : sal_Unicode cChar = rTxt[i];
521 45650 : sal_Bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
522 45650 : if (!bSkip)
523 45650 : ++nRes;
524 : }
525 : }
526 43784 : return nRes;
527 : }
528 :
529 :
530 0 : uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars(
531 : const OUString &rOrigWord,
532 : uno::Reference< XHyphenatedWord > &rxHyphWord )
533 : {
534 0 : uno::Reference< XHyphenatedWord > xRes;
535 0 : if (!rOrigWord.isEmpty() && rxHyphWord.is())
536 : {
537 0 : sal_Int16 nChgPos = 0,
538 0 : nChgLen = 0;
539 0 : OUString aRplc;
540 0 : sal_Bool bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord );
541 : #if OSL_DEBUG_LEVEL > 1
542 : OUString aWord( rxHyphWord->getWord() );
543 : #endif
544 :
545 0 : OUString aOrigHyphenatedWord;
546 0 : sal_Int16 nOrigHyphenPos = -1;
547 0 : sal_Int16 nOrigHyphenationPos = -1;
548 0 : if (!bAltSpelling)
549 : {
550 0 : aOrigHyphenatedWord = rOrigWord;
551 0 : nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() );
552 0 : nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() );
553 : }
554 : else
555 : {
556 : //! should at least work with the German words
557 : //! B�-c-k-er and Sc-hif-fah-rt
558 :
559 0 : OUString aLeft, aRight;
560 0 : sal_Int16 nPos = GetOrigWordPos( rOrigWord, nChgPos );
561 :
562 : // get words like Sc-hif-fah-rt to work correct
563 0 : sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
564 0 : if (nChgPos > nHyphenationPos)
565 0 : --nPos;
566 :
567 0 : aLeft = rOrigWord.copy( 0, nPos );
568 0 : aRight = rOrigWord.copy( nPos + nChgLen );
569 :
570 0 : aOrigHyphenatedWord = aLeft;
571 0 : aOrigHyphenatedWord += aRplc;
572 0 : aOrigHyphenatedWord += aRight;
573 :
574 0 : nOrigHyphenPos = sal::static_int_cast< sal_Int16 >(aLeft.getLength() +
575 0 : rxHyphWord->getHyphenPos() - nChgPos);
576 0 : nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos );
577 : }
578 :
579 0 : if (nOrigHyphenPos == -1 || nOrigHyphenationPos == -1)
580 : {
581 : DBG_ASSERT( 0, "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
582 : }
583 : else
584 : {
585 0 : sal_Int16 nLang = LinguLocaleToLanguage( rxHyphWord->getLocale() );
586 0 : xRes = new HyphenatedWord(
587 : rOrigWord, nLang, nOrigHyphenationPos,
588 0 : aOrigHyphenatedWord, nOrigHyphenPos );
589 0 : }
590 :
591 : }
592 0 : return xRes;
593 : }
594 :
595 :
596 :
597 :
598 5632 : static CharClass & lcl_GetCharClass()
599 : {
600 5632 : static CharClass aCC( LanguageTag( LANGUAGE_ENGLISH_US ));
601 5632 : return aCC;
602 : }
603 :
604 :
605 5632 : osl::Mutex & lcl_GetCharClassMutex()
606 : {
607 5632 : static osl::Mutex aMutex;
608 5632 : return aMutex;
609 : }
610 :
611 :
612 5512 : sal_Bool IsUpper( const String &rText, xub_StrLen nPos, xub_StrLen nLen, sal_Int16 nLanguage )
613 : {
614 5512 : MutexGuard aGuard( lcl_GetCharClassMutex() );
615 :
616 5512 : CharClass &rCC = lcl_GetCharClass();
617 5512 : rCC.setLanguageTag( LanguageTag( nLanguage ));
618 5512 : sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen );
619 5512 : return (nFlags & KCharacterType::UPPER)
620 5512 : && !(nFlags & KCharacterType::LOWER);
621 : }
622 :
623 33129 : CapType SAL_CALL capitalType(const OUString& aTerm, CharClass * pCC)
624 : {
625 33129 : sal_Int32 tlen = aTerm.getLength();
626 33129 : if ((pCC) && (tlen))
627 : {
628 33129 : String aStr(aTerm);
629 33129 : sal_Int32 nc = 0;
630 230252 : for (sal_uInt16 tindex = 0; tindex < tlen; tindex++)
631 : {
632 197123 : if (pCC->getCharacterType(aStr,tindex) &
633 33265 : ::com::sun::star::i18n::KCharacterType::UPPER) nc++;
634 : }
635 :
636 33129 : if (nc == 0)
637 8185 : return CAPTYPE_NOCAP;
638 24944 : if (nc == tlen)
639 3239 : return CAPTYPE_ALLCAP;
640 21705 : if ((nc == 1) && (pCC->getCharacterType(aStr,0) &
641 : ::com::sun::star::i18n::KCharacterType::UPPER))
642 20634 : return CAPTYPE_INITCAP;
643 :
644 1071 : return CAPTYPE_MIXED;
645 : }
646 0 : return CAPTYPE_UNKNOWN;
647 : }
648 :
649 :
650 120 : String ToLower( const String &rText, sal_Int16 nLanguage )
651 : {
652 120 : MutexGuard aGuard( lcl_GetCharClassMutex() );
653 :
654 120 : CharClass &rCC = lcl_GetCharClass();
655 120 : rCC.setLanguageTag( LanguageTag( nLanguage ));
656 120 : return rCC.lowercase( rText );
657 : }
658 :
659 :
660 : // sorted(!) array of unicode ranges for code points that are exclusively(!) used as numbers
661 : // and thus may NOT not be part of names or words like the Chinese/Japanese number characters
662 : static const sal_uInt32 the_aDigitZeroes [] =
663 : {
664 : 0x00000030, //0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE
665 : 0x00000660, //0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
666 : 0x000006F0, //06F9 ; Decimal # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
667 : 0x000007C0, //07C9 ; Decimal # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
668 : 0x00000966, //096F ; Decimal # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
669 : 0x000009E6, //09EF ; Decimal # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
670 : 0x00000A66, //0A6F ; Decimal # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
671 : 0x00000AE6, //0AEF ; Decimal # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
672 : 0x00000B66, //0B6F ; Decimal # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
673 : 0x00000BE6, //0BEF ; Decimal # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
674 : 0x00000C66, //0C6F ; Decimal # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
675 : 0x00000CE6, //0CEF ; Decimal # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
676 : 0x00000D66, //0D6F ; Decimal # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
677 : 0x00000E50, //0E59 ; Decimal # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
678 : 0x00000ED0, //0ED9 ; Decimal # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
679 : 0x00000F20, //0F29 ; Decimal # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
680 : 0x00001040, //1049 ; Decimal # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
681 : 0x00001090, //1099 ; Decimal # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
682 : 0x000017E0, //17E9 ; Decimal # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
683 : 0x00001810, //1819 ; Decimal # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
684 : 0x00001946, //194F ; Decimal # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
685 : 0x000019D0, //19D9 ; Decimal # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
686 : 0x00001B50, //1B59 ; Decimal # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
687 : 0x00001BB0, //1BB9 ; Decimal # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
688 : 0x00001C40, //1C49 ; Decimal # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
689 : 0x00001C50, //1C59 ; Decimal # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
690 : 0x0000A620, //A629 ; Decimal # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
691 : 0x0000A8D0, //A8D9 ; Decimal # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
692 : 0x0000A900, //A909 ; Decimal # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
693 : 0x0000AA50, //AA59 ; Decimal # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
694 : 0x0000FF10, //FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
695 : 0x000104A0, //104A9 ; Decimal # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
696 : 0x0001D7CE //1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
697 : };
698 :
699 5421 : sal_Bool HasDigits( const OUString &rText )
700 : {
701 : static const int nNumDigitZeroes = sizeof(the_aDigitZeroes) / sizeof(the_aDigitZeroes[0]);
702 5421 : const sal_Int32 nLen = rText.getLength();
703 :
704 5421 : sal_Int32 i = 0;
705 28218 : while (i < nLen) // for all characters ...
706 : {
707 21713 : const sal_uInt32 nCodePoint = rText.iterateCodePoints( &i ); // handle unicode surrogates correctly...
708 39049 : for (int j = 0; j < nNumDigitZeroes; ++j) // ... check in all 0..9 ranges
709 : {
710 39049 : sal_uInt32 nDigitZero = the_aDigitZeroes[ j ];
711 39049 : if (nDigitZero > nCodePoint)
712 17376 : break;
713 21673 : if (/*nDigitZero <= nCodePoint &&*/ nCodePoint <= nDigitZero + 9)
714 4337 : return sal_True;
715 : }
716 : }
717 1084 : return sal_False;
718 : }
719 :
720 :
721 0 : sal_Bool IsNumeric( const String &rText )
722 : {
723 0 : sal_Bool bRes = sal_False;
724 0 : xub_StrLen nLen = rText.Len();
725 0 : if (nLen)
726 : {
727 0 : bRes = sal_True;
728 0 : xub_StrLen i = 0;
729 0 : while (i < nLen)
730 : {
731 0 : sal_Unicode cChar = rText.GetChar( i++ );
732 0 : if ( !((sal_Unicode)'0' <= cChar && cChar <= (sal_Unicode)'9') )
733 : {
734 0 : bRes = sal_False;
735 0 : break;
736 : }
737 : }
738 : }
739 0 : return bRes;
740 : }
741 :
742 :
743 :
744 140 : uno::Reference< XLinguProperties > GetLinguProperties()
745 : {
746 140 : return LinguProperties::create( comphelper::getProcessComponentContext() );
747 : }
748 :
749 34110 : uno::Reference< XSearchableDictionaryList > GetDictionaryList()
750 : {
751 34110 : uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
752 34110 : uno::Reference< XSearchableDictionaryList > xRef;
753 : try
754 : {
755 34110 : xRef = DictionaryList::create(xContext);
756 : }
757 0 : catch (const uno::Exception &)
758 : {
759 : DBG_ASSERT( 0, "createInstance failed" );
760 : }
761 :
762 34110 : return xRef;
763 : }
764 :
765 17019 : uno::Reference< XDictionary > GetIgnoreAllList()
766 : {
767 17019 : uno::Reference< XDictionary > xRes;
768 34038 : uno::Reference< XSearchableDictionaryList > xDL( GetDictionaryList() );
769 17019 : if (xDL.is())
770 17019 : xRes = xDL->getDictionaryByName( "IgnoreAllList" );
771 34038 : return xRes;
772 : }
773 :
774 :
775 29 : AppExitListener::AppExitListener()
776 : {
777 : // add object to Desktop EventListeners in order to properly call
778 : // the AtExit function at appliction exit.
779 29 : uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
780 :
781 : try
782 : {
783 29 : xDesktop = frame::Desktop::create(xContext);
784 : }
785 0 : catch (const uno::Exception &)
786 : {
787 : DBG_ASSERT( 0, "createInstance failed" );
788 29 : }
789 29 : }
790 :
791 29 : AppExitListener::~AppExitListener()
792 : {
793 29 : }
794 :
795 :
796 29 : void AppExitListener::Activate()
797 : {
798 29 : if (xDesktop.is())
799 29 : xDesktop->addTerminateListener( this );
800 29 : }
801 :
802 :
803 29 : void AppExitListener::Deactivate()
804 : {
805 29 : if (xDesktop.is())
806 14 : xDesktop->removeTerminateListener( this );
807 29 : }
808 :
809 :
810 : void SAL_CALL
811 15 : AppExitListener::disposing( const EventObject& rEvtSource )
812 : throw(RuntimeException)
813 : {
814 15 : MutexGuard aGuard( GetLinguMutex() );
815 :
816 15 : if (xDesktop.is() && rEvtSource.Source == xDesktop)
817 : {
818 15 : xDesktop = NULL; //! release reference to desktop
819 15 : }
820 15 : }
821 :
822 :
823 : void SAL_CALL
824 21 : AppExitListener::queryTermination( const EventObject& /*rEvtSource*/ )
825 : throw(frame::TerminationVetoException, RuntimeException)
826 : {
827 21 : }
828 :
829 :
830 : void SAL_CALL
831 21 : AppExitListener::notifyTermination( const EventObject& rEvtSource )
832 : throw(RuntimeException)
833 : {
834 21 : MutexGuard aGuard( GetLinguMutex() );
835 :
836 21 : if (xDesktop.is() && rEvtSource.Source == xDesktop)
837 : {
838 21 : AtExit();
839 21 : }
840 21 : }
841 :
842 :
843 : } // namespace linguistic
844 :
845 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|