Update ooo320-m1
[ooovba.git] / linguistic / source / misc.cxx
blob2df19215fdf60336012cfae1a9e3668c95659926
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: misc.cxx,v $
10 * $Revision: 1.31 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_linguistic.hxx"
33 #include <tools/string.hxx>
34 #include <tools/fsys.hxx>
35 #include <tools/debug.hxx>
36 #include <svtools/pathoptions.hxx>
37 #include <svtools/lngmisc.hxx>
38 #include <ucbhelper/content.hxx>
39 #include <i18npool/mslangid.hxx>
40 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/beans/XFastPropertySet.hpp>
43 #include <com/sun/star/beans/XPropertyChangeListener.hpp>
44 #include <com/sun/star/frame/XTerminateListener.hpp>
45 #include <com/sun/star/frame/XDesktop.hpp>
46 #include <com/sun/star/frame/XStorable.hpp>
48 #include <com/sun/star/beans/PropertyValues.hpp>
49 #include <com/sun/star/uno/Sequence.hxx>
50 #include <com/sun/star/uno/Reference.h>
51 #include <com/sun/star/linguistic2/DictionaryType.hpp>
52 #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
53 #include <unotools/processfactory.hxx>
54 #include <unotools/localedatawrapper.hxx>
56 #include <rtl/instance.hxx>
58 #include "misc.hxx"
59 #include "defs.hxx"
60 #include "lngprops.hxx"
61 #include "hyphdta.hxx"
64 using namespace utl;
65 using namespace osl;
66 using namespace rtl;
67 using namespace com::sun::star;
68 using namespace com::sun::star::beans;
69 using namespace com::sun::star::lang;
70 using namespace com::sun::star::uno;
71 using namespace com::sun::star::i18n;
72 using namespace com::sun::star::linguistic2;
74 namespace linguistic
77 ///////////////////////////////////////////////////////////////////////////
79 //!! multi-thread safe mutex for all platforms !!
80 struct LinguMutex : public rtl::Static< osl::Mutex, LinguMutex >
84 osl::Mutex & GetLinguMutex()
86 return LinguMutex::get();
89 ///////////////////////////////////////////////////////////////////////////
91 LocaleDataWrapper & GetLocaleDataWrapper( INT16 nLang )
93 static LocaleDataWrapper aLclDtaWrp(
94 getProcessServiceFactory(),
95 CreateLocale( Application::GetSettings().GetUILanguage() ) );
97 const Locale &rLcl = aLclDtaWrp.getLoadedLocale();
98 Locale aLcl( CreateLocale( nLang ) );
99 if (aLcl.Language != rLcl.Language ||
100 aLcl.Country != rLcl.Country ||
101 aLcl.Variant != rLcl.Variant)
102 aLclDtaWrp.setLocale( aLcl );
103 return aLclDtaWrp;
106 ///////////////////////////////////////////////////////////////////////////
109 returns text-encoding used for ByteString unicode String conversion
111 rtl_TextEncoding GetTextEncoding( INT16 nLanguage )
113 DBG_ASSERT( nLanguage != LANGUAGE_NONE, "invalid language argument" );
114 static INT16 nLastLanguage = LANGUAGE_NONE;
116 // set default value for unknown languages
117 static rtl_TextEncoding nEncoding = RTL_TEXTENCODING_DONTKNOW;
119 if (nLastLanguage != nLanguage)
121 //!! IPR uses textencodings Latin-1, Latin-2, Latin-5 and Latin-7 !!
123 nLastLanguage = nLanguage;
124 switch (nLanguage)
126 case LANGUAGE_GERMAN :
127 case LANGUAGE_GERMAN_SWISS :
128 case LANGUAGE_ENGLISH_US :
129 case LANGUAGE_ENGLISH_UK :
130 case LANGUAGE_FRENCH :
131 case LANGUAGE_ITALIAN :
132 case LANGUAGE_SPANISH :
133 case LANGUAGE_CATALAN :
134 case LANGUAGE_PORTUGUESE :
135 case LANGUAGE_PORTUGUESE_BRAZILIAN :
136 case LANGUAGE_DANISH :
137 case LANGUAGE_DUTCH :
138 case LANGUAGE_SWEDISH :
139 case LANGUAGE_FINNISH :
140 case LANGUAGE_NORWEGIAN_BOKMAL :
141 case LANGUAGE_NORWEGIAN_NYNORSK :
142 case LANGUAGE_AFRIKAANS :
143 case LANGUAGE_ENGLISH_EIRE :
144 case LANGUAGE_ENGLISH_AUS :
145 #ifdef WNT
146 nEncoding = RTL_TEXTENCODING_MS_1252; break;
147 #else
148 nEncoding = RTL_TEXTENCODING_ISO_8859_1; break;
149 #endif
150 case LANGUAGE_CZECH :
151 case LANGUAGE_HUNGARIAN :
152 case LANGUAGE_POLISH :
153 #ifdef WNT
154 nEncoding = RTL_TEXTENCODING_MS_1250; break;
155 #else
156 nEncoding = RTL_TEXTENCODING_ISO_8859_2; break;
157 #endif
158 case LANGUAGE_RUSSIAN :
159 #ifdef WNT
160 nEncoding = RTL_TEXTENCODING_MS_1251; break;
161 #else
162 nEncoding = RTL_TEXTENCODING_ISO_8859_5; break;
163 #endif
164 case LANGUAGE_GREEK :
165 #ifdef WNT
166 nEncoding = RTL_TEXTENCODING_MS_1253; break;
167 #else
168 nEncoding = RTL_TEXTENCODING_ISO_8859_7; break;
169 #endif
170 default:
171 DBG_ASSERT( 0, "unexpected language" );
175 return nEncoding;
178 ///////////////////////////////////////////////////////////////////////////
180 static inline sal_Int32 Minimum( sal_Int32 n1, sal_Int32 n2, sal_Int32 n3 )
182 sal_Int32 nMin = n1 < n2 ? n1 : n2;
183 return nMin < n3 ? nMin : n3;
186 ///////////////////////////////////////////////////////////////////////////
188 class IntArray2D
190 private:
191 sal_Int32 *pData;
192 int n1, n2;
194 public:
195 IntArray2D( int nDim1, int nDim2 );
196 ~IntArray2D();
198 sal_Int32 & Value( int i, int k );
201 IntArray2D::IntArray2D( int nDim1, int nDim2 )
203 n1 = nDim1;
204 n2 = nDim2;
205 pData = new sal_Int32[n1 * n2];
208 IntArray2D::~IntArray2D()
210 delete[] pData;
213 sal_Int32 & IntArray2D::Value( int i, int k )
215 DBG_ASSERT( 0 <= i && i < n1, "first index out of range" );
216 DBG_ASSERT( 0 <= k && k < n2, "first index out of range" );
217 DBG_ASSERT( i * n2 + k < n1 * n2, "index out of range" );
218 return pData[ i * n2 + k ];
222 sal_Int32 LevDistance( const OUString &rTxt1, const OUString &rTxt2 )
224 sal_Int32 nLen1 = rTxt1.getLength();
225 sal_Int32 nLen2 = rTxt2.getLength();
227 if (nLen1 == 0)
228 return nLen2;
229 if (nLen2 == 0)
230 return nLen1;
232 IntArray2D aData( nLen1 + 1, nLen2 + 1 );
234 sal_Int32 i, k;
235 for (i = 0; i <= nLen1; ++i)
236 aData.Value(i, 0) = i;
237 for (k = 0; k <= nLen2; ++k)
238 aData.Value(0, k) = k;
239 for (i = 1; i <= nLen1; ++i)
241 for (k = 1; k <= nLen2; ++k)
243 sal_Unicode c1i = rTxt1.getStr()[i - 1];
244 sal_Unicode c2k = rTxt2.getStr()[k - 1];
245 sal_Int32 nCost = c1i == c2k ? 0 : 1;
246 sal_Int32 nNew = Minimum( aData.Value(i-1, k ) + 1,
247 aData.Value(i , k-1) + 1,
248 aData.Value(i-1, k-1) + nCost );
249 // take transposition (exchange with left or right char) in account
250 if (2 < i && 2 < k)
252 int nT = aData.Value(i-2, k-2) + 1;
253 if (rTxt1.getStr()[i - 2] != c1i)
254 ++nT;
255 if (rTxt2.getStr()[k - 2] != c2k)
256 ++nT;
257 if (nT < nNew)
258 nNew = nT;
261 aData.Value(i, k) = nNew;
264 sal_Int32 nDist = aData.Value(nLen1, nLen2);
265 return nDist;
268 ///////////////////////////////////////////////////////////////////////////
270 BOOL IsUseDicList( const PropertyValues &rProperties,
271 const uno::Reference< XPropertySet > &rxProp )
273 BOOL bRes = TRUE;
275 INT32 nLen = rProperties.getLength();
276 const PropertyValue *pVal = rProperties.getConstArray();
277 INT32 i;
279 for ( i = 0; i < nLen; ++i)
281 if (UPH_IS_USE_DICTIONARY_LIST == pVal[i].Handle)
283 pVal[i].Value >>= bRes;
284 break;
287 if (i >= nLen) // no temporary value found in 'rProperties'
289 uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
290 if (xFast.is())
291 xFast->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST ) >>= bRes;
294 return bRes;
298 BOOL IsIgnoreControlChars( const PropertyValues &rProperties,
299 const uno::Reference< XPropertySet > &rxProp )
301 BOOL bRes = TRUE;
303 INT32 nLen = rProperties.getLength();
304 const PropertyValue *pVal = rProperties.getConstArray();
305 INT32 i;
307 for ( i = 0; i < nLen; ++i)
309 if (UPH_IS_IGNORE_CONTROL_CHARACTERS == pVal[i].Handle)
311 pVal[i].Value >>= bRes;
312 break;
315 if (i >= nLen) // no temporary value found in 'rProperties'
317 uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
318 if (xFast.is())
319 xFast->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS ) >>= bRes;
322 return bRes;
326 static BOOL lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry )
328 BOOL bRes = FALSE;
329 if (xEntry.is())
331 // there has to be (at least one) '=' denoting a hyphenation position
332 // and it must not be before any character of the word
333 sal_Int32 nIdx = xEntry->getDictionaryWord().indexOf( '=' );
334 bRes = nIdx != -1 && nIdx != 0;
336 return bRes;
340 uno::Reference< XDictionaryEntry > SearchDicList(
341 const uno::Reference< XDictionaryList > &xDicList,
342 const OUString &rWord, INT16 nLanguage,
343 BOOL bSearchPosDics, BOOL bSearchSpellEntry )
345 MutexGuard aGuard( GetLinguMutex() );
347 uno::Reference< XDictionaryEntry > xEntry;
349 if (!xDicList.is())
350 return xEntry;
352 const uno::Sequence< uno::Reference< XDictionary > >
353 aDics( xDicList->getDictionaries() );
354 const uno::Reference< XDictionary >
355 *pDic = aDics.getConstArray();
356 INT32 nDics = xDicList->getCount();
358 INT32 i;
359 for (i = 0; i < nDics; i++)
361 uno::Reference< XDictionary > axDic( pDic[i], UNO_QUERY );
363 DictionaryType eType = axDic->getDictionaryType();
364 INT16 nLang = LocaleToLanguage( axDic->getLocale() );
366 if ( axDic.is() && axDic->isActive()
367 && (nLang == nLanguage || nLang == LANGUAGE_NONE) )
369 DBG_ASSERT( eType != DictionaryType_MIXED,
370 "lng : unexpected dictionary type" );
372 if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE)
373 || ( bSearchPosDics && eType == DictionaryType_POSITIVE))
375 if ( (xEntry = axDic->getEntry( rWord )).is() )
377 if (bSearchSpellEntry || lcl_HasHyphInfo( xEntry ))
378 break;
380 xEntry = 0;
385 return xEntry;
389 sal_Bool SaveDictionaries( const uno::Reference< XDictionaryList > &xDicList )
391 if (!xDicList.is())
392 return sal_True;
394 sal_Bool bRet = sal_True;
396 Sequence< uno::Reference< XDictionary > > aDics( xDicList->getDictionaries() );
397 const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
398 INT32 nCount = aDics.getLength();
399 for (INT32 i = 0; i < nCount; i++)
403 uno::Reference< frame::XStorable > xStor( pDic[i], UNO_QUERY );
404 if (xStor.is())
406 if (!xStor->isReadonly() && xStor->hasLocation())
407 xStor->store();
410 catch(uno::Exception &)
412 bRet = sal_False;
416 return bRet;
420 sal_uInt8 AddEntryToDic(
421 uno::Reference< XDictionary > &rxDic,
422 const OUString &rWord, sal_Bool bIsNeg,
423 const OUString &rRplcTxt, sal_Int16 /* nRplcLang */,
424 sal_Bool bStripDot )
426 if (!rxDic.is())
427 return DIC_ERR_NOT_EXISTS;
429 OUString aTmp( rWord );
430 if (bStripDot)
432 sal_Int32 nLen = rWord.getLength();
433 if (nLen > 0 && '.' == rWord[ nLen - 1])
435 // remove trailing '.'
436 // (this is the official way to do this :-( )
437 aTmp = aTmp.copy( 0, nLen - 1 );
440 sal_Bool bAddOk = rxDic->add( aTmp, bIsNeg, rRplcTxt );
442 sal_uInt8 nRes = DIC_ERR_NONE;
443 if (!bAddOk)
445 if (rxDic->isFull())
446 nRes = DIC_ERR_FULL;
447 else
449 uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
450 if (xStor.is() && xStor->isReadonly())
451 nRes = DIC_ERR_READONLY;
452 else
453 nRes = DIC_ERR_UNKNOWN;
457 return nRes;
461 ///////////////////////////////////////////////////////////////////////////
463 LanguageType LocaleToLanguage( const Locale& rLocale )
465 // empty Locale -> LANGUAGE_NONE
466 if ( rLocale.Language.getLength() == 0 )
467 return LANGUAGE_NONE;
469 return MsLangId::convertLocaleToLanguage( rLocale );
473 Locale& LanguageToLocale( Locale& rLocale, LanguageType eLang )
475 if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */)
476 MsLangId::convertLanguageToLocale( eLang, rLocale );
478 return rLocale;
481 Locale CreateLocale( LanguageType eLang )
483 Locale aLocale;
484 if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */)
485 return MsLangId::convertLanguageToLocale( eLang );
487 return aLocale;
490 uno::Sequence< Locale > LangSeqToLocaleSeq( const uno::Sequence< INT16 > &rLangSeq )
492 const INT16 *pLang = rLangSeq.getConstArray();
493 INT32 nCount = rLangSeq.getLength();
495 uno::Sequence< Locale > aLocales( nCount );
496 Locale *pLocale = aLocales.getArray();
497 for (INT32 i = 0; i < nCount; ++i)
499 LanguageToLocale( pLocale[i], pLang[ i ] );
502 return aLocales;
505 uno::Sequence< INT16 >
506 LocaleSeqToLangSeq( uno::Sequence< Locale > &rLocaleSeq )
508 const Locale *pLocale = rLocaleSeq.getConstArray();
509 INT32 nCount = rLocaleSeq.getLength();
511 uno::Sequence< INT16 > aLangs( nCount );
512 INT16 *pLang = aLangs.getArray();
513 for (INT32 i = 0; i < nCount; ++i)
515 pLang[i] = LocaleToLanguage( pLocale[i] );
518 return aLangs;
521 ///////////////////////////////////////////////////////////////////////////
523 BOOL IsReadOnly( const String &rURL, BOOL *pbExist )
525 BOOL bRes = FALSE;
526 BOOL bExists = FALSE;
528 if (rURL.Len() > 0)
532 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xCmdEnv;
533 ::ucbhelper::Content aContent( rURL, xCmdEnv );
535 bExists = aContent.isDocument();
536 if (bExists)
538 Any aAny( aContent.getPropertyValue( A2OU( "IsReadOnly" ) ) );
539 aAny >>= bRes;
542 catch (Exception &)
544 bRes = TRUE;
548 if (pbExist)
549 *pbExist = bExists;
550 return bRes;
553 ///////////////////////////////////////////////////////////////////////////
556 static BOOL GetAltSpelling( INT16 &rnChgPos, INT16 &rnChgLen, OUString &rRplc,
557 uno::Reference< XHyphenatedWord > &rxHyphWord )
559 BOOL bRes = rxHyphWord->isAlternativeSpelling();
560 if (bRes)
562 OUString aWord( rxHyphWord->getWord() ),
563 aHyphenatedWord( rxHyphWord->getHyphenatedWord() );
564 INT16 nHyphenationPos = rxHyphWord->getHyphenationPos();
565 /*INT16 nHyphenPos = rxHyphWord->getHyphenPos()*/;
566 const sal_Unicode *pWord = aWord.getStr(),
567 *pAltWord = aHyphenatedWord.getStr();
569 // at least char changes directly left or right to the hyphen
570 // should(!) be handled properly...
571 //! nHyphenationPos and nHyphenPos differ at most by 1 (see above)
572 //! Beware: eg "Schiffahrt" in German (pre spelling reform)
573 //! proves to be a bit nasty (nChgPosLeft and nChgPosRight overlap
574 //! to an extend.)
576 // find first different char from left
577 sal_Int32 nPosL = 0,
578 nAltPosL = 0;
579 for (INT16 i = 0 ; pWord[ nPosL ] == pAltWord[ nAltPosL ]; nPosL++, nAltPosL++, i++)
581 // restrict changes area beginning to the right to
582 // the char immediately following the hyphen.
583 //! serves to insert the additional "f" in "Schiffahrt" at
584 //! position 5 rather than position 6.
585 if (i >= nHyphenationPos + 1)
586 break;
589 // find first different char from right
590 sal_Int32 nPosR = aWord.getLength() - 1,
591 nAltPosR = aHyphenatedWord.getLength() - 1;
592 for ( ; nPosR >= nPosL && nAltPosR >= nAltPosL
593 && pWord[ nPosR ] == pAltWord[ nAltPosR ];
594 nPosR--, nAltPosR--)
597 rnChgPos = sal::static_int_cast< INT16 >(nPosL);
598 rnChgLen = sal::static_int_cast< INT16 >(nPosR - nPosL + 1);
599 DBG_ASSERT( rnChgLen >= 0, "nChgLen < 0");
601 sal_Int32 nTxtStart = nPosL;
602 sal_Int32 nTxtLen = nAltPosL - nPosL + 1;
603 rRplc = aHyphenatedWord.copy( nTxtStart, nTxtLen );
605 return bRes;
609 static INT16 GetOrigWordPos( const OUString &rOrigWord, INT16 nPos )
611 INT32 nLen = rOrigWord.getLength();
612 INT32 i = -1;
613 while (nPos >= 0 && i++ < nLen)
615 sal_Unicode cChar = rOrigWord[i];
616 BOOL bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
617 if (!bSkip)
618 --nPos;
620 return sal::static_int_cast< INT16 >((0 <= i && i < nLen) ? i : -1);
624 INT32 GetPosInWordToCheck( const OUString &rTxt, INT32 nPos )
626 INT32 nRes = -1;
627 INT32 nLen = rTxt.getLength();
628 if (0 <= nPos && nPos < nLen)
630 nRes = 0;
631 for (INT32 i = 0; i < nPos; ++i)
633 sal_Unicode cChar = rTxt[i];
634 BOOL bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
635 if (!bSkip)
636 ++nRes;
639 return nRes;
643 uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars(
644 const OUString &rOrigWord,
645 uno::Reference< XHyphenatedWord > &rxHyphWord )
647 uno::Reference< XHyphenatedWord > xRes;
648 if (rOrigWord.getLength() && rxHyphWord.is())
650 INT16 nChgPos = 0,
651 nChgLen = 0;
652 OUString aRplc;
653 BOOL bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord );
654 #if OSL_DEBUG_LEVEL > 1
655 OUString aWord( rxHyphWord->getWord() );
656 #endif
658 OUString aOrigHyphenatedWord;
659 INT16 nOrigHyphenPos = -1;
660 INT16 nOrigHyphenationPos = -1;
661 if (!bAltSpelling)
663 aOrigHyphenatedWord = rOrigWord;
664 nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() );
665 nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() );
667 else
669 //! should at least work with the German words
670 //! B�-c-k-er and Sc-hif-fah-rt
672 OUString aLeft, aRight;
673 INT16 nPos = GetOrigWordPos( rOrigWord, nChgPos );
675 // get words like Sc-hif-fah-rt to work correct
676 INT16 nHyphenationPos = rxHyphWord->getHyphenationPos();
677 if (nChgPos > nHyphenationPos)
678 --nPos;
680 aLeft = rOrigWord.copy( 0, nPos );
681 aRight = rOrigWord.copy( nPos + nChgLen );
683 aOrigHyphenatedWord = aLeft;
684 aOrigHyphenatedWord += aRplc;
685 aOrigHyphenatedWord += aRight;
687 nOrigHyphenPos = sal::static_int_cast< INT16 >(aLeft.getLength() +
688 rxHyphWord->getHyphenPos() - nChgPos);
689 nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos );
692 if (nOrigHyphenPos == -1 || nOrigHyphenationPos == -1)
694 DBG_ASSERT( 0, "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
696 else
698 INT16 nLang = LocaleToLanguage( rxHyphWord->getLocale() );
699 xRes = new HyphenatedWord(
700 rOrigWord, nLang, nOrigHyphenationPos,
701 aOrigHyphenatedWord, nOrigHyphenPos );
705 return xRes;
709 ///////////////////////////////////////////////////////////////////////////
712 static CharClass & lcl_GetCharClass()
714 static CharClass aCC( CreateLocale( LANGUAGE_ENGLISH_US ) );
715 return aCC;
719 osl::Mutex & lcl_GetCharClassMutex()
721 static osl::Mutex aMutex;
722 return aMutex;
726 BOOL IsUpper( const String &rText, xub_StrLen nPos, xub_StrLen nLen, INT16 nLanguage )
728 MutexGuard aGuard( lcl_GetCharClassMutex() );
730 CharClass &rCC = lcl_GetCharClass();
731 rCC.setLocale( CreateLocale( nLanguage ) );
732 sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen );
733 return (nFlags & KCharacterType::UPPER)
734 && !(nFlags & KCharacterType::LOWER);
738 BOOL IsLower( const String &rText, xub_StrLen nPos, xub_StrLen nLen, INT16 nLanguage )
740 MutexGuard aGuard( lcl_GetCharClassMutex() );
742 CharClass &rCC = lcl_GetCharClass();
743 rCC.setLocale( CreateLocale( nLanguage ) );
744 sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen );
745 return (nFlags & KCharacterType::LOWER)
746 && !(nFlags & KCharacterType::UPPER);
750 String ToLower( const String &rText, INT16 nLanguage )
752 MutexGuard aGuard( lcl_GetCharClassMutex() );
754 CharClass &rCC = lcl_GetCharClass();
755 rCC.setLocale( CreateLocale( nLanguage ) );
756 return rCC.lower( rText );
760 String ToUpper( const String &rText, INT16 nLanguage )
762 MutexGuard aGuard( lcl_GetCharClassMutex() );
764 CharClass &rCC = lcl_GetCharClass();
765 rCC.setLocale( CreateLocale( nLanguage ) );
766 return rCC.upper( rText );
770 String ToTitle( const String &rText, INT16 nLanguage )
772 MutexGuard aGuard( lcl_GetCharClassMutex() );
774 CharClass &rCC = lcl_GetCharClass();
775 rCC.setLocale( CreateLocale( nLanguage ) );
776 return rCC.toTitle( rText, 0, rText.Len() );
780 sal_Unicode ToLower( const sal_Unicode cChar, INT16 nLanguage )
782 MutexGuard aGuard( lcl_GetCharClassMutex() );
784 CharClass &rCC = lcl_GetCharClass();
785 rCC.setLocale( CreateLocale( nLanguage ) );
786 return rCC.lower( cChar ).GetChar(0);
790 sal_Unicode ToUpper( const sal_Unicode cChar, INT16 nLanguage )
792 MutexGuard aGuard( lcl_GetCharClassMutex() );
794 CharClass &rCC = lcl_GetCharClass();
795 rCC.setLocale( CreateLocale( nLanguage ) );
796 return rCC.upper( cChar ).GetChar(0);
799 // sorted(!) array of unicode ranges for code points that are exclusively(!) used as numbers
800 // and thus may NOT not be part of names or words like the Chinese/Japanese number characters
801 static const sal_uInt32 the_aDigitZeroes [] =
803 0x00000030, //0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE
804 0x00000660, //0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
805 0x000006F0, //06F9 ; Decimal # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
806 0x000007C0, //07C9 ; Decimal # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
807 0x00000966, //096F ; Decimal # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
808 0x000009E6, //09EF ; Decimal # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
809 0x00000A66, //0A6F ; Decimal # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
810 0x00000AE6, //0AEF ; Decimal # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
811 0x00000B66, //0B6F ; Decimal # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
812 0x00000BE6, //0BEF ; Decimal # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
813 0x00000C66, //0C6F ; Decimal # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
814 0x00000CE6, //0CEF ; Decimal # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
815 0x00000D66, //0D6F ; Decimal # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
816 0x00000E50, //0E59 ; Decimal # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
817 0x00000ED0, //0ED9 ; Decimal # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
818 0x00000F20, //0F29 ; Decimal # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
819 0x00001040, //1049 ; Decimal # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
820 0x00001090, //1099 ; Decimal # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
821 0x000017E0, //17E9 ; Decimal # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
822 0x00001810, //1819 ; Decimal # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
823 0x00001946, //194F ; Decimal # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
824 0x000019D0, //19D9 ; Decimal # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
825 0x00001B50, //1B59 ; Decimal # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
826 0x00001BB0, //1BB9 ; Decimal # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
827 0x00001C40, //1C49 ; Decimal # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
828 0x00001C50, //1C59 ; Decimal # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
829 0x0000A620, //A629 ; Decimal # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
830 0x0000A8D0, //A8D9 ; Decimal # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
831 0x0000A900, //A909 ; Decimal # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
832 0x0000AA50, //AA59 ; Decimal # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
833 0x0000FF10, //FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
834 0x000104A0, //104A9 ; Decimal # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
835 0x0001D7CE //1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
838 BOOL HasDigits( const OUString &rText )
840 static const int nNumDigitZeroes = sizeof(the_aDigitZeroes) / sizeof(the_aDigitZeroes[0]);
841 const sal_Int32 nLen = rText.getLength();
843 sal_Int32 i = 0;
844 while (i < nLen) // for all characters ...
846 const sal_uInt32 nCodePoint = rText.iterateCodePoints( &i ); // handle unicode surrogates correctly...
847 for (int j = 0; j < nNumDigitZeroes; ++j) // ... check in all 0..9 ranges
849 sal_uInt32 nDigitZero = the_aDigitZeroes[ j ];
850 if (nDigitZero > nCodePoint)
851 break;
852 if (/*nDigitZero <= nCodePoint &&*/ nCodePoint <= nDigitZero + 9)
853 return TRUE;
856 return FALSE;
860 BOOL IsNumeric( const String &rText )
862 BOOL bRes = FALSE;
863 xub_StrLen nLen = rText.Len();
864 if (nLen)
866 bRes = TRUE;
867 xub_StrLen i = 0;
868 while (i < nLen)
870 sal_Unicode cChar = rText.GetChar( i++ );
871 if ( !((sal_Unicode)'0' <= cChar && cChar <= (sal_Unicode)'9') )
873 bRes = FALSE;
874 break;
878 return bRes;
882 ///////////////////////////////////////////////////////////////////////////
884 uno::Reference< XInterface > GetOneInstanceService( const char *pServiceName )
886 uno::Reference< XInterface > xRef;
888 if (pServiceName)
890 uno::Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
891 if (xMgr.is())
895 xRef = xMgr->createInstance( A2OU( pServiceName ) );
897 catch (uno::Exception &)
899 DBG_ASSERT( 0, "createInstance failed" );
904 return xRef;
907 uno::Reference< XPropertySet > GetLinguProperties()
909 return uno::Reference< XPropertySet > (
910 GetOneInstanceService( SN_LINGU_PROPERTIES ), UNO_QUERY );
913 uno::Reference< XSearchableDictionaryList > GetSearchableDictionaryList()
915 return uno::Reference< XSearchableDictionaryList > (
916 GetOneInstanceService( SN_DICTIONARY_LIST ), UNO_QUERY );
919 uno::Reference< XDictionaryList > GetDictionaryList()
921 return uno::Reference< XDictionaryList > (
922 GetOneInstanceService( SN_DICTIONARY_LIST ), UNO_QUERY );
925 uno::Reference< XDictionary > GetIgnoreAllList()
927 uno::Reference< XDictionary > xRes;
928 uno::Reference< XDictionaryList > xDL( GetDictionaryList() );
929 if (xDL.is())
930 xRes = xDL->getDictionaryByName( A2OU("IgnoreAllList") );
931 return xRes;
934 ///////////////////////////////////////////////////////////////////////////
936 AppExitListener::AppExitListener()
938 // add object to Desktop EventListeners in order to properly call
939 // the AtExit function at appliction exit.
940 uno::Reference< XMultiServiceFactory > xMgr = getProcessServiceFactory();
942 if (xMgr.is())
946 xDesktop = uno::Reference< frame::XDesktop >(
947 xMgr->createInstance( A2OU( SN_DESKTOP ) ), UNO_QUERY );
949 catch (uno::Exception &)
951 DBG_ASSERT( 0, "createInstance failed" );
956 AppExitListener::~AppExitListener()
961 void AppExitListener::Activate()
963 if (xDesktop.is())
964 xDesktop->addTerminateListener( this );
968 void AppExitListener::Deactivate()
970 if (xDesktop.is())
971 xDesktop->removeTerminateListener( this );
975 void SAL_CALL
976 AppExitListener::disposing( const EventObject& rEvtSource )
977 throw(RuntimeException)
979 MutexGuard aGuard( GetLinguMutex() );
981 if (xDesktop.is() && rEvtSource.Source == xDesktop)
983 xDesktop = NULL; //! release reference to desktop
988 void SAL_CALL
989 AppExitListener::queryTermination( const EventObject& /*rEvtSource*/ )
990 throw(frame::TerminationVetoException, RuntimeException)
992 //MutexGuard aGuard( GetLinguMutex() );
996 void SAL_CALL
997 AppExitListener::notifyTermination( const EventObject& rEvtSource )
998 throw(RuntimeException)
1000 MutexGuard aGuard( GetLinguMutex() );
1002 if (xDesktop.is() && rEvtSource.Source == xDesktop)
1004 AtExit();
1008 ///////////////////////////////////////////////////////////////////////////
1010 } // namespace linguistic