bump product version to 7.2.5.1
[LibreOffice.git] / linguistic / source / convdiclist.cxx
blob43d75141bc011c6630b6ad7e0cfcc8e1ab90a5b1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <rtl/instance.hxx>
37 #include <tools/debug.hxx>
38 #include <tools/urlobj.hxx>
39 #include <ucbhelper/content.hxx>
40 #include <unotools/localfilehelper.hxx>
41 #include <unotools/lingucfg.hxx>
42 #include <tools/diagnose_ex.h>
44 #include "convdic.hxx"
45 #include "convdiclist.hxx"
46 #include "hhconvdic.hxx"
47 #include <linguistic/misc.hxx>
49 using namespace osl;
50 using namespace com::sun::star;
51 using namespace com::sun::star::lang;
52 using namespace com::sun::star::uno;
53 using namespace com::sun::star::container;
54 using namespace com::sun::star::linguistic2;
55 using namespace linguistic;
57 static OUString GetConvDicMainURL( std::u16string_view rDicName, const OUString &rDirectoryURL )
59 // build URL to use for new (persistent) dictionaries
61 OUString aFullDicName = OUString::Concat(rDicName) + CONV_DIC_DOT_EXT;
63 INetURLObject aURLObj;
64 aURLObj.SetSmartProtocol( INetProtocol::File );
65 aURLObj.SetSmartURL( rDirectoryURL );
66 aURLObj.Append( aFullDicName, INetURLObject::EncodeMechanism::All );
67 DBG_ASSERT(!aURLObj.HasError(), "invalid URL");
68 if (aURLObj.HasError())
69 return OUString();
70 else
71 return aURLObj.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
74 class ConvDicNameContainer :
75 public cppu::WeakImplHelper< css::container::XNameContainer >
77 std::vector< uno::Reference< XConversionDictionary > > aConvDics;
79 sal_Int32 GetIndexByName_Impl( std::u16string_view rName );
81 public:
82 ConvDicNameContainer();
83 ConvDicNameContainer(const ConvDicNameContainer&) = delete;
84 ConvDicNameContainer& operator=(const ConvDicNameContainer&) = delete;
86 // XElementAccess
87 virtual css::uno::Type SAL_CALL getElementType( ) override;
88 virtual sal_Bool SAL_CALL hasElements( ) override;
90 // XNameAccess
91 virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
92 virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
93 virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
95 // XNameReplace
96 virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
98 // XNameContainer
99 virtual void SAL_CALL insertByName( const OUString& aName, const css::uno::Any& aElement ) override;
100 virtual void SAL_CALL removeByName( const OUString& Name ) override;
102 // looks for conversion dictionaries with the specified extension
103 // in the directory and adds them to the container
104 void AddConvDics( const OUString &rSearchDirPathURL, const OUString &rExtension );
106 // calls Flush for the dictionaries that support XFlushable
107 void FlushDics() const;
109 sal_Int32 GetCount() const { return aConvDics.size(); }
110 uno::Reference< XConversionDictionary > GetByName( std::u16string_view rName );
112 const uno::Reference< XConversionDictionary >& GetByIndex( sal_Int32 nIdx )
114 return aConvDics[nIdx];
118 ConvDicNameContainer::ConvDicNameContainer()
122 void ConvDicNameContainer::FlushDics() const
124 sal_Int32 nLen = aConvDics.size();
125 for (sal_Int32 i = 0; i < nLen; ++i)
127 uno::Reference< util::XFlushable > xFlush( aConvDics[i] , UNO_QUERY );
128 if (xFlush.is())
132 xFlush->flush();
134 catch(Exception &)
136 OSL_FAIL( "flushing of conversion dictionary failed" );
142 sal_Int32 ConvDicNameContainer::GetIndexByName_Impl(
143 std::u16string_view rName )
145 sal_Int32 nRes = -1;
146 sal_Int32 nLen = aConvDics.size();
147 for (sal_Int32 i = 0; i < nLen && nRes == -1; ++i)
149 if (rName == aConvDics[i]->getName())
150 nRes = i;
152 return nRes;
155 uno::Reference< XConversionDictionary > ConvDicNameContainer::GetByName(
156 std::u16string_view rName )
158 uno::Reference< XConversionDictionary > xRes;
159 sal_Int32 nIdx = GetIndexByName_Impl( rName );
160 if ( nIdx != -1)
161 xRes = aConvDics[nIdx];
162 return xRes;
165 uno::Type SAL_CALL ConvDicNameContainer::getElementType( )
167 MutexGuard aGuard( GetLinguMutex() );
168 return cppu::UnoType<XConversionDictionary>::get();
171 sal_Bool SAL_CALL ConvDicNameContainer::hasElements( )
173 MutexGuard aGuard( GetLinguMutex() );
174 return !aConvDics.empty();
177 uno::Any SAL_CALL ConvDicNameContainer::getByName( const OUString& rName )
179 MutexGuard aGuard( GetLinguMutex() );
180 uno::Reference< XConversionDictionary > xRes( GetByName( rName ) );
181 if (!xRes.is())
182 throw NoSuchElementException();
183 return makeAny( xRes );
186 uno::Sequence< OUString > SAL_CALL ConvDicNameContainer::getElementNames( )
188 MutexGuard aGuard( GetLinguMutex() );
190 std::vector<OUString> aRes;
191 aRes.reserve(aConvDics.size());
193 std::transform(aConvDics.begin(), aConvDics.end(), std::back_inserter(aRes),
194 [](const uno::Reference<XConversionDictionary>& rDic) { return rDic->getName(); });
196 return comphelper::containerToSequence(aRes);
199 sal_Bool SAL_CALL ConvDicNameContainer::hasByName( const OUString& rName )
201 MutexGuard aGuard( GetLinguMutex() );
202 return GetByName( rName ).is();
205 void SAL_CALL ConvDicNameContainer::replaceByName(
206 const OUString& rName,
207 const uno::Any& rElement )
209 MutexGuard aGuard( GetLinguMutex() );
211 sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
212 if (nRplcIdx == -1)
213 throw NoSuchElementException();
214 uno::Reference< XConversionDictionary > xNew;
215 rElement >>= xNew;
216 if (!xNew.is() || xNew->getName() != rName)
217 throw IllegalArgumentException();
218 aConvDics[ nRplcIdx ] = xNew;
221 void SAL_CALL ConvDicNameContainer::insertByName(
222 const OUString& rName,
223 const Any& rElement )
225 MutexGuard aGuard( GetLinguMutex() );
227 if (GetByName( rName ).is())
228 throw ElementExistException();
229 uno::Reference< XConversionDictionary > xNew;
230 rElement >>= xNew;
231 if (!xNew.is() || xNew->getName() != rName)
232 throw IllegalArgumentException();
234 aConvDics.push_back(xNew);
237 void SAL_CALL ConvDicNameContainer::removeByName( const OUString& rName )
239 MutexGuard aGuard( GetLinguMutex() );
241 sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
242 if (nRplcIdx == -1)
243 throw NoSuchElementException();
245 // physically remove dictionary
246 uno::Reference< XConversionDictionary > xDel = aConvDics[nRplcIdx];
247 OUString aName( xDel->getName() );
248 OUString aDicMainURL( GetConvDicMainURL( aName, GetDictionaryWriteablePath() ) );
249 INetURLObject aObj( aDicMainURL );
250 DBG_ASSERT( aObj.GetProtocol() == INetProtocol::File, "+HangulHanjaOptionsDialog::OkHdl(): non-file URLs cannot be deleted" );
251 if( aObj.GetProtocol() == INetProtocol::File )
255 ::ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
256 uno::Reference< css::ucb::XCommandEnvironment >(),
257 comphelper::getProcessComponentContext() );
258 aCnt.executeCommand( "delete", makeAny( true ) );
260 catch( ... )
262 TOOLS_WARN_EXCEPTION( "linguistic", "HangulHanjaOptionsDialog::OkHdl()" );
266 aConvDics.erase(aConvDics.begin() + nRplcIdx);
269 void ConvDicNameContainer::AddConvDics(
270 const OUString &rSearchDirPathURL,
271 const OUString &rExtension )
273 const Sequence< OUString > aDirCnt(
274 utl::LocalFileHelper::GetFolderContents( rSearchDirPathURL, false ) );
276 for (const OUString& aURL : aDirCnt)
278 sal_Int32 nPos = aURL.lastIndexOf('.');
279 OUString aExt( aURL.copy(nPos + 1).toAsciiLowerCase() );
280 OUString aSearchExt( rExtension.toAsciiLowerCase() );
281 if(aExt != aSearchExt)
282 continue; // skip other files
284 LanguageType nLang;
285 sal_Int16 nConvType;
286 if (IsConvDic( aURL, nLang, nConvType ))
288 // get decoded dictionary file name
289 INetURLObject aURLObj( aURL );
290 OUString aDicName = aURLObj.getBase( INetURLObject::LAST_SEGMENT,
291 true, INetURLObject::DecodeMechanism::WithCharset );
293 uno::Reference < XConversionDictionary > xDic;
294 if (nLang == LANGUAGE_KOREAN &&
295 nConvType == ConversionDictionaryType::HANGUL_HANJA)
297 xDic = new HHConvDic( aDicName, aURL );
299 else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
300 nConvType == ConversionDictionaryType::SCHINESE_TCHINESE)
302 xDic = new ConvDic( aDicName, nLang, nConvType, false, aURL );
305 if (xDic.is())
307 insertByName( xDic->getName(), Any(xDic) );
313 namespace
315 struct StaticConvDicList : public rtl::StaticWithInit<
316 rtl::Reference<ConvDicList>, StaticConvDicList> {
317 rtl::Reference<ConvDicList> operator () () {
318 return new ConvDicList;
323 void ConvDicList::MyAppExitListener::AtExit()
325 rMyDicList.FlushDics();
326 StaticConvDicList::get().clear();
329 ConvDicList::ConvDicList() :
330 aEvtListeners( GetLinguMutex() )
332 bDisposing = false;
334 mxExitListener = new MyAppExitListener( *this );
335 mxExitListener->Activate();
338 ConvDicList::~ConvDicList()
340 if (!bDisposing && mxNameContainer.is())
341 mxNameContainer->FlushDics();
343 mxExitListener->Deactivate();
346 void ConvDicList::FlushDics()
348 // check only pointer to avoid creating the container when
349 // the dictionaries were not accessed yet
350 if (mxNameContainer.is())
351 mxNameContainer->FlushDics();
354 ConvDicNameContainer & ConvDicList::GetNameContainer()
356 if (!mxNameContainer.is())
358 mxNameContainer = new ConvDicNameContainer;
359 mxNameContainer->AddConvDics( GetDictionaryWriteablePath(), CONV_DIC_EXT );
361 // access list of text conversion dictionaries to activate
362 SvtLinguOptions aOpt;
363 SvtLinguConfig().GetOptions( aOpt );
364 for (const OUString& rActiveConvDic : std::as_const(aOpt.aActiveConvDics))
366 uno::Reference< XConversionDictionary > xDic =
367 mxNameContainer->GetByName( rActiveConvDic );
368 if (xDic.is())
369 xDic->setActive( true );
372 // since there is no UI to active/deactivate the dictionaries
373 // for chinese text conversion they should be activated by default
374 uno::Reference< XConversionDictionary > xS2TDic =
375 mxNameContainer->GetByName( u"ChineseS2T" );
376 uno::Reference< XConversionDictionary > xT2SDic =
377 mxNameContainer->GetByName( u"ChineseT2S" );
378 if (xS2TDic.is())
379 xS2TDic->setActive( true );
380 if (xT2SDic.is())
381 xT2SDic->setActive( true );
384 return *mxNameContainer;
387 uno::Reference< container::XNameContainer > SAL_CALL ConvDicList::getDictionaryContainer( )
389 MutexGuard aGuard( GetLinguMutex() );
390 GetNameContainer();
391 DBG_ASSERT( mxNameContainer.is(), "missing name container" );
392 return mxNameContainer;
395 uno::Reference< XConversionDictionary > SAL_CALL ConvDicList::addNewDictionary(
396 const OUString& rName,
397 const Locale& rLocale,
398 sal_Int16 nConvDicType )
400 MutexGuard aGuard( GetLinguMutex() );
402 LanguageType nLang = LinguLocaleToLanguage( rLocale );
404 if (GetNameContainer().hasByName( rName ))
405 throw ElementExistException();
407 uno::Reference< XConversionDictionary > xRes;
408 OUString aDicMainURL( GetConvDicMainURL( rName, GetDictionaryWriteablePath() ) );
409 if (nLang == LANGUAGE_KOREAN &&
410 nConvDicType == ConversionDictionaryType::HANGUL_HANJA)
412 xRes = new HHConvDic( rName, aDicMainURL );
414 else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
415 nConvDicType == ConversionDictionaryType::SCHINESE_TCHINESE)
417 xRes = new ConvDic( rName, nLang, nConvDicType, false, aDicMainURL );
420 if (!xRes.is())
421 throw NoSupportException();
423 xRes->setActive( true );
424 GetNameContainer().insertByName( rName, Any(xRes) );
425 return xRes;
428 uno::Sequence< OUString > SAL_CALL ConvDicList::queryConversions(
429 const OUString& rText,
430 sal_Int32 nStartPos,
431 sal_Int32 nLength,
432 const Locale& rLocale,
433 sal_Int16 nConversionDictionaryType,
434 ConversionDirection eDirection,
435 sal_Int32 nTextConversionOptions )
437 MutexGuard aGuard( GetLinguMutex() );
439 std::vector< OUString > aRes;
441 bool bSupported = false;
442 sal_Int32 nLen = GetNameContainer().GetCount();
443 for (sal_Int32 i = 0; i < nLen; ++i)
445 const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
446 bool bMatch = xDic.is() &&
447 xDic->getLocale() == rLocale &&
448 xDic->getConversionType() == nConversionDictionaryType;
449 bSupported |= bMatch;
450 if (bMatch && xDic->isActive())
452 const Sequence< OUString > aNewConv( xDic->getConversions(
453 rText, nStartPos, nLength,
454 eDirection, nTextConversionOptions ) );
455 aRes.insert( aRes.end(), aNewConv.begin(), aNewConv.end() );
459 if (!bSupported)
460 throw NoSupportException();
462 return comphelper::containerToSequence(aRes);
465 sal_Int16 SAL_CALL ConvDicList::queryMaxCharCount(
466 const Locale& rLocale,
467 sal_Int16 nConversionDictionaryType,
468 ConversionDirection eDirection )
470 MutexGuard aGuard( GetLinguMutex() );
472 sal_Int16 nRes = 0;
473 GetNameContainer();
474 sal_Int32 nLen = GetNameContainer().GetCount();
475 for (sal_Int32 i = 0; i < nLen; ++i)
477 const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
478 if (xDic.is() &&
479 xDic->getLocale() == rLocale &&
480 xDic->getConversionType() == nConversionDictionaryType)
482 sal_Int16 nC = xDic->getMaxCharCount( eDirection );
483 if (nC > nRes)
484 nRes = nC;
487 return nRes;
490 void SAL_CALL ConvDicList::dispose( )
492 MutexGuard aGuard( GetLinguMutex() );
493 if (!bDisposing)
495 bDisposing = true;
496 EventObject aEvtObj( static_cast<XConversionDictionaryList *>(this) );
497 aEvtListeners.disposeAndClear( aEvtObj );
499 FlushDics();
503 void SAL_CALL ConvDicList::addEventListener(
504 const uno::Reference< XEventListener >& rxListener )
506 MutexGuard aGuard( GetLinguMutex() );
507 if (!bDisposing && rxListener.is())
508 aEvtListeners.addInterface( rxListener );
511 void SAL_CALL ConvDicList::removeEventListener(
512 const uno::Reference< XEventListener >& rxListener )
514 MutexGuard aGuard( GetLinguMutex() );
515 if (!bDisposing && rxListener.is())
516 aEvtListeners.removeInterface( rxListener );
519 OUString SAL_CALL ConvDicList::getImplementationName()
521 return "com.sun.star.lingu2.ConvDicList";
524 sal_Bool SAL_CALL ConvDicList::supportsService( const OUString& rServiceName )
526 return cppu::supportsService(this, rServiceName);
529 uno::Sequence< OUString > SAL_CALL ConvDicList::getSupportedServiceNames()
531 return { "com.sun.star.linguistic2.ConversionDictionaryList" };
534 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
535 linguistic_ConvDicList_get_implementation(
536 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
538 return cppu::acquire(StaticConvDicList::get().get());
542 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */