Line data Source code
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 :
21 : #include "app.hxx"
22 : #include "langselect.hxx"
23 : #include "cmdlineargs.hxx"
24 : #include <stdio.h>
25 :
26 : #include <rtl/string.hxx>
27 : #include <rtl/bootstrap.hxx>
28 : #include <unotools/pathoptions.hxx>
29 : #include <tools/resid.hxx>
30 : #include <tools/config.hxx>
31 : #include <i18nlangtag/mslangid.hxx>
32 : #include <i18nlangtag/languagetag.hxx>
33 : #include <comphelper/processfactory.hxx>
34 : #include <com/sun/star/configuration/theDefaultProvider.hpp>
35 : #include <com/sun/star/container/XNameAccess.hpp>
36 : #include <com/sun/star/lang/XComponent.hpp>
37 : #include <com/sun/star/beans/NamedValue.hpp>
38 : #include <com/sun/star/util/XChangesBatch.hpp>
39 : #include <com/sun/star/uno/Any.hxx>
40 : #include <com/sun/star/lang/XLocalizable.hpp>
41 : #include <com/sun/star/lang/Locale.hpp>
42 : #include "com/sun/star/util/XFlushable.hpp"
43 : #include <rtl/instance.hxx>
44 : #include <osl/process.h>
45 : #include <osl/file.hxx>
46 :
47 : using namespace com::sun::star::uno;
48 : using namespace com::sun::star::lang;
49 : using namespace com::sun::star::container;
50 : using namespace com::sun::star::beans;
51 : using namespace com::sun::star::util;
52 :
53 :
54 : namespace desktop {
55 :
56 : static char const SOFFICE_BOOTSTRAP[] = "Bootstrap";
57 : static char const SOFFICE_STARTLANG[] = "STARTLANG";
58 :
59 : sal_Bool LanguageSelection::bFoundLanguage = sal_False;
60 83 : OUString LanguageSelection::aFoundLanguage;
61 : LanguageSelection::LanguageSelectionStatus LanguageSelection::m_eStatus = LS_STATUS_OK;
62 :
63 83 : static sal_Bool existsURL( OUString const& sURL )
64 : {
65 : using namespace osl;
66 83 : DirectoryItem aDirItem;
67 :
68 83 : if (!sURL.isEmpty())
69 83 : return ( DirectoryItem::get( sURL, aDirItem ) == DirectoryItem::E_None );
70 :
71 0 : return sal_False;
72 : }
73 :
74 : // locate soffice.ini/.rc file
75 83 : static OUString locateSofficeIniFile()
76 : {
77 83 : OUString aUserDataPath;
78 166 : OUString aSofficeIniFileURL;
79 :
80 : // Retrieve the default file URL for the soffice.ini/rc
81 83 : rtl::Bootstrap().getIniName( aSofficeIniFileURL );
82 :
83 83 : if ( utl::Bootstrap::locateUserData( aUserDataPath ) == utl::Bootstrap::PATH_EXISTS )
84 : {
85 83 : sal_Int32 nIndex = aSofficeIniFileURL.lastIndexOf( '/');
86 83 : if ( nIndex > 0 )
87 : {
88 83 : OUString aUserSofficeIniFileURL = aUserDataPath + "/config" + aSofficeIniFileURL.copy( nIndex );
89 :
90 83 : if ( existsURL( aUserSofficeIniFileURL ))
91 0 : return aUserSofficeIniFileURL;
92 : }
93 : }
94 : // Fallback try to use the soffice.ini/rc from program folder
95 166 : return aSofficeIniFileURL;
96 : }
97 :
98 83 : bool LanguageSelection::prepareLanguage()
99 : {
100 83 : m_eStatus = LS_STATUS_OK;
101 : Reference< XLocalizable > theConfigProvider(
102 : com::sun::star::configuration::theDefaultProvider::get(
103 : comphelper::getProcessComponentContext() ),
104 83 : UNO_QUERY_THROW );
105 :
106 83 : sal_Bool bSuccess = sal_False;
107 :
108 : // #i42730#get the windows 16Bit locale - it should be preferred over the UI language
109 : try
110 : {
111 83 : Reference< XPropertySet > xProp(getConfigAccess("org.openoffice.System/L10N/", sal_False), UNO_QUERY_THROW);
112 166 : Any aWin16SysLocale = xProp->getPropertyValue("SystemLocale");
113 166 : OUString sWin16SysLocale;
114 83 : aWin16SysLocale >>= sWin16SysLocale;
115 83 : if( !sWin16SysLocale.isEmpty())
116 166 : setDefaultLanguage(sWin16SysLocale);
117 : }
118 0 : catch(const Exception&)
119 : {
120 0 : m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
121 : }
122 :
123 : // #i32939# use system locale to set document default locale
124 : try
125 : {
126 83 : OUString usLocale;
127 : Reference< XPropertySet > xLocaleProp(getConfigAccess(
128 166 : "org.openoffice.System/L10N", sal_True), UNO_QUERY_THROW);
129 83 : xLocaleProp->getPropertyValue("Locale") >>= usLocale;
130 166 : setDefaultLanguage(usLocale);
131 : }
132 0 : catch (const Exception&)
133 : {
134 0 : m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
135 : }
136 :
137 : // get the selected UI language as string
138 83 : bool bCmdLanguage( false );
139 83 : bool bIniLanguage( false );
140 166 : OUString aLocaleString = getUserUILanguage();
141 :
142 83 : if ( aLocaleString.isEmpty() )
143 : {
144 83 : OUString aEmpty;
145 :
146 83 : const CommandLineArgs& rCmdLineArgs = Desktop::GetCommandLineArgs();
147 83 : aLocaleString = rCmdLineArgs.GetLanguage();
148 83 : if (isInstalledLanguage(aLocaleString, sal_False))
149 : {
150 0 : bCmdLanguage = true;
151 0 : bFoundLanguage = true;
152 0 : aFoundLanguage = aLocaleString;
153 : }
154 : else
155 83 : aLocaleString = aEmpty;
156 :
157 83 : if ( !bCmdLanguage )
158 : {
159 83 : OUString aSOfficeIniURL = locateSofficeIniFile();
160 166 : Config aConfig(aSOfficeIniURL);
161 83 : aConfig.SetGroup( SOFFICE_BOOTSTRAP );
162 166 : OString sLang = aConfig.ReadKey( SOFFICE_STARTLANG );
163 83 : aLocaleString = OUString( sLang.getStr(), sLang.getLength(), RTL_TEXTENCODING_ASCII_US );
164 83 : if (isInstalledLanguage(aLocaleString, sal_False))
165 : {
166 0 : bIniLanguage = true;
167 0 : bFoundLanguage = true;
168 0 : aFoundLanguage = aLocaleString;
169 : }
170 : else
171 166 : aLocaleString = aEmpty;
172 83 : }
173 : }
174 :
175 : // user further fallbacks for the UI language
176 83 : if ( aLocaleString.isEmpty() )
177 83 : aLocaleString = getLanguageString();
178 :
179 83 : if ( !aLocaleString.isEmpty() )
180 : {
181 : try
182 : {
183 : // prepare default config provider by localizing it to the selected
184 : // locale this will ensure localized configuration settings to be
185 : // selected according to the UI language.
186 83 : LanguageTag aUILanguageTag(aLocaleString);
187 83 : theConfigProvider->setLocale(aUILanguageTag.getLocale( false));
188 :
189 166 : Reference< XPropertySet > xProp(getConfigAccess("org.openoffice.Setup/L10N/", sal_True), UNO_QUERY_THROW);
190 83 : if ( !bCmdLanguage )
191 : {
192 : // Store language only
193 83 : xProp->setPropertyValue("ooLocale", makeAny(aLocaleString));
194 83 : Reference< XChangesBatch >(xProp, UNO_QUERY_THROW)->commitChanges();
195 : }
196 :
197 83 : if ( bIniLanguage )
198 : {
199 : // Store language only
200 0 : Reference< XPropertySet > xProp2(getConfigAccess("org.openoffice.Office.Linguistic/General/", sal_True), UNO_QUERY_THROW);
201 0 : xProp2->setPropertyValue("UILocale", makeAny(aLocaleString));
202 0 : Reference< XChangesBatch >(xProp2, UNO_QUERY_THROW)->commitChanges();
203 : }
204 :
205 83 : MsLangId::setConfiguredSystemUILanguage( aUILanguageTag.getLanguageType( false) );
206 :
207 166 : OUString sLocale;
208 83 : xProp->getPropertyValue("ooSetupSystemLocale") >>= sLocale;
209 83 : if ( !sLocale.isEmpty() )
210 : {
211 0 : LanguageTag aLocaleLanguageTag(sLocale);
212 0 : MsLangId::setConfiguredSystemLanguage( aLocaleLanguageTag.getLanguageType( false) );
213 : }
214 : else
215 83 : MsLangId::setConfiguredSystemLanguage( MsLangId::getSystemLanguage() );
216 :
217 166 : bSuccess = sal_True;
218 : }
219 0 : catch ( const PropertyVetoException& )
220 : {
221 : // we are not allowed to change this
222 : }
223 0 : catch (const Exception& e)
224 : {
225 0 : OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US);
226 0 : OSL_FAIL(aMsg.getStr());
227 :
228 : }
229 : }
230 :
231 : // #i32939# setting of default document locale
232 : // #i32939# this should not be based on the UI language
233 83 : setDefaultLanguage(aLocaleString);
234 :
235 166 : return bSuccess;
236 : }
237 :
238 249 : void LanguageSelection::setDefaultLanguage(const OUString& sLocale)
239 : {
240 : // #i32939# setting of default document language
241 : // See #i42730# for rules for determining source of settings
242 :
243 : // determine script type of locale
244 249 : LanguageType nLang = LanguageTag(sLocale).getLanguageType();
245 249 : sal_uInt16 nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage(nLang);
246 :
247 249 : switch (nScriptType)
248 : {
249 : case SCRIPTTYPE_ASIAN:
250 0 : MsLangId::setConfiguredAsianFallback( nLang );
251 0 : break;
252 : case SCRIPTTYPE_COMPLEX:
253 0 : MsLangId::setConfiguredComplexFallback( nLang );
254 0 : break;
255 : default:
256 249 : MsLangId::setConfiguredWesternFallback( nLang );
257 249 : break;
258 : }
259 249 : }
260 :
261 166 : OUString LanguageSelection::getUserUILanguage()
262 : {
263 : // check whether the user has selected a specific language
264 166 : OUString aUserLanguage = getUserLanguage();
265 166 : if (!aUserLanguage.isEmpty() )
266 : {
267 0 : if (isInstalledLanguage(aUserLanguage))
268 : {
269 : // all is well
270 0 : bFoundLanguage = sal_True;
271 0 : aFoundLanguage = aUserLanguage;
272 0 : return aFoundLanguage;
273 : }
274 : else
275 : {
276 : // selected language is not/no longer installed
277 0 : resetUserLanguage();
278 : }
279 : }
280 :
281 166 : return aUserLanguage;
282 : }
283 :
284 166 : OUString LanguageSelection::getLanguageString()
285 : {
286 : // did we already find a language?
287 166 : if (bFoundLanguage)
288 83 : return aFoundLanguage;
289 :
290 : // check whether the user has selected a specific language
291 83 : OUString aUserLanguage = getUserUILanguage();
292 83 : if (!aUserLanguage.isEmpty() )
293 0 : return aUserLanguage ;
294 :
295 : // try to use system default
296 83 : aUserLanguage = getSystemLanguage();
297 83 : if (!aUserLanguage.isEmpty() )
298 : {
299 83 : if (isInstalledLanguage(aUserLanguage, sal_False))
300 : {
301 : // great, system default language is available
302 83 : bFoundLanguage = sal_True;
303 83 : aFoundLanguage = aUserLanguage;
304 83 : return aFoundLanguage;
305 : }
306 : }
307 : // fallback 1: en-US
308 0 : OUString usFB("en-US");
309 0 : if (isInstalledLanguage(usFB))
310 : {
311 0 : bFoundLanguage = sal_True;
312 0 : aFoundLanguage = "en-US";
313 0 : return aFoundLanguage;
314 : }
315 :
316 : // fallback didn't work use first installed language
317 0 : aUserLanguage = getFirstInstalledLanguage();
318 :
319 0 : bFoundLanguage = sal_True;
320 0 : aFoundLanguage = aUserLanguage;
321 83 : return aFoundLanguage;
322 : }
323 :
324 747 : Reference< XNameAccess > LanguageSelection::getConfigAccess(const sal_Char* pPath, sal_Bool bUpdate)
325 : {
326 747 : Reference< XNameAccess > xNameAccess;
327 : try{
328 747 : OUString sAccessSrvc;
329 747 : if (bUpdate)
330 166 : sAccessSrvc = "com.sun.star.configuration.ConfigurationUpdateAccess";
331 : else
332 581 : sAccessSrvc = "com.sun.star.configuration.ConfigurationAccess";
333 :
334 1494 : OUString sConfigURL = OUString::createFromAscii(pPath);
335 :
336 : Reference< XMultiServiceFactory > theConfigProvider(
337 : com::sun::star::configuration::theDefaultProvider::get(
338 1494 : comphelper::getProcessComponentContext() ) );
339 :
340 : // access the provider
341 1494 : Sequence< Any > theArgs(1);
342 747 : theArgs[ 0 ] <<= sConfigURL;
343 1494 : xNameAccess = Reference< XNameAccess > (
344 747 : theConfigProvider->createInstanceWithArguments(
345 2241 : sAccessSrvc, theArgs ), UNO_QUERY_THROW );
346 0 : } catch (const com::sun::star::uno::Exception& e)
347 : {
348 0 : OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US);
349 0 : OSL_FAIL(aMsg.getStr());
350 : }
351 747 : return xNameAccess;
352 : }
353 :
354 249 : Sequence< OUString > LanguageSelection::getInstalledLanguages()
355 : {
356 249 : Sequence< OUString > seqLanguages;
357 498 : Reference< XNameAccess > xAccess = getConfigAccess("org.openoffice.Setup/Office/InstalledLocales", sal_False);
358 249 : if (!xAccess.is()) return seqLanguages;
359 249 : seqLanguages = xAccess->getElementNames();
360 249 : return seqLanguages;
361 : }
362 :
363 : // FIXME
364 : // it's not very clever to handle language fallbacks here, but
365 : // right now, there is no place that handles those fallbacks globally
366 166 : static Sequence< OUString > _getFallbackLocales(const OUString& aIsoLang)
367 : {
368 166 : Sequence< OUString > seqFallbacks;
369 166 : if ( aIsoLang == "zh-HK" ) {
370 0 : seqFallbacks = Sequence< OUString >(1);
371 0 : seqFallbacks[0] = "zh-TW";
372 : }
373 166 : return seqFallbacks;
374 : }
375 :
376 249 : sal_Bool LanguageSelection::isInstalledLanguage(OUString& usLocale, sal_Bool bExact)
377 : {
378 249 : sal_Bool bInstalled = sal_False;
379 249 : Sequence< OUString > seqLanguages = getInstalledLanguages();
380 415 : for (sal_Int32 i=0; i<seqLanguages.getLength(); i++)
381 : {
382 249 : if (usLocale.equals(seqLanguages[i]))
383 : {
384 83 : bInstalled = sal_True;
385 83 : break;
386 : }
387 : }
388 :
389 249 : if (!bInstalled && !bExact)
390 : {
391 : // try fallback locales
392 166 : Sequence< OUString > seqFallbacks = _getFallbackLocales(usLocale);
393 166 : for (sal_Int32 j=0; j<seqFallbacks.getLength(); j++)
394 : {
395 0 : for (sal_Int32 i=0; i<seqLanguages.getLength(); i++)
396 : {
397 0 : if (seqFallbacks[j].equals(seqLanguages[i]))
398 : {
399 0 : bInstalled = sal_True;
400 0 : usLocale = seqFallbacks[j];
401 0 : break;
402 : }
403 : }
404 166 : }
405 : }
406 :
407 249 : if (!bInstalled && !bExact)
408 : {
409 : // no exact match was found, well try to find a substitute
410 332 : for (sal_Int32 i=0; i<seqLanguages.getLength(); i++)
411 : {
412 166 : if (usLocale.indexOf(seqLanguages[i]) == 0)
413 : {
414 : // requested locale starts with the installed locale
415 : // (i.e. installed locale has index 0 in requested locale)
416 0 : bInstalled = sal_True;
417 0 : usLocale = seqLanguages[i];
418 0 : break;
419 : }
420 : }
421 : }
422 249 : return bInstalled;
423 : }
424 :
425 0 : OUString LanguageSelection::getFirstInstalledLanguage()
426 : {
427 0 : OUString aLanguage;
428 0 : Sequence< OUString > seqLanguages = getInstalledLanguages();
429 0 : if (seqLanguages.getLength() > 0)
430 0 : aLanguage = seqLanguages[0];
431 0 : return aLanguage;
432 : }
433 :
434 166 : OUString LanguageSelection::getUserLanguage()
435 : {
436 166 : OUString aUserLanguage;
437 332 : Reference< XNameAccess > xAccess(getConfigAccess("org.openoffice.Office.Linguistic/General", sal_False));
438 166 : if (xAccess.is())
439 : {
440 : try
441 : {
442 166 : xAccess->getByName("UILocale") >>= aUserLanguage;
443 : }
444 0 : catch ( NoSuchElementException const & )
445 : {
446 0 : m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
447 0 : return OUString();
448 : }
449 0 : catch ( WrappedTargetException const & )
450 : {
451 0 : m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
452 0 : return OUString();
453 : }
454 : }
455 332 : return aUserLanguage;
456 : }
457 :
458 83 : OUString LanguageSelection::getSystemLanguage()
459 : {
460 83 : OUString aUserLanguage;
461 166 : Reference< XNameAccess > xAccess(getConfigAccess("org.openoffice.System/L10N", sal_False));
462 83 : if (xAccess.is())
463 : {
464 : try
465 : {
466 83 : xAccess->getByName("UILocale") >>= aUserLanguage;
467 : }
468 0 : catch ( NoSuchElementException const & )
469 : {
470 0 : m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
471 0 : return OUString();
472 : }
473 0 : catch ( WrappedTargetException const & )
474 : {
475 0 : m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
476 0 : return OUString();
477 : }
478 : }
479 166 : return aUserLanguage;
480 : }
481 :
482 :
483 0 : void LanguageSelection::resetUserLanguage()
484 : {
485 : try
486 : {
487 0 : Reference< XPropertySet > xProp(getConfigAccess("org.openoffice.Office.Linguistic/General", sal_True), UNO_QUERY_THROW);
488 0 : xProp->setPropertyValue("UILocale", makeAny(OUString()));
489 0 : Reference< XChangesBatch >(xProp, UNO_QUERY_THROW)->commitChanges();
490 : }
491 0 : catch ( const PropertyVetoException& )
492 : {
493 : // we are not allowed to change this
494 : }
495 0 : catch (const Exception& e)
496 : {
497 0 : OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US);
498 : OSL_FAIL(aMsg.getStr());
499 0 : m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
500 : }
501 0 : }
502 :
503 0 : LanguageSelection::LanguageSelectionStatus LanguageSelection::getStatus()
504 : {
505 0 : return m_eStatus;
506 : }
507 :
508 249 : } // namespace desktop
509 :
510 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|