bump product version to 5.0.4.1
[LibreOffice.git] / xmloff / source / style / chrlohdl.cxx
blobb580a2a202260598a7572dd28c3b6e061083c98b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <chrlohdl.hxx>
21 #include <xmloff/xmltoken.hxx>
22 #include <xmloff/xmluconv.hxx>
23 #include <unotools/saveopt.hxx>
24 #include <i18nlangtag/languagetag.hxx>
25 #include <rtl/ustrbuf.hxx>
26 #include <com/sun/star/uno/Any.hxx>
27 #include <com/sun/star/lang/Locale.hpp>
29 using namespace ::com::sun::star;
30 using namespace ::xmloff::token;
32 /* TODO-BCP47: this fiddling with Locale is quite ugly and fragile, especially
33 * for the fo:script temporarily stored in Variant, it would be better to use
34 * LanguageTagODF but we have that nasty UNO API requirement here.
35 * => make LanguageTagODF (unpublished) API? */
37 // For runtime performance, instead of converting back and forth between
38 // com::sun::star::Locale and LanguageTag to decide if script or tag are
39 // needed, this code takes advantage of knowledge about the internal
40 // representation of BCP 47 language tags in a Locale if present as done in a
41 // LanguageTag.
43 XMLCharLanguageHdl::~XMLCharLanguageHdl()
45 // nothing to do
48 bool XMLCharLanguageHdl::equals( const ::com::sun::star::uno::Any& r1, const ::com::sun::star::uno::Any& r2 ) const
50 bool bRet = false;
51 lang::Locale aLocale1, aLocale2;
53 if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) )
55 bool bEmptyOrScriptVariant1 = (aLocale1.Variant.isEmpty() || aLocale1.Variant[0] == '-');
56 bool bEmptyOrScriptVariant2 = (aLocale2.Variant.isEmpty() || aLocale2.Variant[0] == '-');
57 if (bEmptyOrScriptVariant1 && bEmptyOrScriptVariant2)
58 bRet = ( aLocale1.Language == aLocale2.Language );
59 else
61 OUString aLanguage1, aLanguage2;
62 if (bEmptyOrScriptVariant1)
63 aLanguage1 = aLocale1.Language;
64 else
65 aLanguage1 = LanguageTag( aLocale1).getLanguage();
66 if (bEmptyOrScriptVariant2)
67 aLanguage2 = aLocale2.Language;
68 else
69 aLanguage2 = LanguageTag( aLocale2).getLanguage();
70 bRet = ( aLanguage1 == aLanguage2 );
74 return bRet;
77 bool XMLCharLanguageHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const
79 lang::Locale aLocale;
80 rValue >>= aLocale;
82 if( !IsXMLToken(rStrImpValue, XML_NONE) )
84 if (aLocale.Variant.isEmpty())
85 aLocale.Language = rStrImpValue;
86 else
88 if (!aLocale.Language.isEmpty() || aLocale.Variant[0] != '-')
90 SAL_WARN_IF( aLocale.Language != I18NLANGTAG_QLT, "xmloff.style",
91 "XMLCharLanguageHdl::importXML - attempt to import language twice");
93 else
95 aLocale.Variant = rStrImpValue + aLocale.Variant;
96 if (!aLocale.Country.isEmpty())
97 aLocale.Variant += "-" + aLocale.Country;
98 aLocale.Language = I18NLANGTAG_QLT;
103 rValue <<= aLocale;
104 return true;
107 bool XMLCharLanguageHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
109 lang::Locale aLocale;
110 if(!(rValue >>= aLocale))
111 return false;
113 if (aLocale.Variant.isEmpty())
114 rStrExpValue = aLocale.Language;
115 else
117 LanguageTag aLanguageTag( aLocale);
118 OUString aScript, aCountry;
119 aLanguageTag.getIsoLanguageScriptCountry( rStrExpValue, aScript, aCountry);
120 // Do not write *:language='none' for a non-ISO language with
121 // *:rfc-language-tag that is written if Variant is not empty. If there
122 // is no match do not write this attribute at all.
123 if (rStrExpValue.isEmpty())
124 return false;
127 if( rStrExpValue.isEmpty() )
128 rStrExpValue = GetXMLToken( XML_NONE );
130 return true;
133 XMLCharScriptHdl::~XMLCharScriptHdl()
135 // nothing to do
138 bool XMLCharScriptHdl::equals( const ::com::sun::star::uno::Any& r1, const ::com::sun::star::uno::Any& r2 ) const
140 bool bRet = false;
141 lang::Locale aLocale1, aLocale2;
143 if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) )
145 bool bEmptyVariant1 = aLocale1.Variant.isEmpty();
146 bool bEmptyVariant2 = aLocale2.Variant.isEmpty();
147 if (bEmptyVariant1 && bEmptyVariant2)
148 bRet = true;
149 else if ((bEmptyVariant1 && !bEmptyVariant2) || (!bEmptyVariant1 && bEmptyVariant2))
150 ; // stays false
151 else
153 OUString aScript1, aScript2;
154 if (aLocale1.Variant[0] == '-')
155 aScript1 = aLocale1.Variant.copy(1);
156 else
157 aScript1 = LanguageTag( aLocale1).getScript();
158 if (aLocale2.Variant[0] == '-')
159 aScript2 = aLocale2.Variant.copy(1);
160 else
161 aScript2 = LanguageTag( aLocale2).getScript();
162 bRet = ( aScript1 == aScript2 );
166 return bRet;
169 bool XMLCharScriptHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const
171 lang::Locale aLocale;
172 rValue >>= aLocale;
174 if( !IsXMLToken( rStrImpValue, XML_NONE ) )
176 // Import the script only if we don't have a full BCP 47 language tag
177 // in Variant yet.
178 if (aLocale.Variant.isEmpty())
180 if (aLocale.Language.isEmpty())
182 SAL_INFO( "xmloff.style", "XMLCharScriptHdl::importXML - script but no language yet");
183 // Temporarily store in Variant and hope the best (we will get
184 // a language later, yes?)
185 aLocale.Variant = "-" + rStrImpValue;
187 else
189 aLocale.Variant = aLocale.Language + "-" + rStrImpValue;
190 if (!aLocale.Country.isEmpty())
191 aLocale.Variant += "-" + aLocale.Country;
192 aLocale.Language = I18NLANGTAG_QLT;
195 else if (aLocale.Variant[0] == '-')
197 SAL_WARN( "xmloff.style", "XMLCharScriptHdl::importXML - attempt to insert script twice: "
198 << rStrImpValue << " -> " << aLocale.Variant);
200 else
202 // Assume that if there already is a script or anything else BCP 47
203 // it was read by XMLCharRfcLanguageTagHdl() and takes precedence.
204 // On the other hand, an *:rfc-language-tag without script and a
205 // *:script ?!?
206 #if OSL_DEBUG_LEVEL > 0 || defined(DBG_UTIL)
207 LanguageTag aLanguageTag( aLocale);
208 if (!aLanguageTag.hasScript())
210 SAL_WARN( "xmloff.style", "XMLCharScriptHdl::importXML - attempt to insert script over bcp47: "
211 << rStrImpValue << " -> " << aLanguageTag.getBcp47());
213 #endif
217 rValue <<= aLocale;
218 return true;
221 bool XMLCharScriptHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
223 lang::Locale aLocale;
224 if(!(rValue >>= aLocale))
225 return false;
227 // Do not write script='none' for default script.
229 if (aLocale.Variant.isEmpty())
230 return false;
232 LanguageTag aLanguageTag( aLocale);
233 if (!aLanguageTag.hasScript())
234 return false;
236 if (SvtSaveOptions().GetODFDefaultVersion() < SvtSaveOptions::ODFVER_012)
237 return false;
239 OUString aLanguage, aCountry;
240 aLanguageTag.getIsoLanguageScriptCountry( aLanguage, rStrExpValue, aCountry);
241 // For non-ISO language it does not make sense to write *:script if
242 // *:language is not written either, does it? It's all in
243 // *:rfc-language-tag
244 if (aLanguage.isEmpty() || rStrExpValue.isEmpty())
245 return false;
247 return true;
250 XMLCharCountryHdl::~XMLCharCountryHdl()
252 // nothing to do
255 bool XMLCharCountryHdl::equals( const ::com::sun::star::uno::Any& r1, const ::com::sun::star::uno::Any& r2 ) const
257 bool bRet = false;
258 lang::Locale aLocale1, aLocale2;
260 if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) )
261 bRet = ( aLocale1.Country == aLocale2.Country );
263 return bRet;
266 bool XMLCharCountryHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const
268 lang::Locale aLocale;
269 rValue >>= aLocale;
271 if( !IsXMLToken( rStrImpValue, XML_NONE ) )
273 if (aLocale.Country.isEmpty())
275 aLocale.Country = rStrImpValue;
276 if (aLocale.Variant.getLength() >= 7 && aLocale.Language == I18NLANGTAG_QLT)
278 // already assembled language tag, at least ll-Ssss and not
279 // ll-CC or lll-CC
280 sal_Int32 i = aLocale.Variant.indexOf('-'); // separator to script
281 if (2 <= i && i < aLocale.Variant.getLength())
283 i = aLocale.Variant.indexOf( '-', i+1);
284 if (i < 0) // no other separator
285 aLocale.Variant += "-" + rStrImpValue; // append country
291 rValue <<= aLocale;
292 return true;
295 bool XMLCharCountryHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
297 lang::Locale aLocale;
298 if(!(rValue >>= aLocale))
299 return false;
301 if (aLocale.Variant.isEmpty())
302 rStrExpValue = aLocale.Country;
303 else
305 LanguageTag aLanguageTag( aLocale);
306 OUString aLanguage, aScript;
307 aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, rStrExpValue);
308 // Do not write *:country='none' for a non-ISO country with
309 // *:rfc-language-tag that is written if Variant is not empty. If there
310 // is no match do not write this attribute at all.
311 if (rStrExpValue.isEmpty())
312 return false;
315 if( rStrExpValue.isEmpty() )
316 rStrExpValue = GetXMLToken( XML_NONE );
318 return true;
321 XMLCharRfcLanguageTagHdl::~XMLCharRfcLanguageTagHdl()
323 // nothing to do
326 bool XMLCharRfcLanguageTagHdl::equals( const ::com::sun::star::uno::Any& r1, const ::com::sun::star::uno::Any& r2 ) const
328 bool bRet = false;
329 lang::Locale aLocale1, aLocale2;
331 if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) )
332 bRet = ( aLocale1.Variant == aLocale2.Variant );
334 return bRet;
337 bool XMLCharRfcLanguageTagHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const
339 lang::Locale aLocale;
340 rValue >>= aLocale;
342 if( !IsXMLToken( rStrImpValue, XML_NONE ) )
344 aLocale.Variant = rStrImpValue;
345 aLocale.Language = I18NLANGTAG_QLT;
348 rValue <<= aLocale;
349 return true;
352 bool XMLCharRfcLanguageTagHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
354 lang::Locale aLocale;
355 if(!(rValue >>= aLocale))
356 return false;
358 // Do not write rfc-language-tag='none' if BCP 47 is not needed.
359 if (aLocale.Variant.isEmpty())
360 return false;
362 if (SvtSaveOptions().GetODFDefaultVersion() < SvtSaveOptions::ODFVER_012)
363 return false;
365 rStrExpValue = aLocale.Variant;
367 return true;
370 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */