LibreOffice Module linguistic (master) 1
convdiclist.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <string_view>
23
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>
36#include <tools/debug.hxx>
37#include <tools/urlobj.hxx>
38#include <ucbhelper/content.hxx>
40#include <unotools/lingucfg.hxx>
42
43#include "convdic.hxx"
44#include "convdiclist.hxx"
45#include "hhconvdic.hxx"
46#include <linguistic/misc.hxx>
47
48using namespace osl;
49using namespace com::sun::star;
50using namespace com::sun::star::lang;
51using namespace com::sun::star::uno;
52using namespace com::sun::star::container;
53using namespace com::sun::star::linguistic2;
54using namespace linguistic;
55
56static OUString GetConvDicMainURL( std::u16string_view rDicName, std::u16string_view rDirectoryURL )
57{
58 // build URL to use for new (persistent) dictionaries
59
60 OUString aFullDicName = OUString::Concat(rDicName) + CONV_DIC_DOT_EXT;
61
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
71}
72
74 public cppu::WeakImplHelper< css::container::XNameContainer >
75{
76 std::vector< uno::Reference< XConversionDictionary > > aConvDics;
77
78 sal_Int32 GetIndexByName_Impl( std::u16string_view rName );
79
80public:
84
85 // XElementAccess
86 virtual css::uno::Type SAL_CALL getElementType( ) override;
87 virtual sal_Bool SAL_CALL hasElements( ) override;
88
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;
93
94 // XNameReplace
95 virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
96
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;
100
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 );
104
105 // calls Flush for the dictionaries that support XFlushable
106 void FlushDics() const;
107
108 sal_Int32 GetCount() const { return aConvDics.size(); }
109 uno::Reference< XConversionDictionary > GetByName( std::u16string_view rName );
110
111 const uno::Reference< XConversionDictionary >& GetByIndex( sal_Int32 nIdx )
112 {
113 return aConvDics[nIdx];
114 }
115};
116
118{
119}
120
122{
123 sal_Int32 nLen = aConvDics.size();
124 for (sal_Int32 i = 0; i < nLen; ++i)
125 {
126 uno::Reference< util::XFlushable > xFlush( aConvDics[i] , UNO_QUERY );
127 if (xFlush.is())
128 {
129 try
130 {
131 xFlush->flush();
132 }
133 catch(Exception &)
134 {
135 OSL_FAIL( "flushing of conversion dictionary failed" );
136 }
137 }
138 }
139}
140
142 std::u16string_view rName )
143{
144 sal_Int32 nRes = -1;
145 sal_Int32 nLen = aConvDics.size();
146 for (sal_Int32 i = 0; i < nLen && nRes == -1; ++i)
147 {
148 if (rName == aConvDics[i]->getName())
149 nRes = i;
150 }
151 return nRes;
152}
153
154uno::Reference< XConversionDictionary > ConvDicNameContainer::GetByName(
155 std::u16string_view rName )
156{
157 uno::Reference< XConversionDictionary > xRes;
158 sal_Int32 nIdx = GetIndexByName_Impl( rName );
159 if ( nIdx != -1)
160 xRes = aConvDics[nIdx];
161 return xRes;
162}
163
165{
167}
168
170{
171 MutexGuard aGuard( GetLinguMutex() );
172 return !aConvDics.empty();
173}
174
175uno::Any SAL_CALL ConvDicNameContainer::getByName( const OUString& rName )
176{
177 MutexGuard aGuard( GetLinguMutex() );
178 uno::Reference< XConversionDictionary > xRes( GetByName( rName ) );
179 if (!xRes.is())
180 throw NoSuchElementException();
181 return Any( xRes );
182}
183
184uno::Sequence< OUString > SAL_CALL ConvDicNameContainer::getElementNames( )
185{
186 MutexGuard aGuard( GetLinguMutex() );
187
188 std::vector<OUString> aRes;
189 aRes.reserve(aConvDics.size());
190
191 std::transform(aConvDics.begin(), aConvDics.end(), std::back_inserter(aRes),
192 [](const uno::Reference<XConversionDictionary>& rDic) { return rDic->getName(); });
193
195}
196
197sal_Bool SAL_CALL ConvDicNameContainer::hasByName( const OUString& rName )
198{
199 MutexGuard aGuard( GetLinguMutex() );
200 return GetByName( rName ).is();
201}
202
204 const OUString& rName,
205 const uno::Any& rElement )
206{
207 MutexGuard aGuard( GetLinguMutex() );
208
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;
217}
218
220 const OUString& rName,
221 const Any& rElement )
222{
223 MutexGuard aGuard( GetLinguMutex() );
224
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();
231
232 aConvDics.push_back(xNew);
233}
234
235void SAL_CALL ConvDicNameContainer::removeByName( const OUString& rName )
236{
237 MutexGuard aGuard( GetLinguMutex() );
238
239 sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
240 if (nRplcIdx == -1)
241 throw NoSuchElementException();
242
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 )
250 {
251 try
252 {
254 uno::Reference< css::ucb::XCommandEnvironment >(),
256 aCnt.executeCommand( "delete", Any( true ) );
257 }
258 catch( ... )
259 {
260 TOOLS_WARN_EXCEPTION( "linguistic", "HangulHanjaOptionsDialog::OkHdl()" );
261 }
262 }
263
264 aConvDics.erase(aConvDics.begin() + nRplcIdx);
265}
266
268 const OUString &rSearchDirPathURL,
269 const OUString &rExtension )
270{
271 const Sequence< OUString > aDirCnt(
272 utl::LocalFileHelper::GetFolderContents( rSearchDirPathURL, false ) );
273
274 for (const OUString& aURL : aDirCnt)
275 {
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
281
282 LanguageType nLang;
283 sal_Int16 nConvType;
284 if (IsConvDic( aURL, nLang, nConvType ))
285 {
286 // get decoded dictionary file name
287 INetURLObject aURLObj( aURL );
288 OUString aDicName = aURLObj.getBase( INetURLObject::LAST_SEGMENT,
290
291 uno::Reference < XConversionDictionary > xDic;
292 if (nLang == LANGUAGE_KOREAN &&
293 nConvType == ConversionDictionaryType::HANGUL_HANJA)
294 {
295 xDic = new HHConvDic( aDicName, aURL );
296 }
297 else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
298 nConvType == ConversionDictionaryType::SCHINESE_TCHINESE)
299 {
300 xDic = new ConvDic( aDicName, nLang, nConvType, false, aURL );
301 }
302
303 if (xDic.is())
304 {
305 insertByName( xDic->getName(), Any(xDic) );
306 }
307 }
308 }
309}
310
311namespace
312{
313 rtl::Reference<ConvDicList>& StaticConvDicList()
314 {
315 static rtl::Reference<ConvDicList> SINGLETON = new ConvDicList;
316 return SINGLETON;
317 };
318}
319
321{
323 StaticConvDicList().clear();
324}
325
328{
329 bDisposing = false;
330
331 mxExitListener = new MyAppExitListener( *this );
332 mxExitListener->Activate();
333}
334
336{
337 if (!bDisposing && mxNameContainer.is())
338 mxNameContainer->FlushDics();
339
340 mxExitListener->Deactivate();
341}
342
344{
345 // check only pointer to avoid creating the container when
346 // the dictionaries were not accessed yet
347 if (mxNameContainer.is())
348 mxNameContainer->FlushDics();
349}
350
352{
353 if (!mxNameContainer.is())
354 {
357
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))
362 {
363 uno::Reference< XConversionDictionary > xDic =
364 mxNameContainer->GetByName( rActiveConvDic );
365 if (xDic.is())
366 xDic->setActive( true );
367 }
368
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 );
379
380 }
381 return *mxNameContainer;
382}
383
384uno::Reference< container::XNameContainer > SAL_CALL ConvDicList::getDictionaryContainer( )
385{
386 MutexGuard aGuard( GetLinguMutex() );
388 DBG_ASSERT( mxNameContainer.is(), "missing name container" );
389 return mxNameContainer;
390}
391
392uno::Reference< XConversionDictionary > SAL_CALL ConvDicList::addNewDictionary(
393 const OUString& rName,
394 const Locale& rLocale,
395 sal_Int16 nConvDicType )
396{
397 MutexGuard aGuard( GetLinguMutex() );
398
399 LanguageType nLang = LinguLocaleToLanguage( rLocale );
400
401 if (GetNameContainer().hasByName( rName ))
402 throw ElementExistException();
403
404 uno::Reference< XConversionDictionary > xRes;
405 OUString aDicMainURL( GetConvDicMainURL( rName, GetDictionaryWriteablePath() ) );
406 if (nLang == LANGUAGE_KOREAN &&
407 nConvDicType == ConversionDictionaryType::HANGUL_HANJA)
408 {
409 xRes = new HHConvDic( rName, aDicMainURL );
410 }
411 else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
412 nConvDicType == ConversionDictionaryType::SCHINESE_TCHINESE)
413 {
414 xRes = new ConvDic( rName, nLang, nConvDicType, false, aDicMainURL );
415 }
416
417 if (!xRes.is())
418 throw NoSupportException();
419
420 xRes->setActive( true );
421 GetNameContainer().insertByName( rName, Any(xRes) );
422 return xRes;
423}
424
425uno::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 )
433{
434 MutexGuard aGuard( GetLinguMutex() );
435
436 std::vector< OUString > aRes;
437
438 bool bSupported = false;
439 sal_Int32 nLen = GetNameContainer().GetCount();
440 for (sal_Int32 i = 0; i < nLen; ++i)
441 {
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())
448 {
449 const Sequence< OUString > aNewConv( xDic->getConversions(
450 rText, nStartPos, nLength,
451 eDirection, nTextConversionOptions ) );
452 aRes.insert( aRes.end(), aNewConv.begin(), aNewConv.end() );
453 }
454 }
455
456 if (!bSupported)
457 throw NoSupportException();
458
460}
461
463 const Locale& rLocale,
464 sal_Int16 nConversionDictionaryType,
465 ConversionDirection eDirection )
466{
467 MutexGuard aGuard( GetLinguMutex() );
468
469 sal_Int16 nRes = 0;
471 sal_Int32 nLen = GetNameContainer().GetCount();
472 for (sal_Int32 i = 0; i < nLen; ++i)
473 {
474 const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
475 if (xDic.is() &&
476 xDic->getLocale() == rLocale &&
477 xDic->getConversionType() == nConversionDictionaryType)
478 {
479 sal_Int16 nC = xDic->getMaxCharCount( eDirection );
480 if (nC > nRes)
481 nRes = nC;
482 }
483 }
484 return nRes;
485}
486
487void SAL_CALL ConvDicList::dispose( )
488{
489 MutexGuard aGuard( GetLinguMutex() );
490 if (!bDisposing)
491 {
492 bDisposing = true;
493 EventObject aEvtObj( static_cast<XConversionDictionaryList *>(this) );
495
496 FlushDics();
497 }
498}
499
501 const uno::Reference< XEventListener >& rxListener )
502{
503 MutexGuard aGuard( GetLinguMutex() );
504 if (!bDisposing && rxListener.is())
505 aEvtListeners.addInterface( rxListener );
506}
507
509 const uno::Reference< XEventListener >& rxListener )
510{
511 MutexGuard aGuard( GetLinguMutex() );
512 if (!bDisposing && rxListener.is())
513 aEvtListeners.removeInterface( rxListener );
514}
515
517{
518 return "com.sun.star.lingu2.ConvDicList";
519}
520
521sal_Bool SAL_CALL ConvDicList::supportsService( const OUString& rServiceName )
522{
523 return cppu::supportsService(this, rServiceName);
524}
525
526uno::Sequence< OUString > SAL_CALL ConvDicList::getSupportedServiceNames()
527{
528 return { "com.sun.star.linguistic2.ConversionDictionaryList" };
529}
530
531extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
533 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
534{
535 return cppu::acquire(StaticConvDicList().get());
536}
537
538
539/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual void AtExit() override
ConvDicNameContainer & GetNameContainer()
virtual css::uno::Reference< css::linguistic2::XConversionDictionary > SAL_CALL addNewDictionary(const OUString &aName, const css::lang::Locale &aLocale, sal_Int16 nConversionDictionaryType) override
rtl::Reference< ConvDicNameContainer > mxNameContainer
Definition: convdiclist.hxx:54
virtual void SAL_CALL dispose() override
void FlushDics()
virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener > &xListener) override
virtual css::uno::Sequence< OUString > SAL_CALL queryConversions(const OUString &aText, sal_Int32 nStartPos, sal_Int32 nLength, const css::lang::Locale &aLocale, sal_Int16 nConversionDictionaryType, css::linguistic2::ConversionDirection eDirection, sal_Int32 nTextConversionOptions) override
virtual OUString SAL_CALL getImplementationName() override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual void SAL_CALL removeEventListener(const css::uno::Reference< css::lang::XEventListener > &aListener) override
::comphelper::OInterfaceContainerHelper3< css::lang::XEventListener > aEvtListeners
Definition: convdiclist.hxx:53
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
virtual sal_Int16 SAL_CALL queryMaxCharCount(const css::lang::Locale &aLocale, sal_Int16 nConversionDictionaryType, css::linguistic2::ConversionDirection eDirection) override
virtual css::uno::Reference< css::container::XNameContainer > SAL_CALL getDictionaryContainer() override
virtual ~ConvDicList() override
rtl::Reference< MyAppExitListener > mxExitListener
Definition: convdiclist.hxx:55
const uno::Reference< XConversionDictionary > & GetByIndex(sal_Int32 nIdx)
virtual void SAL_CALL removeByName(const OUString &Name) override
uno::Reference< XConversionDictionary > GetByName(std::u16string_view rName)
virtual css::uno::Any SAL_CALL getByName(const OUString &aName) override
sal_Int32 GetCount() const
virtual void SAL_CALL replaceByName(const OUString &aName, const css::uno::Any &aElement) override
virtual sal_Bool SAL_CALL hasByName(const OUString &aName) override
ConvDicNameContainer & operator=(const ConvDicNameContainer &)=delete
sal_Int32 GetIndexByName_Impl(std::u16string_view rName)
virtual sal_Bool SAL_CALL hasElements() override
ConvDicNameContainer(const ConvDicNameContainer &)=delete
virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override
std::vector< uno::Reference< XConversionDictionary > > aConvDics
Definition: convdiclist.cxx:76
virtual void SAL_CALL insertByName(const OUString &aName, const css::uno::Any &aElement) override
virtual css::uno::Type SAL_CALL getElementType() override
void AddConvDics(const OUString &rSearchDirPathURL, const OUString &rExtension)
void FlushDics() const
void SetSmartProtocol(INetProtocol eTheSmartScheme)
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
bool HasError() const
OUString getBase(sal_Int32 nIndex=LAST_SEGMENT, bool bIgnoreFinalSlash=true, DecodeMechanism eMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
bool SetSmartURL(std::u16string_view rTheAbsURIRef, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8, FSysStyle eStyle=FSysStyle::Detect)
INetProtocol GetProtocol() const
bool Append(std::u16string_view rTheSegment, EncodeMechanism eMechanism=EncodeMechanism::WasEncoded, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
void GetOptions(SvtLinguOptions &rOptions) const
sal_Int32 addInterface(const css::uno::Reference< ListenerT > &rxIFace)
void disposeAndClear(const css::lang::EventObject &rEvt)
sal_Int32 removeInterface(const css::uno::Reference< ListenerT > &rxIFace)
css::uno::Type const & get()
css::uno::Any executeCommand(const OUString &rCommandName, const css::uno::Any &rCommandArgument)
static css::uno::Sequence< OUString > GetFolderContents(const OUString &rFolder, bool bFolder)
bool IsConvDic(const OUString &rFileURL, LanguageType &nLang, sal_Int16 &nConvType)
Definition: convdic.cxx:110
constexpr OUStringLiteral CONV_DIC_EXT
Definition: convdic.hxx:33
#define CONV_DIC_DOT_EXT
Definition: convdic.hxx:34
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * linguistic_ConvDicList_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
static OUString GetConvDicMainURL(std::u16string_view rDicName, std::u16string_view rDirectoryURL)
Definition: convdiclist.cxx:56
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
URL aURL
float u
OUString aName
#define LANGUAGE_CHINESE_TRADITIONAL
#define LANGUAGE_CHINESE_SIMPLIFIED
#define LANGUAGE_KOREAN
sal_uInt16 nPos
@ Exception
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Reference< XComponentContext > getProcessComponentContext()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
OUString GetDictionaryWriteablePath()
Definition: misc2.cxx:131
osl::Mutex & GetLinguMutex()
! multi-thread safe mutex for all platforms !!
Definition: misc.cxx:60
LanguageType LinguLocaleToLanguage(const css::lang::Locale &rLocale)
Convert Locale to LanguageType for legacy handling.
Definition: misc.cxx:74
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
css::uno::Sequence< OUString > aActiveConvDics
unsigned char sal_Bool
sal_Int32 nLength