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