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