Line data Source code
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 <sal/macros.h>
21 : #include <tools/debug.hxx>
22 : #include <unotools/pathoptions.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/XPropertyChangeListener.hpp>
29 : #include <com/sun/star/beans/PropertyValues.hpp>
30 : #include <com/sun/star/frame/XTerminateListener.hpp>
31 : #include <com/sun/star/frame/Desktop.hpp>
32 : #include <com/sun/star/frame/XStorable.hpp>
33 : #include <com/sun/star/linguistic2/DictionaryType.hpp>
34 : #include <com/sun/star/linguistic2/DictionaryList.hpp>
35 : #include <com/sun/star/linguistic2/LinguProperties.hpp>
36 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
37 : #include <com/sun/star/uno/Sequence.hxx>
38 : #include <com/sun/star/uno/Reference.h>
39 : #include <comphelper/processfactory.hxx>
40 : #include <unotools/localedatawrapper.hxx>
41 : #include <unotools/syslocale.hxx>
42 :
43 : #include <rtl/instance.hxx>
44 :
45 : #include "linguistic/misc.hxx"
46 : #include "defs.hxx"
47 : #include "linguistic/lngprops.hxx"
48 : #include "linguistic/hyphdta.hxx"
49 :
50 : using namespace osl;
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;
57 :
58 : namespace linguistic
59 : {
60 :
61 : //!! multi-thread safe mutex for all platforms !!
62 : struct LinguMutex : public rtl::Static< osl::Mutex, LinguMutex >
63 : {
64 : };
65 :
66 8853914113 : osl::Mutex & GetLinguMutex()
67 : {
68 8853914113 : return LinguMutex::get();
69 : }
70 :
71 85382539 : LocaleDataWrapper & GetLocaleDataWrapper( sal_Int16 nLang )
72 : {
73 85382539 : static LocaleDataWrapper aLclDtaWrp( SvtSysLocale().GetLanguageTag() );
74 :
75 85382539 : const LanguageTag &rLcl = aLclDtaWrp.getLoadedLanguageTag();
76 170765078 : LanguageTag aLcl( nLang );
77 85382539 : if (aLcl != rLcl)
78 0 : aLclDtaWrp.setLanguageTag( aLcl );
79 170765078 : return aLclDtaWrp;
80 : }
81 :
82 1214068987 : LanguageType LinguLocaleToLanguage( const ::com::sun::star::lang::Locale& rLocale )
83 : {
84 1214068987 : if ( rLocale.Language.isEmpty() )
85 338 : return LANGUAGE_NONE;
86 1214068649 : return LanguageTag::convertToLanguageType( rLocale );
87 : }
88 :
89 30 : ::com::sun::star::lang::Locale LinguLanguageToLocale( LanguageType nLanguage )
90 : {
91 30 : if (nLanguage == LANGUAGE_NONE)
92 30 : return ::com::sun::star::lang::Locale();
93 0 : return LanguageTag::convertToLocale( nLanguage);
94 : }
95 :
96 863173378 : bool LinguIsUnspecified( LanguageType nLanguage )
97 : {
98 863173378 : switch (nLanguage)
99 : {
100 : case LANGUAGE_NONE:
101 : case LANGUAGE_UNDETERMINED:
102 : case LANGUAGE_MULTIPLE:
103 388885079 : return true;
104 : }
105 474288299 : return false;
106 : }
107 :
108 : // When adding anything keep both LinguIsUnspecified() methods in sync!
109 : // For mappings between language code string and LanguageType see
110 : // i18nlangtag/source/isolang/isolang.cxx
111 :
112 344 : bool LinguIsUnspecified( const OUString & rBcp47 )
113 : {
114 344 : if (rBcp47.getLength() != 3)
115 344 : return false;
116 0 : if (rBcp47 == "zxx" || rBcp47 == "und" || rBcp47 == "mul")
117 0 : return true;
118 0 : return false;
119 : }
120 :
121 0 : static inline sal_Int32 Minimum( sal_Int32 n1, sal_Int32 n2, sal_Int32 n3 )
122 : {
123 0 : sal_Int32 nMin = n1 < n2 ? n1 : n2;
124 0 : return nMin < n3 ? nMin : n3;
125 : }
126 :
127 : class IntArray2D
128 : {
129 : private:
130 : sal_Int32 *pData;
131 : int n1, n2;
132 :
133 : public:
134 : IntArray2D( int nDim1, int nDim2 );
135 : ~IntArray2D();
136 :
137 : sal_Int32 & Value( int i, int k );
138 : };
139 :
140 0 : IntArray2D::IntArray2D( int nDim1, int nDim2 )
141 : {
142 0 : n1 = nDim1;
143 0 : n2 = nDim2;
144 0 : pData = new sal_Int32[n1 * n2];
145 0 : }
146 :
147 0 : IntArray2D::~IntArray2D()
148 : {
149 0 : delete[] pData;
150 0 : }
151 :
152 0 : sal_Int32 & IntArray2D::Value( int i, int k )
153 : {
154 : DBG_ASSERT( 0 <= i && i < n1, "first index out of range" );
155 : DBG_ASSERT( 0 <= k && k < n2, "first index out of range" );
156 : DBG_ASSERT( i * n2 + k < n1 * n2, "index out of range" );
157 0 : return pData[ i * n2 + k ];
158 : }
159 :
160 0 : sal_Int32 LevDistance( const OUString &rTxt1, const OUString &rTxt2 )
161 : {
162 0 : sal_Int32 nLen1 = rTxt1.getLength();
163 0 : sal_Int32 nLen2 = rTxt2.getLength();
164 :
165 0 : if (nLen1 == 0)
166 0 : return nLen2;
167 0 : if (nLen2 == 0)
168 0 : return nLen1;
169 :
170 0 : IntArray2D aData( nLen1 + 1, nLen2 + 1 );
171 :
172 : sal_Int32 i, k;
173 0 : for (i = 0; i <= nLen1; ++i)
174 0 : aData.Value(i, 0) = i;
175 0 : for (k = 0; k <= nLen2; ++k)
176 0 : aData.Value(0, k) = k;
177 0 : for (i = 1; i <= nLen1; ++i)
178 : {
179 0 : for (k = 1; k <= nLen2; ++k)
180 : {
181 0 : sal_Unicode c1i = rTxt1[i - 1];
182 0 : sal_Unicode c2k = rTxt2[k - 1];
183 0 : sal_Int32 nCost = c1i == c2k ? 0 : 1;
184 0 : sal_Int32 nNew = Minimum( aData.Value(i-1, k ) + 1,
185 0 : aData.Value(i , k-1) + 1,
186 0 : aData.Value(i-1, k-1) + nCost );
187 : // take transposition (exchange with left or right char) in account
188 0 : if (2 < i && 2 < k)
189 : {
190 0 : int nT = aData.Value(i-2, k-2) + 1;
191 0 : if (rTxt1[i - 2] != c1i)
192 0 : ++nT;
193 0 : if (rTxt2[k - 2] != c2k)
194 0 : ++nT;
195 0 : if (nT < nNew)
196 0 : nNew = nT;
197 : }
198 :
199 0 : aData.Value(i, k) = nNew;
200 : }
201 : }
202 0 : sal_Int32 nDist = aData.Value(nLen1, nLen2);
203 0 : return nDist;
204 : }
205 :
206 85382531 : bool IsUseDicList( const PropertyValues &rProperties,
207 : const uno::Reference< XPropertySet > &rxProp )
208 : {
209 85382531 : bool bRes = true;
210 :
211 85382531 : sal_Int32 nLen = rProperties.getLength();
212 85382531 : const PropertyValue *pVal = rProperties.getConstArray();
213 : sal_Int32 i;
214 :
215 85382531 : for ( i = 0; i < nLen; ++i)
216 : {
217 0 : if (UPH_IS_USE_DICTIONARY_LIST == pVal[i].Handle)
218 : {
219 0 : pVal[i].Value >>= bRes;
220 0 : break;
221 : }
222 : }
223 85382531 : if (i >= nLen) // no temporary value found in 'rProperties'
224 : {
225 85382531 : uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
226 85382531 : if (xFast.is())
227 85382531 : xFast->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST ) >>= bRes;
228 : }
229 :
230 85382531 : return bRes;
231 : }
232 :
233 85382531 : bool IsIgnoreControlChars( const PropertyValues &rProperties,
234 : const uno::Reference< XPropertySet > &rxProp )
235 : {
236 85382531 : bool bRes = true;
237 :
238 85382531 : sal_Int32 nLen = rProperties.getLength();
239 85382531 : const PropertyValue *pVal = rProperties.getConstArray();
240 : sal_Int32 i;
241 :
242 85382531 : for ( i = 0; i < nLen; ++i)
243 : {
244 0 : if (UPH_IS_IGNORE_CONTROL_CHARACTERS == pVal[i].Handle)
245 : {
246 0 : pVal[i].Value >>= bRes;
247 0 : break;
248 : }
249 : }
250 85382531 : if (i >= nLen) // no temporary value found in 'rProperties'
251 : {
252 85382531 : uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
253 85382531 : if (xFast.is())
254 85382531 : xFast->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS ) >>= bRes;
255 : }
256 :
257 85382531 : return bRes;
258 : }
259 :
260 0 : static bool lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry )
261 : {
262 0 : bool bRes = false;
263 0 : if (xEntry.is())
264 : {
265 : // there has to be (at least one) '=' or '[' denoting a hyphenation position
266 : // and it must not be before any character of the word
267 0 : sal_Int32 nIdx = xEntry->getDictionaryWord().indexOf( '=' );
268 0 : if (nIdx == -1)
269 0 : nIdx = xEntry->getDictionaryWord().indexOf( '[' );
270 0 : bRes = nIdx != -1 && nIdx != 0;
271 : }
272 0 : return bRes;
273 : }
274 :
275 194442621 : uno::Reference< XDictionaryEntry > SearchDicList(
276 : const uno::Reference< XSearchableDictionaryList > &xDicList,
277 : const OUString &rWord, sal_Int16 nLanguage,
278 : bool bSearchPosDics, bool bSearchSpellEntry )
279 : {
280 194442621 : MutexGuard aGuard( GetLinguMutex() );
281 :
282 194442621 : uno::Reference< XDictionaryEntry > xEntry;
283 :
284 194442621 : if (!xDicList.is())
285 0 : return xEntry;
286 :
287 : const uno::Sequence< uno::Reference< XDictionary > >
288 388885242 : aDics( xDicList->getDictionaries() );
289 : const uno::Reference< XDictionary >
290 194442621 : *pDic = aDics.getConstArray();
291 194442621 : sal_Int32 nDics = xDicList->getCount();
292 :
293 : sal_Int32 i;
294 1166652871 : for (i = 0; i < nDics; i++)
295 : {
296 972210891 : uno::Reference< XDictionary > axDic( pDic[i], UNO_QUERY );
297 :
298 972210891 : DictionaryType eType = axDic->getDictionaryType();
299 972210891 : sal_Int16 nLang = LinguLocaleToLanguage( axDic->getLocale() );
300 :
301 2916632673 : if ( axDic.is() && axDic->isActive()
302 1944421782 : && (nLang == nLanguage || LinguIsUnspecified( nLang)) )
303 : {
304 : DBG_ASSERT( eType != DictionaryType_MIXED,
305 : "lng : unexpected dictionary type" );
306 :
307 583326929 : if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE)
308 583326929 : || ( bSearchPosDics && eType == DictionaryType_POSITIVE))
309 : {
310 291670676 : if ( (xEntry = axDic->getEntry( rWord )).is() )
311 : {
312 641 : if (bSearchSpellEntry || lcl_HasHyphInfo( xEntry ))
313 641 : break;
314 : }
315 291670035 : xEntry = 0;
316 : }
317 : }
318 972210250 : }
319 :
320 388885242 : return xEntry;
321 : }
322 :
323 0 : bool SaveDictionaries( const uno::Reference< XSearchableDictionaryList > &xDicList )
324 : {
325 0 : if (!xDicList.is())
326 0 : return true;
327 :
328 0 : bool bRet = true;
329 :
330 0 : Sequence< uno::Reference< XDictionary > > aDics( xDicList->getDictionaries() );
331 0 : const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
332 0 : sal_Int32 nCount = aDics.getLength();
333 0 : for (sal_Int32 i = 0; i < nCount; i++)
334 : {
335 : try
336 : {
337 0 : uno::Reference< frame::XStorable > xStor( pDic[i], UNO_QUERY );
338 0 : if (xStor.is())
339 : {
340 0 : if (!xStor->isReadonly() && xStor->hasLocation())
341 0 : xStor->store();
342 0 : }
343 : }
344 0 : catch(uno::Exception &)
345 : {
346 0 : bRet = false;
347 : }
348 : }
349 :
350 0 : return bRet;
351 : }
352 :
353 0 : DictionaryError AddEntryToDic(
354 : uno::Reference< XDictionary > &rxDic,
355 : const OUString &rWord, bool bIsNeg,
356 : const OUString &rRplcTxt, sal_Int16 /* nRplcLang */,
357 : bool bStripDot )
358 : {
359 0 : if (!rxDic.is())
360 0 : return DictionaryError::NOT_EXISTS;
361 :
362 0 : OUString aTmp( rWord );
363 0 : if (bStripDot)
364 : {
365 0 : sal_Int32 nLen = rWord.getLength();
366 0 : if (nLen > 0 && '.' == rWord[ nLen - 1])
367 : {
368 : // remove trailing '.'
369 : // (this is the official way to do this :-( )
370 0 : aTmp = aTmp.copy( 0, nLen - 1 );
371 : }
372 : }
373 0 : bool bAddOk = rxDic->add( aTmp, bIsNeg, rRplcTxt );
374 :
375 0 : DictionaryError nRes = DictionaryError::NONE;
376 0 : if (!bAddOk)
377 : {
378 0 : if (rxDic->isFull())
379 0 : nRes = DictionaryError::FULL;
380 : else
381 : {
382 0 : uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
383 0 : if (xStor.is() && xStor->isReadonly())
384 0 : nRes = DictionaryError::READONLY;
385 : else
386 0 : nRes = DictionaryError::UNKNOWN;
387 : }
388 : }
389 :
390 0 : return nRes;
391 : }
392 :
393 : uno::Sequence< sal_Int16 >
394 129 : LocaleSeqToLangSeq( uno::Sequence< Locale > &rLocaleSeq )
395 : {
396 129 : const Locale *pLocale = rLocaleSeq.getConstArray();
397 129 : sal_Int32 nCount = rLocaleSeq.getLength();
398 :
399 129 : uno::Sequence< sal_Int16 > aLangs( nCount );
400 129 : sal_Int16 *pLang = aLangs.getArray();
401 473 : for (sal_Int32 i = 0; i < nCount; ++i)
402 : {
403 344 : pLang[i] = LinguLocaleToLanguage( pLocale[i] );
404 : }
405 :
406 129 : return aLangs;
407 : }
408 :
409 0 : bool IsReadOnly( const OUString &rURL, bool *pbExist )
410 : {
411 0 : bool bRes = false;
412 0 : bool bExists = false;
413 :
414 0 : if (!rURL.isEmpty())
415 : {
416 : try
417 : {
418 0 : uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xCmdEnv;
419 0 : ::ucbhelper::Content aContent( rURL, xCmdEnv, comphelper::getProcessComponentContext() );
420 :
421 0 : bExists = aContent.isDocument();
422 0 : if (bExists)
423 : {
424 0 : Any aAny( aContent.getPropertyValue( "IsReadOnly" ) );
425 0 : aAny >>= bRes;
426 0 : }
427 : }
428 0 : catch (Exception &)
429 : {
430 0 : bRes = true;
431 : }
432 : }
433 :
434 0 : if (pbExist)
435 0 : *pbExist = bExists;
436 0 : return bRes;
437 : }
438 :
439 0 : static bool GetAltSpelling( sal_Int16 &rnChgPos, sal_Int16 &rnChgLen, OUString &rRplc,
440 : uno::Reference< XHyphenatedWord > &rxHyphWord )
441 : {
442 0 : bool bRes = rxHyphWord->isAlternativeSpelling();
443 0 : if (bRes)
444 : {
445 0 : OUString aWord( rxHyphWord->getWord() ),
446 0 : aHyphenatedWord( rxHyphWord->getHyphenatedWord() );
447 0 : sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
448 : /*sal_Int16 nHyphenPos = rxHyphWord->getHyphenPos()*/;
449 0 : const sal_Unicode *pWord = aWord.getStr(),
450 0 : *pAltWord = aHyphenatedWord.getStr();
451 :
452 : // at least char changes directly left or right to the hyphen
453 : // should(!) be handled properly...
454 : //! nHyphenationPos and nHyphenPos differ at most by 1 (see above)
455 : //! Beware: eg "Schiffahrt" in German (pre spelling reform)
456 : //! proves to be a bit nasty (nChgPosLeft and nChgPosRight overlap
457 : //! to an extend.)
458 :
459 : // find first different char from left
460 0 : sal_Int32 nPosL = 0,
461 0 : nAltPosL = 0;
462 0 : for (sal_Int16 i = 0 ; pWord[ nPosL ] == pAltWord[ nAltPosL ]; nPosL++, nAltPosL++, i++)
463 : {
464 : // restrict changes area beginning to the right to
465 : // the char immediately following the hyphen.
466 : //! serves to insert the additional "f" in "Schiffahrt" at
467 : //! position 5 rather than position 6.
468 0 : if (i >= nHyphenationPos + 1)
469 0 : break;
470 : }
471 :
472 : // find first different char from right
473 0 : sal_Int32 nPosR = aWord.getLength() - 1,
474 0 : nAltPosR = aHyphenatedWord.getLength() - 1;
475 0 : for ( ; nPosR >= nPosL && nAltPosR >= nAltPosL
476 0 : && pWord[ nPosR ] == pAltWord[ nAltPosR ];
477 : nPosR--, nAltPosR--)
478 : ;
479 :
480 0 : rnChgPos = sal::static_int_cast< sal_Int16 >(nPosL);
481 0 : rnChgLen = sal::static_int_cast< sal_Int16 >(nAltPosR - nPosL);
482 : DBG_ASSERT( rnChgLen >= 0, "nChgLen < 0");
483 :
484 0 : sal_Int32 nTxtStart = nPosL;
485 0 : sal_Int32 nTxtLen = nAltPosR - nPosL + 1;
486 0 : rRplc = aHyphenatedWord.copy( nTxtStart, nTxtLen );
487 : }
488 0 : return bRes;
489 : }
490 :
491 0 : static sal_Int16 GetOrigWordPos( const OUString &rOrigWord, sal_Int16 nPos )
492 : {
493 0 : sal_Int32 nLen = rOrigWord.getLength();
494 0 : sal_Int32 i = -1;
495 0 : while (nPos >= 0 && i++ < nLen)
496 : {
497 0 : sal_Unicode cChar = rOrigWord[i];
498 0 : bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
499 0 : if (!bSkip)
500 0 : --nPos;
501 : }
502 0 : return sal::static_int_cast< sal_Int16 >((0 <= i && i < nLen) ? i : -1);
503 : }
504 :
505 10470 : sal_Int32 GetPosInWordToCheck( const OUString &rTxt, sal_Int32 nPos )
506 : {
507 10470 : sal_Int32 nRes = -1;
508 10470 : sal_Int32 nLen = rTxt.getLength();
509 10470 : if (0 <= nPos && nPos < nLen)
510 : {
511 10470 : nRes = 0;
512 23336 : for (sal_Int32 i = 0; i < nPos; ++i)
513 : {
514 12866 : sal_Unicode cChar = rTxt[i];
515 12866 : bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
516 12866 : if (!bSkip)
517 12866 : ++nRes;
518 : }
519 : }
520 10470 : return nRes;
521 : }
522 :
523 0 : uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars(
524 : const OUString &rOrigWord,
525 : uno::Reference< XHyphenatedWord > &rxHyphWord )
526 : {
527 0 : uno::Reference< XHyphenatedWord > xRes;
528 0 : if (!rOrigWord.isEmpty() && rxHyphWord.is())
529 : {
530 0 : sal_Int16 nChgPos = 0,
531 0 : nChgLen = 0;
532 0 : OUString aRplc;
533 0 : bool bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord );
534 :
535 0 : OUString aOrigHyphenatedWord;
536 0 : sal_Int16 nOrigHyphenPos = -1;
537 0 : sal_Int16 nOrigHyphenationPos = -1;
538 0 : if (!bAltSpelling)
539 : {
540 0 : aOrigHyphenatedWord = rOrigWord;
541 0 : nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() );
542 0 : nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() );
543 : }
544 : else
545 : {
546 : //! should at least work with the German words
547 : //! B-"u-c-k-er and Sc-hif-fah-rt
548 :
549 0 : OUString aLeft, aRight;
550 0 : sal_Int16 nPos = GetOrigWordPos( rOrigWord, nChgPos );
551 :
552 : // get words like Sc-hif-fah-rt to work correct
553 0 : sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
554 0 : if (nChgPos > nHyphenationPos)
555 0 : --nPos;
556 :
557 0 : aLeft = rOrigWord.copy( 0, nPos );
558 0 : aRight = rOrigWord.copy( nPos ); // FIXME: changes at the right side
559 :
560 0 : aOrigHyphenatedWord = aLeft;
561 0 : aOrigHyphenatedWord += aRplc;
562 0 : aOrigHyphenatedWord += aRight;
563 :
564 0 : nOrigHyphenPos = sal::static_int_cast< sal_Int16 >(aLeft.getLength() +
565 0 : rxHyphWord->getHyphenPos() - nChgPos);
566 0 : nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos );
567 : }
568 :
569 0 : if (nOrigHyphenPos == -1 || nOrigHyphenationPos == -1)
570 : {
571 : DBG_ASSERT( false, "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
572 : }
573 : else
574 : {
575 0 : sal_Int16 nLang = LinguLocaleToLanguage( rxHyphWord->getLocale() );
576 0 : xRes = new HyphenatedWord(
577 : rOrigWord, nLang, nOrigHyphenationPos,
578 0 : aOrigHyphenatedWord, nOrigHyphenPos );
579 0 : }
580 :
581 : }
582 0 : return xRes;
583 : }
584 :
585 425 : static CharClass & lcl_GetCharClass()
586 : {
587 425 : static CharClass aCC( LanguageTag( LANGUAGE_ENGLISH_US ));
588 425 : return aCC;
589 : }
590 :
591 425 : osl::Mutex & lcl_GetCharClassMutex()
592 : {
593 425 : static osl::Mutex aMutex;
594 425 : return aMutex;
595 : }
596 :
597 0 : bool IsUpper( const OUString &rText, sal_Int32 nPos, sal_Int32 nLen, sal_Int16 nLanguage )
598 : {
599 0 : MutexGuard aGuard( lcl_GetCharClassMutex() );
600 :
601 0 : CharClass &rCC = lcl_GetCharClass();
602 0 : rCC.setLanguageTag( LanguageTag( nLanguage ));
603 0 : sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen );
604 0 : return (nFlags & KCharacterType::UPPER)
605 0 : && !(nFlags & KCharacterType::LOWER);
606 : }
607 :
608 85381890 : CapType SAL_CALL capitalType(const OUString& aTerm, CharClass * pCC)
609 : {
610 85381890 : sal_Int32 tlen = aTerm.getLength();
611 85381890 : if ((pCC) && (tlen))
612 : {
613 85381890 : OUString aStr(aTerm);
614 85381890 : sal_Int32 nc = 0;
615 821649993 : for (sal_Int32 tindex = 0; tindex < tlen; ++tindex)
616 : {
617 736268103 : if (pCC->getCharacterType(aStr,tindex) &
618 68389708 : ::com::sun::star::i18n::KCharacterType::UPPER) nc++;
619 : }
620 :
621 85381890 : if (nc == 0)
622 50798510 : return CapType::NOCAP;
623 34583380 : if (nc == tlen)
624 532 : return CapType::ALLCAP;
625 34582848 : if ((nc == 1) && (pCC->getCharacterType(aStr,0) &
626 : ::com::sun::star::i18n::KCharacterType::UPPER))
627 11844277 : return CapType::INITCAP;
628 :
629 22738571 : return CapType::MIXED;
630 : }
631 0 : return CapType::UNKNOWN;
632 : }
633 :
634 425 : OUString ToLower( const OUString &rText, sal_Int16 nLanguage )
635 : {
636 425 : MutexGuard aGuard( lcl_GetCharClassMutex() );
637 :
638 425 : CharClass &rCC = lcl_GetCharClass();
639 425 : rCC.setLanguageTag( LanguageTag( nLanguage ));
640 425 : return rCC.lowercase( rText );
641 : }
642 :
643 : // sorted(!) array of unicode ranges for code points that are exclusively(!) used as numbers
644 : // and thus may NOT not be part of names or words like the Chinese/Japanese number characters
645 : static const sal_uInt32 the_aDigitZeroes [] =
646 : {
647 : 0x00000030, //0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE
648 : 0x00000660, //0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
649 : 0x000006F0, //06F9 ; Decimal # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
650 : 0x000007C0, //07C9 ; Decimal # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
651 : 0x00000966, //096F ; Decimal # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
652 : 0x000009E6, //09EF ; Decimal # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
653 : 0x00000A66, //0A6F ; Decimal # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
654 : 0x00000AE6, //0AEF ; Decimal # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
655 : 0x00000B66, //0B6F ; Decimal # Nd [10] ODIA DIGIT ZERO..ODIA DIGIT NINE
656 : 0x00000BE6, //0BEF ; Decimal # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
657 : 0x00000C66, //0C6F ; Decimal # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
658 : 0x00000CE6, //0CEF ; Decimal # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
659 : 0x00000D66, //0D6F ; Decimal # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
660 : 0x00000E50, //0E59 ; Decimal # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
661 : 0x00000ED0, //0ED9 ; Decimal # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
662 : 0x00000F20, //0F29 ; Decimal # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
663 : 0x00001040, //1049 ; Decimal # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
664 : 0x00001090, //1099 ; Decimal # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
665 : 0x000017E0, //17E9 ; Decimal # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
666 : 0x00001810, //1819 ; Decimal # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
667 : 0x00001946, //194F ; Decimal # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
668 : 0x000019D0, //19D9 ; Decimal # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
669 : 0x00001B50, //1B59 ; Decimal # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
670 : 0x00001BB0, //1BB9 ; Decimal # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
671 : 0x00001C40, //1C49 ; Decimal # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
672 : 0x00001C50, //1C59 ; Decimal # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
673 : 0x0000A620, //A629 ; Decimal # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
674 : 0x0000A8D0, //A8D9 ; Decimal # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
675 : 0x0000A900, //A909 ; Decimal # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
676 : 0x0000AA50, //AA59 ; Decimal # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
677 : 0x0000FF10, //FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
678 : 0x000104A0, //104A9 ; Decimal # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
679 : 0x0001D7CE //1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
680 : };
681 :
682 71070576 : bool HasDigits( const OUString &rText )
683 : {
684 : static const int nNumDigitZeroes = sizeof(the_aDigitZeroes) / sizeof(the_aDigitZeroes[0]);
685 71070576 : const sal_Int32 nLen = rText.getLength();
686 :
687 71070576 : sal_Int32 i = 0;
688 834224598 : while (i < nLen) // for all characters ...
689 : {
690 692088837 : const sal_uInt32 nCodePoint = rText.iterateCodePoints( &i ); // handle unicode surrogates correctly...
691 1364855972 : for (int j = 0; j < nNumDigitZeroes; ++j) // ... check in all 0..9 ranges
692 : {
693 1364855972 : sal_uInt32 nDigitZero = the_aDigitZeroes[ j ];
694 1364855972 : if (nDigitZero > nCodePoint)
695 692083446 : break;
696 672772526 : if (/*nDigitZero <= nCodePoint &&*/ nCodePoint <= nDigitZero + 9)
697 5391 : return true;
698 : }
699 : }
700 71065185 : return false;
701 : }
702 :
703 0 : bool IsNumeric( const OUString &rText )
704 : {
705 0 : bool bRes = false;
706 0 : if (!rText.isEmpty())
707 : {
708 0 : sal_Int32 nLen = rText.getLength();
709 0 : bRes = true;
710 0 : for(sal_Int32 i = 0; i < nLen; ++i)
711 : {
712 0 : sal_Unicode cChar = rText[ i ];
713 0 : if ( !((sal_Unicode)'0' <= cChar && cChar <= (sal_Unicode)'9') )
714 : {
715 0 : bRes = false;
716 0 : break;
717 : }
718 : }
719 : }
720 0 : return bRes;
721 : }
722 :
723 220 : uno::Reference< XLinguProperties > GetLinguProperties()
724 : {
725 220 : return LinguProperties::create( comphelper::getProcessComponentContext() );
726 : }
727 :
728 194437498 : uno::Reference< XSearchableDictionaryList > GetDictionaryList()
729 : {
730 194437498 : uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
731 194437498 : uno::Reference< XSearchableDictionaryList > xRef;
732 : try
733 : {
734 194437498 : xRef = DictionaryList::create(xContext);
735 : }
736 0 : catch (const uno::Exception &)
737 : {
738 : DBG_ASSERT( false, "createInstance failed" );
739 : }
740 :
741 194437498 : return xRef;
742 : }
743 :
744 97218693 : uno::Reference< XDictionary > GetIgnoreAllList()
745 : {
746 97218693 : uno::Reference< XDictionary > xRes;
747 194437386 : uno::Reference< XSearchableDictionaryList > xDL( GetDictionaryList() );
748 97218693 : if (xDL.is())
749 97218693 : xRes = xDL->getDictionaryByName( "IgnoreAllList" );
750 194437386 : return xRes;
751 : }
752 :
753 58 : AppExitListener::AppExitListener()
754 : {
755 : // add object to Desktop EventListeners in order to properly call
756 : // the AtExit function at appliction exit.
757 58 : uno::Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
758 :
759 : try
760 : {
761 58 : xDesktop = frame::Desktop::create(xContext);
762 : }
763 0 : catch (const uno::Exception &)
764 : {
765 : DBG_ASSERT( false, "createInstance failed" );
766 58 : }
767 58 : }
768 :
769 54 : AppExitListener::~AppExitListener()
770 : {
771 54 : }
772 :
773 58 : void AppExitListener::Activate()
774 : {
775 58 : if (xDesktop.is())
776 58 : xDesktop->addTerminateListener( this );
777 58 : }
778 :
779 54 : void AppExitListener::Deactivate()
780 : {
781 54 : if (xDesktop.is())
782 0 : xDesktop->removeTerminateListener( this );
783 54 : }
784 :
785 : void SAL_CALL
786 58 : AppExitListener::disposing( const EventObject& rEvtSource )
787 : throw(RuntimeException, std::exception)
788 : {
789 58 : MutexGuard aGuard( GetLinguMutex() );
790 :
791 58 : if (xDesktop.is() && rEvtSource.Source == xDesktop)
792 : {
793 58 : xDesktop = NULL; //! release reference to desktop
794 58 : }
795 58 : }
796 :
797 : void SAL_CALL
798 30 : AppExitListener::queryTermination( const EventObject& /*rEvtSource*/ )
799 : throw(frame::TerminationVetoException, RuntimeException, std::exception)
800 : {
801 30 : }
802 :
803 : void SAL_CALL
804 30 : AppExitListener::notifyTermination( const EventObject& rEvtSource )
805 : throw(RuntimeException, std::exception)
806 : {
807 30 : MutexGuard aGuard( GetLinguMutex() );
808 :
809 30 : if (xDesktop.is() && rEvtSource.Source == xDesktop)
810 : {
811 30 : AtExit();
812 30 : }
813 30 : }
814 :
815 : } // namespace linguistic
816 :
817 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|