bump product version to 4.1.6.2
[LibreOffice.git] / linguistic / source / misc.cxx
blob91c59b5bae7b97bf1c20e452412d8263a06cd8bc
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 <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>
44 #include <rtl/instance.hxx>
46 #include "linguistic/misc.hxx"
47 #include "defs.hxx"
48 #include "linguistic/lngprops.hxx"
49 #include "linguistic/hyphdta.hxx"
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;
60 namespace linguistic
64 //!! multi-thread safe mutex for all platforms !!
65 struct LinguMutex : public rtl::Static< osl::Mutex, LinguMutex >
69 osl::Mutex & GetLinguMutex()
71 return LinguMutex::get();
75 LocaleDataWrapper & GetLocaleDataWrapper( sal_Int16 nLang )
77 static LocaleDataWrapper aLclDtaWrp( SvtSysLocale().GetLanguageTag() );
79 const LanguageTag &rLcl = aLclDtaWrp.getLoadedLanguageTag();
80 LanguageTag aLcl( nLang );
81 if (aLcl != rLcl)
82 aLclDtaWrp.setLanguageTag( aLcl );
83 return aLclDtaWrp;
87 LanguageType LinguLocaleToLanguage( const ::com::sun::star::lang::Locale& rLocale )
89 if ( rLocale.Language.isEmpty() )
90 return LANGUAGE_NONE;
91 return LanguageTag( rLocale ).getLanguageType();
95 ::com::sun::star::lang::Locale LinguLanguageToLocale( LanguageType nLanguage )
97 if (nLanguage == LANGUAGE_NONE)
98 return ::com::sun::star::lang::Locale();
99 return LanguageTag( nLanguage).getLocale();
103 bool LinguIsUnspecified( LanguageType nLanguage )
105 switch (nLanguage)
107 case LANGUAGE_NONE:
108 case LANGUAGE_UNDETERMINED:
109 case LANGUAGE_MULTIPLE:
110 return true;
112 return false;
116 static inline sal_Int32 Minimum( sal_Int32 n1, sal_Int32 n2, sal_Int32 n3 )
118 sal_Int32 nMin = n1 < n2 ? n1 : n2;
119 return nMin < n3 ? nMin : n3;
122 class IntArray2D
124 private:
125 sal_Int32 *pData;
126 int n1, n2;
128 public:
129 IntArray2D( int nDim1, int nDim2 );
130 ~IntArray2D();
132 sal_Int32 & Value( int i, int k );
135 IntArray2D::IntArray2D( int nDim1, int nDim2 )
137 n1 = nDim1;
138 n2 = nDim2;
139 pData = new sal_Int32[n1 * n2];
142 IntArray2D::~IntArray2D()
144 delete[] pData;
147 sal_Int32 & IntArray2D::Value( int i, int k )
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 return pData[ i * n2 + k ];
156 sal_Int32 LevDistance( const OUString &rTxt1, const OUString &rTxt2 )
158 sal_Int32 nLen1 = rTxt1.getLength();
159 sal_Int32 nLen2 = rTxt2.getLength();
161 if (nLen1 == 0)
162 return nLen2;
163 if (nLen2 == 0)
164 return nLen1;
166 IntArray2D aData( nLen1 + 1, nLen2 + 1 );
168 sal_Int32 i, k;
169 for (i = 0; i <= nLen1; ++i)
170 aData.Value(i, 0) = i;
171 for (k = 0; k <= nLen2; ++k)
172 aData.Value(0, k) = k;
173 for (i = 1; i <= nLen1; ++i)
175 for (k = 1; k <= nLen2; ++k)
177 sal_Unicode c1i = rTxt1.getStr()[i - 1];
178 sal_Unicode c2k = rTxt2.getStr()[k - 1];
179 sal_Int32 nCost = c1i == c2k ? 0 : 1;
180 sal_Int32 nNew = Minimum( aData.Value(i-1, k ) + 1,
181 aData.Value(i , k-1) + 1,
182 aData.Value(i-1, k-1) + nCost );
183 // take transposition (exchange with left or right char) in account
184 if (2 < i && 2 < k)
186 int nT = aData.Value(i-2, k-2) + 1;
187 if (rTxt1.getStr()[i - 2] != c1i)
188 ++nT;
189 if (rTxt2.getStr()[k - 2] != c2k)
190 ++nT;
191 if (nT < nNew)
192 nNew = nT;
195 aData.Value(i, k) = nNew;
198 sal_Int32 nDist = aData.Value(nLen1, nLen2);
199 return nDist;
203 sal_Bool IsUseDicList( const PropertyValues &rProperties,
204 const uno::Reference< XPropertySet > &rxProp )
206 sal_Bool bRes = sal_True;
208 sal_Int32 nLen = rProperties.getLength();
209 const PropertyValue *pVal = rProperties.getConstArray();
210 sal_Int32 i;
212 for ( i = 0; i < nLen; ++i)
214 if (UPH_IS_USE_DICTIONARY_LIST == pVal[i].Handle)
216 pVal[i].Value >>= bRes;
217 break;
220 if (i >= nLen) // no temporary value found in 'rProperties'
222 uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
223 if (xFast.is())
224 xFast->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST ) >>= bRes;
227 return bRes;
231 sal_Bool IsIgnoreControlChars( const PropertyValues &rProperties,
232 const uno::Reference< XPropertySet > &rxProp )
234 sal_Bool bRes = sal_True;
236 sal_Int32 nLen = rProperties.getLength();
237 const PropertyValue *pVal = rProperties.getConstArray();
238 sal_Int32 i;
240 for ( i = 0; i < nLen; ++i)
242 if (UPH_IS_IGNORE_CONTROL_CHARACTERS == pVal[i].Handle)
244 pVal[i].Value >>= bRes;
245 break;
248 if (i >= nLen) // no temporary value found in 'rProperties'
250 uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
251 if (xFast.is())
252 xFast->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS ) >>= bRes;
255 return bRes;
259 static sal_Bool lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry )
261 sal_Bool bRes = sal_False;
262 if (xEntry.is())
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 sal_Int32 nIdx = xEntry->getDictionaryWord().indexOf( '=' );
267 bRes = nIdx != -1 && nIdx != 0;
269 return bRes;
273 uno::Reference< XDictionaryEntry > SearchDicList(
274 const uno::Reference< XSearchableDictionaryList > &xDicList,
275 const OUString &rWord, sal_Int16 nLanguage,
276 sal_Bool bSearchPosDics, sal_Bool bSearchSpellEntry )
278 MutexGuard aGuard( GetLinguMutex() );
280 uno::Reference< XDictionaryEntry > xEntry;
282 if (!xDicList.is())
283 return xEntry;
285 const uno::Sequence< uno::Reference< XDictionary > >
286 aDics( xDicList->getDictionaries() );
287 const uno::Reference< XDictionary >
288 *pDic = aDics.getConstArray();
289 sal_Int32 nDics = xDicList->getCount();
291 sal_Int32 i;
292 for (i = 0; i < nDics; i++)
294 uno::Reference< XDictionary > axDic( pDic[i], UNO_QUERY );
296 DictionaryType eType = axDic->getDictionaryType();
297 sal_Int16 nLang = LinguLocaleToLanguage( axDic->getLocale() );
299 if ( axDic.is() && axDic->isActive()
300 && (nLang == nLanguage || LinguIsUnspecified( nLang)) )
302 DBG_ASSERT( eType != DictionaryType_MIXED,
303 "lng : unexpected dictionary type" );
305 if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE)
306 || ( bSearchPosDics && eType == DictionaryType_POSITIVE))
308 if ( (xEntry = axDic->getEntry( rWord )).is() )
310 if (bSearchSpellEntry || lcl_HasHyphInfo( xEntry ))
311 break;
313 xEntry = 0;
318 return xEntry;
322 sal_Bool SaveDictionaries( const uno::Reference< XSearchableDictionaryList > &xDicList )
324 if (!xDicList.is())
325 return sal_True;
327 sal_Bool bRet = sal_True;
329 Sequence< uno::Reference< XDictionary > > aDics( xDicList->getDictionaries() );
330 const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
331 sal_Int32 nCount = aDics.getLength();
332 for (sal_Int32 i = 0; i < nCount; i++)
336 uno::Reference< frame::XStorable > xStor( pDic[i], UNO_QUERY );
337 if (xStor.is())
339 if (!xStor->isReadonly() && xStor->hasLocation())
340 xStor->store();
343 catch(uno::Exception &)
345 bRet = sal_False;
349 return bRet;
353 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 )
359 if (!rxDic.is())
360 return DIC_ERR_NOT_EXISTS;
362 OUString aTmp( rWord );
363 if (bStripDot)
365 sal_Int32 nLen = rWord.getLength();
366 if (nLen > 0 && '.' == rWord[ nLen - 1])
368 // remove trailing '.'
369 // (this is the official way to do this :-( )
370 aTmp = aTmp.copy( 0, nLen - 1 );
373 sal_Bool bAddOk = rxDic->add( aTmp, bIsNeg, rRplcTxt );
375 sal_uInt8 nRes = DIC_ERR_NONE;
376 if (!bAddOk)
378 if (rxDic->isFull())
379 nRes = DIC_ERR_FULL;
380 else
382 uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
383 if (xStor.is() && xStor->isReadonly())
384 nRes = DIC_ERR_READONLY;
385 else
386 nRes = DIC_ERR_UNKNOWN;
390 return nRes;
394 uno::Sequence< sal_Int16 >
395 LocaleSeqToLangSeq( uno::Sequence< Locale > &rLocaleSeq )
397 const Locale *pLocale = rLocaleSeq.getConstArray();
398 sal_Int32 nCount = rLocaleSeq.getLength();
400 uno::Sequence< sal_Int16 > aLangs( nCount );
401 sal_Int16 *pLang = aLangs.getArray();
402 for (sal_Int32 i = 0; i < nCount; ++i)
404 pLang[i] = LinguLocaleToLanguage( pLocale[i] );
407 return aLangs;
411 sal_Bool IsReadOnly( const String &rURL, sal_Bool *pbExist )
413 sal_Bool bRes = sal_False;
414 sal_Bool bExists = sal_False;
416 if (rURL.Len() > 0)
420 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xCmdEnv;
421 ::ucbhelper::Content aContent( rURL, xCmdEnv, comphelper::getProcessComponentContext() );
423 bExists = aContent.isDocument();
424 if (bExists)
426 Any aAny( aContent.getPropertyValue( "IsReadOnly" ) );
427 aAny >>= bRes;
430 catch (Exception &)
432 bRes = sal_True;
436 if (pbExist)
437 *pbExist = bExists;
438 return bRes;
443 static sal_Bool GetAltSpelling( sal_Int16 &rnChgPos, sal_Int16 &rnChgLen, OUString &rRplc,
444 uno::Reference< XHyphenatedWord > &rxHyphWord )
446 sal_Bool bRes = rxHyphWord->isAlternativeSpelling();
447 if (bRes)
449 OUString aWord( rxHyphWord->getWord() ),
450 aHyphenatedWord( rxHyphWord->getHyphenatedWord() );
451 sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
452 /*sal_Int16 nHyphenPos = rxHyphWord->getHyphenPos()*/;
453 const sal_Unicode *pWord = aWord.getStr(),
454 *pAltWord = aHyphenatedWord.getStr();
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.)
463 // find first different char from left
464 sal_Int32 nPosL = 0,
465 nAltPosL = 0;
466 for (sal_Int16 i = 0 ; pWord[ nPosL ] == pAltWord[ nAltPosL ]; nPosL++, nAltPosL++, i++)
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 if (i >= nHyphenationPos + 1)
473 break;
476 // find first different char from right
477 sal_Int32 nPosR = aWord.getLength() - 1,
478 nAltPosR = aHyphenatedWord.getLength() - 1;
479 for ( ; nPosR >= nPosL && nAltPosR >= nAltPosL
480 && pWord[ nPosR ] == pAltWord[ nAltPosR ];
481 nPosR--, nAltPosR--)
484 rnChgPos = sal::static_int_cast< sal_Int16 >(nPosL);
485 rnChgLen = sal::static_int_cast< sal_Int16 >(nPosR - nPosL + 1);
486 DBG_ASSERT( rnChgLen >= 0, "nChgLen < 0");
488 sal_Int32 nTxtStart = nPosL;
489 sal_Int32 nTxtLen = nAltPosL - nPosL + 1;
490 rRplc = aHyphenatedWord.copy( nTxtStart, nTxtLen );
492 return bRes;
496 static sal_Int16 GetOrigWordPos( const OUString &rOrigWord, sal_Int16 nPos )
498 sal_Int32 nLen = rOrigWord.getLength();
499 sal_Int32 i = -1;
500 while (nPos >= 0 && i++ < nLen)
502 sal_Unicode cChar = rOrigWord[i];
503 sal_Bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
504 if (!bSkip)
505 --nPos;
507 return sal::static_int_cast< sal_Int16 >((0 <= i && i < nLen) ? i : -1);
511 sal_Int32 GetPosInWordToCheck( const OUString &rTxt, sal_Int32 nPos )
513 sal_Int32 nRes = -1;
514 sal_Int32 nLen = rTxt.getLength();
515 if (0 <= nPos && nPos < nLen)
517 nRes = 0;
518 for (sal_Int32 i = 0; i < nPos; ++i)
520 sal_Unicode cChar = rTxt[i];
521 sal_Bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
522 if (!bSkip)
523 ++nRes;
526 return nRes;
530 uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars(
531 const OUString &rOrigWord,
532 uno::Reference< XHyphenatedWord > &rxHyphWord )
534 uno::Reference< XHyphenatedWord > xRes;
535 if (!rOrigWord.isEmpty() && rxHyphWord.is())
537 sal_Int16 nChgPos = 0,
538 nChgLen = 0;
539 OUString aRplc;
540 sal_Bool bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord );
541 #if OSL_DEBUG_LEVEL > 1
542 OUString aWord( rxHyphWord->getWord() );
543 #endif
545 OUString aOrigHyphenatedWord;
546 sal_Int16 nOrigHyphenPos = -1;
547 sal_Int16 nOrigHyphenationPos = -1;
548 if (!bAltSpelling)
550 aOrigHyphenatedWord = rOrigWord;
551 nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() );
552 nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() );
554 else
556 //! should at least work with the German words
557 //! B�-c-k-er and Sc-hif-fah-rt
559 OUString aLeft, aRight;
560 sal_Int16 nPos = GetOrigWordPos( rOrigWord, nChgPos );
562 // get words like Sc-hif-fah-rt to work correct
563 sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
564 if (nChgPos > nHyphenationPos)
565 --nPos;
567 aLeft = rOrigWord.copy( 0, nPos );
568 aRight = rOrigWord.copy( nPos + nChgLen );
570 aOrigHyphenatedWord = aLeft;
571 aOrigHyphenatedWord += aRplc;
572 aOrigHyphenatedWord += aRight;
574 nOrigHyphenPos = sal::static_int_cast< sal_Int16 >(aLeft.getLength() +
575 rxHyphWord->getHyphenPos() - nChgPos);
576 nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos );
579 if (nOrigHyphenPos == -1 || nOrigHyphenationPos == -1)
581 DBG_ASSERT( 0, "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
583 else
585 sal_Int16 nLang = LinguLocaleToLanguage( rxHyphWord->getLocale() );
586 xRes = new HyphenatedWord(
587 rOrigWord, nLang, nOrigHyphenationPos,
588 aOrigHyphenatedWord, nOrigHyphenPos );
592 return xRes;
598 static CharClass & lcl_GetCharClass()
600 static CharClass aCC( LanguageTag( LANGUAGE_ENGLISH_US ));
601 return aCC;
605 osl::Mutex & lcl_GetCharClassMutex()
607 static osl::Mutex aMutex;
608 return aMutex;
612 sal_Bool IsUpper( const String &rText, xub_StrLen nPos, xub_StrLen nLen, sal_Int16 nLanguage )
614 MutexGuard aGuard( lcl_GetCharClassMutex() );
616 CharClass &rCC = lcl_GetCharClass();
617 rCC.setLanguageTag( LanguageTag( nLanguage ));
618 sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen );
619 return (nFlags & KCharacterType::UPPER)
620 && !(nFlags & KCharacterType::LOWER);
623 CapType SAL_CALL capitalType(const OUString& aTerm, CharClass * pCC)
625 sal_Int32 tlen = aTerm.getLength();
626 if ((pCC) && (tlen))
628 String aStr(aTerm);
629 sal_Int32 nc = 0;
630 for (sal_uInt16 tindex = 0; tindex < tlen; tindex++)
632 if (pCC->getCharacterType(aStr,tindex) &
633 ::com::sun::star::i18n::KCharacterType::UPPER) nc++;
636 if (nc == 0)
637 return CAPTYPE_NOCAP;
638 if (nc == tlen)
639 return CAPTYPE_ALLCAP;
640 if ((nc == 1) && (pCC->getCharacterType(aStr,0) &
641 ::com::sun::star::i18n::KCharacterType::UPPER))
642 return CAPTYPE_INITCAP;
644 return CAPTYPE_MIXED;
646 return CAPTYPE_UNKNOWN;
650 String ToLower( const String &rText, sal_Int16 nLanguage )
652 MutexGuard aGuard( lcl_GetCharClassMutex() );
654 CharClass &rCC = lcl_GetCharClass();
655 rCC.setLanguageTag( LanguageTag( nLanguage ));
656 return rCC.lowercase( rText );
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 [] =
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
699 sal_Bool HasDigits( const OUString &rText )
701 static const int nNumDigitZeroes = sizeof(the_aDigitZeroes) / sizeof(the_aDigitZeroes[0]);
702 const sal_Int32 nLen = rText.getLength();
704 sal_Int32 i = 0;
705 while (i < nLen) // for all characters ...
707 const sal_uInt32 nCodePoint = rText.iterateCodePoints( &i ); // handle unicode surrogates correctly...
708 for (int j = 0; j < nNumDigitZeroes; ++j) // ... check in all 0..9 ranges
710 sal_uInt32 nDigitZero = the_aDigitZeroes[ j ];
711 if (nDigitZero > nCodePoint)
712 break;
713 if (/*nDigitZero <= nCodePoint &&*/ nCodePoint <= nDigitZero + 9)
714 return sal_True;
717 return sal_False;
721 sal_Bool IsNumeric( const String &rText )
723 sal_Bool bRes = sal_False;
724 xub_StrLen nLen = rText.Len();
725 if (nLen)
727 bRes = sal_True;
728 xub_StrLen i = 0;
729 while (i < nLen)
731 sal_Unicode cChar = rText.GetChar( i++ );
732 if ( !((sal_Unicode)'0' <= cChar && cChar <= (sal_Unicode)'9') )
734 bRes = sal_False;
735 break;
739 return bRes;
744 uno::Reference< XLinguProperties > GetLinguProperties()
746 return LinguProperties::create( comphelper::getProcessComponentContext() );
749 uno::Reference< XSearchableDictionaryList > GetDictionaryList()
751 uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
752 uno::Reference< XSearchableDictionaryList > xRef;
755 xRef = DictionaryList::create(xContext);
757 catch (const uno::Exception &)
759 DBG_ASSERT( 0, "createInstance failed" );
762 return xRef;
765 uno::Reference< XDictionary > GetIgnoreAllList()
767 uno::Reference< XDictionary > xRes;
768 uno::Reference< XSearchableDictionaryList > xDL( GetDictionaryList() );
769 if (xDL.is())
770 xRes = xDL->getDictionaryByName( "IgnoreAllList" );
771 return xRes;
775 AppExitListener::AppExitListener()
777 // add object to Desktop EventListeners in order to properly call
778 // the AtExit function at appliction exit.
779 uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
783 xDesktop = frame::Desktop::create(xContext);
785 catch (const uno::Exception &)
787 DBG_ASSERT( 0, "createInstance failed" );
791 AppExitListener::~AppExitListener()
796 void AppExitListener::Activate()
798 if (xDesktop.is())
799 xDesktop->addTerminateListener( this );
803 void AppExitListener::Deactivate()
805 if (xDesktop.is())
806 xDesktop->removeTerminateListener( this );
810 void SAL_CALL
811 AppExitListener::disposing( const EventObject& rEvtSource )
812 throw(RuntimeException)
814 MutexGuard aGuard( GetLinguMutex() );
816 if (xDesktop.is() && rEvtSource.Source == xDesktop)
818 xDesktop = NULL; //! release reference to desktop
823 void SAL_CALL
824 AppExitListener::queryTermination( const EventObject& /*rEvtSource*/ )
825 throw(frame::TerminationVetoException, RuntimeException)
830 void SAL_CALL
831 AppExitListener::notifyTermination( const EventObject& rEvtSource )
832 throw(RuntimeException)
834 MutexGuard aGuard( GetLinguMutex() );
836 if (xDesktop.is() && rEvtSource.Source == xDesktop)
838 AtExit();
843 } // namespace linguistic
845 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */