summaryrefslogtreecommitdiffstats
path: root/linguistic/source/convdiclist.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'linguistic/source/convdiclist.cxx')
-rw-r--r--linguistic/source/convdiclist.cxx539
1 files changed, 539 insertions, 0 deletions
diff --git a/linguistic/source/convdiclist.cxx b/linguistic/source/convdiclist.cxx
new file mode 100644
index 000000000..6be588ea1
--- /dev/null
+++ b/linguistic/source/convdiclist.cxx
@@ -0,0 +1,539 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
+#include <com/sun/star/linguistic2/XConversionDictionaryList.hpp>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/debug.hxx>
+#include <tools/urlobj.hxx>
+#include <ucbhelper/content.hxx>
+#include <unotools/localfilehelper.hxx>
+#include <unotools/lingucfg.hxx>
+#include <tools/diagnose_ex.h>
+
+#include "convdic.hxx"
+#include "convdiclist.hxx"
+#include "hhconvdic.hxx"
+#include <linguistic/misc.hxx>
+
+using namespace osl;
+using namespace com::sun::star;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::container;
+using namespace com::sun::star::linguistic2;
+using namespace linguistic;
+
+static OUString GetConvDicMainURL( std::u16string_view rDicName, std::u16string_view rDirectoryURL )
+{
+ // build URL to use for new (persistent) dictionaries
+
+ OUString aFullDicName = OUString::Concat(rDicName) + CONV_DIC_DOT_EXT;
+
+ INetURLObject aURLObj;
+ aURLObj.SetSmartProtocol( INetProtocol::File );
+ aURLObj.SetSmartURL( rDirectoryURL );
+ aURLObj.Append( aFullDicName, INetURLObject::EncodeMechanism::All );
+ DBG_ASSERT(!aURLObj.HasError(), "invalid URL");
+ if (aURLObj.HasError())
+ return OUString();
+ else
+ return aURLObj.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
+}
+
+class ConvDicNameContainer :
+ public cppu::WeakImplHelper< css::container::XNameContainer >
+{
+ std::vector< uno::Reference< XConversionDictionary > > aConvDics;
+
+ sal_Int32 GetIndexByName_Impl( std::u16string_view rName );
+
+public:
+ ConvDicNameContainer();
+ ConvDicNameContainer(const ConvDicNameContainer&) = delete;
+ ConvDicNameContainer& operator=(const ConvDicNameContainer&) = delete;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
+
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& aName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& Name ) override;
+
+ // looks for conversion dictionaries with the specified extension
+ // in the directory and adds them to the container
+ void AddConvDics( const OUString &rSearchDirPathURL, const OUString &rExtension );
+
+ // calls Flush for the dictionaries that support XFlushable
+ void FlushDics() const;
+
+ sal_Int32 GetCount() const { return aConvDics.size(); }
+ uno::Reference< XConversionDictionary > GetByName( std::u16string_view rName );
+
+ const uno::Reference< XConversionDictionary >& GetByIndex( sal_Int32 nIdx )
+ {
+ return aConvDics[nIdx];
+ }
+};
+
+ConvDicNameContainer::ConvDicNameContainer()
+{
+}
+
+void ConvDicNameContainer::FlushDics() const
+{
+ sal_Int32 nLen = aConvDics.size();
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ uno::Reference< util::XFlushable > xFlush( aConvDics[i] , UNO_QUERY );
+ if (xFlush.is())
+ {
+ try
+ {
+ xFlush->flush();
+ }
+ catch(Exception &)
+ {
+ OSL_FAIL( "flushing of conversion dictionary failed" );
+ }
+ }
+ }
+}
+
+sal_Int32 ConvDicNameContainer::GetIndexByName_Impl(
+ std::u16string_view rName )
+{
+ sal_Int32 nRes = -1;
+ sal_Int32 nLen = aConvDics.size();
+ for (sal_Int32 i = 0; i < nLen && nRes == -1; ++i)
+ {
+ if (rName == aConvDics[i]->getName())
+ nRes = i;
+ }
+ return nRes;
+}
+
+uno::Reference< XConversionDictionary > ConvDicNameContainer::GetByName(
+ std::u16string_view rName )
+{
+ uno::Reference< XConversionDictionary > xRes;
+ sal_Int32 nIdx = GetIndexByName_Impl( rName );
+ if ( nIdx != -1)
+ xRes = aConvDics[nIdx];
+ return xRes;
+}
+
+uno::Type SAL_CALL ConvDicNameContainer::getElementType( )
+{
+ return cppu::UnoType<XConversionDictionary>::get();
+}
+
+sal_Bool SAL_CALL ConvDicNameContainer::hasElements( )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return !aConvDics.empty();
+}
+
+uno::Any SAL_CALL ConvDicNameContainer::getByName( const OUString& rName )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ uno::Reference< XConversionDictionary > xRes( GetByName( rName ) );
+ if (!xRes.is())
+ throw NoSuchElementException();
+ return Any( xRes );
+}
+
+uno::Sequence< OUString > SAL_CALL ConvDicNameContainer::getElementNames( )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ std::vector<OUString> aRes;
+ aRes.reserve(aConvDics.size());
+
+ std::transform(aConvDics.begin(), aConvDics.end(), std::back_inserter(aRes),
+ [](const uno::Reference<XConversionDictionary>& rDic) { return rDic->getName(); });
+
+ return comphelper::containerToSequence(aRes);
+}
+
+sal_Bool SAL_CALL ConvDicNameContainer::hasByName( const OUString& rName )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return GetByName( rName ).is();
+}
+
+void SAL_CALL ConvDicNameContainer::replaceByName(
+ const OUString& rName,
+ const uno::Any& rElement )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
+ if (nRplcIdx == -1)
+ throw NoSuchElementException();
+ uno::Reference< XConversionDictionary > xNew;
+ rElement >>= xNew;
+ if (!xNew.is() || xNew->getName() != rName)
+ throw IllegalArgumentException();
+ aConvDics[ nRplcIdx ] = xNew;
+}
+
+void SAL_CALL ConvDicNameContainer::insertByName(
+ const OUString& rName,
+ const Any& rElement )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (GetByName( rName ).is())
+ throw ElementExistException();
+ uno::Reference< XConversionDictionary > xNew;
+ rElement >>= xNew;
+ if (!xNew.is() || xNew->getName() != rName)
+ throw IllegalArgumentException();
+
+ aConvDics.push_back(xNew);
+}
+
+void SAL_CALL ConvDicNameContainer::removeByName( const OUString& rName )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
+ if (nRplcIdx == -1)
+ throw NoSuchElementException();
+
+ // physically remove dictionary
+ uno::Reference< XConversionDictionary > xDel = aConvDics[nRplcIdx];
+ OUString aName( xDel->getName() );
+ OUString aDicMainURL( GetConvDicMainURL( aName, GetDictionaryWriteablePath() ) );
+ INetURLObject aObj( aDicMainURL );
+ DBG_ASSERT( aObj.GetProtocol() == INetProtocol::File, "+HangulHanjaOptionsDialog::OkHdl(): non-file URLs cannot be deleted" );
+ if( aObj.GetProtocol() == INetProtocol::File )
+ {
+ try
+ {
+ ::ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ uno::Reference< css::ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+ aCnt.executeCommand( "delete", Any( true ) );
+ }
+ catch( ... )
+ {
+ TOOLS_WARN_EXCEPTION( "linguistic", "HangulHanjaOptionsDialog::OkHdl()" );
+ }
+ }
+
+ aConvDics.erase(aConvDics.begin() + nRplcIdx);
+}
+
+void ConvDicNameContainer::AddConvDics(
+ const OUString &rSearchDirPathURL,
+ const OUString &rExtension )
+{
+ const Sequence< OUString > aDirCnt(
+ utl::LocalFileHelper::GetFolderContents( rSearchDirPathURL, false ) );
+
+ for (const OUString& aURL : aDirCnt)
+ {
+ sal_Int32 nPos = aURL.lastIndexOf('.');
+ OUString aExt( aURL.copy(nPos + 1).toAsciiLowerCase() );
+ OUString aSearchExt( rExtension.toAsciiLowerCase() );
+ if(aExt != aSearchExt)
+ continue; // skip other files
+
+ LanguageType nLang;
+ sal_Int16 nConvType;
+ if (IsConvDic( aURL, nLang, nConvType ))
+ {
+ // get decoded dictionary file name
+ INetURLObject aURLObj( aURL );
+ OUString aDicName = aURLObj.getBase( INetURLObject::LAST_SEGMENT,
+ true, INetURLObject::DecodeMechanism::WithCharset );
+
+ uno::Reference < XConversionDictionary > xDic;
+ if (nLang == LANGUAGE_KOREAN &&
+ nConvType == ConversionDictionaryType::HANGUL_HANJA)
+ {
+ xDic = new HHConvDic( aDicName, aURL );
+ }
+ else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
+ nConvType == ConversionDictionaryType::SCHINESE_TCHINESE)
+ {
+ xDic = new ConvDic( aDicName, nLang, nConvType, false, aURL );
+ }
+
+ if (xDic.is())
+ {
+ insertByName( xDic->getName(), Any(xDic) );
+ }
+ }
+ }
+}
+
+namespace
+{
+ rtl::Reference<ConvDicList>& StaticConvDicList()
+ {
+ static rtl::Reference<ConvDicList> SINGLETON = new ConvDicList;
+ return SINGLETON;
+ };
+}
+
+void ConvDicList::MyAppExitListener::AtExit()
+{
+ rMyDicList.FlushDics();
+ StaticConvDicList().clear();
+}
+
+ConvDicList::ConvDicList() :
+ aEvtListeners( GetLinguMutex() )
+{
+ bDisposing = false;
+
+ mxExitListener = new MyAppExitListener( *this );
+ mxExitListener->Activate();
+}
+
+ConvDicList::~ConvDicList()
+{
+ if (!bDisposing && mxNameContainer.is())
+ mxNameContainer->FlushDics();
+
+ mxExitListener->Deactivate();
+}
+
+void ConvDicList::FlushDics()
+{
+ // check only pointer to avoid creating the container when
+ // the dictionaries were not accessed yet
+ if (mxNameContainer.is())
+ mxNameContainer->FlushDics();
+}
+
+ConvDicNameContainer & ConvDicList::GetNameContainer()
+{
+ if (!mxNameContainer.is())
+ {
+ mxNameContainer = new ConvDicNameContainer;
+ mxNameContainer->AddConvDics( GetDictionaryWriteablePath(), CONV_DIC_EXT );
+
+ // access list of text conversion dictionaries to activate
+ SvtLinguOptions aOpt;
+ SvtLinguConfig().GetOptions( aOpt );
+ for (const OUString& rActiveConvDic : std::as_const(aOpt.aActiveConvDics))
+ {
+ uno::Reference< XConversionDictionary > xDic =
+ mxNameContainer->GetByName( rActiveConvDic );
+ if (xDic.is())
+ xDic->setActive( true );
+ }
+
+ // since there is no UI to active/deactivate the dictionaries
+ // for chinese text conversion they should be activated by default
+ uno::Reference< XConversionDictionary > xS2TDic =
+ mxNameContainer->GetByName( u"ChineseS2T" );
+ uno::Reference< XConversionDictionary > xT2SDic =
+ mxNameContainer->GetByName( u"ChineseT2S" );
+ if (xS2TDic.is())
+ xS2TDic->setActive( true );
+ if (xT2SDic.is())
+ xT2SDic->setActive( true );
+
+ }
+ return *mxNameContainer;
+}
+
+uno::Reference< container::XNameContainer > SAL_CALL ConvDicList::getDictionaryContainer( )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ GetNameContainer();
+ DBG_ASSERT( mxNameContainer.is(), "missing name container" );
+ return mxNameContainer;
+}
+
+uno::Reference< XConversionDictionary > SAL_CALL ConvDicList::addNewDictionary(
+ const OUString& rName,
+ const Locale& rLocale,
+ sal_Int16 nConvDicType )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ LanguageType nLang = LinguLocaleToLanguage( rLocale );
+
+ if (GetNameContainer().hasByName( rName ))
+ throw ElementExistException();
+
+ uno::Reference< XConversionDictionary > xRes;
+ OUString aDicMainURL( GetConvDicMainURL( rName, GetDictionaryWriteablePath() ) );
+ if (nLang == LANGUAGE_KOREAN &&
+ nConvDicType == ConversionDictionaryType::HANGUL_HANJA)
+ {
+ xRes = new HHConvDic( rName, aDicMainURL );
+ }
+ else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
+ nConvDicType == ConversionDictionaryType::SCHINESE_TCHINESE)
+ {
+ xRes = new ConvDic( rName, nLang, nConvDicType, false, aDicMainURL );
+ }
+
+ if (!xRes.is())
+ throw NoSupportException();
+
+ xRes->setActive( true );
+ GetNameContainer().insertByName( rName, Any(xRes) );
+ return xRes;
+}
+
+uno::Sequence< OUString > SAL_CALL ConvDicList::queryConversions(
+ const OUString& rText,
+ sal_Int32 nStartPos,
+ sal_Int32 nLength,
+ const Locale& rLocale,
+ sal_Int16 nConversionDictionaryType,
+ ConversionDirection eDirection,
+ sal_Int32 nTextConversionOptions )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ std::vector< OUString > aRes;
+
+ bool bSupported = false;
+ sal_Int32 nLen = GetNameContainer().GetCount();
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
+ bool bMatch = xDic.is() &&
+ xDic->getLocale() == rLocale &&
+ xDic->getConversionType() == nConversionDictionaryType;
+ bSupported |= bMatch;
+ if (bMatch && xDic->isActive())
+ {
+ const Sequence< OUString > aNewConv( xDic->getConversions(
+ rText, nStartPos, nLength,
+ eDirection, nTextConversionOptions ) );
+ aRes.insert( aRes.end(), aNewConv.begin(), aNewConv.end() );
+ }
+ }
+
+ if (!bSupported)
+ throw NoSupportException();
+
+ return comphelper::containerToSequence(aRes);
+}
+
+sal_Int16 SAL_CALL ConvDicList::queryMaxCharCount(
+ const Locale& rLocale,
+ sal_Int16 nConversionDictionaryType,
+ ConversionDirection eDirection )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ sal_Int16 nRes = 0;
+ GetNameContainer();
+ sal_Int32 nLen = GetNameContainer().GetCount();
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
+ if (xDic.is() &&
+ xDic->getLocale() == rLocale &&
+ xDic->getConversionType() == nConversionDictionaryType)
+ {
+ sal_Int16 nC = xDic->getMaxCharCount( eDirection );
+ if (nC > nRes)
+ nRes = nC;
+ }
+ }
+ return nRes;
+}
+
+void SAL_CALL ConvDicList::dispose( )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ if (!bDisposing)
+ {
+ bDisposing = true;
+ EventObject aEvtObj( static_cast<XConversionDictionaryList *>(this) );
+ aEvtListeners.disposeAndClear( aEvtObj );
+
+ FlushDics();
+ }
+}
+
+void SAL_CALL ConvDicList::addEventListener(
+ const uno::Reference< XEventListener >& rxListener )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ if (!bDisposing && rxListener.is())
+ aEvtListeners.addInterface( rxListener );
+}
+
+void SAL_CALL ConvDicList::removeEventListener(
+ const uno::Reference< XEventListener >& rxListener )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ if (!bDisposing && rxListener.is())
+ aEvtListeners.removeInterface( rxListener );
+}
+
+OUString SAL_CALL ConvDicList::getImplementationName()
+{
+ return "com.sun.star.lingu2.ConvDicList";
+}
+
+sal_Bool SAL_CALL ConvDicList::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL ConvDicList::getSupportedServiceNames()
+{
+ return { "com.sun.star.linguistic2.ConversionDictionaryList" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+linguistic_ConvDicList_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(StaticConvDicList().get());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */