LibreOffice Module linguistic (master) 1
misc.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <memory>
21#include <optional>
22#include <sal/log.hxx>
23#include <svl/lngmisc.hxx>
24#include <ucbhelper/content.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>
42#include <svtools/strings.hrc>
43#include <unotools/resmgr.hxx>
44
45#include <linguistic/misc.hxx>
47
48using namespace osl;
49using namespace com::sun::star;
50using namespace com::sun::star::beans;
51using namespace com::sun::star::lang;
52using namespace com::sun::star::uno;
53using namespace com::sun::star::i18n;
54using namespace com::sun::star::linguistic2;
55
56namespace linguistic
57{
58
60osl::Mutex & GetLinguMutex()
61{
62 static osl::Mutex SINGLETON;
63 return SINGLETON;
64}
65
67{
68 static std::optional<LocaleDataWrapper> oLclDtaWrp;
69 if (!oLclDtaWrp || oLclDtaWrp->getLoadedLanguageTag().getLanguageType() != nLang)
70 oLclDtaWrp.emplace(LanguageTag( nLang ));
71 return *oLclDtaWrp;
72}
73
74LanguageType LinguLocaleToLanguage( const css::lang::Locale& rLocale )
75{
76 if ( rLocale.Language.isEmpty() )
77 return LANGUAGE_NONE;
78 return LanguageTag::convertToLanguageType( rLocale );
79}
80
81css::lang::Locale LinguLanguageToLocale( LanguageType nLanguage )
82{
83 if (nLanguage == LANGUAGE_NONE)
84 return css::lang::Locale();
85 return LanguageTag::convertToLocale( nLanguage);
86}
87
89{
90 return nLanguage.anyOf(
94}
95
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
99
100bool LinguIsUnspecified( std::u16string_view rBcp47 )
101{
102 if (rBcp47.size() != 3)
103 return false;
104 return rBcp47 == u"zxx" || rBcp47 == u"und" || rBcp47 == u"mul";
105}
106
107static sal_Int32 Minimum( sal_Int32 n1, sal_Int32 n2, sal_Int32 n3 )
108{
109 return std::min(std::min(n1, n2), n3);
110}
111
112namespace {
113
114class IntArray2D
115{
116private:
117 std::unique_ptr<sal_Int32[]> pData;
118 int n1, n2;
119
120public:
121 IntArray2D( int nDim1, int nDim2 );
122
123 sal_Int32 & Value( int i, int k );
124};
125
126}
127
128IntArray2D::IntArray2D( int nDim1, int nDim2 )
129{
130 n1 = nDim1;
131 n2 = nDim2;
132 pData.reset( new sal_Int32[n1 * n2] );
133}
134
135sal_Int32 & IntArray2D::Value( int i, int k )
136{
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 ];
141}
142
143sal_Int32 LevDistance( std::u16string_view rTxt1, std::u16string_view rTxt2 )
144{
145 sal_Int32 nLen1 = rTxt1.size();
146 sal_Int32 nLen2 = rTxt2.size();
147
148 if (nLen1 == 0)
149 return nLen2;
150 if (nLen2 == 0)
151 return nLen1;
152
153 IntArray2D aData( nLen1 + 1, nLen2 + 1 );
154
155 sal_Int32 i, k;
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)
161 {
162 for (k = 1; k <= nLen2; ++k)
163 {
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
171 if (2 < i && 2 < k)
172 {
173 int nT = aData.Value(i-2, k-2) + 1;
174 if (rTxt1[i - 2] != c1i)
175 ++nT;
176 if (rTxt2[k - 2] != c2k)
177 ++nT;
178 if (nT < nNew)
179 nNew = nT;
180 }
181
182 aData.Value(i, k) = nNew;
183 }
184 }
185 sal_Int32 nDist = aData.Value(nLen1, nLen2);
186 return nDist;
187}
188
189bool IsUseDicList( const PropertyValues &rProperties,
190 const uno::Reference< XPropertySet > &rxProp )
191{
192 bool bRes = true;
193
194 const PropertyValue *pVal = std::find_if(rProperties.begin(), rProperties.end(),
195 [](const PropertyValue& rVal) { return UPH_IS_USE_DICTIONARY_LIST == rVal.Handle; });
196
197 if (pVal != rProperties.end())
198 {
199 pVal->Value >>= bRes;
200 }
201 else // no temporary value found in 'rProperties'
202 {
203 uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
204 if (xFast.is())
205 xFast->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST ) >>= bRes;
206 }
207
208 return bRes;
209}
210
211bool IsIgnoreControlChars( const PropertyValues &rProperties,
212 const uno::Reference< XPropertySet > &rxProp )
213{
214 bool bRes = true;
215
216 const PropertyValue *pVal = std::find_if(rProperties.begin(), rProperties.end(),
217 [](const PropertyValue& rVal) { return UPH_IS_IGNORE_CONTROL_CHARACTERS == rVal.Handle; });
218
219 if (pVal != rProperties.end())
220 {
221 pVal->Value >>= bRes;
222 }
223 else // no temporary value found in 'rProperties'
224 {
225 uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
226 if (xFast.is())
227 xFast->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS ) >>= bRes;
228 }
229
230 return bRes;
231}
232
233static bool lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry )
234{
235 bool bRes = false;
236 if (xEntry.is())
237 {
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( '=' );
241 if (nIdx == -1)
242 nIdx = xEntry->getDictionaryWord().indexOf( '[' );
243 bRes = nIdx != -1 && nIdx != 0;
244 }
245 return bRes;
246}
247
248uno::Reference< XDictionaryEntry > SearchDicList(
249 const uno::Reference< XSearchableDictionaryList > &xDicList,
250 const OUString &rWord, LanguageType nLanguage,
251 bool bSearchPosDics, bool bSearchSpellEntry )
252{
253 MutexGuard aGuard( GetLinguMutex() );
254
255 uno::Reference< XDictionaryEntry > xEntry;
256
257 if (!xDicList.is())
258 return xEntry;
259
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();
265
266 sal_Int32 i;
267 for (i = 0; i < nDics; i++)
268 {
269 uno::Reference< XDictionary > axDic = pDic[i];
270
271 DictionaryType eType = axDic->getDictionaryType();
272 LanguageType nLang = LinguLocaleToLanguage( axDic->getLocale() );
273
274 if ( axDic.is() && axDic->isActive()
275 && (nLang == nLanguage || LinguIsUnspecified( nLang)) )
276 {
277 // DictionaryType_MIXED is deprecated
278 SAL_WARN_IF(eType == DictionaryType_MIXED, "linguistic", "unexpected dictionary type");
279
280 if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE)
281 || ( bSearchPosDics && eType == DictionaryType_POSITIVE))
282 {
283 xEntry = axDic->getEntry( rWord );
284 if ( xEntry.is() && (bSearchSpellEntry || lcl_HasHyphInfo( xEntry )) )
285 break;
286 xEntry = nullptr;
287 }
288 }
289 }
290
291 return xEntry;
292}
293
294bool SaveDictionaries( const uno::Reference< XSearchableDictionaryList > &xDicList )
295{
296 if (!xDicList.is())
297 return true;
298
299 bool bRet = true;
300
301 const Sequence< uno::Reference< XDictionary > > aDics( xDicList->getDictionaries() );
302 for (const uno::Reference<XDictionary>& rDic : aDics)
303 {
304 try
305 {
306 uno::Reference< frame::XStorable > xStor( rDic, UNO_QUERY );
307 if (xStor.is())
308 {
309 if (!xStor->isReadonly() && xStor->hasLocation())
310 xStor->store();
311 }
312 }
313 catch(uno::Exception &)
314 {
315 bRet = false;
316 }
317 }
318
319 return bRet;
320}
321
323 uno::Reference< XDictionary > const &rxDic,
324 const OUString &rWord, bool bIsNeg,
325 const OUString &rRplcTxt,
326 bool bStripDot )
327{
328 if (!rxDic.is())
330
331 OUString aTmp( rWord );
332 if (bStripDot)
333 {
334 sal_Int32 nLen = rWord.getLength();
335 if (nLen > 0 && '.' == rWord[ nLen - 1])
336 {
337 // remove trailing '.'
338 // (this is the official way to do this :-( )
339 aTmp = aTmp.copy( 0, nLen - 1 );
340 }
341 }
342 bool bAddOk = rxDic->add( aTmp, bIsNeg, rRplcTxt );
343
345 if (!bAddOk)
346 {
347 if (rxDic->isFull())
349 else
350 {
351 uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
352 if (xStor.is() && xStor->isReadonly())
354 else
356 }
357 }
358
359 return nRes;
360}
361
362std::vector< LanguageType >
363 LocaleSeqToLangVec( uno::Sequence< Locale > const &rLocaleSeq )
364{
365 std::vector< LanguageType > aLangs;
366 aLangs.reserve(rLocaleSeq.getLength());
367
368 std::transform(rLocaleSeq.begin(), rLocaleSeq.end(), std::back_inserter(aLangs),
369 [](const Locale& rLocale) { return LinguLocaleToLanguage(rLocale); });
370
371 return aLangs;
372}
373
374uno::Sequence< sal_Int16 >
375 LocaleSeqToLangSeq( uno::Sequence< Locale > const &rLocaleSeq )
376{
377 std::vector<sal_Int16> aLangs;
378 aLangs.reserve(rLocaleSeq.getLength());
379
380 std::transform(rLocaleSeq.begin(), rLocaleSeq.end(), std::back_inserter(aLangs),
381 [](const Locale& rLocale) { return static_cast<sal_uInt16>(LinguLocaleToLanguage(rLocale)); });
382
383 return comphelper::containerToSequence(aLangs);
384}
385bool IsReadOnly( const OUString &rURL, bool *pbExist )
386{
387 bool bRes = false;
388 bool bExists = false;
389
390 if (!rURL.isEmpty())
391 {
392 try
393 {
394 uno::Reference< css::ucb::XCommandEnvironment > xCmdEnv;
396
397 bExists = aContent.isDocument();
398 if (bExists)
399 {
400 Any aAny( aContent.getPropertyValue( "IsReadOnly" ) );
401 aAny >>= bRes;
402 }
403 }
404 catch (Exception &)
405 {
406 bRes = true;
407 }
408 }
409
410 if (pbExist)
411 *pbExist = bExists;
412 return bRes;
413}
414
415static bool GetAltSpelling( sal_Int16 &rnChgPos, sal_Int16 &rnChgLen, OUString &rRplc,
416 uno::Reference< XHyphenatedWord > const &rxHyphWord )
417{
418 bool bRes = rxHyphWord->isAlternativeSpelling();
419 if (bRes)
420 {
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();
427
428 // at least char changes directly left or right to the hyphen
429 // should(!) be handled properly...
434
435 // find first different char from left
436 sal_Int32 nPosL = 0,
437 nAltPosL = 0;
438 for (sal_Int16 i = 0 ; pWord[ nPosL ] == pAltWord[ nAltPosL ]; nPosL++, nAltPosL++, i++)
439 {
440 // restrict changes area beginning to the right to
441 // the char immediately following the hyphen.
444 if (i >= nHyphenationPos + 1)
445 break;
446 }
447
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 ];
453 nPosR--, nAltPosR--)
454 ;
455
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");
459
460 sal_Int32 nTxtStart = nPosL;
461 sal_Int32 nTxtLen = nAltPosR - nPosL + 1;
462 rRplc = aHyphenatedWord.copy( nTxtStart, nTxtLen );
463 }
464 return bRes;
465}
466
467static sal_Int16 GetOrigWordPos( std::u16string_view rOrigWord, sal_Int16 nPos )
468{
469 sal_Int32 nLen = rOrigWord.size();
470 sal_Int32 i = -1;
471 while (nPos >= 0 && i++ < nLen)
472 {
473 sal_Unicode cChar = rOrigWord[i];
474 bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
475 if (!bSkip)
476 --nPos;
477 }
478 return sal::static_int_cast< sal_Int16 >((0 <= i && i < nLen) ? i : -1);
479}
480
481sal_Int32 GetPosInWordToCheck( std::u16string_view rTxt, sal_Int32 nPos )
482{
483 sal_Int32 nRes = -1;
484 sal_Int32 nLen = rTxt.size();
485 if (0 <= nPos && nPos < nLen)
486 {
487 nRes = 0;
488 for (sal_Int32 i = 0; i < nPos; ++i)
489 {
490 sal_Unicode cChar = rTxt[i];
491 bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
492 if (!bSkip)
493 ++nRes;
494 }
495 }
496 return nRes;
497}
498
499uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars(
500 const OUString &rOrigWord,
501 uno::Reference< XHyphenatedWord > const &rxHyphWord )
502{
503 uno::Reference< XHyphenatedWord > xRes;
504 if (!rOrigWord.isEmpty() && rxHyphWord.is())
505 {
506 sal_Int16 nChgPos = 0,
507 nChgLen = 0;
508 OUString aRplc;
509 bool bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord );
510
511 OUString aOrigHyphenatedWord;
512 sal_Int16 nOrigHyphenPos = -1;
513 sal_Int16 nOrigHyphenationPos = -1;
514 if (!bAltSpelling)
515 {
516 aOrigHyphenatedWord = rOrigWord;
517 nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() );
518 nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() );
519 }
520 else
521 {
524
525 sal_Int16 nPos = GetOrigWordPos( rOrigWord, nChgPos );
526
527 // get words like Sc-hif-fah-rt to work correct
528 sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
529 if (nChgPos > nHyphenationPos)
530 --nPos;
531
532 std::u16string_view aLeft = rOrigWord.subView( 0, nPos );
533 std::u16string_view aRight = rOrigWord.subView( nPos ); // FIXME: changes at the right side
534
535 aOrigHyphenatedWord = aLeft + aRplc + aRight;
536
537 nOrigHyphenPos = sal::static_int_cast< sal_Int16 >(aLeft.size() +
538 rxHyphWord->getHyphenPos() - nChgPos);
539 nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos );
540 }
541
542 if (nOrigHyphenPos == -1 || nOrigHyphenationPos == -1)
543 {
544 SAL_WARN( "linguistic", "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
545 }
546 else
547 {
548 LanguageType nLang = LinguLocaleToLanguage( rxHyphWord->getLocale() );
549 xRes = new HyphenatedWord(
550 rOrigWord, nLang, nOrigHyphenationPos,
551 aOrigHyphenatedWord, nOrigHyphenPos );
552 }
553
554 }
555 return xRes;
556}
557
558bool IsUpper( const OUString &rText, sal_Int32 nPos, sal_Int32 nLen, LanguageType nLanguage )
559{
560 CharClass aCC(( LanguageTag( nLanguage ) ));
561 return aCC.isUpper( rText, nPos, nLen );
562}
563
564CapType capitalType(const OUString& aTerm, CharClass const * pCC)
565{
566 sal_Int32 tlen = aTerm.getLength();
567 if (!pCC || !tlen)
568 return CapType::UNKNOWN;
569
570 sal_Int32 nc = 0;
571 for (sal_Int32 tindex = 0; tindex < tlen; ++tindex)
572 {
573 if (pCC->getCharacterType(aTerm,tindex) &
574 css::i18n::KCharacterType::UPPER) nc++;
575 }
576
577 if (nc == 0)
578 return CapType::NOCAP;
579 if (nc == tlen)
580 return CapType::ALLCAP;
581 if ((nc == 1) && (pCC->getCharacterType(aTerm,0) &
582 css::i18n::KCharacterType::UPPER))
583 return CapType::INITCAP;
584
585 return CapType::MIXED;
586}
587
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
590const sal_uInt32 the_aDigitZeroes [] =
591{
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
625};
626
627bool HasDigits( const OUString &rText )
628{
629 const sal_Int32 nLen = rText.getLength();
630
631 sal_Int32 i = 0;
632 while (i < nLen) // for all characters ...
633 {
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
636 {
637 if (nDigitZero > nCodePoint)
638 break;
639 if (/*nDigitZero <= nCodePoint &&*/ nCodePoint <= nDigitZero + 9)
640 return true;
641 }
642 }
643 return false;
644}
645
646bool IsNumeric( std::u16string_view rText )
647{
648 bool bRes = false;
649 if (!rText.empty())
650 {
651 sal_Int32 nLen = rText.size();
652 bRes = true;
653 for(sal_Int32 i = 0; i < nLen; ++i)
654 {
655 sal_Unicode cChar = rText[ i ];
656 if ( '0' > cChar || cChar > '9' )
657 {
658 bRes = false;
659 break;
660 }
661 }
662 }
663 return bRes;
664}
665
666uno::Reference< XLinguProperties > GetLinguProperties()
667{
668 return LinguProperties::create( comphelper::getProcessComponentContext() );
669}
670
671uno::Reference< XSearchableDictionaryList > GetDictionaryList()
672{
673 uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
674 uno::Reference< XSearchableDictionaryList > xRef;
675 try
676 {
677 xRef = DictionaryList::create(xContext);
678 }
679 catch (const uno::Exception &)
680 {
681 SAL_WARN( "linguistic", "createInstance failed" );
682 }
683
684 return xRef;
685}
686
687uno::Reference< XDictionary > GetIgnoreAllList()
688{
689 uno::Reference< XDictionary > xRes;
690 uno::Reference< XSearchableDictionaryList > xDL( GetDictionaryList() );
691 if (xDL.is())
692 {
693 std::locale loc(Translate::Create("svt"));
694 xRes = xDL->getDictionaryByName( Translate::get(STR_DESCRIPTION_IGNOREALLLIST, loc) );
695 }
696 return xRes;
697}
698
700{
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() );
704
705 try
706 {
707 xDesktop = frame::Desktop::create(xContext);
708 }
709 catch (const uno::Exception &)
710 {
711 SAL_WARN( "linguistic", "createInstance failed" );
712 }
713}
714
716{
717}
718
720{
721 if (xDesktop.is())
722 xDesktop->addTerminateListener( this );
723}
724
726{
727 if (xDesktop.is())
728 xDesktop->removeTerminateListener( this );
729}
730
731void SAL_CALL
732 AppExitListener::disposing( const EventObject& rEvtSource )
733{
734 MutexGuard aGuard( GetLinguMutex() );
735
736 if (xDesktop.is() && rEvtSource.Source == xDesktop)
737 {
738 xDesktop = nullptr;
739 }
740}
741
742void SAL_CALL
743 AppExitListener::queryTermination( const EventObject& /*rEvtSource*/ )
744{
745}
746
747void SAL_CALL
748 AppExitListener::notifyTermination( const EventObject& rEvtSource )
749{
750 MutexGuard aGuard( GetLinguMutex() );
751
752 if (xDesktop.is() && rEvtSource.Source == xDesktop)
753 {
754 AtExit();
755 }
756}
757
758} // namespace linguistic
759
760/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 getCharacterType(const OUString &rStr, sal_Int32 nPos) const
bool isUpper(const OUString &rStr, sal_Int32 nPos) const
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)
static LanguageType convertToLanguageType(const css::lang::Locale &rLocale, bool bResolveSystem=true)
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
Definition: misc.cxx:732
css::uno::Reference< css::frame::XDesktop2 > xDesktop
Definition: misc.hxx:173
virtual void SAL_CALL queryTermination(const css::lang::EventObject &aEvent) override
Definition: misc.cxx:743
virtual ~AppExitListener() override
Definition: misc.cxx:715
virtual void SAL_CALL notifyTermination(const css::lang::EventObject &aEvent) override
Definition: misc.cxx:748
css::uno::Any getPropertyValue(const OUString &rPropertyName)
float u
DocumentType eType
#define LANGUAGE_NONE
#define LANGUAGE_UNDETERMINED
#define LANGUAGE_MULTIPLE
#define UPH_IS_USE_DICTIONARY_LIST
#define UPH_IS_IGNORE_CONTROL_CHARACTERS
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
std::unique_ptr< sal_Int32[]> pData
Definition: misc.cxx:117
int n2
Definition: misc.cxx:118
int n1
Definition: misc.cxx:118
sal_uInt32 n3
constexpr OUStringLiteral aData
std::locale Create(std::string_view aPrefixName, const LanguageTag &rLocale)
OUString get(TranslateId sContextAndId, const std::locale &loc)
@ Exception
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Reference< XComponentContext > getProcessComponentContext()
std::map< sal_Int32, std::shared_ptr< SetItemPropertyStorage > > PropertyValues
Value
int i
bool IsHyphen(sal_Unicode cChar)
bool SaveDictionaries(const uno::Reference< XSearchableDictionaryList > &xDicList)
Definition: misc.cxx:294
std::vector< LanguageType > LocaleSeqToLangVec(uno::Sequence< Locale > const &rLocaleSeq)
Definition: misc.cxx:363
bool IsReadOnly(const OUString &rURL, bool *pbExist)
Definition: misc.cxx:385
static bool GetAltSpelling(sal_Int16 &rnChgPos, sal_Int16 &rnChgLen, OUString &rRplc, uno::Reference< XHyphenatedWord > const &rxHyphWord)
Definition: misc.cxx:415
const sal_uInt32 the_aDigitZeroes[]
Definition: misc.cxx:590
uno::Sequence< sal_Int16 > LocaleSeqToLangSeq(uno::Sequence< Locale > const &rLocaleSeq)
Definition: misc.cxx:375
bool LinguIsUnspecified(LanguageType nLanguage)
Checks if a LanguageType is one of the values that denote absence of language or undetermined languag...
Definition: misc.cxx:88
uno::Reference< XSearchableDictionaryList > GetDictionaryList()
Definition: misc.cxx:671
static sal_Int16 GetOrigWordPos(std::u16string_view rOrigWord, sal_Int16 nPos)
Definition: misc.cxx:467
uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars(const OUString &rOrigWord, uno::Reference< XHyphenatedWord > const &rxHyphWord)
Definition: misc.cxx:499
uno::Reference< XLinguProperties > GetLinguProperties()
Definition: misc.cxx:666
DictionaryError
Definition: misc.hxx:61
static sal_Int32 Minimum(sal_Int32 n1, sal_Int32 n2, sal_Int32 n3)
Definition: misc.cxx:107
CapType capitalType(const OUString &aTerm, CharClass const *pCC)
Definition: misc.cxx:564
uno::Reference< XDictionaryEntry > SearchDicList(const uno::Reference< XSearchableDictionaryList > &xDicList, const OUString &rWord, LanguageType nLanguage, bool bSearchPosDics, bool bSearchSpellEntry)
Definition: misc.cxx:248
sal_Int32 GetPosInWordToCheck(std::u16string_view rTxt, sal_Int32 nPos)
Definition: misc.cxx:481
bool IsControlChar(sal_Unicode cChar)
osl::Mutex & GetLinguMutex()
! multi-thread safe mutex for all platforms !!
Definition: misc.cxx:60
bool IsUpper(const OUString &rText, sal_Int32 nPos, sal_Int32 nLen, LanguageType nLanguage)
Definition: misc.cxx:558
bool IsIgnoreControlChars(const PropertyValues &rProperties, const uno::Reference< XPropertySet > &rxProp)
Definition: misc.cxx:211
sal_Int32 LevDistance(std::u16string_view rTxt1, std::u16string_view rTxt2)
Definition: misc.cxx:143
bool IsNumeric(std::u16string_view rText)
Definition: misc.cxx:646
css::lang::Locale LinguLanguageToLocale(LanguageType nLanguage)
Convert LanguageType to Locale for legacy handling.
Definition: misc.cxx:81
static bool lcl_HasHyphInfo(const uno::Reference< XDictionaryEntry > &xEntry)
Definition: misc.cxx:233
bool HasDigits(const OUString &rText)
Definition: misc.cxx:627
const LocaleDataWrapper & GetLocaleDataWrapper(LanguageType nLang)
Definition: misc.cxx:66
DictionaryError AddEntryToDic(uno::Reference< XDictionary > const &rxDic, const OUString &rWord, bool bIsNeg, const OUString &rRplcTxt, bool bStripDot)
Definition: misc.cxx:322
uno::Reference< XDictionary > GetIgnoreAllList()
Definition: misc.cxx:687
LanguageType LinguLocaleToLanguage(const css::lang::Locale &rLocale)
Convert Locale to LanguageType for legacy handling.
Definition: misc.cxx:74
bool IsUseDicList(const PropertyValues &rProperties, const uno::Reference< XPropertySet > &rxProp)
Definition: misc.cxx:189
bool anyOf(strong_int v) const
sal_uInt16 sal_Unicode