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