LibreOffice Module svx (master)  1
langbox.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 <com/sun/star/linguistic2/XAvailableLocales.hpp>
21 #include <com/sun/star/linguistic2/XLinguServiceManager2.hpp>
22 #include <com/sun/star/linguistic2/XSpellChecker1.hpp>
23 #include <linguistic/misc.hxx>
24 #include <rtl/ustring.hxx>
25 #include <sal/log.hxx>
27 #include <tools/urlobj.hxx>
28 #include <svtools/langtab.hxx>
29 #include <i18nlangtag/mslangid.hxx>
30 #include <i18nlangtag/lang.h>
31 #include <editeng/unolingu.hxx>
32 #include <svl/languageoptions.hxx>
33 #include <svx/langbox.hxx>
34 #include <svx/dialmgr.hxx>
35 #include <svx/strings.hrc>
36 #include <bitmaps.hlst>
37 
38 #include <comphelper/string.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/settings.hxx>
42 
43 using namespace ::com::sun::star::util;
44 using namespace ::com::sun::star::linguistic2;
45 using namespace ::com::sun::star::uno;
46 
47 OUString GetDicInfoStr( const OUString& rName, const LanguageType nLang, bool bNeg )
48 {
49  INetURLObject aURLObj;
50  aURLObj.SetSmartProtocol( INetProtocol::File );
52  OUString aTmp( aURLObj.GetBase() + " " );
53 
54  if ( bNeg )
55  {
56  aTmp += " (-) ";
57  }
58 
59  if ( LANGUAGE_NONE == nLang )
60  aTmp += SvxResId(RID_SVXSTR_LANGUAGE_ALL);
61  else
62  {
63  aTmp += "[" + SvtLanguageTable::GetLanguageString( nLang ) + "]";
64  }
65 
66  return aTmp;
67 }
68 
69 // misc local helper functions
70 static std::vector< LanguageType > lcl_LocaleSeqToLangSeq( Sequence< css::lang::Locale > const &rSeq )
71 {
72  sal_Int32 nCount = rSeq.getLength();
73 
74  std::vector< LanguageType > aLangs;
75  aLangs.reserve(nCount);
76 
77  std::transform(rSeq.begin(), rSeq.end(), std::back_inserter(aLangs),
78  [](const css::lang::Locale& rLocale) -> LanguageType {
79  return LanguageTag::convertToLanguageType(rLocale); });
80 
81  return aLangs;
82 }
83 
84 static bool lcl_SeqHasLang( const Sequence< sal_Int16 > & rLangSeq, sal_Int16 nLang )
85 {
86  return rLangSeq.hasElements()
87  && std::find(rLangSeq.begin(), rLangSeq.end(), nLang) != rLangSeq.end();
88 }
89 
90 namespace {
91 
92 bool lcl_isPrerequisite( LanguageType nLangType )
93 {
94  return
95  nLangType != LANGUAGE_DONTKNOW &&
96  nLangType != LANGUAGE_SYSTEM &&
97  nLangType != LANGUAGE_NONE &&
98  !MsLangId::isLegacy( nLangType) &&
99  MsLangId::getSubLanguage( nLangType);
100 }
101 
102 bool lcl_isScriptTypeRequested( LanguageType nLangType, SvxLanguageListFlags nLangList )
103 {
104  return
105  bool(nLangList & SvxLanguageListFlags::ALL) ||
106  (bool(nLangList & SvxLanguageListFlags::WESTERN) &&
107  (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType) == SvtScriptType::LATIN)) ||
108  (bool(nLangList & SvxLanguageListFlags::CTL) &&
109  (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType) == SvtScriptType::COMPLEX)) ||
110  (bool(nLangList & SvxLanguageListFlags::CJK) &&
111  (SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType) == SvtScriptType::ASIAN));
112 }
113 
114 }
115 
116 
118 {
119  OUString sLang = m_xControl->get_active_id();
120  if (!sLang.isEmpty())
121  return LanguageType(sLang.toInt32());
122  else
123  return LANGUAGE_DONTKNOW;
124 }
125 
126 int SvxLanguageBox::find_id(const LanguageType eLangType) const
127 {
128  return m_xControl->find_id(OUString::number(static_cast<sal_uInt16>(eLangType)));
129 }
130 
131 void SvxLanguageBox::set_id(int pos, const LanguageType eLangType)
132 {
133  m_xControl->set_id(pos, OUString::number(static_cast<sal_uInt16>(eLangType)));
134 }
135 
137 {
138  return LanguageType(m_xControl->get_id(pos).toInt32());
139 }
140 
142 {
143  m_xControl->remove_id(OUString::number(static_cast<sal_uInt16>(eLangType)));
144 }
145 
146 void SvxLanguageBox::append(const LanguageType eLangType, const OUString& rStr)
147 {
148  m_xControl->append(OUString::number(static_cast<sal_uInt16>(eLangType)), rStr);
149 }
150 
152 {
153  // If the core uses a LangID of an imported MS document and wants to select
154  // a language that is replaced, we need to select the replacement instead.
156 
157  sal_Int32 nAt = ImplTypeToPos( nLang );
158 
159  if (nAt == -1)
160  {
161  InsertLanguage( nLang ); // on-the-fly-ID
162  nAt = ImplTypeToPos( nLang );
163  }
164 
165  if (nAt != -1)
166  m_xControl->set_active(nAt);
167 }
168 
169 void SvxLanguageBox::AddLanguages(const std::vector< LanguageType >& rLanguageTypes,
170  SvxLanguageListFlags nLangList, std::vector<weld::ComboBoxEntry>& rEntries)
171 {
172  for ( auto const & nLangType : rLanguageTypes )
173  {
174  if (lcl_isPrerequisite( nLangType ))
175  {
177  if (lcl_isScriptTypeRequested( nLang, nLangList))
178  {
179  int nAt = ImplTypeToPos(nLang);
180  if (nAt != -1)
181  continue;
182  weld::ComboBoxEntry aNewEntry(BuildEntry(nLang));
183  if (aNewEntry.sString.isEmpty())
184  continue;
185  if (std::find_if(rEntries.begin(), rEntries.end(),
186  [=](const weld::ComboBoxEntry& rEntry){ return rEntry.sId == aNewEntry.sId; }) != rEntries.end())
187  continue;
188  rEntries.push_back(aNewEntry);
189  }
190  }
191  }
192 }
193 
194 void SvxLanguageBox::SetLanguageList(SvxLanguageListFlags nLangList, bool bHasLangNone,
195  bool bLangNoneIsLangAll, bool bCheckSpellAvail,
196  bool bDefaultLangExist, LanguageType eDefaultLangType,
197  sal_Int16 nDefaultType)
198 {
199  m_bHasLangNone = bHasLangNone;
200  m_bLangNoneIsLangAll = bLangNoneIsLangAll;
201  m_bWithCheckmark = bCheckSpellAvail;
202 
203  if (SvxLanguageListFlags::EMPTY == nLangList)
204  {
205  m_xControl->clear();
206  return;
207  }
208 
209  bool bAddAvailable = (!(nLangList & SvxLanguageListFlags::ONLY_KNOWN) &&
210  ((nLangList & SvxLanguageListFlags::ALL) ||
211  (nLangList & SvxLanguageListFlags::WESTERN) ||
212  (nLangList & SvxLanguageListFlags::CTL) ||
213  (nLangList & SvxLanguageListFlags::CJK)));
214  std::vector< LanguageType > aSpellAvailLang;
215  std::vector< LanguageType > aHyphAvailLang;
216  std::vector< LanguageType > aThesAvailLang;
217  Sequence< sal_Int16 > aSpellUsedLang;
218  Reference< XAvailableLocales > xAvail( LinguMgr::GetLngSvcMgr() );
219  if (xAvail.is())
220  {
221  Sequence< css::lang::Locale > aTmp;
222 
223  if (bAddAvailable)
224  {
225  aTmp = xAvail->getAvailableLocales( SN_SPELLCHECKER );
226  aSpellAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
227 
228  aTmp = xAvail->getAvailableLocales( SN_HYPHENATOR );
229  aHyphAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
230 
231  aTmp = xAvail->getAvailableLocales( SN_THESAURUS );
232  aThesAvailLang = lcl_LocaleSeqToLangSeq( aTmp );
233  }
234  }
235  if (SvxLanguageListFlags::SPELL_USED & nLangList)
236  {
237  Reference< XSpellChecker1 > xTmp1 = LinguMgr::GetSpellChecker();
238  if (xTmp1.is())
239  aSpellUsedLang = xTmp1->getLanguages();
240  }
241 
242  std::vector<LanguageType> aKnown;
243  sal_uInt32 nCount;
244  if ( nLangList & SvxLanguageListFlags::ONLY_KNOWN )
245  {
247  nCount = aKnown.size();
248  }
249  else
250  {
252  }
253 
254  std::vector<weld::ComboBoxEntry> aEntries;
255  for ( sal_uInt32 i = 0; i < nCount; i++ )
256  {
257  LanguageType nLangType;
258  if ( nLangList & SvxLanguageListFlags::ONLY_KNOWN )
259  nLangType = aKnown[i];
260  else
262  if ( lcl_isPrerequisite( nLangType ) &&
263  (lcl_isScriptTypeRequested( nLangType, nLangList) ||
264  (bool(nLangList & SvxLanguageListFlags::FBD_CHARS) &&
265  MsLangId::hasForbiddenCharacters(nLangType)) ||
266  (bool(nLangList & SvxLanguageListFlags::SPELL_USED) &&
267  lcl_SeqHasLang(aSpellUsedLang, static_cast<sal_uInt16>(nLangType)))
268  ) )
269  {
270  aEntries.push_back(BuildEntry(nLangType));
271  if (aEntries.back().sString.isEmpty())
272  aEntries.pop_back();
273  }
274  }
275 
276  if (bAddAvailable)
277  {
278  // Spell checkers, hyphenators and thesauri may add language tags
279  // unknown so far.
280  AddLanguages(aSpellAvailLang, nLangList, aEntries);
281  AddLanguages(aHyphAvailLang, nLangList, aEntries);
282  AddLanguages(aThesAvailLang, nLangList, aEntries);
283  }
284 
285  std::sort(aEntries.begin(), aEntries.end(),
286  [](const weld::ComboBoxEntry e1, const weld::ComboBoxEntry e2) {
287  static const auto aSorter = comphelper::string::NaturalStringSorter(
289  Application::GetSettings().GetLanguageTag().getLocale());
290  return aSorter.compare(e1.sString, e2.sString) < 0;
291  });
292 
293  int nSeparatorPosition = 0;
294  if (bDefaultLangExist)
295  {
296  aEntries.insert(aEntries.begin(), BuildEntry(eDefaultLangType, nDefaultType));
297  nSeparatorPosition++;
298  }
299 
300  if (bHasLangNone)
301  {
302  aEntries.insert(aEntries.begin(), BuildEntry(LANGUAGE_NONE));
303  nSeparatorPosition++;
304  }
305 
306  m_xControl->insert_vector(aEntries, false);
307  if (nSeparatorPosition > 0)
308  m_xControl->insert_separator(nSeparatorPosition, "");
309 }
310 
312 {
313  return m_xControl->find_id(OUString::number(static_cast<sal_uInt16>(eType)));
314 }
315 
316 void SvxLanguageBox::InsertLanguage(const LanguageType nLangType, sal_Int16 nType)
317 {
318  weld::ComboBoxEntry aEntry = BuildEntry(nLangType, nType);
319  if (aEntry.sString.isEmpty())
320  return;
321  if (aEntry.sImage.isEmpty())
322  m_xControl->append(aEntry.sId, aEntry.sString);
323  else
324  m_xControl->append(aEntry.sId, aEntry.sString, aEntry.sImage);
325 }
326 
328 {
329  InsertLanguage(nLangType, css::i18n::ScriptType::WEAK);
330 }
331 
333 {
335  // For obsolete and to be replaced languages check whether an entry of the
336  // replacement already exists and if so don't add an entry with identical
337  // string as would be returned by SvtLanguageTable::GetString().
338  if (nLang != nLangType)
339  {
340  int nAt = ImplTypeToPos( nLang );
341  if (nAt != -1)
342  return weld::ComboBoxEntry("");
343  }
344 
345  OUString aStrEntry = SvtLanguageTable::GetLanguageString( nLang );
347  aStrEntry = m_aAllString;
348 
349  LanguageType nRealLang = nLang;
350  if (nRealLang == LANGUAGE_SYSTEM)
351  {
352  nRealLang = MsLangId::resolveSystemLanguageByScriptType(nRealLang, nType);
353  aStrEntry += " - " + SvtLanguageTable::GetLanguageString( nRealLang );
354  }
355  else if (nRealLang == LANGUAGE_USER_SYSTEM_CONFIG)
356  {
357  nRealLang = MsLangId::getSystemLanguage();
358  aStrEntry += " - " + SvtLanguageTable::GetLanguageString( nRealLang );
359  }
360 
361  if (m_bWithCheckmark)
362  {
363  if (!m_xSpellUsedLang)
364  {
365  Reference<XSpellChecker1> xSpell = LinguMgr::GetSpellChecker();
366  if (xSpell.is())
367  m_xSpellUsedLang.reset(new Sequence<sal_Int16>(xSpell->getLanguages()));
368  }
369 
370  bool bFound = m_xSpellUsedLang && lcl_SeqHasLang(*m_xSpellUsedLang, static_cast<sal_uInt16>(nRealLang));
371 
372  return weld::ComboBoxEntry(aStrEntry, OUString::number(static_cast<sal_uInt16>(nLangType)), bFound ? OUString(RID_SVXBMP_CHECKED) : OUString(RID_SVXBMP_NOTCHECKED));
373  }
374  else
375  return weld::ComboBoxEntry(aStrEntry, OUString::number(static_cast<sal_uInt16>(nLangType)));
376 }
377 
378 IMPL_LINK(SvxLanguageBox, ChangeHdl, weld::ComboBox&, rControl, void)
379 {
380  if (rControl.has_entry())
381  {
382  EditedAndValid eOldState = m_eEditedAndValid;
383  OUString aStr(rControl.get_active_text());
384  if (aStr.isEmpty())
385  m_eEditedAndValid = EditedAndValid::Invalid;
386  else
387  {
388  const int nPos = rControl.find_text(aStr);
389  if (nPos != -1)
390  {
391  int nStartSelectPos, nEndSelectPos;
392  rControl.get_entry_selection_bounds(nStartSelectPos, nEndSelectPos);
393 
394  // Select the corresponding listbox entry if not current. This
395  // invalidates the Edit Selection thus has to happen between
396  // obtaining the Selection and setting the new Selection.
397  int nSelPos = m_xControl->get_active();
398  bool bSetEditSelection;
399  if (nSelPos == nPos)
400  bSetEditSelection = false;
401  else
402  {
403  m_xControl->set_active(nPos);
404  bSetEditSelection = true;
405  }
406 
407  // If typing into the Edit control led us here, advance start of a
408  // full selection by one so the next character will already
409  // continue the string instead of having to type the same character
410  // again to start a new string. The selection is in reverse
411  // when obtained from the Edit control.
412  if (nEndSelectPos == 0)
413  {
414  OUString aText(m_xControl->get_active_text());
415  if (nStartSelectPos == aText.getLength())
416  {
417  ++nEndSelectPos;
418  bSetEditSelection = true;
419  }
420  }
421 
422  if (bSetEditSelection)
423  rControl.select_entry_region(nStartSelectPos, nEndSelectPos);
424 
425  m_eEditedAndValid = EditedAndValid::No;
426  }
427  else
428  {
429  OUString aCanonicalized;
430  bool bValid = LanguageTag::isValidBcp47( aStr, &aCanonicalized, true);
431  m_eEditedAndValid = (bValid ? EditedAndValid::Valid : EditedAndValid::Invalid);
432  if (bValid && aCanonicalized != aStr)
433  {
434  m_xControl->set_entry_text(aCanonicalized);
435  const auto nCursorPos = aCanonicalized.getLength();
436  m_xControl->select_entry_region(nCursorPos, nCursorPos);
437  }
438  }
439  }
440  if (eOldState != m_eEditedAndValid)
441  {
442  if (m_eEditedAndValid == EditedAndValid::Invalid)
443  rControl.set_entry_message_type(weld::EntryMessageType::Error);
444  else
445  rControl.set_entry_message_type(weld::EntryMessageType::Normal);
446  }
447  }
448  m_aChangeHdl.Call(rControl);
449 }
450 
451 SvxLanguageBox::SvxLanguageBox(std::unique_ptr<weld::ComboBox> pControl)
452  : m_xControl(std::move(pControl))
453  , m_aAllString(SvxResId(RID_SVXSTR_LANGUAGE_ALL))
454  , m_eSavedLanguage(LANGUAGE_DONTKNOW)
455  , m_eEditedAndValid(EditedAndValid::No)
456  , m_bHasLangNone(false)
457  , m_bLangNoneIsLangAll(false)
458  , m_bWithCheckmark(false)
459 {
460  m_xControl->connect_changed(LINK(this, SvxLanguageBox, ChangeHdl));
461 }
462 
464 {
466  return -1;
467 
468  LanguageTag aLanguageTag(m_xControl->get_active_text());
469  LanguageType nLang = aLanguageTag.getLanguageType();
470  if (nLang == LANGUAGE_DONTKNOW)
471  {
472  SAL_WARN( "svx.dialog", "SvxLanguageComboBox::SaveEditedAsEntry: unknown tag");
473  return -1;
474  }
475 
476  int nPos = ImplTypeToPos( nLang);
477  if (nPos != -1)
478  return nPos; // Already present but with a different string.
479 
481  {
482  // In SvtLanguageTable but not in SvxLanguageComboBox. On purpose? This
483  // may be an entry with different settings or CTL instead of Western or
484  // ... all things we don't handle yet.
485  SAL_WARN( "svx.dialog", "SvxLanguageComboBox::SaveEditedAsEntry: already in SvtLanguageTable: " <<
486  SvtLanguageTable::GetLanguageString( nLang) << ", " << nLang);
487  }
488  else
489  {
490  // Add to both, SvtLanguageTable and SvxLanguageComboBox.
491  /* TODO: a descriptive user comment would be a nice to have here. */
492  SvtLanguageTable::AddLanguageTag( aLanguageTag );
493  }
494 
495  InsertLanguage(nLang);
496  return ImplTypeToPos(nLang);
497 }
498 
499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define LANGUAGE_NONE
void remove_id(const LanguageType eLangType)
Definition: langbox.cxx:141
Reference< XControl > m_xControl
std::unique_ptr< css::uno::Sequence< sal_Int16 > > m_xSpellUsedLang
Definition: langbox.hxx:62
static std::vector< LanguageType > lcl_LocaleSeqToLangSeq(Sequence< css::lang::Locale > const &rSeq)
Definition: langbox.cxx:70
LanguageType get_active_id() const
Definition: langbox.cxx:117
static LanguageType convertToLanguageType(const css::lang::Locale &rLocale, bool bResolveSystem=true)
static const AllSettings & GetSettings()
EditedAndValid m_eEditedAndValid
Definition: langbox.hxx:64
static LanguageType getSubLanguage(LanguageType nLangID)
static LanguageType resolveSystemLanguageByScriptType(LanguageType nLang, sal_Int16 nType)
IMPL_LINK(SvxLanguageBox, ChangeHdl, weld::ComboBox &, rControl, void)
Definition: langbox.cxx:378
bool m_bHasLangNone
Definition: langbox.hxx:65
SVX_DLLPRIVATE void InsertLanguage(const LanguageType nLangType, sal_Int16 nType)
Definition: langbox.cxx:316
SVX_DLLPRIVATE int ImplTypeToPos(LanguageType eType) const
Definition: langbox.cxx:311
OUString GetBase() const
static bool hasForbiddenCharacters(LanguageType nLang)
OUString SvxResId(const char *pId)
Definition: dialmgr.cxx:25
int nCount
SVX_DLLPRIVATE weld::ComboBoxEntry BuildEntry(const LanguageType nLangType, sal_Int16 nType=css::i18n::ScriptType::WEAK)
Definition: langbox.cxx:332
static bool HasLanguageType(const LanguageType eType)
static SvtScriptType GetScriptTypeOfLanguage(LanguageType nLang)
static bool isLegacy(LanguageType nLang)
OUString GetDicInfoStr(const OUString &rName, const LanguageType nLang, bool bNeg)
Definition: langbox.cxx:47
DocumentType eType
static LanguageType getSystemLanguage()
static css::uno::Reference< css::linguistic2::XSpellChecker1 > GetSpellChecker()
int i
void SetSmartProtocol(INetProtocol eTheSmartScheme)
#define LANGUAGE_SYSTEM
SVX_DLLPRIVATE void AddLanguages(const std::vector< LanguageType > &rLanguageTypes, SvxLanguageListFlags nLangList, std::vector< weld::ComboBoxEntry > &rEntries)
Definition: langbox.cxx:169
std::unique_ptr< weld::ComboBox > m_xControl
Definition: langbox.hxx:59
static bool lcl_SeqHasLang(const Sequence< sal_Int16 > &rLangSeq, sal_Int16 nLang)
Definition: langbox.cxx:84
#define LANGUAGE_DONTKNOW
#define SN_HYPHENATOR
static sal_uInt32 AddLanguageTag(const LanguageTag &rLanguageTag)
static css::uno::Reference< css::linguistic2::XLinguServiceManager2 > GetLngSvcMgr()
void set_active_id(const LanguageType eLangType)
Definition: langbox.cxx:151
void set_id(int nPos, const LanguageType eLangType)
Definition: langbox.cxx:131
SvxLanguageBox(std::unique_ptr< weld::ComboBox > pControl)
Definition: langbox.cxx:451
void SetLanguageList(SvxLanguageListFlags nLangList, bool bHasLangNone, bool bLangNoneIsLangAll=false, bool bCheckSpellAvail=false, bool bDefaultLangExist=false, LanguageType eDefaultLangType=LANGUAGE_NONE, sal_Int16 nDefaultType=0)
Definition: langbox.cxx:194
LanguageType get_id(int nPos) const
Definition: langbox.cxx:136
int find_id(const LanguageType eLangType) const
Definition: langbox.cxx:126
const LanguageTag & getLocale()
static std::vector< LanguageType > getInstalledLanguageTypes()
bool isValidBcp47() const
#define SN_THESAURUS
#define LANGUAGE_USER_SYSTEM_CONFIG
sal_Int32 SaveEditedAsEntry()
Definition: langbox.cxx:463
static LanguageType GetLanguageTypeAtIndex(sal_uInt32 nIndex)
bool m_bWithCheckmark
Definition: langbox.hxx:67
SvxLanguageListFlags
Definition: langbox.hxx:29
void append(const LanguageType eLangType, const OUString &rStr)
Definition: langbox.cxx:146
Reference< XComponentContext > getProcessComponentContext()
static OUString GetLanguageString(const LanguageType eType)
OUString m_aAllString
Definition: langbox.hxx:61
ScXMLEditAttributeMap::Entry const aEntries[]
static sal_uInt32 GetLanguageEntryCount()
#define SAL_WARN(area, stream)
bool m_bLangNoneIsLangAll
Definition: langbox.hxx:66
static LanguageType getReplacementForObsoleteLanguage(LanguageType nLang)
aStr
sal_uInt16 nPos
#define SN_SPELLCHECKER
bool SetSmartURL(OUString const &rTheAbsURIRef, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8, FSysStyle eStyle=FSysStyle::Detect)