Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / linguistic / source / convdiclist.cxx
blob26c9fca36f929de76b7face6bdc3ef9e4c8abc71
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/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 <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/stream.hxx>
38 #include <tools/urlobj.hxx>
39 #include <ucbhelper/content.hxx>
40 #include <unotools/localfilehelper.hxx>
41 #include <unotools/lingucfg.hxx>
42 #include <unotools/pathoptions.hxx>
43 #include <unotools/useroptions.hxx>
45 #include "convdic.hxx"
46 #include "convdiclist.hxx"
47 #include "defs.hxx"
48 #include "hhconvdic.hxx"
49 #include "lngreg.hxx"
50 #include <linguistic/misc.hxx>
52 using namespace osl;
53 using namespace com::sun::star;
54 using namespace com::sun::star::lang;
55 using namespace com::sun::star::uno;
56 using namespace com::sun::star::container;
57 using namespace com::sun::star::linguistic2;
58 using namespace linguistic;
60 #define SN_CONV_DICTIONARY_LIST "com.sun.star.linguistic2.ConversionDictionaryList"
62 OUString GetConvDicMainURL( const OUString &rDicName, const OUString &rDirectoryURL )
64 // build URL to use for new (persistent) dictionaries
66 OUString aFullDicName = rDicName + CONV_DIC_DOT_EXT;
68 INetURLObject aURLObj;
69 aURLObj.SetSmartProtocol( INetProtocol::File );
70 aURLObj.SetSmartURL( rDirectoryURL );
71 aURLObj.Append( aFullDicName, INetURLObject::EncodeMechanism::All );
72 DBG_ASSERT(!aURLObj.HasError(), "invalid URL");
73 if (aURLObj.HasError())
74 return OUString();
75 else
76 return aURLObj.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
79 class ConvDicNameContainer :
80 public cppu::WeakImplHelper< css::container::XNameContainer >
82 std::vector< uno::Reference< XConversionDictionary > > aConvDics;
84 sal_Int32 GetIndexByName_Impl( const OUString& rName );
86 public:
87 ConvDicNameContainer();
88 ConvDicNameContainer(const ConvDicNameContainer&) = delete;
89 ConvDicNameContainer& operator=(const ConvDicNameContainer&) = delete;
91 // XElementAccess
92 virtual css::uno::Type SAL_CALL getElementType( ) override;
93 virtual sal_Bool SAL_CALL hasElements( ) override;
95 // XNameAccess
96 virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
97 virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
98 virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
100 // XNameReplace
101 virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
103 // XNameContainer
104 virtual void SAL_CALL insertByName( const OUString& aName, const css::uno::Any& aElement ) override;
105 virtual void SAL_CALL removeByName( const OUString& Name ) override;
107 // looks for conversion dictionaries with the specified extension
108 // in the directory and adds them to the container
109 void AddConvDics( const OUString &rSearchDirPathURL, const OUString &rExtension );
111 // calls Flush for the dictionaries that support XFlushable
112 void FlushDics() const;
114 sal_Int32 GetCount() const { return aConvDics.size(); }
115 uno::Reference< XConversionDictionary > GetByName( const OUString& rName );
117 const uno::Reference< XConversionDictionary >& GetByIndex( sal_Int32 nIdx )
119 return aConvDics[nIdx];
123 ConvDicNameContainer::ConvDicNameContainer()
127 void ConvDicNameContainer::FlushDics() const
129 sal_Int32 nLen = aConvDics.size();
130 for (sal_Int32 i = 0; i < nLen; ++i)
132 uno::Reference< util::XFlushable > xFlush( aConvDics[i] , UNO_QUERY );
133 if (xFlush.is())
137 xFlush->flush();
139 catch(Exception &)
141 OSL_FAIL( "flushing of conversion dictionary failed" );
147 sal_Int32 ConvDicNameContainer::GetIndexByName_Impl(
148 const OUString& rName )
150 sal_Int32 nRes = -1;
151 sal_Int32 nLen = aConvDics.size();
152 for (sal_Int32 i = 0; i < nLen && nRes == -1; ++i)
154 if (rName == aConvDics[i]->getName())
155 nRes = i;
157 return nRes;
160 uno::Reference< XConversionDictionary > ConvDicNameContainer::GetByName(
161 const OUString& rName )
163 uno::Reference< XConversionDictionary > xRes;
164 sal_Int32 nIdx = GetIndexByName_Impl( rName );
165 if ( nIdx != -1)
166 xRes = aConvDics[nIdx];
167 return xRes;
170 uno::Type SAL_CALL ConvDicNameContainer::getElementType( )
172 MutexGuard aGuard( GetLinguMutex() );
173 return cppu::UnoType<XConversionDictionary>::get();
176 sal_Bool SAL_CALL ConvDicNameContainer::hasElements( )
178 MutexGuard aGuard( GetLinguMutex() );
179 return !aConvDics.empty();
182 uno::Any SAL_CALL ConvDicNameContainer::getByName( const OUString& rName )
184 MutexGuard aGuard( GetLinguMutex() );
185 uno::Reference< XConversionDictionary > xRes( GetByName( rName ) );
186 if (!xRes.is())
187 throw NoSuchElementException();
188 return makeAny( xRes );
191 uno::Sequence< OUString > SAL_CALL ConvDicNameContainer::getElementNames( )
193 MutexGuard aGuard( GetLinguMutex() );
195 sal_Int32 nLen = aConvDics.size();
196 uno::Sequence< OUString > aRes( nLen );
197 OUString *pName = aRes.getArray();
198 for (sal_Int32 i = 0; i < nLen; ++i)
199 pName[i] = aConvDics[i]->getName();
200 return aRes;
203 sal_Bool SAL_CALL ConvDicNameContainer::hasByName( const OUString& rName )
205 MutexGuard aGuard( GetLinguMutex() );
206 return GetByName( rName ).is();
209 void SAL_CALL ConvDicNameContainer::replaceByName(
210 const OUString& rName,
211 const uno::Any& rElement )
213 MutexGuard aGuard( GetLinguMutex() );
215 sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
216 if (nRplcIdx == -1)
217 throw NoSuchElementException();
218 uno::Reference< XConversionDictionary > xNew;
219 rElement >>= xNew;
220 if (!xNew.is() || xNew->getName() != rName)
221 throw IllegalArgumentException();
222 aConvDics[ nRplcIdx ] = xNew;
225 void SAL_CALL ConvDicNameContainer::insertByName(
226 const OUString& rName,
227 const Any& rElement )
229 MutexGuard aGuard( GetLinguMutex() );
231 if (GetByName( rName ).is())
232 throw ElementExistException();
233 uno::Reference< XConversionDictionary > xNew;
234 rElement >>= xNew;
235 if (!xNew.is() || xNew->getName() != rName)
236 throw IllegalArgumentException();
238 aConvDics.push_back(xNew);
241 void SAL_CALL ConvDicNameContainer::removeByName( const OUString& rName )
243 MutexGuard aGuard( GetLinguMutex() );
245 sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
246 if (nRplcIdx == -1)
247 throw NoSuchElementException();
249 // physically remove dictionary
250 uno::Reference< XConversionDictionary > xDel = aConvDics[nRplcIdx];
251 OUString aName( xDel->getName() );
252 OUString aDicMainURL( GetConvDicMainURL( aName, GetDictionaryWriteablePath() ) );
253 INetURLObject aObj( aDicMainURL );
254 DBG_ASSERT( aObj.GetProtocol() == INetProtocol::File, "+HangulHanjaOptionsDialog::OkHdl(): non-file URLs cannot be deleted" );
255 if( aObj.GetProtocol() == INetProtocol::File )
259 ::ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
260 uno::Reference< css::ucb::XCommandEnvironment >(),
261 comphelper::getProcessComponentContext() );
262 aCnt.executeCommand( "delete", makeAny( true ) );
264 catch( css::ucb::CommandAbortedException& )
266 SAL_WARN( "linguistic", "HangulHanjaOptionsDialog::OkHdl(): CommandAbortedException" );
268 catch( ... )
270 SAL_WARN( "linguistic", "HangulHanjaOptionsDialog::OkHdl(): Any other exception" );
274 aConvDics.erase(aConvDics.begin() + nRplcIdx);
277 void ConvDicNameContainer::AddConvDics(
278 const OUString &rSearchDirPathURL,
279 const OUString &rExtension )
281 const Sequence< OUString > aDirCnt(
282 utl::LocalFileHelper::GetFolderContents( rSearchDirPathURL, false ) );
283 const OUString *pDirCnt = aDirCnt.getConstArray();
284 sal_Int32 nEntries = aDirCnt.getLength();
286 for (sal_Int32 i = 0; i < nEntries; ++i)
288 OUString aURL( pDirCnt[i] );
290 sal_Int32 nPos = aURL.lastIndexOf('.');
291 OUString aExt( aURL.copy(nPos + 1).toAsciiLowerCase() );
292 OUString aSearchExt( rExtension.toAsciiLowerCase() );
293 if(aExt != aSearchExt)
294 continue; // skip other files
296 LanguageType nLang;
297 sal_Int16 nConvType;
298 if (IsConvDic( aURL, nLang, nConvType ))
300 // get decoded dictionary file name
301 INetURLObject aURLObj( aURL );
302 OUString aDicName = aURLObj.getBase( INetURLObject::LAST_SEGMENT,
303 true, INetURLObject::DecodeMechanism::WithCharset );
305 uno::Reference < XConversionDictionary > xDic;
306 if (nLang == LANGUAGE_KOREAN &&
307 nConvType == ConversionDictionaryType::HANGUL_HANJA)
309 xDic = new HHConvDic( aDicName, aURL );
311 else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
312 nConvType == ConversionDictionaryType::SCHINESE_TCHINESE)
314 xDic = new ConvDic( aDicName, nLang, nConvType, false, aURL );
317 if (xDic.is())
319 insertByName( xDic->getName(), Any(xDic) );
325 namespace
327 struct StaticConvDicList : public rtl::StaticWithInit<
328 uno::Reference<XInterface>, StaticConvDicList> {
329 uno::Reference<XInterface> operator () () {
330 return static_cast<cppu::OWeakObject *>(new ConvDicList);
335 void ConvDicList::MyAppExitListener::AtExit()
337 rMyDicList.FlushDics();
338 StaticConvDicList::get().clear();
341 ConvDicList::ConvDicList() :
342 aEvtListeners( GetLinguMutex() )
344 bDisposing = false;
346 mxExitListener = new MyAppExitListener( *this );
347 mxExitListener->Activate();
350 ConvDicList::~ConvDicList()
352 if (!bDisposing && mxNameContainer.is())
353 mxNameContainer->FlushDics();
355 mxExitListener->Deactivate();
358 void ConvDicList::FlushDics()
360 // check only pointer to avoid creating the container when
361 // the dictionaries were not accessed yet
362 if (mxNameContainer.is())
363 mxNameContainer->FlushDics();
366 ConvDicNameContainer & ConvDicList::GetNameContainer()
368 if (!mxNameContainer.is())
370 mxNameContainer = new ConvDicNameContainer;
371 mxNameContainer->AddConvDics( GetDictionaryWriteablePath(), CONV_DIC_EXT );
373 // access list of text conversion dictionaries to activate
374 SvtLinguOptions aOpt;
375 SvtLinguConfig().GetOptions( aOpt );
376 sal_Int32 nLen = aOpt.aActiveConvDics.getLength();
377 const OUString *pActiveConvDics = aOpt.aActiveConvDics.getConstArray();
378 for (sal_Int32 i = 0; i < nLen; ++i)
380 uno::Reference< XConversionDictionary > xDic =
381 mxNameContainer->GetByName( pActiveConvDics[i] );
382 if (xDic.is())
383 xDic->setActive( true );
386 // since there is no UI to active/deactivate the dictionaries
387 // for chinese text conversion they should be activated by default
388 uno::Reference< XConversionDictionary > xS2TDic(
389 mxNameContainer->GetByName( "ChineseS2T" ), UNO_QUERY );
390 uno::Reference< XConversionDictionary > xT2SDic(
391 mxNameContainer->GetByName( "ChineseT2S" ), UNO_QUERY );
392 if (xS2TDic.is())
393 xS2TDic->setActive( true );
394 if (xT2SDic.is())
395 xT2SDic->setActive( true );
398 return *mxNameContainer;
401 uno::Reference< container::XNameContainer > SAL_CALL ConvDicList::getDictionaryContainer( )
403 MutexGuard aGuard( GetLinguMutex() );
404 GetNameContainer();
405 DBG_ASSERT( mxNameContainer.is(), "missing name container" );
406 return mxNameContainer.get();
409 uno::Reference< XConversionDictionary > SAL_CALL ConvDicList::addNewDictionary(
410 const OUString& rName,
411 const Locale& rLocale,
412 sal_Int16 nConvDicType )
414 MutexGuard aGuard( GetLinguMutex() );
416 LanguageType nLang = LinguLocaleToLanguage( rLocale );
418 if (GetNameContainer().hasByName( rName ))
419 throw ElementExistException();
421 uno::Reference< XConversionDictionary > xRes;
422 OUString aDicMainURL( GetConvDicMainURL( rName, GetDictionaryWriteablePath() ) );
423 if (nLang == LANGUAGE_KOREAN &&
424 nConvDicType == ConversionDictionaryType::HANGUL_HANJA)
426 xRes = new HHConvDic( rName, aDicMainURL );
428 else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
429 nConvDicType == ConversionDictionaryType::SCHINESE_TCHINESE)
431 xRes = new ConvDic( rName, nLang, nConvDicType, false, aDicMainURL );
434 if (!xRes.is())
435 throw NoSupportException();
437 xRes->setActive( true );
438 GetNameContainer().insertByName( rName, Any(xRes) );
439 return xRes;
442 uno::Sequence< OUString > SAL_CALL ConvDicList::queryConversions(
443 const OUString& rText,
444 sal_Int32 nStartPos,
445 sal_Int32 nLength,
446 const Locale& rLocale,
447 sal_Int16 nConversionDictionaryType,
448 ConversionDirection eDirection,
449 sal_Int32 nTextConversionOptions )
451 MutexGuard aGuard( GetLinguMutex() );
453 std::vector< OUString > aRes;
455 bool bSupported = false;
456 sal_Int32 nLen = GetNameContainer().GetCount();
457 for (sal_Int32 i = 0; i < nLen; ++i)
459 const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
460 bool bMatch = xDic.is() &&
461 xDic->getLocale() == rLocale &&
462 xDic->getConversionType() == nConversionDictionaryType;
463 bSupported |= bMatch;
464 if (bMatch && xDic->isActive())
466 Sequence< OUString > aNewConv( xDic->getConversions(
467 rText, nStartPos, nLength,
468 eDirection, nTextConversionOptions ) );
469 sal_Int32 nNewLen = aNewConv.getLength();
470 if (nNewLen > 0)
472 for (sal_Int32 k = 0; k < nNewLen; ++k)
473 aRes.push_back(aNewConv[k]);
478 if (!bSupported)
479 throw NoSupportException();
481 return comphelper::containerToSequence(aRes);
484 sal_Int16 SAL_CALL ConvDicList::queryMaxCharCount(
485 const Locale& rLocale,
486 sal_Int16 nConversionDictionaryType,
487 ConversionDirection eDirection )
489 MutexGuard aGuard( GetLinguMutex() );
491 sal_Int16 nRes = 0;
492 GetNameContainer();
493 sal_Int32 nLen = GetNameContainer().GetCount();
494 for (sal_Int32 i = 0; i < nLen; ++i)
496 const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
497 if (xDic.is() &&
498 xDic->getLocale() == rLocale &&
499 xDic->getConversionType() == nConversionDictionaryType)
501 sal_Int16 nC = xDic->getMaxCharCount( eDirection );
502 if (nC > nRes)
503 nRes = nC;
506 return nRes;
509 void SAL_CALL ConvDicList::dispose( )
511 MutexGuard aGuard( GetLinguMutex() );
512 if (!bDisposing)
514 bDisposing = true;
515 EventObject aEvtObj( static_cast<XConversionDictionaryList *>(this) );
516 aEvtListeners.disposeAndClear( aEvtObj );
518 FlushDics();
522 void SAL_CALL ConvDicList::addEventListener(
523 const uno::Reference< XEventListener >& rxListener )
525 MutexGuard aGuard( GetLinguMutex() );
526 if (!bDisposing && rxListener.is())
527 aEvtListeners.addInterface( rxListener );
530 void SAL_CALL ConvDicList::removeEventListener(
531 const uno::Reference< XEventListener >& rxListener )
533 MutexGuard aGuard( GetLinguMutex() );
534 if (!bDisposing && rxListener.is())
535 aEvtListeners.removeInterface( rxListener );
538 OUString SAL_CALL ConvDicList::getImplementationName()
540 return getImplementationName_Static();
543 sal_Bool SAL_CALL ConvDicList::supportsService( const OUString& rServiceName )
545 return cppu::supportsService(this, rServiceName);
548 uno::Sequence< OUString > SAL_CALL ConvDicList::getSupportedServiceNames()
550 return getSupportedServiceNames_Static();
553 uno::Sequence< OUString > ConvDicList::getSupportedServiceNames_Static()
554 throw()
556 uno::Sequence<OUString> aSNS { SN_CONV_DICTIONARY_LIST };
557 return aSNS;
560 /// @throws css::uno::Exception
561 uno::Reference< uno::XInterface > ConvDicList_CreateInstance(
562 const uno::Reference< XMultiServiceFactory > & /*rSMgr*/ )
564 return StaticConvDicList::get();
567 void * ConvDicList_getFactory(
568 const sal_Char * pImplName,
569 XMultiServiceFactory * pServiceManager )
571 void * pRet = nullptr;
572 if ( ConvDicList::getImplementationName_Static().equalsAscii( pImplName ) )
574 uno::Reference< XSingleServiceFactory > xFactory =
575 cppu::createOneInstanceFactory(
576 pServiceManager,
577 ConvDicList::getImplementationName_Static(),
578 ConvDicList_CreateInstance,
579 ConvDicList::getSupportedServiceNames_Static());
580 // acquire, because we return an interface pointer instead of a reference
581 xFactory->acquire();
582 pRet = xFactory.get();
584 return pRet;
587 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */