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 <svl/cjkoptions.hxx>
21 
22 #include <o3tl/any.hxx>
23 #include <svl/languageoptions.hxx>
24 #include <i18nlangtag/lang.h>
25 #include <unotools/configitem.hxx>
26 #include <com/sun/star/uno/Any.h>
27 #include <com/sun/star/uno/Sequence.hxx>
28 #include <osl/mutex.hxx>
29 #include <rtl/instance.hxx>
30 
31 #include "itemholder2.hxx"
32 
33 using namespace ::com::sun::star::uno;
34 
35 #define CFG_READONLY_DEFAULT false
36 
37 class SvtCJKOptions_Impl : public utl::ConfigItem
38 {
39     bool        bIsLoaded;
40     bool        bCJKFont;
41     bool        bVerticalText;
42     bool        bAsianTypography;
43     bool        bJapaneseFind;
44     bool        bRuby;
45     bool        bChangeCaseMap;
46     bool        bDoubleLines;
47     bool        bEmphasisMarks;
48     bool        bVerticalCallOut;
49 
50     bool        bROCJKFont;
51     bool        bROVerticalText;
52     bool        bROAsianTypography;
53     bool        bROJapaneseFind;
54     bool        bRORuby;
55     bool        bROChangeCaseMap;
56     bool        bRODoubleLines;
57     bool        bROEmphasisMarks;
58     bool        bROVerticalCallOut;
59 
60     virtual void    ImplCommit() override;
61 
62 public:
63     SvtCJKOptions_Impl();
64 
65     virtual void    Notify( const css::uno::Sequence< OUString >& rPropertyNames ) override;
66     void            Load();
67 
IsLoaded() const68     bool IsLoaded() const                   { return bIsLoaded;         }
69 
IsCJKFontEnabled() const70     bool IsCJKFontEnabled() const           { return bCJKFont;          }
IsVerticalTextEnabled() const71     bool IsVerticalTextEnabled() const      { return bVerticalText;     }
IsAsianTypographyEnabled() const72     bool IsAsianTypographyEnabled() const   { return bAsianTypography;  }
IsJapaneseFindEnabled() const73     bool IsJapaneseFindEnabled() const      { return bJapaneseFind;     }
IsRubyEnabled() const74     bool IsRubyEnabled() const              { return bRuby;             }
IsChangeCaseMapEnabled() const75     bool IsChangeCaseMapEnabled() const     { return bChangeCaseMap;    }
IsDoubleLinesEnabled() const76     bool IsDoubleLinesEnabled() const       { return bDoubleLines;      }
77 
IsAnyEnabled() const78     bool IsAnyEnabled() const {
79         return  bCJKFont||bVerticalText||bAsianTypography||bJapaneseFind||
80                 bRuby||bChangeCaseMap||bDoubleLines||bEmphasisMarks||bVerticalCallOut;   }
81     void    SetAll(bool bSet);
82     bool IsReadOnly(SvtCJKOptions::EOption eOption) const;
83 };
84 
85 namespace
86 {
87     struct PropertyNames
88         : public rtl::Static< Sequence<OUString>, PropertyNames > {};
89 }
90 
SvtCJKOptions_Impl()91 SvtCJKOptions_Impl::SvtCJKOptions_Impl() :
92     utl::ConfigItem("Office.Common/I18N/CJK"),
93     bIsLoaded(false),
94     bCJKFont(true),
95     bVerticalText(true),
96     bAsianTypography(true),
97     bJapaneseFind(true),
98     bRuby(true),
99     bChangeCaseMap(true),
100     bDoubleLines(true),
101     bEmphasisMarks(true),
102     bVerticalCallOut(true),
103     bROCJKFont(CFG_READONLY_DEFAULT),
104     bROVerticalText(CFG_READONLY_DEFAULT),
105     bROAsianTypography(CFG_READONLY_DEFAULT),
106     bROJapaneseFind(CFG_READONLY_DEFAULT),
107     bRORuby(CFG_READONLY_DEFAULT),
108     bROChangeCaseMap(CFG_READONLY_DEFAULT),
109     bRODoubleLines(CFG_READONLY_DEFAULT),
110     bROEmphasisMarks(CFG_READONLY_DEFAULT),
111     bROVerticalCallOut(CFG_READONLY_DEFAULT)
112 {
113 }
114 
SetAll(bool bSet)115 void    SvtCJKOptions_Impl::SetAll(bool bSet)
116 {
117     if (
118         bROCJKFont          ||
119         bROVerticalText     ||
120         bROAsianTypography  ||
121         bROJapaneseFind     ||
122         bRORuby             ||
123         bROChangeCaseMap    ||
124         bRODoubleLines      ||
125         bROEmphasisMarks    ||
126         bROVerticalCallOut
127        )
128         return;
129 
130     bCJKFont=bSet;
131     bVerticalText=bSet;
132     bAsianTypography=bSet;
133     bJapaneseFind=bSet;
134     bRuby=bSet;
135     bChangeCaseMap=bSet;
136     bDoubleLines=bSet;
137     bEmphasisMarks=bSet;
138     bVerticalCallOut=bSet;
139 
140     SetModified();
141     Commit();
142     NotifyListeners(ConfigurationHints::NONE);
143 }
144 
Load()145 void SvtCJKOptions_Impl::Load()
146 {
147     Sequence<OUString> &rPropertyNames = PropertyNames::get();
148     if(!rPropertyNames.hasElements())
149     {
150         rPropertyNames.realloc(9);
151         OUString* pNames = rPropertyNames.getArray();
152 
153         pNames[0] = "CJKFont";
154         pNames[1] = "VerticalText";
155         pNames[2] = "AsianTypography";
156         pNames[3] = "JapaneseFind";
157         pNames[4] = "Ruby";
158         pNames[5] = "ChangeCaseMap";
159         pNames[6] = "DoubleLines";
160         pNames[7] = "EmphasisMarks";
161         pNames[8] = "VerticalCallOut";
162 
163         EnableNotification( rPropertyNames );
164     }
165     Sequence< Any > aValues = GetProperties(rPropertyNames);
166     Sequence< sal_Bool > aROStates = GetReadOnlyStates(rPropertyNames);
167     const Any* pValues = aValues.getConstArray();
168     const sal_Bool* pROStates = aROStates.getConstArray();
169     assert(aValues.getLength() == rPropertyNames.getLength() && "GetProperties failed");
170     assert(aROStates.getLength() == rPropertyNames.getLength() && "GetReadOnlyStates failed");
171     if ( aValues.getLength() == rPropertyNames.getLength() && aROStates.getLength() == rPropertyNames.getLength() )
172     {
173         for ( int nProp = 0; nProp < rPropertyNames.getLength(); nProp++ )
174         {
175             if( pValues[nProp].hasValue() )
176             {
177                 bool bValue = *o3tl::doAccess<bool>(pValues[nProp]);
178                 switch ( nProp )
179                 {
180                     case 0: { bCJKFont = bValue; bROCJKFont = pROStates[nProp]; } break;
181                     case 1: { bVerticalText = bValue; bROVerticalText = pROStates[nProp]; } break;
182                     case 2: { bAsianTypography = bValue; bROAsianTypography = pROStates[nProp]; } break;
183                     case 3: { bJapaneseFind = bValue; bROJapaneseFind = pROStates[nProp]; } break;
184                     case 4: { bRuby = bValue; bRORuby = pROStates[nProp]; } break;
185                     case 5: { bChangeCaseMap = bValue; bROChangeCaseMap = pROStates[nProp]; } break;
186                     case 6: { bDoubleLines = bValue; bRODoubleLines = pROStates[nProp]; } break;
187                     case 7: { bEmphasisMarks = bValue; bROEmphasisMarks = pROStates[nProp]; } break;
188                     case 8: { bVerticalCallOut = bValue; bROVerticalCallOut = pROStates[nProp]; } break;
189                 }
190             }
191         }
192     }
193 
194     if (!bCJKFont)
195     {
196         SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage(LANGUAGE_SYSTEM);
197         //system locale is CJK
198         bool bAutoEnableCJK = bool(nScriptType & SvtScriptType::ASIAN);
199 
200         if (!bAutoEnableCJK)
201         {
202             SvtSystemLanguageOptions aSystemLocaleSettings;
203 
204             //windows secondary system locale is CJK
205             LanguageType eSystemLanguage = aSystemLocaleSettings.GetWin16SystemLanguage();
206             if (eSystemLanguage != LANGUAGE_SYSTEM)
207             {
208                 SvtScriptType nWinScript = SvtLanguageOptions::GetScriptTypeOfLanguage( eSystemLanguage );
209                 bAutoEnableCJK = bool(nWinScript & SvtScriptType::ASIAN);
210             }
211 
212             //CJK keyboard is installed
213             if (!bAutoEnableCJK)
214                 bAutoEnableCJK = aSystemLocaleSettings.isCJKKeyboardLayoutInstalled();
215         }
216 
217         if (bAutoEnableCJK)
218         {
219             SetAll(true);
220         }
221     }
222     bIsLoaded = true;
223 }
224 
Notify(const Sequence<OUString> &)225 void    SvtCJKOptions_Impl::Notify( const Sequence< OUString >& )
226 {
227     Load();
228     NotifyListeners(ConfigurationHints::NONE);
229 }
230 
ImplCommit()231 void    SvtCJKOptions_Impl::ImplCommit()
232 {
233     Sequence<OUString> &rPropertyNames = PropertyNames::get();
234     OUString* pOrgNames = rPropertyNames.getArray();
235     sal_Int32 nOrgCount = rPropertyNames.getLength();
236 
237     Sequence< OUString > aNames(nOrgCount);
238     Sequence< Any > aValues(nOrgCount);
239 
240     OUString* pNames = aNames.getArray();
241     Any* pValues = aValues.getArray();
242     sal_Int32 nRealCount = 0;
243 
244     for(int nProp = 0; nProp < nOrgCount; nProp++)
245     {
246         switch(nProp)
247         {
248             case  0:
249                 {
250                     if (!bROCJKFont)
251                     {
252                         pNames[nRealCount] = pOrgNames[nProp];
253                         pValues[nRealCount] <<= bCJKFont;
254                         ++nRealCount;
255                     }
256                 }
257                 break;
258 
259             case  1:
260                 {
261                     if (!bROVerticalText)
262                     {
263                         pNames[nRealCount] = pOrgNames[nProp];
264                         pValues[nRealCount] <<= bVerticalText;
265                         ++nRealCount;
266                     }
267                 }
268                 break;
269 
270             case  2:
271                 {
272                     if (!bROAsianTypography)
273                     {
274                         pNames[nRealCount] = pOrgNames[nProp];
275                         pValues[nRealCount] <<= bAsianTypography;
276                         ++nRealCount;
277                     }
278                 }
279                 break;
280 
281             case  3:
282                 {
283                     if (!bROJapaneseFind)
284                     {
285                         pNames[nRealCount] = pOrgNames[nProp];
286                         pValues[nRealCount] <<= bJapaneseFind;
287                         ++nRealCount;
288                     }
289                 }
290                 break;
291 
292             case  4:
293                 {
294                     if (!bRORuby)
295                     {
296                         pNames[nRealCount] = pOrgNames[nProp];
297                         pValues[nRealCount] <<= bRuby;
298                         ++nRealCount;
299                     }
300                 }
301                 break;
302 
303             case  5:
304                 {
305                     if (!bROChangeCaseMap)
306                     {
307                         pNames[nRealCount] = pOrgNames[nProp];
308                         pValues[nRealCount] <<= bChangeCaseMap;
309                         ++nRealCount;
310                     }
311                 }
312                 break;
313 
314             case  6:
315                 {
316                     if (!bRODoubleLines)
317                     {
318                         pNames[nRealCount] = pOrgNames[nProp];
319                         pValues[nRealCount] <<= bDoubleLines;
320                         ++nRealCount;
321                     }
322                 }
323                 break;
324 
325             case  7:
326                 {
327                     if (!bROEmphasisMarks)
328                     {
329                         pNames[nRealCount] = pOrgNames[nProp];
330                         pValues[nRealCount] <<= bEmphasisMarks;
331                         ++nRealCount;
332                     }
333                 }
334                 break;
335 
336             case  8:
337                 {
338                     if (!bROVerticalCallOut)
339                     {
340                         pNames[nRealCount] = pOrgNames[nProp];
341                         pValues[nRealCount] <<= bVerticalCallOut;
342                         ++nRealCount;
343                     }
344                 }
345                 break;
346         }
347     }
348     aNames.realloc(nRealCount);
349     aValues.realloc(nRealCount);
350     PutProperties(aNames, aValues);
351 }
352 
IsReadOnly(SvtCJKOptions::EOption eOption) const353 bool SvtCJKOptions_Impl::IsReadOnly(SvtCJKOptions::EOption eOption) const
354 {
355     bool bReadOnly = CFG_READONLY_DEFAULT;
356     switch(eOption)
357     {
358         case SvtCJKOptions::E_CJKFONT : bReadOnly = bROCJKFont; break;
359         case SvtCJKOptions::E_VERTICALTEXT : bReadOnly = bROVerticalText; break;
360         case SvtCJKOptions::E_ASIANTYPOGRAPHY : bReadOnly = bROAsianTypography; break;
361         case SvtCJKOptions::E_JAPANESEFIND : bReadOnly = bROJapaneseFind; break;
362         case SvtCJKOptions::E_RUBY : bReadOnly = bRORuby; break;
363         case SvtCJKOptions::E_CHANGECASEMAP : bReadOnly = bROChangeCaseMap; break;
364         case SvtCJKOptions::E_DOUBLELINES : bReadOnly = bRODoubleLines; break;
365         case SvtCJKOptions::E_EMPHASISMARKS : bReadOnly = bROEmphasisMarks; break;
366         case SvtCJKOptions::E_VERTICALCALLOUT : bReadOnly = bROVerticalCallOut; break;
367         case SvtCJKOptions::E_ALL : if (bROCJKFont || bROVerticalText || bROAsianTypography || bROJapaneseFind || bRORuby || bROChangeCaseMap || bRODoubleLines || bROEmphasisMarks || bROVerticalCallOut)
368                                         bReadOnly = true;
369                                 break;
370     }
371     return bReadOnly;
372 }
373 
374 namespace {
375 
376     // global
377     std::weak_ptr<SvtCJKOptions_Impl> g_pCJKOptions;
378 
379     struct theCJKOptionsMutex : public rtl::Static< ::osl::Mutex , theCJKOptionsMutex >{};
380 }
381 
SvtCJKOptions(bool bDontLoad)382 SvtCJKOptions::SvtCJKOptions(bool bDontLoad)
383 {
384     // Global access, must be guarded (multithreading)
385     ::osl::MutexGuard aGuard( theCJKOptionsMutex::get() );
386     pImpl = g_pCJKOptions.lock();
387     if ( !pImpl )
388     {
389         pImpl = std::make_shared<SvtCJKOptions_Impl>();
390         g_pCJKOptions = pImpl;
391         ItemHolder2::holdConfigItem(EItem::CJKOptions);
392     }
393 
394     if( !bDontLoad && !pImpl->IsLoaded())
395         pImpl->Load();
396 }
397 
398 
~SvtCJKOptions()399 SvtCJKOptions::~SvtCJKOptions()
400 {
401     // Global access, must be guarded (multithreading)
402     ::osl::MutexGuard aGuard( theCJKOptionsMutex::get() );
403 
404     // pImpl needs to be cleared before the mutex is dropped
405     pImpl.reset();
406 }
407 
IsCJKFontEnabled() const408 bool SvtCJKOptions::IsCJKFontEnabled() const
409 {
410     assert(pImpl->IsLoaded());
411     return pImpl->IsCJKFontEnabled();
412 }
413 
IsVerticalTextEnabled() const414 bool SvtCJKOptions::IsVerticalTextEnabled() const
415 {
416     assert(pImpl->IsLoaded());
417     return pImpl->IsVerticalTextEnabled();
418 }
419 
IsAsianTypographyEnabled() const420 bool SvtCJKOptions::IsAsianTypographyEnabled() const
421 {
422     assert(pImpl->IsLoaded());
423     return pImpl->IsAsianTypographyEnabled();
424 }
425 
IsJapaneseFindEnabled() const426 bool SvtCJKOptions::IsJapaneseFindEnabled() const
427 {
428     assert(pImpl->IsLoaded());
429     return pImpl->IsJapaneseFindEnabled();
430 }
431 
IsRubyEnabled() const432 bool SvtCJKOptions::IsRubyEnabled() const
433 {
434     assert(pImpl->IsLoaded());
435     return pImpl->IsRubyEnabled();
436 }
437 
IsChangeCaseMapEnabled() const438 bool SvtCJKOptions::IsChangeCaseMapEnabled() const
439 {
440     assert(pImpl->IsLoaded());
441     return pImpl->IsChangeCaseMapEnabled();
442 }
443 
IsDoubleLinesEnabled() const444 bool SvtCJKOptions::IsDoubleLinesEnabled() const
445 {
446     assert(pImpl->IsLoaded());
447     return pImpl->IsDoubleLinesEnabled();
448 }
449 
SetAll(bool bSet)450 void        SvtCJKOptions::SetAll(bool bSet)
451 {
452     assert(pImpl->IsLoaded());
453     pImpl->SetAll(bSet);
454 }
455 
IsAnyEnabled() const456 bool    SvtCJKOptions::IsAnyEnabled() const
457 {
458     assert(pImpl->IsLoaded());
459     return pImpl->IsAnyEnabled();
460 }
461 
IsReadOnly(EOption eOption) const462 bool    SvtCJKOptions::IsReadOnly(EOption eOption) const
463 {
464     assert(pImpl->IsLoaded());
465     return pImpl->IsReadOnly(eOption);
466 }
467 
468 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
469