Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / linguistic / source / convdiclist.cxx
blob79ea6f639fab3abdb6a99f8a03497a70097d1611
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 <com/sun/star/container/XNameContainer.hpp>
23 #include <com/sun/star/lang/Locale.hpp>
24 #include <com/sun/star/lang/NoSupportException.hpp>
25 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
26 #include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
27 #include <com/sun/star/linguistic2/XConversionDictionaryList.hpp>
28 #include <com/sun/star/uno/Reference.h>
29 #include <com/sun/star/util/XFlushable.hpp>
30 #include <cppuhelper/factory.hxx>
31 #include <cppuhelper/implbase.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/sequence.hxx>
34 #include <cppuhelper/supportsservice.hxx>
35 #include <rtl/instance.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 <tools/diagnose_ex.h>
43 #include "convdic.hxx"
44 #include "convdiclist.hxx"
45 #include "hhconvdic.hxx"
46 #include "lngreg.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 #define SN_CONV_DICTIONARY_LIST "com.sun.star.linguistic2.ConversionDictionaryList"
59 static OUString GetConvDicMainURL( const OUString &rDicName, const OUString &rDirectoryURL )
61 // build URL to use for new (persistent) dictionaries
63 OUString aFullDicName = rDicName + CONV_DIC_DOT_EXT;
65 INetURLObject aURLObj;
66 aURLObj.SetSmartProtocol( INetProtocol::File );
67 aURLObj.SetSmartURL( rDirectoryURL );
68 aURLObj.Append( aFullDicName, INetURLObject::EncodeMechanism::All );
69 DBG_ASSERT(!aURLObj.HasError(), "invalid URL");
70 if (aURLObj.HasError())
71 return OUString();
72 else
73 return aURLObj.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
76 class ConvDicNameContainer :
77 public cppu::WeakImplHelper< css::container::XNameContainer >
79 std::vector< uno::Reference< XConversionDictionary > > aConvDics;
81 sal_Int32 GetIndexByName_Impl( const OUString& rName );
83 public:
84 ConvDicNameContainer();
85 ConvDicNameContainer(const ConvDicNameContainer&) = delete;
86 ConvDicNameContainer& operator=(const ConvDicNameContainer&) = delete;
88 // XElementAccess
89 virtual css::uno::Type SAL_CALL getElementType( ) override;
90 virtual sal_Bool SAL_CALL hasElements( ) override;
92 // XNameAccess
93 virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
94 virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
95 virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
97 // XNameReplace
98 virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
100 // XNameContainer
101 virtual void SAL_CALL insertByName( const OUString& aName, const css::uno::Any& aElement ) override;
102 virtual void SAL_CALL removeByName( const OUString& Name ) override;
104 // looks for conversion dictionaries with the specified extension
105 // in the directory and adds them to the container
106 void AddConvDics( const OUString &rSearchDirPathURL, const OUString &rExtension );
108 // calls Flush for the dictionaries that support XFlushable
109 void FlushDics() const;
111 sal_Int32 GetCount() const { return aConvDics.size(); }
112 uno::Reference< XConversionDictionary > GetByName( const OUString& rName );
114 const uno::Reference< XConversionDictionary >& GetByIndex( sal_Int32 nIdx )
116 return aConvDics[nIdx];
120 ConvDicNameContainer::ConvDicNameContainer()
124 void ConvDicNameContainer::FlushDics() const
126 sal_Int32 nLen = aConvDics.size();
127 for (sal_Int32 i = 0; i < nLen; ++i)
129 uno::Reference< util::XFlushable > xFlush( aConvDics[i] , UNO_QUERY );
130 if (xFlush.is())
134 xFlush->flush();
136 catch(Exception &)
138 OSL_FAIL( "flushing of conversion dictionary failed" );
144 sal_Int32 ConvDicNameContainer::GetIndexByName_Impl(
145 const OUString& rName )
147 sal_Int32 nRes = -1;
148 sal_Int32 nLen = aConvDics.size();
149 for (sal_Int32 i = 0; i < nLen && nRes == -1; ++i)
151 if (rName == aConvDics[i]->getName())
152 nRes = i;
154 return nRes;
157 uno::Reference< XConversionDictionary > ConvDicNameContainer::GetByName(
158 const OUString& rName )
160 uno::Reference< XConversionDictionary > xRes;
161 sal_Int32 nIdx = GetIndexByName_Impl( rName );
162 if ( nIdx != -1)
163 xRes = aConvDics[nIdx];
164 return xRes;
167 uno::Type SAL_CALL ConvDicNameContainer::getElementType( )
169 MutexGuard aGuard( GetLinguMutex() );
170 return cppu::UnoType<XConversionDictionary>::get();
173 sal_Bool SAL_CALL ConvDicNameContainer::hasElements( )
175 MutexGuard aGuard( GetLinguMutex() );
176 return !aConvDics.empty();
179 uno::Any SAL_CALL ConvDicNameContainer::getByName( const OUString& rName )
181 MutexGuard aGuard( GetLinguMutex() );
182 uno::Reference< XConversionDictionary > xRes( GetByName( rName ) );
183 if (!xRes.is())
184 throw NoSuchElementException();
185 return makeAny( xRes );
188 uno::Sequence< OUString > SAL_CALL ConvDicNameContainer::getElementNames( )
190 MutexGuard aGuard( GetLinguMutex() );
192 std::vector<OUString> aRes;
193 aRes.reserve(aConvDics.size());
195 std::transform(aConvDics.begin(), aConvDics.end(), std::back_inserter(aRes),
196 [](const uno::Reference<XConversionDictionary>& rDic) { return rDic->getName(); });
198 return comphelper::containerToSequence(aRes);
201 sal_Bool SAL_CALL ConvDicNameContainer::hasByName( const OUString& rName )
203 MutexGuard aGuard( GetLinguMutex() );
204 return GetByName( rName ).is();
207 void SAL_CALL ConvDicNameContainer::replaceByName(
208 const OUString& rName,
209 const uno::Any& rElement )
211 MutexGuard aGuard( GetLinguMutex() );
213 sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
214 if (nRplcIdx == -1)
215 throw NoSuchElementException();
216 uno::Reference< XConversionDictionary > xNew;
217 rElement >>= xNew;
218 if (!xNew.is() || xNew->getName() != rName)
219 throw IllegalArgumentException();
220 aConvDics[ nRplcIdx ] = xNew;
223 void SAL_CALL ConvDicNameContainer::insertByName(
224 const OUString& rName,
225 const Any& rElement )
227 MutexGuard aGuard( GetLinguMutex() );
229 if (GetByName( rName ).is())
230 throw ElementExistException();
231 uno::Reference< XConversionDictionary > xNew;
232 rElement >>= xNew;
233 if (!xNew.is() || xNew->getName() != rName)
234 throw IllegalArgumentException();
236 aConvDics.push_back(xNew);
239 void SAL_CALL ConvDicNameContainer::removeByName( const OUString& rName )
241 MutexGuard aGuard( GetLinguMutex() );
243 sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
244 if (nRplcIdx == -1)
245 throw NoSuchElementException();
247 // physically remove dictionary
248 uno::Reference< XConversionDictionary > xDel = aConvDics[nRplcIdx];
249 OUString aName( xDel->getName() );
250 OUString aDicMainURL( GetConvDicMainURL( aName, GetDictionaryWriteablePath() ) );
251 INetURLObject aObj( aDicMainURL );
252 DBG_ASSERT( aObj.GetProtocol() == INetProtocol::File, "+HangulHanjaOptionsDialog::OkHdl(): non-file URLs cannot be deleted" );
253 if( aObj.GetProtocol() == INetProtocol::File )
257 ::ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
258 uno::Reference< css::ucb::XCommandEnvironment >(),
259 comphelper::getProcessComponentContext() );
260 aCnt.executeCommand( "delete", makeAny( true ) );
262 catch( ... )
264 TOOLS_WARN_EXCEPTION( "linguistic", "HangulHanjaOptionsDialog::OkHdl()" );
268 aConvDics.erase(aConvDics.begin() + nRplcIdx);
271 void ConvDicNameContainer::AddConvDics(
272 const OUString &rSearchDirPathURL,
273 const OUString &rExtension )
275 const Sequence< OUString > aDirCnt(
276 utl::LocalFileHelper::GetFolderContents( rSearchDirPathURL, false ) );
278 for (const OUString& aURL : aDirCnt)
280 sal_Int32 nPos = aURL.lastIndexOf('.');
281 OUString aExt( aURL.copy(nPos + 1).toAsciiLowerCase() );
282 OUString aSearchExt( rExtension.toAsciiLowerCase() );
283 if(aExt != aSearchExt)
284 continue; // skip other files
286 LanguageType nLang;
287 sal_Int16 nConvType;
288 if (IsConvDic( aURL, nLang, nConvType ))
290 // get decoded dictionary file name
291 INetURLObject aURLObj( aURL );
292 OUString aDicName = aURLObj.getBase( INetURLObject::LAST_SEGMENT,
293 true, INetURLObject::DecodeMechanism::WithCharset );
295 uno::Reference < XConversionDictionary > xDic;
296 if (nLang == LANGUAGE_KOREAN &&
297 nConvType == ConversionDictionaryType::HANGUL_HANJA)
299 xDic = new HHConvDic( aDicName, aURL );
301 else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
302 nConvType == ConversionDictionaryType::SCHINESE_TCHINESE)
304 xDic = new ConvDic( aDicName, nLang, nConvType, false, aURL );
307 if (xDic.is())
309 insertByName( xDic->getName(), Any(xDic) );
315 namespace
317 struct StaticConvDicList : public rtl::StaticWithInit<
318 uno::Reference<XInterface>, StaticConvDicList> {
319 uno::Reference<XInterface> operator () () {
320 return static_cast<cppu::OWeakObject *>(new ConvDicList);
325 void ConvDicList::MyAppExitListener::AtExit()
327 rMyDicList.FlushDics();
328 StaticConvDicList::get().clear();
331 ConvDicList::ConvDicList() :
332 aEvtListeners( GetLinguMutex() )
334 bDisposing = false;
336 mxExitListener = new MyAppExitListener( *this );
337 mxExitListener->Activate();
340 ConvDicList::~ConvDicList()
342 if (!bDisposing && mxNameContainer.is())
343 mxNameContainer->FlushDics();
345 mxExitListener->Deactivate();
348 void ConvDicList::FlushDics()
350 // check only pointer to avoid creating the container when
351 // the dictionaries were not accessed yet
352 if (mxNameContainer.is())
353 mxNameContainer->FlushDics();
356 ConvDicNameContainer & ConvDicList::GetNameContainer()
358 if (!mxNameContainer.is())
360 mxNameContainer = new ConvDicNameContainer;
361 mxNameContainer->AddConvDics( GetDictionaryWriteablePath(), CONV_DIC_EXT );
363 // access list of text conversion dictionaries to activate
364 SvtLinguOptions aOpt;
365 SvtLinguConfig().GetOptions( aOpt );
366 for (const OUString& rActiveConvDic : std::as_const(aOpt.aActiveConvDics))
368 uno::Reference< XConversionDictionary > xDic =
369 mxNameContainer->GetByName( rActiveConvDic );
370 if (xDic.is())
371 xDic->setActive( true );
374 // since there is no UI to active/deactivate the dictionaries
375 // for chinese text conversion they should be activated by default
376 uno::Reference< XConversionDictionary > xS2TDic =
377 mxNameContainer->GetByName( "ChineseS2T" );
378 uno::Reference< XConversionDictionary > xT2SDic =
379 mxNameContainer->GetByName( "ChineseT2S" );
380 if (xS2TDic.is())
381 xS2TDic->setActive( true );
382 if (xT2SDic.is())
383 xT2SDic->setActive( true );
386 return *mxNameContainer;
389 uno::Reference< container::XNameContainer > SAL_CALL ConvDicList::getDictionaryContainer( )
391 MutexGuard aGuard( GetLinguMutex() );
392 GetNameContainer();
393 DBG_ASSERT( mxNameContainer.is(), "missing name container" );
394 return mxNameContainer.get();
397 uno::Reference< XConversionDictionary > SAL_CALL ConvDicList::addNewDictionary(
398 const OUString& rName,
399 const Locale& rLocale,
400 sal_Int16 nConvDicType )
402 MutexGuard aGuard( GetLinguMutex() );
404 LanguageType nLang = LinguLocaleToLanguage( rLocale );
406 if (GetNameContainer().hasByName( rName ))
407 throw ElementExistException();
409 uno::Reference< XConversionDictionary > xRes;
410 OUString aDicMainURL( GetConvDicMainURL( rName, GetDictionaryWriteablePath() ) );
411 if (nLang == LANGUAGE_KOREAN &&
412 nConvDicType == ConversionDictionaryType::HANGUL_HANJA)
414 xRes = new HHConvDic( rName, aDicMainURL );
416 else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
417 nConvDicType == ConversionDictionaryType::SCHINESE_TCHINESE)
419 xRes = new ConvDic( rName, nLang, nConvDicType, false, aDicMainURL );
422 if (!xRes.is())
423 throw NoSupportException();
425 xRes->setActive( true );
426 GetNameContainer().insertByName( rName, Any(xRes) );
427 return xRes;
430 uno::Sequence< OUString > SAL_CALL ConvDicList::queryConversions(
431 const OUString& rText,
432 sal_Int32 nStartPos,
433 sal_Int32 nLength,
434 const Locale& rLocale,
435 sal_Int16 nConversionDictionaryType,
436 ConversionDirection eDirection,
437 sal_Int32 nTextConversionOptions )
439 MutexGuard aGuard( GetLinguMutex() );
441 std::vector< OUString > aRes;
443 bool bSupported = false;
444 sal_Int32 nLen = GetNameContainer().GetCount();
445 for (sal_Int32 i = 0; i < nLen; ++i)
447 const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
448 bool bMatch = xDic.is() &&
449 xDic->getLocale() == rLocale &&
450 xDic->getConversionType() == nConversionDictionaryType;
451 bSupported |= bMatch;
452 if (bMatch && xDic->isActive())
454 const Sequence< OUString > aNewConv( xDic->getConversions(
455 rText, nStartPos, nLength,
456 eDirection, nTextConversionOptions ) );
457 std::copy(aNewConv.begin(), aNewConv.end(), std::back_inserter(aRes));
461 if (!bSupported)
462 throw NoSupportException();
464 return comphelper::containerToSequence(aRes);
467 sal_Int16 SAL_CALL ConvDicList::queryMaxCharCount(
468 const Locale& rLocale,
469 sal_Int16 nConversionDictionaryType,
470 ConversionDirection eDirection )
472 MutexGuard aGuard( GetLinguMutex() );
474 sal_Int16 nRes = 0;
475 GetNameContainer();
476 sal_Int32 nLen = GetNameContainer().GetCount();
477 for (sal_Int32 i = 0; i < nLen; ++i)
479 const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
480 if (xDic.is() &&
481 xDic->getLocale() == rLocale &&
482 xDic->getConversionType() == nConversionDictionaryType)
484 sal_Int16 nC = xDic->getMaxCharCount( eDirection );
485 if (nC > nRes)
486 nRes = nC;
489 return nRes;
492 void SAL_CALL ConvDicList::dispose( )
494 MutexGuard aGuard( GetLinguMutex() );
495 if (!bDisposing)
497 bDisposing = true;
498 EventObject aEvtObj( static_cast<XConversionDictionaryList *>(this) );
499 aEvtListeners.disposeAndClear( aEvtObj );
501 FlushDics();
505 void SAL_CALL ConvDicList::addEventListener(
506 const uno::Reference< XEventListener >& rxListener )
508 MutexGuard aGuard( GetLinguMutex() );
509 if (!bDisposing && rxListener.is())
510 aEvtListeners.addInterface( rxListener );
513 void SAL_CALL ConvDicList::removeEventListener(
514 const uno::Reference< XEventListener >& rxListener )
516 MutexGuard aGuard( GetLinguMutex() );
517 if (!bDisposing && rxListener.is())
518 aEvtListeners.removeInterface( rxListener );
521 OUString SAL_CALL ConvDicList::getImplementationName()
523 return getImplementationName_Static();
526 sal_Bool SAL_CALL ConvDicList::supportsService( const OUString& rServiceName )
528 return cppu::supportsService(this, rServiceName);
531 uno::Sequence< OUString > SAL_CALL ConvDicList::getSupportedServiceNames()
533 return getSupportedServiceNames_Static();
536 uno::Sequence< OUString > ConvDicList::getSupportedServiceNames_Static()
537 throw()
539 uno::Sequence<OUString> aSNS { SN_CONV_DICTIONARY_LIST };
540 return aSNS;
543 /// @throws css::uno::Exception
544 static uno::Reference< uno::XInterface > ConvDicList_CreateInstance(
545 const uno::Reference< XMultiServiceFactory > & /*rSMgr*/ )
547 return StaticConvDicList::get();
550 void * ConvDicList_getFactory(
551 const sal_Char * pImplName,
552 XMultiServiceFactory * pServiceManager )
554 void * pRet = nullptr;
555 if ( ConvDicList::getImplementationName_Static().equalsAscii( pImplName ) )
557 uno::Reference< XSingleServiceFactory > xFactory =
558 cppu::createOneInstanceFactory(
559 pServiceManager,
560 ConvDicList::getImplementationName_Static(),
561 ConvDicList_CreateInstance,
562 ConvDicList::getSupportedServiceNames_Static());
563 // acquire, because we return an interface pointer instead of a reference
564 xFactory->acquire();
565 pRet = xFactory.get();
567 return pRet;
570 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */