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 file
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 <unotools/localedatawrapper.hxx>
21 #include <unotools/transliterationwrapper.hxx>
22
23 #include <i18nlangtag/languagetag.hxx>
24 #include <i18nutil/transliteration.hxx>
25
26 #include <rtl/ustrbuf.hxx>
27
28 #include <vcl/i18nhelp.hxx>
29
30 using namespace ::com::sun::star;
31
I18nHelper(const css::uno::Reference<css::uno::XComponentContext> & rxContext,const LanguageTag & rLanguageTag)32 vcl::I18nHelper::I18nHelper( const css::uno::Reference< css::uno::XComponentContext >& rxContext, const LanguageTag& rLanguageTag )
33 :
34 maLanguageTag( rLanguageTag)
35 {
36 m_xContext = rxContext;
37 mpLocaleDataWrapper = nullptr;
38 mpTransliterationWrapper= nullptr;
39 mbTransliterateIgnoreCase = false;
40 }
41
~I18nHelper()42 vcl::I18nHelper::~I18nHelper()
43 {
44 ImplDestroyWrappers();
45 }
46
ImplDestroyWrappers()47 void vcl::I18nHelper::ImplDestroyWrappers()
48 {
49 mpLocaleDataWrapper.reset();
50 mpTransliterationWrapper.reset();
51 }
52
ImplGetTransliterationWrapper() const53 utl::TransliterationWrapper& vcl::I18nHelper::ImplGetTransliterationWrapper() const
54 {
55 if ( !mpTransliterationWrapper )
56 {
57 TransliterationFlags nModules = TransliterationFlags::IGNORE_WIDTH;
58 if ( mbTransliterateIgnoreCase )
59 nModules |= TransliterationFlags::IGNORE_CASE;
60
61 const_cast<vcl::I18nHelper*>(this)->mpTransliterationWrapper.reset(new utl::TransliterationWrapper( m_xContext, nModules ));
62 const_cast<vcl::I18nHelper*>(this)->mpTransliterationWrapper->loadModuleIfNeeded( maLanguageTag.getLanguageType() );
63 }
64 return *mpTransliterationWrapper;
65 }
66
ImplGetLocaleDataWrapper() const67 LocaleDataWrapper& vcl::I18nHelper::ImplGetLocaleDataWrapper() const
68 {
69 if ( !mpLocaleDataWrapper )
70 {
71 const_cast<vcl::I18nHelper*>(this)->mpLocaleDataWrapper.reset(new LocaleDataWrapper( m_xContext, maLanguageTag ));
72 }
73 return *mpLocaleDataWrapper;
74 }
75
is_formatting_mark(sal_Unicode c)76 static bool is_formatting_mark( sal_Unicode c )
77 {
78 if( (c >= 0x200B) && (c <= 0x200F) ) // BiDi and zero-width-markers
79 return true;
80 if( (c >= 0x2028) && (c <= 0x202E) ) // BiDi and paragraph-markers
81 return true;
82 return false;
83 }
84
85 /* #i100057# filter formatting marks out of strings before passing them to
86 the transliteration. The real solution would have been an additional TransliterationModule
87 to ignore these marks during transliteration; however changing the code in i18npool that actually
88 implements this could produce unwanted side effects.
89
90 Of course this copying around is not really good, but looking at i18npool, one more time
91 will not hurt.
92 */
filterFormattingChars(const OUString & rStr)93 OUString vcl::I18nHelper::filterFormattingChars( const OUString& rStr )
94 {
95 sal_Int32 nLength = rStr.getLength();
96 OUStringBuffer aBuf( nLength );
97 const sal_Unicode* pStr = rStr.getStr();
98 while( nLength-- )
99 {
100 if( ! is_formatting_mark( *pStr ) )
101 aBuf.append( *pStr );
102 pStr++;
103 }
104 return aBuf.makeStringAndClear();
105 }
106
CompareString(const OUString & rStr1,const OUString & rStr2) const107 sal_Int32 vcl::I18nHelper::CompareString( const OUString& rStr1, const OUString& rStr2 ) const
108 {
109 ::osl::Guard< ::osl::Mutex > aGuard( const_cast<vcl::I18nHelper*>(this)->maMutex );
110
111 if ( mbTransliterateIgnoreCase )
112 {
113 // Change mbTransliterateIgnoreCase and destroy the wrapper, next call to
114 // ImplGetTransliterationWrapper() will create a wrapper with the correct bIgnoreCase
115 const_cast<vcl::I18nHelper*>(this)->mbTransliterateIgnoreCase = false;
116 const_cast<vcl::I18nHelper*>(this)->mpTransliterationWrapper.reset();
117 }
118
119 OUString aStr1( filterFormattingChars(rStr1) );
120 OUString aStr2( filterFormattingChars(rStr2) );
121 return ImplGetTransliterationWrapper().compareString( aStr1, aStr2 );
122 }
123
MatchString(const OUString & rStr1,const OUString & rStr2) const124 bool vcl::I18nHelper::MatchString( const OUString& rStr1, const OUString& rStr2 ) const
125 {
126 ::osl::Guard< ::osl::Mutex > aGuard( const_cast<vcl::I18nHelper*>(this)->maMutex );
127
128 if ( !mbTransliterateIgnoreCase )
129 {
130 // Change mbTransliterateIgnoreCase and destroy the wrapper, next call to
131 // ImplGetTransliterationWrapper() will create a wrapper with the correct bIgnoreCase
132 const_cast<vcl::I18nHelper*>(this)->mbTransliterateIgnoreCase = true;
133 const_cast<vcl::I18nHelper*>(this)->mpTransliterationWrapper.reset();
134 }
135
136 OUString aStr1( filterFormattingChars(rStr1) );
137 OUString aStr2( filterFormattingChars(rStr2) );
138 return ImplGetTransliterationWrapper().isMatch( aStr1, aStr2 );
139 }
140
MatchMnemonic(const OUString & rString,sal_Unicode cMnemonicChar) const141 bool vcl::I18nHelper::MatchMnemonic( const OUString& rString, sal_Unicode cMnemonicChar ) const
142 {
143 ::osl::Guard< ::osl::Mutex > aGuard( const_cast<vcl::I18nHelper*>(this)->maMutex );
144
145 bool bEqual = false;
146 sal_Int32 n = rString.indexOf( '~' );
147 if ( n != -1 )
148 {
149 OUString aMatchStr = rString.copy( n+1 ); // not only one char, because of transliteration...
150 bEqual = MatchString( OUString(cMnemonicChar), aMatchStr );
151 }
152 return bEqual;
153 }
154
GetNum(tools::Long nNumber,sal_uInt16 nDecimals,bool bUseThousandSep,bool bTrailingZeros) const155 OUString vcl::I18nHelper::GetNum( tools::Long nNumber, sal_uInt16 nDecimals, bool bUseThousandSep, bool bTrailingZeros ) const
156 {
157 return ImplGetLocaleDataWrapper().getNum( nNumber, nDecimals, bUseThousandSep, bTrailingZeros );
158 }
159
160 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
161