LibreOffice Module xmloff (master)  1
chrlohdl.cxx
Go to the documentation of this file.
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 "chrlohdl.hxx"
21 #include <xmloff/xmltoken.hxx>
22 #include <xmloff/xmluconv.hxx>
23 #include <unotools/saveopt.hxx>
25 #include <sal/log.hxx>
26 #include <com/sun/star/uno/Any.hxx>
27 #include <com/sun/star/lang/Locale.hpp>
28 
29 using namespace ::com::sun::star;
30 using namespace ::xmloff::token;
31 
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? */
36 
37 // For runtime performance, instead of converting back and forth between
38 // css::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.
42 
44 {
45  // nothing to do
46 }
47 
48 bool XMLCharLanguageHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const
49 {
50  bool bRet = false;
51  lang::Locale aLocale1, aLocale2;
52 
53  if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) )
54  {
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
60  {
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 );
71  }
72  }
73 
74  return bRet;
75 }
76 
77 bool XMLCharLanguageHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const
78 {
79  lang::Locale aLocale;
80  rValue >>= aLocale;
81 
82  if( !IsXMLToken(rStrImpValue, XML_NONE) )
83  {
84  if (aLocale.Variant.isEmpty())
85  aLocale.Language = rStrImpValue;
86  else
87  {
88  if (!aLocale.Language.isEmpty() || aLocale.Variant[0] != '-')
89  {
90  SAL_WARN_IF( aLocale.Language != I18NLANGTAG_QLT, "xmloff.style",
91  "XMLCharLanguageHdl::importXML - attempt to import language twice");
92  }
93  else
94  {
95  aLocale.Variant = rStrImpValue + aLocale.Variant;
96  if (!aLocale.Country.isEmpty())
97  aLocale.Variant += "-" + aLocale.Country;
98  aLocale.Language = I18NLANGTAG_QLT;
99  }
100  }
101  }
102 
103  rValue <<= aLocale;
104  return true;
105 }
106 
107 bool XMLCharLanguageHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
108 {
109  lang::Locale aLocale;
110  if(!(rValue >>= aLocale))
111  return false;
112 
113  if (aLocale.Variant.isEmpty())
114  rStrExpValue = aLocale.Language;
115  else
116  {
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;
125  }
126 
127  if( rStrExpValue.isEmpty() )
128  rStrExpValue = GetXMLToken( XML_NONE );
129 
130  return true;
131 }
132 
134 {
135  // nothing to do
136 }
137 
138 bool XMLCharScriptHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const
139 {
140  bool bRet = false;
141  lang::Locale aLocale1, aLocale2;
142 
143  if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) )
144  {
145  bool bEmptyVariant1 = aLocale1.Variant.isEmpty();
146  bool bEmptyVariant2 = aLocale2.Variant.isEmpty();
147  if (bEmptyVariant1 && bEmptyVariant2)
148  bRet = true;
149  else if (bEmptyVariant1 != bEmptyVariant2)
150  ; // stays false
151  else
152  {
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 );
163  }
164  }
165 
166  return bRet;
167 }
168 
169 bool XMLCharScriptHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const
170 {
171  lang::Locale aLocale;
172  rValue >>= aLocale;
173 
174  if( !IsXMLToken( rStrImpValue, XML_NONE ) )
175  {
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())
179  {
180  if (aLocale.Language.isEmpty())
181  {
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;
186  }
187  else
188  {
189  aLocale.Variant = aLocale.Language + "-" + rStrImpValue;
190  if (!aLocale.Country.isEmpty())
191  aLocale.Variant += "-" + aLocale.Country;
192  aLocale.Language = I18NLANGTAG_QLT;
193  }
194  }
195  else if (aLocale.Variant[0] == '-')
196  {
197  SAL_WARN( "xmloff.style", "XMLCharScriptHdl::importXML - attempt to insert script twice: "
198  << rStrImpValue << " -> " << aLocale.Variant);
199  }
200  else
201  {
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())
209  {
210  SAL_WARN( "xmloff.style", "XMLCharScriptHdl::importXML - attempt to insert script over bcp47: "
211  << rStrImpValue << " -> " << aLanguageTag.getBcp47());
212  }
213 #endif
214  }
215  }
216 
217  rValue <<= aLocale;
218  return true;
219 }
220 
221 bool XMLCharScriptHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
222 {
223  lang::Locale aLocale;
224  if(!(rValue >>= aLocale))
225  return false;
226 
227  // Do not write script='none' for default script.
228 
229  if (aLocale.Variant.isEmpty())
230  return false;
231 
232  LanguageTag aLanguageTag( aLocale);
233  if (!aLanguageTag.hasScript())
234  return false;
235 
237  return false;
238 
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  return !aLanguage.isEmpty() && !rStrExpValue.isEmpty();
245 }
246 
248 {
249  // nothing to do
250 }
251 
252 bool XMLCharCountryHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const
253 {
254  bool bRet = false;
255  lang::Locale aLocale1, aLocale2;
256 
257  if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) )
258  bRet = ( aLocale1.Country == aLocale2.Country );
259 
260  return bRet;
261 }
262 
263 bool XMLCharCountryHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const
264 {
265  lang::Locale aLocale;
266  rValue >>= aLocale;
267 
268  if( !IsXMLToken( rStrImpValue, XML_NONE ) )
269  {
270  if (aLocale.Country.isEmpty())
271  {
272  aLocale.Country = rStrImpValue;
273  if (aLocale.Variant.getLength() >= 7 && aLocale.Language == I18NLANGTAG_QLT)
274  {
275  // already assembled language tag, at least ll-Ssss and not
276  // ll-CC or lll-CC
277  sal_Int32 i = aLocale.Variant.indexOf('-'); // separator to script
278  if (2 <= i && i < aLocale.Variant.getLength())
279  {
280  i = aLocale.Variant.indexOf( '-', i+1);
281  if (i < 0) // no other separator
282  aLocale.Variant += "-" + rStrImpValue; // append country
283  }
284  }
285  }
286  }
287 
288  rValue <<= aLocale;
289  return true;
290 }
291 
292 bool XMLCharCountryHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
293 {
294  lang::Locale aLocale;
295  if(!(rValue >>= aLocale))
296  return false;
297 
298  if (aLocale.Variant.isEmpty())
299  rStrExpValue = aLocale.Country;
300  else
301  {
302  LanguageTag aLanguageTag( aLocale);
303  OUString aLanguage, aScript;
304  aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, rStrExpValue);
305  // Do not write *:country='none' for a non-ISO country with
306  // *:rfc-language-tag that is written if Variant is not empty. If there
307  // is no match do not write this attribute at all.
308  if (rStrExpValue.isEmpty())
309  return false;
310  }
311 
312  if( rStrExpValue.isEmpty() )
313  rStrExpValue = GetXMLToken( XML_NONE );
314 
315  return true;
316 }
317 
319 {
320  // nothing to do
321 }
322 
323 bool XMLCharRfcLanguageTagHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const
324 {
325  bool bRet = false;
326  lang::Locale aLocale1, aLocale2;
327 
328  if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) )
329  bRet = ( aLocale1.Variant == aLocale2.Variant );
330 
331  return bRet;
332 }
333 
334 bool XMLCharRfcLanguageTagHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const
335 {
336  lang::Locale aLocale;
337  rValue >>= aLocale;
338 
339  if( !IsXMLToken( rStrImpValue, XML_NONE ) )
340  {
341  aLocale.Variant = rStrImpValue;
342  aLocale.Language = I18NLANGTAG_QLT;
343  }
344 
345  rValue <<= aLocale;
346  return true;
347 }
348 
349 bool XMLCharRfcLanguageTagHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const
350 {
351  lang::Locale aLocale;
352  if(!(rValue >>= aLocale))
353  return false;
354 
355  // Do not write rfc-language-tag='none' if BCP 47 is not needed.
356  if (aLocale.Variant.isEmpty())
357  return false;
358 
360  return false;
361 
362  rStrExpValue = aLocale.Variant;
363 
364  return true;
365 }
366 
367 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual bool equals(const css::uno::Any &r1, const css::uno::Any &r2) const override
Compares two Any's in case of the given XML-data-type.
Definition: chrlohdl.cxx:252
bool IsXMLToken(const OUString &rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3461
the SvXMLTypeConverter converts values of various types from their internal representation to the tex...
Definition: xmluconv.hxx:77
virtual ~XMLCharScriptHdl() override
Definition: chrlohdl.cxx:133
virtual bool importXML(const OUString &rStrImpValue, css::uno::Any &rValue, const SvXMLUnitConverter &rUnitConverter) const override
Imports the given value according to the XML-data-type corresponding to the derived class...
Definition: chrlohdl.cxx:263
virtual bool equals(const css::uno::Any &r1, const css::uno::Any &r2) const override
Compares two Any's in case of the given XML-data-type.
Definition: chrlohdl.cxx:48
const OUString & getBcp47(bool bResolveSystem=true) const
OUString getScript() const
virtual ~XMLCharLanguageHdl() override
Definition: chrlohdl.cxx:43
void getIsoLanguageScriptCountry(OUString &rLanguage, OUString &rScript, OUString &rCountry) const
virtual bool equals(const css::uno::Any &r1, const css::uno::Any &r2) const override
Compares two Any's in case of the given XML-data-type.
Definition: chrlohdl.cxx:138
css::uno::Any const & rValue
Definition: ImageStyle.hxx:38
virtual bool importXML(const OUString &rStrImpValue, css::uno::Any &rValue, const SvXMLUnitConverter &rUnitConverter) const override
Imports the given value according to the XML-data-type corresponding to the derived class...
Definition: chrlohdl.cxx:169
OUString getLanguage() const
virtual bool exportXML(OUString &rStrExpValue, const css::uno::Any &rValue, const SvXMLUnitConverter &rUnitConverter) const override
Exports the given value according to the XML-data-type corresponding to the derived class...
Definition: chrlohdl.cxx:221
virtual bool equals(const css::uno::Any &r1, const css::uno::Any &r2) const override
Compares two Any's in case of the given XML-data-type.
Definition: chrlohdl.cxx:323
virtual bool importXML(const OUString &rStrImpValue, css::uno::Any &rValue, const SvXMLUnitConverter &rUnitConverter) const override
Imports the given value according to the XML-data-type corresponding to the derived class...
Definition: chrlohdl.cxx:334
virtual ~XMLCharRfcLanguageTagHdl() override
Definition: chrlohdl.cxx:318
#define I18NLANGTAG_QLT
virtual ~XMLCharCountryHdl() override
Definition: chrlohdl.cxx:247
int i
virtual bool exportXML(OUString &rStrExpValue, const css::uno::Any &rValue, const SvXMLUnitConverter &rUnitConverter) const override
Exports the given value according to the XML-data-type corresponding to the derived class...
Definition: chrlohdl.cxx:292
virtual bool exportXML(OUString &rStrExpValue, const css::uno::Any &rValue, const SvXMLUnitConverter &rUnitConverter) const override
Exports the given value according to the XML-data-type corresponding to the derived class...
Definition: chrlohdl.cxx:107
ODFSaneDefaultVersion GetODFSaneDefaultVersion() const
#define SAL_WARN_IF(condition, area, stream)
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
return the OUString representation for eToken
Definition: xmltoken.cxx:3405
Handling of tokens in XML:
#define SAL_INFO(area, stream)
#define SAL_WARN(area, stream)
if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))
bool hasScript() const
virtual bool exportXML(OUString &rStrExpValue, const css::uno::Any &rValue, const SvXMLUnitConverter &rUnitConverter) const override
Exports the given value according to the XML-data-type corresponding to the derived class...
Definition: chrlohdl.cxx:349
virtual bool importXML(const OUString &rStrImpValue, css::uno::Any &rValue, const SvXMLUnitConverter &rUnitConverter) const override
Imports the given value according to the XML-data-type corresponding to the derived class...
Definition: chrlohdl.cxx:77