From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- linguistic/source/convdiclist.cxx | 539 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 539 insertions(+) create mode 100644 linguistic/source/convdiclist.cxx (limited to 'linguistic/source/convdiclist.cxx') 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "convdic.hxx" +#include "convdiclist.hxx" +#include "hhconvdic.hxx" +#include + +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::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 aRes; + aRes.reserve(aConvDics.size()); + + std::transform(aConvDics.begin(), aConvDics.end(), std::back_inserter(aRes), + [](const uno::Reference& 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& StaticConvDicList() + { + static rtl::Reference 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(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 const&) +{ + return cppu::acquire(StaticConvDicList().get()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3