1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <boost/noncopyable.hpp>
23 #include <com/sun/star/container/XNameContainer.hpp>
24 #include <com/sun/star/lang/Locale.hpp>
25 #include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
26 #include <com/sun/star/linguistic2/XConversionDictionary.hpp>
27 #include <com/sun/star/linguistic2/XConversionDictionaryList.hpp>
28 #include <com/sun/star/registry/XRegistryKey.hpp>
29 #include <com/sun/star/uno/Reference.h>
30 #include <com/sun/star/util/XFlushable.hpp>
31 #include <cppuhelper/factory.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <cppuhelper/supportsservice.hxx>
34 #include <rtl/instance.hxx>
35 #include <tools/stream.hxx>
36 #include <tools/urlobj.hxx>
37 #include <ucbhelper/content.hxx>
38 #include <unotools/localfilehelper.hxx>
39 #include <unotools/lingucfg.hxx>
40 #include <unotools/pathoptions.hxx>
41 #include <unotools/useroptions.hxx>
43 #include "convdic.hxx"
44 #include "convdiclist.hxx"
46 #include "hhconvdic.hxx"
48 #include "linguistic/misc.hxx"
51 using namespace com::sun::star
;
52 using namespace com::sun::star::lang
;
53 using namespace com::sun::star::uno
;
54 using namespace com::sun::star::container
;
55 using namespace com::sun::star::linguistic2
;
56 using namespace linguistic
;
58 #define SN_CONV_DICTIONARY_LIST "com.sun.star.linguistic2.ConversionDictionaryList"
60 bool operator == ( const Locale
&r1
, const Locale
&r2
)
62 return r1
.Language
== r2
.Language
&&
63 r1
.Country
== r2
.Country
&&
64 r1
.Variant
== r2
.Variant
;
67 OUString
GetConvDicMainURL( const OUString
&rDicName
, const OUString
&rDirectoryURL
)
69 // build URL to use for new (persistent) dictionaries
71 OUString aFullDicName
= OUString(rDicName
) + CONV_DIC_DOT_EXT
;
73 INetURLObject aURLObj
;
74 aURLObj
.SetSmartProtocol( INetProtocol::File
);
75 aURLObj
.SetSmartURL( rDirectoryURL
);
76 aURLObj
.Append( aFullDicName
, INetURLObject::ENCODE_ALL
);
77 DBG_ASSERT(!aURLObj
.HasError(), "invalid URL");
78 if (aURLObj
.HasError())
81 return aURLObj
.GetMainURL( INetURLObject::DECODE_TO_IURI
);
84 class ConvDicNameContainer
:
85 public cppu::WeakImplHelper1
87 ::com::sun::star::container::XNameContainer
89 private boost::noncopyable
91 uno::Sequence
< uno::Reference
< XConversionDictionary
> > aConvDics
;
93 sal_Int32
GetIndexByName_Impl( const OUString
& rName
);
96 ConvDicNameContainer();
97 virtual ~ConvDicNameContainer();
100 virtual ::com::sun::star::uno::Type SAL_CALL
getElementType( ) throw (::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
101 virtual sal_Bool SAL_CALL
hasElements( ) throw (::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
104 virtual ::com::sun::star::uno::Any SAL_CALL
getByName( const OUString
& aName
) throw (::com::sun::star::container::NoSuchElementException
, ::com::sun::star::lang::WrappedTargetException
, ::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
105 virtual ::com::sun::star::uno::Sequence
< OUString
> SAL_CALL
getElementNames( ) throw (::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
106 virtual sal_Bool SAL_CALL
hasByName( const OUString
& aName
) throw (::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
109 virtual void SAL_CALL
replaceByName( const OUString
& aName
, const ::com::sun::star::uno::Any
& aElement
) throw (::com::sun::star::lang::IllegalArgumentException
, ::com::sun::star::container::NoSuchElementException
, ::com::sun::star::lang::WrappedTargetException
, ::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
112 virtual void SAL_CALL
insertByName( const OUString
& aName
, const ::com::sun::star::uno::Any
& aElement
) throw (::com::sun::star::lang::IllegalArgumentException
, ::com::sun::star::container::ElementExistException
, ::com::sun::star::lang::WrappedTargetException
, ::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
113 virtual void SAL_CALL
removeByName( const OUString
& Name
) throw (::com::sun::star::container::NoSuchElementException
, ::com::sun::star::lang::WrappedTargetException
, ::com::sun::star::uno::RuntimeException
, std::exception
) SAL_OVERRIDE
;
115 // looks for conversion dictionaries with the specified extension
116 // in the directory and adds them to the container
117 void AddConvDics( const OUString
&rSearchDirPathURL
, const OUString
&rExtension
);
119 // calls Flush for the dictionaries that support XFlushable
120 void FlushDics() const;
122 sal_Int32
GetCount() const { return aConvDics
.getLength(); }
123 uno::Reference
< XConversionDictionary
> GetByName( const OUString
& rName
);
125 const uno::Reference
< XConversionDictionary
> GetByIndex( sal_Int32 nIdx
)
127 return aConvDics
.getConstArray()[nIdx
];
131 ConvDicNameContainer::ConvDicNameContainer()
135 ConvDicNameContainer::~ConvDicNameContainer()
139 void ConvDicNameContainer::FlushDics() const
141 sal_Int32 nLen
= aConvDics
.getLength();
142 const uno::Reference
< XConversionDictionary
> *pDic
= aConvDics
.getConstArray();
143 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
145 uno::Reference
< util::XFlushable
> xFlush( pDic
[i
] , UNO_QUERY
);
154 OSL_FAIL( "flushing of conversion dictionary failed" );
160 sal_Int32
ConvDicNameContainer::GetIndexByName_Impl(
161 const OUString
& rName
)
164 sal_Int32 nLen
= aConvDics
.getLength();
165 const uno::Reference
< XConversionDictionary
> *pDic
= aConvDics
.getConstArray();
166 for (sal_Int32 i
= 0; i
< nLen
&& nRes
== -1; ++i
)
168 if (rName
== pDic
[i
]->getName())
174 uno::Reference
< XConversionDictionary
> ConvDicNameContainer::GetByName(
175 const OUString
& rName
)
177 uno::Reference
< XConversionDictionary
> xRes
;
178 sal_Int32 nIdx
= GetIndexByName_Impl( rName
);
180 xRes
= aConvDics
.getArray()[nIdx
];
184 uno::Type SAL_CALL
ConvDicNameContainer::getElementType( )
185 throw (RuntimeException
, std::exception
)
187 MutexGuard
aGuard( GetLinguMutex() );
188 return uno::Type( cppu::UnoType
<XConversionDictionary
>::get());
191 sal_Bool SAL_CALL
ConvDicNameContainer::hasElements( )
192 throw (RuntimeException
, std::exception
)
194 MutexGuard
aGuard( GetLinguMutex() );
195 return aConvDics
.getLength() > 0;
198 uno::Any SAL_CALL
ConvDicNameContainer::getByName( const OUString
& rName
)
199 throw (NoSuchElementException
, WrappedTargetException
, RuntimeException
, std::exception
)
201 MutexGuard
aGuard( GetLinguMutex() );
202 uno::Reference
< XConversionDictionary
> xRes( GetByName( rName
) );
204 throw NoSuchElementException();
205 return makeAny( xRes
);
208 uno::Sequence
< OUString
> SAL_CALL
ConvDicNameContainer::getElementNames( )
209 throw (RuntimeException
, std::exception
)
211 MutexGuard
aGuard( GetLinguMutex() );
213 sal_Int32 nLen
= aConvDics
.getLength();
214 uno::Sequence
< OUString
> aRes( nLen
);
215 OUString
*pName
= aRes
.getArray();
216 const uno::Reference
< XConversionDictionary
> *pDic
= aConvDics
.getConstArray();
217 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
218 pName
[i
] = pDic
[i
]->getName();
222 sal_Bool SAL_CALL
ConvDicNameContainer::hasByName( const OUString
& rName
)
223 throw (RuntimeException
, std::exception
)
225 MutexGuard
aGuard( GetLinguMutex() );
226 return GetByName( rName
).is();
229 void SAL_CALL
ConvDicNameContainer::replaceByName(
230 const OUString
& rName
,
231 const uno::Any
& rElement
)
232 throw (IllegalArgumentException
, NoSuchElementException
, WrappedTargetException
, RuntimeException
, std::exception
)
234 MutexGuard
aGuard( GetLinguMutex() );
236 sal_Int32 nRplcIdx
= GetIndexByName_Impl( rName
);
238 throw NoSuchElementException();
239 uno::Reference
< XConversionDictionary
> xNew
;
241 if (!xNew
.is() || xNew
->getName() != rName
)
242 throw IllegalArgumentException();
243 aConvDics
.getArray()[ nRplcIdx
] = xNew
;
246 void SAL_CALL
ConvDicNameContainer::insertByName(
247 const OUString
& rName
,
248 const Any
& rElement
)
249 throw (IllegalArgumentException
, ElementExistException
, WrappedTargetException
, RuntimeException
, std::exception
)
251 MutexGuard
aGuard( GetLinguMutex() );
253 if (GetByName( rName
).is())
254 throw ElementExistException();
255 uno::Reference
< XConversionDictionary
> xNew
;
257 if (!xNew
.is() || xNew
->getName() != rName
)
258 throw IllegalArgumentException();
260 sal_Int32 nLen
= aConvDics
.getLength();
261 aConvDics
.realloc( nLen
+ 1 );
262 aConvDics
.getArray()[ nLen
] = xNew
;
265 void SAL_CALL
ConvDicNameContainer::removeByName( const OUString
& rName
)
266 throw (NoSuchElementException
, WrappedTargetException
, RuntimeException
, std::exception
)
268 MutexGuard
aGuard( GetLinguMutex() );
270 sal_Int32 nRplcIdx
= GetIndexByName_Impl( rName
);
272 throw NoSuchElementException();
274 // physically remove dictionary
275 uno::Reference
< XConversionDictionary
> xDel
= aConvDics
.getArray()[nRplcIdx
];
276 OUString
aName( xDel
->getName() );
277 OUString
aDicMainURL( GetConvDicMainURL( aName
, GetDictionaryWriteablePath() ) );
278 INetURLObject
aObj( aDicMainURL
);
279 DBG_ASSERT( aObj
.GetProtocol() == INetProtocol::File
, "+HangulHanjaOptionsDialog::OkHdl(): non-file URLs cannot be deleted" );
280 if( aObj
.GetProtocol() == INetProtocol::File
)
284 ::ucbhelper::Content
aCnt( aObj
.GetMainURL( INetURLObject::NO_DECODE
),
285 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
>(),
286 comphelper::getProcessComponentContext() );
287 aCnt
.executeCommand( "delete", makeAny( true ) );
289 catch( ::com::sun::star::ucb::CommandAbortedException
& )
291 SAL_WARN( "linguistic", "HangulHanjaOptionsDialog::OkHdl(): CommandAbortedException" );
295 SAL_WARN( "linguistic", "HangulHanjaOptionsDialog::OkHdl(): Any other exception" );
299 sal_Int32 nLen
= aConvDics
.getLength();
300 uno::Reference
< XConversionDictionary
> *pDic
= aConvDics
.getArray();
301 for (sal_Int32 i
= nRplcIdx
; i
< nLen
- 1; ++i
)
302 pDic
[i
] = pDic
[i
+ 1];
303 aConvDics
.realloc( nLen
- 1 );
306 void ConvDicNameContainer::AddConvDics(
307 const OUString
&rSearchDirPathURL
,
308 const OUString
&rExtension
)
310 const Sequence
< OUString
> aDirCnt(
311 utl::LocalFileHelper::GetFolderContents( rSearchDirPathURL
, false ) );
312 const OUString
*pDirCnt
= aDirCnt
.getConstArray();
313 sal_Int32 nEntries
= aDirCnt
.getLength();
315 for (sal_Int32 i
= 0; i
< nEntries
; ++i
)
317 OUString
aURL( pDirCnt
[i
] );
319 sal_Int32 nPos
= aURL
.lastIndexOf('.');
320 OUString
aExt( aURL
.copy(nPos
+ 1).toAsciiLowerCase() );
321 OUString
aSearchExt( rExtension
.toAsciiLowerCase() );
322 if(aExt
!= aSearchExt
)
323 continue; // skip other files
327 if (IsConvDic( aURL
, nLang
, nConvType
))
329 // get decoded dictionary file name
330 INetURLObject
aURLObj( aURL
);
331 OUString aDicName
= aURLObj
.getBase( INetURLObject::LAST_SEGMENT
,
332 true, INetURLObject::DECODE_WITH_CHARSET
,
333 RTL_TEXTENCODING_UTF8
);
335 uno::Reference
< XConversionDictionary
> xDic
;
336 if (nLang
== LANGUAGE_KOREAN
&&
337 nConvType
== ConversionDictionaryType::HANGUL_HANJA
)
339 xDic
= new HHConvDic( aDicName
, aURL
);
341 else if ((nLang
== LANGUAGE_CHINESE_SIMPLIFIED
|| nLang
== LANGUAGE_CHINESE_TRADITIONAL
) &&
342 nConvType
== ConversionDictionaryType::SCHINESE_TCHINESE
)
344 xDic
= new ConvDic( aDicName
, nLang
, nConvType
, false, aURL
);
351 insertByName( xDic
->getName(), aAny
);
359 struct StaticConvDicList
: public rtl::StaticWithInit
<
360 uno::Reference
<XInterface
>, StaticConvDicList
> {
361 uno::Reference
<XInterface
> operator () () {
362 return (cppu::OWeakObject
*) new ConvDicList
;
367 void ConvDicList::MyAppExitListener::AtExit()
369 rMyDicList
.FlushDics();
370 StaticConvDicList::get().clear();
373 ConvDicList::ConvDicList() :
374 aEvtListeners( GetLinguMutex() )
379 pExitListener
= new MyAppExitListener( *this );
380 xExitListener
= pExitListener
;
381 pExitListener
->Activate();
384 ConvDicList::~ConvDicList()
387 if (!bDisposing
&& pNameContainer
)
388 pNameContainer
->FlushDics();
390 pExitListener
->Deactivate();
393 void ConvDicList::FlushDics()
395 // check only pointer to avoid creating the container when
396 // the dictionaries were not accessed yet
398 pNameContainer
->FlushDics();
401 ConvDicNameContainer
& ConvDicList::GetNameContainer()
405 pNameContainer
= new ConvDicNameContainer
;
406 pNameContainer
->AddConvDics( GetDictionaryWriteablePath(), OUString(CONV_DIC_EXT
) );
407 xNameContainer
= pNameContainer
;
409 // access list of text conversion dictionaries to activate
410 SvtLinguOptions aOpt
;
411 SvtLinguConfig().GetOptions( aOpt
);
412 sal_Int32 nLen
= aOpt
.aActiveConvDics
.getLength();
413 const OUString
*pActiveConvDics
= aOpt
.aActiveConvDics
.getConstArray();
414 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
416 uno::Reference
< XConversionDictionary
> xDic
=
417 pNameContainer
->GetByName( pActiveConvDics
[i
] );
419 xDic
->setActive( sal_True
);
422 // since there is no UI to active/deactivate the dictionaries
423 // for chinese text conversion they should be activated by default
424 uno::Reference
< XConversionDictionary
> xS2TDic(
425 pNameContainer
->GetByName( "ChineseS2T" ), UNO_QUERY
);
426 uno::Reference
< XConversionDictionary
> xT2SDic(
427 pNameContainer
->GetByName( "ChineseT2S" ), UNO_QUERY
);
429 xS2TDic
->setActive( sal_True
);
431 xT2SDic
->setActive( sal_True
);
434 return *pNameContainer
;
437 uno::Reference
< container::XNameContainer
> SAL_CALL
ConvDicList::getDictionaryContainer( ) throw (RuntimeException
, std::exception
)
439 MutexGuard
aGuard( GetLinguMutex() );
441 DBG_ASSERT( xNameContainer
.is(), "missing name container" );
442 return xNameContainer
;
445 uno::Reference
< XConversionDictionary
> SAL_CALL
ConvDicList::addNewDictionary(
446 const OUString
& rName
,
447 const Locale
& rLocale
,
448 sal_Int16 nConvDicType
)
449 throw (NoSupportException
, ElementExistException
, RuntimeException
, std::exception
)
451 MutexGuard
aGuard( GetLinguMutex() );
453 sal_Int16 nLang
= LinguLocaleToLanguage( rLocale
);
455 if (GetNameContainer().hasByName( rName
))
456 throw ElementExistException();
458 uno::Reference
< XConversionDictionary
> xRes
;
459 OUString
aDicMainURL( GetConvDicMainURL( rName
, GetDictionaryWriteablePath() ) );
460 if (nLang
== LANGUAGE_KOREAN
&&
461 nConvDicType
== ConversionDictionaryType::HANGUL_HANJA
)
463 xRes
= new HHConvDic( rName
, aDicMainURL
);
465 else if ((nLang
== LANGUAGE_CHINESE_SIMPLIFIED
|| nLang
== LANGUAGE_CHINESE_TRADITIONAL
) &&
466 nConvDicType
== ConversionDictionaryType::SCHINESE_TCHINESE
)
468 xRes
= new ConvDic( rName
, nLang
, nConvDicType
, false, aDicMainURL
);
472 throw NoSupportException();
475 xRes
->setActive( sal_True
);
478 GetNameContainer().insertByName( rName
, aAny
);
483 uno::Sequence
< OUString
> SAL_CALL
ConvDicList::queryConversions(
484 const OUString
& rText
,
487 const Locale
& rLocale
,
488 sal_Int16 nConversionDictionaryType
,
489 ConversionDirection eDirection
,
490 sal_Int32 nTextConversionOptions
)
491 throw (IllegalArgumentException
, NoSupportException
, RuntimeException
, std::exception
)
493 MutexGuard
aGuard( GetLinguMutex() );
495 sal_Int32 nCount
= 0;
496 uno::Sequence
< OUString
> aRes( 20 );
497 OUString
*pRes
= aRes
.getArray();
499 bool bSupported
= false;
500 sal_Int32 nLen
= GetNameContainer().GetCount();
501 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
503 const uno::Reference
< XConversionDictionary
> xDic( GetNameContainer().GetByIndex(i
) );
504 bool bMatch
= xDic
.is() &&
505 xDic
->getLocale() == rLocale
&&
506 xDic
->getConversionType() == nConversionDictionaryType
;
507 bSupported
|= bMatch
;
508 if (bMatch
&& xDic
->isActive())
510 Sequence
< OUString
> aNewConv( xDic
->getConversions(
511 rText
, nStartPos
, nLength
,
512 eDirection
, nTextConversionOptions
) );
513 sal_Int32 nNewLen
= aNewConv
.getLength();
516 if (nCount
+ nNewLen
> aRes
.getLength())
518 aRes
.realloc( nCount
+ nNewLen
+ 20 );
519 pRes
= aRes
.getArray();
521 const OUString
*pNewConv
= aNewConv
.getConstArray();
522 for (sal_Int32 k
= 0; k
< nNewLen
; ++k
)
523 pRes
[nCount
++] = pNewConv
[k
];
529 throw NoSupportException();
531 aRes
.realloc( nCount
);
535 sal_Int16 SAL_CALL
ConvDicList::queryMaxCharCount(
536 const Locale
& rLocale
,
537 sal_Int16 nConversionDictionaryType
,
538 ConversionDirection eDirection
)
539 throw (RuntimeException
, std::exception
)
541 MutexGuard
aGuard( GetLinguMutex() );
545 sal_Int32 nLen
= GetNameContainer().GetCount();
546 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
548 const uno::Reference
< XConversionDictionary
> xDic( GetNameContainer().GetByIndex(i
) );
550 xDic
->getLocale() == rLocale
&&
551 xDic
->getConversionType() == nConversionDictionaryType
)
553 sal_Int16 nC
= xDic
->getMaxCharCount( eDirection
);
561 void SAL_CALL
ConvDicList::dispose( )
562 throw (RuntimeException
, std::exception
)
564 MutexGuard
aGuard( GetLinguMutex() );
568 EventObject
aEvtObj( (XConversionDictionaryList
*) this );
569 aEvtListeners
.disposeAndClear( aEvtObj
);
575 void SAL_CALL
ConvDicList::addEventListener(
576 const uno::Reference
< XEventListener
>& rxListener
)
577 throw (RuntimeException
, std::exception
)
579 MutexGuard
aGuard( GetLinguMutex() );
580 if (!bDisposing
&& rxListener
.is())
581 aEvtListeners
.addInterface( rxListener
);
584 void SAL_CALL
ConvDicList::removeEventListener(
585 const uno::Reference
< XEventListener
>& rxListener
)
586 throw (RuntimeException
, std::exception
)
588 MutexGuard
aGuard( GetLinguMutex() );
589 if (!bDisposing
&& rxListener
.is())
590 aEvtListeners
.removeInterface( rxListener
);
593 OUString SAL_CALL
ConvDicList::getImplementationName()
594 throw (RuntimeException
, std::exception
)
596 MutexGuard
aGuard( GetLinguMutex() );
597 return getImplementationName_Static();
600 sal_Bool SAL_CALL
ConvDicList::supportsService( const OUString
& rServiceName
)
601 throw (RuntimeException
, std::exception
)
603 return cppu::supportsService(this, rServiceName
);
606 uno::Sequence
< OUString
> SAL_CALL
ConvDicList::getSupportedServiceNames()
607 throw (RuntimeException
, std::exception
)
609 MutexGuard
aGuard( GetLinguMutex() );
610 return getSupportedServiceNames_Static();
613 uno::Sequence
< OUString
> ConvDicList::getSupportedServiceNames_Static()
616 uno::Sequence
< OUString
> aSNS( 1 );
617 aSNS
.getArray()[0] = SN_CONV_DICTIONARY_LIST
;
621 uno::Reference
< uno::XInterface
> SAL_CALL
ConvDicList_CreateInstance(
622 const uno::Reference
< XMultiServiceFactory
> & /*rSMgr*/ )
625 return StaticConvDicList::get();
628 void * SAL_CALL
ConvDicList_getFactory(
629 const sal_Char
* pImplName
,
630 XMultiServiceFactory
* pServiceManager
, void * )
633 if ( ConvDicList::getImplementationName_Static().equalsAscii( pImplName
) )
635 uno::Reference
< XSingleServiceFactory
> xFactory
=
636 cppu::createOneInstanceFactory(
638 ConvDicList::getImplementationName_Static(),
639 ConvDicList_CreateInstance
,
640 ConvDicList::getSupportedServiceNames_Static());
641 // acquire, because we return an interface pointer instead of a reference
643 pRet
= xFactory
.get();
648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */