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
;
63 //!! multi-thread safe mutex for all platforms !!
64 struct LinguMutex
: public rtl::Static
< osl::Mutex
, LinguMutex
>
70 osl::Mutex
& GetLinguMutex()
72 return LinguMutex::get();
75 const LocaleDataWrapper
& GetLocaleDataWrapper( LanguageType nLang
)
77 static LocaleDataWrapper
aLclDtaWrp( SvtSysLocale().GetLanguageTag() );
79 if (nLang
!= aLclDtaWrp
.getLoadedLanguageTag().getLanguageType())
80 aLclDtaWrp
.setLanguageTag( LanguageTag( nLang
) );
84 LanguageType
LinguLocaleToLanguage( const css::lang::Locale
& rLocale
)
86 if ( rLocale
.Language
.isEmpty() )
88 return LanguageTag::convertToLanguageType( rLocale
);
91 css::lang::Locale
LinguLanguageToLocale( LanguageType nLanguage
)
93 if (nLanguage
== LANGUAGE_NONE
)
94 return css::lang::Locale();
95 return LanguageTag::convertToLocale( nLanguage
);
98 bool LinguIsUnspecified( LanguageType nLanguage
)
100 return nLanguage
.anyOf(
102 LANGUAGE_UNDETERMINED
,
106 // When adding anything keep both LinguIsUnspecified() methods in sync!
107 // For mappings between language code string and LanguageType see
108 // i18nlangtag/source/isolang/isolang.cxx
110 bool LinguIsUnspecified( const OUString
& rBcp47
)
112 if (rBcp47
.getLength() != 3)
114 return rBcp47
== "zxx" || rBcp47
== "und" || rBcp47
== "mul";
117 static sal_Int32
Minimum( sal_Int32 n1
, sal_Int32 n2
, sal_Int32 n3
)
119 return std::min(std::min(n1
, n2
), n3
);
127 std::unique_ptr
<sal_Int32
[]> pData
;
131 IntArray2D( int nDim1
, int nDim2
);
133 sal_Int32
& Value( int i
, int k
);
138 IntArray2D::IntArray2D( int nDim1
, int nDim2
)
142 pData
.reset( new sal_Int32
[n1
* n2
] );
145 sal_Int32
& IntArray2D::Value( int i
, int k
)
147 assert( (0 <= i
&& i
< n1
) && "first index out of range" );
148 assert( (0 <= k
&& k
< n2
) && "second index out of range" );
149 assert( (i
* n2
+ k
< n1
* n2
) && "index out of range" );
150 return pData
[ i
* n2
+ k
];
153 sal_Int32
LevDistance( const OUString
&rTxt1
, const OUString
&rTxt2
)
155 sal_Int32 nLen1
= rTxt1
.getLength();
156 sal_Int32 nLen2
= rTxt2
.getLength();
163 IntArray2D
aData( nLen1
+ 1, nLen2
+ 1 );
166 for (i
= 0; i
<= nLen1
; ++i
)
167 aData
.Value(i
, 0) = i
;
168 for (k
= 0; k
<= nLen2
; ++k
)
169 aData
.Value(0, k
) = k
;
170 for (i
= 1; i
<= nLen1
; ++i
)
172 for (k
= 1; k
<= nLen2
; ++k
)
174 sal_Unicode c1i
= rTxt1
[i
- 1];
175 sal_Unicode c2k
= rTxt2
[k
- 1];
176 sal_Int32 nCost
= c1i
== c2k
? 0 : 1;
177 sal_Int32 nNew
= Minimum( aData
.Value(i
-1, k
) + 1,
178 aData
.Value(i
, k
-1) + 1,
179 aData
.Value(i
-1, k
-1) + nCost
);
180 // take transposition (exchange with left or right char) in account
183 int nT
= aData
.Value(i
-2, k
-2) + 1;
184 if (rTxt1
[i
- 2] != c1i
)
186 if (rTxt2
[k
- 2] != c2k
)
192 aData
.Value(i
, k
) = nNew
;
195 sal_Int32 nDist
= aData
.Value(nLen1
, nLen2
);
199 bool IsUseDicList( const PropertyValues
&rProperties
,
200 const uno::Reference
< XPropertySet
> &rxProp
)
204 const PropertyValue
*pVal
= std::find_if(rProperties
.begin(), rProperties
.end(),
205 [](const PropertyValue
& rVal
) { return UPH_IS_USE_DICTIONARY_LIST
== rVal
.Handle
; });
207 if (pVal
!= rProperties
.end())
209 pVal
->Value
>>= bRes
;
211 else // no temporary value found in 'rProperties'
213 uno::Reference
< XFastPropertySet
> xFast( rxProp
, UNO_QUERY
);
215 xFast
->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST
) >>= bRes
;
221 bool IsIgnoreControlChars( const PropertyValues
&rProperties
,
222 const uno::Reference
< XPropertySet
> &rxProp
)
226 const PropertyValue
*pVal
= std::find_if(rProperties
.begin(), rProperties
.end(),
227 [](const PropertyValue
& rVal
) { return UPH_IS_IGNORE_CONTROL_CHARACTERS
== rVal
.Handle
; });
229 if (pVal
!= rProperties
.end())
231 pVal
->Value
>>= bRes
;
233 else // no temporary value found in 'rProperties'
235 uno::Reference
< XFastPropertySet
> xFast( rxProp
, UNO_QUERY
);
237 xFast
->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS
) >>= bRes
;
243 static bool lcl_HasHyphInfo( const uno::Reference
<XDictionaryEntry
> &xEntry
)
248 // there has to be (at least one) '=' or '[' denoting a hyphenation position
249 // and it must not be before any character of the word
250 sal_Int32 nIdx
= xEntry
->getDictionaryWord().indexOf( '=' );
252 nIdx
= xEntry
->getDictionaryWord().indexOf( '[' );
253 bRes
= nIdx
!= -1 && nIdx
!= 0;
258 uno::Reference
< XDictionaryEntry
> SearchDicList(
259 const uno::Reference
< XSearchableDictionaryList
> &xDicList
,
260 const OUString
&rWord
, LanguageType nLanguage
,
261 bool bSearchPosDics
, bool bSearchSpellEntry
)
263 MutexGuard
aGuard( GetLinguMutex() );
265 uno::Reference
< XDictionaryEntry
> xEntry
;
270 const uno::Sequence
< uno::Reference
< XDictionary
> >
271 aDics( xDicList
->getDictionaries() );
272 const uno::Reference
< XDictionary
>
273 *pDic
= aDics
.getConstArray();
274 sal_Int32 nDics
= xDicList
->getCount();
277 for (i
= 0; i
< nDics
; i
++)
279 uno::Reference
< XDictionary
> axDic
= pDic
[i
];
281 DictionaryType eType
= axDic
->getDictionaryType();
282 LanguageType nLang
= LinguLocaleToLanguage( axDic
->getLocale() );
284 if ( axDic
.is() && axDic
->isActive()
285 && (nLang
== nLanguage
|| LinguIsUnspecified( nLang
)) )
287 // DictionaryType_MIXED is deprecated
288 SAL_WARN_IF(eType
== DictionaryType_MIXED
, "linguistic", "unexpected dictionary type");
290 if ( (!bSearchPosDics
&& eType
== DictionaryType_NEGATIVE
)
291 || ( bSearchPosDics
&& eType
== DictionaryType_POSITIVE
))
293 xEntry
= axDic
->getEntry( rWord
);
294 if ( xEntry
.is() && (bSearchSpellEntry
|| lcl_HasHyphInfo( xEntry
)) )
304 bool SaveDictionaries( const uno::Reference
< XSearchableDictionaryList
> &xDicList
)
311 const Sequence
< uno::Reference
< XDictionary
> > aDics( xDicList
->getDictionaries() );
312 for (const uno::Reference
<XDictionary
>& rDic
: aDics
)
316 uno::Reference
< frame::XStorable
> xStor( rDic
, UNO_QUERY
);
319 if (!xStor
->isReadonly() && xStor
->hasLocation())
323 catch(uno::Exception
&)
332 DictionaryError
AddEntryToDic(
333 uno::Reference
< XDictionary
> const &rxDic
,
334 const OUString
&rWord
, bool bIsNeg
,
335 const OUString
&rRplcTxt
,
339 return DictionaryError::NOT_EXISTS
;
341 OUString
aTmp( rWord
);
344 sal_Int32 nLen
= rWord
.getLength();
345 if (nLen
> 0 && '.' == rWord
[ nLen
- 1])
347 // remove trailing '.'
348 // (this is the official way to do this :-( )
349 aTmp
= aTmp
.copy( 0, nLen
- 1 );
352 bool bAddOk
= rxDic
->add( aTmp
, bIsNeg
, rRplcTxt
);
354 DictionaryError nRes
= DictionaryError::NONE
;
358 nRes
= DictionaryError::FULL
;
361 uno::Reference
< frame::XStorable
> xStor( rxDic
, UNO_QUERY
);
362 if (xStor
.is() && xStor
->isReadonly())
363 nRes
= DictionaryError::READONLY
;
365 nRes
= DictionaryError::UNKNOWN
;
372 std::vector
< LanguageType
>
373 LocaleSeqToLangVec( uno::Sequence
< Locale
> const &rLocaleSeq
)
375 std::vector
< LanguageType
> aLangs
;
376 aLangs
.reserve(rLocaleSeq
.getLength());
378 std::transform(rLocaleSeq
.begin(), rLocaleSeq
.end(), std::back_inserter(aLangs
),
379 [](const Locale
& rLocale
) { return LinguLocaleToLanguage(rLocale
); });
384 uno::Sequence
< sal_Int16
>
385 LocaleSeqToLangSeq( uno::Sequence
< Locale
> const &rLocaleSeq
)
387 std::vector
<sal_Int16
> aLangs
;
388 aLangs
.reserve(rLocaleSeq
.getLength());
390 std::transform(rLocaleSeq
.begin(), rLocaleSeq
.end(), std::back_inserter(aLangs
),
391 [](const Locale
& rLocale
) { return static_cast<sal_uInt16
>(LinguLocaleToLanguage(rLocale
)); });
393 return comphelper::containerToSequence(aLangs
);
395 bool IsReadOnly( const OUString
&rURL
, bool *pbExist
)
398 bool bExists
= false;
404 uno::Reference
< css::ucb::XCommandEnvironment
> xCmdEnv
;
405 ::ucbhelper::Content
aContent( rURL
, xCmdEnv
, comphelper::getProcessComponentContext() );
407 bExists
= aContent
.isDocument();
410 Any
aAny( aContent
.getPropertyValue( "IsReadOnly" ) );
425 static bool GetAltSpelling( sal_Int16
&rnChgPos
, sal_Int16
&rnChgLen
, OUString
&rRplc
,
426 uno::Reference
< XHyphenatedWord
> const &rxHyphWord
)
428 bool bRes
= rxHyphWord
->isAlternativeSpelling();
431 OUString
aWord( rxHyphWord
->getWord() ),
432 aHyphenatedWord( rxHyphWord
->getHyphenatedWord() );
433 sal_Int16 nHyphenationPos
= rxHyphWord
->getHyphenationPos();
434 /*sal_Int16 nHyphenPos = rxHyphWord->getHyphenPos()*/;
435 const sal_Unicode
*pWord
= aWord
.getStr(),
436 *pAltWord
= aHyphenatedWord
.getStr();
438 // at least char changes directly left or right to the hyphen
439 // should(!) be handled properly...
440 //! nHyphenationPos and nHyphenPos differ at most by 1 (see above)
441 //! Beware: eg "Schiffahrt" in German (pre spelling reform)
442 //! proves to be a bit nasty (nChgPosLeft and nChgPosRight overlap
445 // find first different char from left
448 for (sal_Int16 i
= 0 ; pWord
[ nPosL
] == pAltWord
[ nAltPosL
]; nPosL
++, nAltPosL
++, i
++)
450 // restrict changes area beginning to the right to
451 // the char immediately following the hyphen.
452 //! serves to insert the additional "f" in "Schiffahrt" at
453 //! position 5 rather than position 6.
454 if (i
>= nHyphenationPos
+ 1)
458 // find first different char from right
459 sal_Int32 nPosR
= aWord
.getLength() - 1,
460 nAltPosR
= aHyphenatedWord
.getLength() - 1;
461 for ( ; nPosR
>= nPosL
&& nAltPosR
>= nAltPosL
462 && pWord
[ nPosR
] == pAltWord
[ nAltPosR
];
466 rnChgPos
= sal::static_int_cast
< sal_Int16
>(nPosL
);
467 rnChgLen
= sal::static_int_cast
< sal_Int16
>(nAltPosR
- nPosL
);
468 assert( rnChgLen
>= 0 && "nChgLen < 0");
470 sal_Int32 nTxtStart
= nPosL
;
471 sal_Int32 nTxtLen
= nAltPosR
- nPosL
+ 1;
472 rRplc
= aHyphenatedWord
.copy( nTxtStart
, nTxtLen
);
477 static sal_Int16
GetOrigWordPos( const OUString
&rOrigWord
, sal_Int16 nPos
)
479 sal_Int32 nLen
= rOrigWord
.getLength();
481 while (nPos
>= 0 && i
++ < nLen
)
483 sal_Unicode cChar
= rOrigWord
[i
];
484 bool bSkip
= IsHyphen( cChar
) || IsControlChar( cChar
);
488 return sal::static_int_cast
< sal_Int16
>((0 <= i
&& i
< nLen
) ? i
: -1);
491 sal_Int32
GetPosInWordToCheck( const OUString
&rTxt
, sal_Int32 nPos
)
494 sal_Int32 nLen
= rTxt
.getLength();
495 if (0 <= nPos
&& nPos
< nLen
)
498 for (sal_Int32 i
= 0; i
< nPos
; ++i
)
500 sal_Unicode cChar
= rTxt
[i
];
501 bool bSkip
= IsHyphen( cChar
) || IsControlChar( cChar
);
509 uno::Reference
< XHyphenatedWord
> RebuildHyphensAndControlChars(
510 const OUString
&rOrigWord
,
511 uno::Reference
< XHyphenatedWord
> const &rxHyphWord
)
513 uno::Reference
< XHyphenatedWord
> xRes
;
514 if (!rOrigWord
.isEmpty() && rxHyphWord
.is())
516 sal_Int16 nChgPos
= 0,
519 bool bAltSpelling
= GetAltSpelling( nChgPos
, nChgLen
, aRplc
, rxHyphWord
);
521 OUString aOrigHyphenatedWord
;
522 sal_Int16 nOrigHyphenPos
= -1;
523 sal_Int16 nOrigHyphenationPos
= -1;
526 aOrigHyphenatedWord
= rOrigWord
;
527 nOrigHyphenPos
= GetOrigWordPos( rOrigWord
, rxHyphWord
->getHyphenPos() );
528 nOrigHyphenationPos
= GetOrigWordPos( rOrigWord
, rxHyphWord
->getHyphenationPos() );
532 //! should at least work with the German words
533 //! B-"u-c-k-er and Sc-hif-fah-rt
535 OUString aLeft
, aRight
;
536 sal_Int16 nPos
= GetOrigWordPos( rOrigWord
, nChgPos
);
538 // get words like Sc-hif-fah-rt to work correct
539 sal_Int16 nHyphenationPos
= rxHyphWord
->getHyphenationPos();
540 if (nChgPos
> nHyphenationPos
)
543 aLeft
= rOrigWord
.copy( 0, nPos
);
544 aRight
= rOrigWord
.copy( nPos
); // FIXME: changes at the right side
546 aOrigHyphenatedWord
= aLeft
+ aRplc
+ aRight
;
548 nOrigHyphenPos
= sal::static_int_cast
< sal_Int16
>(aLeft
.getLength() +
549 rxHyphWord
->getHyphenPos() - nChgPos
);
550 nOrigHyphenationPos
= GetOrigWordPos( rOrigWord
, nHyphenationPos
);
553 if (nOrigHyphenPos
== -1 || nOrigHyphenationPos
== -1)
555 SAL_WARN( "linguistic", "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
559 LanguageType nLang
= LinguLocaleToLanguage( rxHyphWord
->getLocale() );
560 xRes
= new HyphenatedWord(
561 rOrigWord
, nLang
, nOrigHyphenationPos
,
562 aOrigHyphenatedWord
, nOrigHyphenPos
);
569 static CharClass
& lcl_GetCharClass()
571 static CharClass
aCC( LanguageTag( LANGUAGE_ENGLISH_US
));
575 static osl::Mutex
& lcl_GetCharClassMutex()
577 static osl::Mutex aMutex
;
581 bool IsUpper( const OUString
&rText
, sal_Int32 nPos
, sal_Int32 nLen
, LanguageType nLanguage
)
583 MutexGuard
aGuard( lcl_GetCharClassMutex() );
585 CharClass
&rCC
= lcl_GetCharClass();
586 rCC
.setLanguageTag( LanguageTag( nLanguage
));
587 sal_Int32 nFlags
= rCC
.getStringType( rText
, nPos
, nLen
);
588 return (nFlags
& KCharacterType::UPPER
)
589 && !(nFlags
& KCharacterType::LOWER
);
592 CapType
capitalType(const OUString
& aTerm
, CharClass
const * pCC
)
594 sal_Int32 tlen
= aTerm
.getLength();
598 for (sal_Int32 tindex
= 0; tindex
< tlen
; ++tindex
)
600 if (pCC
->getCharacterType(aTerm
,tindex
) &
601 css::i18n::KCharacterType::UPPER
) nc
++;
605 return CapType::NOCAP
;
607 return CapType::ALLCAP
;
608 if ((nc
== 1) && (pCC
->getCharacterType(aTerm
,0) &
609 css::i18n::KCharacterType::UPPER
))
610 return CapType::INITCAP
;
612 return CapType::MIXED
;
614 return CapType::UNKNOWN
;
617 OUString
ToLower( const OUString
&rText
, LanguageType nLanguage
)
619 MutexGuard
aGuard( lcl_GetCharClassMutex() );
621 CharClass
&rCC
= lcl_GetCharClass();
622 rCC
.setLanguageTag( LanguageTag( nLanguage
));
623 return rCC
.lowercase( rText
);
626 // sorted(!) array of unicode ranges for code points that are exclusively(!) used as numbers
627 // and thus may NOT not be part of names or words like the Chinese/Japanese number characters
628 const sal_uInt32 the_aDigitZeroes
[] =
630 0x00000030, //0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE
631 0x00000660, //0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
632 0x000006F0, //06F9 ; Decimal # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
633 0x000007C0, //07C9 ; Decimal # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
634 0x00000966, //096F ; Decimal # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
635 0x000009E6, //09EF ; Decimal # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
636 0x00000A66, //0A6F ; Decimal # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
637 0x00000AE6, //0AEF ; Decimal # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
638 0x00000B66, //0B6F ; Decimal # Nd [10] ODIA DIGIT ZERO..ODIA DIGIT NINE
639 0x00000BE6, //0BEF ; Decimal # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
640 0x00000C66, //0C6F ; Decimal # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
641 0x00000CE6, //0CEF ; Decimal # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
642 0x00000D66, //0D6F ; Decimal # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
643 0x00000E50, //0E59 ; Decimal # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
644 0x00000ED0, //0ED9 ; Decimal # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
645 0x00000F20, //0F29 ; Decimal # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
646 0x00001040, //1049 ; Decimal # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
647 0x00001090, //1099 ; Decimal # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
648 0x000017E0, //17E9 ; Decimal # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
649 0x00001810, //1819 ; Decimal # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
650 0x00001946, //194F ; Decimal # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
651 0x000019D0, //19D9 ; Decimal # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
652 0x00001B50, //1B59 ; Decimal # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
653 0x00001BB0, //1BB9 ; Decimal # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
654 0x00001C40, //1C49 ; Decimal # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
655 0x00001C50, //1C59 ; Decimal # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
656 0x0000A620, //A629 ; Decimal # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
657 0x0000A8D0, //A8D9 ; Decimal # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
658 0x0000A900, //A909 ; Decimal # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
659 0x0000AA50, //AA59 ; Decimal # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
660 0x0000FF10, //FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
661 0x000104A0, //104A9 ; Decimal # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
662 0x0001D7CE //1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
665 bool HasDigits( const OUString
&rText
)
667 const sal_Int32 nLen
= rText
.getLength();
670 while (i
< nLen
) // for all characters ...
672 const sal_uInt32 nCodePoint
= rText
.iterateCodePoints( &i
); // handle unicode surrogates correctly...
673 for (unsigned int nDigitZero
: the_aDigitZeroes
) // ... check in all 0..9 ranges
675 if (nDigitZero
> nCodePoint
)
677 if (/*nDigitZero <= nCodePoint &&*/ nCodePoint
<= nDigitZero
+ 9)
684 bool IsNumeric( const OUString
&rText
)
687 if (!rText
.isEmpty())
689 sal_Int32 nLen
= rText
.getLength();
691 for(sal_Int32 i
= 0; i
< nLen
; ++i
)
693 sal_Unicode cChar
= rText
[ i
];
694 if ( '0' > cChar
|| cChar
> '9' )
704 uno::Reference
< XLinguProperties
> GetLinguProperties()
706 return LinguProperties::create( comphelper::getProcessComponentContext() );
709 uno::Reference
< XSearchableDictionaryList
> GetDictionaryList()
711 uno::Reference
< XComponentContext
> xContext( comphelper::getProcessComponentContext() );
712 uno::Reference
< XSearchableDictionaryList
> xRef
;
715 xRef
= DictionaryList::create(xContext
);
717 catch (const uno::Exception
&)
719 SAL_WARN( "linguistic", "createInstance failed" );
725 uno::Reference
< XDictionary
> GetIgnoreAllList()
727 uno::Reference
< XDictionary
> xRes
;
728 uno::Reference
< XSearchableDictionaryList
> xDL( GetDictionaryList() );
731 std::locale
loc(Translate::Create("svt"));
732 xRes
= xDL
->getDictionaryByName( Translate::get(STR_DESCRIPTION_IGNOREALLLIST
, loc
) );
737 AppExitListener::AppExitListener()
739 // add object to Desktop EventListeners in order to properly call
740 // the AtExit function at application exit.
741 uno::Reference
< XComponentContext
> xContext( comphelper::getProcessComponentContext() );
745 xDesktop
= frame::Desktop::create(xContext
);
747 catch (const uno::Exception
&)
749 SAL_WARN( "linguistic", "createInstance failed" );
753 AppExitListener::~AppExitListener()
757 void AppExitListener::Activate()
760 xDesktop
->addTerminateListener( this );
763 void AppExitListener::Deactivate()
766 xDesktop
->removeTerminateListener( this );
770 AppExitListener::disposing( const EventObject
& rEvtSource
)
772 MutexGuard
aGuard( GetLinguMutex() );
774 if (xDesktop
.is() && rEvtSource
.Source
== xDesktop
)
776 xDesktop
= nullptr; //! release reference to desktop
781 AppExitListener::queryTermination( const EventObject
& /*rEvtSource*/ )
786 AppExitListener::notifyTermination( const EventObject
& rEvtSource
)
788 MutexGuard
aGuard( GetLinguMutex() );
790 if (xDesktop
.is() && rEvtSource
.Source
== xDesktop
)
796 } // namespace linguistic
798 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */