1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: misc.cxx,v $
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>
60 #include "lngprops.hxx"
61 #include "hyphdta.hxx"
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
;
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
);
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
;
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
:
146 nEncoding
= RTL_TEXTENCODING_MS_1252
; break;
148 nEncoding
= RTL_TEXTENCODING_ISO_8859_1
; break;
150 case LANGUAGE_CZECH
:
151 case LANGUAGE_HUNGARIAN
:
152 case LANGUAGE_POLISH
:
154 nEncoding
= RTL_TEXTENCODING_MS_1250
; break;
156 nEncoding
= RTL_TEXTENCODING_ISO_8859_2
; break;
158 case LANGUAGE_RUSSIAN
:
160 nEncoding
= RTL_TEXTENCODING_MS_1251
; break;
162 nEncoding
= RTL_TEXTENCODING_ISO_8859_5
; break;
164 case LANGUAGE_GREEK
:
166 nEncoding
= RTL_TEXTENCODING_MS_1253
; break;
168 nEncoding
= RTL_TEXTENCODING_ISO_8859_7
; break;
171 DBG_ASSERT( 0, "unexpected language" );
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 ///////////////////////////////////////////////////////////////////////////
195 IntArray2D( int nDim1
, int nDim2
);
198 sal_Int32
& Value( int i
, int k
);
201 IntArray2D::IntArray2D( int nDim1
, int nDim2
)
205 pData
= new sal_Int32
[n1
* n2
];
208 IntArray2D::~IntArray2D()
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();
232 IntArray2D
aData( nLen1
+ 1, nLen2
+ 1 );
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
252 int nT
= aData
.Value(i
-2, k
-2) + 1;
253 if (rTxt1
.getStr()[i
- 2] != c1i
)
255 if (rTxt2
.getStr()[k
- 2] != c2k
)
261 aData
.Value(i
, k
) = nNew
;
264 sal_Int32 nDist
= aData
.Value(nLen1
, nLen2
);
268 ///////////////////////////////////////////////////////////////////////////
270 BOOL
IsUseDicList( const PropertyValues
&rProperties
,
271 const uno::Reference
< XPropertySet
> &rxProp
)
275 INT32 nLen
= rProperties
.getLength();
276 const PropertyValue
*pVal
= rProperties
.getConstArray();
279 for ( i
= 0; i
< nLen
; ++i
)
281 if (UPH_IS_USE_DICTIONARY_LIST
== pVal
[i
].Handle
)
283 pVal
[i
].Value
>>= bRes
;
287 if (i
>= nLen
) // no temporary value found in 'rProperties'
289 uno::Reference
< XFastPropertySet
> xFast( rxProp
, UNO_QUERY
);
291 xFast
->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST
) >>= bRes
;
298 BOOL
IsIgnoreControlChars( const PropertyValues
&rProperties
,
299 const uno::Reference
< XPropertySet
> &rxProp
)
303 INT32 nLen
= rProperties
.getLength();
304 const PropertyValue
*pVal
= rProperties
.getConstArray();
307 for ( i
= 0; i
< nLen
; ++i
)
309 if (UPH_IS_IGNORE_CONTROL_CHARACTERS
== pVal
[i
].Handle
)
311 pVal
[i
].Value
>>= bRes
;
315 if (i
>= nLen
) // no temporary value found in 'rProperties'
317 uno::Reference
< XFastPropertySet
> xFast( rxProp
, UNO_QUERY
);
319 xFast
->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS
) >>= bRes
;
326 static BOOL
lcl_HasHyphInfo( const uno::Reference
<XDictionaryEntry
> &xEntry
)
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;
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
;
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();
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
))
389 sal_Bool
SaveDictionaries( const uno::Reference
< XDictionaryList
> &xDicList
)
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
);
406 if (!xStor
->isReadonly() && xStor
->hasLocation())
410 catch(uno::Exception
&)
420 sal_uInt8
AddEntryToDic(
421 uno::Reference
< XDictionary
> &rxDic
,
422 const OUString
&rWord
, sal_Bool bIsNeg
,
423 const OUString
&rRplcTxt
, sal_Int16
/* nRplcLang */,
427 return DIC_ERR_NOT_EXISTS
;
429 OUString
aTmp( rWord
);
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
;
449 uno::Reference
< frame::XStorable
> xStor( rxDic
, UNO_QUERY
);
450 if (xStor
.is() && xStor
->isReadonly())
451 nRes
= DIC_ERR_READONLY
;
453 nRes
= DIC_ERR_UNKNOWN
;
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
);
481 Locale
CreateLocale( LanguageType eLang
)
484 if ( eLang
!= LANGUAGE_NONE
/* && eLang != LANGUAGE_SYSTEM */)
485 return MsLangId::convertLanguageToLocale( eLang
);
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
] );
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
] );
521 ///////////////////////////////////////////////////////////////////////////
523 BOOL
IsReadOnly( const String
&rURL
, BOOL
*pbExist
)
526 BOOL bExists
= FALSE
;
532 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
> xCmdEnv
;
533 ::ucbhelper::Content
aContent( rURL
, xCmdEnv
);
535 bExists
= aContent
.isDocument();
538 Any
aAny( aContent
.getPropertyValue( A2OU( "IsReadOnly" ) ) );
553 ///////////////////////////////////////////////////////////////////////////
556 static BOOL
GetAltSpelling( INT16
&rnChgPos
, INT16
&rnChgLen
, OUString
&rRplc
,
557 uno::Reference
< XHyphenatedWord
> &rxHyphWord
)
559 BOOL bRes
= rxHyphWord
->isAlternativeSpelling();
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
576 // find first different char from left
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)
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
];
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
);
609 static INT16
GetOrigWordPos( const OUString
&rOrigWord
, INT16 nPos
)
611 INT32 nLen
= rOrigWord
.getLength();
613 while (nPos
>= 0 && i
++ < nLen
)
615 sal_Unicode cChar
= rOrigWord
[i
];
616 BOOL bSkip
= IsHyphen( cChar
) || IsControlChar( cChar
);
620 return sal::static_int_cast
< INT16
>((0 <= i
&& i
< nLen
) ? i
: -1);
624 INT32
GetPosInWordToCheck( const OUString
&rTxt
, INT32 nPos
)
627 INT32 nLen
= rTxt
.getLength();
628 if (0 <= nPos
&& nPos
< nLen
)
631 for (INT32 i
= 0; i
< nPos
; ++i
)
633 sal_Unicode cChar
= rTxt
[i
];
634 BOOL bSkip
= IsHyphen( cChar
) || IsControlChar( cChar
);
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())
653 BOOL bAltSpelling
= GetAltSpelling( nChgPos
, nChgLen
, aRplc
, rxHyphWord
);
654 #if OSL_DEBUG_LEVEL > 1
655 OUString
aWord( rxHyphWord
->getWord() );
658 OUString aOrigHyphenatedWord
;
659 INT16 nOrigHyphenPos
= -1;
660 INT16 nOrigHyphenationPos
= -1;
663 aOrigHyphenatedWord
= rOrigWord
;
664 nOrigHyphenPos
= GetOrigWordPos( rOrigWord
, rxHyphWord
->getHyphenPos() );
665 nOrigHyphenationPos
= GetOrigWordPos( rOrigWord
, rxHyphWord
->getHyphenationPos() );
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
)
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" );
698 INT16 nLang
= LocaleToLanguage( rxHyphWord
->getLocale() );
699 xRes
= new HyphenatedWord(
700 rOrigWord
, nLang
, nOrigHyphenationPos
,
701 aOrigHyphenatedWord
, nOrigHyphenPos
);
709 ///////////////////////////////////////////////////////////////////////////
712 static CharClass
& lcl_GetCharClass()
714 static CharClass
aCC( CreateLocale( LANGUAGE_ENGLISH_US
) );
719 osl::Mutex
& lcl_GetCharClassMutex()
721 static osl::Mutex 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();
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
)
852 if (/*nDigitZero <= nCodePoint &&*/ nCodePoint
<= nDigitZero
+ 9)
860 BOOL
IsNumeric( const String
&rText
)
863 xub_StrLen nLen
= rText
.Len();
870 sal_Unicode cChar
= rText
.GetChar( i
++ );
871 if ( !((sal_Unicode
)'0' <= cChar
&& cChar
<= (sal_Unicode
)'9') )
882 ///////////////////////////////////////////////////////////////////////////
884 uno::Reference
< XInterface
> GetOneInstanceService( const char *pServiceName
)
886 uno::Reference
< XInterface
> xRef
;
890 uno::Reference
< XMultiServiceFactory
> xMgr( getProcessServiceFactory() );
895 xRef
= xMgr
->createInstance( A2OU( pServiceName
) );
897 catch (uno::Exception
&)
899 DBG_ASSERT( 0, "createInstance failed" );
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() );
930 xRes
= xDL
->getDictionaryByName( A2OU("IgnoreAllList") );
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();
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()
964 xDesktop
->addTerminateListener( this );
968 void AppExitListener::Deactivate()
971 xDesktop
->removeTerminateListener( this );
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
989 AppExitListener::queryTermination( const EventObject
& /*rEvtSource*/ )
990 throw(frame::TerminationVetoException
, RuntimeException
)
992 //MutexGuard aGuard( GetLinguMutex() );
997 AppExitListener::notifyTermination( const EventObject
& rEvtSource
)
998 throw(RuntimeException
)
1000 MutexGuard
aGuard( GetLinguMutex() );
1002 if (xDesktop
.is() && rEvtSource
.Source
== xDesktop
)
1008 ///////////////////////////////////////////////////////////////////////////
1010 } // namespace linguistic