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 .
22 #include <sal/log.hxx>
23 #include <svl/lngmisc.hxx>
24 #include <ucbhelper/content.hxx>
25 #include <i18nlangtag/languagetag.hxx>
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/beans/XFastPropertySet.hpp>
28 #include <com/sun/star/beans/PropertyValues.hpp>
29 #include <com/sun/star/frame/Desktop.hpp>
30 #include <com/sun/star/frame/XStorable.hpp>
31 #include <com/sun/star/linguistic2/DictionaryType.hpp>
32 #include <com/sun/star/linguistic2/DictionaryList.hpp>
33 #include <com/sun/star/linguistic2/LinguProperties.hpp>
34 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
35 #include <com/sun/star/uno/Sequence.hxx>
36 #include <com/sun/star/uno/Reference.h>
37 #include <comphelper/processfactory.hxx>
38 #include <comphelper/sequence.hxx>
39 #include <unotools/charclass.hxx>
40 #include <unotools/linguprops.hxx>
41 #include <unotools/localedatawrapper.hxx>
42 #include <svtools/strings.hrc>
43 #include <unotools/resmgr.hxx>
45 #include <linguistic/misc.hxx>
46 #include <linguistic/hyphdta.hxx>
49 using namespace com::sun::star
;
50 using namespace com::sun::star::beans
;
51 using namespace com::sun::star::lang
;
52 using namespace com::sun::star::uno
;
53 using namespace com::sun::star::i18n
;
54 using namespace com::sun::star::linguistic2
;
59 //!! multi-thread safe mutex for all platforms !!
60 osl::Mutex
& GetLinguMutex()
62 static osl::Mutex SINGLETON
;
66 const LocaleDataWrapper
& GetLocaleDataWrapper( LanguageType nLang
)
68 static std::optional
<LocaleDataWrapper
> oLclDtaWrp
;
69 if (!oLclDtaWrp
|| oLclDtaWrp
->getLoadedLanguageTag().getLanguageType() != nLang
)
70 oLclDtaWrp
.emplace(LanguageTag( nLang
));
74 LanguageType
LinguLocaleToLanguage( const css::lang::Locale
& rLocale
)
76 if ( rLocale
.Language
.isEmpty() )
78 return LanguageTag::convertToLanguageType( rLocale
);
81 css::lang::Locale
LinguLanguageToLocale( LanguageType nLanguage
)
83 if (nLanguage
== LANGUAGE_NONE
)
84 return css::lang::Locale();
85 return LanguageTag::convertToLocale( nLanguage
);
88 bool LinguIsUnspecified( LanguageType nLanguage
)
90 return nLanguage
.anyOf(
92 LANGUAGE_UNDETERMINED
,
96 // When adding anything keep both LinguIsUnspecified() methods in sync!
97 // For mappings between language code string and LanguageType see
98 // i18nlangtag/source/isolang/isolang.cxx
100 bool LinguIsUnspecified( std::u16string_view rBcp47
)
102 if (rBcp47
.size() != 3)
104 return rBcp47
== u
"zxx" || rBcp47
== u
"und" || rBcp47
== u
"mul";
107 static sal_Int32
Minimum( sal_Int32 n1
, sal_Int32 n2
, sal_Int32 n3
)
109 return std::min(std::min(n1
, n2
), n3
);
117 std::unique_ptr
<sal_Int32
[]> pData
;
121 IntArray2D( int nDim1
, int nDim2
);
123 sal_Int32
& Value( int i
, int k
);
128 IntArray2D::IntArray2D( int nDim1
, int nDim2
)
132 pData
.reset( new sal_Int32
[n1
* n2
] );
135 sal_Int32
& IntArray2D::Value( int i
, int k
)
137 assert( (0 <= i
&& i
< n1
) && "first index out of range" );
138 assert( (0 <= k
&& k
< n2
) && "second index out of range" );
139 assert( (i
* n2
+ k
< n1
* n2
) && "index out of range" );
140 return pData
[ i
* n2
+ k
];
143 sal_Int32
LevDistance( std::u16string_view rTxt1
, std::u16string_view rTxt2
)
145 sal_Int32 nLen1
= rTxt1
.size();
146 sal_Int32 nLen2
= rTxt2
.size();
153 IntArray2D
aData( nLen1
+ 1, nLen2
+ 1 );
156 for (i
= 0; i
<= nLen1
; ++i
)
157 aData
.Value(i
, 0) = i
;
158 for (k
= 0; k
<= nLen2
; ++k
)
159 aData
.Value(0, k
) = k
;
160 for (i
= 1; i
<= nLen1
; ++i
)
162 for (k
= 1; k
<= nLen2
; ++k
)
164 sal_Unicode c1i
= rTxt1
[i
- 1];
165 sal_Unicode c2k
= rTxt2
[k
- 1];
166 sal_Int32 nCost
= c1i
== c2k
? 0 : 1;
167 sal_Int32 nNew
= Minimum( aData
.Value(i
-1, k
) + 1,
168 aData
.Value(i
, k
-1) + 1,
169 aData
.Value(i
-1, k
-1) + nCost
);
170 // take transposition (exchange with left or right char) in account
173 int nT
= aData
.Value(i
-2, k
-2) + 1;
174 if (rTxt1
[i
- 2] != c1i
)
176 if (rTxt2
[k
- 2] != c2k
)
182 aData
.Value(i
, k
) = nNew
;
185 sal_Int32 nDist
= aData
.Value(nLen1
, nLen2
);
189 bool IsUseDicList( const PropertyValues
&rProperties
,
190 const uno::Reference
< XPropertySet
> &rxProp
)
194 const PropertyValue
*pVal
= std::find_if(rProperties
.begin(), rProperties
.end(),
195 [](const PropertyValue
& rVal
) { return UPH_IS_USE_DICTIONARY_LIST
== rVal
.Handle
; });
197 if (pVal
!= rProperties
.end())
199 pVal
->Value
>>= bRes
;
201 else // no temporary value found in 'rProperties'
203 uno::Reference
< XFastPropertySet
> xFast( rxProp
, UNO_QUERY
);
205 xFast
->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST
) >>= bRes
;
211 bool IsIgnoreControlChars( const PropertyValues
&rProperties
,
212 const uno::Reference
< XPropertySet
> &rxProp
)
216 const PropertyValue
*pVal
= std::find_if(rProperties
.begin(), rProperties
.end(),
217 [](const PropertyValue
& rVal
) { return UPH_IS_IGNORE_CONTROL_CHARACTERS
== rVal
.Handle
; });
219 if (pVal
!= rProperties
.end())
221 pVal
->Value
>>= bRes
;
223 else // no temporary value found in 'rProperties'
225 uno::Reference
< XFastPropertySet
> xFast( rxProp
, UNO_QUERY
);
227 xFast
->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS
) >>= bRes
;
233 static bool lcl_HasHyphInfo( const uno::Reference
<XDictionaryEntry
> &xEntry
)
238 // there has to be (at least one) '=' or '[' denoting a hyphenation position
239 // and it must not be before any character of the word
240 sal_Int32 nIdx
= xEntry
->getDictionaryWord().indexOf( '=' );
242 nIdx
= xEntry
->getDictionaryWord().indexOf( '[' );
243 bRes
= nIdx
!= -1 && nIdx
!= 0;
248 uno::Reference
< XDictionaryEntry
> SearchDicList(
249 const uno::Reference
< XSearchableDictionaryList
> &xDicList
,
250 const OUString
&rWord
, LanguageType nLanguage
,
251 bool bSearchPosDics
, bool bSearchSpellEntry
)
253 MutexGuard
aGuard( GetLinguMutex() );
255 uno::Reference
< XDictionaryEntry
> xEntry
;
260 const uno::Sequence
< uno::Reference
< XDictionary
> >
261 aDics( xDicList
->getDictionaries() );
262 const uno::Reference
< XDictionary
>
263 *pDic
= aDics
.getConstArray();
264 sal_Int32 nDics
= xDicList
->getCount();
267 for (i
= 0; i
< nDics
; i
++)
269 uno::Reference
< XDictionary
> axDic
= pDic
[i
];
271 DictionaryType eType
= axDic
->getDictionaryType();
272 LanguageType nLang
= LinguLocaleToLanguage( axDic
->getLocale() );
274 if ( axDic
.is() && axDic
->isActive()
275 && (nLang
== nLanguage
|| LinguIsUnspecified( nLang
)) )
277 // DictionaryType_MIXED is deprecated
278 SAL_WARN_IF(eType
== DictionaryType_MIXED
, "linguistic", "unexpected dictionary type");
280 if ( (!bSearchPosDics
&& eType
== DictionaryType_NEGATIVE
)
281 || ( bSearchPosDics
&& eType
== DictionaryType_POSITIVE
))
283 xEntry
= axDic
->getEntry( rWord
);
284 if ( xEntry
.is() && (bSearchSpellEntry
|| lcl_HasHyphInfo( xEntry
)) )
294 bool SaveDictionaries( const uno::Reference
< XSearchableDictionaryList
> &xDicList
)
301 const Sequence
< uno::Reference
< XDictionary
> > aDics( xDicList
->getDictionaries() );
302 for (const uno::Reference
<XDictionary
>& rDic
: aDics
)
306 uno::Reference
< frame::XStorable
> xStor( rDic
, UNO_QUERY
);
309 if (!xStor
->isReadonly() && xStor
->hasLocation())
313 catch(uno::Exception
&)
322 DictionaryError
AddEntryToDic(
323 uno::Reference
< XDictionary
> const &rxDic
,
324 const OUString
&rWord
, bool bIsNeg
,
325 const OUString
&rRplcTxt
,
329 return DictionaryError::NOT_EXISTS
;
331 OUString
aTmp( rWord
);
334 sal_Int32 nLen
= rWord
.getLength();
335 if (nLen
> 0 && '.' == rWord
[ nLen
- 1])
337 // remove trailing '.'
338 // (this is the official way to do this :-( )
339 aTmp
= aTmp
.copy( 0, nLen
- 1 );
342 bool bAddOk
= rxDic
->add( aTmp
, bIsNeg
, rRplcTxt
);
344 DictionaryError nRes
= DictionaryError::NONE
;
348 nRes
= DictionaryError::FULL
;
351 uno::Reference
< frame::XStorable
> xStor( rxDic
, UNO_QUERY
);
352 if (xStor
.is() && xStor
->isReadonly())
353 nRes
= DictionaryError::READONLY
;
355 nRes
= DictionaryError::UNKNOWN
;
362 std::vector
< LanguageType
>
363 LocaleSeqToLangVec( uno::Sequence
< Locale
> const &rLocaleSeq
)
365 std::vector
< LanguageType
> aLangs
;
366 aLangs
.reserve(rLocaleSeq
.getLength());
368 std::transform(rLocaleSeq
.begin(), rLocaleSeq
.end(), std::back_inserter(aLangs
),
369 [](const Locale
& rLocale
) { return LinguLocaleToLanguage(rLocale
); });
374 uno::Sequence
< sal_Int16
>
375 LocaleSeqToLangSeq( uno::Sequence
< Locale
> const &rLocaleSeq
)
377 std::vector
<sal_Int16
> aLangs
;
378 aLangs
.reserve(rLocaleSeq
.getLength());
380 std::transform(rLocaleSeq
.begin(), rLocaleSeq
.end(), std::back_inserter(aLangs
),
381 [](const Locale
& rLocale
) { return static_cast<sal_uInt16
>(LinguLocaleToLanguage(rLocale
)); });
383 return comphelper::containerToSequence(aLangs
);
385 bool IsReadOnly( const OUString
&rURL
, bool *pbExist
)
388 bool bExists
= false;
394 uno::Reference
< css::ucb::XCommandEnvironment
> xCmdEnv
;
395 ::ucbhelper::Content
aContent( rURL
, xCmdEnv
, comphelper::getProcessComponentContext() );
397 bExists
= aContent
.isDocument();
400 Any
aAny( aContent
.getPropertyValue( "IsReadOnly" ) );
415 static bool GetAltSpelling( sal_Int16
&rnChgPos
, sal_Int16
&rnChgLen
, OUString
&rRplc
,
416 uno::Reference
< XHyphenatedWord
> const &rxHyphWord
)
418 bool bRes
= rxHyphWord
->isAlternativeSpelling();
421 OUString
aWord( rxHyphWord
->getWord() ),
422 aHyphenatedWord( rxHyphWord
->getHyphenatedWord() );
423 sal_Int16 nHyphenationPos
= rxHyphWord
->getHyphenationPos();
424 /*sal_Int16 nHyphenPos = rxHyphWord->getHyphenPos()*/;
425 const sal_Unicode
*pWord
= aWord
.getStr(),
426 *pAltWord
= aHyphenatedWord
.getStr();
428 // at least char changes directly left or right to the hyphen
429 // should(!) be handled properly...
430 //! nHyphenationPos and nHyphenPos differ at most by 1 (see above)
431 //! Beware: eg "Schiffahrt" in German (pre spelling reform)
432 //! proves to be a bit nasty (nChgPosLeft and nChgPosRight overlap
435 // find first different char from left
438 for (sal_Int16 i
= 0 ; pWord
[ nPosL
] == pAltWord
[ nAltPosL
]; nPosL
++, nAltPosL
++, i
++)
440 // restrict changes area beginning to the right to
441 // the char immediately following the hyphen.
442 //! serves to insert the additional "f" in "Schiffahrt" at
443 //! position 5 rather than position 6.
444 if (i
>= nHyphenationPos
+ 1)
448 // find first different char from right
449 sal_Int32 nPosR
= aWord
.getLength() - 1,
450 nAltPosR
= aHyphenatedWord
.getLength() - 1;
451 for ( ; nPosR
>= nPosL
&& nAltPosR
>= nAltPosL
452 && pWord
[ nPosR
] == pAltWord
[ nAltPosR
];
456 rnChgPos
= sal::static_int_cast
< sal_Int16
>(nPosL
);
457 rnChgLen
= sal::static_int_cast
< sal_Int16
>(nAltPosR
- nPosL
);
458 assert( rnChgLen
>= 0 && "nChgLen < 0");
460 sal_Int32 nTxtStart
= nPosL
;
461 sal_Int32 nTxtLen
= nAltPosR
- nPosL
+ 1;
462 rRplc
= aHyphenatedWord
.copy( nTxtStart
, nTxtLen
);
467 static sal_Int16
GetOrigWordPos( std::u16string_view rOrigWord
, sal_Int16 nPos
)
469 sal_Int32 nLen
= rOrigWord
.size();
471 while (nPos
>= 0 && i
++ < nLen
)
473 sal_Unicode cChar
= rOrigWord
[i
];
474 bool bSkip
= IsHyphen( cChar
) || IsControlChar( cChar
);
478 return sal::static_int_cast
< sal_Int16
>((0 <= i
&& i
< nLen
) ? i
: -1);
481 sal_Int32
GetPosInWordToCheck( std::u16string_view rTxt
, sal_Int32 nPos
)
484 sal_Int32 nLen
= rTxt
.size();
485 if (0 <= nPos
&& nPos
< nLen
)
488 for (sal_Int32 i
= 0; i
< nPos
; ++i
)
490 sal_Unicode cChar
= rTxt
[i
];
491 bool bSkip
= IsHyphen( cChar
) || IsControlChar( cChar
);
499 uno::Reference
< XHyphenatedWord
> RebuildHyphensAndControlChars(
500 const OUString
&rOrigWord
,
501 uno::Reference
< XHyphenatedWord
> const &rxHyphWord
)
503 uno::Reference
< XHyphenatedWord
> xRes
;
504 if (!rOrigWord
.isEmpty() && rxHyphWord
.is())
506 sal_Int16 nChgPos
= 0,
509 bool bAltSpelling
= GetAltSpelling( nChgPos
, nChgLen
, aRplc
, rxHyphWord
);
511 OUString aOrigHyphenatedWord
;
512 sal_Int16 nOrigHyphenPos
= -1;
513 sal_Int16 nOrigHyphenationPos
= -1;
516 aOrigHyphenatedWord
= rOrigWord
;
517 nOrigHyphenPos
= GetOrigWordPos( rOrigWord
, rxHyphWord
->getHyphenPos() );
518 nOrigHyphenationPos
= GetOrigWordPos( rOrigWord
, rxHyphWord
->getHyphenationPos() );
522 //! should at least work with the German words
523 //! B-"u-c-k-er and Sc-hif-fah-rt
525 sal_Int16 nPos
= GetOrigWordPos( rOrigWord
, nChgPos
);
527 // get words like Sc-hif-fah-rt to work correct
528 sal_Int16 nHyphenationPos
= rxHyphWord
->getHyphenationPos();
529 if (nChgPos
> nHyphenationPos
)
532 std::u16string_view aLeft
= rOrigWord
.subView( 0, nPos
);
533 std::u16string_view aRight
= rOrigWord
.subView( nPos
); // FIXME: changes at the right side
535 aOrigHyphenatedWord
= aLeft
+ aRplc
+ aRight
;
537 nOrigHyphenPos
= sal::static_int_cast
< sal_Int16
>(aLeft
.size() +
538 rxHyphWord
->getHyphenPos() - nChgPos
);
539 nOrigHyphenationPos
= GetOrigWordPos( rOrigWord
, nHyphenationPos
);
542 if (nOrigHyphenPos
== -1 || nOrigHyphenationPos
== -1)
544 SAL_WARN( "linguistic", "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
548 LanguageType nLang
= LinguLocaleToLanguage( rxHyphWord
->getLocale() );
549 xRes
= new HyphenatedWord(
550 rOrigWord
, nLang
, nOrigHyphenationPos
,
551 aOrigHyphenatedWord
, nOrigHyphenPos
);
558 bool IsUpper( const OUString
&rText
, sal_Int32 nPos
, sal_Int32 nLen
, LanguageType nLanguage
)
560 CharClass
aCC(( LanguageTag( nLanguage
) ));
561 return aCC
.isUpper( rText
, nPos
, nLen
);
564 CapType
capitalType(const OUString
& aTerm
, CharClass
const * pCC
)
566 sal_Int32 tlen
= aTerm
.getLength();
568 return CapType::UNKNOWN
;
571 for (sal_Int32 tindex
= 0; tindex
< tlen
; ++tindex
)
573 if (pCC
->getCharacterType(aTerm
,tindex
) &
574 css::i18n::KCharacterType::UPPER
) nc
++;
578 return CapType::NOCAP
;
580 return CapType::ALLCAP
;
581 if ((nc
== 1) && (pCC
->getCharacterType(aTerm
,0) &
582 css::i18n::KCharacterType::UPPER
))
583 return CapType::INITCAP
;
585 return CapType::MIXED
;
588 // sorted(!) array of unicode ranges for code points that are exclusively(!) used as numbers
589 // and thus may NOT not be part of names or words like the Chinese/Japanese number characters
590 const sal_uInt32 the_aDigitZeroes
[] =
592 0x00000030, //0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE
593 0x00000660, //0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
594 0x000006F0, //06F9 ; Decimal # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
595 0x000007C0, //07C9 ; Decimal # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
596 0x00000966, //096F ; Decimal # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
597 0x000009E6, //09EF ; Decimal # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
598 0x00000A66, //0A6F ; Decimal # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
599 0x00000AE6, //0AEF ; Decimal # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
600 0x00000B66, //0B6F ; Decimal # Nd [10] ODIA DIGIT ZERO..ODIA DIGIT NINE
601 0x00000BE6, //0BEF ; Decimal # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
602 0x00000C66, //0C6F ; Decimal # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
603 0x00000CE6, //0CEF ; Decimal # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
604 0x00000D66, //0D6F ; Decimal # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
605 0x00000E50, //0E59 ; Decimal # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
606 0x00000ED0, //0ED9 ; Decimal # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
607 0x00000F20, //0F29 ; Decimal # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
608 0x00001040, //1049 ; Decimal # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
609 0x00001090, //1099 ; Decimal # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
610 0x000017E0, //17E9 ; Decimal # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
611 0x00001810, //1819 ; Decimal # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
612 0x00001946, //194F ; Decimal # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
613 0x000019D0, //19D9 ; Decimal # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
614 0x00001B50, //1B59 ; Decimal # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
615 0x00001BB0, //1BB9 ; Decimal # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
616 0x00001C40, //1C49 ; Decimal # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
617 0x00001C50, //1C59 ; Decimal # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
618 0x0000A620, //A629 ; Decimal # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
619 0x0000A8D0, //A8D9 ; Decimal # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
620 0x0000A900, //A909 ; Decimal # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
621 0x0000AA50, //AA59 ; Decimal # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
622 0x0000FF10, //FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
623 0x000104A0, //104A9 ; Decimal # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
624 0x0001D7CE //1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
627 bool HasDigits( const OUString
&rText
)
629 const sal_Int32 nLen
= rText
.getLength();
632 while (i
< nLen
) // for all characters ...
634 const sal_uInt32 nCodePoint
= rText
.iterateCodePoints( &i
); // handle unicode surrogates correctly...
635 for (unsigned int nDigitZero
: the_aDigitZeroes
) // ... check in all 0..9 ranges
637 if (nDigitZero
> nCodePoint
)
639 if (/*nDigitZero <= nCodePoint &&*/ nCodePoint
<= nDigitZero
+ 9)
646 bool IsNumeric( std::u16string_view rText
)
651 sal_Int32 nLen
= rText
.size();
653 for(sal_Int32 i
= 0; i
< nLen
; ++i
)
655 sal_Unicode cChar
= rText
[ i
];
656 if ( '0' > cChar
|| cChar
> '9' )
666 uno::Reference
< XLinguProperties
> GetLinguProperties()
668 return LinguProperties::create( comphelper::getProcessComponentContext() );
671 uno::Reference
< XSearchableDictionaryList
> GetDictionaryList()
673 uno::Reference
< XComponentContext
> xContext( comphelper::getProcessComponentContext() );
674 uno::Reference
< XSearchableDictionaryList
> xRef
;
677 xRef
= DictionaryList::create(xContext
);
679 catch (const uno::Exception
&)
681 SAL_WARN( "linguistic", "createInstance failed" );
687 uno::Reference
< XDictionary
> GetIgnoreAllList()
689 uno::Reference
< XDictionary
> xRes
;
690 uno::Reference
< XSearchableDictionaryList
> xDL( GetDictionaryList() );
693 std::locale
loc(Translate::Create("svt"));
694 xRes
= xDL
->getDictionaryByName( Translate::get(STR_DESCRIPTION_IGNOREALLLIST
, loc
) );
699 AppExitListener::AppExitListener()
701 // add object to Desktop EventListeners in order to properly call
702 // the AtExit function at application exit.
703 uno::Reference
< XComponentContext
> xContext( comphelper::getProcessComponentContext() );
707 xDesktop
= frame::Desktop::create(xContext
);
709 catch (const uno::Exception
&)
711 SAL_WARN( "linguistic", "createInstance failed" );
715 AppExitListener::~AppExitListener()
719 void AppExitListener::Activate()
722 xDesktop
->addTerminateListener( this );
725 void AppExitListener::Deactivate()
728 xDesktop
->removeTerminateListener( this );
732 AppExitListener::disposing( const EventObject
& rEvtSource
)
734 MutexGuard
aGuard( GetLinguMutex() );
736 if (xDesktop
.is() && rEvtSource
.Source
== xDesktop
)
738 xDesktop
= nullptr; //! release reference to desktop
743 AppExitListener::queryTermination( const EventObject
& /*rEvtSource*/ )
748 AppExitListener::notifyTermination( const EventObject
& rEvtSource
)
750 MutexGuard
aGuard( GetLinguMutex() );
752 if (xDesktop
.is() && rEvtSource
.Source
== xDesktop
)
758 } // namespace linguistic
760 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */