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 <sal/macros.h>
22 #include "lngopt.hxx"
23 #include <linguistic/misc.hxx>
24 #include <tools/debug.hxx>
25 #include <unotools/lingucfg.hxx>
26 
27 #include <comphelper/sequence.hxx>
28 #include <cppuhelper/factory.hxx>
29 #include <cppuhelper/supportsservice.hxx>
30 #include <cppuhelper/weak.hxx>
31 #include <com/sun/star/lang/Locale.hpp>
32 
33 using namespace utl;
34 using namespace osl;
35 using namespace com::sun::star;
36 using namespace com::sun::star::beans;
37 using namespace com::sun::star::lang;
38 using namespace com::sun::star::uno;
39 using namespace com::sun::star::linguistic2;
40 using namespace linguistic;
41 
42 using namespace com::sun::star::registry;
43 
44 
45 // static member initialization
46 SvtLinguOptions *   LinguOptions::pData = nullptr;
47 oslInterlockedCount LinguOptions::nRefCount;
48 
49 
LinguOptions()50 LinguOptions::LinguOptions()
51 {
52     if (!pData)
53     {
54         pData = new SvtLinguOptions;
55         SvtLinguConfig aLinguCfg;
56         aLinguCfg.GetOptions( *pData );
57     }
58 
59     osl_atomic_increment( &nRefCount );
60 }
61 
62 
LinguOptions(const LinguOptions &)63 LinguOptions::LinguOptions(const LinguOptions & /*rOpt*/)
64 {
65     DBG_ASSERT( pData, "lng : data missing" );
66     osl_atomic_increment( &nRefCount );
67 }
68 
69 
~LinguOptions()70 LinguOptions::~LinguOptions()
71 {
72     MutexGuard  aGuard( GetLinguMutex() );
73 
74     if ( osl_atomic_decrement( &nRefCount ) == 0 )
75     {
76         delete pData;   pData  = nullptr;
77     }
78 }
79 
80 namespace {
81 
82 struct WID_Name
83 {
84     sal_Int32        nWID;
85     const char  *pPropertyName;
86 };
87 
88 }
89 
90 //! order of entries is import (see LinguOptions::GetName)
91 //! since the WID is used as index in this table!
92 WID_Name const aWID_Name[] =
93 {
94     { 0,                                  nullptr },
95     { UPH_IS_USE_DICTIONARY_LIST,         UPN_IS_USE_DICTIONARY_LIST },
96     { UPH_IS_IGNORE_CONTROL_CHARACTERS,   UPN_IS_IGNORE_CONTROL_CHARACTERS },
97     { UPH_IS_SPELL_UPPER_CASE,            UPN_IS_SPELL_UPPER_CASE },
98     { UPH_IS_SPELL_WITH_DIGITS,           UPN_IS_SPELL_WITH_DIGITS },
99     { UPH_IS_SPELL_CAPITALIZATION,        UPN_IS_SPELL_CAPITALIZATION },
100     { UPH_HYPH_MIN_LEADING,               UPN_HYPH_MIN_LEADING },
101     { UPH_HYPH_MIN_TRAILING,              UPN_HYPH_MIN_TRAILING },
102     { UPH_HYPH_MIN_WORD_LENGTH,           UPN_HYPH_MIN_WORD_LENGTH },
103     { UPH_DEFAULT_LOCALE,                 UPN_DEFAULT_LOCALE },
104     { UPH_IS_SPELL_AUTO,                  UPN_IS_SPELL_AUTO },
105     { 0,                                  nullptr },
106     { 0,                                  nullptr },
107     { UPH_IS_SPELL_SPECIAL,               UPN_IS_SPELL_SPECIAL },
108     { UPH_IS_HYPH_AUTO,                   UPN_IS_HYPH_AUTO },
109     { UPH_IS_HYPH_SPECIAL,                UPN_IS_HYPH_SPECIAL },
110     { UPH_IS_WRAP_REVERSE,                UPN_IS_WRAP_REVERSE },
111     { 0,                                  nullptr },
112     { 0,                                  nullptr },
113     { 0,                                  nullptr },
114     { 0,                                  nullptr },
115     { UPH_DEFAULT_LANGUAGE,               UPN_DEFAULT_LANGUAGE },
116     { UPH_DEFAULT_LOCALE_CJK,             UPN_DEFAULT_LOCALE_CJK },
117     { UPH_DEFAULT_LOCALE_CTL,             UPN_DEFAULT_LOCALE_CTL }
118 };
119 
120 
GetName(sal_Int32 nWID)121 OUString LinguOptions::GetName( sal_Int32 nWID )
122 {
123     MutexGuard  aGuard( GetLinguMutex() );
124 
125     OUString aRes;
126 
127     if (0 <= nWID && nWID < sal_Int32(SAL_N_ELEMENTS(aWID_Name)) && aWID_Name[ nWID ].nWID == nWID)
128         aRes = OUString::createFromAscii(aWID_Name[nWID].pPropertyName);
129     else
130         OSL_FAIL("lng : unknown WID");
131 
132     return aRes;
133 }
134 
135 
136 //! map must be sorted by first entry in alphabetical increasing order.
lcl_GetLinguProps()137 static const SfxItemPropertyMapEntry* lcl_GetLinguProps()
138 {
139     static const SfxItemPropertyMapEntry aLinguProps[] =
140     {
141         { u"" UPN_DEFAULT_LANGUAGE,           UPH_DEFAULT_LANGUAGE,
142                 ::cppu::UnoType<sal_Int16>::get(),    0, 0 },
143         { u"" UPN_DEFAULT_LOCALE,             UPH_DEFAULT_LOCALE,
144                 ::cppu::UnoType<Locale>::get(),       0, 0 },
145         { u"" UPN_DEFAULT_LOCALE_CJK,         UPH_DEFAULT_LOCALE_CJK,
146                 ::cppu::UnoType<Locale>::get(),       0, 0 },
147         { u"" UPN_DEFAULT_LOCALE_CTL,         UPH_DEFAULT_LOCALE_CTL,
148                 ::cppu::UnoType<Locale>::get(),       0, 0 },
149         { u"" UPN_HYPH_MIN_LEADING,           UPH_HYPH_MIN_LEADING,
150                 ::cppu::UnoType<sal_Int16>::get(),    0, 0 },
151         { u"" UPN_HYPH_MIN_TRAILING,          UPH_HYPH_MIN_TRAILING,
152                 ::cppu::UnoType<sal_Int16>::get(),    0, 0 },
153         { u"" UPN_HYPH_MIN_WORD_LENGTH,       UPH_HYPH_MIN_WORD_LENGTH,
154                 ::cppu::UnoType<sal_Int16>::get(),    0, 0 },
155         { u"" UPN_IS_GERMAN_PRE_REFORM,       UPH_IS_GERMAN_PRE_REFORM,       /*! deprecated !*/
156                 cppu::UnoType<bool>::get(),            0, 0 },
157         { u"" UPN_IS_HYPH_AUTO,               UPH_IS_HYPH_AUTO,
158                 cppu::UnoType<bool>::get(),            0, 0 },
159         { u"" UPN_IS_HYPH_SPECIAL,            UPH_IS_HYPH_SPECIAL,
160                 cppu::UnoType<bool>::get(),            0, 0 },
161         { u"" UPN_IS_IGNORE_CONTROL_CHARACTERS,   UPH_IS_IGNORE_CONTROL_CHARACTERS,
162                 cppu::UnoType<bool>::get(),            0, 0 },
163         { u"" UPN_IS_SPELL_AUTO,              UPH_IS_SPELL_AUTO,
164                 cppu::UnoType<bool>::get(),            0, 0 },
165         { u"" UPN_IS_SPELL_CAPITALIZATION,    UPH_IS_SPELL_CAPITALIZATION,
166                 cppu::UnoType<bool>::get(),            0, 0 },
167         { u"" UPN_IS_SPELL_HIDE,              UPH_IS_SPELL_HIDE,              /*! deprecated !*/
168                 cppu::UnoType<bool>::get(),            0, 0 },
169         { u"" UPN_IS_SPELL_IN_ALL_LANGUAGES,  UPH_IS_SPELL_IN_ALL_LANGUAGES,  /*! deprecated !*/
170                 cppu::UnoType<bool>::get(),            0, 0 },
171         { u"" UPN_IS_SPELL_SPECIAL,           UPH_IS_SPELL_SPECIAL,
172                 cppu::UnoType<bool>::get(),            0, 0 },
173         { u"" UPN_IS_SPELL_UPPER_CASE,        UPH_IS_SPELL_UPPER_CASE,
174                 cppu::UnoType<bool>::get(),            0, 0 },
175         { u"" UPN_IS_SPELL_WITH_DIGITS,       UPH_IS_SPELL_WITH_DIGITS,
176                 cppu::UnoType<bool>::get(),            0, 0 },
177         { u"" UPN_IS_USE_DICTIONARY_LIST,     UPH_IS_USE_DICTIONARY_LIST,
178                 cppu::UnoType<bool>::get(),            0, 0 },
179         { u"" UPN_IS_WRAP_REVERSE,            UPH_IS_WRAP_REVERSE,
180                 cppu::UnoType<bool>::get(),            0, 0 },
181         { u"", 0, css::uno::Type(), 0, 0 }
182     };
183     return aLinguProps;
184 }
LinguProps()185 LinguProps::LinguProps() :
186     aEvtListeners   (GetLinguMutex()),
187     aPropListeners  (GetLinguMutex()),
188     aPropertyMap(lcl_GetLinguProps())
189 {
190     bDisposing = false;
191 }
192 
launchEvent(const PropertyChangeEvent & rEvt) const193 void LinguProps::launchEvent( const PropertyChangeEvent &rEvt ) const
194 {
195     cppu::OInterfaceContainerHelper *pContainer =
196             aPropListeners.getContainer( rEvt.PropertyHandle );
197     if (pContainer)
198     {
199         cppu::OInterfaceIteratorHelper aIt( *pContainer );
200         while (aIt.hasMoreElements())
201         {
202             Reference< XPropertyChangeListener > xRef( aIt.next(), UNO_QUERY );
203             if (xRef.is())
204                 xRef->propertyChange( rEvt );
205         }
206     }
207 }
208 
getPropertySetInfo()209 Reference< XPropertySetInfo > SAL_CALL LinguProps::getPropertySetInfo()
210 {
211     MutexGuard  aGuard( GetLinguMutex() );
212 
213     static Reference< XPropertySetInfo > aRef =
214             new SfxItemPropertySetInfo( aPropertyMap );
215     return aRef;
216 }
217 
setPropertyValue(const OUString & rPropertyName,const Any & rValue)218 void SAL_CALL LinguProps::setPropertyValue(
219             const OUString& rPropertyName, const Any& rValue )
220 {
221     MutexGuard  aGuard( GetLinguMutex() );
222 
223     const SfxItemPropertyMapEntry* pCur = aPropertyMap.getByName( rPropertyName );
224     if (pCur)
225     {
226         Any aOld( aConfig.GetProperty( pCur->nWID ) );
227         if (aOld != rValue && aConfig.SetProperty( pCur->nWID, rValue ))
228         {
229             PropertyChangeEvent aChgEvt( static_cast<XPropertySet *>(this), rPropertyName,
230                     false, pCur->nWID, aOld, rValue );
231             launchEvent( aChgEvt );
232         }
233     }
234 }
235 
getPropertyValue(const OUString & rPropertyName)236 Any SAL_CALL LinguProps::getPropertyValue( const OUString& rPropertyName )
237 {
238     MutexGuard  aGuard( GetLinguMutex() );
239 
240     Any aRet;
241 
242     const SfxItemPropertyMapEntry* pCur = aPropertyMap.getByName( rPropertyName );
243     if(pCur)
244     {
245         aRet = aConfig.GetProperty( pCur->nWID );
246     }
247 
248     return aRet;
249 }
250 
addPropertyChangeListener(const OUString & rPropertyName,const Reference<XPropertyChangeListener> & rxListener)251 void SAL_CALL LinguProps::addPropertyChangeListener(
252             const OUString& rPropertyName,
253             const Reference< XPropertyChangeListener >& rxListener )
254 {
255     MutexGuard  aGuard( GetLinguMutex() );
256 
257     if (!bDisposing && rxListener.is())
258     {
259         const SfxItemPropertyMapEntry* pCur = aPropertyMap.getByName( rPropertyName );
260         if(pCur)
261             aPropListeners.addInterface( pCur->nWID, rxListener );
262     }
263 }
264 
removePropertyChangeListener(const OUString & rPropertyName,const Reference<XPropertyChangeListener> & rxListener)265 void SAL_CALL LinguProps::removePropertyChangeListener(
266             const OUString& rPropertyName,
267             const Reference< XPropertyChangeListener >& rxListener )
268 {
269     MutexGuard  aGuard( GetLinguMutex() );
270 
271     if (!bDisposing && rxListener.is())
272     {
273         const SfxItemPropertyMapEntry* pCur = aPropertyMap.getByName( rPropertyName );
274         if(pCur)
275             aPropListeners.removeInterface( pCur->nWID, rxListener );
276     }
277 }
278 
addVetoableChangeListener(const OUString &,const Reference<XVetoableChangeListener> &)279 void SAL_CALL LinguProps::addVetoableChangeListener(
280             const OUString& /*rPropertyName*/,
281             const Reference< XVetoableChangeListener >& /*xListener*/ )
282 {
283 }
284 
removeVetoableChangeListener(const OUString &,const Reference<XVetoableChangeListener> &)285 void SAL_CALL LinguProps::removeVetoableChangeListener(
286             const OUString& /*rPropertyName*/,
287             const Reference< XVetoableChangeListener >& /*xListener*/ )
288 {
289 }
290 
291 
setFastPropertyValue(sal_Int32 nHandle,const Any & rValue)292 void SAL_CALL LinguProps::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue )
293 {
294     MutexGuard  aGuard( GetLinguMutex() );
295 
296     Any aOld( aConfig.GetProperty( nHandle ) );
297     if (aOld != rValue && aConfig.SetProperty( nHandle, rValue ))
298     {
299         PropertyChangeEvent aChgEvt( static_cast<XPropertySet *>(this),
300                 LinguOptions::GetName( nHandle ), false, nHandle, aOld, rValue );
301         launchEvent( aChgEvt );
302     }
303 }
304 
305 
getFastPropertyValue(sal_Int32 nHandle)306 Any SAL_CALL LinguProps::getFastPropertyValue( sal_Int32 nHandle )
307 {
308     MutexGuard  aGuard( GetLinguMutex() );
309 
310     Any aRes( aConfig.GetProperty( nHandle ) );
311     return aRes;
312 }
313 
314 
315 Sequence< PropertyValue > SAL_CALL
getPropertyValues()316     LinguProps::getPropertyValues()
317 {
318     MutexGuard  aGuard( GetLinguMutex() );
319 
320     std::vector<PropertyValue> aProps;
321     aProps.reserve(aPropertyMap.getPropertyEntries().size());
322     for(auto pEntry : aPropertyMap.getPropertyEntries())
323         aProps.push_back(PropertyValue(pEntry->aName, pEntry->nWID,
324                                  aConfig.GetProperty(pEntry->nWID),
325                                  css::beans::PropertyState_DIRECT_VALUE));
326     return comphelper::containerToSequence(aProps);
327 }
328 
329 void SAL_CALL
setPropertyValues(const Sequence<PropertyValue> & rProps)330     LinguProps::setPropertyValues( const Sequence< PropertyValue >& rProps )
331 {
332     MutexGuard  aGuard( GetLinguMutex() );
333 
334     for (const PropertyValue &rVal : rProps)
335     {
336         setPropertyValue( rVal.Name, rVal.Value );
337     }
338 }
339 
340 void SAL_CALL
dispose()341     LinguProps::dispose()
342 {
343     MutexGuard  aGuard( GetLinguMutex() );
344 
345     if (!bDisposing)
346     {
347         bDisposing = true;
348 
349         //! it's too late to save the options here!
350         // (see AppExitListener for saving)
351         //aOpt.Save();  // save (possible) changes before exiting
352 
353         EventObject aEvtObj( static_cast<XPropertySet *>(this) );
354         aEvtListeners.disposeAndClear( aEvtObj );
355         aPropListeners.disposeAndClear( aEvtObj );
356     }
357 }
358 
359 void SAL_CALL
addEventListener(const Reference<XEventListener> & rxListener)360     LinguProps::addEventListener( const Reference< XEventListener >& rxListener )
361 {
362     MutexGuard  aGuard( GetLinguMutex() );
363 
364     if (!bDisposing && rxListener.is())
365         aEvtListeners.addInterface( rxListener );
366 }
367 
368 void SAL_CALL
removeEventListener(const Reference<XEventListener> & rxListener)369     LinguProps::removeEventListener( const Reference< XEventListener >& rxListener )
370 {
371     MutexGuard  aGuard( GetLinguMutex() );
372 
373     if (!bDisposing && rxListener.is())
374         aEvtListeners.removeInterface( rxListener );
375 }
376 
377 
378 // Service specific part
379 
380 // XServiceInfo
getImplementationName()381 OUString SAL_CALL LinguProps::getImplementationName()
382 {
383     return "com.sun.star.lingu2.LinguProps";
384 }
385 
386 // XServiceInfo
supportsService(const OUString & ServiceName)387 sal_Bool SAL_CALL LinguProps::supportsService( const OUString& ServiceName )
388 {
389     return cppu::supportsService(this, ServiceName);
390 }
391 
392 // XServiceInfo
getSupportedServiceNames()393 uno::Sequence< OUString > SAL_CALL LinguProps::getSupportedServiceNames()
394 {
395     return { "com.sun.star.linguistic2.LinguProperties" };
396 }
397 
getPropertyBool(const OUString & aPropertyName)398 bool LinguProps::getPropertyBool(const OUString& aPropertyName)
399 {
400    uno::Any any = getPropertyValue(aPropertyName);
401    bool b = false;
402    any >>= b;
403    return b;
404 }
405 
getPropertyInt16(const OUString & aPropertyName)406 sal_Int16 LinguProps::getPropertyInt16(const OUString& aPropertyName)
407 {
408    uno::Any any = getPropertyValue(aPropertyName);
409    sal_Int16 b = 0;
410    any >>= b;
411    return b;
412 }
413 
getPropertyLocale(const OUString & aPropertyName)414 Locale LinguProps::getPropertyLocale(const OUString& aPropertyName)
415 {
416    uno::Any any = getPropertyValue(aPropertyName);
417    css::lang::Locale b;
418    any >>= b;
419    return b;
420 }
421 
422 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
linguistic_LinguProps_get_implementation(css::uno::XComponentContext *,css::uno::Sequence<css::uno::Any> const &)423 linguistic_LinguProps_get_implementation(
424     css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
425 {
426     return cppu::acquire(new LinguProps());
427 }
428 
429 
430 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
431