blob: 7be68a361e2b29c691d13564bf149c83dbb1370d [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_linguistic.hxx"
#include <tools/fsys.hxx>
#include <tools/stream.hxx>
#include <tools/urlobj.hxx>
#include <unotools/pathoptions.hxx>
#include <unotools/useroptions.hxx>
#include <unotools/lingucfg.hxx>
#include <rtl/instance.hxx>
#include <cppuhelper/factory.hxx> // helper for factories
#include <unotools/localfilehelper.hxx>
#include <com/sun/star/linguistic2/XConversionDictionaryList.hpp>
#include <com/sun/star/linguistic2/XConversionDictionary.hpp>
#include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
#include <com/sun/star/util/XFlushable.hpp>
#include <com/sun/star/lang/Locale.hpp>
#ifndef _COM_SUN_STAR_UNO_REFERENCE_HPP_
#include <com/sun/star/uno/Reference.h>
#endif
#include <com/sun/star/registry/XRegistryKey.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <ucbhelper/content.hxx>
#include "convdiclist.hxx"
#include "convdic.hxx"
#include "hhconvdic.hxx"
#include "linguistic/misc.hxx"
#include "defs.hxx"
//using namespace utl;
using namespace osl;
using namespace rtl;
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;
#define SN_CONV_DICTIONARY_LIST "com.sun.star.linguistic2.ConversionDictionaryList"
///////////////////////////////////////////////////////////////////////////
bool operator == ( const Locale &r1, const Locale &r2 )
{
return r1.Language == r2.Language &&
r1.Country == r2.Country &&
r1.Variant == r2.Variant;
}
///////////////////////////////////////////////////////////////////////////
String GetConvDicMainURL( const String &rDicName, const String &rDirectoryURL )
{
// build URL to use for new (persistent) dictionaries
String aFullDicName( rDicName );
aFullDicName.AppendAscii( CONV_DIC_DOT_EXT );
INetURLObject aURLObj;
aURLObj.SetSmartProtocol( INET_PROT_FILE );
aURLObj.SetSmartURL( rDirectoryURL );
aURLObj.Append( aFullDicName, INetURLObject::ENCODE_ALL );
DBG_ASSERT(!aURLObj.HasError(), "invalid URL");
if (aURLObj.HasError())
return String();
else
return aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
}
///////////////////////////////////////////////////////////////////////////
class ConvDicNameContainer :
public cppu::WeakImplHelper1
<
::com::sun::star::container::XNameContainer
>
{
uno::Sequence< uno::Reference< XConversionDictionary > > aConvDics;
ConvDicList &rConvDicList;
// disallow copy-constructor and assignment-operator for now
ConvDicNameContainer(const ConvDicNameContainer &);
ConvDicNameContainer & operator = (const ConvDicNameContainer &);
sal_Int32 GetIndexByName_Impl( const OUString& rName );
public:
ConvDicNameContainer( ConvDicList &rMyConvDicList );
virtual ~ConvDicNameContainer();
// XElementAccess
virtual ::com::sun::star::uno::Type SAL_CALL getElementType( ) throw (::com::sun::star::uno::RuntimeException);
virtual sal_Bool SAL_CALL hasElements( ) throw (::com::sun::star::uno::RuntimeException);
// XNameAccess
virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames( ) throw (::com::sun::star::uno::RuntimeException);
virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (::com::sun::star::uno::RuntimeException);
// XNameReplace
virtual void SAL_CALL replaceByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
// XNameContainer
virtual void SAL_CALL insertByName( const ::rtl::OUString& aName, const ::com::sun::star::uno::Any& aElement ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
virtual void SAL_CALL removeByName( const ::rtl::OUString& Name ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
// looks for conversion dictionaries with the specified extension
// in the directory and adds them to the container
void AddConvDics( const String &rSearchDirPathURL, const String &rExtension );
// calls Flush for the dictionaries that support XFlushable
void FlushDics() const;
sal_Int32 GetCount() const { return aConvDics.getLength(); }
uno::Reference< XConversionDictionary > GetByName( const OUString& rName );
const uno::Reference< XConversionDictionary > GetByIndex( sal_Int32 nIdx )
{
return aConvDics.getConstArray()[nIdx];
}
};
ConvDicNameContainer::ConvDicNameContainer( ConvDicList &rMyConvDicList ) :
rConvDicList( rMyConvDicList )
{
}
ConvDicNameContainer::~ConvDicNameContainer()
{
}
void ConvDicNameContainer::FlushDics() const
{
sal_Int32 nLen = aConvDics.getLength();
const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
for (sal_Int32 i = 0; i < nLen; ++i)
{
uno::Reference< util::XFlushable > xFlush( pDic[i] , UNO_QUERY );
if (xFlush.is())
{
try
{
xFlush->flush();
}
catch(Exception &)
{
DBG_ERROR( "flushing of conversion dictionary failed" );
}
}
}
}
sal_Int32 ConvDicNameContainer::GetIndexByName_Impl(
const OUString& rName )
{
sal_Int32 nRes = -1;
sal_Int32 nLen = aConvDics.getLength();
const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
for (sal_Int32 i = 0; i < nLen && nRes == -1; ++i)
{
if (rName == pDic[i]->getName())
nRes = i;
}
return nRes;
}
uno::Reference< XConversionDictionary > ConvDicNameContainer::GetByName(
const OUString& rName )
{
uno::Reference< XConversionDictionary > xRes;
sal_Int32 nIdx = GetIndexByName_Impl( rName );
if ( nIdx != -1)
xRes = aConvDics.getArray()[nIdx];
return xRes;
}
uno::Type SAL_CALL ConvDicNameContainer::getElementType( )
throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
return uno::Type( ::getCppuType( (uno::Reference< XConversionDictionary > *) 0) );
}
sal_Bool SAL_CALL ConvDicNameContainer::hasElements( )
throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
return aConvDics.getLength() > 0;
}
uno::Any SAL_CALL ConvDicNameContainer::getByName( const OUString& rName )
throw (NoSuchElementException, WrappedTargetException, RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
uno::Reference< XConversionDictionary > xRes( GetByName( rName ) );
if (!xRes.is())
throw NoSuchElementException();
return makeAny( xRes );
}
uno::Sequence< OUString > SAL_CALL ConvDicNameContainer::getElementNames( )
throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
sal_Int32 nLen = aConvDics.getLength();
uno::Sequence< OUString > aRes( nLen );
OUString *pName = aRes.getArray();
const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
for (sal_Int32 i = 0; i < nLen; ++i)
pName[i] = pDic[i]->getName();
return aRes;
}
sal_Bool SAL_CALL ConvDicNameContainer::hasByName( const OUString& rName )
throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
return GetByName( rName ).is();
}
void SAL_CALL ConvDicNameContainer::replaceByName(
const OUString& rName,
const uno::Any& rElement )
throw (IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException)
{
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.getArray()[ nRplcIdx ] = xNew;
}
void SAL_CALL ConvDicNameContainer::insertByName(
const OUString& rName,
const Any& rElement )
throw (IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
if (GetByName( rName ).is())
throw ElementExistException();
uno::Reference< XConversionDictionary > xNew;
rElement >>= xNew;
if (!xNew.is() || xNew->getName() != rName)
throw IllegalArgumentException();
sal_Int32 nLen = aConvDics.getLength();
aConvDics.realloc( nLen + 1 );
aConvDics.getArray()[ nLen ] = xNew;
}
void SAL_CALL ConvDicNameContainer::removeByName( const OUString& rName )
throw (NoSuchElementException, WrappedTargetException, RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
if (nRplcIdx == -1)
throw NoSuchElementException();
// physically remove dictionary
uno::Reference< XConversionDictionary > xDel = aConvDics.getArray()[nRplcIdx];
String aName( xDel->getName() );
String aDicMainURL( GetConvDicMainURL( aName, GetDictionaryWriteablePath() ) );
INetURLObject aObj( aDicMainURL );
DBG_ASSERT( aObj.GetProtocol() == INET_PROT_FILE, "+HangulHanjaOptionsDialog::OkHdl(): non-file URLs cannot be deleted" );
if( aObj.GetProtocol() == INET_PROT_FILE )
{
try
{
::ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ),
uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () );
aCnt.executeCommand( OUString::createFromAscii( "delete" ), makeAny( sal_Bool( sal_True ) ) );
}
catch( ::com::sun::star::ucb::CommandAbortedException& )
{
DBG_ERRORFILE( "HangulHanjaOptionsDialog::OkHdl(): CommandAbortedException" );
}
catch( ... )
{
DBG_ERRORFILE( "HangulHanjaOptionsDialog::OkHdl(): Any other exception" );
}
}
sal_Int32 nLen = aConvDics.getLength();
uno::Reference< XConversionDictionary > *pDic = aConvDics.getArray();
for (sal_Int32 i = nRplcIdx; i < nLen - 1; ++i)
pDic[i] = pDic[i + 1];
aConvDics.realloc( nLen - 1 );
}
void ConvDicNameContainer::AddConvDics(
const String &rSearchDirPathURL,
const String &rExtension )
{
const Sequence< OUString > aDirCnt(
utl::LocalFileHelper::GetFolderContents( rSearchDirPathURL, sal_False ) );
const OUString *pDirCnt = aDirCnt.getConstArray();
sal_Int32 nEntries = aDirCnt.getLength();
for (sal_Int32 i = 0; i < nEntries; ++i)
{
String aURL( pDirCnt[i] );
xub_StrLen nPos = aURL.SearchBackward('.');
String aExt(aURL.Copy(nPos + 1));
aExt.ToLowerAscii();
String aSearchExt( rExtension );
aSearchExt.ToLowerAscii();
if(aExt != aSearchExt)
continue; // skip other files
sal_Int16 nLang;
sal_Int16 nConvType;
if (IsConvDic( aURL, nLang, nConvType ))
{
// get decoded dictionary file name
INetURLObject aURLObj( aURL );
String aDicName = aURLObj.getBase( INetURLObject::LAST_SEGMENT,
true, INetURLObject::DECODE_WITH_CHARSET,
RTL_TEXTENCODING_UTF8 );
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, sal_False, aURL );
}
if (xDic.is())
{
uno::Any aAny;
aAny <<= xDic;
insertByName( xDic->getName(), aAny );
}
}
}
}
///////////////////////////////////////////////////////////////////////////
namespace
{
struct StaticConvDicList : public rtl::StaticWithInit<
uno::Reference<XInterface>, StaticConvDicList> {
uno::Reference<XInterface> operator () () {
return (cppu::OWeakObject *) new ConvDicList;
}
};
}
void ConvDicList::MyAppExitListener::AtExit()
{
rMyDicList.FlushDics();
StaticConvDicList::get().clear();
}
ConvDicList::ConvDicList() :
aEvtListeners( GetLinguMutex() )
{
pNameContainer = 0;
bDisposing = sal_False;
pExitListener = new MyAppExitListener( *this );
xExitListener = pExitListener;
pExitListener->Activate();
}
ConvDicList::~ConvDicList()
{
// NameContainer will deleted when the reference xNameContainer
// is destroyed.
// delete pNameContainer;
if (!bDisposing && pNameContainer)
pNameContainer->FlushDics();
pExitListener->Deactivate();
}
void ConvDicList::FlushDics()
{
// check only pointer to avoid creating the container when
// the dictionaries were not accessed yet
if (pNameContainer)
pNameContainer->FlushDics();
}
ConvDicNameContainer & ConvDicList::GetNameContainer()
{
if (!pNameContainer)
{
pNameContainer = new ConvDicNameContainer( *this );
pNameContainer->AddConvDics( GetDictionaryWriteablePath(),
A2OU( CONV_DIC_EXT ) );
xNameContainer = pNameContainer;
// access list of text conversion dictionaries to activate
SvtLinguOptions aOpt;
SvtLinguConfig().GetOptions( aOpt );
sal_Int32 nLen = aOpt.aActiveConvDics.getLength();
const OUString *pActiveConvDics = aOpt.aActiveConvDics.getConstArray();
for (sal_Int32 i = 0; i < nLen; ++i)
{
uno::Reference< XConversionDictionary > xDic =
pNameContainer->GetByName( pActiveConvDics[i] );
if (xDic.is())
xDic->setActive( sal_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(
pNameContainer->GetByName( A2OU("ChineseS2T") ), UNO_QUERY );
uno::Reference< XConversionDictionary > xT2SDic(
pNameContainer->GetByName( A2OU("ChineseT2S") ), UNO_QUERY );
if (xS2TDic.is())
xS2TDic->setActive( sal_True );
if (xT2SDic.is())
xT2SDic->setActive( sal_True );
}
return *pNameContainer;
}
uno::Reference< container::XNameContainer > SAL_CALL ConvDicList::getDictionaryContainer( ) throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
GetNameContainer();
DBG_ASSERT( xNameContainer.is(), "missing name container" );
return xNameContainer;
}
uno::Reference< XConversionDictionary > SAL_CALL ConvDicList::addNewDictionary(
const OUString& rName,
const Locale& rLocale,
sal_Int16 nConvDicType )
throw (NoSupportException, ElementExistException, RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
sal_Int16 nLang = LocaleToLanguage( rLocale );
if (GetNameContainer().hasByName( rName ))
throw ElementExistException();
uno::Reference< XConversionDictionary > xRes;
String 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, sal_False, aDicMainURL );
}
if (!xRes.is())
throw NoSupportException();
else
{
xRes->setActive( sal_True );
uno::Any aAny;
aAny <<= xRes;
GetNameContainer().insertByName( rName, aAny );
}
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 )
throw (IllegalArgumentException, NoSupportException, RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
/*sal_Int16 nLang = LocaleToLanguage( rLocale );*/
sal_Int32 nCount = 0;
uno::Sequence< OUString > aRes( 20 );
OUString *pRes = aRes.getArray();
sal_Bool bSupported = sal_False;
sal_Int32 nLen = GetNameContainer().GetCount();
for (sal_Int32 i = 0; i < nLen; ++i)
{
const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
sal_Bool bMatch = xDic.is() &&
xDic->getLocale() == rLocale &&
xDic->getConversionType() == nConversionDictionaryType;
bSupported |= bMatch;
if (bMatch && xDic->isActive())
{
Sequence< OUString > aNewConv( xDic->getConversions(
rText, nStartPos, nLength,
eDirection, nTextConversionOptions ) );
sal_Int32 nNewLen = aNewConv.getLength();
if (nNewLen > 0)
{
if (nCount + nNewLen > aRes.getLength())
{
aRes.realloc( nCount + nNewLen + 20 );
pRes = aRes.getArray();
}
const OUString *pNewConv = aNewConv.getConstArray();
for (sal_Int32 k = 0; k < nNewLen; ++k)
pRes[nCount++] = pNewConv[k];
}
}
}
if (!bSupported)
throw NoSupportException();
aRes.realloc( nCount );
return aRes;
}
sal_Int16 SAL_CALL ConvDicList::queryMaxCharCount(
const Locale& rLocale,
sal_Int16 nConversionDictionaryType,
ConversionDirection eDirection )
throw (RuntimeException)
{
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( )
throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
if (!bDisposing)
{
bDisposing = sal_True;
EventObject aEvtObj( (XConversionDictionaryList *) this );
aEvtListeners.disposeAndClear( aEvtObj );
FlushDics();
}
}
void SAL_CALL ConvDicList::addEventListener(
const uno::Reference< XEventListener >& rxListener )
throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
if (!bDisposing && rxListener.is())
aEvtListeners.addInterface( rxListener );
}
void SAL_CALL ConvDicList::removeEventListener(
const uno::Reference< XEventListener >& rxListener )
throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
if (!bDisposing && rxListener.is())
aEvtListeners.removeInterface( rxListener );
}
OUString SAL_CALL ConvDicList::getImplementationName( )
throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
return getImplementationName_Static();
}
sal_Bool SAL_CALL ConvDicList::supportsService( const OUString& rServiceName )
throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
return rServiceName.equalsAscii( SN_CONV_DICTIONARY_LIST );
}
uno::Sequence< OUString > SAL_CALL ConvDicList::getSupportedServiceNames( )
throw (RuntimeException)
{
MutexGuard aGuard( GetLinguMutex() );
return getSupportedServiceNames_Static();
}
uno::Sequence< OUString > ConvDicList::getSupportedServiceNames_Static()
throw()
{
uno::Sequence< OUString > aSNS( 1 );
aSNS.getArray()[0] = A2OU( SN_CONV_DICTIONARY_LIST );
return aSNS;
}
///////////////////////////////////////////////////////////////////////////
uno::Reference< uno::XInterface > SAL_CALL ConvDicList_CreateInstance(
const uno::Reference< XMultiServiceFactory > & /*rSMgr*/ )
throw(Exception)
{
return StaticConvDicList::get();
}
void * SAL_CALL ConvDicList_getFactory(
const sal_Char * pImplName,
XMultiServiceFactory * pServiceManager, void * )
{
void * pRet = 0;
if ( !ConvDicList::getImplementationName_Static().compareToAscii( pImplName ) )
{
uno::Reference< XSingleServiceFactory > xFactory =
cppu::createOneInstanceFactory(
pServiceManager,
ConvDicList::getImplementationName_Static(),
ConvDicList_CreateInstance,
ConvDicList::getSupportedServiceNames_Static());
// acquire, because we return an interface pointer instead of a reference
xFactory->acquire();
pRet = xFactory.get();
}
return pRet;
}
///////////////////////////////////////////////////////////////////////////