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 <string_view>
24 #include <com/sun/star/container/XNameContainer.hpp>
25 #include <com/sun/star/lang/Locale.hpp>
26 #include <com/sun/star/lang/NoSupportException.hpp>
27 #include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
28 #include <com/sun/star/linguistic2/XConversionDictionaryList.hpp>
29 #include <com/sun/star/uno/Reference.h>
30 #include <com/sun/star/util/XFlushable.hpp>
31 #include <cppuhelper/factory.hxx>
32 #include <cppuhelper/implbase.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/sequence.hxx>
35 #include <cppuhelper/supportsservice.hxx>
36 #include <tools/debug.hxx>
37 #include <tools/urlobj.hxx>
38 #include <ucbhelper/content.hxx>
39 #include <unotools/localfilehelper.hxx>
40 #include <unotools/lingucfg.hxx>
41 #include <comphelper/diagnose_ex.hxx>
43 #include "convdic.hxx"
44 #include "convdiclist.hxx"
45 #include "hhconvdic.hxx"
46 #include <linguistic/misc.hxx>
49 using namespace com::sun::star
;
50 using namespace com::sun::star::lang
;
51 using namespace com::sun::star::uno
;
52 using namespace com::sun::star::container
;
53 using namespace com::sun::star::linguistic2
;
54 using namespace linguistic
;
56 static OUString
GetConvDicMainURL( std::u16string_view rDicName
, std::u16string_view rDirectoryURL
)
58 // build URL to use for new (persistent) dictionaries
60 OUString aFullDicName
= OUString::Concat(rDicName
) + CONV_DIC_DOT_EXT
;
62 INetURLObject aURLObj
;
63 aURLObj
.SetSmartProtocol( INetProtocol::File
);
64 aURLObj
.SetSmartURL( rDirectoryURL
);
65 aURLObj
.Append( aFullDicName
, INetURLObject::EncodeMechanism::All
);
66 DBG_ASSERT(!aURLObj
.HasError(), "invalid URL");
67 if (aURLObj
.HasError())
70 return aURLObj
.GetMainURL( INetURLObject::DecodeMechanism::ToIUri
);
73 class ConvDicNameContainer
:
74 public cppu::WeakImplHelper
< css::container::XNameContainer
>
76 std::vector
< uno::Reference
< XConversionDictionary
> > aConvDics
;
78 sal_Int32
GetIndexByName_Impl( std::u16string_view rName
);
81 ConvDicNameContainer();
82 ConvDicNameContainer(const ConvDicNameContainer
&) = delete;
83 ConvDicNameContainer
& operator=(const ConvDicNameContainer
&) = delete;
86 virtual css::uno::Type SAL_CALL
getElementType( ) override
;
87 virtual sal_Bool SAL_CALL
hasElements( ) override
;
90 virtual css::uno::Any SAL_CALL
getByName( const OUString
& aName
) override
;
91 virtual css::uno::Sequence
< OUString
> SAL_CALL
getElementNames( ) override
;
92 virtual sal_Bool SAL_CALL
hasByName( const OUString
& aName
) override
;
95 virtual void SAL_CALL
replaceByName( const OUString
& aName
, const css::uno::Any
& aElement
) override
;
98 virtual void SAL_CALL
insertByName( const OUString
& aName
, const css::uno::Any
& aElement
) override
;
99 virtual void SAL_CALL
removeByName( const OUString
& Name
) override
;
101 // looks for conversion dictionaries with the specified extension
102 // in the directory and adds them to the container
103 void AddConvDics( const OUString
&rSearchDirPathURL
, const OUString
&rExtension
);
105 // calls Flush for the dictionaries that support XFlushable
106 void FlushDics() const;
108 sal_Int32
GetCount() const { return aConvDics
.size(); }
109 uno::Reference
< XConversionDictionary
> GetByName( std::u16string_view rName
);
111 const uno::Reference
< XConversionDictionary
>& GetByIndex( sal_Int32 nIdx
)
113 return aConvDics
[nIdx
];
117 ConvDicNameContainer::ConvDicNameContainer()
121 void ConvDicNameContainer::FlushDics() const
123 sal_Int32 nLen
= aConvDics
.size();
124 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
126 uno::Reference
< util::XFlushable
> xFlush( aConvDics
[i
] , UNO_QUERY
);
135 OSL_FAIL( "flushing of conversion dictionary failed" );
141 sal_Int32
ConvDicNameContainer::GetIndexByName_Impl(
142 std::u16string_view rName
)
145 sal_Int32 nLen
= aConvDics
.size();
146 for (sal_Int32 i
= 0; i
< nLen
&& nRes
== -1; ++i
)
148 if (rName
== aConvDics
[i
]->getName())
154 uno::Reference
< XConversionDictionary
> ConvDicNameContainer::GetByName(
155 std::u16string_view rName
)
157 uno::Reference
< XConversionDictionary
> xRes
;
158 sal_Int32 nIdx
= GetIndexByName_Impl( rName
);
160 xRes
= aConvDics
[nIdx
];
164 uno::Type SAL_CALL
ConvDicNameContainer::getElementType( )
166 return cppu::UnoType
<XConversionDictionary
>::get();
169 sal_Bool SAL_CALL
ConvDicNameContainer::hasElements( )
171 MutexGuard
aGuard( GetLinguMutex() );
172 return !aConvDics
.empty();
175 uno::Any SAL_CALL
ConvDicNameContainer::getByName( const OUString
& rName
)
177 MutexGuard
aGuard( GetLinguMutex() );
178 uno::Reference
< XConversionDictionary
> xRes( GetByName( rName
) );
180 throw NoSuchElementException();
184 uno::Sequence
< OUString
> SAL_CALL
ConvDicNameContainer::getElementNames( )
186 MutexGuard
aGuard( GetLinguMutex() );
188 std::vector
<OUString
> aRes
;
189 aRes
.reserve(aConvDics
.size());
191 std::transform(aConvDics
.begin(), aConvDics
.end(), std::back_inserter(aRes
),
192 [](const uno::Reference
<XConversionDictionary
>& rDic
) { return rDic
->getName(); });
194 return comphelper::containerToSequence(aRes
);
197 sal_Bool SAL_CALL
ConvDicNameContainer::hasByName( const OUString
& rName
)
199 MutexGuard
aGuard( GetLinguMutex() );
200 return GetByName( rName
).is();
203 void SAL_CALL
ConvDicNameContainer::replaceByName(
204 const OUString
& rName
,
205 const uno::Any
& rElement
)
207 MutexGuard
aGuard( GetLinguMutex() );
209 sal_Int32 nRplcIdx
= GetIndexByName_Impl( rName
);
211 throw NoSuchElementException();
212 uno::Reference
< XConversionDictionary
> xNew
;
214 if (!xNew
.is() || xNew
->getName() != rName
)
215 throw IllegalArgumentException();
216 aConvDics
[ nRplcIdx
] = xNew
;
219 void SAL_CALL
ConvDicNameContainer::insertByName(
220 const OUString
& rName
,
221 const Any
& rElement
)
223 MutexGuard
aGuard( GetLinguMutex() );
225 if (GetByName( rName
).is())
226 throw ElementExistException();
227 uno::Reference
< XConversionDictionary
> xNew
;
229 if (!xNew
.is() || xNew
->getName() != rName
)
230 throw IllegalArgumentException();
232 aConvDics
.push_back(xNew
);
235 void SAL_CALL
ConvDicNameContainer::removeByName( const OUString
& rName
)
237 MutexGuard
aGuard( GetLinguMutex() );
239 sal_Int32 nRplcIdx
= GetIndexByName_Impl( rName
);
241 throw NoSuchElementException();
243 // physically remove dictionary
244 uno::Reference
< XConversionDictionary
> xDel
= aConvDics
[nRplcIdx
];
245 OUString
aName( xDel
->getName() );
246 OUString
aDicMainURL( GetConvDicMainURL( aName
, GetDictionaryWriteablePath() ) );
247 INetURLObject
aObj( aDicMainURL
);
248 DBG_ASSERT( aObj
.GetProtocol() == INetProtocol::File
, "+HangulHanjaOptionsDialog::OkHdl(): non-file URLs cannot be deleted" );
249 if( aObj
.GetProtocol() == INetProtocol::File
)
253 ::ucbhelper::Content
aCnt( aObj
.GetMainURL( INetURLObject::DecodeMechanism::NONE
),
254 uno::Reference
< css::ucb::XCommandEnvironment
>(),
255 comphelper::getProcessComponentContext() );
256 aCnt
.executeCommand( "delete", Any( true ) );
260 TOOLS_WARN_EXCEPTION( "linguistic", "HangulHanjaOptionsDialog::OkHdl()" );
264 aConvDics
.erase(aConvDics
.begin() + nRplcIdx
);
267 void ConvDicNameContainer::AddConvDics(
268 const OUString
&rSearchDirPathURL
,
269 const OUString
&rExtension
)
271 const Sequence
< OUString
> aDirCnt(
272 utl::LocalFileHelper::GetFolderContents( rSearchDirPathURL
, false ) );
274 for (const OUString
& aURL
: aDirCnt
)
276 sal_Int32 nPos
= aURL
.lastIndexOf('.');
277 OUString
aExt( aURL
.copy(nPos
+ 1).toAsciiLowerCase() );
278 OUString
aSearchExt( rExtension
.toAsciiLowerCase() );
279 if(aExt
!= aSearchExt
)
280 continue; // skip other files
284 if (IsConvDic( aURL
, nLang
, nConvType
))
286 // get decoded dictionary file name
287 INetURLObject
aURLObj( aURL
);
288 OUString aDicName
= aURLObj
.getBase( INetURLObject::LAST_SEGMENT
,
289 true, INetURLObject::DecodeMechanism::WithCharset
);
291 uno::Reference
< XConversionDictionary
> xDic
;
292 if (nLang
== LANGUAGE_KOREAN
&&
293 nConvType
== ConversionDictionaryType::HANGUL_HANJA
)
295 xDic
= new HHConvDic( aDicName
, aURL
);
297 else if ((nLang
== LANGUAGE_CHINESE_SIMPLIFIED
|| nLang
== LANGUAGE_CHINESE_TRADITIONAL
) &&
298 nConvType
== ConversionDictionaryType::SCHINESE_TCHINESE
)
300 xDic
= new ConvDic( aDicName
, nLang
, nConvType
, false, aURL
);
305 insertByName( xDic
->getName(), Any(xDic
) );
313 rtl::Reference
<ConvDicList
>& StaticConvDicList()
315 static rtl::Reference
<ConvDicList
> SINGLETON
= new ConvDicList
;
320 void ConvDicList::MyAppExitListener::AtExit()
322 rMyDicList
.FlushDics();
323 StaticConvDicList().clear();
326 ConvDicList::ConvDicList() :
327 aEvtListeners( GetLinguMutex() )
331 mxExitListener
= new MyAppExitListener( *this );
332 mxExitListener
->Activate();
335 ConvDicList::~ConvDicList()
337 if (!bDisposing
&& mxNameContainer
.is())
338 mxNameContainer
->FlushDics();
340 mxExitListener
->Deactivate();
343 void ConvDicList::FlushDics()
345 // check only pointer to avoid creating the container when
346 // the dictionaries were not accessed yet
347 if (mxNameContainer
.is())
348 mxNameContainer
->FlushDics();
351 ConvDicNameContainer
& ConvDicList::GetNameContainer()
353 if (!mxNameContainer
.is())
355 mxNameContainer
= new ConvDicNameContainer
;
356 mxNameContainer
->AddConvDics( GetDictionaryWriteablePath(), CONV_DIC_EXT
);
358 // access list of text conversion dictionaries to activate
359 SvtLinguOptions aOpt
;
360 SvtLinguConfig().GetOptions( aOpt
);
361 for (const OUString
& rActiveConvDic
: std::as_const(aOpt
.aActiveConvDics
))
363 uno::Reference
< XConversionDictionary
> xDic
=
364 mxNameContainer
->GetByName( rActiveConvDic
);
366 xDic
->setActive( true );
369 // since there is no UI to active/deactivate the dictionaries
370 // for chinese text conversion they should be activated by default
371 uno::Reference
< XConversionDictionary
> xS2TDic
=
372 mxNameContainer
->GetByName( u
"ChineseS2T" );
373 uno::Reference
< XConversionDictionary
> xT2SDic
=
374 mxNameContainer
->GetByName( u
"ChineseT2S" );
376 xS2TDic
->setActive( true );
378 xT2SDic
->setActive( true );
381 return *mxNameContainer
;
384 uno::Reference
< container::XNameContainer
> SAL_CALL
ConvDicList::getDictionaryContainer( )
386 MutexGuard
aGuard( GetLinguMutex() );
388 DBG_ASSERT( mxNameContainer
.is(), "missing name container" );
389 return mxNameContainer
;
392 uno::Reference
< XConversionDictionary
> SAL_CALL
ConvDicList::addNewDictionary(
393 const OUString
& rName
,
394 const Locale
& rLocale
,
395 sal_Int16 nConvDicType
)
397 MutexGuard
aGuard( GetLinguMutex() );
399 LanguageType nLang
= LinguLocaleToLanguage( rLocale
);
401 if (GetNameContainer().hasByName( rName
))
402 throw ElementExistException();
404 uno::Reference
< XConversionDictionary
> xRes
;
405 OUString
aDicMainURL( GetConvDicMainURL( rName
, GetDictionaryWriteablePath() ) );
406 if (nLang
== LANGUAGE_KOREAN
&&
407 nConvDicType
== ConversionDictionaryType::HANGUL_HANJA
)
409 xRes
= new HHConvDic( rName
, aDicMainURL
);
411 else if ((nLang
== LANGUAGE_CHINESE_SIMPLIFIED
|| nLang
== LANGUAGE_CHINESE_TRADITIONAL
) &&
412 nConvDicType
== ConversionDictionaryType::SCHINESE_TCHINESE
)
414 xRes
= new ConvDic( rName
, nLang
, nConvDicType
, false, aDicMainURL
);
418 throw NoSupportException();
420 xRes
->setActive( true );
421 GetNameContainer().insertByName( rName
, Any(xRes
) );
425 uno::Sequence
< OUString
> SAL_CALL
ConvDicList::queryConversions(
426 const OUString
& rText
,
429 const Locale
& rLocale
,
430 sal_Int16 nConversionDictionaryType
,
431 ConversionDirection eDirection
,
432 sal_Int32 nTextConversionOptions
)
434 MutexGuard
aGuard( GetLinguMutex() );
436 std::vector
< OUString
> aRes
;
438 bool bSupported
= false;
439 sal_Int32 nLen
= GetNameContainer().GetCount();
440 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
442 const uno::Reference
< XConversionDictionary
> xDic( GetNameContainer().GetByIndex(i
) );
443 bool bMatch
= xDic
.is() &&
444 xDic
->getLocale() == rLocale
&&
445 xDic
->getConversionType() == nConversionDictionaryType
;
446 bSupported
|= bMatch
;
447 if (bMatch
&& xDic
->isActive())
449 const Sequence
< OUString
> aNewConv( xDic
->getConversions(
450 rText
, nStartPos
, nLength
,
451 eDirection
, nTextConversionOptions
) );
452 aRes
.insert( aRes
.end(), aNewConv
.begin(), aNewConv
.end() );
457 throw NoSupportException();
459 return comphelper::containerToSequence(aRes
);
462 sal_Int16 SAL_CALL
ConvDicList::queryMaxCharCount(
463 const Locale
& rLocale
,
464 sal_Int16 nConversionDictionaryType
,
465 ConversionDirection eDirection
)
467 MutexGuard
aGuard( GetLinguMutex() );
471 sal_Int32 nLen
= GetNameContainer().GetCount();
472 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
474 const uno::Reference
< XConversionDictionary
> xDic( GetNameContainer().GetByIndex(i
) );
476 xDic
->getLocale() == rLocale
&&
477 xDic
->getConversionType() == nConversionDictionaryType
)
479 sal_Int16 nC
= xDic
->getMaxCharCount( eDirection
);
487 void SAL_CALL
ConvDicList::dispose( )
489 MutexGuard
aGuard( GetLinguMutex() );
493 EventObject
aEvtObj( static_cast<XConversionDictionaryList
*>(this) );
494 aEvtListeners
.disposeAndClear( aEvtObj
);
500 void SAL_CALL
ConvDicList::addEventListener(
501 const uno::Reference
< XEventListener
>& rxListener
)
503 MutexGuard
aGuard( GetLinguMutex() );
504 if (!bDisposing
&& rxListener
.is())
505 aEvtListeners
.addInterface( rxListener
);
508 void SAL_CALL
ConvDicList::removeEventListener(
509 const uno::Reference
< XEventListener
>& rxListener
)
511 MutexGuard
aGuard( GetLinguMutex() );
512 if (!bDisposing
&& rxListener
.is())
513 aEvtListeners
.removeInterface( rxListener
);
516 OUString SAL_CALL
ConvDicList::getImplementationName()
518 return "com.sun.star.lingu2.ConvDicList";
521 sal_Bool SAL_CALL
ConvDicList::supportsService( const OUString
& rServiceName
)
523 return cppu::supportsService(this, rServiceName
);
526 uno::Sequence
< OUString
> SAL_CALL
ConvDicList::getSupportedServiceNames()
528 return { "com.sun.star.linguistic2.ConversionDictionaryList" };
531 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
532 linguistic_ConvDicList_get_implementation(
533 css::uno::XComponentContext
* , css::uno::Sequence
<css::uno::Any
> const&)
535 return cppu::acquire(StaticConvDicList().get());
539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */