tdf#151548 ContentControls: Add Delete()
[LibreOffice.git] / linguistic / source / convdiclist.cxx
blob766b67a4cc375c88b05cf4be4ba9985f747004e8
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 <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>
48 using namespace osl;
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())
68 return OUString();
69 else
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 );
80 public:
81 ConvDicNameContainer();
82 ConvDicNameContainer(const ConvDicNameContainer&) = delete;
83 ConvDicNameContainer& operator=(const ConvDicNameContainer&) = delete;
85 // XElementAccess
86 virtual css::uno::Type SAL_CALL getElementType( ) override;
87 virtual sal_Bool SAL_CALL hasElements( ) override;
89 // XNameAccess
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;
94 // XNameReplace
95 virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
97 // XNameContainer
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 );
127 if (xFlush.is())
131 xFlush->flush();
133 catch(Exception &)
135 OSL_FAIL( "flushing of conversion dictionary failed" );
141 sal_Int32 ConvDicNameContainer::GetIndexByName_Impl(
142 std::u16string_view rName )
144 sal_Int32 nRes = -1;
145 sal_Int32 nLen = aConvDics.size();
146 for (sal_Int32 i = 0; i < nLen && nRes == -1; ++i)
148 if (rName == aConvDics[i]->getName())
149 nRes = i;
151 return nRes;
154 uno::Reference< XConversionDictionary > ConvDicNameContainer::GetByName(
155 std::u16string_view rName )
157 uno::Reference< XConversionDictionary > xRes;
158 sal_Int32 nIdx = GetIndexByName_Impl( rName );
159 if ( nIdx != -1)
160 xRes = aConvDics[nIdx];
161 return xRes;
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 ) );
179 if (!xRes.is())
180 throw NoSuchElementException();
181 return Any( xRes );
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 );
210 if (nRplcIdx == -1)
211 throw NoSuchElementException();
212 uno::Reference< XConversionDictionary > xNew;
213 rElement >>= 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;
228 rElement >>= 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 );
240 if (nRplcIdx == -1)
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 ) );
258 catch( ... )
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
282 LanguageType nLang;
283 sal_Int16 nConvType;
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 );
303 if (xDic.is())
305 insertByName( xDic->getName(), Any(xDic) );
311 namespace
313 rtl::Reference<ConvDicList>& StaticConvDicList()
315 static rtl::Reference<ConvDicList> SINGLETON = new ConvDicList;
316 return SINGLETON;
320 void ConvDicList::MyAppExitListener::AtExit()
322 rMyDicList.FlushDics();
323 StaticConvDicList().clear();
326 ConvDicList::ConvDicList() :
327 aEvtListeners( GetLinguMutex() )
329 bDisposing = false;
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 );
365 if (xDic.is())
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" );
375 if (xS2TDic.is())
376 xS2TDic->setActive( true );
377 if (xT2SDic.is())
378 xT2SDic->setActive( true );
381 return *mxNameContainer;
384 uno::Reference< container::XNameContainer > SAL_CALL ConvDicList::getDictionaryContainer( )
386 MutexGuard aGuard( GetLinguMutex() );
387 GetNameContainer();
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 );
417 if (!xRes.is())
418 throw NoSupportException();
420 xRes->setActive( true );
421 GetNameContainer().insertByName( rName, Any(xRes) );
422 return xRes;
425 uno::Sequence< OUString > SAL_CALL ConvDicList::queryConversions(
426 const OUString& rText,
427 sal_Int32 nStartPos,
428 sal_Int32 nLength,
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() );
456 if (!bSupported)
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() );
469 sal_Int16 nRes = 0;
470 GetNameContainer();
471 sal_Int32 nLen = GetNameContainer().GetCount();
472 for (sal_Int32 i = 0; i < nLen; ++i)
474 const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
475 if (xDic.is() &&
476 xDic->getLocale() == rLocale &&
477 xDic->getConversionType() == nConversionDictionaryType)
479 sal_Int16 nC = xDic->getMaxCharCount( eDirection );
480 if (nC > nRes)
481 nRes = nC;
484 return nRes;
487 void SAL_CALL ConvDicList::dispose( )
489 MutexGuard aGuard( GetLinguMutex() );
490 if (!bDisposing)
492 bDisposing = true;
493 EventObject aEvtObj( static_cast<XConversionDictionaryList *>(this) );
494 aEvtListeners.disposeAndClear( aEvtObj );
496 FlushDics();
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: */