1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <com/sun/star/linguistic2/XAvailableLocales.hpp>
21 #include <com/sun/star/i18n/ScriptType.hpp>
22 #include <linguistic/misc.hxx>
23 #include <rtl/ustring.hxx>
24 #include <unotools/localedatawrapper.hxx>
25 #include <tools/urlobj.hxx>
26 #include <svtools/langtab.hxx>
27 #include <tools/shl.hxx>
28 #include <i18nlangtag/mslangid.hxx>
29 #include <i18nlangtag/lang.h>
30 #include <editeng/scripttypeitem.hxx>
31 #include <editeng/unolingu.hxx>
32 #include <svx/langbox.hxx>
33 #include <svx/dialmgr.hxx>
34 #include <svx/dialogs.hrc>
35 #include <vcl/builder.hxx>
37 using namespace ::com::sun::star::util
;
38 using namespace ::com::sun::star::lang
;
39 using namespace ::com::sun::star::linguistic2
;
40 using namespace ::com::sun::star::uno
;
42 // -----------------------------------------------------------------------
44 String
GetDicInfoStr( const String
& rName
, const sal_uInt16 nLang
, bool bNeg
)
46 INetURLObject aURLObj
;
47 aURLObj
.SetSmartProtocol( INET_PROT_FILE
);
48 aURLObj
.SetSmartURL( rName
, INetURLObject::ENCODE_ALL
);
49 String
aTmp( aURLObj
.GetBase() );
50 aTmp
+= sal_Unicode( ' ' );
54 sal_Char
const sTmp
[] = " (-) ";
55 aTmp
.AppendAscii( sTmp
);
58 if ( LANGUAGE_NONE
== nLang
)
59 aTmp
+= SVX_RESSTR(RID_SVXSTR_LANGUAGE_ALL
);
62 aTmp
+= sal_Unicode( '[' );
63 aTmp
+= SvtLanguageTable::GetLanguageString( (LanguageType
)nLang
);
64 aTmp
+= sal_Unicode( ']' );
70 //========================================================================
71 // misc local helper functions
72 //========================================================================
74 static Sequence
< sal_Int16
> lcl_LocaleSeqToLangSeq( Sequence
< Locale
> &rSeq
)
76 const Locale
*pLocale
= rSeq
.getConstArray();
77 sal_Int32 nCount
= rSeq
.getLength();
79 Sequence
< sal_Int16
> aLangs( nCount
);
80 sal_Int16
*pLang
= aLangs
.getArray();
81 for (sal_Int32 i
= 0; i
< nCount
; ++i
)
83 pLang
[i
] = LanguageTag( pLocale
[i
] ).getLanguageType();
91 static bool lcl_SeqHasLang( const Sequence
< sal_Int16
> & rLangSeq
, sal_Int16 nLang
)
94 sal_Int32 nLen
= rLangSeq
.getLength();
97 const sal_Int16
*pLang
= rLangSeq
.getConstArray();
98 for (i
= 0; i
< nLen
; ++i
)
100 if (nLang
== pLang
[i
])
104 return i
>= 0 && i
< nLen
;
107 //========================================================================
108 // class SvxLanguageBox
109 //========================================================================
111 sal_uInt16
TypeToPos_Impl( LanguageType eType
, const ListBox
& rLb
)
113 sal_uInt16 nPos
= LISTBOX_ENTRY_NOTFOUND
;
114 sal_uInt16 nCount
= rLb
.GetEntryCount();
116 for ( sal_uInt16 i
=0; nPos
== LISTBOX_ENTRY_NOTFOUND
&& i
<nCount
; i
++ )
117 if ( eType
== LanguageType((sal_uIntPtr
)rLb
.GetEntryData(i
)) )
123 //------------------------------------------------------------------------
124 SvxLanguageBox::SvxLanguageBox( Window
* pParent
, const ResId
& rResId
, sal_Bool bCheck
) :
125 ListBox( pParent
, rResId
),
126 m_pSpellUsedLang( NULL
),
127 m_bWithCheckmark( bCheck
)
132 SvxLanguageBox::SvxLanguageBox( Window
* pParent
, WinBits nBits
, sal_Bool bCheck
)
133 : ListBox( pParent
, nBits
)
134 , m_pSpellUsedLang( NULL
)
135 , m_bWithCheckmark( bCheck
)
140 extern "C" SAL_DLLPUBLIC_EXPORT Window
* SAL_CALL
makeSvxLanguageBox(Window
*pParent
, VclBuilder::stringmap
&)
142 SvxLanguageBox
*pListBox
= new SvxLanguageBox(pParent
, WB_LEFT
|WB_DROPDOWN
|WB_VCENTER
|WB_3DLOOK
|WB_TABSTOP
);
143 pListBox
->EnableAutoSize(true);
147 //------------------------------------------------------------------------
148 void SvxLanguageBox::Init()
150 m_pLangTable
= new SvtLanguageTable
;
151 m_aNotCheckedImage
= Image( SVX_RES( RID_SVXIMG_NOTCHECKED
) );
152 m_aCheckedImage
= Image( SVX_RES( RID_SVXIMG_CHECKED
) );
153 m_aAllString
= String( SVX_RESSTR( RID_SVXSTR_LANGUAGE_ALL
) );
154 m_nLangList
= LANG_LIST_EMPTY
;
155 m_bHasLangNone
= sal_False
;
156 m_bLangNoneIsLangAll
= sal_False
;
158 // display entries sorted
159 SetStyle( GetStyle() | WB_SORT
);
161 if ( m_bWithCheckmark
)
163 SvtLanguageTable aLangTable
;
164 sal_uInt32 nCount
= aLangTable
.GetEntryCount();
165 for ( sal_uInt32 i
= 0; i
< nCount
; i
++ )
167 LanguageType nLangType
= aLangTable
.GetTypeAtIndex( i
);
170 if ((LANGUAGE_DONTKNOW
== nLangType
) ||
171 (LANGUAGE_SYSTEM
== nLangType
))
177 InsertLanguage( nLangType
);
179 m_nLangList
= LANG_LIST_ALL
;
182 //------------------------------------------------------------------------
184 SvxLanguageBox::~SvxLanguageBox()
186 delete m_pSpellUsedLang
;
190 //------------------------------------------------------------------------
192 sal_uInt16
SvxLanguageBox::ImplInsertImgEntry( const String
& rEntry
, sal_uInt16 nPos
, bool bChecked
)
196 nRet
= InsertEntry( rEntry
, m_aNotCheckedImage
, nPos
);
198 nRet
= InsertEntry( rEntry
, m_aCheckedImage
, nPos
);
202 //------------------------------------------------------------------------
204 void SvxLanguageBox::SetLanguageList( sal_Int16 nLangList
,
205 sal_Bool bHasLangNone
, sal_Bool bLangNoneIsLangAll
, sal_Bool bCheckSpellAvail
)
209 m_nLangList
= nLangList
;
210 m_bHasLangNone
= bHasLangNone
;
211 m_bLangNoneIsLangAll
= bLangNoneIsLangAll
;
212 m_bWithCheckmark
= bCheckSpellAvail
;
214 if ( LANG_LIST_EMPTY
!= nLangList
)
216 Sequence
< sal_Int16
> aSpellAvailLang
;
217 Sequence
< sal_Int16
> aHyphAvailLang
;
218 Sequence
< sal_Int16
> aThesAvailLang
;
219 Sequence
< sal_Int16
> aSpellUsedLang
;
220 Sequence
< sal_Int16
> aHyphUsedLang
;
221 Sequence
< sal_Int16
> aThesUsedLang
;
222 Reference
< XAvailableLocales
> xAvail( LinguMgr::GetLngSvcMgr(), UNO_QUERY
);
225 Sequence
< Locale
> aTmp
;
227 if (LANG_LIST_SPELL_AVAIL
& nLangList
)
229 aTmp
= xAvail
->getAvailableLocales( SN_SPELLCHECKER
);
230 aSpellAvailLang
= lcl_LocaleSeqToLangSeq( aTmp
);
232 if (LANG_LIST_HYPH_AVAIL
& nLangList
)
234 aTmp
= xAvail
->getAvailableLocales( SN_HYPHENATOR
);
235 aHyphAvailLang
= lcl_LocaleSeqToLangSeq( aTmp
);
237 if (LANG_LIST_THES_AVAIL
& nLangList
)
239 aTmp
= xAvail
->getAvailableLocales( SN_THESAURUS
);
240 aThesAvailLang
= lcl_LocaleSeqToLangSeq( aTmp
);
243 if (LANG_LIST_SPELL_USED
& nLangList
)
245 Reference
< XSpellChecker1
> xTmp1( SvxGetSpellChecker(), UNO_QUERY
);
247 aSpellUsedLang
= xTmp1
->getLanguages();
249 if (LANG_LIST_HYPH_USED
& nLangList
)
251 Reference
< XHyphenator
> xTmp( SvxGetHyphenator() );
253 Sequence
< Locale
> aLocaleSequence( xTmp
->getLocales() );
254 aHyphUsedLang
= lcl_LocaleSeqToLangSeq( aLocaleSequence
);
257 if (LANG_LIST_THES_USED
& nLangList
)
259 Reference
< XThesaurus
> xTmp( SvxGetThesaurus() );
261 Sequence
< Locale
> aLocaleSequence( xTmp
->getLocales() );
262 aThesUsedLang
= lcl_LocaleSeqToLangSeq( aLocaleSequence
);
266 SvtLanguageTable aLangTable
;
267 ::com::sun::star::uno::Sequence
< sal_uInt16
> xKnown
;
268 const sal_uInt16
* pKnown
;
270 if ( nLangList
& LANG_LIST_ONLY_KNOWN
)
272 xKnown
= LocaleDataWrapper::getInstalledLanguageTypes();
273 pKnown
= xKnown
.getConstArray();
274 nCount
= xKnown
.getLength();
278 nCount
= aLangTable
.GetEntryCount();
281 for ( sal_uInt32 i
= 0; i
< nCount
; i
++ )
283 LanguageType nLangType
;
284 if ( nLangList
& LANG_LIST_ONLY_KNOWN
)
285 nLangType
= pKnown
[i
];
287 nLangType
= aLangTable
.GetTypeAtIndex( i
);
288 if ( nLangType
!= LANGUAGE_DONTKNOW
&&
289 nLangType
!= LANGUAGE_SYSTEM
&&
290 nLangType
!= LANGUAGE_NONE
&&
291 (MsLangId::getSubLanguage( nLangType
) != 0 ||
292 (nLangList
& LANG_LIST_ALSO_PRIMARY_ONLY
)) &&
293 ((nLangList
& LANG_LIST_ALL
) != 0 ||
294 ((nLangList
& LANG_LIST_WESTERN
) != 0 &&
295 (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType
) ==
296 SCRIPTTYPE_LATIN
)) ||
297 ((nLangList
& LANG_LIST_CTL
) != 0 &&
298 (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType
) ==
299 SCRIPTTYPE_COMPLEX
)) ||
300 ((nLangList
& LANG_LIST_CJK
) != 0 &&
301 (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType
) ==
302 SCRIPTTYPE_ASIAN
)) ||
303 ((nLangList
& LANG_LIST_FBD_CHARS
) != 0 &&
304 MsLangId::hasForbiddenCharacters(nLangType
)) ||
305 ((nLangList
& LANG_LIST_SPELL_AVAIL
) != 0 &&
306 lcl_SeqHasLang(aSpellAvailLang
, nLangType
)) ||
307 ((nLangList
& LANG_LIST_HYPH_AVAIL
) != 0 &&
308 lcl_SeqHasLang(aHyphAvailLang
, nLangType
)) ||
309 ((nLangList
& LANG_LIST_THES_AVAIL
) != 0 &&
310 lcl_SeqHasLang(aThesAvailLang
, nLangType
)) ||
311 ((nLangList
& LANG_LIST_SPELL_USED
) != 0 &&
312 lcl_SeqHasLang(aSpellUsedLang
, nLangType
)) ||
313 ((nLangList
& LANG_LIST_HYPH_USED
) != 0 &&
314 lcl_SeqHasLang(aHyphUsedLang
, nLangType
)) ||
315 ((nLangList
& LANG_LIST_THES_USED
) != 0 &&
316 lcl_SeqHasLang(aThesUsedLang
, nLangType
))) )
317 InsertLanguage( nLangType
);
321 InsertLanguage( LANGUAGE_NONE
);
325 //------------------------------------------------------------------------
327 sal_uInt16
SvxLanguageBox::InsertLanguage( const LanguageType nLangType
, sal_uInt16 nPos
)
329 return ImplInsertLanguage( nLangType
, nPos
, ::com::sun::star::i18n::ScriptType::WEAK
);
332 //------------------------------------------------------------------------
334 sal_uInt16
SvxLanguageBox::ImplInsertLanguage( const LanguageType nLangType
, sal_uInt16 nPos
, sal_Int16 nType
)
336 LanguageType nLang
= MsLangId::getReplacementForObsoleteLanguage( nLangType
);
337 // For obsolete and to be replaced languages check whether an entry of the
338 // replacement already exists and if so don't add an entry with identical
339 // string as would be returned by SvtLanguageTable::GetString().
340 if (nLang
!= nLangType
)
342 sal_uInt16 nAt
= TypeToPos_Impl( nLang
, *this );
343 if ( nAt
!= LISTBOX_ENTRY_NOTFOUND
)
347 String aStrEntry
= m_pLangTable
->GetString( nLang
);
348 if (LANGUAGE_NONE
== nLang
&& m_bHasLangNone
&& m_bLangNoneIsLangAll
)
349 aStrEntry
= m_aAllString
;
351 LanguageType nRealLang
= nLang
;
352 if (nRealLang
== LANGUAGE_SYSTEM
)
354 nRealLang
= MsLangId::resolveSystemLanguageByScriptType(nRealLang
, nType
);
355 aStrEntry
.AppendAscii(" - ");
356 aStrEntry
.Append(m_pLangTable
->GetString( nRealLang
));
357 } else if (nRealLang
== LANGUAGE_USER_SYSTEM_CONFIG
) {
358 nRealLang
= MsLangId::getSystemLanguage();
359 aStrEntry
.AppendAscii(" - ");
360 aStrEntry
.Append(m_pLangTable
->GetString( nRealLang
));
363 aStrEntry
= ApplyLreOrRleEmbedding( aStrEntry
);
366 if ( m_bWithCheckmark
)
370 if (!m_pSpellUsedLang
)
372 Reference
< XSpellChecker1
> xSpell( SvxGetSpellChecker(), UNO_QUERY
);
374 m_pSpellUsedLang
= new Sequence
< sal_Int16
>( xSpell
->getLanguages() );
376 bFound
= m_pSpellUsedLang
?
377 lcl_SeqHasLang( *m_pSpellUsedLang
, nRealLang
) : false;
379 nAt
= ImplInsertImgEntry( aStrEntry
, nPos
, bFound
);
382 nAt
= InsertEntry( aStrEntry
, nPos
);
384 SetEntryData( nAt
, (void*)(sal_uIntPtr
)nLangType
);
388 //------------------------------------------------------------------------
390 sal_uInt16
SvxLanguageBox::InsertDefaultLanguage( sal_Int16 nType
, sal_uInt16 nPos
)
392 return ImplInsertLanguage( LANGUAGE_SYSTEM
, nPos
, nType
);
395 //------------------------------------------------------------------------
397 sal_uInt16
SvxLanguageBox::InsertSystemLanguage( sal_uInt16 nPos
)
399 return ImplInsertLanguage( LANGUAGE_USER_SYSTEM_CONFIG
, nPos
, ::com::sun::star::i18n::ScriptType::WEAK
);
402 //------------------------------------------------------------------------
404 sal_uInt16
SvxLanguageBox::InsertLanguage( const LanguageType nLangType
,
405 sal_Bool bCheckEntry
, sal_uInt16 nPos
)
407 LanguageType nLang
= MsLangId::getReplacementForObsoleteLanguage( nLangType
);
408 // For obsolete and to be replaced languages check whether an entry of the
409 // replacement already exists and if so don't add an entry with identical
410 // string as would be returned by SvtLanguageTable::GetString().
411 if (nLang
!= nLangType
)
413 sal_uInt16 nAt
= TypeToPos_Impl( nLang
, *this );
414 if ( nAt
!= LISTBOX_ENTRY_NOTFOUND
)
418 String aStrEntry
= m_pLangTable
->GetString( nLang
);
419 if (LANGUAGE_NONE
== nLang
&& m_bHasLangNone
&& m_bLangNoneIsLangAll
)
420 aStrEntry
= m_aAllString
;
422 sal_uInt16 nAt
= ImplInsertImgEntry( aStrEntry
, nPos
, bCheckEntry
);
423 SetEntryData( nAt
, (void*)(sal_uIntPtr
)nLang
);
428 //------------------------------------------------------------------------
430 void SvxLanguageBox::RemoveLanguage( const LanguageType eLangType
)
432 sal_uInt16 nAt
= TypeToPos_Impl( eLangType
, *this );
434 if ( nAt
!= LISTBOX_ENTRY_NOTFOUND
)
438 //------------------------------------------------------------------------
440 LanguageType
SvxLanguageBox::GetSelectLanguage() const
442 sal_uInt16 nPos
= GetSelectEntryPos();
444 if ( nPos
!= LISTBOX_ENTRY_NOTFOUND
)
445 return LanguageType( (sal_uIntPtr
)GetEntryData(nPos
) );
447 return LanguageType( LANGUAGE_DONTKNOW
);
450 //------------------------------------------------------------------------
452 void SvxLanguageBox::SelectLanguage( const LanguageType eLangType
, sal_Bool bSelect
)
454 // If the core uses a LangID of an imported MS document and wants to select
455 // a language that is replaced, we need to select the replacement instead.
456 LanguageType nLang
= MsLangId::getReplacementForObsoleteLanguage( eLangType
);
458 sal_uInt16 nAt
= TypeToPos_Impl( nLang
, *this );
460 if ( nAt
!= LISTBOX_ENTRY_NOTFOUND
)
461 SelectEntryPos( nAt
, bSelect
);
464 //------------------------------------------------------------------------
466 sal_Bool
SvxLanguageBox::IsLanguageSelected( const LanguageType eLangType
) const
468 // Same here, work on the replacement if applicable.
469 LanguageType nLang
= MsLangId::getReplacementForObsoleteLanguage( eLangType
);
471 sal_uInt16 nAt
= TypeToPos_Impl( nLang
, *this );
473 if ( nAt
!= LISTBOX_ENTRY_NOTFOUND
)
474 return IsEntryPosSelected( nAt
);
479 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */