1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
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
;
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
) );
80 LanguageType
LinguLocaleToLanguage( const css::lang::Locale
& rLocale
)
82 if ( rLocale
.Language
.isEmpty() )
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(
98 LANGUAGE_UNDETERMINED
,
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)
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
);
121 std::unique_ptr
<sal_Int32
[]> pData
;
125 IntArray2D( int nDim1
, int nDim2
);
127 sal_Int32
& Value( int i
, int k
);
130 IntArray2D::IntArray2D( int nDim1
, int 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();
155 IntArray2D
aData( nLen1
+ 1, nLen2
+ 1 );
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
175 int nT
= aData
.Value(i
-2, k
-2) + 1;
176 if (rTxt1
[i
- 2] != c1i
)
178 if (rTxt2
[k
- 2] != c2k
)
184 aData
.Value(i
, k
) = nNew
;
187 sal_Int32 nDist
= aData
.Value(nLen1
, nLen2
);
191 bool IsUseDicList( const PropertyValues
&rProperties
,
192 const uno::Reference
< XPropertySet
> &rxProp
)
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
);
207 xFast
->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST
) >>= bRes
;
213 bool IsIgnoreControlChars( const PropertyValues
&rProperties
,
214 const uno::Reference
< XPropertySet
> &rxProp
)
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
);
229 xFast
->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS
) >>= bRes
;
235 static bool lcl_HasHyphInfo( const uno::Reference
<XDictionaryEntry
> &xEntry
)
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( '=' );
244 nIdx
= xEntry
->getDictionaryWord().indexOf( '[' );
245 bRes
= nIdx
!= -1 && nIdx
!= 0;
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
;
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();
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
))
298 bool SaveDictionaries( const uno::Reference
< XSearchableDictionaryList
> &xDicList
)
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
);
313 if (!xStor
->isReadonly() && xStor
->hasLocation())
317 catch(uno::Exception
&)
326 DictionaryError
AddEntryToDic(
327 uno::Reference
< XDictionary
> const &rxDic
,
328 const OUString
&rWord
, bool bIsNeg
,
329 const OUString
&rRplcTxt
,
333 return DictionaryError::NOT_EXISTS
;
335 OUString
aTmp( rWord
);
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
;
352 nRes
= DictionaryError::FULL
;
355 uno::Reference
< frame::XStorable
> xStor( rxDic
, UNO_QUERY
);
356 if (xStor
.is() && xStor
->isReadonly())
357 nRes
= DictionaryError::READONLY
;
359 nRes
= DictionaryError::UNKNOWN
;
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
); });
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
)
392 bool bExists
= false;
398 uno::Reference
< css::ucb::XCommandEnvironment
> xCmdEnv
;
399 ::ucbhelper::Content
aContent( rURL
, xCmdEnv
, comphelper::getProcessComponentContext() );
401 bExists
= aContent
.isDocument();
404 Any
aAny( aContent
.getPropertyValue( "IsReadOnly" ) );
419 static bool GetAltSpelling( sal_Int16
&rnChgPos
, sal_Int16
&rnChgLen
, OUString
&rRplc
,
420 uno::Reference
< XHyphenatedWord
> const &rxHyphWord
)
422 bool bRes
= rxHyphWord
->isAlternativeSpelling();
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
439 // find first different char from left
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)
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
];
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
);
471 static sal_Int16
GetOrigWordPos( const OUString
&rOrigWord
, sal_Int16 nPos
)
473 sal_Int32 nLen
= rOrigWord
.getLength();
475 while (nPos
>= 0 && i
++ < nLen
)
477 sal_Unicode cChar
= rOrigWord
[i
];
478 bool bSkip
= IsHyphen( cChar
) || IsControlChar( cChar
);
482 return sal::static_int_cast
< sal_Int16
>((0 <= i
&& i
< nLen
) ? i
: -1);
485 sal_Int32
GetPosInWordToCheck( const OUString
&rTxt
, sal_Int32 nPos
)
488 sal_Int32 nLen
= rTxt
.getLength();
489 if (0 <= nPos
&& nPos
< nLen
)
492 for (sal_Int32 i
= 0; i
< nPos
; ++i
)
494 sal_Unicode cChar
= rTxt
[i
];
495 bool bSkip
= IsHyphen( cChar
) || IsControlChar( cChar
);
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,
513 bool bAltSpelling
= GetAltSpelling( nChgPos
, nChgLen
, aRplc
, rxHyphWord
);
515 OUString aOrigHyphenatedWord
;
516 sal_Int16 nOrigHyphenPos
= -1;
517 sal_Int16 nOrigHyphenationPos
= -1;
520 aOrigHyphenatedWord
= rOrigWord
;
521 nOrigHyphenPos
= GetOrigWordPos( rOrigWord
, rxHyphWord
->getHyphenPos() );
522 nOrigHyphenationPos
= GetOrigWordPos( rOrigWord
, rxHyphWord
->getHyphenationPos() );
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
)
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" );
553 LanguageType nLang
= LinguLocaleToLanguage( rxHyphWord
->getLocale() );
554 xRes
= new HyphenatedWord(
555 rOrigWord
, nLang
, nOrigHyphenationPos
,
556 aOrigHyphenatedWord
, nOrigHyphenPos
);
563 static CharClass
& lcl_GetCharClass()
565 static CharClass
aCC( LanguageTag( LANGUAGE_ENGLISH_US
));
569 static osl::Mutex
& lcl_GetCharClassMutex()
571 static osl::Mutex 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();
592 for (sal_Int32 tindex
= 0; tindex
< tlen
; ++tindex
)
594 if (pCC
->getCharacterType(aTerm
,tindex
) &
595 css::i18n::KCharacterType::UPPER
) nc
++;
599 return CapType::NOCAP
;
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();
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
)
671 if (/*nDigitZero <= nCodePoint &&*/ nCodePoint
<= nDigitZero
+ 9)
678 bool IsNumeric( const OUString
&rText
)
681 if (!rText
.isEmpty())
683 sal_Int32 nLen
= rText
.getLength();
685 for(sal_Int32 i
= 0; i
< nLen
; ++i
)
687 sal_Unicode cChar
= rText
[ i
];
688 if ( !('0' <= cChar
&& cChar
<= '9') )
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" );
719 uno::Reference
< XDictionary
> GetIgnoreAllList()
721 uno::Reference
< XDictionary
> xRes
;
722 uno::Reference
< XSearchableDictionaryList
> xDL( GetDictionaryList() );
725 std::locale
loc(Translate::Create("svt"));
726 xRes
= xDL
->getDictionaryByName( Translate::get(STR_DESCRIPTION_IGNOREALLLIST
, loc
) );
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()
754 xDesktop
->addTerminateListener( this );
757 void AppExitListener::Deactivate()
760 xDesktop
->removeTerminateListener( this );
764 AppExitListener::disposing( const EventObject
& rEvtSource
)
766 MutexGuard
aGuard( GetLinguMutex() );
768 if (xDesktop
.is() && rEvtSource
.Source
== xDesktop
)
770 xDesktop
= nullptr; //! release reference to desktop
775 AppExitListener::queryTermination( const EventObject
& /*rEvtSource*/ )
780 AppExitListener::notifyTermination( const EventObject
& rEvtSource
)
782 MutexGuard
aGuard( GetLinguMutex() );
784 if (xDesktop
.is() && rEvtSource
.Source
== xDesktop
)
790 } // namespace linguistic
792 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */