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