Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / linguistic / source / misc.cxx
blobef64ac9d25b33d08c4ce0d92b51d64f590ae3813
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <sal/log.hxx>
22 #include <svl/lngmisc.hxx>
23 #include <ucbhelper/content.hxx>
24 #include <i18nlangtag/languagetag.hxx>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/beans/XFastPropertySet.hpp>
27 #include <com/sun/star/beans/PropertyValues.hpp>
28 #include <com/sun/star/frame/Desktop.hpp>
29 #include <com/sun/star/frame/XStorable.hpp>
30 #include <com/sun/star/linguistic2/DictionaryType.hpp>
31 #include <com/sun/star/linguistic2/DictionaryList.hpp>
32 #include <com/sun/star/linguistic2/LinguProperties.hpp>
33 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
34 #include <com/sun/star/uno/Sequence.hxx>
35 #include <com/sun/star/uno/Reference.h>
36 #include <comphelper/processfactory.hxx>
37 #include <comphelper/sequence.hxx>
38 #include <unotools/charclass.hxx>
39 #include <unotools/linguprops.hxx>
40 #include <unotools/localedatawrapper.hxx>
41 #include <unotools/syslocale.hxx>
42 #include <svtools/strings.hrc>
43 #include <unotools/resmgr.hxx>
45 #include <rtl/instance.hxx>
47 #include <linguistic/misc.hxx>
48 #include <linguistic/hyphdta.hxx>
50 using namespace osl;
51 using namespace com::sun::star;
52 using namespace com::sun::star::beans;
53 using namespace com::sun::star::lang;
54 using namespace com::sun::star::uno;
55 using namespace com::sun::star::i18n;
56 using namespace com::sun::star::linguistic2;
58 namespace linguistic
61 //!! multi-thread safe mutex for all platforms !!
62 struct LinguMutex : public rtl::Static< osl::Mutex, LinguMutex >
66 osl::Mutex & GetLinguMutex()
68 return LinguMutex::get();
71 const LocaleDataWrapper & GetLocaleDataWrapper( LanguageType nLang )
73 static LocaleDataWrapper aLclDtaWrp( SvtSysLocale().GetLanguageTag() );
75 if (nLang != aLclDtaWrp.getLoadedLanguageTag().getLanguageType())
76 aLclDtaWrp.setLanguageTag( LanguageTag( nLang ) );
77 return aLclDtaWrp;
80 LanguageType LinguLocaleToLanguage( const css::lang::Locale& rLocale )
82 if ( rLocale.Language.isEmpty() )
83 return LANGUAGE_NONE;
84 return LanguageTag::convertToLanguageType( rLocale );
87 css::lang::Locale LinguLanguageToLocale( LanguageType nLanguage )
89 if (nLanguage == LANGUAGE_NONE)
90 return css::lang::Locale();
91 return LanguageTag::convertToLocale( nLanguage);
94 bool LinguIsUnspecified( LanguageType nLanguage )
96 return nLanguage.anyOf(
97 LANGUAGE_NONE,
98 LANGUAGE_UNDETERMINED,
99 LANGUAGE_MULTIPLE);
102 // When adding anything keep both LinguIsUnspecified() methods in sync!
103 // For mappings between language code string and LanguageType see
104 // i18nlangtag/source/isolang/isolang.cxx
106 bool LinguIsUnspecified( const OUString & rBcp47 )
108 if (rBcp47.getLength() != 3)
109 return false;
110 return rBcp47 == "zxx" || rBcp47 == "und" || rBcp47 == "mul";
113 static sal_Int32 Minimum( sal_Int32 n1, sal_Int32 n2, sal_Int32 n3 )
115 return std::min(std::min(n1, n2), n3);
118 class IntArray2D
120 private:
121 std::unique_ptr<sal_Int32[]> pData;
122 int n1, n2;
124 public:
125 IntArray2D( int nDim1, int nDim2 );
127 sal_Int32 & Value( int i, int k );
130 IntArray2D::IntArray2D( int nDim1, int nDim2 )
132 n1 = nDim1;
133 n2 = nDim2;
134 pData.reset( new sal_Int32[n1 * n2] );
137 sal_Int32 & IntArray2D::Value( int i, int k )
139 assert( (0 <= i && i < n1) && "first index out of range" );
140 assert( (0 <= k && k < n2) && "second index out of range" );
141 assert( (i * n2 + k < n1 * n2) && "index out of range" );
142 return pData[ i * n2 + k ];
145 sal_Int32 LevDistance( const OUString &rTxt1, const OUString &rTxt2 )
147 sal_Int32 nLen1 = rTxt1.getLength();
148 sal_Int32 nLen2 = rTxt2.getLength();
150 if (nLen1 == 0)
151 return nLen2;
152 if (nLen2 == 0)
153 return nLen1;
155 IntArray2D aData( nLen1 + 1, nLen2 + 1 );
157 sal_Int32 i, k;
158 for (i = 0; i <= nLen1; ++i)
159 aData.Value(i, 0) = i;
160 for (k = 0; k <= nLen2; ++k)
161 aData.Value(0, k) = k;
162 for (i = 1; i <= nLen1; ++i)
164 for (k = 1; k <= nLen2; ++k)
166 sal_Unicode c1i = rTxt1[i - 1];
167 sal_Unicode c2k = rTxt2[k - 1];
168 sal_Int32 nCost = c1i == c2k ? 0 : 1;
169 sal_Int32 nNew = Minimum( aData.Value(i-1, k ) + 1,
170 aData.Value(i , k-1) + 1,
171 aData.Value(i-1, k-1) + nCost );
172 // take transposition (exchange with left or right char) in account
173 if (2 < i && 2 < k)
175 int nT = aData.Value(i-2, k-2) + 1;
176 if (rTxt1[i - 2] != c1i)
177 ++nT;
178 if (rTxt2[k - 2] != c2k)
179 ++nT;
180 if (nT < nNew)
181 nNew = nT;
184 aData.Value(i, k) = nNew;
187 sal_Int32 nDist = aData.Value(nLen1, nLen2);
188 return nDist;
191 bool IsUseDicList( const PropertyValues &rProperties,
192 const uno::Reference< XPropertySet > &rxProp )
194 bool bRes = true;
196 const PropertyValue *pVal = std::find_if(rProperties.begin(), rProperties.end(),
197 [](const PropertyValue& rVal) { return UPH_IS_USE_DICTIONARY_LIST == rVal.Handle; });
199 if (pVal != rProperties.end())
201 pVal->Value >>= bRes;
203 else // no temporary value found in 'rProperties'
205 uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
206 if (xFast.is())
207 xFast->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST ) >>= bRes;
210 return bRes;
213 bool IsIgnoreControlChars( const PropertyValues &rProperties,
214 const uno::Reference< XPropertySet > &rxProp )
216 bool bRes = true;
218 const PropertyValue *pVal = std::find_if(rProperties.begin(), rProperties.end(),
219 [](const PropertyValue& rVal) { return UPH_IS_IGNORE_CONTROL_CHARACTERS == rVal.Handle; });
221 if (pVal != rProperties.end())
223 pVal->Value >>= bRes;
225 else // no temporary value found in 'rProperties'
227 uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
228 if (xFast.is())
229 xFast->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS ) >>= bRes;
232 return bRes;
235 static bool lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry )
237 bool bRes = false;
238 if (xEntry.is())
240 // there has to be (at least one) '=' or '[' denoting a hyphenation position
241 // and it must not be before any character of the word
242 sal_Int32 nIdx = xEntry->getDictionaryWord().indexOf( '=' );
243 if (nIdx == -1)
244 nIdx = xEntry->getDictionaryWord().indexOf( '[' );
245 bRes = nIdx != -1 && nIdx != 0;
247 return bRes;
250 uno::Reference< XDictionaryEntry > SearchDicList(
251 const uno::Reference< XSearchableDictionaryList > &xDicList,
252 const OUString &rWord, LanguageType nLanguage,
253 bool bSearchPosDics, bool bSearchSpellEntry )
255 MutexGuard aGuard( GetLinguMutex() );
257 uno::Reference< XDictionaryEntry > xEntry;
259 if (!xDicList.is())
260 return xEntry;
262 const uno::Sequence< uno::Reference< XDictionary > >
263 aDics( xDicList->getDictionaries() );
264 const uno::Reference< XDictionary >
265 *pDic = aDics.getConstArray();
266 sal_Int32 nDics = xDicList->getCount();
268 sal_Int32 i;
269 for (i = 0; i < nDics; i++)
271 uno::Reference< XDictionary > axDic = pDic[i];
273 DictionaryType eType = axDic->getDictionaryType();
274 LanguageType nLang = LinguLocaleToLanguage( axDic->getLocale() );
276 if ( axDic.is() && axDic->isActive()
277 && (nLang == nLanguage || LinguIsUnspecified( nLang)) )
279 // DictionaryType_MIXED is deprecated
280 SAL_WARN_IF(eType == DictionaryType_MIXED, "linguistic", "unexpected dictionary type");
282 if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE)
283 || ( bSearchPosDics && eType == DictionaryType_POSITIVE))
285 if ( (xEntry = axDic->getEntry( rWord )).is() )
287 if (bSearchSpellEntry || lcl_HasHyphInfo( xEntry ))
288 break;
290 xEntry = nullptr;
295 return xEntry;
298 bool SaveDictionaries( const uno::Reference< XSearchableDictionaryList > &xDicList )
300 if (!xDicList.is())
301 return true;
303 bool bRet = true;
305 const Sequence< uno::Reference< XDictionary > > aDics( xDicList->getDictionaries() );
306 for (const uno::Reference<XDictionary>& rDic : aDics)
310 uno::Reference< frame::XStorable > xStor( rDic, UNO_QUERY );
311 if (xStor.is())
313 if (!xStor->isReadonly() && xStor->hasLocation())
314 xStor->store();
317 catch(uno::Exception &)
319 bRet = false;
323 return bRet;
326 DictionaryError AddEntryToDic(
327 uno::Reference< XDictionary > const &rxDic,
328 const OUString &rWord, bool bIsNeg,
329 const OUString &rRplcTxt,
330 bool bStripDot )
332 if (!rxDic.is())
333 return DictionaryError::NOT_EXISTS;
335 OUString aTmp( rWord );
336 if (bStripDot)
338 sal_Int32 nLen = rWord.getLength();
339 if (nLen > 0 && '.' == rWord[ nLen - 1])
341 // remove trailing '.'
342 // (this is the official way to do this :-( )
343 aTmp = aTmp.copy( 0, nLen - 1 );
346 bool bAddOk = rxDic->add( aTmp, bIsNeg, rRplcTxt );
348 DictionaryError nRes = DictionaryError::NONE;
349 if (!bAddOk)
351 if (rxDic->isFull())
352 nRes = DictionaryError::FULL;
353 else
355 uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
356 if (xStor.is() && xStor->isReadonly())
357 nRes = DictionaryError::READONLY;
358 else
359 nRes = DictionaryError::UNKNOWN;
363 return nRes;
366 std::vector< LanguageType >
367 LocaleSeqToLangVec( uno::Sequence< Locale > const &rLocaleSeq )
369 std::vector< LanguageType > aLangs;
370 aLangs.reserve(rLocaleSeq.getLength());
372 std::transform(rLocaleSeq.begin(), rLocaleSeq.end(), std::back_inserter(aLangs),
373 [](const Locale& rLocale) { return LinguLocaleToLanguage(rLocale); });
375 return aLangs;
378 uno::Sequence< sal_Int16 >
379 LocaleSeqToLangSeq( uno::Sequence< Locale > const &rLocaleSeq )
381 std::vector<sal_Int16> aLangs;
382 aLangs.reserve(rLocaleSeq.getLength());
384 std::transform(rLocaleSeq.begin(), rLocaleSeq.end(), std::back_inserter(aLangs),
385 [](const Locale& rLocale) { return static_cast<sal_uInt16>(LinguLocaleToLanguage(rLocale)); });
387 return comphelper::containerToSequence(aLangs);
389 bool IsReadOnly( const OUString &rURL, bool *pbExist )
391 bool bRes = false;
392 bool bExists = false;
394 if (!rURL.isEmpty())
398 uno::Reference< css::ucb::XCommandEnvironment > xCmdEnv;
399 ::ucbhelper::Content aContent( rURL, xCmdEnv, comphelper::getProcessComponentContext() );
401 bExists = aContent.isDocument();
402 if (bExists)
404 Any aAny( aContent.getPropertyValue( "IsReadOnly" ) );
405 aAny >>= bRes;
408 catch (Exception &)
410 bRes = true;
414 if (pbExist)
415 *pbExist = bExists;
416 return bRes;
419 static bool GetAltSpelling( sal_Int16 &rnChgPos, sal_Int16 &rnChgLen, OUString &rRplc,
420 uno::Reference< XHyphenatedWord > const &rxHyphWord )
422 bool bRes = rxHyphWord->isAlternativeSpelling();
423 if (bRes)
425 OUString aWord( rxHyphWord->getWord() ),
426 aHyphenatedWord( rxHyphWord->getHyphenatedWord() );
427 sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
428 /*sal_Int16 nHyphenPos = rxHyphWord->getHyphenPos()*/;
429 const sal_Unicode *pWord = aWord.getStr(),
430 *pAltWord = aHyphenatedWord.getStr();
432 // at least char changes directly left or right to the hyphen
433 // should(!) be handled properly...
434 //! nHyphenationPos and nHyphenPos differ at most by 1 (see above)
435 //! Beware: eg "Schiffahrt" in German (pre spelling reform)
436 //! proves to be a bit nasty (nChgPosLeft and nChgPosRight overlap
437 //! to an extend.)
439 // find first different char from left
440 sal_Int32 nPosL = 0,
441 nAltPosL = 0;
442 for (sal_Int16 i = 0 ; pWord[ nPosL ] == pAltWord[ nAltPosL ]; nPosL++, nAltPosL++, i++)
444 // restrict changes area beginning to the right to
445 // the char immediately following the hyphen.
446 //! serves to insert the additional "f" in "Schiffahrt" at
447 //! position 5 rather than position 6.
448 if (i >= nHyphenationPos + 1)
449 break;
452 // find first different char from right
453 sal_Int32 nPosR = aWord.getLength() - 1,
454 nAltPosR = aHyphenatedWord.getLength() - 1;
455 for ( ; nPosR >= nPosL && nAltPosR >= nAltPosL
456 && pWord[ nPosR ] == pAltWord[ nAltPosR ];
457 nPosR--, nAltPosR--)
460 rnChgPos = sal::static_int_cast< sal_Int16 >(nPosL);
461 rnChgLen = sal::static_int_cast< sal_Int16 >(nAltPosR - nPosL);
462 assert( rnChgLen >= 0 && "nChgLen < 0");
464 sal_Int32 nTxtStart = nPosL;
465 sal_Int32 nTxtLen = nAltPosR - nPosL + 1;
466 rRplc = aHyphenatedWord.copy( nTxtStart, nTxtLen );
468 return bRes;
471 static sal_Int16 GetOrigWordPos( const OUString &rOrigWord, sal_Int16 nPos )
473 sal_Int32 nLen = rOrigWord.getLength();
474 sal_Int32 i = -1;
475 while (nPos >= 0 && i++ < nLen)
477 sal_Unicode cChar = rOrigWord[i];
478 bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
479 if (!bSkip)
480 --nPos;
482 return sal::static_int_cast< sal_Int16 >((0 <= i && i < nLen) ? i : -1);
485 sal_Int32 GetPosInWordToCheck( const OUString &rTxt, sal_Int32 nPos )
487 sal_Int32 nRes = -1;
488 sal_Int32 nLen = rTxt.getLength();
489 if (0 <= nPos && nPos < nLen)
491 nRes = 0;
492 for (sal_Int32 i = 0; i < nPos; ++i)
494 sal_Unicode cChar = rTxt[i];
495 bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
496 if (!bSkip)
497 ++nRes;
500 return nRes;
503 uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars(
504 const OUString &rOrigWord,
505 uno::Reference< XHyphenatedWord > const &rxHyphWord )
507 uno::Reference< XHyphenatedWord > xRes;
508 if (!rOrigWord.isEmpty() && rxHyphWord.is())
510 sal_Int16 nChgPos = 0,
511 nChgLen = 0;
512 OUString aRplc;
513 bool bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord );
515 OUString aOrigHyphenatedWord;
516 sal_Int16 nOrigHyphenPos = -1;
517 sal_Int16 nOrigHyphenationPos = -1;
518 if (!bAltSpelling)
520 aOrigHyphenatedWord = rOrigWord;
521 nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() );
522 nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() );
524 else
526 //! should at least work with the German words
527 //! B-"u-c-k-er and Sc-hif-fah-rt
529 OUString aLeft, aRight;
530 sal_Int16 nPos = GetOrigWordPos( rOrigWord, nChgPos );
532 // get words like Sc-hif-fah-rt to work correct
533 sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
534 if (nChgPos > nHyphenationPos)
535 --nPos;
537 aLeft = rOrigWord.copy( 0, nPos );
538 aRight = rOrigWord.copy( nPos ); // FIXME: changes at the right side
540 aOrigHyphenatedWord = aLeft + aRplc + aRight;
542 nOrigHyphenPos = sal::static_int_cast< sal_Int16 >(aLeft.getLength() +
543 rxHyphWord->getHyphenPos() - nChgPos);
544 nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos );
547 if (nOrigHyphenPos == -1 || nOrigHyphenationPos == -1)
549 SAL_WARN( "linguistic", "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
551 else
553 LanguageType nLang = LinguLocaleToLanguage( rxHyphWord->getLocale() );
554 xRes = new HyphenatedWord(
555 rOrigWord, nLang, nOrigHyphenationPos,
556 aOrigHyphenatedWord, nOrigHyphenPos );
560 return xRes;
563 static CharClass & lcl_GetCharClass()
565 static CharClass aCC( LanguageTag( LANGUAGE_ENGLISH_US ));
566 return aCC;
569 static osl::Mutex & lcl_GetCharClassMutex()
571 static osl::Mutex aMutex;
572 return aMutex;
575 bool IsUpper( const OUString &rText, sal_Int32 nPos, sal_Int32 nLen, LanguageType nLanguage )
577 MutexGuard aGuard( lcl_GetCharClassMutex() );
579 CharClass &rCC = lcl_GetCharClass();
580 rCC.setLanguageTag( LanguageTag( nLanguage ));
581 sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen );
582 return (nFlags & KCharacterType::UPPER)
583 && !(nFlags & KCharacterType::LOWER);
586 CapType capitalType(const OUString& aTerm, CharClass const * pCC)
588 sal_Int32 tlen = aTerm.getLength();
589 if (pCC && tlen)
591 sal_Int32 nc = 0;
592 for (sal_Int32 tindex = 0; tindex < tlen; ++tindex)
594 if (pCC->getCharacterType(aTerm,tindex) &
595 css::i18n::KCharacterType::UPPER) nc++;
598 if (nc == 0)
599 return CapType::NOCAP;
600 if (nc == tlen)
601 return CapType::ALLCAP;
602 if ((nc == 1) && (pCC->getCharacterType(aTerm,0) &
603 css::i18n::KCharacterType::UPPER))
604 return CapType::INITCAP;
606 return CapType::MIXED;
608 return CapType::UNKNOWN;
611 OUString ToLower( const OUString &rText, LanguageType nLanguage )
613 MutexGuard aGuard( lcl_GetCharClassMutex() );
615 CharClass &rCC = lcl_GetCharClass();
616 rCC.setLanguageTag( LanguageTag( nLanguage ));
617 return rCC.lowercase( rText );
620 // sorted(!) array of unicode ranges for code points that are exclusively(!) used as numbers
621 // and thus may NOT not be part of names or words like the Chinese/Japanese number characters
622 static const sal_uInt32 the_aDigitZeroes [] =
624 0x00000030, //0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE
625 0x00000660, //0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
626 0x000006F0, //06F9 ; Decimal # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
627 0x000007C0, //07C9 ; Decimal # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
628 0x00000966, //096F ; Decimal # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
629 0x000009E6, //09EF ; Decimal # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
630 0x00000A66, //0A6F ; Decimal # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
631 0x00000AE6, //0AEF ; Decimal # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
632 0x00000B66, //0B6F ; Decimal # Nd [10] ODIA DIGIT ZERO..ODIA DIGIT NINE
633 0x00000BE6, //0BEF ; Decimal # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
634 0x00000C66, //0C6F ; Decimal # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
635 0x00000CE6, //0CEF ; Decimal # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
636 0x00000D66, //0D6F ; Decimal # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
637 0x00000E50, //0E59 ; Decimal # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
638 0x00000ED0, //0ED9 ; Decimal # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
639 0x00000F20, //0F29 ; Decimal # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
640 0x00001040, //1049 ; Decimal # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
641 0x00001090, //1099 ; Decimal # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
642 0x000017E0, //17E9 ; Decimal # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
643 0x00001810, //1819 ; Decimal # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
644 0x00001946, //194F ; Decimal # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
645 0x000019D0, //19D9 ; Decimal # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
646 0x00001B50, //1B59 ; Decimal # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
647 0x00001BB0, //1BB9 ; Decimal # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
648 0x00001C40, //1C49 ; Decimal # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
649 0x00001C50, //1C59 ; Decimal # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
650 0x0000A620, //A629 ; Decimal # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
651 0x0000A8D0, //A8D9 ; Decimal # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
652 0x0000A900, //A909 ; Decimal # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
653 0x0000AA50, //AA59 ; Decimal # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
654 0x0000FF10, //FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
655 0x000104A0, //104A9 ; Decimal # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
656 0x0001D7CE //1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
659 bool HasDigits( const OUString &rText )
661 const sal_Int32 nLen = rText.getLength();
663 sal_Int32 i = 0;
664 while (i < nLen) // for all characters ...
666 const sal_uInt32 nCodePoint = rText.iterateCodePoints( &i ); // handle unicode surrogates correctly...
667 for (unsigned int nDigitZero : the_aDigitZeroes) // ... check in all 0..9 ranges
669 if (nDigitZero > nCodePoint)
670 break;
671 if (/*nDigitZero <= nCodePoint &&*/ nCodePoint <= nDigitZero + 9)
672 return true;
675 return false;
678 bool IsNumeric( const OUString &rText )
680 bool bRes = false;
681 if (!rText.isEmpty())
683 sal_Int32 nLen = rText.getLength();
684 bRes = true;
685 for(sal_Int32 i = 0; i < nLen; ++i)
687 sal_Unicode cChar = rText[ i ];
688 if ( !('0' <= cChar && cChar <= '9') )
690 bRes = false;
691 break;
695 return bRes;
698 uno::Reference< XLinguProperties > GetLinguProperties()
700 return LinguProperties::create( comphelper::getProcessComponentContext() );
703 uno::Reference< XSearchableDictionaryList > GetDictionaryList()
705 uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
706 uno::Reference< XSearchableDictionaryList > xRef;
709 xRef = DictionaryList::create(xContext);
711 catch (const uno::Exception &)
713 SAL_WARN( "linguistic", "createInstance failed" );
716 return xRef;
719 uno::Reference< XDictionary > GetIgnoreAllList()
721 uno::Reference< XDictionary > xRes;
722 uno::Reference< XSearchableDictionaryList > xDL( GetDictionaryList() );
723 if (xDL.is())
725 std::locale loc(Translate::Create("svt"));
726 xRes = xDL->getDictionaryByName( Translate::get(STR_DESCRIPTION_IGNOREALLLIST, loc) );
728 return xRes;
731 AppExitListener::AppExitListener()
733 // add object to Desktop EventListeners in order to properly call
734 // the AtExit function at application exit.
735 uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
739 xDesktop = frame::Desktop::create(xContext);
741 catch (const uno::Exception &)
743 SAL_WARN( "linguistic", "createInstance failed" );
747 AppExitListener::~AppExitListener()
751 void AppExitListener::Activate()
753 if (xDesktop.is())
754 xDesktop->addTerminateListener( this );
757 void AppExitListener::Deactivate()
759 if (xDesktop.is())
760 xDesktop->removeTerminateListener( this );
763 void SAL_CALL
764 AppExitListener::disposing( const EventObject& rEvtSource )
766 MutexGuard aGuard( GetLinguMutex() );
768 if (xDesktop.is() && rEvtSource.Source == xDesktop)
770 xDesktop = nullptr; //! release reference to desktop
774 void SAL_CALL
775 AppExitListener::queryTermination( const EventObject& /*rEvtSource*/ )
779 void SAL_CALL
780 AppExitListener::notifyTermination( const EventObject& rEvtSource )
782 MutexGuard aGuard( GetLinguMutex() );
784 if (xDesktop.is() && rEvtSource.Source == xDesktop)
786 AtExit();
790 } // namespace linguistic
792 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */