summaryrefslogtreecommitdiff
path: root/linguistic/source
diff options
context:
space:
mode:
Diffstat (limited to 'linguistic/source')
-rw-r--r--linguistic/source/convdic.cxx744
-rw-r--r--linguistic/source/convdic.hxx179
-rw-r--r--linguistic/source/convdiclist.cxx741
-rw-r--r--linguistic/source/convdiclist.hxx122
-rw-r--r--linguistic/source/convdicxml.cxx462
-rw-r--r--linguistic/source/convdicxml.hxx134
-rw-r--r--linguistic/source/defs.hxx136
-rwxr-xr-xlinguistic/source/dicimp.cxx1207
-rw-r--r--linguistic/source/dicimp.hxx238
-rw-r--r--linguistic/source/dlistimp.cxx969
-rw-r--r--linguistic/source/dlistimp.hxx151
-rw-r--r--linguistic/source/gciterator.cxx1359
-rw-r--r--linguistic/source/gciterator.hxx209
-rw-r--r--linguistic/source/grammarchecker.cxx326
-rw-r--r--linguistic/source/grammarchecker.hxx108
-rw-r--r--linguistic/source/hhconvdic.cxx169
-rw-r--r--linguistic/source/hhconvdic.hxx78
-rw-r--r--linguistic/source/hyphdsp.cxx736
-rw-r--r--linguistic/source/hyphdsp.hxx172
-rw-r--r--linguistic/source/hyphdta.cxx189
-rw-r--r--linguistic/source/iprcache.cxx284
-rw-r--r--linguistic/source/lngopt.cxx711
-rw-r--r--linguistic/source/lngopt.hxx186
-rw-r--r--linguistic/source/lngprophelp.cxx717
-rw-r--r--linguistic/source/lngreg.cxx198
-rw-r--r--linguistic/source/lngsvcmgr.cxx2042
-rw-r--r--linguistic/source/lngsvcmgr.hxx199
-rw-r--r--linguistic/source/makefile.mk111
-rw-r--r--linguistic/source/misc.cxx1009
-rw-r--r--linguistic/source/misc2.cxx300
-rw-r--r--linguistic/source/spelldsp.cxx871
-rw-r--r--linguistic/source/spelldsp.hxx163
-rw-r--r--linguistic/source/spelldta.cxx366
-rw-r--r--linguistic/source/thesdsp.cxx282
-rw-r--r--linguistic/source/thesdsp.hxx129
-rw-r--r--linguistic/source/thesdta.cxx83
36 files changed, 16080 insertions, 0 deletions
diff --git a/linguistic/source/convdic.cxx b/linguistic/source/convdic.cxx
new file mode 100644
index 000000000000..0b7245eb3019
--- /dev/null
+++ b/linguistic/source/convdic.cxx
@@ -0,0 +1,744 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+#include <cppuhelper/factory.hxx>
+#include <i18npool/lang.h>
+#include <osl/mutex.hxx>
+#include <tools/debug.hxx>
+#include <tools/fsys.hxx>
+#include <tools/stream.hxx>
+#include <tools/stream.hxx>
+#include <tools/string.hxx>
+#include <tools/urlobj.hxx>
+#include <ucbhelper/content.hxx>
+#include <unotools/processfactory.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+
+#include <com/sun/star/linguistic2/XConversionDictionary.hpp>
+#include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
+#include <com/sun/star/linguistic2/XConversionPropertyType.hpp>
+#include <com/sun/star/linguistic2/ConversionPropertyType.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/lang/EventObject.hpp>
+#include <com/sun/star/ucb/XSimpleFileAccess.hpp>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/util/XFlushListener.hpp>
+#include <com/sun/star/io/XActiveDataSource.hpp>
+#include <com/sun/star/io/XActiveDataSource.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/xml/sax/InputSource.hpp>
+#include <com/sun/star/xml/sax/XParser.hpp>
+
+
+#include "convdic.hxx"
+#include "convdicxml.hxx"
+#include "misc.hxx"
+#include "defs.hxx"
+
+using namespace std;
+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::linguistic2;
+using namespace linguistic;
+
+#define SN_CONV_DICTIONARY "com.sun.star.linguistic2.ConversionDictionary"
+#define SN_HCD_CONV_DICTIONARY "com.sun.star.linguistic2.HangulHanjaConversionDictionary"
+
+
+///////////////////////////////////////////////////////////////////////////
+void ReadThroughDic( const String &rMainURL, ConvDicXMLImport &rImport )
+{
+ if (rMainURL.Len() == 0)
+ return;
+ DBG_ASSERT(!INetURLObject( rMainURL ).HasError(), "invalid URL");
+
+ uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() );
+
+ // get xInputStream stream
+ uno::Reference< io::XInputStream > xIn;
+ try
+ {
+ uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance(
+ A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW );
+ xIn = xAccess->openFileRead( rMainURL );
+ }
+ catch (uno::Exception & e)
+ {
+ DBG_ASSERT( 0, "failed to get input stream" );
+ (void) e;
+ }
+ if (!xIn.is())
+ return;
+
+ SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xIn ) );
+
+ ULONG nError = sal::static_int_cast< ULONG >(-1);
+
+ // prepare ParserInputSource
+ xml::sax::InputSource aParserInput;
+ aParserInput.aInputStream = xIn;
+
+ // get parser
+ uno::Reference< xml::sax::XParser > xParser;
+ try
+ {
+ xParser = uno::Reference< xml::sax::XParser >( xServiceFactory->createInstance(
+ A2OU( "com.sun.star.xml.sax.Parser" ) ), UNO_QUERY );
+ }
+ catch (uno::Exception &)
+ {
+ }
+ DBG_ASSERT( xParser.is(), "Can't create parser" );
+ if (!xParser.is())
+ return;
+
+ // get filter
+ //ConvDicXMLImport *pImport = new ConvDicXMLImport( this, rMainURL );
+ //!! keep a reference until everything is done to
+ //!! ensure the proper lifetime of the object
+ uno::Reference < xml::sax::XDocumentHandler > xFilter(
+ (xml::sax::XExtendedDocumentHandler *) &rImport, UNO_QUERY );
+
+ // connect parser and filter
+ xParser->setDocumentHandler( xFilter );
+
+ // finally, parser the stream
+ try
+ {
+ xParser->parseStream( aParserInput ); // implicitly calls ConvDicXMLImport::CreateContext
+ if (rImport.GetSuccess())
+ nError = 0;
+ }
+ catch( xml::sax::SAXParseException& )
+ {
+// if( bEncrypted )
+// nError = ERRCODE_SFX_WRONGPASSWORD;
+ }
+ catch( xml::sax::SAXException& )
+ {
+// if( bEncrypted )
+// nError = ERRCODE_SFX_WRONGPASSWORD;
+ }
+ catch( io::IOException& )
+ {
+ }
+}
+
+BOOL IsConvDic( const String &rFileURL, INT16 &nLang, sal_Int16 &nConvType )
+{
+ BOOL bRes = FALSE;
+
+ if (rFileURL.Len() == 0)
+ return bRes;
+
+ // check if file extension matches CONV_DIC_EXT
+ String aExt;
+ xub_StrLen nPos = rFileURL.SearchBackward( '.' );
+ if (STRING_NOTFOUND != nPos)
+ aExt = rFileURL.Copy( nPos + 1 );
+ aExt.ToLowerAscii();
+ if (!aExt.EqualsAscii( CONV_DIC_EXT ))
+ return bRes;
+
+ // first argument being 0 should stop the file from being parsed
+ // up to the end (reading all entries) when the required
+ // data (language, conversion type) is found.
+ ConvDicXMLImport *pImport = new ConvDicXMLImport( 0, rFileURL );
+
+ //!! keep a first reference to ensure the lifetime of the object !!
+ uno::Reference< XInterface > xRef( (document::XFilter *) pImport, UNO_QUERY );
+
+ ReadThroughDic( rFileURL, *pImport ); // will implicitly add the entries
+ bRes = pImport->GetLanguage() != LANGUAGE_NONE &&
+ pImport->GetConversionType() != -1;
+ DBG_ASSERT( bRes, "conversion dictionary corrupted?" );
+
+ if (bRes)
+ {
+ nLang = pImport->GetLanguage();
+ nConvType = pImport->GetConversionType();
+ }
+
+ return bRes;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+ConvDic::ConvDic(
+ const String &rName,
+ INT16 nLang,
+ sal_Int16 nConvType,
+ BOOL bBiDirectional,
+ const String &rMainURL) :
+ aFlushListeners( GetLinguMutex() )
+{
+ aName = rName;
+ nLanguage = nLang;
+ nConversionType = nConvType;
+ aMainURL = rMainURL;
+
+ if (bBiDirectional)
+ pFromRight = std::auto_ptr< ConvMap >( new ConvMap );
+ if (nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL)
+ pConvPropType = std::auto_ptr< PropTypeMap >( new PropTypeMap );
+
+ nMaxLeftCharCount = nMaxRightCharCount = 0;
+ bMaxCharCountIsValid = TRUE;
+
+ bNeedEntries = TRUE;
+ bIsModified = bIsActive = FALSE;
+ bIsReadonly = FALSE;
+
+ if( rMainURL.Len() > 0 )
+ {
+ BOOL bExists = FALSE;
+ bIsReadonly = IsReadOnly( rMainURL, &bExists );
+
+ if( !bExists ) // new empty dictionary
+ {
+ bNeedEntries = FALSE;
+ //! create physical representation of an **empty** dictionary
+ //! that could be found by the dictionary-list implementation
+ // (Note: empty dictionaries are not just empty files!)
+ Save();
+ bIsReadonly = IsReadOnly( rMainURL ); // will be FALSE if Save was succesfull
+ }
+ }
+ else
+ {
+ bNeedEntries = FALSE;
+ }
+}
+
+
+ConvDic::~ConvDic()
+{
+}
+
+
+void ConvDic::Load()
+{
+ DBG_ASSERT( !bIsModified, "dictionary is modified. Really do 'Load'?" );
+
+ //!! prevent function from being called recursively via HasEntry, AddEntry
+ bNeedEntries = FALSE;
+ ConvDicXMLImport *pImport = new ConvDicXMLImport( this, aMainURL );
+ //!! keep a first reference to ensure the lifetime of the object !!
+ uno::Reference< XInterface > xRef( (document::XFilter *) pImport, UNO_QUERY );
+ ReadThroughDic( aMainURL, *pImport ); // will implicitly add the entries
+ bIsModified = FALSE;
+}
+
+
+void ConvDic::Save()
+{
+ DBG_ASSERT( !bNeedEntries, "saving while entries missing" );
+ if (aMainURL.Len() == 0 || bNeedEntries)
+ return;
+ DBG_ASSERT(!INetURLObject( aMainURL ).HasError(), "invalid URL");
+
+ uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() );
+
+ // get XOutputStream stream
+ uno::Reference< io::XStream > xStream;
+ try
+ {
+ uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance(
+ A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW );
+ xStream = xAccess->openFileReadWrite( aMainURL );
+ }
+ catch (uno::Exception & e)
+ {
+ DBG_ASSERT( 0, "failed to get input stream" );
+ (void) e;
+ }
+ if (!xStream.is())
+ return;
+
+ SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) );
+
+ // get XML writer
+ uno::Reference< io::XActiveDataSource > xSaxWriter;
+ if (xServiceFactory.is())
+ {
+ try
+ {
+ xSaxWriter = uno::Reference< io::XActiveDataSource >(
+ xServiceFactory->createInstance(
+ OUString::createFromAscii( "com.sun.star.xml.sax.Writer" ) ), UNO_QUERY );
+ }
+ catch (uno::Exception &)
+ {
+ }
+ }
+ DBG_ASSERT( xSaxWriter.is(), "can't instantiate XML writer" );
+
+ if (xSaxWriter.is() && xStream.is())
+ {
+ // connect XML writer to output stream
+ xSaxWriter->setOutputStream( xStream->getOutputStream() );
+
+ // prepare arguments (prepend doc handler to given arguments)
+ uno::Reference< xml::sax::XDocumentHandler > xDocHandler( xSaxWriter, UNO_QUERY );
+ ConvDicXMLExport *pExport = new ConvDicXMLExport( *this, aMainURL, xDocHandler );
+ //!! keep a first(!) reference until everything is done to
+ //!! ensure the proper lifetime of the object
+ uno::Reference< document::XFilter > aRef( (document::XFilter *) pExport );
+ sal_Bool bRet = pExport->Export(); // write entries to file
+ DBG_ASSERT( !pStream->GetError(), "I/O error while writing to stream" );
+ if (bRet)
+ bIsModified = FALSE;
+ }
+ DBG_ASSERT( !bIsModified, "dictionary still modified after save. Save failed?" );
+}
+
+
+ConvMap::iterator ConvDic::GetEntry( ConvMap &rMap, const rtl::OUString &rFirstText, const rtl::OUString &rSecondText )
+{
+ pair< ConvMap::iterator, ConvMap::iterator > aRange =
+ rMap.equal_range( rFirstText );
+ ConvMap::iterator aPos = rMap.end();
+ for (ConvMap::iterator aIt = aRange.first;
+ aIt != aRange.second && aPos == rMap.end();
+ ++aIt)
+ {
+ if ((*aIt).second == rSecondText)
+ aPos = aIt;
+ }
+ return aPos;
+}
+
+
+BOOL ConvDic::HasEntry( const OUString &rLeftText, const OUString &rRightText )
+{
+ if (bNeedEntries)
+ Load();
+ ConvMap::iterator aIt = GetEntry( aFromLeft, rLeftText, rRightText );
+ return aIt != aFromLeft.end();
+}
+
+
+void ConvDic::AddEntry( const OUString &rLeftText, const OUString &rRightText )
+{
+ if (bNeedEntries)
+ Load();
+
+ DBG_ASSERT(!HasEntry( rLeftText, rRightText), "entry already exists" );
+ aFromLeft .insert( ConvMap::value_type( rLeftText, rRightText ) );
+ if (pFromRight.get())
+ pFromRight->insert( ConvMap::value_type( rRightText, rLeftText ) );
+
+ if (bMaxCharCountIsValid)
+ {
+ if (rLeftText.getLength() > nMaxLeftCharCount)
+ nMaxLeftCharCount = (sal_Int16) rLeftText.getLength();
+ if (pFromRight.get() && rRightText.getLength() > nMaxRightCharCount)
+ nMaxRightCharCount = (sal_Int16) rRightText.getLength();
+ }
+
+ bIsModified = TRUE;
+}
+
+
+void ConvDic::RemoveEntry( const OUString &rLeftText, const OUString &rRightText )
+{
+ if (bNeedEntries)
+ Load();
+
+ ConvMap::iterator aLeftIt = GetEntry( aFromLeft, rLeftText, rRightText );
+ DBG_ASSERT( aLeftIt != aFromLeft.end(), "left map entry missing" );
+ aFromLeft .erase( aLeftIt );
+
+ if (pFromRight.get())
+ {
+ ConvMap::iterator aRightIt = GetEntry( *pFromRight, rRightText, rLeftText );
+ DBG_ASSERT( aRightIt != pFromRight->end(), "right map entry missing" );
+ pFromRight->erase( aRightIt );
+ }
+
+ bIsModified = TRUE;
+ bMaxCharCountIsValid = FALSE;
+}
+
+
+OUString SAL_CALL ConvDic::getName( )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aName;
+}
+
+
+Locale SAL_CALL ConvDic::getLocale( )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return CreateLocale( nLanguage );
+}
+
+
+sal_Int16 SAL_CALL ConvDic::getConversionType( )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return nConversionType;
+}
+
+
+void SAL_CALL ConvDic::setActive( sal_Bool bActivate )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ bIsActive = bActivate;
+}
+
+
+sal_Bool SAL_CALL ConvDic::isActive( )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return bIsActive;
+}
+
+
+void SAL_CALL ConvDic::clear( )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ aFromLeft .clear();
+ if (pFromRight.get())
+ pFromRight->clear();
+ bNeedEntries = FALSE;
+ bIsModified = TRUE;
+ nMaxLeftCharCount = 0;
+ nMaxRightCharCount = 0;
+ bMaxCharCountIsValid = TRUE;
+}
+
+
+uno::Sequence< OUString > SAL_CALL ConvDic::getConversions(
+ const OUString& aText,
+ sal_Int32 nStartPos,
+ sal_Int32 nLength,
+ ConversionDirection eDirection,
+ sal_Int32 /*nTextConversionOptions*/ )
+ throw (IllegalArgumentException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (!pFromRight.get() && eDirection == ConversionDirection_FROM_RIGHT)
+ return uno::Sequence< OUString >();
+
+ if (bNeedEntries)
+ Load();
+
+ OUString aLookUpText( aText.copy(nStartPos, nLength) );
+ ConvMap &rConvMap = eDirection == ConversionDirection_FROM_LEFT ?
+ aFromLeft : *pFromRight;
+ pair< ConvMap::iterator, ConvMap::iterator > aRange =
+ rConvMap.equal_range( aLookUpText );
+
+ INT32 nCount = 0;
+ ConvMap::iterator aIt;
+ for (aIt = aRange.first; aIt != aRange.second; ++aIt)
+ ++nCount;
+
+ uno::Sequence< OUString > aRes( nCount );
+ OUString *pRes = aRes.getArray();
+ INT32 i = 0;
+ for (aIt = aRange.first; aIt != aRange.second; ++aIt)
+ pRes[i++] = (*aIt).second;
+
+ return aRes;
+}
+
+
+static BOOL lcl_SeqHasEntry(
+ const OUString *pSeqStart, // first element to check
+ INT32 nToCheck, // number of elements to check
+ const OUString &rText)
+{
+ BOOL bRes = FALSE;
+ if (pSeqStart && nToCheck > 0)
+ {
+ const OUString *pDone = pSeqStart + nToCheck; // one behind last to check
+ while (!bRes && pSeqStart != pDone)
+ {
+ if (*pSeqStart++ == rText)
+ bRes = TRUE;
+ }
+ }
+ return bRes;
+}
+
+uno::Sequence< OUString > SAL_CALL ConvDic::getConversionEntries(
+ ConversionDirection eDirection )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (!pFromRight.get() && eDirection == ConversionDirection_FROM_RIGHT)
+ return uno::Sequence< OUString >();
+
+ if (bNeedEntries)
+ Load();
+
+ ConvMap &rConvMap = eDirection == ConversionDirection_FROM_LEFT ?
+ aFromLeft : *pFromRight;
+ uno::Sequence< OUString > aRes( rConvMap.size() );
+ OUString *pRes = aRes.getArray();
+ ConvMap::iterator aIt = rConvMap.begin();
+ INT32 nIdx = 0;
+ while (aIt != rConvMap.end())
+ {
+ OUString aCurEntry( (*aIt).first );
+ // skip duplicate entries ( duplicate = duplicate entries
+ // respective to the evaluated side (FROM_LEFT or FROM_RIGHT).
+ // Thus if FROM_LEFT is evaluated for pairs (A,B) and (A,C)
+ // only one entry for A will be returned in the result)
+ if (nIdx == 0 || !lcl_SeqHasEntry( pRes, nIdx, aCurEntry ))
+ pRes[ nIdx++ ] = aCurEntry;
+ ++aIt;
+ }
+ aRes.realloc( nIdx );
+
+ return aRes;
+}
+
+
+void SAL_CALL ConvDic::addEntry(
+ const OUString& aLeftText,
+ const OUString& aRightText )
+ throw (IllegalArgumentException, container::ElementExistException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ if (bNeedEntries)
+ Load();
+ if (HasEntry( aLeftText, aRightText ))
+ throw container::ElementExistException();
+ AddEntry( aLeftText, aRightText );
+}
+
+
+void SAL_CALL ConvDic::removeEntry(
+ const OUString& aLeftText,
+ const OUString& aRightText )
+ throw (container::NoSuchElementException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ if (bNeedEntries)
+ Load();
+ if (!HasEntry( aLeftText, aRightText ))
+ throw container::NoSuchElementException();
+ RemoveEntry( aLeftText, aRightText );
+}
+
+
+sal_Int16 SAL_CALL ConvDic::getMaxCharCount( ConversionDirection eDirection )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (!pFromRight.get() && eDirection == ConversionDirection_FROM_RIGHT)
+ {
+ DBG_ASSERT( nMaxRightCharCount == 0, "max right char count should be 0" );
+ return 0;
+ }
+
+ if (bNeedEntries)
+ Load();
+
+ if (!bMaxCharCountIsValid)
+ {
+ nMaxLeftCharCount = 0;
+ ConvMap::iterator aIt = aFromLeft.begin();
+ while (aIt != aFromLeft.end())
+ {
+ sal_Int16 nTmp = (sal_Int16) (*aIt).first.getLength();
+ if (nTmp > nMaxLeftCharCount)
+ nMaxLeftCharCount = nTmp;
+ ++aIt;
+ }
+
+ nMaxRightCharCount = 0;
+ if (pFromRight.get())
+ {
+ aIt = pFromRight->begin();
+ while (aIt != pFromRight->end())
+ {
+ sal_Int16 nTmp = (sal_Int16) (*aIt).first.getLength();
+ if (nTmp > nMaxRightCharCount)
+ nMaxRightCharCount = nTmp;
+ ++aIt;
+ }
+ }
+
+ bMaxCharCountIsValid = TRUE;
+ }
+ sal_Int16 nRes = eDirection == ConversionDirection_FROM_LEFT ?
+ nMaxLeftCharCount : nMaxRightCharCount;
+ DBG_ASSERT( nRes >= 0, "invalid MaxCharCount" );
+ return nRes;
+}
+
+
+void SAL_CALL ConvDic::setPropertyType(
+ const OUString& rLeftText,
+ const OUString& rRightText,
+ sal_Int16 nPropertyType )
+ throw (container::NoSuchElementException, IllegalArgumentException, RuntimeException)
+{
+ sal_Bool bHasElement = HasEntry( rLeftText, rRightText);
+ if (!bHasElement)
+ throw container::NoSuchElementException();
+
+ // currently we assume that entries with the same left text have the
+ // same PropertyType even if the right text is different...
+ if (pConvPropType.get())
+ pConvPropType->insert( PropTypeMap::value_type( rLeftText, nPropertyType ) );
+ bIsModified = sal_True;
+}
+
+
+sal_Int16 SAL_CALL ConvDic::getPropertyType(
+ const OUString& rLeftText,
+ const OUString& rRightText )
+ throw (container::NoSuchElementException, RuntimeException)
+{
+ sal_Bool bHasElement = HasEntry( rLeftText, rRightText);
+ if (!bHasElement)
+ throw container::NoSuchElementException();
+
+ sal_Int16 nRes = ConversionPropertyType::NOT_DEFINED;
+ if (pConvPropType.get())
+ {
+ // still assuming that entries with same left text have same PropertyType
+ // even if they have different right text...
+ PropTypeMap::iterator aIt = pConvPropType->find( rLeftText );
+ if (aIt != pConvPropType->end())
+ nRes = (*aIt).second;
+ }
+ return nRes;
+}
+
+
+void SAL_CALL ConvDic::flush( )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bIsModified)
+ return;
+
+ Save();
+
+ // notify listeners
+ EventObject aEvtObj;
+ aEvtObj.Source = uno::Reference< XFlushable >( this );
+ cppu::OInterfaceIteratorHelper aIt( aFlushListeners );
+ while (aIt.hasMoreElements())
+ {
+ uno::Reference< util::XFlushListener > xRef( aIt.next(), UNO_QUERY );
+ if (xRef.is())
+ xRef->flushed( aEvtObj );
+ }
+}
+
+
+void SAL_CALL ConvDic::addFlushListener(
+ const uno::Reference< util::XFlushListener >& rxListener )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ if (rxListener.is())
+ aFlushListeners.addInterface( rxListener );
+}
+
+
+void SAL_CALL ConvDic::removeFlushListener(
+ const uno::Reference< util::XFlushListener >& rxListener )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ if (rxListener.is())
+ aFlushListeners.removeInterface( rxListener );
+}
+
+
+OUString SAL_CALL ConvDic::getImplementationName( )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return getImplementationName_Static();
+}
+
+
+sal_Bool SAL_CALL ConvDic::supportsService( const OUString& rServiceName )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ sal_Bool bRes = sal_False;
+ if (rServiceName.equalsAscii( SN_CONV_DICTIONARY ))
+ bRes = sal_True;
+ return bRes;
+}
+
+
+uno::Sequence< OUString > SAL_CALL ConvDic::getSupportedServiceNames( )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return getSupportedServiceNames_Static();
+}
+
+
+uno::Sequence< OUString > ConvDic::getSupportedServiceNames_Static()
+ throw()
+{
+ uno::Sequence< OUString > aSNS( 1 );
+ aSNS.getArray()[0] = A2OU( SN_CONV_DICTIONARY );
+ return aSNS;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+
diff --git a/linguistic/source/convdic.hxx b/linguistic/source/convdic.hxx
new file mode 100644
index 000000000000..c0a22da8a1f1
--- /dev/null
+++ b/linguistic/source/convdic.hxx
@@ -0,0 +1,179 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef _LINGUISTIC_CONVDIC_HXX_
+#define _LINGUISTIC_CONVDIC_HXX_
+
+#include <com/sun/star/linguistic2/XConversionDictionary.hpp>
+#include <com/sun/star/linguistic2/XConversionPropertyType.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase4.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <tools/string.hxx>
+
+#include <hash_map>
+#include <set>
+#include <memory>
+#include "misc.hxx"
+#include "defs.hxx"
+
+// text conversion dictionary extension
+#define CONV_DIC_EXT "tcd"
+#define CONV_DIC_DOT_EXT ".tcd"
+
+#define SN_CONV_DICTIONARY "com.sun.star.linguistic2.ConversionDictionary"
+
+
+class SvStream;
+
+///////////////////////////////////////////////////////////////////////////
+
+BOOL IsConvDic( const String &rFileURL, INT16 &nLang, sal_Int16 &nConvType );
+
+///////////////////////////////////////////////////////////////////////////
+
+struct StrLT
+{
+ bool operator()( const rtl::OUString &rTxt1, const rtl::OUString &rTxt2 ) const
+ {
+ return rTxt1 < rTxt2;
+ }
+};
+
+struct StrEQ
+{
+ bool operator()( const rtl::OUString &rTxt1, const rtl::OUString &rTxt2 ) const
+ {
+ return rTxt1 == rTxt2;
+ }
+};
+
+typedef std::hash_multimap< const rtl::OUString, rtl::OUString,
+ const rtl::OUStringHash, StrEQ > ConvMap;
+
+typedef std::set< rtl::OUString, StrLT > ConvMapKeySet;
+
+typedef std::hash_multimap< const rtl::OUString, sal_Int16,
+ rtl::OUStringHash, StrEQ > PropTypeMap;
+
+///////////////////////////////////////////////////////////////////////////
+
+class ConvDic :
+ public ::cppu::WeakImplHelper4
+ <
+ ::com::sun::star::linguistic2::XConversionDictionary,
+ ::com::sun::star::linguistic2::XConversionPropertyType,
+ ::com::sun::star::util::XFlushable,
+ ::com::sun::star::lang::XServiceInfo
+ >
+{
+ friend class ConvDicXMLExport;
+
+protected:
+
+ ::cppu::OInterfaceContainerHelper aFlushListeners;
+
+ ConvMap aFromLeft;
+ std::auto_ptr< ConvMap > pFromRight; // only available for bidirectional conversion dictionaries
+
+ std::auto_ptr< PropTypeMap > pConvPropType;
+
+ String aMainURL; // URL to file
+ rtl::OUString aName;
+ INT16 nLanguage;
+ sal_Int16 nConversionType;
+ sal_Int16 nMaxLeftCharCount;
+ sal_Int16 nMaxRightCharCount;
+ BOOL bMaxCharCountIsValid;
+ BOOL bNeedEntries;
+ BOOL bIsModified;
+ BOOL bIsActive;
+ BOOL bIsReadonly;
+
+ // disallow copy-constructor and assignment-operator for now
+ ConvDic(const ConvDic &);
+ ConvDic & operator = (const ConvDic &);
+
+ ConvMap::iterator GetEntry( ConvMap &rMap, const rtl::OUString &rFirstText, const rtl::OUString &rSecondText );
+ void Load();
+ void Save();
+
+public:
+ ConvDic( const String &rName,
+ INT16 nLanguage,
+ sal_Int16 nConversionType,
+ BOOL bBiDirectional,
+ const String &rMainURL);
+ virtual ~ConvDic();
+
+ // XConversionDictionary
+ virtual ::rtl::OUString SAL_CALL getName( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::lang::Locale SAL_CALL getLocale( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual sal_Int16 SAL_CALL getConversionType( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setActive( sal_Bool bActivate ) throw (::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL isActive( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL clear( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getConversions( const ::rtl::OUString& aText, sal_Int32 nStartPos, sal_Int32 nLength, ::com::sun::star::linguistic2::ConversionDirection eDirection, sal_Int32 nTextConversionOptions ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getConversionEntries( ::com::sun::star::linguistic2::ConversionDirection eDirection ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addEntry( const ::rtl::OUString& aLeftText, const ::rtl::OUString& aRightText ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeEntry( const ::rtl::OUString& aLeftText, const ::rtl::OUString& aRightText ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);
+ virtual sal_Int16 SAL_CALL getMaxCharCount( ::com::sun::star::linguistic2::ConversionDirection eDirection ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XConversionPropertyType
+ virtual void SAL_CALL setPropertyType( const ::rtl::OUString& aLeftText, const ::rtl::OUString& aRightText, ::sal_Int16 nPropertyType ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Int16 SAL_CALL getPropertyType( const ::rtl::OUString& aLeftText, const ::rtl::OUString& aRightText ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);
+
+ // XFlushable
+ virtual void SAL_CALL flush( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addFlushListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XFlushListener >& l ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeFlushListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XFlushListener >& l ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException);
+
+
+ static inline ::rtl::OUString
+ getImplementationName_Static() throw();
+ static com::sun::star::uno::Sequence< ::rtl::OUString >
+ getSupportedServiceNames_Static() throw();
+
+ BOOL HasEntry( const rtl::OUString &rLeftText, const rtl::OUString &rRightText );
+ void AddEntry( const rtl::OUString &rLeftText, const rtl::OUString &rRightText );
+ void RemoveEntry( const rtl::OUString &rLeftText, const rtl::OUString &rRightText );
+};
+
+inline ::rtl::OUString ConvDic::getImplementationName_Static() throw()
+{
+ return A2OU( "com.sun.star.lingu2.ConvDic" );
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/convdiclist.cxx b/linguistic/source/convdiclist.cxx
new file mode 100644
index 000000000000..2916b2ee6eec
--- /dev/null
+++ b/linguistic/source/convdiclist.cxx
@@ -0,0 +1,741 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 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 "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 &);
+
+ 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;
+
+ INT32 GetCount() const { return aConvDics.getLength(); }
+ uno::Reference< XConversionDictionary > GetByName( const OUString& rName );
+
+ const uno::Reference< XConversionDictionary > GetByIndex( INT32 nIdx )
+ {
+ return aConvDics.getConstArray()[nIdx];
+ }
+};
+
+
+ConvDicNameContainer::ConvDicNameContainer( ConvDicList &rMyConvDicList ) :
+ rConvDicList( rMyConvDicList )
+{
+}
+
+
+ConvDicNameContainer::~ConvDicNameContainer()
+{
+}
+
+
+void ConvDicNameContainer::FlushDics() const
+{
+ INT32 nLen = aConvDics.getLength();
+ const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
+ for (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" );
+ }
+ }
+ }
+}
+
+
+INT32 ConvDicNameContainer::GetIndexByName_Impl(
+ const OUString& rName )
+{
+ INT32 nRes = -1;
+ INT32 nLen = aConvDics.getLength();
+ const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
+ for (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;
+ 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() );
+
+ INT32 nLen = aConvDics.getLength();
+ uno::Sequence< OUString > aRes( nLen );
+ OUString *pName = aRes.getArray();
+ const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
+ for (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() );
+
+ 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();
+
+ 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() );
+
+ 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" );
+ }
+ }
+
+ INT32 nLen = aConvDics.getLength();
+ uno::Reference< XConversionDictionary > *pDic = aConvDics.getArray();
+ for (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, FALSE ) );
+ const OUString *pDirCnt = aDirCnt.getConstArray();
+ INT32 nEntries = aDirCnt.getLength();
+
+ for (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
+
+ 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, 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 = 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 );
+ INT32 nLen = aOpt.aActiveConvDics.getLength();
+ const OUString *pActiveConvDics = aOpt.aActiveConvDics.getConstArray();
+ for (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() );
+
+ 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, 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() );
+
+ /*INT16 nLang = LocaleToLanguage( rLocale );*/
+
+ INT32 nCount = 0;
+ uno::Sequence< OUString > aRes( 20 );
+ OUString *pRes = aRes.getArray();
+
+ sal_Bool bSupported = sal_False;
+ INT32 nLen = GetNameContainer().GetCount();
+ for (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 ) );
+ 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 (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();
+ INT32 nLen = GetNameContainer().GetCount();
+ for (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 = 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();
+}
+
+
+sal_Bool SAL_CALL ConvDicList_writeInfo(
+ void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey )
+{
+ try
+ {
+ String aImpl( '/' );
+ aImpl += ConvDicList::getImplementationName_Static().getStr();
+ aImpl.AppendAscii( "/UNO/SERVICES" );
+ uno::Reference< registry::XRegistryKey > xNewKey =
+ pRegistryKey->createKey(aImpl );
+ uno::Sequence< OUString > aServices =
+ ConvDicList::getSupportedServiceNames_Static();
+ for( INT32 i = 0; i < aServices.getLength(); i++ )
+ xNewKey->createKey( aServices.getConstArray()[i]);
+
+ return sal_True;
+ }
+ catch(Exception &)
+ {
+ return sal_False;
+ }
+}
+
+
+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;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/convdiclist.hxx b/linguistic/source/convdiclist.hxx
new file mode 100644
index 000000000000..d1c0740d991f
--- /dev/null
+++ b/linguistic/source/convdiclist.hxx
@@ -0,0 +1,122 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_CONVDICLIST_HXX_
+#define _LINGUISTIC_CONVDICLIST_HXX_
+
+#include <com/sun/star/linguistic2/XConversionDictionaryList.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase3.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <svl/svarray.hxx>
+#include <tools/debug.hxx>
+
+#include "misc.hxx"
+#include "lngopt.hxx"
+
+
+class ConvDicNameContainer;
+
+///////////////////////////////////////////////////////////////////////////
+
+class ConvDicList :
+ public cppu::WeakImplHelper3
+ <
+ ::com::sun::star::linguistic2::XConversionDictionaryList,
+ ::com::sun::star::lang::XComponent,
+ ::com::sun::star::lang::XServiceInfo
+ >
+{
+
+ class MyAppExitListener : public linguistic::AppExitListener
+ {
+ ConvDicList & rMyDicList;
+
+ public:
+ MyAppExitListener( ConvDicList &rDicList ) : rMyDicList( rDicList ) {}
+ virtual void AtExit();
+ };
+
+
+ ::cppu::OInterfaceContainerHelper aEvtListeners;
+
+ ConvDicNameContainer *pNameContainer;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::container::XNameContainer > xNameContainer;
+
+ MyAppExitListener *pExitListener;
+ ::com::sun::star::uno::Reference< ::com::sun::star::frame::
+ XTerminateListener > xExitListener;
+
+ BOOL bDisposing;
+
+ // disallow copy-constructor and assignment-operator for now
+ ConvDicList( const ConvDicList & );
+ ConvDicList & operator = (const ConvDicList &);
+
+ ConvDicNameContainer & GetNameContainer();
+
+public:
+ ConvDicList();
+ virtual ~ConvDicList();
+
+ // XConversionDictionaryList
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > SAL_CALL getDictionaryContainer( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XConversionDictionary > SAL_CALL addNewDictionary( const ::rtl::OUString& aName, const ::com::sun::star::lang::Locale& aLocale, sal_Int16 nConversionDictionaryType ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::container::ElementExistException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL queryConversions( const ::rtl::OUString& aText, sal_Int32 nStartPos, sal_Int32 nLength, const ::com::sun::star::lang::Locale& aLocale, sal_Int16 nConversionDictionaryType, ::com::sun::star::linguistic2::ConversionDirection eDirection, sal_Int32 nTextConversionOptions ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException);
+ virtual sal_Int16 SAL_CALL queryMaxCharCount( const ::com::sun::star::lang::Locale& aLocale, sal_Int16 nConversionDictionaryType, ::com::sun::star::linguistic2::ConversionDirection eDirection ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException);
+
+
+ static inline ::rtl::OUString
+ getImplementationName_Static() throw();
+ static com::sun::star::uno::Sequence< ::rtl::OUString >
+ getSupportedServiceNames_Static() throw();
+
+ // non UNO-specific
+ void FlushDics();
+};
+
+inline ::rtl::OUString ConvDicList::getImplementationName_Static() throw()
+{
+ return A2OU( "com.sun.star.lingu2.ConvDicList" );
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/convdicxml.cxx b/linguistic/source/convdicxml.cxx
new file mode 100644
index 000000000000..f3d56f7024a9
--- /dev/null
+++ b/linguistic/source/convdicxml.cxx
@@ -0,0 +1,462 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+#include <tools/urlobj.hxx>
+#include <tools/debug.hxx>
+#include <tools/fsys.hxx>
+#include <tools/string.hxx>
+#include <i18npool/mslangid.hxx>
+#include <tools/stream.hxx>
+#include <osl/mutex.hxx>
+#include <unotools/processfactory.hxx>
+#include <ucbhelper/content.hxx>
+
+#include <cppuhelper/factory.hxx> // helper for factories
+#include <com/sun/star/linguistic2/XConversionDictionary.hpp>
+#include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
+#include <com/sun/star/linguistic2/ConversionPropertyType.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/lang/EventObject.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/util/XFlushListener.hpp>
+#include <com/sun/star/io/XActiveDataSource.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <xmloff/nmspmap.hxx>
+#include <xmloff/xmlnmspe.hxx>
+#include <unotools/streamwrap.hxx>
+
+#include "convdic.hxx"
+#include "convdicxml.hxx"
+#include "misc.hxx"
+#include "defs.hxx"
+
+using namespace std;
+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::linguistic2;
+using namespace linguistic;
+
+#define XML_NAMESPACE_TCD_STRING "http://openoffice.org/2003/text-conversion-dictionary"
+#define CONV_TYPE_HANGUL_HANJA "Hangul / Hanja"
+#define CONV_TYPE_SCHINESE_TCHINESE "Chinese simplified / Chinese traditional"
+
+///////////////////////////////////////////////////////////////////////////
+
+static const OUString ConversionTypeToText( sal_Int16 nConversionType )
+{
+ OUString aRes;
+ if (nConversionType == ConversionDictionaryType::HANGUL_HANJA)
+ aRes = A2OU( CONV_TYPE_HANGUL_HANJA );
+ else if (nConversionType == ConversionDictionaryType::SCHINESE_TCHINESE)
+ aRes = A2OU( CONV_TYPE_SCHINESE_TCHINESE );
+ return aRes;
+}
+
+static sal_Int16 GetConversionTypeFromText( const String &rText )
+{
+ sal_Int16 nRes = -1;
+ if (rText.EqualsAscii( CONV_TYPE_HANGUL_HANJA ))
+ nRes = ConversionDictionaryType::HANGUL_HANJA;
+ else if (rText.EqualsAscii( CONV_TYPE_SCHINESE_TCHINESE ))
+ nRes = ConversionDictionaryType::SCHINESE_TCHINESE;
+ return nRes;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+class ConvDicXMLImportContext :
+ public SvXMLImportContext
+{
+public:
+ ConvDicXMLImportContext(
+ ConvDicXMLImport &rImport,
+ sal_uInt16 nPrfx, const OUString& rLName ) :
+ SvXMLImportContext( rImport, nPrfx, rLName )
+ {
+ }
+
+ const ConvDicXMLImport & GetConvDicImport() const
+ {
+ return (const ConvDicXMLImport &) GetImport();
+ }
+
+ ConvDicXMLImport & GetConvDicImport()
+ {
+ return (ConvDicXMLImport &) GetImport();
+ }
+
+ // SvXMLImportContext
+ virtual void Characters( const OUString &rChars );
+ virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList);
+};
+
+
+class ConvDicXMLDictionaryContext_Impl :
+ public ConvDicXMLImportContext
+{
+ INT16 nLanguage;
+ sal_Int16 nConversionType;
+
+public:
+ ConvDicXMLDictionaryContext_Impl( ConvDicXMLImport &rImport,
+ sal_uInt16 nPrefix, const OUString& rLName) :
+ ConvDicXMLImportContext( rImport, nPrefix, rLName )
+ {
+ nLanguage = LANGUAGE_NONE;
+ nConversionType = -1;
+ }
+
+ // SvXMLImportContext
+ virtual void StartElement( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList );
+ virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList );
+
+ INT16 GetLanguage() const { return nLanguage; }
+ sal_Int16 GetConversionType() const { return nConversionType; }
+};
+
+
+class ConvDicXMLEntryTextContext_Impl :
+ public ConvDicXMLImportContext
+{
+ OUString aLeftText;
+ sal_Int16 nPropertyType; // used for Chinese simplified/traditional conversion
+ ConvDicXMLDictionaryContext_Impl &rDicContext;
+
+public:
+ ConvDicXMLEntryTextContext_Impl(
+ ConvDicXMLImport &rImport,
+ sal_uInt16 nPrefix, const OUString& rLName,
+ ConvDicXMLDictionaryContext_Impl &rParentContext ) :
+ ConvDicXMLImportContext( rImport, nPrefix, rLName ),
+ nPropertyType( ConversionPropertyType::NOT_DEFINED ),
+ rDicContext( rParentContext )
+ {
+ }
+
+ // SvXMLImportContext
+ virtual void StartElement( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList );
+ virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList );
+
+ const OUString & GetLeftText() const { return aLeftText; }
+ sal_Int16 GetPropertyType() const { return nPropertyType; }
+ void SetPropertyType( sal_Int16 nVal ) { nPropertyType = nVal; }
+};
+
+
+class ConvDicXMLRightTextContext_Impl :
+ public ConvDicXMLImportContext
+{
+ OUString aRightText;
+ ConvDicXMLEntryTextContext_Impl &rEntryContext;
+
+public:
+ ConvDicXMLRightTextContext_Impl(
+ ConvDicXMLImport &rImport,
+ sal_uInt16 nPrefix, const OUString& rLName,
+ ConvDicXMLEntryTextContext_Impl &rParentContext ) :
+ ConvDicXMLImportContext( rImport, nPrefix, rLName ),
+ rEntryContext( rParentContext )
+ {
+ }
+
+ // SvXMLImportContext
+ virtual void EndElement();
+ virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList );
+ virtual void Characters( const OUString &rChars );
+
+ const OUString & GetRightText() const { return aRightText; }
+ const OUString & GetLeftText() const { return rEntryContext.GetLeftText(); }
+ ConvDic * GetDic() { return GetConvDicImport().GetDic(); }
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+void ConvDicXMLImportContext::Characters(const OUString & /*rChars*/)
+{
+ /*
+ Whitespace occurring within the content of token elements is "trimmed"
+ from the ends (i.e. all whitespace at the beginning and end of the
+ content is removed), and "collapsed" internally (i.e. each sequence of
+ 1 or more whitespace characters is replaced with one blank character).
+ */
+ //collapsing not done yet!
+
+ // warning-free code: since the result is not used there is no need for trimming...
+ //const OUString &rChars2 = rChars.trim();
+}
+
+SvXMLImportContext * ConvDicXMLImportContext::CreateChildContext(
+ sal_uInt16 nPrefix, const OUString& rLocalName,
+ const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ )
+{
+ SvXMLImportContext *pContext = 0;
+ if (nPrefix == XML_NAMESPACE_TCD && rLocalName.equalsAscii( "text-conversion-dictionary" ))
+ pContext = new ConvDicXMLDictionaryContext_Impl( GetConvDicImport(), nPrefix, rLocalName );
+ else
+ pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
+ return pContext;
+}
+
+////////////////////////////////////////
+
+void ConvDicXMLDictionaryContext_Impl::StartElement(
+ const uno::Reference< xml::sax::XAttributeList > &rxAttrList )
+{
+ sal_Int16 nAttrCount = rxAttrList.is() ? rxAttrList->getLength() : 0;
+ for (sal_Int16 i = 0; i < nAttrCount; ++i)
+ {
+ OUString aAttrName = rxAttrList->getNameByIndex(i);
+ OUString aLocalName;
+ sal_uInt16 nPrefix = GetImport().GetNamespaceMap().
+ GetKeyByAttrName( aAttrName, &aLocalName );
+ OUString aValue = rxAttrList->getValueByIndex(i);
+
+ if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "lang" ))
+ nLanguage = MsLangId::convertIsoStringToLanguage( aValue );
+ else if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "conversion-type" ))
+ nConversionType = GetConversionTypeFromText( aValue );
+ }
+ GetConvDicImport().SetLanguage( nLanguage );
+ GetConvDicImport().SetConversionType( nConversionType );
+
+ //!! hack to stop the parser from reading the rest of the file !!
+ //!! when only the header (language, conversion type) is needed !!
+// if (GetConvDicImport().GetDic() == 0)
+// throw uno::RuntimeException();
+}
+
+SvXMLImportContext * ConvDicXMLDictionaryContext_Impl::CreateChildContext(
+ sal_uInt16 nPrefix, const OUString& rLocalName,
+ const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ )
+{
+ SvXMLImportContext *pContext = 0;
+ if (nPrefix == XML_NAMESPACE_TCD && rLocalName.equalsAscii( "entry" ))
+ pContext = new ConvDicXMLEntryTextContext_Impl( GetConvDicImport(), nPrefix, rLocalName, *this );
+ else
+ pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
+ return pContext;
+}
+
+////////////////////////////////////////
+
+SvXMLImportContext * ConvDicXMLEntryTextContext_Impl::CreateChildContext(
+ sal_uInt16 nPrefix, const OUString& rLocalName,
+ const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ )
+{
+ SvXMLImportContext *pContext = 0;
+ if (nPrefix == XML_NAMESPACE_TCD && rLocalName.equalsAscii( "right-text" ))
+ pContext = new ConvDicXMLRightTextContext_Impl( GetConvDicImport(), nPrefix, rLocalName, *this );
+ else
+ pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
+ return pContext;
+}
+
+void ConvDicXMLEntryTextContext_Impl::StartElement(
+ const uno::Reference< xml::sax::XAttributeList >& rxAttrList )
+{
+ sal_Int16 nAttrCount = rxAttrList.is() ? rxAttrList->getLength() : 0;
+ for (sal_Int16 i = 0; i < nAttrCount; ++i)
+ {
+ OUString aAttrName = rxAttrList->getNameByIndex(i);
+ OUString aLocalName;
+ sal_uInt16 nPrefix = GetImport().GetNamespaceMap().
+ GetKeyByAttrName( aAttrName, &aLocalName );
+ OUString aValue = rxAttrList->getValueByIndex(i);
+
+ if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "left-text" ))
+ aLeftText = aValue;
+ if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "property-type" ))
+ nPropertyType = (sal_Int16) aValue.toInt32();
+ }
+}
+
+////////////////////////////////////////
+
+SvXMLImportContext * ConvDicXMLRightTextContext_Impl::CreateChildContext(
+ sal_uInt16 nPrefix, const OUString& rLocalName,
+ const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ )
+{
+ // leaf: return default (empty) context
+ SvXMLImportContext *pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
+ return pContext;
+}
+
+void ConvDicXMLRightTextContext_Impl::Characters( const OUString &rChars )
+{
+ aRightText += rChars;
+}
+
+void ConvDicXMLRightTextContext_Impl::EndElement()
+{
+ ConvDic *pDic = GetDic();
+ if (pDic)
+ pDic->AddEntry( GetLeftText(), GetRightText() );
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+sal_Bool ConvDicXMLExport::Export()
+{
+ sal_Bool bRet = sal_False;
+
+ uno::Reference< document::XExporter > xExporter( this );
+ uno::Reference< document::XFilter > xFilter( xExporter, UNO_QUERY );
+ uno::Sequence< beans::PropertyValue > aProps(0);
+ xFilter->filter( aProps ); // calls exportDoc implicitly
+
+ return bRet = bSuccess;
+}
+
+
+sal_uInt32 ConvDicXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum /*eClass*/ )
+{
+ _GetNamespaceMap().Add( A2OU( "tcd" ),
+ A2OU( XML_NAMESPACE_TCD_STRING ), XML_NAMESPACE_TCD );
+
+ GetDocHandler()->startDocument();
+
+ // Add xmlns line and some other arguments
+ AddAttribute( _GetNamespaceMap().GetAttrNameByKey( XML_NAMESPACE_TCD ),
+ _GetNamespaceMap().GetNameByKey( XML_NAMESPACE_TCD ) );
+ AddAttributeASCII( XML_NAMESPACE_TCD, "package", "org.openoffice.Office" );
+
+ OUString aIsoLang( MsLangId::convertLanguageToIsoString( rDic.nLanguage ) );
+ AddAttribute( XML_NAMESPACE_TCD, "lang", aIsoLang );
+ OUString aConvType( ConversionTypeToText( rDic.nConversionType ) );
+ AddAttribute( XML_NAMESPACE_TCD, "conversion-type", aConvType );
+
+ //!! block necessary in order to have SvXMLElementExport d-tor called
+ //!! before the call to endDocument
+ {
+ SvXMLElementExport aRoot( *this, XML_NAMESPACE_TCD, "text-conversion-dictionary", sal_True, sal_True );
+ _ExportContent();
+ }
+
+ GetDocHandler()->endDocument();
+
+ bSuccess = sal_True;
+ return 0;
+}
+
+
+void ConvDicXMLExport::_ExportContent()
+{
+ // aquire sorted list of all keys
+ ConvMapKeySet aKeySet;
+ ConvMap::iterator aIt;
+ for (aIt = rDic.aFromLeft.begin(); aIt != rDic.aFromLeft.end(); ++aIt)
+ aKeySet.insert( (*aIt).first );
+
+ ConvMapKeySet::iterator aKeyIt;
+ for (aKeyIt = aKeySet.begin(); aKeyIt != aKeySet.end(); ++aKeyIt)
+ {
+ OUString aLeftText( *aKeyIt );
+ AddAttribute( XML_NAMESPACE_TCD, "left-text", aLeftText );
+ if (rDic.pConvPropType.get()) // property-type list available?
+ {
+ sal_Int16 nPropertyType = -1;
+ PropTypeMap::iterator aIt2 = rDic.pConvPropType->find( aLeftText );
+ if (aIt2 != rDic.pConvPropType->end())
+ nPropertyType = (*aIt2).second;
+ DBG_ASSERT( nPropertyType, "property-type not found" );
+ if (nPropertyType == -1)
+ nPropertyType = ConversionPropertyType::NOT_DEFINED;
+ AddAttribute( XML_NAMESPACE_TCD, "property-type", OUString::valueOf( (sal_Int32) nPropertyType ) );
+ }
+ SvXMLElementExport aEntryMain( *this, XML_NAMESPACE_TCD,
+ "entry" , sal_True, sal_True );
+
+ pair< ConvMap::iterator, ConvMap::iterator > aRange =
+ rDic.aFromLeft.equal_range( *aKeyIt );
+ for (aIt = aRange.first; aIt != aRange.second; ++aIt)
+ {
+ DBG_ASSERT( *aKeyIt == (*aIt).first, "key <-> entry mismatch" );
+ OUString aRightText( (*aIt).second );
+ SvXMLElementExport aEntryRightText( *this, XML_NAMESPACE_TCD,
+ "right-text" , sal_True, sal_False );
+ Characters( aRightText );
+ }
+ }
+}
+
+::rtl::OUString SAL_CALL ConvDicXMLExport::getImplementationName()
+ throw( uno::RuntimeException )
+{
+ return A2OU( "com.sun.star.lingu2.ConvDicXMLExport" );
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+void SAL_CALL ConvDicXMLImport::startDocument(void)
+ throw( xml::sax::SAXException, uno::RuntimeException )
+{
+ // register namespace at first possible opportunity
+ GetNamespaceMap().Add( A2OU( "tcd" ),
+ A2OU( XML_NAMESPACE_TCD_STRING ), XML_NAMESPACE_TCD );
+ SvXMLImport::startDocument();
+}
+
+void SAL_CALL ConvDicXMLImport::endDocument(void)
+ throw( xml::sax::SAXException, uno::RuntimeException )
+{
+ SvXMLImport::endDocument();
+}
+
+SvXMLImportContext * ConvDicXMLImport::CreateContext(
+ sal_uInt16 nPrefix,
+ const rtl::OUString &rLocalName,
+ const uno::Reference < xml::sax::XAttributeList > & /*rxAttrList*/ )
+{
+ SvXMLImportContext *pContext = 0;
+ if (nPrefix == XML_NAMESPACE_TCD && rLocalName.equalsAscii( "text-conversion-dictionary" ))
+ pContext = new ConvDicXMLDictionaryContext_Impl( *this, nPrefix, rLocalName );
+ else
+ pContext = new SvXMLImportContext( *this, nPrefix, rLocalName );
+ return pContext;
+}
+
+
+OUString SAL_CALL ConvDicXMLImport::getImplementationName()
+ throw( uno::RuntimeException )
+{
+ return A2OU( "com.sun.star.lingu2.ConvDicXMLImport" );
+}
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/convdicxml.hxx b/linguistic/source/convdicxml.hxx
new file mode 100644
index 000000000000..eca7e9e48ce6
--- /dev/null
+++ b/linguistic/source/convdicxml.hxx
@@ -0,0 +1,134 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_CONVDICXML_HXX_
+#define _LINGUISTIC_CONVDICXML_HXX_
+
+#include <com/sun/star/linguistic2/XConversionDictionary.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <xmloff/xmlexp.hxx>
+#include <xmloff/xmlimp.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <tools/string.hxx>
+#include <rtl/ustring.hxx>
+#include "misc.hxx"
+#include "defs.hxx"
+
+
+class ConvDic;
+
+///////////////////////////////////////////////////////////////////////////
+
+class ConvDicXMLExport : public SvXMLExport
+{
+ ConvDic &rDic;
+ sal_Bool bSuccess;
+
+protected:
+ //void ExportNodes(const SmNode *pIn, int nLevel);
+
+public:
+ ConvDicXMLExport( ConvDic &rConvDic,
+ const rtl::OUString &rFileName,
+ com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler > &rHandler) :
+ SvXMLExport ( utl::getProcessServiceFactory(), rFileName, rHandler ),
+ rDic ( rConvDic ),
+ bSuccess ( sal_False )
+ {
+ }
+ virtual ~ConvDicXMLExport()
+ {
+ }
+
+ // XServiceInfo (override parent method)
+ ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException );
+
+ // SvXMLExport
+ void _ExportAutoStyles() {}
+ void _ExportMasterStyles() {}
+ void _ExportContent();
+ sal_uInt32 exportDoc( enum ::xmloff::token::XMLTokenEnum eClass );
+
+ sal_Bool Export();
+};
+
+
+class ConvDicXMLImport : public SvXMLImport
+{
+ ConvDic *pDic; // conversion dictionary to be used
+ // if != NULL: whole file will be read and
+ // all entries will be added to the dictionary
+ // if == NULL: no entries will be added
+ // but the language and conversion type will
+ // still be determined!
+
+ INT16 nLanguage; // language of the dictionary
+ sal_Int16 nConversionType; // conversion type the dictionary is used for
+ sal_Bool bSuccess;
+
+public:
+
+ //!! see comment for pDic member
+ ConvDicXMLImport( ConvDic *pConvDic, const rtl::OUString /*&rFileName*/ ) :
+ SvXMLImport ( utl::getProcessServiceFactory(), IMPORT_ALL ),
+ pDic ( pConvDic )
+ {
+ nLanguage = LANGUAGE_NONE;
+ nConversionType = -1;
+ bSuccess = sal_False;
+ }
+
+ virtual ~ConvDicXMLImport() throw ()
+ {
+ }
+
+ // XServiceInfo (override parent method)
+ ::rtl::OUString SAL_CALL getImplementationName() throw( ::com::sun::star::uno::RuntimeException );
+
+ virtual void SAL_CALL startDocument(void) throw( ::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException );
+ virtual void SAL_CALL endDocument(void) throw( ::com::sun::star::xml::sax::SAXException, ::com::sun::star::uno::RuntimeException );
+
+ virtual SvXMLImportContext * CreateContext(
+ sal_uInt16 nPrefix, const rtl::OUString &rLocalName,
+ const com::sun::star::uno::Reference < com::sun::star::xml::sax::XAttributeList > &rxAttrList );
+
+ ConvDic * GetDic() { return pDic; }
+ INT16 GetLanguage() const { return nLanguage; }
+ sal_Int16 GetConversionType() const { return nConversionType; }
+ sal_Bool GetSuccess() const { return bSuccess; }
+
+ void SetLanguage( INT16 nLang ) { nLanguage = nLang; }
+ void SetConversionType( sal_Int16 nType ) { nConversionType = nType; }
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/defs.hxx b/linguistic/source/defs.hxx
new file mode 100644
index 000000000000..b888d86f8720
--- /dev/null
+++ b/linguistic/source/defs.hxx
@@ -0,0 +1,136 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_DEFS_HXX_
+#define _LINGUISTIC_DEFS_HXX_
+
+#include <com/sun/star/linguistic2/XSpellChecker.hpp>
+#include <com/sun/star/linguistic2/XProofreader.hpp>
+#include <com/sun/star/linguistic2/XHyphenator.hpp>
+#include <com/sun/star/linguistic2/XThesaurus.hpp>
+
+#include <boost/shared_ptr.hpp>
+
+class SvStream;
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#define A2OU(x) ::rtl::OUString::createFromAscii( x )
+
+typedef boost::shared_ptr< SvStream > SvStreamPtr;
+
+namespace css = ::com::sun::star;
+
+///////////////////////////////////////////////////////////////////////////
+
+struct LangSvcEntries
+{
+ css::uno::Sequence< ::rtl::OUString > aSvcImplNames;
+
+ sal_Int16 nLastTriedSvcIndex;
+ bool bAlreadyWarned;
+ bool bDoWarnAgain;
+
+ LangSvcEntries() : nLastTriedSvcIndex(-1), bAlreadyWarned(false), bDoWarnAgain(false) {}
+
+ inline LangSvcEntries( const css::uno::Sequence< ::rtl::OUString > &rSvcImplNames ) :
+ aSvcImplNames(rSvcImplNames),
+ nLastTriedSvcIndex(-1), bAlreadyWarned(false), bDoWarnAgain(false)
+ {
+ }
+
+ inline LangSvcEntries( const ::rtl::OUString &rSvcImplName ) :
+ nLastTriedSvcIndex(-1), bAlreadyWarned(false), bDoWarnAgain(false)
+ {
+ aSvcImplNames.realloc(1);
+ aSvcImplNames[0] = rSvcImplName;
+ }
+
+ bool IsAlreadyWarned() const { return bAlreadyWarned != 0; }
+ void SetAlreadyWarned( bool bVal ) { bAlreadyWarned = 0 != bVal; }
+ bool IsDoWarnAgain() const { return bDoWarnAgain != 0; }
+ void SetDoWarnAgain( bool bVal ) { bDoWarnAgain = 0 != bVal; }
+
+ inline void Clear()
+ {
+ aSvcImplNames.realloc(0);
+ nLastTriedSvcIndex = -1;
+ bAlreadyWarned = false;
+ bDoWarnAgain = false;
+ }
+};
+
+struct LangSvcEntries_Spell : public LangSvcEntries
+{
+ css::uno::Sequence< css::uno::Reference< css::linguistic2::XSpellChecker > > aSvcRefs;
+
+ LangSvcEntries_Spell() : LangSvcEntries() {}
+ LangSvcEntries_Spell( const css::uno::Sequence< ::rtl::OUString > &rSvcImplNames ) : LangSvcEntries( rSvcImplNames ) {}
+};
+
+struct LangSvcEntries_Grammar : public LangSvcEntries
+{
+ css::uno::Sequence< css::uno::Reference< css::linguistic2::XProofreader > > aSvcRefs;
+
+ LangSvcEntries_Grammar() : LangSvcEntries() {}
+ LangSvcEntries_Grammar( const ::rtl::OUString &rSvcImplName ) : LangSvcEntries( rSvcImplName ) {}
+};
+
+struct LangSvcEntries_Hyph : public LangSvcEntries
+{
+ css::uno::Sequence< css::uno::Reference< css::linguistic2::XHyphenator > > aSvcRefs;
+
+ LangSvcEntries_Hyph() : LangSvcEntries() {}
+ LangSvcEntries_Hyph( const ::rtl::OUString &rSvcImplName ) : LangSvcEntries( rSvcImplName ) {}
+};
+
+struct LangSvcEntries_Thes : public LangSvcEntries
+{
+ css::uno::Sequence< css::uno::Reference< css::linguistic2::XThesaurus > > aSvcRefs;
+
+ LangSvcEntries_Thes() : LangSvcEntries() {}
+ LangSvcEntries_Thes( const css::uno::Sequence< ::rtl::OUString > &rSvcImplNames ) : LangSvcEntries( rSvcImplNames ) {}
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+// virtual base class for the different dispatchers
+class LinguDispatcher
+{
+public:
+ enum DspType { DSP_SPELL, DSP_HYPH, DSP_THES, DSP_GRAMMAR };
+
+ virtual void SetServiceList( const css::lang::Locale &rLocale, const css::uno::Sequence< rtl::OUString > &rSvcImplNames ) = 0;
+ virtual css::uno::Sequence< rtl::OUString > GetServiceList( const css::lang::Locale &rLocale ) const = 0;
+ virtual DspType GetDspType() const = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/dicimp.cxx b/linguistic/source/dicimp.cxx
new file mode 100755
index 000000000000..fe53bf344ac3
--- /dev/null
+++ b/linguistic/source/dicimp.cxx
@@ -0,0 +1,1207 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+#include <cppuhelper/factory.hxx>
+#include <dicimp.hxx>
+#include <hyphdsp.hxx>
+#include <i18npool/lang.h>
+#include <i18npool/mslangid.hxx>
+#include <osl/mutex.hxx>
+#include <tools/debug.hxx>
+#include <tools/fsys.hxx>
+#include <tools/stream.hxx>
+#include <tools/string.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/processfactory.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+
+#include <com/sun/star/ucb/XSimpleFileAccess.hpp>
+#include <com/sun/star/linguistic2/DictionaryType.hpp>
+#include <com/sun/star/linguistic2/DictionaryEventFlags.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+
+#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::linguistic2;
+using namespace linguistic;
+
+///////////////////////////////////////////////////////////////////////////
+
+#define BUFSIZE 4096
+#define VERS2_NOLANGUAGE 1024
+
+#define MAX_HEADER_LENGTH 16
+
+static const sal_Char* pDicExt = "dic";
+static const sal_Char* pVerStr2 = "WBSWG2";
+static const sal_Char* pVerStr5 = "WBSWG5";
+static const sal_Char* pVerStr6 = "WBSWG6";
+static const sal_Char* pVerOOo7 = "OOoUserDict1";
+
+static const INT16 DIC_VERSION_DONTKNOW = -1;
+static const INT16 DIC_VERSION_2 = 2;
+static const INT16 DIC_VERSION_5 = 5;
+static const INT16 DIC_VERSION_6 = 6;
+static const INT16 DIC_VERSION_7 = 7;
+
+static sal_Bool getTag(const ByteString &rLine,
+ const sal_Char *pTagName, ByteString &rTagValue)
+{
+ xub_StrLen nPos = rLine.Search( pTagName );
+ if (nPos == STRING_NOTFOUND)
+ return FALSE;
+
+ rTagValue = rLine.Copy( nPos + sal::static_int_cast< xub_StrLen >(strlen( pTagName )) ).EraseLeadingAndTrailingChars();
+ return TRUE;
+}
+
+
+INT16 ReadDicVersion( SvStreamPtr &rpStream, USHORT &nLng, BOOL &bNeg )
+{
+ // Sniff the header
+ INT16 nDicVersion = DIC_VERSION_DONTKNOW;
+ sal_Char pMagicHeader[MAX_HEADER_LENGTH];
+
+ nLng = LANGUAGE_NONE;
+ bNeg = FALSE;
+
+ if (!rpStream.get() || rpStream->GetError())
+ return -1;
+
+ sal_Size nSniffPos = rpStream->Tell();
+ static sal_Size nVerOOo7Len = sal::static_int_cast< sal_Size >(strlen( pVerOOo7 ));
+ pMagicHeader[ nVerOOo7Len ] = '\0';
+ if ((rpStream->Read((void *) pMagicHeader, nVerOOo7Len) == nVerOOo7Len) &&
+ !strcmp(pMagicHeader, pVerOOo7))
+ {
+ sal_Bool bSuccess;
+ ByteString aLine;
+
+ nDicVersion = DIC_VERSION_7;
+
+ // 1st skip magic / header line
+ rpStream->ReadLine(aLine);
+
+ // 2nd line: language all | en-US | pt-BR ...
+ while (sal_True == (bSuccess = rpStream->ReadLine(aLine)))
+ {
+ ByteString aTagValue;
+
+ if (aLine.GetChar(0) == '#') // skip comments
+ continue;
+
+ // lang: field
+ if (getTag(aLine, "lang: ", aTagValue))
+ {
+ if (aTagValue == "<none>")
+ nLng = LANGUAGE_NONE;
+ else
+ nLng = MsLangId::convertIsoStringToLanguage(OUString(aTagValue.GetBuffer(),
+ aTagValue.Len(), RTL_TEXTENCODING_ASCII_US));
+ }
+
+ // type: negative / positive
+ if (getTag(aLine, "type: ", aTagValue))
+ {
+ if (aTagValue == "negative")
+ bNeg = TRUE;
+ else
+ bNeg = FALSE;
+ }
+
+ if (aLine.Search ("---") != STRING_NOTFOUND) // end of header
+ break;
+ }
+ if (!bSuccess)
+ return -2;
+ }
+ else
+ {
+ USHORT nLen;
+
+ rpStream->Seek (nSniffPos );
+
+ *rpStream >> nLen;
+ if (nLen >= MAX_HEADER_LENGTH)
+ return -1;
+
+ rpStream->Read(pMagicHeader, nLen);
+ pMagicHeader[nLen] = '\0';
+
+ // Check version magic
+ if (0 == strcmp( pMagicHeader, pVerStr6 ))
+ nDicVersion = DIC_VERSION_6;
+ else if (0 == strcmp( pMagicHeader, pVerStr5 ))
+ nDicVersion = DIC_VERSION_5;
+ else if (0 == strcmp( pMagicHeader, pVerStr2 ))
+ nDicVersion = DIC_VERSION_2;
+ else
+ nDicVersion = DIC_VERSION_DONTKNOW;
+
+ if (DIC_VERSION_2 == nDicVersion ||
+ DIC_VERSION_5 == nDicVersion ||
+ DIC_VERSION_6 == nDicVersion)
+ {
+ // The language of the dictionary
+ *rpStream >> nLng;
+
+ if (VERS2_NOLANGUAGE == nLng)
+ nLng = LANGUAGE_NONE;
+
+ // Negative Flag
+ sal_Char nTmp;
+ *rpStream >> nTmp;
+ bNeg = (BOOL)nTmp;
+ }
+ }
+
+ return nDicVersion;
+}
+
+
+
+const String GetDicExtension()
+{
+ return String::CreateFromAscii( pDicExt );
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+DictionaryNeo::DictionaryNeo() :
+ aDicEvtListeners( GetLinguMutex() ),
+ eDicType (DictionaryType_POSITIVE),
+ nLanguage (LANGUAGE_NONE)
+{
+ nCount = 0;
+ nDicVersion = DIC_VERSION_DONTKNOW;
+ bNeedEntries = FALSE;
+ bIsModified = bIsActive = FALSE;
+ bIsReadonly = FALSE;
+}
+
+DictionaryNeo::DictionaryNeo(const OUString &rName,
+ INT16 nLang, DictionaryType eType,
+ const OUString &rMainURL,
+ BOOL bWriteable) :
+ aDicEvtListeners( GetLinguMutex() ),
+ aDicName (rName),
+ aMainURL (rMainURL),
+ eDicType (eType),
+ nLanguage (nLang)
+{
+ nCount = 0;
+ nDicVersion = DIC_VERSION_DONTKNOW;
+ bNeedEntries = TRUE;
+ bIsModified = bIsActive = FALSE;
+ bIsReadonly = !bWriteable;
+
+ if( rMainURL.getLength() > 0 )
+ {
+ BOOL bExists = FileExists( rMainURL );
+ if( !bExists )
+ {
+ // save new dictionaries with in Format 7 (UTF8 plain text)
+ nDicVersion = DIC_VERSION_7;
+
+ //! create physical representation of an **empty** dictionary
+ //! that could be found by the dictionary-list implementation
+ // (Note: empty dictionaries are not just empty files!)
+ DBG_ASSERT( !bIsReadonly,
+ "DictionaryNeo: dictionaries should be writeable if they are to be saved" );
+ if (!bIsReadonly)
+ saveEntries( rMainURL );
+ bNeedEntries = FALSE;
+ }
+ }
+ else
+ {
+ // non persistent dictionaries (like IgnoreAllList) should always be writable
+ bIsReadonly = FALSE;
+ bNeedEntries = FALSE;
+ }
+}
+
+DictionaryNeo::~DictionaryNeo()
+{
+}
+
+ULONG DictionaryNeo::loadEntries(const OUString &rMainURL)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ // counter check that it is safe to set bIsModified to FALSE at
+ // the end of the function
+ DBG_ASSERT(!bIsModified, "lng : dictionary already modified!");
+
+ // function should only be called once in order to load entries from file
+ bNeedEntries = FALSE;
+
+ if (rMainURL.getLength() == 0)
+ return 0;
+
+ uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() );
+
+ // get XInputStream stream
+ uno::Reference< io::XInputStream > xStream;
+ try
+ {
+ uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance(
+ A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW );
+ xStream = xAccess->openFileRead( rMainURL );
+ }
+ catch (uno::Exception & e)
+ {
+ DBG_ASSERT( 0, "failed to get input stream" );
+ (void) e;
+ }
+ if (!xStream.is())
+ return static_cast< ULONG >(-1);
+
+ SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) );
+
+ ULONG nErr = sal::static_int_cast< ULONG >(-1);
+
+ // Header einlesen
+ BOOL bNegativ;
+ USHORT nLang;
+ nDicVersion = ReadDicVersion(pStream, nLang, bNegativ);
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+
+ nLanguage = nLang;
+
+ eDicType = bNegativ ? DictionaryType_NEGATIVE : DictionaryType_POSITIVE;
+
+ rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
+ if (nDicVersion >= DIC_VERSION_6)
+ eEnc = RTL_TEXTENCODING_UTF8;
+ nCount = 0;
+
+ if (DIC_VERSION_6 == nDicVersion ||
+ DIC_VERSION_5 == nDicVersion ||
+ DIC_VERSION_2 == nDicVersion)
+ {
+ USHORT nLen = 0;
+ sal_Char aWordBuf[ BUFSIZE ];
+
+ // Das erste Wort einlesen
+ if (!pStream->IsEof())
+ {
+ *pStream >> nLen;
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+ if ( nLen < BUFSIZE )
+ {
+ pStream->Read(aWordBuf, nLen);
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+ *(aWordBuf + nLen) = 0;
+ }
+ }
+
+ while(!pStream->IsEof())
+ {
+ // Aus dem File einlesen
+ // Einfuegen ins Woerterbuch ohne Konvertierung
+ if(*aWordBuf)
+ {
+ ByteString aDummy( aWordBuf );
+ String aText( aDummy, eEnc );
+ uno::Reference< XDictionaryEntry > xEntry =
+ new DicEntry( aText, bNegativ );
+ addEntry_Impl( xEntry , TRUE ); //! don't launch events here
+ }
+
+ *pStream >> nLen;
+ if (pStream->IsEof()) // #75082# GPF in online-spelling
+ break;
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+#ifdef LINGU_EXCEPTIONS
+ if (nLen >= BUFSIZE)
+ throw io::IOException() ;
+#endif
+
+ if (nLen < BUFSIZE)
+ {
+ pStream->Read(aWordBuf, nLen);
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+ }
+ else
+ return SVSTREAM_READ_ERROR;
+ *(aWordBuf + nLen) = 0;
+ }
+ }
+ else if (DIC_VERSION_7 == nDicVersion)
+ {
+ sal_Bool bSuccess;
+ ByteString aLine;
+
+ // remaining lines - stock strings (a [==] b)
+ while (sal_True == (bSuccess = pStream->ReadLine(aLine)))
+ {
+ if (aLine.GetChar(0) == '#') // skip comments
+ continue;
+ rtl::OUString aText = rtl::OStringToOUString (aLine, RTL_TEXTENCODING_UTF8);
+ uno::Reference< XDictionaryEntry > xEntry =
+ new DicEntry( aText, eDicType == DictionaryType_NEGATIVE );
+ addEntry_Impl( xEntry , TRUE ); //! don't launch events here
+ }
+ }
+
+ DBG_ASSERT(isSorted(), "lng : dictionary is not sorted");
+
+ // since this routine should be called only initialy (prior to any
+ // modification to be saved) we reset the bIsModified flag here that
+ // was implicitly set by addEntry_Impl
+ bIsModified = FALSE;
+
+ return pStream->GetError();
+}
+
+
+static ByteString formatForSave(
+ const uno::Reference< XDictionaryEntry > &xEntry, rtl_TextEncoding eEnc )
+{
+ ByteString aStr(xEntry->getDictionaryWord().getStr(), eEnc);
+
+ if (xEntry->isNegative())
+ {
+ aStr += "==";
+ aStr += ByteString(xEntry->getReplacementText().getStr(), eEnc);
+ }
+ return aStr;
+}
+
+
+ULONG DictionaryNeo::saveEntries(const OUString &rURL)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (rURL.getLength() == 0)
+ return 0;
+ DBG_ASSERT(!INetURLObject( rURL ).HasError(), "lng : invalid URL");
+
+ uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() );
+
+ // get XOutputStream stream
+ uno::Reference< io::XStream > xStream;
+ try
+ {
+ uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance(
+ A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW );
+ xStream = xAccess->openFileReadWrite( rURL );
+ }
+ catch (uno::Exception & e)
+ {
+ DBG_ASSERT( 0, "failed to get input stream" );
+ (void) e;
+ }
+ if (!xStream.is())
+ return static_cast< ULONG >(-1);
+
+ SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) );
+
+ ULONG nErr = sal::static_int_cast< ULONG >(-1);
+
+ rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
+ if (nDicVersion >= DIC_VERSION_6)
+ eEnc = RTL_TEXTENCODING_UTF8;
+
+ if (nDicVersion == DIC_VERSION_7)
+ {
+ pStream->WriteLine(ByteString (pVerOOo7));
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+
+ if (nLanguage == LANGUAGE_NONE)
+ pStream->WriteLine(ByteString("lang: <none>"));
+ else
+ {
+ ByteString aLine("lang: ");
+ aLine += ByteString( String( MsLangId::convertLanguageToIsoString( nLanguage ) ), eEnc);
+ pStream->WriteLine( aLine );
+ }
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+
+ if (eDicType == DictionaryType_POSITIVE)
+ pStream->WriteLine(ByteString("type: positive"));
+ else
+ pStream->WriteLine(ByteString("type: negative"));
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+
+ pStream->WriteLine(ByteString("---"));
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+
+ const uno::Reference< XDictionaryEntry > *pEntry = aEntries.getConstArray();
+ for (INT32 i = 0; i < nCount; i++)
+ {
+ ByteString aOutStr = formatForSave(pEntry[i], eEnc);
+ pStream->WriteLine (aOutStr);
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+ }
+ }
+ else
+ {
+ sal_Char aWordBuf[BUFSIZE];
+
+ // write version
+ const sal_Char *pVerStr = NULL;
+ if (DIC_VERSION_6 == nDicVersion)
+ pVerStr = pVerStr6;
+ else
+ pVerStr = eDicType == DictionaryType_POSITIVE ? pVerStr2 : pVerStr5;
+ strcpy( aWordBuf, pVerStr ); // #100211# - checked
+ USHORT nLen = sal::static_int_cast< USHORT >(strlen( aWordBuf ));
+ *pStream << nLen;
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+ pStream->Write(aWordBuf, nLen);
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+
+ *pStream << nLanguage;
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+ *pStream << (sal_Char) (eDicType == DictionaryType_NEGATIVE ? TRUE : FALSE);
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+
+ const uno::Reference< XDictionaryEntry > *pEntry = aEntries.getConstArray();
+ for (INT32 i = 0; i < nCount; i++)
+ {
+ ByteString aOutStr = formatForSave(pEntry[i], eEnc);
+
+ // the old format would fail (mis-calculation of nLen) and write
+ // uninitialized junk for combined len >= BUFSIZE - we truncate
+ // silently here, but BUFSIZE is large anyway.
+ nLen = aOutStr.Len();
+ if (nLen >= BUFSIZE)
+ nLen = BUFSIZE - 1;
+
+ *pStream << nLen;
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+ pStream->Write(aOutStr.GetBuffer(), nLen);
+ if (0 != (nErr = pStream->GetError()))
+ return nErr;
+ }
+ }
+
+ //! get return value before Stream is destroyed
+ ULONG nError = pStream->GetError();
+
+ return nError;
+}
+
+void DictionaryNeo::launchEvent(INT16 nEvent,
+ uno::Reference< XDictionaryEntry > xEntry)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ DictionaryEvent aEvt;
+ aEvt.Source = uno::Reference< XDictionary >( this );
+ aEvt.nEvent = nEvent;
+ aEvt.xDictionaryEntry = xEntry;
+
+ cppu::OInterfaceIteratorHelper aIt( aDicEvtListeners );
+ while (aIt.hasMoreElements())
+ {
+ uno::Reference< XDictionaryEventListener > xRef( aIt.next(), UNO_QUERY );
+ if (xRef.is())
+ xRef->processDictionaryEvent( aEvt );
+ }
+}
+
+int DictionaryNeo::cmpDicEntry(const OUString& rWord1,
+ const OUString &rWord2,
+ BOOL bSimilarOnly)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ // returns 0 if rWord1 is equal to rWord2
+ // " a value < 0 if rWord1 is less than rWord2
+ // " a value > 0 if rWord1 is greater than rWord2
+
+ int nRes = 0;
+
+ OUString aWord1( rWord1 ),
+ aWord2( rWord2 );
+ INT32 nLen1 = aWord1.getLength(),
+ nLen2 = aWord2.getLength();
+ if (bSimilarOnly)
+ {
+ const sal_Unicode cChar = '.';
+ if (nLen1 && cChar == aWord1[ nLen1 - 1 ])
+ nLen1--;
+ if (nLen2 && cChar == aWord2[ nLen2 - 1 ])
+ nLen2--;
+ }
+
+ const sal_Unicode cIgnChar = '=';
+ INT32 nIdx1 = 0,
+ nIdx2 = 0,
+ nNumIgnChar1 = 0,
+ nNumIgnChar2 = 0;
+
+ sal_Int32 nDiff = 0;
+ sal_Unicode cChar1 = '\0';
+ sal_Unicode cChar2 = '\0';
+ do
+ {
+ // skip chars to be ignored
+ while (nIdx1 < nLen1 && (cChar1 = aWord1[ nIdx1 ]) == cIgnChar)
+ {
+ nIdx1++;
+ nNumIgnChar1++;
+ }
+ while (nIdx2 < nLen2 && (cChar2 = aWord2[ nIdx2 ]) == cIgnChar)
+ {
+ nIdx2++;
+ nNumIgnChar2++;
+ }
+
+ if (nIdx1 < nLen1 && nIdx2 < nLen2)
+ {
+ nDiff = cChar1 - cChar2;
+ if (nDiff)
+ break;
+ nIdx1++;
+ nIdx2++;
+ }
+ } while (nIdx1 < nLen1 && nIdx2 < nLen2);
+
+
+ if (nDiff)
+ nRes = nDiff;
+ else
+ { // the string with the smallest count of not ignored chars is the
+ // shorter one
+
+ // count remaining IgnChars
+ while (nIdx1 < nLen1 )
+ {
+ if (aWord1[ nIdx1++ ] == cIgnChar)
+ nNumIgnChar1++;
+ }
+ while (nIdx2 < nLen2 )
+ {
+ if (aWord2[ nIdx2++ ] == cIgnChar)
+ nNumIgnChar2++;
+ }
+
+ nRes = ((INT32) nLen1 - nNumIgnChar1) - ((INT32) nLen2 - nNumIgnChar2);
+ }
+
+ return nRes;
+}
+
+BOOL DictionaryNeo::seekEntry(const OUString &rWord,
+ INT32 *pPos, BOOL bSimilarOnly)
+{
+ // look for entry with binary search.
+ // return TRUE if found FALSE else.
+ // if pPos != NULL it will become the position of the found entry, or
+ // if that was not found the position where it has to be inserted
+ // to keep the entries sorted
+
+ MutexGuard aGuard( GetLinguMutex() );
+
+ const uno::Reference< XDictionaryEntry > *pEntry = aEntries.getConstArray();
+ INT32 nUpperIdx = getCount(),
+ nMidIdx,
+ nLowerIdx = 0;
+ if( nUpperIdx > 0 )
+ {
+ nUpperIdx--;
+ while( nLowerIdx <= nUpperIdx )
+ {
+ nMidIdx = (nLowerIdx + nUpperIdx) / 2;
+ DBG_ASSERT(pEntry[nMidIdx].is(), "lng : empty entry encountered");
+
+ int nCmp = - cmpDicEntry( pEntry[nMidIdx]->getDictionaryWord(),
+ rWord, bSimilarOnly );
+ if(nCmp == 0)
+ {
+ if( pPos ) *pPos = nMidIdx;
+ return TRUE;
+ }
+ else if(nCmp > 0)
+ nLowerIdx = nMidIdx + 1;
+ else if( nMidIdx == 0 )
+ {
+ if( pPos ) *pPos = nLowerIdx;
+ return FALSE;
+ }
+ else
+ nUpperIdx = nMidIdx - 1;
+ }
+ }
+ if( pPos ) *pPos = nLowerIdx;
+ return FALSE;
+}
+
+BOOL DictionaryNeo::isSorted()
+{
+ BOOL bRes = TRUE;
+
+ const uno::Reference< XDictionaryEntry > *pEntry = aEntries.getConstArray();
+ INT32 nEntries = getCount();
+ INT32 i;
+ for (i = 1; i < nEntries; i++)
+ {
+ if (cmpDicEntry( pEntry[i-1]->getDictionaryWord(),
+ pEntry[i]->getDictionaryWord() ) > 0)
+ {
+ bRes = FALSE;
+ break;
+ }
+ }
+ return bRes;
+}
+
+BOOL DictionaryNeo::addEntry_Impl(const uno::Reference< XDictionaryEntry > xDicEntry,
+ BOOL bIsLoadEntries)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = FALSE;
+
+ if ( bIsLoadEntries || (!bIsReadonly && xDicEntry.is()) )
+ {
+ BOOL bIsNegEntry = xDicEntry->isNegative();
+ BOOL bAddEntry = !isFull() &&
+ ( ( eDicType == DictionaryType_POSITIVE && !bIsNegEntry )
+ || ( eDicType == DictionaryType_NEGATIVE && bIsNegEntry )
+ || ( eDicType == DictionaryType_MIXED ) );
+
+ // look for position to insert entry at
+ // if there is already an entry do not insert the new one
+ INT32 nPos = 0;
+ BOOL bFound = FALSE;
+ if (bAddEntry)
+ {
+ bFound = seekEntry( xDicEntry->getDictionaryWord(), &nPos );
+ if (bFound)
+ bAddEntry = FALSE;
+ }
+
+ if (bAddEntry)
+ {
+ DBG_ASSERT(!bNeedEntries, "lng : entries still not loaded");
+
+ if (nCount >= aEntries.getLength())
+ aEntries.realloc( Max(2 * nCount, nCount + 32) );
+ uno::Reference< XDictionaryEntry > *pEntry = aEntries.getArray();
+
+ // shift old entries right
+ INT32 i;
+ for (i = nCount - 1; i >= nPos; i--)
+ pEntry[ i+1 ] = pEntry[ i ];
+ // insert new entry at specified position
+ pEntry[ nPos ] = xDicEntry;
+ DBG_ASSERT(isSorted(), "lng : dictionary entries unsorted");
+
+ nCount++;
+
+ bIsModified = TRUE;
+ bRes = TRUE;
+
+ if (!bIsLoadEntries)
+ launchEvent( DictionaryEventFlags::ADD_ENTRY, xDicEntry );
+ }
+ }
+
+ return bRes;
+}
+
+
+uno::Reference< XInterface > SAL_CALL DictionaryNeo_CreateInstance(
+ const uno::Reference< XMultiServiceFactory > & /*rSMgr*/ )
+ throw(Exception)
+{
+ uno::Reference< XInterface > xService =
+ (cppu::OWeakObject*) new DictionaryNeo;
+ return xService;
+}
+
+OUString SAL_CALL DictionaryNeo::getName( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aDicName;
+}
+
+void SAL_CALL DictionaryNeo::setName( const OUString& aName )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (aDicName != aName)
+ {
+ aDicName = aName;
+ launchEvent(DictionaryEventFlags::CHG_NAME, NULL);
+ }
+}
+
+DictionaryType SAL_CALL DictionaryNeo::getDictionaryType( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ return eDicType;
+}
+
+void SAL_CALL DictionaryNeo::setActive( sal_Bool bActivate )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (bIsActive != bActivate)
+ {
+ bIsActive = bActivate != 0;
+ INT16 nEvent = bIsActive ?
+ DictionaryEventFlags::ACTIVATE_DIC : DictionaryEventFlags::DEACTIVATE_DIC;
+
+ // remove entries from memory if dictionary is deactivated
+ if (bIsActive == FALSE)
+ {
+ BOOL bIsEmpty = nCount == 0;
+
+ // save entries first if necessary
+ if (bIsModified && hasLocation() && !isReadonly())
+ {
+ store();
+
+ aEntries.realloc( 0 );
+ nCount = 0;
+ bNeedEntries = !bIsEmpty;
+ }
+ DBG_ASSERT( !bIsModified || !hasLocation() || isReadonly(),
+ "lng : dictionary is still modified" );
+ }
+
+ launchEvent(nEvent, NULL);
+ }
+}
+
+sal_Bool SAL_CALL DictionaryNeo::isActive( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return bIsActive;
+}
+
+sal_Int32 SAL_CALL DictionaryNeo::getCount( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (bNeedEntries)
+ loadEntries( aMainURL );
+ return nCount;
+}
+
+Locale SAL_CALL DictionaryNeo::getLocale( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ Locale aRes;
+ return LanguageToLocale( aRes, nLanguage );
+}
+
+void SAL_CALL DictionaryNeo::setLocale( const Locale& aLocale )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ INT16 nLanguageP = LocaleToLanguage( aLocale );
+ if (!bIsReadonly && nLanguage != nLanguageP)
+ {
+ nLanguage = nLanguageP;
+ bIsModified = TRUE; // new language needs to be saved with dictionary
+
+ launchEvent( DictionaryEventFlags::CHG_LANGUAGE, NULL );
+ }
+}
+
+uno::Reference< XDictionaryEntry > SAL_CALL DictionaryNeo::getEntry(
+ const OUString& aWord )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (bNeedEntries)
+ loadEntries( aMainURL );
+
+ INT32 nPos;
+ BOOL bFound = seekEntry( aWord, &nPos, TRUE );
+ DBG_ASSERT( nCount <= aEntries.getLength(), "lng : wrong number of entries");
+ DBG_ASSERT(!bFound || nPos < nCount, "lng : index out of range");
+
+ return bFound ? aEntries.getConstArray()[ nPos ]
+ : uno::Reference< XDictionaryEntry >();
+}
+
+sal_Bool SAL_CALL DictionaryNeo::addEntry(
+ const uno::Reference< XDictionaryEntry >& xDicEntry )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = FALSE;
+
+ if (!bIsReadonly)
+ {
+ if (bNeedEntries)
+ loadEntries( aMainURL );
+ bRes = addEntry_Impl( xDicEntry );
+ }
+
+ return bRes;
+}
+
+sal_Bool SAL_CALL
+ DictionaryNeo::add( const OUString& rWord, sal_Bool bIsNegative,
+ const OUString& rRplcText )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = FALSE;
+
+ if (!bIsReadonly)
+ {
+ uno::Reference< XDictionaryEntry > xEntry =
+ new DicEntry( rWord, bIsNegative, rRplcText );
+ bRes = addEntry_Impl( xEntry );
+ }
+
+ return bRes;
+}
+
+void lcl_SequenceRemoveElementAt(
+ uno::Sequence< uno::Reference< XDictionaryEntry > >& rEntries, int nPos )
+{
+ //TODO: helper for SequenceRemoveElementAt available?
+ if(nPos >= rEntries.getLength())
+ return;
+ uno::Sequence< uno::Reference< XDictionaryEntry > > aTmp(rEntries.getLength() - 1);
+ uno::Reference< XDictionaryEntry > * pOrig = rEntries.getArray();
+ uno::Reference< XDictionaryEntry > * pTemp = aTmp.getArray();
+ int nOffset = 0;
+ for(int i = 0; i < aTmp.getLength(); i++)
+ {
+ if(nPos == i)
+ nOffset++;
+ pTemp[i] = pOrig[i + nOffset];
+ }
+
+ rEntries = aTmp;
+}
+
+sal_Bool SAL_CALL DictionaryNeo::remove( const OUString& aWord )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRemoved = FALSE;
+
+ if (!bIsReadonly)
+ {
+ if (bNeedEntries)
+ loadEntries( aMainURL );
+
+ INT32 nPos;
+ BOOL bFound = seekEntry( aWord, &nPos );
+ DBG_ASSERT( nCount < aEntries.getLength(),
+ "lng : wrong number of entries");
+ DBG_ASSERT(!bFound || nPos < nCount, "lng : index out of range");
+
+ // remove element if found
+ if (bFound)
+ {
+ // entry to be removed
+ uno::Reference< XDictionaryEntry >
+ xDicEntry( aEntries.getConstArray()[ nPos ] );
+ DBG_ASSERT(xDicEntry.is(), "lng : dictionary entry is NULL");
+
+ nCount--;
+
+ //! the following call reduces the length of the sequence by 1 also
+ lcl_SequenceRemoveElementAt( aEntries, nPos );
+ bRemoved = bIsModified = TRUE;
+
+ launchEvent( DictionaryEventFlags::DEL_ENTRY, xDicEntry );
+ }
+ }
+
+ return bRemoved;
+}
+
+sal_Bool SAL_CALL DictionaryNeo::isFull( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (bNeedEntries)
+ loadEntries( aMainURL );
+ return nCount >= DIC_MAX_ENTRIES;
+}
+
+uno::Sequence< uno::Reference< XDictionaryEntry > >
+ SAL_CALL DictionaryNeo::getEntries( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (bNeedEntries)
+ loadEntries( aMainURL );
+ //! return sequence with length equal to the number of dictionary entries
+ //! (internal used sequence may have additional unused elements.)
+ return uno::Sequence< uno::Reference< XDictionaryEntry > >
+ (aEntries.getConstArray(), nCount);
+}
+
+
+void SAL_CALL DictionaryNeo::clear( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bIsReadonly && nCount)
+ {
+ // release all references to old entries and provide space for new ones
+ aEntries = uno::Sequence< uno::Reference< XDictionaryEntry > > ( 32 );
+
+ nCount = 0;
+ bNeedEntries = FALSE;
+ bIsModified = TRUE;
+
+ launchEvent( DictionaryEventFlags::ENTRIES_CLEARED , NULL );
+ }
+}
+
+sal_Bool SAL_CALL DictionaryNeo::addDictionaryEventListener(
+ const uno::Reference< XDictionaryEventListener >& xListener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = FALSE;
+ if (xListener.is())
+ {
+ INT32 nLen = aDicEvtListeners.getLength();
+ bRes = aDicEvtListeners.addInterface( xListener ) != nLen;
+ }
+ return bRes;
+}
+
+sal_Bool SAL_CALL DictionaryNeo::removeDictionaryEventListener(
+ const uno::Reference< XDictionaryEventListener >& xListener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = FALSE;
+ if (xListener.is())
+ {
+ INT32 nLen = aDicEvtListeners.getLength();
+ bRes = aDicEvtListeners.removeInterface( xListener ) != nLen;
+ }
+ return bRes;
+}
+
+
+sal_Bool SAL_CALL DictionaryNeo::hasLocation()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aMainURL.getLength() > 0;
+}
+
+OUString SAL_CALL DictionaryNeo::getLocation()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aMainURL;
+}
+
+sal_Bool SAL_CALL DictionaryNeo::isReadonly()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ return bIsReadonly;
+}
+
+void SAL_CALL DictionaryNeo::store()
+ throw(io::IOException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (bIsModified && hasLocation() && !isReadonly())
+ {
+ if (saveEntries( aMainURL ))
+ {
+#ifdef LINGU_EXCEPTIONS
+ throw io::IOException();
+#endif
+ }
+ else
+ bIsModified = FALSE;
+ }
+}
+
+void SAL_CALL DictionaryNeo::storeAsURL(
+ const OUString& aURL,
+ const uno::Sequence< beans::PropertyValue >& /*rArgs*/ )
+ throw(io::IOException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (saveEntries( aURL ))
+ {
+#ifdef LINGU_EXCEPTIONS
+ throw io::IOException();
+#endif
+ }
+ else
+ {
+ aMainURL = aURL;
+ bIsModified = FALSE;
+ bIsReadonly = IsReadOnly( getLocation() );
+ }
+}
+
+void SAL_CALL DictionaryNeo::storeToURL(
+ const OUString& aURL,
+ const uno::Sequence< beans::PropertyValue >& /*rArgs*/ )
+ throw(io::IOException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (saveEntries( aURL ))
+ {
+#ifdef LINGU_EXCEPTIONS
+ throw io::IOException();
+#endif
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+DicEntry::DicEntry()
+{
+ bIsNegativ = FALSE;
+}
+
+DicEntry::DicEntry(const OUString &rDicFileWord,
+ BOOL bIsNegativWord)
+{
+ if (rDicFileWord.getLength())
+ splitDicFileWord( rDicFileWord, aDicWord, aReplacement );
+ bIsNegativ = bIsNegativWord;
+}
+
+DicEntry::DicEntry(const OUString &rDicWord, BOOL bNegativ,
+ const OUString &rRplcText) :
+ aDicWord (rDicWord),
+ aReplacement (rRplcText),
+ bIsNegativ (bNegativ)
+{
+}
+
+DicEntry::~DicEntry()
+{
+}
+
+void DicEntry::splitDicFileWord(const OUString &rDicFileWord,
+ OUString &rDicWord,
+ OUString &rReplacement)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ static const OUString aDelim( A2OU( "==" ) );
+
+ sal_Int32 nDelimPos = rDicFileWord.indexOf( aDelim );
+ if (-1 != nDelimPos)
+ {
+ sal_Int32 nTriplePos = nDelimPos + 2;
+ if ( nTriplePos < rDicFileWord.getLength()
+ && rDicFileWord[ nTriplePos ] == '=' )
+ ++nDelimPos;
+ rDicWord = rDicFileWord.copy( 0, nDelimPos );
+ rReplacement = rDicFileWord.copy( nDelimPos + 2 );
+ }
+ else
+ {
+ rDicWord = rDicFileWord;
+ rReplacement = OUString();
+ }
+}
+
+OUString SAL_CALL DicEntry::getDictionaryWord( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aDicWord;
+}
+
+sal_Bool SAL_CALL DicEntry::isNegative( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return bIsNegativ;
+}
+
+OUString SAL_CALL DicEntry::getReplacementText( )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aReplacement;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/dicimp.hxx b/linguistic/source/dicimp.hxx
new file mode 100644
index 000000000000..eca18c2166d3
--- /dev/null
+++ b/linguistic/source/dicimp.hxx
@@ -0,0 +1,238 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_DICIMP_HXX_
+#define _LINGUISTIC_DICIMP_HXX_
+
+#include <com/sun/star/linguistic2/XDictionary.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <uno/lbnames.h> // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
+#include <cppuhelper/implbase2.hxx> // helper for implementations
+#include <cppuhelper/implbase1.hxx> // helper for implementations
+#include <cppuhelper/interfacecontainer.h>
+#include <tools/string.hxx>
+#include <tools/stream.hxx>
+
+#include "defs.hxx"
+#include "misc.hxx"
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#define DIC_MAX_ENTRIES 30000
+
+INT16 ReadDicVersion( SvStreamPtr &rpStream, USHORT &nLng, BOOL &bNeg );
+const String GetDicExtension();
+
+///////////////////////////////////////////////////////////////////////////
+
+class DictionaryNeo :
+ public ::cppu::WeakImplHelper2
+ <
+ ::com::sun::star::linguistic2::XDictionary,
+ ::com::sun::star::frame::XStorable
+ >
+{
+
+ ::cppu::OInterfaceContainerHelper aDicEvtListeners;
+ ::com::sun::star::uno::Sequence<
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionaryEntry > > aEntries;
+ ::rtl::OUString aDicName;
+ ::rtl::OUString aMainURL;
+ ::com::sun::star::linguistic2::DictionaryType eDicType;
+ INT16 nCount;
+ INT16 nLanguage;
+ INT16 nDicVersion;
+ BOOL bNeedEntries;
+ BOOL bIsModified;
+ BOOL bIsActive;
+ BOOL bIsReadonly;
+
+ // disallow copy-constructor and assignment-operator for now
+ DictionaryNeo(const DictionaryNeo &);
+ DictionaryNeo & operator = (const DictionaryNeo &);
+
+ void launchEvent(INT16 nEvent,
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionaryEntry > xEntry);
+
+ ULONG loadEntries(const ::rtl::OUString &rMainURL);
+ ULONG saveEntries(const ::rtl::OUString &rMainURL);
+ int cmpDicEntry(const ::rtl::OUString &rWord1,
+ const ::rtl::OUString &rWord2,
+ BOOL bSimilarOnly = FALSE);
+ BOOL seekEntry(const ::rtl::OUString &rWord, INT32 *pPos,
+ BOOL bSimilarOnly = FALSE);
+ BOOL isSorted();
+
+ BOOL addEntry_Impl(const ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionaryEntry > xDicEntry,
+ BOOL bIsLoadEntries = FALSE);
+
+public:
+ DictionaryNeo();
+ DictionaryNeo(const ::rtl::OUString &rName, INT16 nLang,
+ ::com::sun::star::linguistic2::DictionaryType eType,
+ const ::rtl::OUString &rMainURL,
+ BOOL bWriteable );
+ virtual ~DictionaryNeo();
+
+ // XNamed
+ virtual ::rtl::OUString SAL_CALL
+ getName()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL
+ setName( const ::rtl::OUString& aName )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ // XDictionary
+ virtual ::com::sun::star::linguistic2::DictionaryType SAL_CALL
+ getDictionaryType()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL
+ setActive( sal_Bool bActivate )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ isActive()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL
+ getCount()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::lang::Locale SAL_CALL
+ getLocale()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL
+ setLocale( const ::com::sun::star::lang::Locale& aLocale )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionaryEntry > SAL_CALL
+ getEntry( const ::rtl::OUString& aWord )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ addEntry( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionaryEntry >& xDicEntry )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ add( const ::rtl::OUString& aWord, sal_Bool bIsNegative,
+ const ::rtl::OUString& aRplcText )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ remove( const ::rtl::OUString& aWord )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ isFull()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence<
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionaryEntry > > SAL_CALL
+ getEntries()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL
+ clear()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ addDictionaryEventListener( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionaryEventListener >& xListener )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ removeDictionaryEventListener( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionaryEventListener >& xListener )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ // XStorable
+ virtual sal_Bool SAL_CALL
+ hasLocation()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL
+ getLocation()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ isReadonly()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL
+ store()
+ throw(::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL
+ storeAsURL( const ::rtl::OUString& aURL,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::beans::PropertyValue >& aArgs )
+ throw(::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL
+ storeToURL( const ::rtl::OUString& aURL,
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::beans::PropertyValue >& aArgs )
+ throw(::com::sun::star::io::IOException,
+ ::com::sun::star::uno::RuntimeException);
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+
+class DicEntry :
+ public cppu::WeakImplHelper1
+ <
+ ::com::sun::star::linguistic2::XDictionaryEntry
+ >
+{
+ ::rtl::OUString aDicWord, // including hyphen positions represented by "="
+ aReplacement; // including hyphen positions represented by "="
+ BOOL bIsNegativ;
+
+ // disallow copy-constructor and assignment-operator for now
+ DicEntry(const DicEntry &);
+ DicEntry & operator = (const DicEntry &);
+
+ void splitDicFileWord(const ::rtl::OUString &rDicFileWord,
+ ::rtl::OUString &rDicWord,
+ ::rtl::OUString &rReplacement);
+
+public:
+ DicEntry();
+ DicEntry(const ::rtl::OUString &rDicFileWord, BOOL bIsNegativ);
+ DicEntry(const ::rtl::OUString &rDicWord, BOOL bIsNegativ,
+ const ::rtl::OUString &rRplcText);
+ virtual ~DicEntry();
+
+ // XDictionaryEntry
+ virtual ::rtl::OUString SAL_CALL
+ getDictionaryWord() throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ isNegative() throw(::com::sun::star::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL
+ getReplacementText() throw(::com::sun::star::uno::RuntimeException);
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/dlistimp.cxx b/linguistic/source/dlistimp.cxx
new file mode 100644
index 000000000000..817dbeb311ca
--- /dev/null
+++ b/linguistic/source/dlistimp.cxx
@@ -0,0 +1,969 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+#include <cppuhelper/factory.hxx>
+#include <i18npool/mslangid.hxx>
+#include <osl/file.hxx>
+#include <tools/fsys.hxx>
+#include <tools/stream.hxx>
+#include <tools/urlobj.hxx>
+#include <i18npool/mslangid.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/useroptions.hxx>
+#include <cppuhelper/factory.hxx> // helper for factories
+#include <unotools/localfilehelper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/linguistic2/DictionaryEventFlags.hpp>
+#include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/ucb/XSimpleFileAccess.hpp>
+
+#include "defs.hxx"
+#include "dlistimp.hxx"
+#include "dicimp.hxx"
+#include "lngopt.hxx"
+
+#include "defs.hxx"
+#include "dlistimp.hxx"
+#include "dicimp.hxx"
+#include "lngopt.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::linguistic2;
+using namespace linguistic;
+
+///////////////////////////////////////////////////////////////////////////
+
+static BOOL IsVers2OrNewer( const String& rFileURL, USHORT& nLng, BOOL& bNeg );
+
+static void AddInternal( const uno::Reference< XDictionary > &rDic,
+ const rtl::OUString& rNew );
+static void AddUserData( const uno::Reference< XDictionary > &rDic );
+
+///////////////////////////////////////////////////////////////////////////
+
+class DicEvtListenerHelper :
+ public cppu::WeakImplHelper1
+ <
+ XDictionaryEventListener
+ >
+{
+ cppu::OInterfaceContainerHelper aDicListEvtListeners;
+ uno::Sequence< DictionaryEvent > aCollectDicEvt;
+ uno::Reference< XDictionaryList > xMyDicList;
+
+ INT16 nCondensedEvt;
+ INT16 nNumCollectEvtListeners,
+ nNumVerboseListeners;
+
+public:
+ DicEvtListenerHelper( const uno::Reference< XDictionaryList > &rxDicList );
+ virtual ~DicEvtListenerHelper();
+
+ // XEventListener
+ virtual void SAL_CALL
+ disposing( const EventObject& rSource )
+ throw(RuntimeException);
+
+ // XDictionaryEventListener
+ virtual void SAL_CALL
+ processDictionaryEvent( const DictionaryEvent& rDicEvent )
+ throw(RuntimeException);
+
+ // non-UNO functions
+ void DisposeAndClear( const EventObject &rEvtObj );
+
+ BOOL AddDicListEvtListener(
+ const uno::Reference< XDictionaryListEventListener >& rxListener,
+ BOOL bReceiveVerbose );
+ BOOL RemoveDicListEvtListener(
+ const uno::Reference< XDictionaryListEventListener >& rxListener );
+ INT16 BeginCollectEvents();
+ INT16 EndCollectEvents();
+ INT16 FlushEvents();
+ void ClearEvents() { nCondensedEvt = 0; }
+};
+
+
+DicEvtListenerHelper::DicEvtListenerHelper(
+ const uno::Reference< XDictionaryList > &rxDicList ) :
+ aDicListEvtListeners ( GetLinguMutex() ),
+ xMyDicList ( rxDicList )
+{
+ nCondensedEvt = 0;
+ nNumCollectEvtListeners = nNumVerboseListeners = 0;
+}
+
+
+DicEvtListenerHelper::~DicEvtListenerHelper()
+{
+ DBG_ASSERT(aDicListEvtListeners.getLength() == 0,
+ "lng : event listeners are still existing");
+}
+
+
+void DicEvtListenerHelper::DisposeAndClear( const EventObject &rEvtObj )
+{
+ aDicListEvtListeners.disposeAndClear( rEvtObj );
+}
+
+
+void SAL_CALL DicEvtListenerHelper::disposing( const EventObject& rSource )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Reference< XInterface > xSrc( rSource.Source );
+
+ // remove event object from EventListener list
+ if (xSrc.is())
+ aDicListEvtListeners.removeInterface( xSrc );
+
+ // if object is a dictionary then remove it from the dictionary list
+ // Note: this will probably happen only if someone makes a XDictionary
+ // implementation of his own that is also a XComponent.
+ uno::Reference< XDictionary > xDic( xSrc, UNO_QUERY );
+ if (xDic.is())
+ {
+ xMyDicList->removeDictionary( xDic );
+ }
+}
+
+
+void SAL_CALL DicEvtListenerHelper::processDictionaryEvent(
+ const DictionaryEvent& rDicEvent )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Reference< XDictionary > xDic( rDicEvent.Source, UNO_QUERY );
+ DBG_ASSERT(xDic.is(), "lng : missing event source");
+
+ // assert that there is a corresponding dictionary entry if one was
+ // added or deleted
+ uno::Reference< XDictionaryEntry > xDicEntry( rDicEvent.xDictionaryEntry, UNO_QUERY );
+ DBG_ASSERT( !(rDicEvent.nEvent &
+ (DictionaryEventFlags::ADD_ENTRY | DictionaryEventFlags::DEL_ENTRY))
+ || xDicEntry.is(),
+ "lng : missing dictionary entry" );
+
+ /*BOOL bActiveDicsModified = FALSE;*/
+ //
+ // evaluate DictionaryEvents and update data for next DictionaryListEvent
+ //
+ DictionaryType eDicType = xDic->getDictionaryType();
+ DBG_ASSERT(eDicType != DictionaryType_MIXED,
+ "lng : unexpected dictionary type");
+ if ((rDicEvent.nEvent & DictionaryEventFlags::ADD_ENTRY) && xDic->isActive())
+ nCondensedEvt |= xDicEntry->isNegative() ?
+ DictionaryListEventFlags::ADD_NEG_ENTRY :
+ DictionaryListEventFlags::ADD_POS_ENTRY;
+ if ((rDicEvent.nEvent & DictionaryEventFlags::DEL_ENTRY) && xDic->isActive())
+ nCondensedEvt |= xDicEntry->isNegative() ?
+ DictionaryListEventFlags::DEL_NEG_ENTRY :
+ DictionaryListEventFlags::DEL_POS_ENTRY;
+ if ((rDicEvent.nEvent & DictionaryEventFlags::ENTRIES_CLEARED) && xDic->isActive())
+ nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
+ DictionaryListEventFlags::DEL_NEG_ENTRY :
+ DictionaryListEventFlags::DEL_POS_ENTRY;
+ if ((rDicEvent.nEvent & DictionaryEventFlags::CHG_LANGUAGE) && xDic->isActive())
+ nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
+ DictionaryListEventFlags::DEACTIVATE_NEG_DIC
+ | DictionaryListEventFlags::ACTIVATE_NEG_DIC :
+ DictionaryListEventFlags::DEACTIVATE_POS_DIC
+ | DictionaryListEventFlags::ACTIVATE_POS_DIC;
+ if ((rDicEvent.nEvent & DictionaryEventFlags::ACTIVATE_DIC))
+ nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
+ DictionaryListEventFlags::ACTIVATE_NEG_DIC :
+ DictionaryListEventFlags::ACTIVATE_POS_DIC;
+ if ((rDicEvent.nEvent & DictionaryEventFlags::DEACTIVATE_DIC))
+ nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
+ DictionaryListEventFlags::DEACTIVATE_NEG_DIC :
+ DictionaryListEventFlags::DEACTIVATE_POS_DIC;
+
+ // update list of collected events if needs to be
+ if (nNumVerboseListeners > 0)
+ {
+ INT32 nColEvts = aCollectDicEvt.getLength();
+ aCollectDicEvt.realloc( nColEvts + 1 );
+ aCollectDicEvt.getArray()[ nColEvts ] = rDicEvent;
+ }
+
+ if (nNumCollectEvtListeners == 0 && nCondensedEvt != 0)
+ FlushEvents();
+}
+
+
+BOOL DicEvtListenerHelper::AddDicListEvtListener(
+ const uno::Reference< XDictionaryListEventListener >& xListener,
+ BOOL /*bReceiveVerbose*/ )
+{
+ DBG_ASSERT( xListener.is(), "empty reference" );
+ INT32 nCount = aDicListEvtListeners.getLength();
+ return aDicListEvtListeners.addInterface( xListener ) != nCount;
+}
+
+
+BOOL DicEvtListenerHelper::RemoveDicListEvtListener(
+ const uno::Reference< XDictionaryListEventListener >& xListener )
+{
+ DBG_ASSERT( xListener.is(), "empty reference" );
+ INT32 nCount = aDicListEvtListeners.getLength();
+ return aDicListEvtListeners.removeInterface( xListener ) != nCount;
+}
+
+
+INT16 DicEvtListenerHelper::BeginCollectEvents()
+{
+ return ++nNumCollectEvtListeners;
+}
+
+
+INT16 DicEvtListenerHelper::EndCollectEvents()
+{
+ DBG_ASSERT(nNumCollectEvtListeners > 0, "lng: mismatched function call");
+ if (nNumCollectEvtListeners > 0)
+ {
+ FlushEvents();
+ nNumCollectEvtListeners--;
+ }
+
+ return nNumCollectEvtListeners;
+}
+
+
+INT16 DicEvtListenerHelper::FlushEvents()
+{
+ if (0 != nCondensedEvt)
+ {
+ // build DictionaryListEvent to pass on to listeners
+ uno::Sequence< DictionaryEvent > aDicEvents;
+ if (nNumVerboseListeners > 0)
+ aDicEvents = aCollectDicEvt;
+ DictionaryListEvent aEvent( xMyDicList, nCondensedEvt, aDicEvents );
+
+ // pass on event
+ cppu::OInterfaceIteratorHelper aIt( aDicListEvtListeners );
+ while (aIt.hasMoreElements())
+ {
+ uno::Reference< XDictionaryListEventListener > xRef( aIt.next(), UNO_QUERY );
+ if (xRef.is())
+ xRef->processDictionaryListEvent( aEvent );
+ }
+
+ // clear "list" of events
+ nCondensedEvt = 0;
+ aCollectDicEvt.realloc( 0 );
+ }
+
+ return nNumCollectEvtListeners;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+void DicList::MyAppExitListener::AtExit()
+{
+ rMyDicList.SaveDics();
+}
+
+
+DicList::DicList() :
+ aEvtListeners ( GetLinguMutex() )
+{
+ pDicEvtLstnrHelper = new DicEvtListenerHelper( this );
+ xDicEvtLstnrHelper = pDicEvtLstnrHelper;
+ bDisposing = FALSE;
+ bInCreation = FALSE;
+
+ pExitListener = new MyAppExitListener( *this );
+ xExitListener = pExitListener;
+ pExitListener->Activate();
+}
+
+DicList::~DicList()
+{
+ pExitListener->Deactivate();
+}
+
+
+void DicList::SearchForDictionaries(
+ DictionaryVec_t&rDicList,
+ const String &rDicDirURL,
+ BOOL bIsWriteablePath )
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ const uno::Sequence< rtl::OUString > aDirCnt( utl::LocalFileHelper::
+ GetFolderContents( rDicDirURL, FALSE ) );
+ const rtl::OUString *pDirCnt = aDirCnt.getConstArray();
+ INT32 nEntries = aDirCnt.getLength();
+
+ String aDCN( String::CreateFromAscii( "dcn" ) );
+ String aDCP( String::CreateFromAscii( "dcp" ) );
+ for (INT32 i = 0; i < nEntries; ++i)
+ {
+ String aURL( pDirCnt[i] );
+ USHORT nLang = LANGUAGE_NONE;
+ BOOL bNeg = FALSE;
+
+ if(!::IsVers2OrNewer( aURL, nLang, bNeg ))
+ {
+ // Wenn kein
+ xub_StrLen nPos = aURL.Search('.');
+ String aExt(aURL.Copy(nPos + 1));
+ aExt.ToLowerAscii();
+
+ if(aExt == aDCN) // negativ
+ bNeg = TRUE;
+ else if(aExt == aDCP) // positiv
+ bNeg = FALSE;
+ else
+ continue; // andere Files
+ }
+
+ // Aufnehmen in die Liste der Dictionaries
+ // Wenn existent nicht aufnehmen
+ //
+ INT16 nSystemLanguage = MsLangId::getSystemLanguage();
+ String aTmp1 = ToLower( aURL, nSystemLanguage );
+ xub_StrLen nPos = aTmp1.SearchBackward( '/' );
+ if (STRING_NOTFOUND != nPos)
+ aTmp1 = aTmp1.Copy( nPos + 1 );
+ String aTmp2;
+ size_t j;
+ size_t nCount = rDicList.size();
+ for(j = 0; j < nCount; j++)
+ {
+ aTmp2 = rDicList[j]->getName().getStr();
+ aTmp2 = ToLower( aTmp2, nSystemLanguage );
+ if(aTmp1 == aTmp2)
+ break;
+ }
+ if(j >= nCount) // dictionary not yet in DicList
+ {
+ // get decoded dictionary file name
+ INetURLObject aURLObj( aURL );
+ String aDicName = aURLObj.getName( INetURLObject::LAST_SEGMENT,
+ true, INetURLObject::DECODE_WITH_CHARSET,
+ RTL_TEXTENCODING_UTF8 );
+
+ DictionaryType eType = bNeg ? DictionaryType_NEGATIVE : DictionaryType_POSITIVE;
+ uno::Reference< XDictionary > xDic =
+ new DictionaryNeo( aDicName, nLang, eType, aURL, bIsWriteablePath );
+
+ addDictionary( xDic );
+ nCount++;
+ }
+ }
+}
+
+
+INT32 DicList::GetDicPos(const uno::Reference< XDictionary > &xDic)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ INT32 nPos = -1;
+ DictionaryVec_t& rDicList = GetOrCreateDicList();
+ size_t n = rDicList.size();
+ for (size_t i = 0; i < n; i++)
+ {
+ if ( rDicList[i] == xDic )
+ return i;
+ }
+ return nPos;
+}
+
+
+uno::Reference< XInterface > SAL_CALL
+ DicList_CreateInstance( const uno::Reference< XMultiServiceFactory > & /*rSMgr*/ )
+ throw(Exception)
+{
+ uno::Reference< XInterface > xService = (cppu::OWeakObject *) new DicList;
+ return xService;
+}
+
+sal_Int16 SAL_CALL DicList::getCount() throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+ return static_cast< sal_Int16 >(GetOrCreateDicList().size());
+}
+
+uno::Sequence< uno::Reference< XDictionary > > SAL_CALL
+ DicList::getDictionaries()
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ DictionaryVec_t& rDicList = GetOrCreateDicList();
+
+ uno::Sequence< uno::Reference< XDictionary > > aDics( rDicList.size() );
+ uno::Reference< XDictionary > *pDic = aDics.getArray();
+
+ INT32 n = (USHORT) aDics.getLength();
+ for (INT32 i = 0; i < n; i++)
+ pDic[i] = rDicList[i];
+
+ return aDics;
+}
+
+uno::Reference< XDictionary > SAL_CALL
+ DicList::getDictionaryByName( const rtl::OUString& aDictionaryName )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Reference< XDictionary > xDic;
+ DictionaryVec_t& rDicList = GetOrCreateDicList();
+ size_t nCount = rDicList.size();
+ for (size_t i = 0; i < nCount; i++)
+ {
+ const uno::Reference< XDictionary > &rDic = rDicList[i];
+ if (rDic.is() && rDic->getName() == aDictionaryName)
+ {
+ xDic = rDic;
+ break;
+ }
+ }
+
+ return xDic;
+}
+
+sal_Bool SAL_CALL DicList::addDictionary(
+ const uno::Reference< XDictionary >& xDictionary )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ if (bDisposing)
+ return FALSE;
+
+ BOOL bRes = FALSE;
+ if (xDictionary.is())
+ {
+ DictionaryVec_t& rDicList = GetOrCreateDicList();
+ rDicList.push_back( xDictionary );
+ bRes = TRUE;
+
+ // add listener helper to the dictionaries listener lists
+ xDictionary->addDictionaryEventListener( xDicEvtLstnrHelper );
+ }
+ return bRes;
+}
+
+sal_Bool SAL_CALL
+ DicList::removeDictionary( const uno::Reference< XDictionary >& xDictionary )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ if (bDisposing)
+ return FALSE;
+
+ BOOL bRes = FALSE;
+ INT32 nPos = GetDicPos( xDictionary );
+ if (nPos >= 0)
+ {
+ // remove dictionary list from the dictionaries listener lists
+ DictionaryVec_t& rDicList = GetOrCreateDicList();
+ uno::Reference< XDictionary > xDic( rDicList[ nPos ] );
+ DBG_ASSERT(xDic.is(), "lng : empty reference");
+ if (xDic.is())
+ {
+ // deactivate dictionary if not already done
+ xDic->setActive( FALSE );
+
+ xDic->removeDictionaryEventListener( xDicEvtLstnrHelper );
+ }
+
+ // remove element at nPos
+ rDicList.erase( rDicList.begin() + nPos );
+ bRes = TRUE;
+ }
+ return bRes;
+}
+
+sal_Bool SAL_CALL DicList::addDictionaryListEventListener(
+ const uno::Reference< XDictionaryListEventListener >& xListener,
+ sal_Bool bReceiveVerbose )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ if (bDisposing)
+ return FALSE;
+
+ DBG_ASSERT(!bReceiveVerbose, "lng : not yet supported");
+
+ BOOL bRes = FALSE;
+ if (xListener.is()) //! don't add empty references
+ {
+ bRes = pDicEvtLstnrHelper->
+ AddDicListEvtListener( xListener, bReceiveVerbose );
+ }
+ return bRes;
+}
+
+sal_Bool SAL_CALL DicList::removeDictionaryListEventListener(
+ const uno::Reference< XDictionaryListEventListener >& xListener )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ if (bDisposing)
+ return FALSE;
+
+ BOOL bRes = FALSE;
+ if(xListener.is())
+ {
+ bRes = pDicEvtLstnrHelper->RemoveDicListEvtListener( xListener );
+ }
+ return bRes;
+}
+
+sal_Int16 SAL_CALL DicList::beginCollectEvents() throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+ return pDicEvtLstnrHelper->BeginCollectEvents();
+}
+
+sal_Int16 SAL_CALL DicList::endCollectEvents() throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+ return pDicEvtLstnrHelper->EndCollectEvents();
+}
+
+sal_Int16 SAL_CALL DicList::flushEvents() throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+ return pDicEvtLstnrHelper->FlushEvents();
+}
+
+uno::Reference< XDictionary > SAL_CALL
+ DicList::createDictionary( const rtl::OUString& rName, const Locale& rLocale,
+ DictionaryType eDicType, const rtl::OUString& rURL )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+ bool bIsWriteablePath = rURL.match( GetDictionaryWriteablePath(), 0 );
+ return new DictionaryNeo( rName, nLanguage, eDicType, rURL, bIsWriteablePath );
+}
+
+
+uno::Reference< XDictionaryEntry > SAL_CALL
+ DicList::queryDictionaryEntry( const rtl::OUString& rWord, const Locale& rLocale,
+ sal_Bool bSearchPosDics, sal_Bool bSearchSpellEntry )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+ return SearchDicList( this, rWord, LocaleToLanguage( rLocale ),
+ bSearchPosDics, bSearchSpellEntry );
+}
+
+
+void SAL_CALL
+ DicList::dispose()
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bDisposing)
+ {
+ bDisposing = TRUE;
+ EventObject aEvtObj( (XDictionaryList *) this );
+
+ aEvtListeners.disposeAndClear( aEvtObj );
+ if (pDicEvtLstnrHelper)
+ pDicEvtLstnrHelper->DisposeAndClear( aEvtObj );
+
+ //! avoid creation of dictionaries if not already done
+ if (aDicList.size() > 0)
+ {
+ DictionaryVec_t& rDicList = GetOrCreateDicList();
+ size_t nCount = rDicList.size();
+ for (size_t i = 0; i < nCount; i++)
+ {
+ uno::Reference< XDictionary > xDic( rDicList[i], UNO_QUERY );
+
+ // save (modified) dictionaries
+ uno::Reference< frame::XStorable > xStor( xDic , UNO_QUERY );
+ if (xStor.is())
+ {
+ try
+ {
+ if (!xStor->isReadonly() && xStor->hasLocation())
+ xStor->store();
+ }
+ catch(Exception &)
+ {
+ }
+ }
+
+ // release references to (members of) this object hold by
+ // dictionaries
+ if (xDic.is())
+ xDic->removeDictionaryEventListener( xDicEvtLstnrHelper );
+ }
+ }
+ }
+}
+
+void SAL_CALL
+ DicList::addEventListener( const uno::Reference< XEventListener >& rxListener )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bDisposing && rxListener.is())
+ aEvtListeners.addInterface( rxListener );
+}
+
+void SAL_CALL
+ DicList::removeEventListener( const uno::Reference< XEventListener >& rxListener )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bDisposing && rxListener.is())
+ aEvtListeners.removeInterface( rxListener );
+}
+
+void DicList::_CreateDicList()
+{
+ bInCreation = TRUE;
+
+ // look for dictionaries
+ const rtl::OUString aWriteablePath( GetDictionaryWriteablePath() );
+ uno::Sequence< rtl::OUString > aPaths( GetDictionaryPaths() );
+ const rtl::OUString *pPaths = aPaths.getConstArray();
+ for (sal_Int32 i = 0; i < aPaths.getLength(); ++i)
+ {
+ const BOOL bIsWriteablePath = (pPaths[i] == aWriteablePath);
+ SearchForDictionaries( aDicList, pPaths[i], bIsWriteablePath );
+ }
+
+ // create IgnoreAllList dictionary with empty URL (non persistent)
+ // and add it to list
+ rtl::OUString aDicName( A2OU( "IgnoreAllList" ) );
+ uno::Reference< XDictionary > xIgnAll(
+ createDictionary( aDicName, CreateLocale( LANGUAGE_NONE ),
+ DictionaryType_POSITIVE, rtl::OUString() ) );
+ if (xIgnAll.is())
+ {
+ AddUserData( xIgnAll );
+ xIgnAll->setActive( TRUE );
+ addDictionary( xIgnAll );
+ }
+
+
+ // evaluate list of dictionaries to be activated from configuration
+ //
+ //! to suppress overwriting the list of active dictionaries in the
+ //! configuration with incorrect arguments during the following
+ //! activation of the dictionaries
+ pDicEvtLstnrHelper->BeginCollectEvents();
+ //
+ const uno::Sequence< rtl::OUString > aActiveDics( aOpt.GetActiveDics() );
+ const rtl::OUString *pActiveDic = aActiveDics.getConstArray();
+ INT32 nLen = aActiveDics.getLength();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ if (pActiveDic[i].getLength())
+ {
+ uno::Reference< XDictionary > xDic( getDictionaryByName( pActiveDic[i] ) );
+ if (xDic.is())
+ xDic->setActive( TRUE );
+ }
+ }
+
+ // suppress collected events during creation of the dictionary list.
+ // there should be no events during creation.
+ pDicEvtLstnrHelper->ClearEvents();
+
+ pDicEvtLstnrHelper->EndCollectEvents();
+
+ bInCreation = FALSE;
+}
+
+
+void DicList::SaveDics()
+{
+ // save dics only if they have already been used/created.
+ //! don't create them just for the purpose of saving them !
+ if (aDicList.size() > 0)
+ {
+ // save (modified) dictionaries
+ DictionaryVec_t& rDicList = GetOrCreateDicList();
+ size_t nCount = rDicList.size();;
+ for (size_t i = 0; i < nCount; i++)
+ {
+ // save (modified) dictionaries
+ uno::Reference< frame::XStorable > xStor( rDicList[i], UNO_QUERY );
+ if (xStor.is())
+ {
+ try
+ {
+ if (!xStor->isReadonly() && xStor->hasLocation())
+ xStor->store();
+ }
+ catch(Exception &)
+ {
+ }
+ }
+ }
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// Service specific part
+//
+
+rtl::OUString SAL_CALL DicList::getImplementationName( ) throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+ return getImplementationName_Static();
+}
+
+
+sal_Bool SAL_CALL DicList::supportsService( const rtl::OUString& ServiceName )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Sequence< rtl::OUString > aSNL = getSupportedServiceNames();
+ const rtl::OUString * pArray = aSNL.getConstArray();
+ for( INT32 i = 0; i < aSNL.getLength(); i++ )
+ if( pArray[i] == ServiceName )
+ return TRUE;
+ return FALSE;
+}
+
+
+uno::Sequence< rtl::OUString > SAL_CALL DicList::getSupportedServiceNames( )
+ throw(RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+ return getSupportedServiceNames_Static();
+}
+
+
+uno::Sequence< rtl::OUString > DicList::getSupportedServiceNames_Static() throw()
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Sequence< rtl::OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich
+ aSNS.getArray()[0] = A2OU( SN_DICTIONARY_LIST );
+ return aSNS;
+}
+
+
+sal_Bool SAL_CALL DicList_writeInfo(
+ void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey )
+{
+ try
+ {
+ String aImpl( '/' );
+ aImpl += DicList::getImplementationName_Static().getStr();
+ aImpl.AppendAscii( "/UNO/SERVICES" );
+ uno::Reference< registry::XRegistryKey > xNewKey =
+ pRegistryKey->createKey(aImpl );
+ uno::Sequence< rtl::OUString > aServices =
+ DicList::getSupportedServiceNames_Static();
+ for( INT32 i = 0; i < aServices.getLength(); i++ )
+ xNewKey->createKey( aServices.getConstArray()[i]);
+
+ return sal_True;
+ }
+ catch(Exception &)
+ {
+ return sal_False;
+ }
+}
+
+
+void * SAL_CALL DicList_getFactory( const sal_Char * pImplName,
+ XMultiServiceFactory * pServiceManager, void * )
+{
+ void * pRet = 0;
+ if ( !DicList::getImplementationName_Static().compareToAscii( pImplName ) )
+ {
+ uno::Reference< XSingleServiceFactory > xFactory =
+ cppu::createOneInstanceFactory(
+ pServiceManager,
+ DicList::getImplementationName_Static(),
+ DicList_CreateInstance,
+ DicList::getSupportedServiceNames_Static());
+ // acquire, because we return an interface pointer instead of a reference
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+ return pRet;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+xub_StrLen lcl_GetToken( String &rToken,
+ const String &rText, xub_StrLen nPos, const String &rDelim )
+{
+ xub_StrLen nRes = STRING_LEN;
+
+ if (rText.Len() == 0 || nPos >= rText.Len())
+ rToken = String();
+ else if (rDelim.Len() == 0)
+ {
+ rToken = rText;
+ if (rToken.Len())
+ nRes = rText.Len();
+ }
+ else
+ {
+ xub_StrLen i;
+ for (i = nPos; i < rText.Len(); ++i)
+ {
+ if (STRING_NOTFOUND != rDelim.Search( rText.GetChar(i) ))
+ break;
+ }
+
+ if (i >= rText.Len()) // delimeter not found
+ rToken = rText.Copy( nPos );
+ else
+ rToken = rText.Copy( nPos, sal::static_int_cast< xub_StrLen >((INT32) i - nPos) );
+ nRes = i + 1; // continue after found delimeter
+ }
+
+ return nRes;
+}
+
+
+static void AddInternal(
+ const uno::Reference<XDictionary> &rDic,
+ const rtl::OUString& rNew )
+{
+ if (rDic.is())
+ {
+ //! TL TODO: word iterator should be used to break up the text
+ static const char *pDefWordDelim =
+ "!\"#$%&'()*+,-./:;<=>?[]\\_^`{|}~\t \n";
+ ByteString aDummy( pDefWordDelim );
+ String aDelim( aDummy, osl_getThreadTextEncoding() );
+ aDelim.EraseAllChars( '.' );
+
+ String aToken;
+ xub_StrLen nPos = 0;
+ while (STRING_LEN !=
+ (nPos = lcl_GetToken( aToken, rNew, nPos, aDelim )))
+ {
+ if( aToken.Len() && !IsNumeric( aToken ) )
+ {
+ rDic->add( aToken, FALSE, rtl::OUString() );
+ }
+ }
+ }
+}
+
+static void AddUserData( const uno::Reference< XDictionary > &rDic )
+{
+ if (rDic.is())
+ {
+ SvtUserOptions aUserOpt;
+ AddInternal( rDic, aUserOpt.GetFullName() );
+ AddInternal( rDic, aUserOpt.GetCompany() );
+ AddInternal( rDic, aUserOpt.GetStreet() );
+ AddInternal( rDic, aUserOpt.GetCity() );
+ AddInternal( rDic, aUserOpt.GetTitle() );
+ AddInternal( rDic, aUserOpt.GetPosition() );
+ AddInternal( rDic, aUserOpt.GetEmail() );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+#if defined _MSC_VER
+#pragma optimize("g",off)
+#endif
+
+static BOOL IsVers2OrNewer( const String& rFileURL, USHORT& nLng, BOOL& bNeg )
+{
+ if (rFileURL.Len() == 0)
+ return FALSE;
+ String aDIC( GetDicExtension() );
+ String aExt;
+ xub_StrLen nPos = rFileURL.SearchBackward( '.' );
+ if (STRING_NOTFOUND != nPos)
+ aExt = rFileURL.Copy( nPos + 1 );
+ aExt.ToLowerAscii();
+
+ if(aExt != aDIC)
+ return FALSE;
+
+ // get stream to be used
+ uno::Reference< lang::XMultiServiceFactory > xServiceFactory( comphelper::getProcessServiceFactory() );
+
+ // get XInputStream stream
+ uno::Reference< io::XInputStream > xStream;
+ try
+ {
+ uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance(
+ A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW );
+ xStream = xAccess->openFileRead( rFileURL );
+ }
+ catch (uno::Exception & e)
+ {
+ DBG_ASSERT( 0, "failed to get input stream" );
+ (void) e;
+ }
+ DBG_ASSERT( xStream.is(), "failed to get stream for read" );
+ if (!xStream.is())
+ return FALSE;
+
+ SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) );
+
+ int nDicVersion = ReadDicVersion(pStream, nLng, bNeg);
+ if (2 == nDicVersion || nDicVersion >= 5)
+ return TRUE;
+
+ return FALSE;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/dlistimp.hxx b/linguistic/source/dlistimp.hxx
new file mode 100644
index 000000000000..c93cd6b907c6
--- /dev/null
+++ b/linguistic/source/dlistimp.hxx
@@ -0,0 +1,151 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_DLISTIMP_HXX_
+#define _LINGUISTIC_DLISTIMP_HXX_
+
+#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <uno/lbnames.h> // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
+#include <cppuhelper/implbase1.hxx> // helper for implementations
+#include <cppuhelper/implbase3.hxx> // helper for implementations
+#include <cppuhelper/interfacecontainer.h>
+#include <tools/debug.hxx>
+
+#include <vector>
+#include <memory>
+
+#include "misc.hxx"
+#include "lngopt.hxx"
+
+class DicEvtListenerHelper;
+
+///////////////////////////////////////////////////////////////////////////
+
+class DicList :
+ public cppu::WeakImplHelper3
+ <
+ ::com::sun::star::linguistic2::XSearchableDictionaryList,
+ ::com::sun::star::lang::XComponent,
+ ::com::sun::star::lang::XServiceInfo
+ >
+{
+ class MyAppExitListener : public linguistic::AppExitListener
+ {
+ DicList & rMyDicList;
+
+ public:
+ MyAppExitListener( DicList &rDicList ) : rMyDicList( rDicList ) {}
+ virtual void AtExit();
+ };
+
+ LinguOptions aOpt;
+
+ ::cppu::OInterfaceContainerHelper aEvtListeners;
+
+ typedef std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XDictionary > > DictionaryVec_t;
+ DictionaryVec_t aDicList;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::
+ XDictionaryEventListener > xDicEvtLstnrHelper;
+ DicEvtListenerHelper *pDicEvtLstnrHelper;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::frame::
+ XTerminateListener > xExitListener;
+ MyAppExitListener *pExitListener;
+
+ BOOL bDisposing;
+ BOOL bInCreation;
+
+ // disallow copy-constructor and assignment-operator for now
+ DicList( const DicList & );
+ DicList & operator = (const DicList &);
+
+ void _CreateDicList();
+ DictionaryVec_t & GetOrCreateDicList()
+ {
+ if (!bInCreation && aDicList.size() == 0)
+ _CreateDicList();
+ return aDicList;
+ }
+
+ void LaunchEvent(INT16 nEvent, com::sun::star::uno::Sequence<
+ ::com::sun::star::linguistic2::XDictionary > xDic);
+ void SearchForDictionaries( DictionaryVec_t &rDicList,
+ const String &rDicDir, BOOL bIsWritePath );
+ INT32 GetDicPos(const com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionary > &xDic);
+
+public:
+ DicList();
+ virtual ~DicList();
+
+ // XDictionaryList
+ virtual ::sal_Int16 SAL_CALL getCount( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XDictionary > > SAL_CALL getDictionaries( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XDictionary > SAL_CALL getDictionaryByName( const ::rtl::OUString& aDictionaryName ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL addDictionary( const ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XDictionary >& xDictionary ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL removeDictionary( const ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XDictionary >& xDictionary ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL addDictionaryListEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XDictionaryListEventListener >& xListener, ::sal_Bool bReceiveVerbose ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL removeDictionaryListEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XDictionaryListEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Int16 SAL_CALL beginCollectEvents( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Int16 SAL_CALL endCollectEvents( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Int16 SAL_CALL flushEvents( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XDictionary > SAL_CALL createDictionary( const ::rtl::OUString& aName, const ::com::sun::star::lang::Locale& aLocale, ::com::sun::star::linguistic2::DictionaryType eDicType, const ::rtl::OUString& aURL ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XSearchableDictionaryList
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XDictionaryEntry > SAL_CALL queryDictionaryEntry( const ::rtl::OUString& aWord, const ::com::sun::star::lang::Locale& aLocale, sal_Bool bSearchPosDics, sal_Bool bSpellEntry ) throw(::com::sun::star::uno::RuntimeException);
+
+ // XComponent
+ virtual void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw(::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName() throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw(::com::sun::star::uno::RuntimeException);
+
+
+ static inline ::rtl::OUString getImplementationName_Static() throw();
+ static com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedServiceNames_Static() throw();
+
+ // non UNO-specific
+ void SaveDics();
+};
+
+inline ::rtl::OUString DicList::getImplementationName_Static() throw()
+{
+ return A2OU( "com.sun.star.lingu2.DicList" );
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/gciterator.cxx b/linguistic/source/gciterator.cxx
new file mode 100644
index 000000000000..6485e6e841b7
--- /dev/null
+++ b/linguistic/source/gciterator.cxx
@@ -0,0 +1,1359 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#include "precompiled_linguistic.hxx"
+
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XNameReplace.hpp>
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/linguistic2/XSupportedLocales.hpp>
+#include <com/sun/star/linguistic2/XProofreader.hpp>
+#include <com/sun/star/linguistic2/XProofreadingIterator.hpp>
+#include <com/sun/star/linguistic2/SingleProofreadingError.hpp>
+#include <com/sun/star/linguistic2/ProofreadingResult.hpp>
+#include <com/sun/star/linguistic2/LinguServiceEvent.hpp>
+#include <com/sun/star/linguistic2/LinguServiceEventFlags.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/text/TextMarkupType.hpp>
+#include <com/sun/star/text/TextMarkupDescriptor.hpp>
+#include <com/sun/star/text/XTextMarkup.hpp>
+#include <com/sun/star/text/XMultiTextMarkup.hpp>
+#include <com/sun/star/text/XFlatParagraph.hpp>
+#include <com/sun/star/text/XFlatParagraphIterator.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+
+#include <sal/config.h>
+#include <osl/conditn.hxx>
+#include <osl/thread.hxx>
+#include <cppuhelper/implbase4.hxx>
+#include <cppuhelper/implementationentry.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <cppuhelper/extract.hxx>
+#include <cppuhelper/factory.hxx>
+#include <i18npool/mslangid.hxx>
+#include <unotools/processfactory.hxx>
+
+#include <deque>
+#include <map>
+#include <vector>
+
+#include "misc.hxx"
+#include "defs.hxx"
+#include "lngopt.hxx"
+
+#include "gciterator.hxx"
+
+using ::rtl::OUString;
+using namespace linguistic;
+using namespace ::com::sun::star;
+
+// forward declarations
+static ::rtl::OUString GrammarCheckingIterator_getImplementationName() throw();
+static uno::Sequence< OUString > GrammarCheckingIterator_getSupportedServiceNames() throw();
+
+
+//////////////////////////////////////////////////////////////////////
+
+// white space list: obtained from the fonts.config.txt of a Linux system.
+static sal_Unicode aWhiteSpaces[] =
+{
+ 0x0020, /* SPACE */
+ 0x00a0, /* NO-BREAK SPACE */
+ 0x00ad, /* SOFT HYPHEN */
+ 0x115f, /* HANGUL CHOSEONG FILLER */
+ 0x1160, /* HANGUL JUNGSEONG FILLER */
+ 0x1680, /* OGHAM SPACE MARK */
+ 0x2000, /* EN QUAD */
+ 0x2001, /* EM QUAD */
+ 0x2002, /* EN SPACE */
+ 0x2003, /* EM SPACE */
+ 0x2004, /* THREE-PER-EM SPACE */
+ 0x2005, /* FOUR-PER-EM SPACE */
+ 0x2006, /* SIX-PER-EM SPACE */
+ 0x2007, /* FIGURE SPACE */
+ 0x2008, /* PUNCTUATION SPACE */
+ 0x2009, /* THIN SPACE */
+ 0x200a, /* HAIR SPACE */
+ 0x200b, /* ZERO WIDTH SPACE */
+ 0x200c, /* ZERO WIDTH NON-JOINER */
+ 0x200d, /* ZERO WIDTH JOINER */
+ 0x200e, /* LEFT-TO-RIGHT MARK */
+ 0x200f, /* RIGHT-TO-LEFT MARK */
+ 0x2028, /* LINE SEPARATOR */
+ 0x2029, /* PARAGRAPH SEPARATOR */
+ 0x202a, /* LEFT-TO-RIGHT EMBEDDING */
+ 0x202b, /* RIGHT-TO-LEFT EMBEDDING */
+ 0x202c, /* POP DIRECTIONAL FORMATTING */
+ 0x202d, /* LEFT-TO-RIGHT OVERRIDE */
+ 0x202e, /* RIGHT-TO-LEFT OVERRIDE */
+ 0x202f, /* NARROW NO-BREAK SPACE */
+ 0x205f, /* MEDIUM MATHEMATICAL SPACE */
+ 0x2060, /* WORD JOINER */
+ 0x2061, /* FUNCTION APPLICATION */
+ 0x2062, /* INVISIBLE TIMES */
+ 0x2063, /* INVISIBLE SEPARATOR */
+ 0x206A, /* INHIBIT SYMMETRIC SWAPPING */
+ 0x206B, /* ACTIVATE SYMMETRIC SWAPPING */
+ 0x206C, /* INHIBIT ARABIC FORM SHAPING */
+ 0x206D, /* ACTIVATE ARABIC FORM SHAPING */
+ 0x206E, /* NATIONAL DIGIT SHAPES */
+ 0x206F, /* NOMINAL DIGIT SHAPES */
+ 0x3000, /* IDEOGRAPHIC SPACE */
+ 0x3164, /* HANGUL FILLER */
+ 0xfeff, /* ZERO WIDTH NO-BREAK SPACE */
+ 0xffa0, /* HALFWIDTH HANGUL FILLER */
+ 0xfff9, /* INTERLINEAR ANNOTATION ANCHOR */
+ 0xfffa, /* INTERLINEAR ANNOTATION SEPARATOR */
+ 0xfffb /* INTERLINEAR ANNOTATION TERMINATOR */
+};
+
+static int nWhiteSpaces = sizeof( aWhiteSpaces ) / sizeof( aWhiteSpaces[0] );
+
+static bool lcl_IsWhiteSpace( sal_Unicode cChar )
+{
+ bool bFound = false;
+ for (int i = 0; i < nWhiteSpaces && !bFound; ++i)
+ {
+ if (cChar == aWhiteSpaces[i])
+ bFound = true;
+ }
+ return bFound;
+}
+
+static sal_Int32 lcl_SkipWhiteSpaces( const OUString &rText, sal_Int32 nStartPos )
+{
+ // note having nStartPos point right behind the string is OK since that one
+ // is a correct end-of-sentence position to be returned from a grammar checker...
+
+ const sal_Int32 nLen = rText.getLength();
+ bool bIllegalArgument = false;
+ if (nStartPos < 0)
+ {
+ bIllegalArgument = true;
+ nStartPos = 0;
+ }
+ if (nStartPos > nLen)
+ {
+ bIllegalArgument = true;
+ nStartPos = nLen;
+ }
+ if (bIllegalArgument)
+ {
+ DBG_ASSERT( 0, "lcl_SkipWhiteSpaces: illegal arguments" );
+ }
+
+ sal_Int32 nRes = nStartPos;
+ if (0 <= nStartPos && nStartPos < nLen)
+ {
+ const sal_Unicode *pText = rText.getStr() + nStartPos;
+ while (nStartPos < nLen && lcl_IsWhiteSpace( *pText ))
+ ++pText;
+ nRes = pText - rText.getStr();
+ }
+
+ DBG_ASSERT( 0 <= nRes && nRes <= nLen, "lcl_SkipWhiteSpaces return value out of range" );
+ return nRes;
+}
+
+static sal_Int32 lcl_BacktraceWhiteSpaces( const OUString &rText, sal_Int32 nStartPos )
+{
+ // note: having nStartPos point right behind the string is OK since that one
+ // is a correct end-of-sentence position to be returned from a grammar checker...
+
+ const sal_Int32 nLen = rText.getLength();
+ bool bIllegalArgument = false;
+ if (nStartPos < 0)
+ {
+ bIllegalArgument = true;
+ nStartPos = 0;
+ }
+ if (nStartPos > nLen)
+ {
+ bIllegalArgument = true;
+ nStartPos = nLen;
+ }
+ if (bIllegalArgument)
+ {
+ DBG_ASSERT( 0, "lcl_BacktraceWhiteSpaces: illegal arguments" );
+ }
+
+ sal_Int32 nRes = nStartPos;
+ sal_Int32 nPosBefore = nStartPos - 1;
+ const sal_Unicode *pStart = rText.getStr();
+ if (0 <= nPosBefore && nPosBefore < nLen && lcl_IsWhiteSpace( pStart[ nPosBefore ] ))
+ {
+ nStartPos = nPosBefore;
+ if (0 <= nStartPos && nStartPos < nLen)
+ {
+ const sal_Unicode *pText = rText.getStr() + nStartPos;
+ while (pText > pStart && lcl_IsWhiteSpace( *pText ))
+ --pText;
+ // now add 1 since we want to point to the first char after the last char in the sentence...
+ nRes = pText - pStart + 1;
+ }
+ }
+
+ DBG_ASSERT( 0 <= nRes && nRes <= nLen, "lcl_BacktraceWhiteSpaces return value out of range" );
+ return nRes;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+extern "C" void workerfunc (void * gci)
+{
+ ((GrammarCheckingIterator*)gci)->DequeueAndCheck();
+}
+
+static lang::Locale lcl_GetPrimaryLanguageOfSentence(
+ uno::Reference< text::XFlatParagraph > xFlatPara,
+ sal_Int32 nStartIndex )
+{
+ //get the language of the first word
+ return xFlatPara->getLanguageOfText( nStartIndex, 1 );
+}
+
+//////////////////////////////////////////////////////////////////////
+/*
+class MyThread : punlic osl::Thread
+{
+ void run ()
+ {
+ DequeueAndCheck();
+ }
+
+ void own_terminate ()
+ {
+ m_bEnd = true;
+ wait (3000);
+ terminate ();
+ }
+}
+
+MyThread m_aQueue;
+
+vois startGrammarChecking()
+{
+ if (!m_aQueue.isRunning ())
+ m_aQueue.create ();
+}
+
+void stopGrammarChecking ()
+{
+ if (m_aQueue.isRunning ())
+ m_aQueue.own_terminate ();
+}
+*/
+
+GrammarCheckingIterator::GrammarCheckingIterator( const uno::Reference< lang::XMultiServiceFactory > & rxMgr ) :
+ m_xMSF( rxMgr ),
+ m_bEnd( sal_False ),
+ m_aCurCheckedDocId(),
+ m_bGCServicesChecked( sal_False ),
+ m_nDocIdCounter( 0 ),
+ m_nLastEndOfSentencePos( -1 ),
+ m_aEventListeners( MyMutex::get() ),
+ m_aNotifyListeners( MyMutex::get() )
+{
+ osl_createThread( workerfunc, this );
+}
+
+
+GrammarCheckingIterator::~GrammarCheckingIterator()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+}
+
+
+sal_Int32 GrammarCheckingIterator::NextDocId()
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_nDocIdCounter += 1;
+ return m_nDocIdCounter;
+}
+
+
+OUString GrammarCheckingIterator::GetOrCreateDocId(
+ const uno::Reference< lang::XComponent > &xComponent )
+{
+ // internal method; will always be called with locked mutex
+
+ OUString aRes;
+ if (xComponent.is())
+ {
+ if (m_aDocIdMap.find( xComponent.get() ) != m_aDocIdMap.end())
+ {
+ // return already existing entry
+ aRes = m_aDocIdMap[ xComponent.get() ];
+ }
+ else // add new entry
+ {
+ sal_Int32 nRes = NextDocId();
+ aRes = OUString::valueOf( nRes );
+ m_aDocIdMap[ xComponent.get() ] = aRes;
+ xComponent->addEventListener( this );
+ }
+ }
+ return aRes;
+}
+
+
+void GrammarCheckingIterator::AddEntry(
+ uno::WeakReference< text::XFlatParagraphIterator > xFlatParaIterator,
+ uno::WeakReference< text::XFlatParagraph > xFlatPara,
+ const OUString & rDocId,
+ sal_Int32 nStartIndex,
+ sal_Bool bAutomatic )
+{
+ // we may not need/have a xFlatParaIterator (e.g. if checkGrammarAtPos was called)
+ // but we always need a xFlatPara...
+ uno::Reference< text::XFlatParagraph > xPara( xFlatPara );
+ if (xPara.is())
+ {
+ FPEntry aNewFPEntry;
+ aNewFPEntry.m_xParaIterator = xFlatParaIterator;
+ aNewFPEntry.m_xPara = xFlatPara;
+ aNewFPEntry.m_aDocId = rDocId;
+ aNewFPEntry.m_nStartIndex = nStartIndex;
+ aNewFPEntry.m_bAutomatic = bAutomatic;
+
+ // add new entry to the end of this queue
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_aFPEntriesQueue.push_back( aNewFPEntry );
+
+ // wake up the thread in order to do grammar checking
+ m_aWakeUpThread.set();
+ }
+}
+
+
+void GrammarCheckingIterator::ProcessResult(
+ const linguistic2::ProofreadingResult &rRes,
+ const uno::Reference< text::XFlatParagraphIterator > &rxFlatParagraphIterator,
+ bool bIsAutomaticChecking )
+{
+ DBG_ASSERT( rRes.xFlatParagraph.is(), "xFlatParagraph is missing" );
+ //no guard necessary as no members are used
+ sal_Bool bContinueWithNextPara = sal_False;
+ if (!rRes.xFlatParagraph.is() || rRes.xFlatParagraph->isModified())
+ {
+ // if paragraph was modified/deleted meanwhile continue with the next one...
+ bContinueWithNextPara = sal_True;
+ }
+ else // paragraph is still unchanged...
+ {
+ //
+ // mark found errors...
+ //
+
+ sal_Int32 nTextLen = rRes.aText.getLength();
+ bool bBoundariesOk = 0 <= rRes.nStartOfSentencePosition && rRes.nStartOfSentencePosition <= nTextLen &&
+ 0 <= rRes.nBehindEndOfSentencePosition && rRes.nBehindEndOfSentencePosition <= nTextLen &&
+ 0 <= rRes.nStartOfNextSentencePosition && rRes.nStartOfNextSentencePosition <= nTextLen &&
+ rRes.nStartOfSentencePosition <= rRes.nBehindEndOfSentencePosition &&
+ rRes.nBehindEndOfSentencePosition <= rRes.nStartOfNextSentencePosition;
+ (void) bBoundariesOk;
+ DBG_ASSERT( bBoundariesOk, "inconsistent sentence boundaries" );
+ uno::Sequence< linguistic2::SingleProofreadingError > aErrors = rRes.aErrors;
+
+ uno::Reference< text::XMultiTextMarkup > xMulti( rRes.xFlatParagraph, uno::UNO_QUERY );
+ if (xMulti.is()) // use new API for markups
+ {
+ try
+ {
+ // length = number of found errors + 1 sentence markup
+ sal_Int32 nErrors = rRes.aErrors.getLength();
+ uno::Sequence< text::TextMarkupDescriptor > aDescriptors( nErrors + 1 );
+ text::TextMarkupDescriptor * pDescriptors = aDescriptors.getArray();
+
+ // at pos 0 .. nErrors-1 -> all grammar errors
+ for (sal_Int32 i = 0; i < nErrors; ++i)
+ {
+ const linguistic2::SingleProofreadingError &rError = rRes.aErrors[i];
+ text::TextMarkupDescriptor &rDesc = aDescriptors[i];
+
+ rDesc.nType = rError.nErrorType;
+ rDesc.nOffset = rError.nErrorStart;
+ rDesc.nLength = rError.nErrorLength;
+
+ // the proofreader may return SPELLING but right now our core
+ // does only handle PROOFREADING if the result is from the proofreader...
+ // (later on we may wish to color spelling errors found by the proofreader
+ // differently for example. But no special handling right now.
+ if (rDesc.nType == text::TextMarkupType::SPELLCHECK)
+ rDesc.nType = text::TextMarkupType::PROOFREADING;
+ }
+
+ // at pos nErrors -> sentence markup
+ // nSentenceLength: includes the white-spaces following the sentence end...
+ const sal_Int32 nSentenceLength = rRes.nStartOfNextSentencePosition - rRes.nStartOfSentencePosition;
+ pDescriptors[ nErrors ].nType = text::TextMarkupType::SENTENCE;
+ pDescriptors[ nErrors ].nOffset = rRes.nStartOfSentencePosition;
+ pDescriptors[ nErrors ].nLength = nSentenceLength;
+
+ xMulti->commitMultiTextMarkup( aDescriptors ) ;
+ }
+ catch (lang::IllegalArgumentException &)
+ {
+ DBG_ERROR( "commitMultiTextMarkup: IllegalArgumentException exception caught" );
+ }
+ }
+
+ // other sentences left to be checked in this paragraph?
+ if (rRes.nStartOfNextSentencePosition < rRes.aText.getLength())
+ {
+ AddEntry( rxFlatParagraphIterator, rRes.xFlatParagraph, rRes.aDocumentIdentifier, rRes.nStartOfNextSentencePosition, bIsAutomaticChecking );
+ }
+ else // current paragraph finished
+ {
+ // set "already checked" flag for the current flat paragraph
+ if (rRes.xFlatParagraph.is())
+ rRes.xFlatParagraph->setChecked( text::TextMarkupType::PROOFREADING, true );
+
+ bContinueWithNextPara = sal_True;
+ }
+ }
+
+ if (bContinueWithNextPara)
+ {
+ // we need to continue with the next paragraph
+ uno::Reference< text::XFlatParagraph > xFlatParaNext;
+ if (rxFlatParagraphIterator.is())
+ xFlatParaNext = rxFlatParagraphIterator->getNextPara();
+ {
+ AddEntry( rxFlatParagraphIterator, xFlatParaNext, rRes.aDocumentIdentifier, 0, bIsAutomaticChecking );
+ }
+ }
+}
+
+
+uno::Reference< linguistic2::XProofreader > GrammarCheckingIterator::GetGrammarChecker(
+ const lang::Locale &rLocale )
+{
+ (void) rLocale;
+ uno::Reference< linguistic2::XProofreader > xRes;
+
+ // ---- THREAD SAFE START ----
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+
+ // check supported locales for each grammarchecker if not already done
+ if (!m_bGCServicesChecked)
+ {
+ //GetAvailableGCSvcs_Impl();
+ GetConfiguredGCSvcs_Impl();
+ //GetMatchingGCSvcs_Impl();
+ m_bGCServicesChecked = sal_True;
+ }
+
+ const LanguageType nLang = MsLangId::convertLocaleToLanguage( rLocale );
+ GCImplNames_t::const_iterator aLangIt( m_aGCImplNamesByLang.find( nLang ) );
+ if (aLangIt != m_aGCImplNamesByLang.end()) // matching configured language found?
+ {
+ OUString aSvcImplName( aLangIt->second );
+ GCReferences_t::const_iterator aImplNameIt( m_aGCReferencesByService.find( aSvcImplName ) );
+ if (aImplNameIt != m_aGCReferencesByService.end()) // matching impl name found?
+ {
+ xRes = aImplNameIt->second;
+ }
+ else // the service is to be instatiated here for the first time...
+ {
+ try
+ {
+ uno::Reference< lang::XMultiServiceFactory > xMgr(
+ utl::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
+ uno::Reference< linguistic2::XProofreader > xGC(
+ xMgr->createInstance( aSvcImplName ), uno::UNO_QUERY_THROW );
+ uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xGC, uno::UNO_QUERY_THROW );
+
+ if (xSuppLoc->hasLocale( rLocale ))
+ {
+ m_aGCReferencesByService[ aSvcImplName ] = xGC;
+ xRes = xGC;
+
+ uno::Reference< linguistic2::XLinguServiceEventBroadcaster > xBC( xGC, uno::UNO_QUERY );
+ if (xBC.is())
+ xBC->addLinguServiceEventListener( this );
+ }
+ else
+ {
+ DBG_ASSERT( 0, "grammar checker does not support required locale" );
+ }
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "instantiating grammar checker failed" );
+ }
+ }
+ }
+ // ---- THREAD SAFE END ----
+
+ return xRes;
+}
+
+
+void GrammarCheckingIterator::DequeueAndCheck()
+{
+ uno::Sequence< sal_Int32 > aLangPortions;
+ uno::Sequence< lang::Locale > aLangPortionsLocale;
+
+ // ---- THREAD SAFE START ----
+ bool bEnd = false;
+ {
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ bEnd = m_bEnd;
+ }
+ // ---- THREAD SAFE END ----
+ while (!bEnd)
+ {
+ // ---- THREAD SAFE START ----
+ bool bQueueEmpty = false;
+ {
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ bQueueEmpty = m_aFPEntriesQueue.empty();
+ }
+ // ---- THREAD SAFE END ----
+
+ if (!bQueueEmpty)
+ {
+ uno::Reference< text::XFlatParagraphIterator > xFPIterator;
+ uno::Reference< text::XFlatParagraph > xFlatPara;
+ FPEntry aFPEntryItem;
+ OUString aCurDocId;
+ sal_Bool bModified = sal_False;
+ // ---- THREAD SAFE START ----
+ {
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ aFPEntryItem = m_aFPEntriesQueue.front();
+ xFPIterator = aFPEntryItem.m_xParaIterator;
+ xFlatPara = aFPEntryItem.m_xPara;
+ m_aCurCheckedDocId = aFPEntryItem.m_aDocId;
+ aCurDocId = m_aCurCheckedDocId;
+
+ m_aFPEntriesQueue.pop_front();
+ }
+ // ---- THREAD SAFE END ----
+
+ if (xFlatPara.is() && xFPIterator.is())
+ {
+ OUString aCurTxt( xFlatPara->getText() );
+ lang::Locale aCurLocale = lcl_GetPrimaryLanguageOfSentence( xFlatPara, aFPEntryItem.m_nStartIndex );
+
+ bModified = xFlatPara->isModified();
+ if (!bModified)
+ {
+ // ---- THREAD SAFE START ----
+ ::osl::ClearableGuard< ::osl::Mutex > aGuard( MyMutex::get() );
+
+ sal_Int32 nStartPos = aFPEntryItem.m_nStartIndex;
+ sal_Int32 nSuggestedEnd = GetSuggestedEndOfSentence( aCurTxt, nStartPos, aCurLocale );
+ DBG_ASSERT( (nSuggestedEnd == 0 && aCurTxt.getLength() == 0) || nSuggestedEnd > nStartPos,
+ "nSuggestedEndOfSentencePos calculation failed?" );
+
+ linguistic2::ProofreadingResult aRes;
+
+ uno::Reference< linguistic2::XProofreader > xGC( GetGrammarChecker( aCurLocale ), uno::UNO_QUERY );
+ if (xGC.is())
+ {
+ aGuard.clear();
+ uno::Sequence< beans::PropertyValue > aEmptyProps;
+ aRes = xGC->doProofreading( aCurDocId, aCurTxt, aCurLocale, nStartPos, nSuggestedEnd, aEmptyProps );
+
+ //!! work-around to prevent looping if the grammar checker
+ //!! failed to properly identify the sentence end
+ if (aRes.nBehindEndOfSentencePosition <= nStartPos)
+ {
+ DBG_ASSERT( 0, "!! Grammarchecker failed to provide end of sentence !!" );
+ aRes.nBehindEndOfSentencePosition = nSuggestedEnd;
+ }
+
+ aRes.xFlatParagraph = xFlatPara;
+ aRes.nStartOfSentencePosition = nStartPos;
+ }
+ else
+ {
+ // no grammar checker -> no error
+ // but we need to provide the data below in order to continue with the next sentence
+ aRes.aDocumentIdentifier = aCurDocId;
+ aRes.xFlatParagraph = xFlatPara;
+ aRes.aText = aCurTxt;
+ aRes.aLocale = aCurLocale;
+ aRes.nStartOfSentencePosition = nStartPos;
+ aRes.nBehindEndOfSentencePosition = nSuggestedEnd;
+ }
+ aRes.nStartOfNextSentencePosition = lcl_SkipWhiteSpaces( aCurTxt, aRes.nBehindEndOfSentencePosition );
+ aRes.nBehindEndOfSentencePosition = lcl_BacktraceWhiteSpaces( aCurTxt, aRes.nStartOfNextSentencePosition );
+
+ //guard has to be cleared as ProcessResult calls out of this class
+ aGuard.clear();
+ ProcessResult( aRes, xFPIterator, aFPEntryItem.m_bAutomatic );
+ // ---- THREAD SAFE END ----
+ }
+ else
+ {
+ // the paragraph changed meanwhile... (and maybe is still edited)
+ // thus we simply continue to ask for the next to be checked.
+ uno::Reference< text::XFlatParagraph > xFlatParaNext( xFPIterator->getNextPara() );
+ AddEntry( xFPIterator, xFlatParaNext, aCurDocId, 0, aFPEntryItem.m_bAutomatic );
+ }
+ }
+
+ // ---- THREAD SAFE START ----
+ {
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_aCurCheckedDocId = OUString();
+ }
+ // ---- THREAD SAFE END ----
+ }
+ else
+ {
+ // ---- THREAD SAFE START ----
+ {
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ // Check queue state again
+ if (m_aFPEntriesQueue.empty())
+ m_aWakeUpThread.reset();
+ }
+ // ---- THREAD SAFE END ----
+
+ //if the queue is empty
+ // IMPORTANT: Don't call condition.wait() with locked
+ // mutex. Otherwise you would keep out other threads
+ // to add entries to the queue! A condition is thread-
+ // safe implemented.
+ m_aWakeUpThread.wait();
+ }
+
+ // ---- THREAD SAFE START ----
+ {
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ bEnd = m_bEnd;
+ }
+ // ---- THREAD SAFE END ----
+ }
+
+ //!! This one must be the very last statement to call in this function !!
+ m_aRequestEndThread.set();
+}
+
+
+void SAL_CALL GrammarCheckingIterator::startProofreading(
+ const uno::Reference< ::uno::XInterface > & xDoc,
+ const uno::Reference< text::XFlatParagraphIteratorProvider > & xIteratorProvider )
+throw (uno::RuntimeException, lang::IllegalArgumentException)
+{
+ // get paragraph to start checking with
+ const bool bAutomatic = true;
+ uno::Reference<text::XFlatParagraphIterator> xFPIterator = xIteratorProvider->getFlatParagraphIterator(
+ text::TextMarkupType::PROOFREADING, bAutomatic );
+ uno::Reference< text::XFlatParagraph > xPara( xFPIterator.is()? xFPIterator->getFirstPara() : NULL );
+ uno::Reference< lang::XComponent > xComponent( xDoc, uno::UNO_QUERY );
+
+ // ---- THREAD SAFE START ----
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ if (xPara.is() && xComponent.is())
+ {
+ OUString aDocId = GetOrCreateDocId( xComponent );
+
+ // create new entry and add it to queue
+ AddEntry( xFPIterator, xPara, aDocId, 0, bAutomatic );
+ }
+ // ---- THREAD SAFE END ----
+}
+
+
+linguistic2::ProofreadingResult SAL_CALL GrammarCheckingIterator::checkSentenceAtPosition(
+ const uno::Reference< uno::XInterface >& xDoc,
+ const uno::Reference< text::XFlatParagraph >& xFlatPara,
+ const OUString& rText,
+ const lang::Locale& rLocale,
+ sal_Int32 nStartOfSentencePos,
+ sal_Int32 nSuggestedEndOfSentencePos,
+ sal_Int32 nErrorPosInPara )
+throw (lang::IllegalArgumentException, uno::RuntimeException)
+{
+ (void) rLocale;
+
+ // for the context menu...
+
+ linguistic2::ProofreadingResult aRes;
+
+ uno::Reference< lang::XComponent > xComponent( xDoc, uno::UNO_QUERY );
+ if (xFlatPara.is() && xComponent.is() &&
+ ( nErrorPosInPara < 0 || nErrorPosInPara < rText.getLength()))
+ {
+ // iterate through paragraph until we find the sentence we are interested in
+ linguistic2::ProofreadingResult aTmpRes;
+ sal_Int32 nStartPos = nStartOfSentencePos >= 0 ? nStartOfSentencePos : 0;
+
+ bool bFound = false;
+ do
+ {
+ lang::Locale aCurLocale = lcl_GetPrimaryLanguageOfSentence( xFlatPara, nStartPos );
+ sal_Int32 nOldStartOfSentencePos = nStartPos;
+ uno::Reference< linguistic2::XProofreader > xGC;
+ OUString aDocId;
+
+ // ---- THREAD SAFE START ----
+ {
+ ::osl::ClearableGuard< ::osl::Mutex > aGuard( MyMutex::get() );
+ aDocId = GetOrCreateDocId( xComponent );
+ nSuggestedEndOfSentencePos = GetSuggestedEndOfSentence( rText, nStartPos, aCurLocale );
+ DBG_ASSERT( nSuggestedEndOfSentencePos > nStartPos, "nSuggestedEndOfSentencePos calculation failed?" );
+
+ xGC = GetGrammarChecker( aCurLocale );
+ }
+ // ---- THREAD SAFE START ----
+ sal_Int32 nEndPos = -1;
+ if (xGC.is())
+ {
+ uno::Sequence< beans::PropertyValue > aEmptyProps;
+ aTmpRes = xGC->doProofreading( aDocId, rText, aCurLocale, nStartPos, nSuggestedEndOfSentencePos, aEmptyProps );
+
+ //!! work-around to prevent looping if the grammar checker
+ //!! failed to properly identify the sentence end
+ if (aTmpRes.nBehindEndOfSentencePosition <= nStartPos)
+ {
+ DBG_ASSERT( 0, "!! Grammarchecker failed to provide end of sentence !!" );
+ aTmpRes.nBehindEndOfSentencePosition = nSuggestedEndOfSentencePos;
+ }
+
+ aTmpRes.xFlatParagraph = xFlatPara;
+ aTmpRes.nStartOfSentencePosition = nStartPos;
+ nEndPos = aTmpRes.nBehindEndOfSentencePosition;
+
+ if ((nErrorPosInPara< 0 || nStartPos <= nErrorPosInPara) && nErrorPosInPara < nEndPos)
+ bFound = true;
+ }
+ if (nEndPos == -1) // no result from grammar checker
+ nEndPos = nSuggestedEndOfSentencePos;
+ nStartPos = lcl_SkipWhiteSpaces( rText, nEndPos );
+ aTmpRes.nBehindEndOfSentencePosition = nEndPos;
+ aTmpRes.nStartOfNextSentencePosition = nStartPos;
+ aTmpRes.nBehindEndOfSentencePosition = lcl_BacktraceWhiteSpaces( rText, aTmpRes.nStartOfNextSentencePosition );
+
+ // prevent endless loop by forcefully advancing if needs be...
+ if (nStartPos <= nOldStartOfSentencePos)
+ {
+ DBG_ASSERT( 0, "end-of-sentence detection failed?" );
+ nStartPos = nOldStartOfSentencePos + 1;
+ }
+ }
+ while (!bFound && nStartPos < rText.getLength());
+
+ if (bFound && !xFlatPara->isModified())
+ aRes = aTmpRes;
+ }
+
+ return aRes;
+}
+
+
+sal_Int32 GrammarCheckingIterator::GetSuggestedEndOfSentence(
+ const OUString &rText,
+ sal_Int32 nSentenceStartPos,
+ const lang::Locale &rLocale )
+{
+ // internal method; will always be called with locked mutex
+
+ uno::Reference< i18n::XBreakIterator > xBreakIterator;
+ if (!m_xBreakIterator.is())
+ {
+ uno::Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
+ if ( xMSF.is() )
+ xBreakIterator = uno::Reference < i18n::XBreakIterator >( xMSF->createInstance(
+ ::rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator") ), uno::UNO_QUERY );
+ }
+ sal_Int32 nTextLen = rText.getLength();
+ sal_Int32 nEndPosition = nTextLen;
+ if (m_xBreakIterator.is())
+ {
+ sal_Int32 nTmpStartPos = nSentenceStartPos;
+ do
+ {
+ nEndPosition = nTextLen;
+ if (nTmpStartPos < nTextLen)
+ nEndPosition = m_xBreakIterator->endOfSentence( rText, nTmpStartPos, rLocale );
+ if (nEndPosition < 0)
+ nEndPosition = nTextLen;
+
+ ++nTmpStartPos;
+ }
+ while (nEndPosition <= nSentenceStartPos && nEndPosition < nTextLen);
+ if (nEndPosition > nTextLen)
+ nEndPosition = nTextLen;
+ }
+ return nEndPosition;
+}
+
+
+void SAL_CALL GrammarCheckingIterator::resetIgnoreRules( )
+throw (uno::RuntimeException)
+{
+ GCReferences_t::iterator aIt( m_aGCReferencesByService.begin() );
+ while (aIt != m_aGCReferencesByService.end())
+ {
+ uno::Reference< linguistic2::XProofreader > xGC( aIt->second );
+ if (xGC.is())
+ xGC->resetIgnoreRules();
+ ++aIt;
+ }
+}
+
+
+sal_Bool SAL_CALL GrammarCheckingIterator::isProofreading(
+ const uno::Reference< uno::XInterface >& xDoc )
+throw (uno::RuntimeException)
+{
+ // ---- THREAD SAFE START ----
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+
+ sal_Bool bRes = sal_False;
+
+ uno::Reference< lang::XComponent > xComponent( xDoc, uno::UNO_QUERY );
+ if (xComponent.is())
+ {
+ // if the component was already used in one of the two calls to check text
+ // i.e. in startGrammarChecking or checkGrammarAtPos it will be found in the
+ // m_aDocIdMap unless the document already disposed.
+ // If it is not found then it is not yet being checked (or requested to being checked)
+ const DocMap_t::const_iterator aIt( m_aDocIdMap.find( xComponent.get() ) );
+ if (aIt != m_aDocIdMap.end())
+ {
+ // check in document is checked automatically in the background...
+ OUString aDocId = aIt->second;
+ if (m_aCurCheckedDocId.getLength() > 0 && m_aCurCheckedDocId == aDocId)
+ {
+ // an entry for that document was dequed and is currently being checked.
+ bRes = sal_True;
+ }
+ else
+ {
+ // we need to check if there is an entry for that document in the queue...
+ // That is the document is going to be checked sooner or later.
+
+ sal_Int32 nSize = m_aFPEntriesQueue.size();
+ for (sal_Int32 i = 0; i < nSize && !bRes; ++i)
+ {
+ if (aDocId == m_aFPEntriesQueue[i].m_aDocId)
+ bRes = sal_True;
+ }
+ }
+ }
+ }
+ // ---- THREAD SAFE END ----
+
+ return bRes;
+}
+
+
+void SAL_CALL GrammarCheckingIterator::processLinguServiceEvent(
+ const linguistic2::LinguServiceEvent& rLngSvcEvent )
+throw (uno::RuntimeException)
+{
+ if (rLngSvcEvent.nEvent == linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN)
+ {
+ try
+ {
+ uno::Reference< uno::XInterface > xThis( dynamic_cast< XLinguServiceEventBroadcaster * >(this) );
+ linguistic2::LinguServiceEvent aEvent( xThis, linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN );
+ m_aNotifyListeners.notifyEach(
+ &linguistic2::XLinguServiceEventListener::processLinguServiceEvent,
+ aEvent);
+ }
+ catch (uno::RuntimeException &)
+ {
+ throw;
+ }
+ catch (::uno::Exception &rE)
+ {
+ (void) rE;
+ // ignore
+ DBG_WARNING1("processLinguServiceEvent: exception:\n%s",
+ OUStringToOString(rE.Message, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+}
+
+
+sal_Bool SAL_CALL GrammarCheckingIterator::addLinguServiceEventListener(
+ const uno::Reference< linguistic2::XLinguServiceEventListener >& xListener )
+throw (uno::RuntimeException)
+{
+ if (xListener.is())
+ {
+// ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_aNotifyListeners.addInterface( xListener );
+ }
+ return sal_True;
+}
+
+
+sal_Bool SAL_CALL GrammarCheckingIterator::removeLinguServiceEventListener(
+ const uno::Reference< linguistic2::XLinguServiceEventListener >& xListener )
+throw (uno::RuntimeException)
+{
+ if (xListener.is())
+ {
+// ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_aNotifyListeners.removeInterface( xListener );
+ }
+ return sal_True;
+}
+
+
+void SAL_CALL GrammarCheckingIterator::dispose()
+throw (uno::RuntimeException)
+{
+ lang::EventObject aEvt( (linguistic2::XProofreadingIterator *) this );
+ m_aEventListeners.disposeAndClear( aEvt );
+
+ //
+ // now end the thread...
+ //
+ m_aRequestEndThread.reset();
+ // ---- THREAD SAFE START ----
+ {
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_bEnd = sal_True;
+ }
+ // ---- THREAD SAFE END ----
+ m_aWakeUpThread.set();
+ const TimeValue aTime = { 3, 0 }; // wait 3 seconds...
+ m_aRequestEndThread.wait( &aTime );
+ // if the call ends because of time-out we will end anyway...
+
+
+ // ---- THREAD SAFE START ----
+ {
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+
+ // releaase all UNO references
+
+ m_xMSF.clear();
+ m_xBreakIterator.clear();
+
+ // clear containers with UNO references AND have those references released
+ GCReferences_t aTmpEmpty1;
+ DocMap_t aTmpEmpty2;
+ FPQueue_t aTmpEmpty3;
+ m_aGCReferencesByService.swap( aTmpEmpty1 );
+ m_aDocIdMap.swap( aTmpEmpty2 );
+ m_aFPEntriesQueue.swap( aTmpEmpty3 );
+ }
+ // ---- THREAD SAFE END ----
+}
+
+
+void SAL_CALL GrammarCheckingIterator::addEventListener(
+ const uno::Reference< lang::XEventListener >& xListener )
+throw (uno::RuntimeException)
+{
+ if (xListener.is())
+ {
+// ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_aEventListeners.addInterface( xListener );
+ }
+}
+
+
+void SAL_CALL GrammarCheckingIterator::removeEventListener(
+ const uno::Reference< lang::XEventListener >& xListener )
+throw (uno::RuntimeException)
+{
+ if (xListener.is())
+ {
+// ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_aEventListeners.removeInterface( xListener );
+ }
+}
+
+
+void SAL_CALL GrammarCheckingIterator::disposing( const lang::EventObject &rSource )
+throw (uno::RuntimeException)
+{
+ // if the component (document) is disposing release all references
+ //!! There is no need to remove entries from the queue that are from this document
+ //!! since the respectives xFlatParagraphs should become invalid (isModified() == true)
+ //!! and the call to xFlatParagraphIterator->getNextPara() will result in an empty reference.
+ //!! And if an entry is currently checked by a grammar checker upon return the results
+ //!! should be ignored.
+ //!! Also GetOrCreateDocId will not use that very same Id again...
+ //!! All of the above resulting in that we only have to get rid of the implementation pointer here.
+ uno::Reference< lang::XComponent > xDoc( rSource.Source, uno::UNO_QUERY );
+ if (xDoc.is())
+ {
+ // ---- THREAD SAFE START ----
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_aDocIdMap.erase( xDoc.get() );
+ // ---- THREAD SAFE END ----
+ }
+}
+
+
+uno::Reference< util::XChangesBatch > GrammarCheckingIterator::GetUpdateAccess() const
+{
+ if (!m_xUpdateAccess.is())
+ {
+ try
+ {
+ // get configuration provider
+ uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider;
+ uno::Reference< lang::XMultiServiceFactory > xMgr = utl::getProcessServiceFactory();
+ if (xMgr.is())
+ {
+ xConfigurationProvider = uno::Reference< lang::XMultiServiceFactory > (
+ xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.configuration.ConfigurationProvider" ) ) ),
+ uno::UNO_QUERY_THROW ) ;
+ }
+
+ // get configuration update access
+ beans::PropertyValue aValue;
+ aValue.Name = A2OU( "nodepath" );
+ aValue.Value = uno::makeAny( A2OU("org.openoffice.Office.Linguistic/ServiceManager") );
+ uno::Sequence< uno::Any > aProps(1);
+ aProps[0] <<= aValue;
+ m_xUpdateAccess = uno::Reference< util::XChangesBatch >(
+ xConfigurationProvider->createInstanceWithArguments(
+ A2OU( "com.sun.star.configuration.ConfigurationUpdateAccess" ), aProps ),
+ uno::UNO_QUERY_THROW );
+ }
+ catch (uno::Exception &)
+ {
+ }
+ }
+
+ return m_xUpdateAccess;
+}
+
+
+void GrammarCheckingIterator::GetConfiguredGCSvcs_Impl()
+{
+ GCImplNames_t aTmpGCImplNamesByLang;
+
+ try
+ {
+ // get node names (locale iso strings) for configured grammar checkers
+ uno::Reference< container::XNameAccess > xNA( GetUpdateAccess(), uno::UNO_QUERY_THROW );
+ xNA.set( xNA->getByName( A2OU("GrammarCheckerList") ), uno::UNO_QUERY_THROW );
+ const uno::Sequence< OUString > aElementNames( xNA->getElementNames() );
+ const OUString *pElementNames = aElementNames.getConstArray();
+
+ sal_Int32 nLen = aElementNames.getLength();
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ uno::Sequence< OUString > aImplNames;
+ uno::Any aTmp( xNA->getByName( pElementNames[i] ) );
+ if (aTmp >>= aImplNames)
+ {
+ if (aImplNames.getLength() > 0)
+ {
+ // only the first entry is used, there should be only one grammar checker per language
+ const OUString aImplName( aImplNames[0] );
+ const LanguageType nLang = MsLangId::convertIsoStringToLanguage( pElementNames[i] );
+ aTmpGCImplNamesByLang[ nLang ] = aImplName;
+ }
+ }
+ else
+ {
+ DBG_ASSERT( 0, "failed to get aImplNames. Wrong type?" );
+ }
+ }
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "exception caught. Failed to get configured services" );
+ }
+
+ {
+ // ---- THREAD SAFE START ----
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_aGCImplNamesByLang = aTmpGCImplNamesByLang;
+ // ---- THREAD SAFE END ----
+ }
+}
+
+/*
+void GrammarCheckingIterator::GetMatchingGCSvcs_Impl()
+{
+ GCImplNames_t aTmpGCImplNamesByLang;
+
+ try
+ {
+ // get node names (locale iso strings) for configured grammar checkers
+ uno::Reference< container::XNameAccess > xNA( GetUpdateAccess(), uno::UNO_QUERY_THROW );
+ xNA.set( xNA->getByName( A2OU("GrammarCheckers") ), uno::UNO_QUERY_THROW );
+ const uno::Sequence< OUString > aGCImplNames( xNA->getElementNames() );
+ const OUString *pGCImplNames = aGCImplNames.getConstArray();
+
+ sal_Int32 nLen = aGCImplNames.getLength();
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ uno::Reference< container::XNameAccess > xTmpNA( xNA->getByName( pGCImplNames[i] ), uno::UNO_QUERY_THROW );
+ uno::Any aTmp( xTmpNA->getByName( A2OU("Locales") ) );
+ uno::Sequence< OUString > aIsoLocaleNames;
+ if (aTmp >>= aIsoLocaleNames)
+ {
+ const OUString *pIsoLocaleNames = aIsoLocaleNames.getConstArray();
+ for (sal_Int32 k = 0; k < aIsoLocaleNames.getLength(); ++k)
+ {
+ // if there are more grammar checkers for one language, for the time being,
+ // the last one found here will win...
+ const LanguageType nLang = MsLangId::convertIsoStringToLanguage( pIsoLocaleNames[k] );
+ aTmpGCImplNamesByLang[ nLang ] = pGCImplNames[i];
+ }
+ }
+ else
+ {
+ DBG_ASSERT( 0, "failed to get aImplNames. Wrong type?" );
+ }
+ }
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "exception caught. Failed to get matching grammar checker services" );
+ }
+
+ {
+ // ---- THREAD SAFE START ----
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_aGCImplNamesByLang = aTmpGCImplNamesByLang;
+ // ---- THREAD SAFE END ----
+ }
+}
+*/
+
+/*
+void GrammarCheckingIterator::GetAvailableGCSvcs_Impl()
+{
+ // internal method; will always be called with locked mutex
+ if (m_xMSF.is())
+ {
+ uno::Reference< container::XContentEnumerationAccess > xEnumAccess( m_xMSF, uno::UNO_QUERY );
+ uno::Reference< container::XEnumeration > xEnum;
+ if (xEnumAccess.is())
+ xEnum = xEnumAccess->createContentEnumeration( A2OU( SN_GRAMMARCHECKER ) );
+
+ if (xEnum.is())
+ {
+ while (xEnum->hasMoreElements())
+ {
+ uno::Any aCurrent = xEnum->nextElement();
+ uno::Reference< lang::XSingleComponentFactory > xCompFactory;
+ uno::Reference< lang::XSingleServiceFactory > xFactory;
+
+ uno::Reference< uno::XComponentContext > xContext;
+ uno::Reference< beans::XPropertySet > xProps( m_xMSF, uno::UNO_QUERY );
+ xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
+
+ if ( xContext.is() &&
+ (cppu::extractInterface( xCompFactory, aCurrent ) ||
+ cppu::extractInterface( xFactory, aCurrent )) )
+ {
+ try
+ {
+ uno::Reference< linguistic2::XProofreader > xSvc( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
+ if (xSvc.is())
+ {
+ OUString aImplName;
+ uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
+ if (xInfo.is())
+ aImplName = xInfo->getImplementationName();
+ DBG_ASSERT( aImplName.getLength(), "empty implementation name" );
+ uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
+ DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
+ if (xSuppLoc.is() && aImplName.getLength() > 0)
+ {
+ uno::Sequence< lang::Locale > aLocaleSequence( xSuppLoc->getLocales() );
+ // ---- THREAD SAFE START ----
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+ m_aGCLocalesByService[ aImplName ] = aLocaleSequence;
+ m_aGCReferencesByService[ aImplName ] = xSvc;
+ // ---- THREAD SAFE END ----
+ }
+ }
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "instantiating grammar checker failed" );
+ }
+ }
+ }
+ }
+ }
+}
+*/
+
+
+sal_Bool SAL_CALL GrammarCheckingIterator::supportsService(
+ const OUString & rServiceName )
+throw(uno::RuntimeException)
+{
+ uno::Sequence< OUString > aSNL = getSupportedServiceNames();
+ const OUString * pArray = aSNL.getConstArray();
+ for( INT32 i = 0; i < aSNL.getLength(); ++i )
+ if( pArray[i] == rServiceName )
+ return TRUE;
+ return FALSE;
+}
+
+
+OUString SAL_CALL GrammarCheckingIterator::getImplementationName( ) throw (uno::RuntimeException)
+{
+ return GrammarCheckingIterator_getImplementationName();
+}
+
+
+uno::Sequence< OUString > SAL_CALL GrammarCheckingIterator::getSupportedServiceNames( ) throw (uno::RuntimeException)
+{
+ return GrammarCheckingIterator_getSupportedServiceNames();
+}
+
+
+void GrammarCheckingIterator::SetServiceList(
+ const lang::Locale &rLocale,
+ const uno::Sequence< OUString > &rSvcImplNames )
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+
+ LanguageType nLanguage = LocaleToLanguage( rLocale );
+ OUString aImplName;
+ if (rSvcImplNames.getLength() > 0)
+ aImplName = rSvcImplNames[0]; // there is only one grammar checker per language
+
+ if (nLanguage != LANGUAGE_NONE && nLanguage != LANGUAGE_DONTKNOW)
+ {
+ if (aImplName.getLength() > 0)
+ m_aGCImplNamesByLang[ nLanguage ] = aImplName;
+ else
+ m_aGCImplNamesByLang.erase( nLanguage );
+ }
+}
+
+
+uno::Sequence< OUString > GrammarCheckingIterator::GetServiceList(
+ const lang::Locale &rLocale ) const
+{
+ ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
+
+ uno::Sequence< OUString > aRes(1);
+
+ OUString aImplName; // there is only one grammar checker per language
+ LanguageType nLang = LocaleToLanguage( rLocale );
+ GCImplNames_t::const_iterator aIt( m_aGCImplNamesByLang.find( nLang ) );
+ if (aIt != m_aGCImplNamesByLang.end())
+ aImplName = aIt->second;
+
+ if (aImplName.getLength() > 0)
+ aRes[0] = aImplName;
+ else
+ aRes.realloc(0);
+
+ return aRes;
+}
+
+
+LinguDispatcher::DspType GrammarCheckingIterator::GetDspType() const
+{
+ return DSP_GRAMMAR;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+static OUString GrammarCheckingIterator_getImplementationName() throw()
+{
+ return A2OU( "com.sun.star.lingu2.ProofreadingIterator" );
+}
+
+
+static uno::Sequence< OUString > GrammarCheckingIterator_getSupportedServiceNames() throw()
+{
+ uno::Sequence< OUString > aSNS( 1 );
+ aSNS.getArray()[0] = A2OU( SN_GRAMMARCHECKINGITERATOR );
+ return aSNS;
+}
+
+
+static uno::Reference< uno::XInterface > SAL_CALL GrammarCheckingIterator_createInstance(
+ const uno::Reference< lang::XMultiServiceFactory > & rxSMgr )
+throw(uno::Exception)
+{
+ return static_cast< ::cppu::OWeakObject * >(new GrammarCheckingIterator( rxSMgr ));
+}
+
+
+void * SAL_CALL GrammarCheckingIterator_getFactory(
+ const sal_Char *pImplName,
+ lang::XMultiServiceFactory *pServiceManager,
+ void * /*pRegistryKey*/ )
+{
+ void * pRet = 0;
+ if ( !GrammarCheckingIterator_getImplementationName().compareToAscii( pImplName ) )
+ {
+ uno::Reference< lang::XSingleServiceFactory > xFactory =
+ cppu::createOneInstanceFactory(
+ pServiceManager,
+ GrammarCheckingIterator_getImplementationName(),
+ GrammarCheckingIterator_createInstance,
+ GrammarCheckingIterator_getSupportedServiceNames());
+ // acquire, because we return an interface pointer instead of a reference
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+ return pRet;
+}
+
+
+sal_Bool SAL_CALL GrammarCheckingIterator_writeInfo(
+ void * /*pServiceManager*/,
+ registry::XRegistryKey * pRegistryKey )
+{
+ try
+ {
+ OUString aImpl( '/' );
+ aImpl += GrammarCheckingIterator_getImplementationName().getStr();
+ aImpl += A2OU( "/UNO/SERVICES" );
+ uno::Reference< registry::XRegistryKey > xNewKey = pRegistryKey->createKey( aImpl );
+ uno::Sequence< OUString > aServices = GrammarCheckingIterator_getSupportedServiceNames();
+ for( sal_Int32 i = 0; i < aServices.getLength(); i++ )
+ xNewKey->createKey( aServices.getConstArray()[i] );
+
+ return sal_True;
+ }
+ catch (uno::Exception &)
+ {
+ return sal_False;
+ }
+}
+
diff --git a/linguistic/source/gciterator.hxx b/linguistic/source/gciterator.hxx
new file mode 100644
index 000000000000..95105c7d29c9
--- /dev/null
+++ b/linguistic/source/gciterator.hxx
@@ -0,0 +1,209 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_GRAMMARCHECKINGITERATOR_HXX_
+#define _LINGUISTIC_GRAMMARCHECKINGITERATOR_HXX_
+
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XEventListener.hpp>
+#include <com/sun/star/linguistic2/XProofreadingIterator.hpp>
+#include <com/sun/star/linguistic2/XLinguServiceEventListener.hpp>
+#include <com/sun/star/linguistic2/XLinguServiceEventBroadcaster.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/util/XChangesBatch.hpp>
+
+#include <cppuhelper/implbase5.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <osl/mutex.hxx>
+#include <osl/conditn.hxx>
+#include <rtl/instance.hxx>
+
+#include <map>
+#include <deque>
+
+#include "defs.hxx"
+
+//////////////////////////////////////////////////////////////////////
+
+
+struct FPEntry
+{
+ // flat paragraph iterator
+ ::com::sun::star::uno::Reference< ::com::sun::star::text::XFlatParagraphIterator > m_xParaIterator;
+
+ // flat paragraph
+ ::com::sun::star::uno::WeakReference< ::com::sun::star::text::XFlatParagraph > m_xPara;
+
+ // document ID to identify different documents
+ ::rtl::OUString m_aDocId;
+
+ // the starting position to be checked
+ sal_Int32 m_nStartIndex;
+
+ // the flag to identify whether the document does automatical grammar checking
+ sal_Bool m_bAutomatic;
+
+ FPEntry()
+ : m_aDocId()
+ , m_nStartIndex( 0 )
+ , m_bAutomatic( 0 )
+ {
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+class GrammarCheckingIterator:
+ public cppu::WeakImplHelper5
+ <
+ ::com::sun::star::linguistic2::XProofreadingIterator,
+ ::com::sun::star::linguistic2::XLinguServiceEventListener,
+ ::com::sun::star::linguistic2::XLinguServiceEventBroadcaster,
+ ::com::sun::star::lang::XComponent,
+ ::com::sun::star::lang::XServiceInfo
+ >,
+ public LinguDispatcher
+{
+ com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > m_xMSF;
+
+
+ //the queue is keeping track of all senteces to be checked
+ //every element of this queue is a FlatParagraphEntry struct-object
+ typedef std::deque< FPEntry > FPQueue_t;
+
+ // queue for entries to be processed
+ FPQueue_t m_aFPEntriesQueue;
+
+ // the flag to end the endless loop
+ sal_Bool m_bEnd;
+
+ // Note that it must be the pointer and not the uno-reference to check if it is the same implementation object
+ typedef std::map< XComponent *, ::rtl::OUString > DocMap_t;
+ DocMap_t m_aDocIdMap;
+
+ // parameter ::rtl::OUString --> implementation name
+ // parameter ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > --> list of locales supported by service
+// typedef std::map< ::rtl::OUString, ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > > GCLocales_t;
+// GCLocales_t m_aGCLocalesByService;
+
+ // language -> implname mapping
+ typedef std::map< LanguageType, ::rtl::OUString > GCImplNames_t;
+ GCImplNames_t m_aGCImplNamesByLang;
+
+ // implname -> UNO reference mapping
+ typedef std::map< ::rtl::OUString, ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XProofreader > > GCReferences_t;
+ GCReferences_t m_aGCReferencesByService;
+
+ ::rtl::OUString m_aCurCheckedDocId;
+ sal_Bool m_bGCServicesChecked;
+ sal_Int32 m_nDocIdCounter;
+ sal_Int32 m_nLastEndOfSentencePos;
+ osl::Condition m_aWakeUpThread;
+ osl::Condition m_aRequestEndThread;
+
+ //! beware of initilization order !
+ struct MyMutex : public rtl::Static< osl::Mutex, MyMutex > {};
+ //
+ cppu::OInterfaceContainerHelper m_aEventListeners;
+ cppu::OInterfaceContainerHelper m_aNotifyListeners;
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > m_xBreakIterator;
+ mutable ::com::sun::star::uno::Reference< ::com::sun::star::util::XChangesBatch > m_xUpdateAccess;
+
+ sal_Int32 NextDocId();
+ ::rtl::OUString GetOrCreateDocId( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > &xComp );
+
+ void AddEntry(
+ ::com::sun::star::uno::WeakReference< ::com::sun::star::text::XFlatParagraphIterator > xFlatParaIterator,
+ ::com::sun::star::uno::WeakReference< ::com::sun::star::text::XFlatParagraph > xFlatPara,
+ const ::rtl::OUString &rDocId, sal_Int32 nStartIndex, sal_Bool bAutomatic );
+
+ void ProcessResult( const ::com::sun::star::linguistic2::ProofreadingResult &rRes,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::text::XFlatParagraphIterator > &rxFlatParagraphIterator,
+ bool bIsAutomaticChecking );
+
+ sal_Int32 GetSuggestedEndOfSentence( const ::rtl::OUString &rText, sal_Int32 nSentenceStartPos, const ::com::sun::star::lang::Locale &rLocale );
+
+ void GetConfiguredGCSvcs_Impl();
+// void GetMatchingGCSvcs_Impl();
+// void GetAvailableGCSvcs_Impl();
+ ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XProofreader > GetGrammarChecker( const ::com::sun::star::lang::Locale & rLocale );
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::util::XChangesBatch > GetUpdateAccess() const;
+
+ // disallow use of copy c-tor and assignment operator
+ GrammarCheckingIterator( const GrammarCheckingIterator & );
+ GrammarCheckingIterator & operator = ( const GrammarCheckingIterator & );
+
+public:
+
+ void DequeueAndCheck();
+
+ explicit GrammarCheckingIterator( const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > & rxMgr );
+ virtual ~GrammarCheckingIterator();
+
+ // XProofreadingIterator
+ virtual void SAL_CALL startProofreading( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& xDocument, const ::com::sun::star::uno::Reference< ::com::sun::star::text::XFlatParagraphIteratorProvider >& xIteratorProvider ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::linguistic2::ProofreadingResult SAL_CALL checkSentenceAtPosition( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& xDocument, const ::com::sun::star::uno::Reference< ::com::sun::star::text::XFlatParagraph >& xFlatParagraph, const ::rtl::OUString& aText, const ::com::sun::star::lang::Locale& aLocale, ::sal_Int32 nStartOfSentencePosition, ::sal_Int32 nSuggestedBehindEndOfSentencePosition, ::sal_Int32 nErrorPositionInParagraph ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL resetIgnoreRules( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL isProofreading( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& xDocument ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XLinguServiceEventListener
+ virtual void SAL_CALL processLinguServiceEvent( const ::com::sun::star::linguistic2::LinguServiceEvent& aLngSvcEvent ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XLinguServiceEventBroadcaster
+ virtual ::sal_Bool SAL_CALL addLinguServiceEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XLinguServiceEventListener >& xLstnr ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL removeLinguServiceEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XLinguServiceEventListener >& xLstnr ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException);
+
+ // LinguDispatcher
+ virtual void SetServiceList( const ::com::sun::star::lang::Locale &rLocale, const ::com::sun::star::uno::Sequence< rtl::OUString > &rSvcImplNames );
+ virtual ::com::sun::star::uno::Sequence< rtl::OUString > GetServiceList( const ::com::sun::star::lang::Locale &rLocale ) const;
+ virtual DspType GetDspType() const;
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/grammarchecker.cxx b/linguistic/source/grammarchecker.cxx
new file mode 100644
index 000000000000..21e1b7a58a3c
--- /dev/null
+++ b/linguistic/source/grammarchecker.cxx
@@ -0,0 +1,326 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#include "precompiled_linguistic.hxx"
+
+#include <sal/config.h>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase1.hxx>
+#include <com/sun/star/linguistic2/XGrammarChecker.hpp>
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <cppuhelper/implbase4.hxx>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include "misc.hxx"
+#include "defs.hxx"
+#include <cppuhelper/factory.hxx>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <cppuhelper/interfacecontainer.h>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/linguistic2/XSupportedLocales.hpp>
+#include <com/sun/star/linguistic2/SingleGrammarError.hpp>
+#include <com/sun/star/linguistic2/GrammarCheckingResult.hpp>
+#include "lngopt.hxx"
+#include <cppuhelper/extract.hxx>
+#include <unotools/processfactory.hxx>
+#include <map>
+#include <com/sun/star/text/TextMarkupType.hpp>
+
+#include "grammarchecker.hxx"
+
+using namespace ::utl;
+using namespace ::rtl;
+using namespace ::com::sun::star;
+
+////////////////////////////////////////////////////////////
+
+GrammarChecker::GrammarChecker( /*uno::Reference< uno::XComponentContext > const & context*/ )
+ /*m_xContext(context)*/
+{}
+
+GrammarChecker::~GrammarChecker()
+{
+}
+
+
+sal_Bool SAL_CALL GrammarChecker::isSpellChecker() throw (uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ return sal_False;
+}
+
+
+sal_Bool SAL_CALL GrammarChecker::hasLocale( const lang::Locale & aLocale ) throw (uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ (void) aLocale;
+ return sal_False;
+}
+
+uno::Sequence< lang::Locale > SAL_CALL GrammarChecker::getLocales( ) throw (uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ return uno::Sequence< lang::Locale >();
+}
+
+
+void SAL_CALL GrammarChecker::startDocument(sal_Int32 nDocId)
+ throw (uno::RuntimeException, lang::IllegalArgumentException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ (void) nDocId;
+}
+
+void SAL_CALL GrammarChecker::startParagraph(sal_Int32 nDocId)
+ throw (uno::RuntimeException, lang::IllegalArgumentException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ (void) nDocId;
+}
+
+void SAL_CALL GrammarChecker::endParagraph( sal_Int32 nDocId )
+ throw (uno::RuntimeException, lang::IllegalArgumentException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ (void) nDocId;
+}
+
+void SAL_CALL GrammarChecker::endDocument(sal_Int32 nDocId)
+ throw (uno::RuntimeException, lang::IllegalArgumentException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ (void) nDocId;
+}
+
+linguistic2::GrammarCheckingResult SAL_CALL GrammarChecker::doGrammarChecking(
+ sal_Int32 nDocId,
+ const rtl::OUString& rText,
+ const lang::Locale& rLocale,
+ sal_Int32 nStartOfSentencePos,
+ sal_Int32 nSuggestedSentenceEndPos,
+ const uno::Sequence< ::sal_Int32 >& rLanguagePortions,
+ const uno::Sequence< lang::Locale >& rLanguagePortionsLocales )
+ throw (lang::IllegalArgumentException, uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+
+ (void) rLanguagePortions;
+ (void) rLanguagePortionsLocales;
+
+ linguistic2::GrammarCheckingResult aRes;
+ aRes.nDocumentId = nDocId;
+ aRes.aText = rText;
+ aRes.aLocale = rLocale;
+ aRes.nEndOfSentencePos = nSuggestedSentenceEndPos;
+ aRes.xGrammarChecker = this;
+ aRes.aGrammarErrors = GrammarCheckingInDummy( nDocId, rText, rLocale, nStartOfSentencePos, nSuggestedSentenceEndPos );;
+
+ return aRes;
+}
+
+uno::Sequence< linguistic2::SingleGrammarError > GrammarChecker::GrammarCheckingInDummy(
+ sal_Int32 nDocId,
+ const OUString & rFlatParaText,
+ const lang::Locale & rLocale,
+ sal_Int32 nStartOfSentencePos,
+ sal_Int32 nSuggestedSentenceEndPos )
+{
+ (void) nDocId;
+ (void) rFlatParaText;
+ (void) rLocale;
+ (void) nStartOfSentencePos;
+ (void) nSuggestedSentenceEndPos;
+
+
+ typedef std::map< OUString, uno::Sequence<OUString> > Error_t;
+ Error_t aError;
+ uno::Sequence< OUString > aSuggestion(1);
+ OUString *pSeggestion = aSuggestion.getArray();
+ pSeggestion[0] = OUString::createFromAscii("Modified");
+
+ aError[OUString::createFromAscii("GrammarError")] = aSuggestion;
+ aError[OUString::createFromAscii("Grammar Error")] = aSuggestion;
+
+ typedef std::vector< linguistic2::SingleGrammarError> ErrorVector_t;
+ ErrorVector_t aErrorVector;
+
+ OUString aText = rFlatParaText.copy( nStartOfSentencePos, nSuggestedSentenceEndPos - nStartOfSentencePos );
+ sal_Int32 nIndexOf = 0;
+ for(Error_t::const_iterator it = aError.begin(); it != aError.end(); ++it)
+ {
+
+ while(nIndexOf >= 0)
+ {
+ nIndexOf=aText.indexOf(it->first, nIndexOf);
+ if(nIndexOf > -1)
+ {
+ //error found
+ linguistic2::SingleGrammarError aErr;
+ aErr.nErrorStart = nIndexOf + nStartOfSentencePos;
+ nIndexOf += it->first.getLength();
+ aErr.nErrorLength = it->first.getLength();
+ aErr.nErrorType = text::TextMarkupType::GRAMMAR;
+ aErr.nErrorLevel = 0;
+ aErr.aShortComment = OUString();
+ aErr.aFullComment = OUString();
+ aErr.aNewLocale = rLocale;
+ aErr.aSuggestions = it->second;
+
+ aErrorVector.push_back( aErr );
+ }
+ }
+ nIndexOf = 0;
+ }
+
+ sal_Int32 nCount = aErrorVector.size();
+ uno::Sequence< linguistic2::SingleGrammarError > aErrors( nCount );
+ if( nCount > 0 )
+ {
+ linguistic2::SingleGrammarError* pErrors = aErrors.getArray();
+ for (sal_Int32 i=0; i < nCount; ++i)
+ {
+ pErrors[i] = aErrorVector[i];
+ }
+ }
+ return aErrors;
+}
+
+
+sal_Bool SAL_CALL GrammarChecker::hasOptionsDialog( ) throw (uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ return sal_False;
+}
+
+void SAL_CALL GrammarChecker::runOptionsDialog()
+ throw (uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+}
+
+void SAL_CALL GrammarChecker::dispose( ) throw (uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+}
+
+void SAL_CALL GrammarChecker::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
+ throw (uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ (void) xListener;
+}
+
+void SAL_CALL GrammarChecker::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
+ throw (uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ (void) xListener;
+}
+
+sal_Bool SAL_CALL GrammarChecker::supportsService( const OUString& ServiceName ) throw(uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+
+ uno::Sequence< OUString > aSNL = getSupportedServiceNames();
+ const OUString * pArray = aSNL.getConstArray();
+ for( INT32 i = 0; i < aSNL.getLength(); ++i )
+ if( pArray[i] == ServiceName )
+ return TRUE;
+ return FALSE;
+}
+
+uno::Sequence< OUString > GrammarChecker::getSupportedServiceNames_Static( ) throw()
+{
+ //osl::Guard< osl::Mutex > aGuard(GetMutex());
+
+ uno::Sequence< OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich
+ aSNS.getArray()[0] = A2OU( "com.sun.star.linguistic2.GrammarChecker" );//SN_LINGU_SERVCICE_MANAGER
+ return aSNS;
+}
+
+uno::Sequence< OUString > SAL_CALL GrammarChecker::getSupportedServiceNames( ) throw(uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ return getSupportedServiceNames_Static();
+}
+
+OUString SAL_CALL GrammarChecker::getImplementationName( ) throw(uno::RuntimeException)
+{
+ osl::Guard< osl::Mutex > aGuard(GetMutex());
+ return getImplementationName_Static();
+}
+
+sal_Bool SAL_CALL GrammarChecker_writeInfo( void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey )
+{
+ try
+ {
+ String aImpl( '/' );
+ aImpl += GrammarChecker::getImplementationName_Static().getStr();
+ aImpl.AppendAscii( "/UNO/SERVICES" );
+ uno::Reference< registry::XRegistryKey > xNewKey =
+ pRegistryKey->createKey( aImpl );
+ uno::Sequence< OUString > aServices = GrammarChecker::getSupportedServiceNames_Static();
+ for( INT32 i = 0; i < aServices.getLength(); ++i )
+ xNewKey->createKey( aServices.getConstArray()[i] );
+
+ return sal_True;
+ }
+ catch(uno::Exception &)
+ {
+ return sal_False;
+ }
+}
+
+uno::Reference< uno::XInterface > SAL_CALL GrammarChecker_CreateInstance(
+ const uno::Reference< lang::XMultiServiceFactory > & /*rSMgr*/ )
+ throw(uno::Exception)
+{
+ uno::Reference< uno::XInterface > xService = (cppu::OWeakObject*) new GrammarChecker;
+ return xService;
+}
+
+void * SAL_CALL GrammarChecker_getFactory( const sal_Char * pImplName, lang::XMultiServiceFactory * pServiceManager, void * /*pRegistryKey*/ )
+{
+
+ void * pRet = 0;
+ if ( !GrammarChecker::getImplementationName_Static().compareToAscii( pImplName ) )
+ {
+ uno::Reference< lang::XSingleServiceFactory > xFactory =
+ cppu::createOneInstanceFactory(
+ pServiceManager,
+ GrammarChecker::getImplementationName_Static(),
+ GrammarChecker_CreateInstance,
+ GrammarChecker::getSupportedServiceNames_Static());
+ // acquire, because we return an interface pointer instead of a reference
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+ return pRet;
+}
+
diff --git a/linguistic/source/grammarchecker.hxx b/linguistic/source/grammarchecker.hxx
new file mode 100644
index 000000000000..8eee8f4c93f9
--- /dev/null
+++ b/linguistic/source/grammarchecker.hxx
@@ -0,0 +1,108 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_GRAMMARCHECKER_HXX_
+#define _LINGUISTIC_GRAMMARCHECKER_HXX_
+
+
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/linguistic2/XGrammarChecker.hpp>
+#include <com/sun/star/linguistic2/SingleGrammarError.hpp>
+#include <com/sun/star/linguistic2/XSupportedLocales.hpp>
+
+#include <cppuhelper/implbase3.hxx>
+#include <cppuhelper/interfacecontainer.h>
+
+#include <map>
+
+
+class GrammarChecker:
+ public cppu::WeakImplHelper3
+ <
+ ::com::sun::star::linguistic2::XGrammarChecker,
+ ::com::sun::star::lang::XComponent,
+ ::com::sun::star::lang::XServiceInfo
+ >
+{
+// com::sun::star::uno::Reference< uno::XComponentContext > m_xContext;
+
+ // disallow use of copy c-tor and assignment operator
+ GrammarChecker( const GrammarChecker & );
+ GrammarChecker & operator = ( const GrammarChecker & );
+
+public:
+ explicit GrammarChecker( /* uno::Reference< uno::XComponentContext > const & rXContext */ );
+ virtual ~GrammarChecker();
+
+ // XSupportedLocales
+ virtual ::sal_Bool SAL_CALL hasLocale( const ::com::sun::star::lang::Locale & aLocale) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > SAL_CALL getLocales( ) throw ( ::com::sun::star::uno::RuntimeException );
+
+ // XGrammarChecker
+ virtual ::sal_Bool SAL_CALL isSpellChecker( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL startDocument( ::sal_Int32 nDocId ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL startParagraph( ::sal_Int32 nDocId ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL endParagraph( ::sal_Int32 nDocId ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL endDocument( ::sal_Int32 nDocId ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::linguistic2::GrammarCheckingResult SAL_CALL doGrammarChecking( ::sal_Int32 nDocId, const ::rtl::OUString& aText, const ::com::sun::star::lang::Locale& aLocale, ::sal_Int32 nStartOfSentencePos, ::sal_Int32 nSuggestedEndOfSentencePos, const ::com::sun::star::uno::Sequence< ::sal_Int32 >& aLanguagePortions, const ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale >& aLanguagePortionsLocales ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL hasOptionsDialog( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL runOptionsDialog( ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw ( ::com::sun::star::uno::RuntimeException );
+ virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName() throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw (::com::sun::star::uno::RuntimeException);
+
+ static inline ::rtl::OUString getImplementationName_Static();
+ static ::com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedServiceNames_Static() throw();
+
+ ::com::sun::star::uno::Sequence< ::com::sun::star::linguistic2::SingleGrammarError > GrammarCheckingInDummy(
+ ::sal_Int32 nDocId, const ::rtl::OUString &rFlatParaText, const ::com::sun::star::lang::Locale & rLocale,
+ ::sal_Int32 nStartOfSentencePos, ::sal_Int32 nSuggestedSentenceEndPos );
+
+
+ inline ::osl::Mutex & GetMutex()
+ {
+ static osl::Mutex aMutex;
+ return aMutex;
+ }
+};
+
+inline ::rtl::OUString GrammarChecker::getImplementationName_Static()
+{
+ return A2OU( "com.sun.star.lingu2.GrammarChecker" );
+}
+
+
+#endif
+
diff --git a/linguistic/source/hhconvdic.cxx b/linguistic/source/hhconvdic.cxx
new file mode 100644
index 000000000000..207284230b4c
--- /dev/null
+++ b/linguistic/source/hhconvdic.cxx
@@ -0,0 +1,169 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+#include <unicode/uscript.h>
+#include <i18npool/lang.h>
+#include <tools/urlobj.hxx>
+#include <tools/debug.hxx>
+#include <tools/fsys.hxx>
+#include <tools/stream.hxx>
+#include <tools/string.hxx>
+#include <osl/mutex.hxx>
+#include <unotools/processfactory.hxx>
+#include <ucbhelper/content.hxx>
+
+#include <cppuhelper/factory.hxx> // helper for factories
+#include <com/sun/star/linguistic2/XConversionDictionary.hpp>
+#include <com/sun/star/linguistic2/ConversionDictionaryType.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 "hhconvdic.hxx"
+#include "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::linguistic2;
+using namespace linguistic;
+
+#define SN_HH_CONV_DICTIONARY "com.sun.star.linguistic2.HangulHanjaConversionDictionary"
+
+///////////////////////////////////////////////////////////////////////////
+
+#include <i18nutil/unicode.hxx>
+#include <com/sun/star/i18n/UnicodeScript.hpp>
+
+using namespace i18n;
+
+#define SCRIPT_OTHERS 0
+#define SCRIPT_HANJA 1
+#define SCRIPT_HANGUL 2
+
+// from i18npool/source/textconversion/textconversion_ko.cxx
+sal_Int16 SAL_CALL checkScriptType(sal_Unicode c) throw (RuntimeException)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ UScriptCode scriptCode = uscript_getScript(c, &status);
+
+ if ( !U_SUCCESS(status) ) throw RuntimeException();
+
+ return scriptCode == USCRIPT_HANGUL ? SCRIPT_HANGUL :
+ scriptCode == USCRIPT_HAN ? SCRIPT_HANJA : SCRIPT_OTHERS;
+}
+
+
+
+BOOL TextIsAllScriptType( const OUString &rTxt, INT16 nScriptType )
+{
+ BOOL bIsAll = TRUE;
+ for (INT32 i = 0; i < rTxt.getLength() && bIsAll; ++i)
+ {
+ if (checkScriptType( rTxt.getStr()[i]) != nScriptType)
+ bIsAll = FALSE;
+ }
+ return bIsAll;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+HHConvDic::HHConvDic( const String &rName, const String &rMainURL ) :
+ ConvDic( rName, LANGUAGE_KOREAN, ConversionDictionaryType::HANGUL_HANJA, TRUE, rMainURL )
+{
+}
+
+
+HHConvDic::~HHConvDic()
+{
+}
+
+
+void SAL_CALL HHConvDic::addEntry(
+ const OUString& aLeftText,
+ const OUString& aRightText )
+ throw (IllegalArgumentException, container::ElementExistException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if ((aLeftText.getLength() != aRightText.getLength()) ||
+ !TextIsAllScriptType( aLeftText, SCRIPT_HANGUL ) ||
+ !TextIsAllScriptType( aRightText, SCRIPT_HANJA ))
+ throw IllegalArgumentException();
+ ConvDic::addEntry( aLeftText, aRightText );
+}
+
+
+OUString SAL_CALL HHConvDic::getImplementationName( )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return getImplementationName_Static();
+}
+
+
+sal_Bool SAL_CALL HHConvDic::supportsService( const OUString& rServiceName )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ sal_Bool bRes = sal_False;
+ if (rServiceName.equalsAscii( SN_CONV_DICTIONARY )||
+ rServiceName.equalsAscii( SN_HH_CONV_DICTIONARY ))
+ bRes = sal_True;
+ return bRes;
+}
+
+
+uno::Sequence< OUString > SAL_CALL HHConvDic::getSupportedServiceNames( )
+ throw (RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return getSupportedServiceNames_Static();
+}
+
+
+uno::Sequence< OUString > HHConvDic::getSupportedServiceNames_Static()
+ throw()
+{
+ uno::Sequence< OUString > aSNS( 2 );
+ aSNS.getArray()[0] = A2OU( SN_CONV_DICTIONARY );
+ aSNS.getArray()[1] = A2OU( SN_HH_CONV_DICTIONARY );
+ return aSNS;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/hhconvdic.hxx b/linguistic/source/hhconvdic.hxx
new file mode 100644
index 000000000000..9bdecf0903fc
--- /dev/null
+++ b/linguistic/source/hhconvdic.hxx
@@ -0,0 +1,78 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_HHConvDic_HXX_
+#define _LINGUISTIC_HHConvDic_HXX_
+
+#include <com/sun/star/linguistic2/XConversionDictionary.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase3.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <tools/string.hxx>
+
+#include "misc.hxx"
+#include "defs.hxx"
+#include "convdic.hxx"
+
+///////////////////////////////////////////////////////////////////////////
+
+class HHConvDic :
+ public ConvDic
+{
+ // disallow copy-constructor and assignment-operator for now
+ HHConvDic(const HHConvDic &);
+ HHConvDic & operator = (const HHConvDic &);
+
+public:
+ HHConvDic( const String &rName, const String &rMainURL );
+ virtual ~HHConvDic();
+
+ // XConversionDictionary
+ virtual void SAL_CALL addEntry( const ::rtl::OUString& aLeftText, const ::rtl::OUString& aRightText ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, ::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException);
+
+
+ static inline ::rtl::OUString
+ getImplementationName_Static() throw();
+ static com::sun::star::uno::Sequence< ::rtl::OUString >
+ getSupportedServiceNames_Static() throw();
+};
+
+inline ::rtl::OUString HHConvDic::getImplementationName_Static() throw()
+{
+ return A2OU( "com.sun.star.lingu2.HHConvDic" );
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/hyphdsp.cxx b/linguistic/source/hyphdsp.cxx
new file mode 100644
index 000000000000..441d3ff449e9
--- /dev/null
+++ b/linguistic/source/hyphdsp.cxx
@@ -0,0 +1,736 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+
+#include <cppuhelper/factory.hxx> // helper for factories
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
+#include <com/sun/star/linguistic2/XHyphenatedWord.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <i18npool/lang.h>
+#include <unotools/localedatawrapper.hxx>
+#include <tools/debug.hxx>
+#include <svl/lngmisc.hxx>
+#include <unotools/processfactory.hxx>
+#include <osl/mutex.hxx>
+
+#include "hyphdsp.hxx"
+#include "hyphdta.hxx"
+#include "lngprops.hxx"
+#include "lngsvcmgr.hxx"
+
+
+using namespace utl;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::linguistic2;
+using namespace linguistic;
+
+///////////////////////////////////////////////////////////////////////////
+
+HyphenatorDispatcher::HyphenatorDispatcher( LngSvcMgr &rLngSvcMgr ) :
+ rMgr (rLngSvcMgr)
+{
+}
+
+
+HyphenatorDispatcher::~HyphenatorDispatcher()
+{
+ ClearSvcList();
+}
+
+
+void HyphenatorDispatcher::ClearSvcList()
+{
+ // release memory for each table entry
+ HyphSvcByLangMap_t aTmp;
+ aSvcMap.swap( aTmp );
+}
+
+
+Reference<XHyphenatedWord> HyphenatorDispatcher::buildHyphWord(
+ const OUString rOrigWord,
+ const Reference<XDictionaryEntry> &xEntry,
+ INT16 nLang, INT16 nMaxLeading )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Reference< XHyphenatedWord > xRes;
+
+ if (xEntry.is())
+ {
+ OUString aText( xEntry->getDictionaryWord() );
+ INT32 nTextLen = aText.getLength();
+
+ // trailing '=' means "hyphenation should not be possible"
+ if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=')
+ {
+ INT16 nHyphenationPos = -1;
+
+ OUStringBuffer aTmp( nTextLen );
+ BOOL bSkip = FALSE;
+ INT32 nHyphIdx = -1;
+ INT32 nLeading = 0;
+ for (INT32 i = 0; i < nTextLen; i++)
+ {
+ sal_Unicode cTmp = aText[i];
+ if (cTmp != '=')
+ {
+ aTmp.append( cTmp );
+ nLeading++;
+ bSkip = FALSE;
+ nHyphIdx++;
+ }
+ else
+ {
+ if (!bSkip && nHyphIdx >= 0)
+ {
+ if (nLeading <= nMaxLeading)
+ nHyphenationPos = (INT16) nHyphIdx;
+ }
+ bSkip = TRUE; //! multiple '=' should count as one only
+ }
+ }
+
+ if (nHyphenationPos > 0)
+ {
+ aText = aTmp.makeStringAndClear();
+
+#if OSL_DEBUG_LEVEL > 1
+ {
+ if (aText != rOrigWord)
+ {
+ // both words should only differ by a having a trailing '.'
+ // character or not...
+ OUString aShorter, aLonger;
+ if (aText.getLength() <= rOrigWord.getLength())
+ {
+ aShorter = aText;
+ aLonger = rOrigWord;
+ }
+ else
+ {
+ aShorter = rOrigWord;
+ aLonger = aText;
+ }
+ xub_StrLen nS = sal::static_int_cast< xub_StrLen >( aShorter.getLength() );
+ xub_StrLen nL = sal::static_int_cast< xub_StrLen >( aLonger.getLength() );
+ if (nS > 0 && nL > 0)
+ {
+ DBG_ASSERT( (nS + 1 == nL) && aLonger[nL-1] == (sal_Unicode) '.',
+ "HyphenatorDispatcher::buildHyphWord: unexpected difference between words!" );
+ }
+ }
+ }
+#endif
+ //! take care of #i22591#
+ aText = rOrigWord;
+
+ DBG_ASSERT( aText == rOrigWord, "failed to " );
+ xRes = new HyphenatedWord( aText, nLang, nHyphenationPos,
+ aText, nHyphenationPos );
+ }
+ }
+ }
+
+ return xRes;
+}
+
+
+Reference< XPossibleHyphens > HyphenatorDispatcher::buildPossHyphens(
+ const Reference< XDictionaryEntry > &xEntry, INT16 nLanguage )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Reference<XPossibleHyphens> xRes;
+
+ if (xEntry.is())
+ {
+ // text with hyphenation info
+ OUString aText( xEntry->getDictionaryWord() );
+ INT32 nTextLen = aText.getLength();
+
+ // trailing '=' means "hyphenation should not be possible"
+ if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=')
+ {
+ // sequence to hold hyphenation positions
+ Sequence< INT16 > aHyphPos( nTextLen );
+ INT16 *pPos = aHyphPos.getArray();
+ INT32 nHyphCount = 0;
+
+ OUStringBuffer aTmp( nTextLen );
+ BOOL bSkip = FALSE;
+ INT32 nHyphIdx = -1;
+ for (INT32 i = 0; i < nTextLen; i++)
+ {
+ sal_Unicode cTmp = aText[i];
+ if (cTmp != '=')
+ {
+ aTmp.append( cTmp );
+ bSkip = FALSE;
+ nHyphIdx++;
+ }
+ else
+ {
+ if (!bSkip && nHyphIdx >= 0)
+ pPos[ nHyphCount++ ] = (INT16) nHyphIdx;
+ bSkip = TRUE; //! multiple '=' should count as one only
+ }
+ }
+
+ // ignore (multiple) trailing '='
+ if (bSkip && nHyphIdx >= 0)
+ {
+ nHyphCount--;
+ }
+ DBG_ASSERT( nHyphCount >= 0, "lng : invalid hyphenation count");
+
+ if (nHyphCount > 0)
+ {
+ aHyphPos.realloc( nHyphCount );
+ xRes = new PossibleHyphens( aTmp.makeStringAndClear(), nLanguage,
+ aText, aHyphPos );
+ }
+ }
+ }
+
+ return xRes;
+}
+
+
+Sequence< Locale > SAL_CALL HyphenatorDispatcher::getLocales()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) );
+ Locale *pLocales = aLocales.getArray();
+ HyphSvcByLangMap_t::const_iterator aIt;
+ for (aIt = aSvcMap.begin(); aIt != aSvcMap.end(); ++aIt)
+ {
+ *pLocales++ = CreateLocale( aIt->first );
+ }
+ return aLocales;
+}
+
+
+BOOL SAL_CALL HyphenatorDispatcher::hasLocale(const Locale& rLocale)
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ HyphSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LocaleToLanguage( rLocale ) ) );
+ return aIt != aSvcMap.end();
+}
+
+
+Reference< XHyphenatedWord > SAL_CALL
+ HyphenatorDispatcher::hyphenate(
+ const OUString& rWord, const Locale& rLocale, sal_Int16 nMaxLeading,
+ const PropertyValues& rProperties )
+ throw(IllegalArgumentException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Reference< XHyphenatedWord > xRes;
+
+ INT32 nWordLen = rWord.getLength();
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+ if (nLanguage == LANGUAGE_NONE || !nWordLen ||
+ nMaxLeading == 0 || nMaxLeading == nWordLen)
+ return xRes;
+
+ // search for entry with that language
+ HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
+ LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
+
+ BOOL bWordModified = FALSE;
+ if (!pEntry || (nMaxLeading < 0 || nMaxLeading > nWordLen))
+ {
+#ifdef LINGU_EXCEPTIONS
+ throw IllegalArgumentException();
+#else
+ return NULL;
+#endif
+ }
+ else
+ {
+ OUString aChkWord( rWord );
+
+ // replace typographical apostroph by ascii apostroph
+ String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
+ DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
+ if (aSingleQuote.Len())
+ aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
+
+ bWordModified |= RemoveHyphens( aChkWord );
+ if (IsIgnoreControlChars( rProperties, GetPropSet() ))
+ bWordModified |= RemoveControlChars( aChkWord );
+ INT16 nChkMaxLeading = (INT16) GetPosInWordToCheck( rWord, nMaxLeading );
+
+ // check for results from (positive) dictionaries which have precedence!
+ Reference< XDictionaryEntry > xEntry;
+
+ if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
+ {
+ xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
+ TRUE, FALSE );
+ }
+
+ if (xEntry.is())
+ {
+ //! because queryDictionaryEntry (in the end DictionaryNeo::getEntry)
+ //! does not distinguish betwee "XYZ" and "XYZ." in order to avoid
+ //! to require them as different entry we have to supply the
+ //! original word here as well so it can be used in th result
+ //! otherwise a strange effect may occur (see #i22591#)
+ xRes = buildHyphWord( rWord, xEntry, nLanguage, nChkMaxLeading );
+ }
+ else
+ {
+ INT32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
+ DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
+ "lng : index out of range");
+
+ INT32 i = 0;
+ Reference< XHyphenator > xHyph;
+ if (pEntry->aSvcRefs.getLength() > 0)
+ xHyph = pEntry->aSvcRefs[0];
+
+ // try already instantiated service
+ if (i <= pEntry->nLastTriedSvcIndex)
+ {
+ if (xHyph.is() && xHyph->hasLocale( rLocale ))
+ xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading,
+ rProperties );
+ ++i;
+ }
+ else if (pEntry->nLastTriedSvcIndex < nLen - 1)
+ // instantiate services and try it
+ {
+// const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
+ Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
+
+ Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
+ if (xMgr.is())
+ {
+ // build service initialization argument
+ Sequence< Any > aArgs(2);
+ aArgs.getArray()[0] <<= GetPropSet();
+ //! The dispatcher searches the dictionary-list
+ //! thus the service needs not to now about it
+ //aArgs.getArray()[1] <<= GetDicList();
+
+ // create specific service via it's implementation name
+ try
+ {
+ xHyph = Reference< XHyphenator >(
+ xMgr->createInstanceWithArguments(
+ pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "createInstanceWithArguments failed" );
+ }
+ pRef [i] = xHyph;
+
+ Reference< XLinguServiceEventBroadcaster >
+ xBroadcaster( xHyph, UNO_QUERY );
+ if (xBroadcaster.is())
+ rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
+
+ if (xHyph.is() && xHyph->hasLocale( rLocale ))
+ xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading,
+ rProperties );
+
+ pEntry->nLastTriedSvcIndex = (INT16) i;
+ ++i;
+
+ // if language is not supported by the services
+ // remove it from the list.
+ if (xHyph.is() && !xHyph->hasLocale( rLocale ))
+ aSvcMap.erase( nLanguage );
+ }
+ }
+ } // if (xEntry.is())
+ }
+
+ if (bWordModified && xRes.is())
+ xRes = RebuildHyphensAndControlChars( rWord, xRes );
+
+ if (xRes.is() && xRes->getWord() != rWord)
+ {
+ xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(),
+ xRes->getHyphenatedWord(),
+ xRes->getHyphenPos() );
+ }
+
+ return xRes;
+}
+
+
+Reference< XHyphenatedWord > SAL_CALL
+ HyphenatorDispatcher::queryAlternativeSpelling(
+ const OUString& rWord, const Locale& rLocale, sal_Int16 nIndex,
+ const PropertyValues& rProperties )
+ throw(IllegalArgumentException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Reference< XHyphenatedWord > xRes;
+
+ INT32 nWordLen = rWord.getLength();
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+ if (nLanguage == LANGUAGE_NONE || !nWordLen)
+ return xRes;
+
+ // search for entry with that language
+ HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
+ LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
+
+ BOOL bWordModified = FALSE;
+ if (!pEntry || !(0 <= nIndex && nIndex <= nWordLen - 2))
+ {
+#ifdef LINGU_EXCEPTIONS
+ throw IllegalArgumentException();
+#else
+ return NULL;
+#endif
+ }
+ else
+ {
+ OUString aChkWord( rWord );
+
+ // replace typographical apostroph by ascii apostroph
+ String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
+ DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
+ if (aSingleQuote.Len())
+ aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
+
+ bWordModified |= RemoveHyphens( aChkWord );
+ if (IsIgnoreControlChars( rProperties, GetPropSet() ))
+ bWordModified |= RemoveControlChars( aChkWord );
+ INT16 nChkIndex = (INT16) GetPosInWordToCheck( rWord, nIndex );
+
+ // check for results from (positive) dictionaries which have precedence!
+ Reference< XDictionaryEntry > xEntry;
+
+ if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
+ {
+ xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
+ TRUE, FALSE );
+ }
+
+ if (xEntry.is())
+ {
+ //! alternative spellings not yet supported by dictionaries
+ }
+ else
+ {
+ INT32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
+ DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
+ "lng : index out of range");
+
+ INT32 i = 0;
+ Reference< XHyphenator > xHyph;
+ if (pEntry->aSvcRefs.getLength() > 0)
+ xHyph = pEntry->aSvcRefs[0];
+
+ // try already instantiated service
+ if (i <= pEntry->nLastTriedSvcIndex)
+ {
+ if (xHyph.is() && xHyph->hasLocale( rLocale ))
+ xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale,
+ nChkIndex, rProperties );
+ ++i;
+ }
+ else if (pEntry->nLastTriedSvcIndex < nLen - 1)
+ // instantiate services and try it
+ {
+// const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
+ Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
+
+ Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
+ if (xMgr.is())
+ {
+ // build service initialization argument
+ Sequence< Any > aArgs(2);
+ aArgs.getArray()[0] <<= GetPropSet();
+ //! The dispatcher searches the dictionary-list
+ //! thus the service needs not to now about it
+ //aArgs.getArray()[1] <<= GetDicList();
+
+ // create specific service via it's implementation name
+ try
+ {
+ xHyph = Reference< XHyphenator >(
+ xMgr->createInstanceWithArguments(
+ pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "createInstanceWithArguments failed" );
+ }
+ pRef [i] = xHyph;
+
+ Reference< XLinguServiceEventBroadcaster >
+ xBroadcaster( xHyph, UNO_QUERY );
+ if (xBroadcaster.is())
+ rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
+
+ if (xHyph.is() && xHyph->hasLocale( rLocale ))
+ xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale,
+ nChkIndex, rProperties );
+
+ pEntry->nLastTriedSvcIndex = (INT16) i;
+ ++i;
+
+ // if language is not supported by the services
+ // remove it from the list.
+ if (xHyph.is() && !xHyph->hasLocale( rLocale ))
+ aSvcMap.erase( nLanguage );
+ }
+ }
+ } // if (xEntry.is())
+ }
+
+ if (bWordModified && xRes.is())
+ xRes = RebuildHyphensAndControlChars( rWord, xRes );
+
+ if (xRes.is() && xRes->getWord() != rWord)
+ {
+ xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(),
+ xRes->getHyphenatedWord(),
+ xRes->getHyphenPos() );
+ }
+
+ return xRes;
+}
+
+
+Reference< XPossibleHyphens > SAL_CALL
+ HyphenatorDispatcher::createPossibleHyphens(
+ const OUString& rWord, const Locale& rLocale,
+ const PropertyValues& rProperties )
+ throw(IllegalArgumentException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Reference< XPossibleHyphens > xRes;
+
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+ if (nLanguage == LANGUAGE_NONE || !rWord.getLength())
+ return xRes;
+
+ // search for entry with that language
+ HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
+ LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
+
+ if (!pEntry)
+ {
+#ifdef LINGU_EXCEPTIONS
+ throw IllegalArgumentException();
+#endif
+ }
+ else
+ {
+ OUString aChkWord( rWord );
+
+ // replace typographical apostroph by ascii apostroph
+ String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
+ DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
+ if (aSingleQuote.Len())
+ aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
+
+ RemoveHyphens( aChkWord );
+ if (IsIgnoreControlChars( rProperties, GetPropSet() ))
+ RemoveControlChars( aChkWord );
+
+ // check for results from (positive) dictionaries which have precedence!
+ Reference< XDictionaryEntry > xEntry;
+
+ if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
+ {
+ xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
+ TRUE, FALSE );
+ }
+
+ if (xEntry.is())
+ {
+ xRes = buildPossHyphens( xEntry, nLanguage );
+ }
+ else
+ {
+ INT32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
+ DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
+ "lng : index out of range");
+
+ INT32 i = 0;
+ Reference< XHyphenator > xHyph;
+ if (pEntry->aSvcRefs.getLength() > 0)
+ xHyph = pEntry->aSvcRefs[0];
+
+ // try already instantiated service
+ if (i <= pEntry->nLastTriedSvcIndex)
+ {
+ if (xHyph.is() && xHyph->hasLocale( rLocale ))
+ xRes = xHyph->createPossibleHyphens( aChkWord, rLocale,
+ rProperties );
+ ++i;
+ }
+ else if (pEntry->nLastTriedSvcIndex < nLen - 1)
+ // instantiate services and try it
+ {
+// const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
+ Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
+
+ Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
+ if (xMgr.is())
+ {
+ // build service initialization argument
+ Sequence< Any > aArgs(2);
+ aArgs.getArray()[0] <<= GetPropSet();
+ //! The dispatcher searches the dictionary-list
+ //! thus the service needs not to now about it
+ //aArgs.getArray()[1] <<= GetDicList();
+
+ // create specific service via it's implementation name
+ try
+ {
+ xHyph = Reference< XHyphenator >(
+ xMgr->createInstanceWithArguments(
+ pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "createWithArguments failed" );
+ }
+ pRef [i] = xHyph;
+
+ Reference< XLinguServiceEventBroadcaster >
+ xBroadcaster( xHyph, UNO_QUERY );
+ if (xBroadcaster.is())
+ rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
+
+ if (xHyph.is() && xHyph->hasLocale( rLocale ))
+ xRes = xHyph->createPossibleHyphens( aChkWord, rLocale,
+ rProperties );
+
+ pEntry->nLastTriedSvcIndex = (INT16) i;
+ ++i;
+
+ // if language is not supported by the services
+ // remove it from the list.
+ if (xHyph.is() && !xHyph->hasLocale( rLocale ))
+ aSvcMap.erase( nLanguage );
+ }
+ }
+ } // if (xEntry.is())
+ }
+
+ if (xRes.is() && xRes->getWord() != rWord)
+ {
+ xRes = new PossibleHyphens( rWord, nLanguage,
+ xRes->getPossibleHyphens(),
+ xRes->getHyphenationPositions() );
+ }
+
+ return xRes;
+}
+
+
+void HyphenatorDispatcher::SetServiceList( const Locale &rLocale,
+ const Sequence< OUString > &rSvcImplNames )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+
+ INT32 nLen = rSvcImplNames.getLength();
+ if (0 == nLen)
+ // remove entry
+ aSvcMap.erase( nLanguage );
+ else
+ {
+ // modify/add entry
+ LangSvcEntries_Hyph *pEntry = aSvcMap[ nLanguage ].get();
+ // only one hypenator can be in use for a language...
+ //const OUString &rSvcImplName = rSvcImplNames.getConstArray()[0];
+ if (pEntry)
+ {
+ pEntry->Clear();
+ pEntry->aSvcImplNames = rSvcImplNames;
+ pEntry->aSvcImplNames.realloc(1);
+ pEntry->aSvcRefs = Sequence< Reference < XHyphenator > > ( 1 );
+ }
+ else
+ {
+ boost::shared_ptr< LangSvcEntries_Hyph > pTmpEntry( new LangSvcEntries_Hyph( rSvcImplNames[0] ) );
+ pTmpEntry->aSvcRefs = Sequence< Reference < XHyphenator > >( 1 );
+ aSvcMap[ nLanguage ] = pTmpEntry;
+ }
+ }
+}
+
+
+Sequence< OUString >
+ HyphenatorDispatcher::GetServiceList( const Locale &rLocale ) const
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Sequence< OUString > aRes;
+
+ // search for entry with that language and use data from that
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+ HyphenatorDispatcher *pThis = (HyphenatorDispatcher *) this;
+ const HyphSvcByLangMap_t::iterator aIt( pThis->aSvcMap.find( nLanguage ) );
+ const LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
+ if (pEntry)
+ {
+ aRes = pEntry->aSvcImplNames;
+ if (aRes.getLength() > 0)
+ aRes.realloc(1);
+ }
+
+ return aRes;
+}
+
+
+LinguDispatcher::DspType HyphenatorDispatcher::GetDspType() const
+{
+ return DSP_HYPH;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/hyphdsp.hxx b/linguistic/source/hyphdsp.hxx
new file mode 100644
index 000000000000..a722e9046c3c
--- /dev/null
+++ b/linguistic/source/hyphdsp.hxx
@@ -0,0 +1,172 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_HYPHDSP_HXX_
+#define _LINGUISTIC_HYPHDSP_HXX_
+
+
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceDisplayName.hpp>
+#include <com/sun/star/linguistic2/XHyphenator.hpp>
+#include <com/sun/star/linguistic2/XPossibleHyphens.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
+#include <com/sun/star/linguistic2/XLinguServiceEventBroadcaster.hpp>
+
+#include <uno/lbnames.h> // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
+#include <cppuhelper/implbase1.hxx> // helper for implementations
+
+#include <boost/shared_ptr.hpp>
+#include <map>
+
+#include "lngopt.hxx"
+#include "misc.hxx"
+#include "defs.hxx"
+
+class LngSvcMgr;
+
+///////////////////////////////////////////////////////////////////////////
+
+class HyphenatorDispatcher :
+ public cppu::WeakImplHelper1
+ <
+ ::com::sun::star::linguistic2::XHyphenator
+ >,
+ public LinguDispatcher
+{
+ typedef boost::shared_ptr< LangSvcEntries_Hyph > LangSvcEntries_Hyph_Ptr_t;
+ typedef std::map< LanguageType, LangSvcEntries_Hyph_Ptr_t > HyphSvcByLangMap_t;
+ HyphSvcByLangMap_t aSvcMap;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet > xPropSet;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XSearchableDictionaryList > xDicList;
+
+ LngSvcMgr &rMgr;
+
+ // disallow copy-constructor and assignment-operator for now
+ HyphenatorDispatcher(const HyphenatorDispatcher &);
+ HyphenatorDispatcher & operator = (const HyphenatorDispatcher &);
+
+ inline ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet >
+ GetPropSet();
+ inline ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XSearchableDictionaryList >
+ GetDicList();
+
+ void ClearSvcList();
+
+ com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XHyphenatedWord>
+ buildHyphWord( const rtl::OUString rOrigWord,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionaryEntry> &xEntry,
+ INT16 nLang, INT16 nMaxLeading );
+
+ com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XPossibleHyphens >
+ buildPossHyphens( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XDictionaryEntry > &xEntry,
+ INT16 nLanguage );
+
+public:
+ HyphenatorDispatcher( LngSvcMgr &rLngSvcMgr );
+ virtual ~HyphenatorDispatcher();
+
+ // XSupportedLocales
+ virtual ::com::sun::star::uno::Sequence<
+ ::com::sun::star::lang::Locale > SAL_CALL
+ getLocales()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ hasLocale( const ::com::sun::star::lang::Locale& aLocale )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ // XHyphenator
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XHyphenatedWord > SAL_CALL
+ hyphenate( const ::rtl::OUString& aWord,
+ const ::com::sun::star::lang::Locale& aLocale,
+ sal_Int16 nMaxLeading,
+ const ::com::sun::star::beans::PropertyValues& aProperties )
+ throw(::com::sun::star::lang::IllegalArgumentException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XHyphenatedWord > SAL_CALL
+ queryAlternativeSpelling( const ::rtl::OUString& aWord,
+ const ::com::sun::star::lang::Locale& aLocale,
+ sal_Int16 nIndex,
+ const ::com::sun::star::beans::PropertyValues& aProperties )
+ throw(::com::sun::star::lang::IllegalArgumentException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XPossibleHyphens > SAL_CALL
+ createPossibleHyphens(
+ const ::rtl::OUString& aWord,
+ const ::com::sun::star::lang::Locale& aLocale,
+ const ::com::sun::star::beans::PropertyValues& aProperties )
+ throw(::com::sun::star::lang::IllegalArgumentException,
+ ::com::sun::star::uno::RuntimeException);
+
+ // LinguDispatcher
+ virtual void
+ SetServiceList( const ::com::sun::star::lang::Locale &rLocale,
+ const ::com::sun::star::uno::Sequence<
+ rtl::OUString > &rSvcImplNames );
+ virtual ::com::sun::star::uno::Sequence< rtl::OUString >
+ GetServiceList( const ::com::sun::star::lang::Locale &rLocale ) const;
+ virtual DspType
+ GetDspType() const;
+};
+
+
+inline ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet >
+ HyphenatorDispatcher::GetPropSet()
+{
+ return xPropSet.is() ?
+ xPropSet : xPropSet = ::linguistic::GetLinguProperties();
+}
+
+
+inline ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XSearchableDictionaryList >
+ HyphenatorDispatcher::GetDicList()
+{
+ return xDicList.is() ?
+ xDicList : xDicList = ::linguistic::GetSearchableDictionaryList();
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+#endif
+
diff --git a/linguistic/source/hyphdta.cxx b/linguistic/source/hyphdta.cxx
new file mode 100644
index 000000000000..66c3ca3f7775
--- /dev/null
+++ b/linguistic/source/hyphdta.cxx
@@ -0,0 +1,189 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+#include "hyphdta.hxx"
+#include "lngprops.hxx"
+#include "misc.hxx"
+#include <osl/mutex.hxx>
+
+
+#include <rtl/ustrbuf.hxx>
+#include <tools/debug.hxx>
+#include <svl/lngmisc.hxx>
+#include <unotools/localedatawrapper.hxx>
+
+//using namespace utl;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star;
+//using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::linguistic2;
+
+namespace linguistic
+{
+///////////////////////////////////////////////////////////////////////////
+
+
+HyphenatedWord::HyphenatedWord(const OUString &rWord, INT16 nLang, INT16 nHPos,
+ const OUString &rHyphWord, INT16 nPos ) :
+ aWord (rWord),
+ aHyphenatedWord (rHyphWord),
+ nHyphPos (nPos),
+ nHyphenationPos (nHPos),
+ nLanguage (nLang)
+{
+ String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
+ DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
+ if (aSingleQuote.Len())
+ {
+ // ignore typographical apostrophes (which got replaced in original
+ // word when being checked for hyphenation) in results.
+ OUString aTmpWord( rWord );
+ OUString aTmpHyphWord( rHyphWord );
+ aTmpWord = aTmpWord .replace( aSingleQuote.GetChar(0), '\'' );
+ aTmpHyphWord = aTmpHyphWord.replace( aSingleQuote.GetChar(0), '\'' );
+ bIsAltSpelling = aTmpWord != aTmpHyphWord;
+ }
+ else
+ bIsAltSpelling = rWord != rHyphWord;
+}
+
+
+HyphenatedWord::~HyphenatedWord()
+{
+}
+
+
+OUString SAL_CALL HyphenatedWord::getWord()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aWord;
+}
+
+
+Locale SAL_CALL HyphenatedWord::getLocale()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Locale aRes;
+ return LanguageToLocale( aRes, nLanguage );
+}
+
+
+sal_Int16 SAL_CALL HyphenatedWord::getHyphenationPos()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return nHyphenationPos;
+}
+
+
+OUString SAL_CALL HyphenatedWord::getHyphenatedWord()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aHyphenatedWord;
+}
+
+
+sal_Int16 SAL_CALL HyphenatedWord::getHyphenPos()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return nHyphPos;
+}
+
+
+sal_Bool SAL_CALL HyphenatedWord::isAlternativeSpelling()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return bIsAltSpelling;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+PossibleHyphens::PossibleHyphens(const OUString &rWord, INT16 nLang,
+ const OUString &rHyphWord,
+ const Sequence< INT16 > &rPositions) :
+ aWord (rWord),
+ aWordWithHyphens(rHyphWord),
+ aOrigHyphenPos (rPositions),
+ nLanguage (nLang)
+{
+}
+
+
+PossibleHyphens::~PossibleHyphens()
+{
+}
+
+
+OUString SAL_CALL PossibleHyphens::getWord()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aWord;
+}
+
+
+Locale SAL_CALL PossibleHyphens::getLocale()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return CreateLocale( nLanguage );
+}
+
+
+OUString SAL_CALL PossibleHyphens::getPossibleHyphens()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aWordWithHyphens;
+}
+
+
+Sequence< sal_Int16 > SAL_CALL PossibleHyphens::getHyphenationPositions()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aOrigHyphenPos;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+} // namespace linguistic
+
diff --git a/linguistic/source/iprcache.cxx b/linguistic/source/iprcache.cxx
new file mode 100644
index 000000000000..e4c50686afcf
--- /dev/null
+++ b/linguistic/source/iprcache.cxx
@@ -0,0 +1,284 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+#include <string.h>
+
+#include "iprcache.hxx"
+#include "misc.hxx"
+
+#include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
+#include <tools/debug.hxx>
+#include <osl/mutex.hxx>
+
+//#define IPR_DEF_CACHE_SIZE 503
+#define IPR_DEF_CACHE_MAX 375
+#define IPR_DEF_CACHE_MAXINPUT 200
+
+#ifdef DBG_STATISTIC
+#include <tools/stream.hxx>
+
+//#define IPR_CACHE_SIZE nTblSize
+#define IPR_CACHE_MAX nMax
+#define IPR_CACHE_MAXINPUT nMaxInput
+
+#else
+
+//#define IPR_CACHE_SIZE IPR_DEF_CACHE_SIZE
+#define IPR_CACHE_MAX IPR_DEF_CACHE_MAX
+#define IPR_CACHE_MAXINPUT IPR_DEF_CACHE_MAXINPUT
+
+#endif
+#include <unotools/processfactory.hxx>
+
+#include <lngprops.hxx>
+
+using namespace utl;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::linguistic2;
+
+
+namespace linguistic
+{
+
+///////////////////////////////////////////////////////////////////////////
+
+#define NUM_FLUSH_PROPS 6
+
+static const struct
+{
+ const char *pPropName;
+ INT32 nPropHdl;
+} aFlushProperties[ NUM_FLUSH_PROPS ] =
+{
+ { UPN_IS_USE_DICTIONARY_LIST, UPH_IS_USE_DICTIONARY_LIST },
+ { UPN_IS_IGNORE_CONTROL_CHARACTERS, UPH_IS_IGNORE_CONTROL_CHARACTERS },
+ { UPN_IS_SPELL_UPPER_CASE, UPH_IS_SPELL_UPPER_CASE },
+ { UPN_IS_SPELL_WITH_DIGITS, UPH_IS_SPELL_WITH_DIGITS },
+ { UPN_IS_SPELL_CAPITALIZATION, UPH_IS_SPELL_CAPITALIZATION }
+};
+
+
+static void lcl_AddAsPropertyChangeListener(
+ Reference< XPropertyChangeListener > xListener,
+ Reference< XPropertySet > &rPropSet )
+{
+ if (xListener.is() && rPropSet.is())
+ {
+ for (int i = 0; i < NUM_FLUSH_PROPS; ++i)
+ {
+ rPropSet->addPropertyChangeListener(
+ A2OU(aFlushProperties[i].pPropName), xListener );
+ }
+ }
+}
+
+
+static void lcl_RemoveAsPropertyChangeListener(
+ Reference< XPropertyChangeListener > xListener,
+ Reference< XPropertySet > &rPropSet )
+{
+ if (xListener.is() && rPropSet.is())
+ {
+ for (int i = 0; i < NUM_FLUSH_PROPS; ++i)
+ {
+ rPropSet->removePropertyChangeListener(
+ A2OU(aFlushProperties[i].pPropName), xListener );
+ }
+ }
+}
+
+
+static BOOL lcl_IsFlushProperty( INT32 nHandle )
+{
+ int i;
+ for (i = 0; i < NUM_FLUSH_PROPS; ++i)
+ {
+ if (nHandle == aFlushProperties[i].nPropHdl)
+ break;
+ }
+ return i < NUM_FLUSH_PROPS;
+}
+
+
+FlushListener::FlushListener( Flushable *pFO )
+{
+ SetFlushObj( pFO );
+}
+
+
+FlushListener::~FlushListener()
+{
+}
+
+
+void FlushListener::SetDicList( Reference<XDictionaryList> &rDL )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (xDicList != rDL)
+ {
+ if (xDicList.is())
+ xDicList->removeDictionaryListEventListener( this );
+
+ xDicList = rDL;
+ if (xDicList.is())
+ xDicList->addDictionaryListEventListener( this, FALSE );
+ }
+}
+
+
+void FlushListener::SetPropSet( Reference< XPropertySet > &rPS )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (xPropSet != rPS)
+ {
+ if (xPropSet.is())
+ lcl_RemoveAsPropertyChangeListener( this, xPropSet );
+
+ xPropSet = rPS;
+ if (xPropSet.is())
+ lcl_AddAsPropertyChangeListener( this, xPropSet );
+ }
+}
+
+
+void SAL_CALL FlushListener::disposing( const EventObject& rSource )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (xDicList.is() && rSource.Source == xDicList)
+ {
+ xDicList->removeDictionaryListEventListener( this );
+ xDicList = NULL; //! release reference
+ }
+ if (xPropSet.is() && rSource.Source == xPropSet)
+ {
+ lcl_RemoveAsPropertyChangeListener( this, xPropSet );
+ xPropSet = NULL; //! release reference
+ }
+}
+
+
+void SAL_CALL FlushListener::processDictionaryListEvent(
+ const DictionaryListEvent& rDicListEvent )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (rDicListEvent.Source == xDicList)
+ {
+ INT16 nEvt = rDicListEvent.nCondensedEvent;
+ INT16 nFlushFlags =
+ DictionaryListEventFlags::ADD_NEG_ENTRY |
+ DictionaryListEventFlags::DEL_POS_ENTRY |
+ DictionaryListEventFlags::ACTIVATE_NEG_DIC |
+ DictionaryListEventFlags::DEACTIVATE_POS_DIC;
+ BOOL bFlush = 0 != (nEvt & nFlushFlags);
+
+ DBG_ASSERT( pFlushObj, "missing object (NULL pointer)" );
+ if (bFlush && pFlushObj != NULL)
+ pFlushObj->Flush();
+ }
+}
+
+
+void SAL_CALL FlushListener::propertyChange(
+ const PropertyChangeEvent& rEvt )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (rEvt.Source == xPropSet)
+ {
+ BOOL bFlush = lcl_IsFlushProperty( rEvt.PropertyHandle );
+
+ DBG_ASSERT( pFlushObj, "missing object (NULL pointer)" );
+ if (bFlush && pFlushObj != NULL)
+ pFlushObj->Flush();
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+SpellCache::SpellCache()
+{
+ pFlushLstnr = new FlushListener( this );
+ xFlushLstnr = pFlushLstnr;
+ Reference<XDictionaryList> aDictionaryList(GetDictionaryList());
+ pFlushLstnr->SetDicList( aDictionaryList ); //! after reference is established
+ Reference<XPropertySet> aPropertySet(GetLinguProperties());
+ pFlushLstnr->SetPropSet( aPropertySet ); //! after reference is established
+}
+
+SpellCache::~SpellCache()
+{
+ Reference<XDictionaryList> aEmptyList;
+ Reference<XPropertySet> aEmptySet;
+ pFlushLstnr->SetDicList( aEmptyList );
+ pFlushLstnr->SetPropSet( aEmptySet );
+}
+
+void SpellCache::Flush()
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ // clear word list
+ LangWordList_t aEmpty;
+ aWordLists.swap( aEmpty );
+}
+
+bool SpellCache::CheckWord( const OUString& rWord, LanguageType nLang )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ WordList_t &rList = aWordLists[ nLang ];
+ const WordList_t::const_iterator aIt = rList.find( rWord );
+ return aIt != rList.end();
+}
+
+void SpellCache::AddWord( const OUString& rWord, LanguageType nLang )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ WordList_t & rList = aWordLists[ nLang ];
+ // occasional clean-up...
+ if (rList.size() > 500)
+ rList.clear();
+ rList.insert( rWord );
+}
+///////////////////////////////////////////////////////////////////////////
+
+} // namespace linguistic
+
diff --git a/linguistic/source/lngopt.cxx b/linguistic/source/lngopt.cxx
new file mode 100644
index 000000000000..77a1fcbd57b0
--- /dev/null
+++ b/linguistic/source/lngopt.cxx
@@ -0,0 +1,711 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+#include "lngopt.hxx"
+#include "lngprops.hxx"
+#include "misc.hxx"
+#include <tools/debug.hxx>
+#include <unotools/lingucfg.hxx>
+
+#include <uno/lbnames.h> // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
+#include <cppuhelper/implbase1.hxx> // helper for implementations
+
+#include <cppuhelper/factory.hxx> // helper for factories
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <unotools/processfactory.hxx>
+#include <i18npool/mslangid.hxx>
+
+using namespace utl;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star;
+using namespace com::sun::star::container;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::linguistic2;
+using namespace linguistic;
+
+using namespace com::sun::star::registry;
+
+///////////////////////////////////////////////////////////////////////////
+
+
+// static member intialization
+SvtLinguOptions * LinguOptions::pData = NULL;
+vos::ORefCount LinguOptions::aRefCount;
+
+
+LinguOptions::LinguOptions()
+{
+ if (!pData)
+ {
+ pData = new SvtLinguOptions;
+ SvtLinguConfig aLinguCfg;
+ aLinguCfg.GetOptions( *pData );
+ }
+
+ ++aRefCount;
+}
+
+
+LinguOptions::LinguOptions(const LinguOptions & /*rOpt*/)
+{
+ DBG_ASSERT( pData, "lng : data missing" );
+ ++aRefCount;
+}
+
+
+LinguOptions::~LinguOptions()
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (--aRefCount == 0)
+ {
+ delete pData; pData = NULL;
+ }
+}
+
+
+BOOL LinguOptions::SetLocale_Impl( INT16 &rLanguage, Any &rOld, const Any &rVal, sal_Int16 nType)
+{
+ BOOL bRes = FALSE;
+
+ Locale aNew;
+ rVal >>= aNew;
+ INT16 nNew = MsLangId::resolveSystemLanguageByScriptType(MsLangId::convertLocaleToLanguage(aNew), nType);
+ if (nNew != rLanguage)
+ {
+ Locale aLocale( CreateLocale( rLanguage ) );
+ rOld.setValue( &aLocale, ::getCppuType((Locale*)0 ));
+ rLanguage = nNew;
+ bRes = TRUE;
+ }
+
+ return bRes;
+}
+
+
+BOOL LinguOptions::SetValue( Any &rOld, const Any &rVal, INT32 nWID )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = FALSE;
+
+ INT16 *pnVal = 0;
+ BOOL *pbVal = 0;
+
+ switch( nWID )
+ {
+ case WID_IS_GERMAN_PRE_REFORM : /*! deprecated !*/ break;
+ case WID_IS_USE_DICTIONARY_LIST : pbVal = &pData->bIsUseDictionaryList; break;
+ case WID_IS_IGNORE_CONTROL_CHARACTERS : pbVal = &pData->bIsIgnoreControlCharacters; break;
+ case WID_IS_HYPH_AUTO : pbVal = &pData->bIsHyphAuto; break;
+ case WID_IS_HYPH_SPECIAL : pbVal = &pData->bIsHyphSpecial; break;
+ case WID_IS_SPELL_AUTO : pbVal = &pData->bIsSpellAuto; break;
+ case WID_IS_SPELL_HIDE : /*! deprecated !*/ break;
+ case WID_IS_SPELL_IN_ALL_LANGUAGES :/*! deprecated !*/ break;
+ case WID_IS_SPELL_SPECIAL : pbVal = &pData->bIsSpellSpecial; break;
+ case WID_IS_WRAP_REVERSE : pbVal = &pData->bIsSpellReverse; break;
+ case WID_DEFAULT_LANGUAGE : pnVal = &pData->nDefaultLanguage; break;
+ case WID_IS_SPELL_CAPITALIZATION : pbVal = &pData->bIsSpellCapitalization; break;
+ case WID_IS_SPELL_WITH_DIGITS : pbVal = &pData->bIsSpellWithDigits; break;
+ case WID_IS_SPELL_UPPER_CASE : pbVal = &pData->bIsSpellUpperCase; break;
+ case WID_HYPH_MIN_LEADING : pnVal = &pData->nHyphMinLeading; break;
+ case WID_HYPH_MIN_TRAILING : pnVal = &pData->nHyphMinTrailing; break;
+ case WID_HYPH_MIN_WORD_LENGTH : pnVal = &pData->nHyphMinWordLength; break;
+ case WID_DEFAULT_LOCALE :
+ {
+ bRes = SetLocale_Impl( pData->nDefaultLanguage, rOld, rVal, ::com::sun::star::i18n::ScriptType::LATIN );
+ break;
+ }
+ case WID_DEFAULT_LOCALE_CJK :
+ {
+ bRes = SetLocale_Impl( pData->nDefaultLanguage_CJK, rOld, rVal, ::com::sun::star::i18n::ScriptType::ASIAN );
+ break;
+ }
+ case WID_DEFAULT_LOCALE_CTL :
+ {
+ bRes = SetLocale_Impl( pData->nDefaultLanguage_CTL, rOld, rVal, ::com::sun::star::i18n::ScriptType::COMPLEX );
+ break;
+ }
+ default :
+ {
+ DBG_ASSERT( 0,"lng : unknown WID");
+ bRes = FALSE;
+ }
+ }
+
+ if (pbVal)
+ {
+ BOOL bNew = FALSE;
+ rVal >>= bNew;
+ if (bNew != *pbVal)
+ {
+ rOld <<= *pbVal;
+ *pbVal = bNew;
+ bRes = TRUE;
+ }
+ }
+ if (pnVal)
+ {
+ INT16 nNew = 0;
+ rVal >>= nNew;
+ if (nNew != *pnVal)
+ {
+ rOld <<= *pnVal;
+ *pnVal = nNew;
+ bRes = TRUE;
+ }
+ }
+
+// if (bRes)
+// pData->SetModified();
+
+ return bRes;
+}
+
+void LinguOptions::GetValue( Any &rVal, INT32 nWID ) const
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ INT16 *pnVal = 0;
+ BOOL *pbVal = 0;
+ BOOL bDummy = FALSE;
+
+ switch( nWID )
+ {
+ case WID_IS_GERMAN_PRE_REFORM : pbVal = &bDummy; /*! deprecated !*/ break;
+ case WID_IS_USE_DICTIONARY_LIST : pbVal = &pData->bIsUseDictionaryList; break;
+ case WID_IS_IGNORE_CONTROL_CHARACTERS : pbVal = &pData->bIsIgnoreControlCharacters; break;
+ case WID_IS_HYPH_AUTO : pbVal = &pData->bIsHyphAuto; break;
+ case WID_IS_HYPH_SPECIAL : pbVal = &pData->bIsHyphSpecial; break;
+ case WID_IS_SPELL_AUTO : pbVal = &pData->bIsSpellAuto; break;
+ case WID_IS_SPELL_HIDE : pbVal = &bDummy; /*! deprecated !*/ break;
+ case WID_IS_SPELL_IN_ALL_LANGUAGES :pbVal = &bDummy; /*! deprecated !*/ break;
+ case WID_IS_SPELL_SPECIAL : pbVal = &pData->bIsSpellSpecial; break;
+ case WID_IS_WRAP_REVERSE : pbVal = &pData->bIsSpellReverse; break;
+ case WID_DEFAULT_LANGUAGE : pnVal = &pData->nDefaultLanguage; break;
+ case WID_IS_SPELL_CAPITALIZATION : pbVal = &pData->bIsSpellCapitalization; break;
+ case WID_IS_SPELL_WITH_DIGITS : pbVal = &pData->bIsSpellWithDigits; break;
+ case WID_IS_SPELL_UPPER_CASE : pbVal = &pData->bIsSpellUpperCase; break;
+ case WID_HYPH_MIN_LEADING : pnVal = &pData->nHyphMinLeading; break;
+ case WID_HYPH_MIN_TRAILING : pnVal = &pData->nHyphMinTrailing; break;
+ case WID_HYPH_MIN_WORD_LENGTH : pnVal = &pData->nHyphMinWordLength; break;
+ case WID_DEFAULT_LOCALE :
+ {
+ Locale aLocale( MsLangId::convertLanguageToLocale( pData->nDefaultLanguage ) );
+ rVal.setValue( &aLocale, ::getCppuType((Locale*)0 ));
+ break;
+ }
+ case WID_DEFAULT_LOCALE_CJK :
+ {
+ Locale aLocale( MsLangId::convertLanguageToLocale( pData->nDefaultLanguage_CJK ) );
+ rVal.setValue( &aLocale, ::getCppuType((Locale*)0 ));
+ break;
+ }
+ case WID_DEFAULT_LOCALE_CTL :
+ {
+ Locale aLocale( MsLangId::convertLanguageToLocale( pData->nDefaultLanguage_CTL ) );
+ rVal.setValue( &aLocale, ::getCppuType((Locale*)0 ));
+ break;
+ }
+ default :
+ {
+ DBG_ASSERT( 0,"lng : unknown WID");
+ }
+ }
+
+ if (pbVal)
+ rVal <<= *pbVal;
+ if (pnVal)
+ rVal <<= *pnVal;
+}
+
+
+struct WID_Name
+{
+ INT32 nWID;
+ const char *pPropertyName;
+};
+
+//! order of entries is import (see LinguOptions::GetName)
+//! since the WID is used as index in this table!
+WID_Name aWID_Name[] =
+{
+ { 0, 0 },
+ { WID_IS_USE_DICTIONARY_LIST, UPN_IS_USE_DICTIONARY_LIST },
+ { WID_IS_IGNORE_CONTROL_CHARACTERS, UPN_IS_IGNORE_CONTROL_CHARACTERS },
+ { WID_IS_SPELL_UPPER_CASE, UPN_IS_SPELL_UPPER_CASE },
+ { WID_IS_SPELL_WITH_DIGITS, UPN_IS_SPELL_WITH_DIGITS },
+ { WID_IS_SPELL_CAPITALIZATION, UPN_IS_SPELL_CAPITALIZATION },
+ { WID_HYPH_MIN_LEADING, UPN_HYPH_MIN_LEADING },
+ { WID_HYPH_MIN_TRAILING, UPN_HYPH_MIN_TRAILING },
+ { WID_HYPH_MIN_WORD_LENGTH, UPN_HYPH_MIN_WORD_LENGTH },
+ { WID_DEFAULT_LOCALE, UPN_DEFAULT_LOCALE },
+ { WID_IS_SPELL_AUTO, UPN_IS_SPELL_AUTO },
+ { 0, 0 },
+ { 0, 0 },
+ { WID_IS_SPELL_SPECIAL, UPN_IS_SPELL_SPECIAL },
+ { WID_IS_HYPH_AUTO, UPN_IS_HYPH_AUTO },
+ { WID_IS_HYPH_SPECIAL, UPN_IS_HYPH_SPECIAL },
+ { WID_IS_WRAP_REVERSE, UPN_IS_WRAP_REVERSE },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { WID_DEFAULT_LANGUAGE, UPN_DEFAULT_LANGUAGE },
+ { WID_DEFAULT_LOCALE_CJK, UPN_DEFAULT_LOCALE_CJK },
+ { WID_DEFAULT_LOCALE_CTL, UPN_DEFAULT_LOCALE_CTL }
+};
+
+
+OUString LinguOptions::GetName( INT32 nWID )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ OUString aRes;
+
+ INT32 nLen = sizeof( aWID_Name ) / sizeof( aWID_Name[0] );
+ if (0 <= nWID && nWID < nLen
+ && aWID_Name[ nWID ].nWID == nWID)
+ {
+ aRes = OUString( RTL_CONSTASCII_USTRINGPARAM(
+ aWID_Name[ nWID ].pPropertyName ) );
+ }
+ else
+ {
+ DBG_ASSERT( 0,"lng : unknown WID");
+ }
+
+ return aRes;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+//! map must be sorted by first entry in alphabetical increasing order.
+const SfxItemPropertyMapEntry* lcl_GetLinguProps()
+{
+ static const SfxItemPropertyMapEntry aLinguProps[] =
+ {
+ { MAP_CHAR_LEN(UPN_DEFAULT_LANGUAGE), WID_DEFAULT_LANGUAGE,
+ &::getCppuType( (sal_Int16*)0 ), 0, 0 },
+ { MAP_CHAR_LEN(UPN_DEFAULT_LOCALE), WID_DEFAULT_LOCALE,
+ &::getCppuType( (Locale* )0), 0, 0 },
+ { MAP_CHAR_LEN(UPN_DEFAULT_LOCALE_CJK), WID_DEFAULT_LOCALE_CJK,
+ &::getCppuType( (Locale* )0), 0, 0 },
+ { MAP_CHAR_LEN(UPN_DEFAULT_LOCALE_CTL), WID_DEFAULT_LOCALE_CTL,
+ &::getCppuType( (Locale* )0), 0, 0 },
+ { MAP_CHAR_LEN(UPN_HYPH_MIN_LEADING), WID_HYPH_MIN_LEADING,
+ &::getCppuType( (sal_Int16*)0 ), 0, 0 },
+ { MAP_CHAR_LEN(UPN_HYPH_MIN_TRAILING), WID_HYPH_MIN_TRAILING,
+ &::getCppuType( (sal_Int16*)0 ), 0, 0 },
+ { MAP_CHAR_LEN(UPN_HYPH_MIN_WORD_LENGTH), WID_HYPH_MIN_WORD_LENGTH,
+ &::getCppuType( (sal_Int16*)0 ), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_GERMAN_PRE_REFORM), WID_IS_GERMAN_PRE_REFORM, /*! deprecated !*/
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_HYPH_AUTO), WID_IS_HYPH_AUTO,
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_HYPH_SPECIAL), WID_IS_HYPH_SPECIAL,
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_IGNORE_CONTROL_CHARACTERS), WID_IS_IGNORE_CONTROL_CHARACTERS,
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_SPELL_AUTO), WID_IS_SPELL_AUTO,
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_SPELL_CAPITALIZATION), WID_IS_SPELL_CAPITALIZATION,
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_SPELL_HIDE), WID_IS_SPELL_HIDE, /*! deprecated !*/
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_SPELL_IN_ALL_LANGUAGES), WID_IS_SPELL_IN_ALL_LANGUAGES, /*! deprecated !*/
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_SPELL_SPECIAL), WID_IS_SPELL_SPECIAL,
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_SPELL_UPPER_CASE), WID_IS_SPELL_UPPER_CASE,
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_SPELL_WITH_DIGITS), WID_IS_SPELL_WITH_DIGITS,
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_USE_DICTIONARY_LIST), WID_IS_USE_DICTIONARY_LIST,
+ &::getBooleanCppuType(), 0, 0 },
+ { MAP_CHAR_LEN(UPN_IS_WRAP_REVERSE), WID_IS_WRAP_REVERSE,
+ &::getBooleanCppuType(), 0, 0 },
+ { 0,0,0,0,0,0 }
+ };
+ return aLinguProps;
+}
+LinguProps::LinguProps() :
+ aEvtListeners (GetLinguMutex()),
+ aPropListeners (GetLinguMutex()),
+ aPropertyMap(lcl_GetLinguProps())
+{
+ bDisposing = FALSE;
+}
+
+void LinguProps::launchEvent( const PropertyChangeEvent &rEvt ) const
+{
+ cppu::OInterfaceContainerHelper *pContainer =
+ aPropListeners.getContainer( rEvt.PropertyHandle );
+ if (pContainer)
+ {
+ cppu::OInterfaceIteratorHelper aIt( *pContainer );
+ while (aIt.hasMoreElements())
+ {
+ Reference< XPropertyChangeListener > xRef( aIt.next(), UNO_QUERY );
+ if (xRef.is())
+ xRef->propertyChange( rEvt );
+ }
+ }
+}
+
+Reference< XInterface > SAL_CALL LinguProps_CreateInstance(
+ const Reference< XMultiServiceFactory > & /*rSMgr*/ )
+ throw(Exception)
+{
+ Reference< XInterface > xService = (cppu::OWeakObject*)new LinguProps;
+ return xService;
+}
+
+Reference< XPropertySetInfo > SAL_CALL LinguProps::getPropertySetInfo()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ static Reference< XPropertySetInfo > aRef =
+ new SfxItemPropertySetInfo( &aPropertyMap );
+ return aRef;
+}
+
+void SAL_CALL LinguProps::setPropertyValue(
+ const OUString& rPropertyName, const Any& rValue )
+ throw(UnknownPropertyException, PropertyVetoException,
+ IllegalArgumentException, WrappedTargetException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ const SfxItemPropertySimpleEntry* pCur = aPropertyMap.getByName( rPropertyName );
+ if (pCur)
+ {
+ Any aOld( aConfig.GetProperty( pCur->nWID ) );
+ if (aOld != rValue && aConfig.SetProperty( pCur->nWID, rValue ))
+ {
+ PropertyChangeEvent aChgEvt( (XPropertySet *) this, rPropertyName,
+ FALSE, pCur->nWID, aOld, rValue );
+ launchEvent( aChgEvt );
+ }
+ }
+#ifdef LINGU_EXCEPTIONS
+ else
+ {
+ throw UnknownPropertyException();
+ }
+#endif
+}
+
+Any SAL_CALL LinguProps::getPropertyValue( const OUString& rPropertyName )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Any aRet;
+
+ const SfxItemPropertySimpleEntry* pCur = aPropertyMap.getByName( rPropertyName );
+ if(pCur)
+ {
+ aRet = aConfig.GetProperty( pCur->nWID );
+ }
+#ifdef LINGU_EXCEPTIONS
+ else
+ {
+ throw UnknownPropertyException();
+ }
+#endif
+
+ return aRet;
+}
+
+void SAL_CALL LinguProps::addPropertyChangeListener(
+ const OUString& rPropertyName,
+ const Reference< XPropertyChangeListener >& rxListener )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bDisposing && rxListener.is())
+ {
+ const SfxItemPropertySimpleEntry* pCur = aPropertyMap.getByName( rPropertyName );
+ if(pCur)
+ aPropListeners.addInterface( pCur->nWID, rxListener );
+#ifdef LINGU_EXCEPTIONS
+ else
+ {
+ throw UnknownPropertyException();
+ }
+#endif
+ }
+}
+
+void SAL_CALL LinguProps::removePropertyChangeListener(
+ const OUString& rPropertyName,
+ const Reference< XPropertyChangeListener >& rxListener )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bDisposing && rxListener.is())
+ {
+ const SfxItemPropertySimpleEntry* pCur = aPropertyMap.getByName( rPropertyName );
+ if(pCur)
+ aPropListeners.removeInterface( pCur->nWID, rxListener );
+#ifdef LINGU_EXCEPTIONS
+ else
+ {
+ throw UnknownPropertyException();
+ }
+#endif
+ }
+}
+
+void SAL_CALL LinguProps::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const Reference< XVetoableChangeListener >& /*xListener*/ )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+// MutexGuard aGuard( GetLinguMutex() );
+}
+
+void SAL_CALL LinguProps::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const Reference< XVetoableChangeListener >& /*xListener*/ )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+// MutexGuard aGuard( GetLinguMutex() );
+}
+
+
+void SAL_CALL LinguProps::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue )
+ throw(UnknownPropertyException, PropertyVetoException,
+ IllegalArgumentException, WrappedTargetException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Any aOld( aConfig.GetProperty( nHandle ) );
+ if (aOld != rValue && aConfig.SetProperty( nHandle, rValue ))
+ {
+ PropertyChangeEvent aChgEvt( (XPropertySet *) this,
+ LinguOptions::GetName( nHandle ), FALSE, nHandle, aOld, rValue );
+ launchEvent( aChgEvt );
+ }
+}
+
+
+Any SAL_CALL LinguProps::getFastPropertyValue( sal_Int32 nHandle )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Any aRes( aConfig.GetProperty( nHandle ) );
+ return aRes;
+}
+
+
+Sequence< PropertyValue > SAL_CALL
+ LinguProps::getPropertyValues()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ INT32 nLen = aPropertyMap.getSize();
+ Sequence< PropertyValue > aProps( nLen );
+ PropertyValue *pProp = aProps.getArray();
+ PropertyEntryVector_t aPropEntries = aPropertyMap.getPropertyEntries();
+ PropertyEntryVector_t::const_iterator aIt = aPropEntries.begin();
+ for (INT32 i = 0; i < nLen; ++i, ++aIt)
+ {
+ PropertyValue &rVal = pProp[i];
+ Any aAny( aConfig.GetProperty( aIt->nWID ) );
+
+ rVal.Name = aIt->sName;
+ rVal.Handle = aIt->nWID;
+ rVal.Value = aAny;
+ rVal.State = PropertyState_DIRECT_VALUE ;
+ }
+ return aProps;
+}
+
+void SAL_CALL
+ LinguProps::setPropertyValues( const Sequence< PropertyValue >& rProps )
+ throw(UnknownPropertyException, PropertyVetoException,
+ IllegalArgumentException, WrappedTargetException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ INT32 nLen = rProps.getLength();
+ const PropertyValue *pVal = rProps.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ const PropertyValue &rVal = pVal[i];
+ setPropertyValue( rVal.Name, rVal.Value );
+ }
+}
+
+void SAL_CALL
+ LinguProps::dispose()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bDisposing)
+ {
+ bDisposing = TRUE;
+
+ //! its too late to save the options here!
+ // (see AppExitListener for saving)
+ //aOpt.Save(); // save (possible) changes before exiting
+
+ EventObject aEvtObj( (XPropertySet *) this );
+ aEvtListeners.disposeAndClear( aEvtObj );
+ aPropListeners.disposeAndClear( aEvtObj );
+ }
+}
+
+void SAL_CALL
+ LinguProps::addEventListener( const Reference< XEventListener >& rxListener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bDisposing && rxListener.is())
+ aEvtListeners.addInterface( rxListener );
+}
+
+void SAL_CALL
+ LinguProps::removeEventListener( const Reference< XEventListener >& rxListener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bDisposing && rxListener.is())
+ aEvtListeners.removeInterface( rxListener );
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+// Service specific part
+//
+
+// XServiceInfo
+OUString SAL_CALL LinguProps::getImplementationName()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return getImplementationName_Static();
+}
+
+// XServiceInfo
+sal_Bool SAL_CALL LinguProps::supportsService( const OUString& ServiceName )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Sequence< OUString > aSNL = getSupportedServiceNames();
+ const OUString * pArray = aSNL.getConstArray();
+ for( INT32 i = 0; i < aSNL.getLength(); i++ )
+ if( pArray[i] == ServiceName )
+ return TRUE;
+ return FALSE;
+}
+
+// XServiceInfo
+uno::Sequence< OUString > SAL_CALL LinguProps::getSupportedServiceNames()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return getSupportedServiceNames_Static();
+}
+
+// ORegistryServiceManager_Static
+uno::Sequence< OUString > LinguProps::getSupportedServiceNames_Static()
+ throw()
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Sequence< OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich
+ aSNS.getArray()[0] = A2OU( SN_LINGU_PROPERTIES );
+ return aSNS;
+}
+
+
+sal_Bool SAL_CALL LinguProps_writeInfo( void * /*pServiceManager*/,
+ XRegistryKey * pRegistryKey )
+{
+ try
+ {
+ String aImpl( '/' );
+ aImpl += LinguProps::getImplementationName_Static().getStr();
+ aImpl.AppendAscii( "/UNO/SERVICES" );
+ Reference< XRegistryKey > xNewKey =
+ pRegistryKey->createKey(aImpl );
+ uno::Sequence< OUString > aServices = LinguProps::getSupportedServiceNames_Static();
+ for( INT32 i = 0; i < aServices.getLength(); i++ )
+ xNewKey->createKey( aServices.getConstArray()[i]);
+
+ return sal_True;
+ }
+ catch(Exception &)
+ {
+ return sal_False;
+ }
+}
+
+void * SAL_CALL LinguProps_getFactory( const sal_Char * pImplName,
+ XMultiServiceFactory *pServiceManager, void * )
+{
+ void * pRet = 0;
+ if ( !LinguProps::getImplementationName_Static().compareToAscii( pImplName ) )
+ {
+ Reference< XSingleServiceFactory > xFactory =
+ cppu::createOneInstanceFactory(
+ pServiceManager,
+ LinguProps::getImplementationName_Static(),
+ LinguProps_CreateInstance,
+ LinguProps::getSupportedServiceNames_Static());
+ // acquire, because we return an interface pointer instead of a reference
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+ return pRet;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/lngopt.hxx b/linguistic/source/lngopt.hxx
new file mode 100644
index 000000000000..7e86f31fc437
--- /dev/null
+++ b/linguistic/source/lngopt.hxx
@@ -0,0 +1,186 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_LNGOPT_HHX_
+#define _LINGUISTIC_LNGOPT_HHX_
+
+#include <functional>
+
+#include <uno/lbnames.h> // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
+#include <cppuhelper/implbase5.hxx> // helper for implementations
+#include <cppuhelper/interfacecontainer.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <unotools/lingucfg.hxx>
+#include <svl/itemprop.hxx>
+#include <unotools/configitem.hxx>
+#include <com/sun/star/uno/Any.h>
+#include <tools/solar.h>
+
+#include <svl/itemprop.hxx>
+#include "misc.hxx"
+#include "defs.hxx"
+#include <vos/refernce.hxx>
+
+namespace com { namespace sun { namespace star {
+ namespace beans {
+ struct PropertyChangeEvent;
+ }
+ namespace registry {
+ class XRegistryKey;
+ }
+}}}
+
+
+
+///////////////////////////////////////////////////////////////////////////
+// LinguOptions
+// This class represents all Linguistik relevant options.
+//
+
+class LinguOptions
+{
+ static SvtLinguOptions *pData;
+ static vos::ORefCount aRefCount; // number of objects of this class
+
+ //! uses default assignment-operator
+
+ BOOL SetLocale_Impl( INT16 &rLanguage,
+ ::com::sun::star::uno::Any &rOld,
+ const ::com::sun::star::uno::Any &rVal, sal_Int16 nType );
+
+public:
+ LinguOptions();
+ LinguOptions(const LinguOptions &rOpt);
+ ~LinguOptions();
+
+ BOOL SetValue( ::com::sun::star::uno::Any &rOld,
+ const ::com::sun::star::uno::Any &rVal, INT32 nWID );
+ void GetValue( ::com::sun::star::uno::Any &rVal, INT32 nWID ) const;
+
+ static ::rtl::OUString GetName( INT32 nWID );
+
+ const ::com::sun::star::uno::Sequence< rtl::OUString >
+ GetActiveDics() const { return pData->aActiveDics; }
+
+ const ::com::sun::star::uno::Sequence< rtl::OUString >
+ GetActiveConvDics() const { return pData->aActiveConvDics; }
+};
+
+
+///////////////////////////////////////////////////////////////////////////
+
+// uses templates from <cppuhelper/interfacecontainer.h>
+
+
+// helper function call class
+struct PropHashType_Impl
+{
+ size_t operator()(const INT32 &s) const { return s; }
+};
+
+typedef cppu::OMultiTypeInterfaceContainerHelperVar
+ <
+ INT32,
+ PropHashType_Impl,
+ std::equal_to< INT32 >
+ > OPropertyListenerContainerHelper;
+
+///////////////////////////////////////////////////////////////////////////
+
+
+class LinguProps :
+ public cppu::WeakImplHelper5
+ <
+ com::sun::star::beans::XPropertySet,
+ com::sun::star::beans::XFastPropertySet,
+ com::sun::star::beans::XPropertyAccess,
+ com::sun::star::lang::XComponent,
+ com::sun::star::lang::XServiceInfo
+ >
+{
+ ::cppu::OInterfaceContainerHelper aEvtListeners;
+ OPropertyListenerContainerHelper aPropListeners;
+
+ SfxItemPropertyMap aPropertyMap;
+ SvtLinguConfig aConfig;
+
+ BOOL bDisposing;
+
+ // disallow copy-constructor and assignment-operator for now
+ LinguProps(const LinguProps &);
+ LinguProps & operator = (const LinguProps &);
+
+ void launchEvent( const ::com::sun::star::beans::PropertyChangeEvent &rEvt ) const;
+
+public:
+ LinguProps();
+
+ // XPropertySet
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& rxListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& rxListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& rxListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& rxListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
+
+ // XFastPropertySet
+ virtual void SAL_CALL setFastPropertyValue( sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue( sal_Int32 nHandle ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
+
+ // XPropertyAccess
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getPropertyValues() throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setPropertyValues( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
+
+ // XComponent
+ virtual void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& rxListener ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& rxListener ) throw(::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName() throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw(::com::sun::star::uno::RuntimeException);
+
+
+ static inline ::rtl::OUString getImplementationName_Static() throw();
+ static com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedServiceNames_Static() throw();
+};
+
+inline ::rtl::OUString LinguProps::getImplementationName_Static() throw()
+{
+ return A2OU( "com.sun.star.lingu2.LinguProps" );
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/lngprophelp.cxx b/linguistic/source/lngprophelp.cxx
new file mode 100644
index 000000000000..91b1a7ff8ebc
--- /dev/null
+++ b/linguistic/source/lngprophelp.cxx
@@ -0,0 +1,717 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+#include <tools/debug.hxx>
+
+#include <com/sun/star/linguistic2/LinguServiceEvent.hpp>
+#include <com/sun/star/linguistic2/LinguServiceEventFlags.hpp>
+#include <com/sun/star/linguistic2/XLinguServiceEventListener.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <osl/mutex.hxx>
+
+#include <misc.hxx>
+#include <lngprops.hxx>
+
+#include <lngprophelp.hxx>
+
+
+//using namespace utl;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::linguistic2;
+using namespace linguistic;
+
+namespace linguistic
+{
+
+///////////////////////////////////////////////////////////////////////////
+
+static const char *aCH[] =
+{
+ UPN_IS_IGNORE_CONTROL_CHARACTERS,
+ UPN_IS_USE_DICTIONARY_LIST,
+};
+
+static int nCHCount = sizeof(aCH) / sizeof(aCH[0]);
+
+
+PropertyChgHelper::PropertyChgHelper(
+ const Reference< XInterface > &rxSource,
+ Reference< XPropertySet > &rxPropSet,
+ int nAllowedEvents ) :
+ PropertyChgHelperBase(),
+ aPropNames (nCHCount),
+ xMyEvtObj (rxSource),
+ aLngSvcEvtListeners (GetLinguMutex()),
+ xPropSet (rxPropSet),
+ nEvtFlags (nAllowedEvents)
+{
+ OUString *pName = aPropNames.getArray();
+ for (INT32 i = 0; i < nCHCount; ++i)
+ {
+ pName[i] = A2OU( aCH[i] );
+ }
+
+ SetDefaultValues();
+}
+
+
+PropertyChgHelper::PropertyChgHelper( const PropertyChgHelper &rHelper ) :
+ PropertyChgHelperBase(),
+ aLngSvcEvtListeners (GetLinguMutex())
+{
+ RemoveAsPropListener();
+ aPropNames = rHelper.aPropNames;
+ xMyEvtObj = rHelper.xMyEvtObj;
+ xPropSet = rHelper.xPropSet;
+ nEvtFlags = rHelper.nEvtFlags;
+ AddAsPropListener();
+
+ SetDefaultValues();
+ GetCurrentValues();
+}
+
+
+PropertyChgHelper::~PropertyChgHelper()
+{
+}
+
+
+void PropertyChgHelper::AddPropNames( const char *pNewNames[], INT32 nCount )
+{
+ if (pNewNames && nCount)
+ {
+ INT32 nLen = GetPropNames().getLength();
+ GetPropNames().realloc( nLen + nCount );
+ OUString *pName = GetPropNames().getArray();
+ for (INT32 i = 0; i < nCount; ++i)
+ {
+ pName[ nLen + i ] = A2OU( pNewNames[ i ] );
+ }
+ }
+}
+
+
+void PropertyChgHelper::SetDefaultValues()
+{
+ bResIsIgnoreControlCharacters = bIsIgnoreControlCharacters = TRUE;
+ bResIsUseDictionaryList = bIsUseDictionaryList = TRUE;
+}
+
+
+void PropertyChgHelper::GetCurrentValues()
+{
+ INT32 nLen = GetPropNames().getLength();
+ if (GetPropSet().is() && nLen)
+ {
+ const OUString *pPropName = GetPropNames().getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ BOOL *pbVal = NULL,
+ *pbResVal = NULL;
+
+ if (pPropName[i].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( UPN_IS_IGNORE_CONTROL_CHARACTERS ) ))
+ {
+ pbVal = &bIsIgnoreControlCharacters;
+ pbResVal = &bResIsIgnoreControlCharacters;
+ }
+ else if (pPropName[i].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( UPN_IS_USE_DICTIONARY_LIST ) ))
+ {
+ pbVal = &bIsUseDictionaryList;
+ pbResVal = &bResIsUseDictionaryList;
+ }
+
+ if (pbVal && pbResVal)
+ {
+ GetPropSet()->getPropertyValue( pPropName[i] ) >>= *pbVal;
+ *pbResVal = *pbVal;
+ }
+ }
+ }
+}
+
+
+void PropertyChgHelper::SetTmpPropVals( const PropertyValues &rPropVals )
+{
+ // return value is default value unless there is an explicitly supplied
+ // temporary value
+ bResIsIgnoreControlCharacters = bIsIgnoreControlCharacters;
+ bResIsUseDictionaryList = bIsUseDictionaryList;
+ //
+ INT32 nLen = rPropVals.getLength();
+ if (nLen)
+ {
+ const PropertyValue *pVal = rPropVals.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ BOOL *pbResVal = NULL;
+ switch (pVal[i].Handle)
+ {
+ case UPH_IS_IGNORE_CONTROL_CHARACTERS :
+ pbResVal = &bResIsIgnoreControlCharacters; break;
+ case UPH_IS_USE_DICTIONARY_LIST :
+ pbResVal = &bResIsUseDictionaryList; break;
+ default:
+ ;
+ //DBG_ASSERT( 0, "unknown property" );
+ }
+ if (pbResVal)
+ pVal[i].Value >>= *pbResVal;
+ }
+ }
+}
+
+
+BOOL PropertyChgHelper::propertyChange_Impl( const PropertyChangeEvent& rEvt )
+{
+ BOOL bRes = FALSE;
+
+ if (GetPropSet().is() && rEvt.Source == GetPropSet())
+ {
+ INT16 nLngSvcFlags = (nEvtFlags & AE_HYPHENATOR) ?
+ LinguServiceEventFlags::HYPHENATE_AGAIN : 0;
+ BOOL bSCWA = FALSE, // SPELL_CORRECT_WORDS_AGAIN ?
+ bSWWA = FALSE; // SPELL_WRONG_WORDS_AGAIN ?
+
+ BOOL *pbVal = NULL;
+ switch (rEvt.PropertyHandle)
+ {
+ case UPH_IS_IGNORE_CONTROL_CHARACTERS :
+ {
+ pbVal = &bIsIgnoreControlCharacters;
+ nLngSvcFlags = 0;
+ break;
+ }
+ case UPH_IS_USE_DICTIONARY_LIST :
+ {
+ pbVal = &bIsUseDictionaryList;
+ bSCWA = bSWWA = TRUE;
+ break;
+ }
+ default:
+ {
+ bRes = FALSE;
+ //DBG_ASSERT( 0, "unknown property" );
+ }
+ }
+ if (pbVal)
+ rEvt.NewValue >>= *pbVal;
+
+ bRes = 0 != pbVal; // sth changed?
+ if (bRes)
+ {
+ BOOL bSpellEvts = (nEvtFlags & AE_SPELLCHECKER) ? TRUE : FALSE;
+ if (bSCWA && bSpellEvts)
+ nLngSvcFlags |= LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN;
+ if (bSWWA && bSpellEvts)
+ nLngSvcFlags |= LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN;
+ if (nLngSvcFlags)
+ {
+ LinguServiceEvent aEvt( GetEvtObj(), nLngSvcFlags );
+ LaunchEvent( aEvt );
+ }
+ }
+ }
+
+ return bRes;
+}
+
+
+void SAL_CALL
+ PropertyChgHelper::propertyChange( const PropertyChangeEvent& rEvt )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ propertyChange_Impl( rEvt );
+}
+
+
+void PropertyChgHelper::AddAsPropListener()
+{
+ if (xPropSet.is())
+ {
+ INT32 nLen = aPropNames.getLength();
+ const OUString *pPropName = aPropNames.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ if (pPropName[i].getLength())
+ xPropSet->addPropertyChangeListener( pPropName[i], this );
+ }
+ }
+}
+
+void PropertyChgHelper::RemoveAsPropListener()
+{
+ if (xPropSet.is())
+ {
+ INT32 nLen = aPropNames.getLength();
+ const OUString *pPropName = aPropNames.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ if (pPropName[i].getLength())
+ xPropSet->removePropertyChangeListener( pPropName[i], this );
+ }
+ }
+}
+
+
+void PropertyChgHelper::LaunchEvent( const LinguServiceEvent &rEvt )
+{
+ cppu::OInterfaceIteratorHelper aIt( aLngSvcEvtListeners );
+ while (aIt.hasMoreElements())
+ {
+ Reference< XLinguServiceEventListener > xRef( aIt.next(), UNO_QUERY );
+ if (xRef.is())
+ xRef->processLinguServiceEvent( rEvt );
+ }
+}
+
+
+void SAL_CALL PropertyChgHelper::disposing( const EventObject& rSource )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ if (rSource.Source == xPropSet)
+ {
+ RemoveAsPropListener();
+ xPropSet = NULL;
+ aPropNames.realloc( 0 );
+ }
+}
+
+
+sal_Bool SAL_CALL
+ PropertyChgHelper::addLinguServiceEventListener(
+ const Reference< XLinguServiceEventListener >& rxListener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = FALSE;
+ if (rxListener.is())
+ {
+ INT32 nCount = aLngSvcEvtListeners.getLength();
+ bRes = aLngSvcEvtListeners.addInterface( rxListener ) != nCount;
+ }
+ return bRes;
+}
+
+
+sal_Bool SAL_CALL
+ PropertyChgHelper::removeLinguServiceEventListener(
+ const Reference< XLinguServiceEventListener >& rxListener )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = FALSE;
+ if (rxListener.is())
+ {
+ INT32 nCount = aLngSvcEvtListeners.getLength();
+ bRes = aLngSvcEvtListeners.removeInterface( rxListener ) != nCount;
+ }
+ return bRes;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+
+PropertyHelper_Thes::PropertyHelper_Thes(
+ const Reference< XInterface > &rxSource,
+ Reference< XPropertySet > &rxPropSet ) :
+ PropertyChgHelper ( rxSource, rxPropSet, 0 )
+{
+ SetDefaultValues();
+ GetCurrentValues();
+}
+
+
+PropertyHelper_Thes::~PropertyHelper_Thes()
+{
+}
+
+
+void SAL_CALL
+ PropertyHelper_Thes::propertyChange( const PropertyChangeEvent& rEvt )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ PropertyChgHelper::propertyChange_Impl( rEvt );
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+// list of properties from the property set to be used
+// and listened to
+static const char *aSP[] =
+{
+ UPN_IS_SPELL_UPPER_CASE,
+ UPN_IS_SPELL_WITH_DIGITS,
+ UPN_IS_SPELL_CAPITALIZATION
+};
+
+
+PropertyHelper_Spell::PropertyHelper_Spell(
+ const Reference< XInterface > & rxSource,
+ Reference< XPropertySet > &rxPropSet ) :
+ PropertyChgHelper ( rxSource, rxPropSet, AE_SPELLCHECKER )
+{
+ AddPropNames( aSP, sizeof(aSP) / sizeof(aSP[0]) );
+ SetDefaultValues();
+ GetCurrentValues();
+
+ nResMaxNumberOfSuggestions = GetDefaultNumberOfSuggestions();
+}
+
+
+PropertyHelper_Spell::~PropertyHelper_Spell()
+{
+}
+
+
+void PropertyHelper_Spell::SetDefaultValues()
+{
+ PropertyChgHelper::SetDefaultValues();
+
+ bResIsSpellUpperCase = bIsSpellUpperCase = FALSE;
+ bResIsSpellWithDigits = bIsSpellWithDigits = FALSE;
+ bResIsSpellCapitalization = bIsSpellCapitalization = TRUE;
+}
+
+
+void PropertyHelper_Spell::GetCurrentValues()
+{
+ PropertyChgHelper::GetCurrentValues();
+
+ INT32 nLen = GetPropNames().getLength();
+ if (GetPropSet().is() && nLen)
+ {
+ const OUString *pPropName = GetPropNames().getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ BOOL *pbVal = NULL,
+ *pbResVal = NULL;
+
+ if (pPropName[i].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( UPN_IS_SPELL_UPPER_CASE ) ))
+ {
+ pbVal = &bIsSpellUpperCase;
+ pbResVal = &bResIsSpellUpperCase;
+ }
+ else if (pPropName[i].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( UPN_IS_SPELL_WITH_DIGITS ) ))
+ {
+ pbVal = &bIsSpellWithDigits;
+ pbResVal = &bResIsSpellWithDigits;
+ }
+ else if (pPropName[i].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( UPN_IS_SPELL_CAPITALIZATION ) ))
+ {
+ pbVal = &bIsSpellCapitalization;
+ pbResVal = &bResIsSpellCapitalization;
+ }
+
+ if (pbVal && pbResVal)
+ {
+ GetPropSet()->getPropertyValue( pPropName[i] ) >>= *pbVal;
+ *pbResVal = *pbVal;
+ }
+ }
+ }
+}
+
+
+BOOL PropertyHelper_Spell::propertyChange_Impl( const PropertyChangeEvent& rEvt )
+{
+ BOOL bRes = PropertyChgHelper::propertyChange_Impl( rEvt );
+
+ if (!bRes && GetPropSet().is() && rEvt.Source == GetPropSet())
+ {
+ INT16 nLngSvcFlags = 0;
+ BOOL bSCWA = FALSE, // SPELL_CORRECT_WORDS_AGAIN ?
+ bSWWA = FALSE; // SPELL_WRONG_WORDS_AGAIN ?
+
+ BOOL *pbVal = NULL;
+ switch (rEvt.PropertyHandle)
+ {
+ case UPH_IS_SPELL_UPPER_CASE :
+ {
+ pbVal = &bIsSpellUpperCase;
+ bSCWA = FALSE == *pbVal; // FALSE->TRUE change?
+ bSWWA = !bSCWA; // TRUE->FALSE change?
+ break;
+ }
+ case UPH_IS_SPELL_WITH_DIGITS :
+ {
+ pbVal = &bIsSpellWithDigits;
+ bSCWA = FALSE == *pbVal; // FALSE->TRUE change?
+ bSWWA = !bSCWA; // TRUE->FALSE change?
+ break;
+ }
+ case UPH_IS_SPELL_CAPITALIZATION :
+ {
+ pbVal = &bIsSpellCapitalization;
+ bSCWA = FALSE == *pbVal; // FALSE->TRUE change?
+ bSWWA = !bSCWA; // TRUE->FALSE change?
+ break;
+ }
+ default:
+ DBG_ASSERT( 0, "unknown property" );
+ }
+ if (pbVal)
+ rEvt.NewValue >>= *pbVal;
+
+ bRes = (pbVal != 0);
+ if (bRes)
+ {
+ if (bSCWA)
+ nLngSvcFlags |= LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN;
+ if (bSWWA)
+ nLngSvcFlags |= LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN;
+ if (nLngSvcFlags)
+ {
+ LinguServiceEvent aEvt( GetEvtObj(), nLngSvcFlags );
+ LaunchEvent( aEvt );
+ }
+ }
+ }
+
+ return bRes;
+}
+
+
+void SAL_CALL
+ PropertyHelper_Spell::propertyChange( const PropertyChangeEvent& rEvt )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ propertyChange_Impl( rEvt );
+}
+
+
+void PropertyHelper_Spell::SetTmpPropVals( const PropertyValues &rPropVals )
+{
+ PropertyChgHelper::SetTmpPropVals( rPropVals );
+
+ // return value is default value unless there is an explicitly supplied
+ // temporary value
+ nResMaxNumberOfSuggestions = GetDefaultNumberOfSuggestions();
+ bResIsSpellWithDigits = bIsSpellWithDigits;
+ bResIsSpellCapitalization = bIsSpellCapitalization;
+ //
+ INT32 nLen = rPropVals.getLength();
+ if (nLen)
+ {
+ const PropertyValue *pVal = rPropVals.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ if (pVal[i].Name.equalsAscii( UPN_MAX_NUMBER_OF_SUGGESTIONS ))
+ {
+ pVal[i].Value >>= nResMaxNumberOfSuggestions;
+ }
+ else
+ {
+ BOOL *pbResVal = NULL;
+ switch (pVal[i].Handle)
+ {
+ case UPH_IS_SPELL_UPPER_CASE : pbResVal = &bResIsSpellUpperCase; break;
+ case UPH_IS_SPELL_WITH_DIGITS : pbResVal = &bResIsSpellWithDigits; break;
+ case UPH_IS_SPELL_CAPITALIZATION : pbResVal = &bResIsSpellCapitalization; break;
+ default:
+ DBG_ASSERT( 0, "unknown property" );
+ }
+ if (pbResVal)
+ pVal[i].Value >>= *pbResVal;
+ }
+ }
+ }
+}
+
+INT16 PropertyHelper_Spell::GetDefaultNumberOfSuggestions() const
+{
+ return 16;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static const char *aHP[] =
+{
+ UPN_HYPH_MIN_LEADING,
+ UPN_HYPH_MIN_TRAILING,
+ UPN_HYPH_MIN_WORD_LENGTH
+};
+
+
+PropertyHelper_Hyphen::PropertyHelper_Hyphen(
+ const Reference< XInterface > & rxSource,
+ Reference< XPropertySet > &rxPropSet ) :
+ PropertyChgHelper ( rxSource, rxPropSet, AE_HYPHENATOR )
+{
+ AddPropNames( aHP, sizeof(aHP) / sizeof(aHP[0]) );
+ SetDefaultValues();
+ GetCurrentValues();
+}
+
+
+PropertyHelper_Hyphen::~PropertyHelper_Hyphen()
+{
+}
+
+
+void PropertyHelper_Hyphen::SetDefaultValues()
+{
+ PropertyChgHelper::SetDefaultValues();
+
+ nResHyphMinLeading = nHyphMinLeading = 2;
+ nResHyphMinTrailing = nHyphMinTrailing = 2;
+ nResHyphMinWordLength = nHyphMinWordLength = 0;
+}
+
+
+void PropertyHelper_Hyphen::GetCurrentValues()
+{
+ PropertyChgHelper::GetCurrentValues();
+
+ INT32 nLen = GetPropNames().getLength();
+ if (GetPropSet().is() && nLen)
+ {
+ const OUString *pPropName = GetPropNames().getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ INT16 *pnVal = NULL,
+ *pnResVal = NULL;
+
+ if (pPropName[i].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( UPN_HYPH_MIN_LEADING ) ))
+ {
+ pnVal = &nHyphMinLeading;
+ pnResVal = &nResHyphMinLeading;
+ }
+ else if (pPropName[i].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( UPN_HYPH_MIN_TRAILING ) ))
+ {
+ pnVal = &nHyphMinTrailing;
+ pnResVal = &nResHyphMinTrailing;
+ }
+ else if (pPropName[i].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( UPN_HYPH_MIN_WORD_LENGTH ) ))
+ {
+ pnVal = &nHyphMinWordLength;
+ pnResVal = &nResHyphMinWordLength;
+ }
+
+ if (pnVal && pnResVal)
+ {
+ GetPropSet()->getPropertyValue( pPropName[i] ) >>= *pnVal;
+ *pnResVal = *pnVal;
+ }
+ }
+ }
+}
+
+
+BOOL PropertyHelper_Hyphen::propertyChange_Impl( const PropertyChangeEvent& rEvt )
+{
+ BOOL bRes = PropertyChgHelper::propertyChange_Impl( rEvt );
+
+ if (!bRes && GetPropSet().is() && rEvt.Source == GetPropSet())
+ {
+ INT16 nLngSvcFlags = LinguServiceEventFlags::HYPHENATE_AGAIN;
+
+ INT16 *pnVal = NULL;
+ switch (rEvt.PropertyHandle)
+ {
+ case UPH_HYPH_MIN_LEADING : pnVal = &nHyphMinLeading; break;
+ case UPH_HYPH_MIN_TRAILING : pnVal = &nHyphMinTrailing; break;
+ case UPH_HYPH_MIN_WORD_LENGTH : pnVal = &nHyphMinWordLength; break;
+ default:
+ DBG_ASSERT( 0, "unknown property" );
+ }
+ if (pnVal)
+ rEvt.NewValue >>= *pnVal;
+
+ bRes = (pnVal != 0);
+ if (bRes)
+ {
+ if (nLngSvcFlags)
+ {
+ LinguServiceEvent aEvt( GetEvtObj(), nLngSvcFlags );
+ LaunchEvent( aEvt );
+ }
+ }
+ }
+
+ return bRes;
+}
+
+
+void SAL_CALL
+ PropertyHelper_Hyphen::propertyChange( const PropertyChangeEvent& rEvt )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ propertyChange_Impl( rEvt );
+}
+
+
+void PropertyHelper_Hyphen::SetTmpPropVals( const PropertyValues &rPropVals )
+{
+ PropertyChgHelper::SetTmpPropVals( rPropVals );
+
+ // return value is default value unless there is an explicitly supplied
+ // temporary value
+ nResHyphMinLeading = nHyphMinLeading;
+ nResHyphMinTrailing = nHyphMinTrailing;
+ nResHyphMinWordLength = nHyphMinWordLength;
+ //
+ INT32 nLen = rPropVals.getLength();
+ if (nLen)
+ {
+ const PropertyValue *pVal = rPropVals.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ INT16 *pnResVal = NULL;
+ switch (pVal[i].Handle)
+ {
+ case UPH_HYPH_MIN_LEADING : pnResVal = &nResHyphMinLeading; break;
+ case UPH_HYPH_MIN_TRAILING : pnResVal = &nResHyphMinTrailing; break;
+ case UPH_HYPH_MIN_WORD_LENGTH : pnResVal = &nResHyphMinWordLength; break;
+ default:
+ DBG_ASSERT( 0, "unknown property" );
+ }
+ if (pnResVal)
+ pVal[i].Value >>= *pnResVal;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+} // namespace linguistic
+
diff --git a/linguistic/source/lngreg.cxx b/linguistic/source/lngreg.cxx
new file mode 100644
index 000000000000..6ab3db60d268
--- /dev/null
+++ b/linguistic/source/lngreg.cxx
@@ -0,0 +1,198 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+
+#include <cppuhelper/factory.hxx> // helper for factories
+#include <rtl/string.hxx>
+
+#include <com/sun/star/registry/XRegistryKey.hpp>
+
+using namespace com::sun::star::lang;
+
+using namespace com::sun::star::registry;
+
+////////////////////////////////////////
+// declaration of external RegEntry-functions defined by the service objects
+//
+
+extern sal_Bool SAL_CALL LngSvcMgr_writeInfo
+(
+ void * /*pServiceManager*/,
+ XRegistryKey * pRegistryKey
+);
+
+extern sal_Bool SAL_CALL DicList_writeInfo
+(
+ void * /*pServiceManager*/, XRegistryKey * pRegistryKey
+);
+
+extern sal_Bool SAL_CALL LinguProps_writeInfo
+(
+ void * /*pServiceManager*/,
+ XRegistryKey * pRegistryKey
+);
+
+extern sal_Bool SAL_CALL ConvDicList_writeInfo
+(
+ void * /*pServiceManager*/, XRegistryKey * pRegistryKey
+);
+
+extern sal_Bool SAL_CALL GrammarCheckingIterator_writeInfo
+(
+ void * /*pServiceManager*/, XRegistryKey * pRegistryKey
+);
+
+//extern sal_Bool SAL_CALL GrammarChecker_writeInfo
+//(
+// void * /*pServiceManager*/, XRegistryKey * pRegistryKey
+//);
+
+extern void * SAL_CALL LngSvcMgr_getFactory
+(
+ const sal_Char * pImplName,
+ XMultiServiceFactory * pServiceManager,
+ void * /*pRegistryKey*/
+);
+
+extern void * SAL_CALL DicList_getFactory
+(
+ const sal_Char * pImplName,
+ XMultiServiceFactory * pServiceManager,
+ void *
+);
+
+void * SAL_CALL LinguProps_getFactory
+(
+ const sal_Char * pImplName,
+ XMultiServiceFactory * pServiceManager,
+ void *
+);
+
+extern void * SAL_CALL ConvDicList_getFactory
+(
+ const sal_Char * pImplName,
+ XMultiServiceFactory * pServiceManager,
+ void *
+);
+
+extern void * SAL_CALL GrammarCheckingIterator_getFactory
+(
+ const sal_Char * pImplName,
+ XMultiServiceFactory * pServiceManager,
+ void *
+);
+
+//extern void * SAL_CALL GrammarChecker_getFactory
+//(
+// const sal_Char * pImplName,
+// XMultiServiceFactory * pServiceManager,
+// void *
+//);
+
+////////////////////////////////////////
+// definition of the two functions that are used to provide the services
+//
+
+extern "C"
+{
+
+void SAL_CALL component_getImplementationEnvironment(
+ const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ )
+{
+ *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+}
+
+sal_Bool SAL_CALL component_writeInfo
+(
+ void * pServiceManager,
+ XRegistryKey * pRegistryKey
+)
+{
+ sal_Bool bRet = LngSvcMgr_writeInfo( pServiceManager, pRegistryKey );
+ if(bRet)
+ bRet = LinguProps_writeInfo( pServiceManager, pRegistryKey );
+ if(bRet)
+ bRet = DicList_writeInfo( pServiceManager, pRegistryKey );
+ if(bRet)
+ bRet = ConvDicList_writeInfo( pServiceManager, pRegistryKey );
+ if(bRet)
+ bRet = GrammarCheckingIterator_writeInfo( pServiceManager, pRegistryKey );
+/*
+ if(bRet)
+ bRet = GrammarChecker_writeInfo( pServiceManager, pRegistryKey );
+*/
+ return bRet;
+}
+
+void * SAL_CALL component_getFactory(
+ const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
+{
+ void * pRet =
+ LngSvcMgr_getFactory(
+ pImplName,
+ reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
+ pRegistryKey );
+
+ if(!pRet)
+ pRet = LinguProps_getFactory(
+ pImplName,
+ reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
+ pRegistryKey );
+
+ if(!pRet)
+ pRet = DicList_getFactory(
+ pImplName,
+ reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
+ pRegistryKey );
+
+ if(!pRet)
+ pRet = ConvDicList_getFactory(
+ pImplName,
+ reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
+ pRegistryKey );
+
+ if(!pRet)
+ pRet = GrammarCheckingIterator_getFactory(
+ pImplName,
+ reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
+ pRegistryKey );
+/*
+ if(!pRet)
+ pRet = GrammarChecker_getFactory(
+ pImplName,
+ reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
+ pRegistryKey );
+*/
+ return pRet;
+}
+}
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/lngsvcmgr.cxx b/linguistic/source/lngsvcmgr.cxx
new file mode 100644
index 000000000000..90e433f50f07
--- /dev/null
+++ b/linguistic/source/lngsvcmgr.cxx
@@ -0,0 +1,2042 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/linguistic2/XSupportedLocales.hpp>
+#include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
+#include <com/sun/star/linguistic2/LinguServiceEventFlags.hpp>
+
+#include <tools/solar.h>
+#include <unotools/lingucfg.hxx>
+#include <unotools/processfactory.hxx>
+#include <i18npool/lang.h>
+#include <i18npool/mslangid.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/extract.hxx>
+#include <rtl/logfile.hxx>
+
+#include "lngsvcmgr.hxx"
+#include "lngopt.hxx"
+#include "misc.hxx"
+#include "spelldsp.hxx"
+#include "hyphdsp.hxx"
+#include "thesdsp.hxx"
+#include "gciterator.hxx"
+
+
+using namespace com::sun::star;
+using namespace linguistic;
+using ::rtl::OUString;
+
+// forward declarations
+uno::Sequence< OUString > static GetLangSvcList( const uno::Any &rVal );
+uno::Sequence< OUString > static GetLangSvc( const uno::Any &rVal );
+
+///////////////////////////////////////////////////////////////////////////
+
+static BOOL lcl_SeqHasString( const uno::Sequence< OUString > &rSeq, const OUString &rText )
+{
+ BOOL bRes = FALSE;
+
+ INT32 nLen = rSeq.getLength();
+ if (nLen == 0 || rText.getLength() == 0)
+ return bRes;
+
+ const OUString *pSeq = rSeq.getConstArray();
+ for (INT32 i = 0; i < nLen && !bRes; ++i)
+ {
+ if (rText == pSeq[i])
+ bRes = TRUE;
+ }
+ return bRes;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static uno::Sequence< lang::Locale > GetAvailLocales(
+ const uno::Sequence< OUString > &rSvcImplNames )
+{
+ uno::Sequence< lang::Locale > aRes;
+
+ uno::Reference< lang::XMultiServiceFactory > xFac( utl::getProcessServiceFactory() );
+ INT32 nNames = rSvcImplNames.getLength();
+ if (nNames && xFac.is())
+ {
+ std::set< LanguageType > aLanguages;
+
+ //! since we're going to create one-instance services we have to
+ //! supply their arguments even if we would not need them here...
+ uno::Sequence< uno::Any > aArgs(2);
+ aArgs.getArray()[0] <<= GetLinguProperties();
+
+ // check all services for the supported languages and new
+ // languages to the result
+ const OUString *pImplNames = rSvcImplNames.getConstArray();
+ INT32 i;
+
+ for (i = 0; i < nNames; ++i)
+ {
+ uno::Reference< linguistic2::XSupportedLocales > xSuppLoc;
+ try
+ {
+ xSuppLoc = uno::Reference< linguistic2::XSupportedLocales >(
+ xFac->createInstanceWithArguments( pImplNames[i], aArgs ), uno::UNO_QUERY );
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "createInstanceWithArguments failed" );
+ }
+
+ if (xSuppLoc.is())
+ {
+ uno::Sequence< lang::Locale > aLoc( xSuppLoc->getLocales() );
+ INT32 nLoc = aLoc.getLength();
+ for (INT32 k = 0; k < nLoc; ++k)
+ {
+ const lang::Locale *pLoc = aLoc.getConstArray();
+ LanguageType nLang = LocaleToLanguage( pLoc[k] );
+
+ // language not already added?
+ if (aLanguages.find( nLang ) == aLanguages.end())
+ aLanguages.insert( nLang );
+ }
+ }
+ else
+ {
+ DBG_ASSERT( 0, "interface not supported by service" );
+ }
+ }
+
+ // build return sequence
+ INT32 nLanguages = static_cast< INT32 >(aLanguages.size());
+ aRes.realloc( nLanguages );
+ lang::Locale *pRes = aRes.getArray();
+ std::set< LanguageType >::const_iterator aIt( aLanguages.begin() );
+ for (i = 0; aIt != aLanguages.end(); ++aIt, ++i)
+ {
+ LanguageType nLang = *aIt;
+ pRes[i] = CreateLocale( nLang );
+ }
+ }
+
+ return aRes;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+struct SvcInfo
+{
+ const OUString aSvcImplName;
+ const uno::Sequence< INT16 > aSuppLanguages;
+
+ SvcInfo( const OUString &rSvcImplName,
+ const uno::Sequence< INT16 > &rSuppLanguages ) :
+ aSvcImplName (rSvcImplName),
+ aSuppLanguages (rSuppLanguages)
+ {
+ }
+
+ BOOL HasLanguage( INT16 nLanguage ) const;
+};
+
+
+BOOL SvcInfo::HasLanguage( INT16 nLanguage ) const
+{
+ INT32 nCnt = aSuppLanguages.getLength();
+ const INT16 *pLang = aSuppLanguages.getConstArray();
+ INT32 i;
+
+ for ( i = 0; i < nCnt; ++i)
+ {
+ if (nLanguage == pLang[i])
+ break;
+ }
+ return i < nCnt;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+void LngSvcMgr::SetAvailableCfgServiceLists( LinguDispatcher &rDispatcher,
+ const SvcInfoArray &rAvailSvcs )
+{
+ // get list of nodenames to look at for their service list
+ const char *pEntryName = 0;
+ BOOL bHasLangSvcList = TRUE;
+ switch (rDispatcher.GetDspType())
+ {
+ case LinguDispatcher::DSP_SPELL : pEntryName = "ServiceManager/SpellCheckerList"; break;
+ case LinguDispatcher::DSP_GRAMMAR : pEntryName = "ServiceManager/GrammarCheckerList";
+ bHasLangSvcList = FALSE;
+ break;
+ case LinguDispatcher::DSP_HYPH : pEntryName = "ServiceManager/HyphenatorList";
+ bHasLangSvcList = FALSE;
+ break;
+ case LinguDispatcher::DSP_THES : pEntryName = "ServiceManager/ThesaurusList"; break;
+ default :
+ DBG_ASSERT( 0, "unexpected case" );
+ }
+ String aNode( String::CreateFromAscii( pEntryName ) );
+ uno::Sequence < OUString > aNodeNames( /*aCfg.*/GetNodeNames( aNode ) );
+
+
+ INT32 nLen = aNodeNames.getLength();
+ const OUString *pNodeNames = aNodeNames.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ uno::Sequence< OUString > aSvcImplNames;
+
+ uno::Sequence< OUString > aNames( 1 );
+ OUString *pNames = aNames.getArray();
+
+ OUString aPropName( aNode );
+ aPropName += OUString::valueOf( (sal_Unicode) '/' );
+ aPropName += pNodeNames[i];
+ pNames[0] = aPropName;
+
+ uno::Sequence< uno::Any > aValues = /*aCfg.*/GetProperties( aNames );
+ if (aValues.getLength())
+ {
+ // get list of configured service names for the
+ // current node (language)
+ const uno::Any &rValue = aValues.getConstArray()[0];
+ if (bHasLangSvcList)
+ aSvcImplNames = GetLangSvcList( rValue );
+ else
+ aSvcImplNames = GetLangSvc( rValue );
+
+ INT32 nSvcs = aSvcImplNames.getLength();
+ if (nSvcs)
+ {
+ const OUString *pImplNames = aSvcImplNames.getConstArray();
+
+ LanguageType nLang = MsLangId::convertIsoStringToLanguage( pNodeNames[i] );
+
+ // build list of available services from those
+ INT32 nCnt = 0;
+ uno::Sequence< OUString > aAvailSvcs( nSvcs );
+ OUString *pAvailSvcs = aAvailSvcs.getArray();
+ for (INT32 k = 0; k < nSvcs; ++k)
+ {
+ // check for availability of the service
+ size_t nAvailSvcs = rAvailSvcs.size();
+ for (size_t m = 0; m < nAvailSvcs; ++m)
+ {
+ const SvcInfo &rSvcInfo = *rAvailSvcs[m];
+ if (rSvcInfo.aSvcImplName == pImplNames[k] &&
+ rSvcInfo.HasLanguage( nLang ))
+ {
+ pAvailSvcs[ nCnt++ ] = rSvcInfo.aSvcImplName;
+ break;
+ }
+ }
+ }
+
+ if (nCnt)
+ {
+ aAvailSvcs.realloc( nCnt );
+ rDispatcher.SetServiceList( CreateLocale( nLang ), aAvailSvcs );
+ }
+ }
+ }
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+class LngSvcMgrListenerHelper :
+ public cppu::WeakImplHelper2
+ <
+ linguistic2::XLinguServiceEventListener,
+ linguistic2::XDictionaryListEventListener
+ >
+{
+ LngSvcMgr &rMyManager;
+// Timer aLaunchTimer;
+
+ //cppu::OMultiTypeInterfaceContainerHelper aListeners;
+ ::cppu::OInterfaceContainerHelper aLngSvcMgrListeners;
+ ::cppu::OInterfaceContainerHelper aLngSvcEvtBroadcasters;
+ uno::Reference< linguistic2::XDictionaryList > xDicList;
+ uno::Reference< uno::XInterface > xMyEvtObj;
+
+ INT16 nCombinedLngSvcEvt;
+
+ // disallow copy-constructor and assignment-operator for now
+ LngSvcMgrListenerHelper(const LngSvcMgrListenerHelper &);
+ LngSvcMgrListenerHelper & operator = (const LngSvcMgrListenerHelper &);
+
+ void LaunchEvent( INT16 nLngSvcEvtFlags );
+
+// DECL_LINK( TimeOut, Timer* );
+ long Timeout();
+
+public:
+ LngSvcMgrListenerHelper( LngSvcMgr &rLngSvcMgr,
+ const uno::Reference< uno::XInterface > &rxSource,
+ const uno::Reference< linguistic2::XDictionaryList > &rxDicList );
+
+ // lang::XEventListener
+ virtual void SAL_CALL
+ disposing( const lang::EventObject& rSource )
+ throw(uno::RuntimeException);
+
+ // linguistic2::XLinguServiceEventListener
+ virtual void SAL_CALL
+ processLinguServiceEvent( const linguistic2::LinguServiceEvent& aLngSvcEvent )
+ throw(uno::RuntimeException);
+
+ // linguistic2::XDictionaryListEventListener
+ virtual void SAL_CALL
+ processDictionaryListEvent(
+ const linguistic2::DictionaryListEvent& rDicListEvent )
+ throw(uno::RuntimeException);
+
+ inline BOOL AddLngSvcMgrListener(
+ const uno::Reference< lang::XEventListener >& rxListener );
+ inline BOOL RemoveLngSvcMgrListener(
+ const uno::Reference< lang::XEventListener >& rxListener );
+ void DisposeAndClear( const lang::EventObject &rEvtObj );
+ BOOL AddLngSvcEvtBroadcaster(
+ const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
+ BOOL RemoveLngSvcEvtBroadcaster(
+ const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
+
+ void AddLngSvcEvt( INT16 nLngSvcEvt );
+};
+
+
+LngSvcMgrListenerHelper::LngSvcMgrListenerHelper(
+ LngSvcMgr &rLngSvcMgr,
+ const uno::Reference< uno::XInterface > &rxSource,
+ const uno::Reference< linguistic2::XDictionaryList > &rxDicList ) :
+ rMyManager ( rLngSvcMgr ),
+ aLngSvcMgrListeners ( GetLinguMutex() ),
+ aLngSvcEvtBroadcasters ( GetLinguMutex() ),
+ xDicList ( rxDicList ),
+ xMyEvtObj ( rxSource )
+{
+ if (xDicList.is())
+ {
+ xDicList->addDictionaryListEventListener(
+ (linguistic2::XDictionaryListEventListener *) this, FALSE );
+ }
+
+ //! The timer is used to 'sum up' different events in order to reduce the
+ //! number of events forwarded.
+ //! (This may happen already if a property was changed that has several
+ //! listeners, and each of them is launching an event of it's own!)
+ //! Thus this behaviour is necessary to avoid unecessary actions of
+ //! this objects listeners!
+// aLaunchTimer.SetTimeout( 2000 );
+// aLaunchTimer.SetTimeoutHdl( LINK( this, LngSvcMgrListenerHelper, TimeOut ) );
+ nCombinedLngSvcEvt = 0;
+}
+
+
+void SAL_CALL LngSvcMgrListenerHelper::disposing( const lang::EventObject& rSource )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Reference< uno::XInterface > xRef( rSource.Source );
+ if ( xRef.is() )
+ {
+ aLngSvcMgrListeners .removeInterface( xRef );
+ aLngSvcEvtBroadcasters.removeInterface( xRef );
+ if (xDicList == xRef)
+ xDicList = 0;
+ }
+}
+
+
+//IMPL_LINK( LngSvcMgrListenerHelper, TimeOut, Timer*, pTimer )
+long LngSvcMgrListenerHelper::Timeout()
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+// if (&aLaunchTimer == pTimer)
+ {
+ // change event source to LinguServiceManager since the listeners
+ // probably do not know (and need not to know) about the specific
+ // SpellChecker's or Hyphenator's.
+ linguistic2::LinguServiceEvent aEvtObj( xMyEvtObj, nCombinedLngSvcEvt );
+ nCombinedLngSvcEvt = 0;
+
+ if (rMyManager.pSpellDsp)
+ rMyManager.pSpellDsp->FlushSpellCache();
+
+ // pass event on to linguistic2::XLinguServiceEventListener's
+ cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
+ while (aIt.hasMoreElements())
+ {
+ uno::Reference< linguistic2::XLinguServiceEventListener > xRef( aIt.next(), uno::UNO_QUERY );
+ if (xRef.is())
+ xRef->processLinguServiceEvent( aEvtObj );
+ }
+ }
+ return 0;
+}
+
+
+void LngSvcMgrListenerHelper::AddLngSvcEvt( INT16 nLngSvcEvt )
+{
+ nCombinedLngSvcEvt |= nLngSvcEvt;
+// aLaunchTimer.Start();
+ Timeout();
+}
+
+
+void SAL_CALL
+ LngSvcMgrListenerHelper::processLinguServiceEvent(
+ const linguistic2::LinguServiceEvent& rLngSvcEvent )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+ AddLngSvcEvt( rLngSvcEvent.nEvent );
+}
+
+
+void SAL_CALL
+ LngSvcMgrListenerHelper::processDictionaryListEvent(
+ const linguistic2::DictionaryListEvent& rDicListEvent )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ INT16 nDlEvt = rDicListEvent.nCondensedEvent;
+ if (0 == nDlEvt)
+ return;
+
+ // we do keep the original event source here though...
+
+ // pass event on to linguistic2::XDictionaryListEventListener's
+ cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
+ while (aIt.hasMoreElements())
+ {
+ uno::Reference< linguistic2::XDictionaryListEventListener > xRef( aIt.next(), uno::UNO_QUERY );
+ if (xRef.is())
+ xRef->processDictionaryListEvent( rDicListEvent );
+ }
+
+ //
+ // "translate" DictionaryList event into linguistic2::LinguServiceEvent
+ //
+ INT16 nLngSvcEvt = 0;
+ //
+ INT16 nSpellCorrectFlags =
+ linguistic2::DictionaryListEventFlags::ADD_NEG_ENTRY |
+ linguistic2::DictionaryListEventFlags::DEL_POS_ENTRY |
+ linguistic2::DictionaryListEventFlags::ACTIVATE_NEG_DIC |
+ linguistic2::DictionaryListEventFlags::DEACTIVATE_POS_DIC;
+ if (0 != (nDlEvt & nSpellCorrectFlags))
+ nLngSvcEvt |= linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN;
+ //
+ INT16 nSpellWrongFlags =
+ linguistic2::DictionaryListEventFlags::ADD_POS_ENTRY |
+ linguistic2::DictionaryListEventFlags::DEL_NEG_ENTRY |
+ linguistic2::DictionaryListEventFlags::ACTIVATE_POS_DIC |
+ linguistic2::DictionaryListEventFlags::DEACTIVATE_NEG_DIC;
+ if (0 != (nDlEvt & nSpellWrongFlags))
+ nLngSvcEvt |= linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN;
+ //
+ INT16 nHyphenateFlags =
+ linguistic2::DictionaryListEventFlags::ADD_POS_ENTRY |
+ linguistic2::DictionaryListEventFlags::DEL_POS_ENTRY |
+ linguistic2::DictionaryListEventFlags::ACTIVATE_POS_DIC |
+ linguistic2::DictionaryListEventFlags::ACTIVATE_NEG_DIC;
+ if (0 != (nDlEvt & nHyphenateFlags))
+ nLngSvcEvt |= linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN;
+
+ if (rMyManager.pSpellDsp)
+ rMyManager.pSpellDsp->FlushSpellCache();
+ if (nLngSvcEvt)
+ LaunchEvent( nLngSvcEvt );
+}
+
+
+void LngSvcMgrListenerHelper::LaunchEvent( INT16 nLngSvcEvtFlags )
+{
+ linguistic2::LinguServiceEvent aEvt( xMyEvtObj, nLngSvcEvtFlags );
+
+ // pass event on to linguistic2::XLinguServiceEventListener's
+ cppu::OInterfaceIteratorHelper aIt( aLngSvcMgrListeners );
+ while (aIt.hasMoreElements())
+ {
+ uno::Reference< linguistic2::XLinguServiceEventListener > xRef( aIt.next(), uno::UNO_QUERY );
+ if (xRef.is())
+ xRef->processLinguServiceEvent( aEvt );
+ }
+}
+
+
+inline BOOL LngSvcMgrListenerHelper::AddLngSvcMgrListener(
+ const uno::Reference< lang::XEventListener >& rxListener )
+{
+ aLngSvcMgrListeners.addInterface( rxListener );
+ return TRUE;
+}
+
+
+inline BOOL LngSvcMgrListenerHelper::RemoveLngSvcMgrListener(
+ const uno::Reference< lang::XEventListener >& rxListener )
+{
+ aLngSvcMgrListeners.removeInterface( rxListener );
+ return TRUE;
+}
+
+
+void LngSvcMgrListenerHelper::DisposeAndClear( const lang::EventObject &rEvtObj )
+{
+ // call "disposing" for all listeners and clear list
+ aLngSvcMgrListeners .disposeAndClear( rEvtObj );
+
+ // remove references to this object hold by the broadcasters
+ cppu::OInterfaceIteratorHelper aIt( aLngSvcEvtBroadcasters );
+ while (aIt.hasMoreElements())
+ {
+ uno::Reference< linguistic2::XLinguServiceEventBroadcaster > xRef( aIt.next(), uno::UNO_QUERY );
+ if (xRef.is())
+ RemoveLngSvcEvtBroadcaster( xRef );
+ }
+
+ // remove refernce to this object hold by the dictionary-list
+ if (xDicList.is())
+ {
+ xDicList->removeDictionaryListEventListener(
+ (linguistic2::XDictionaryListEventListener *) this );
+ xDicList = 0;
+ }
+}
+
+
+BOOL LngSvcMgrListenerHelper::AddLngSvcEvtBroadcaster(
+ const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
+{
+ BOOL bRes = FALSE;
+ if (rxBroadcaster.is())
+ {
+ aLngSvcEvtBroadcasters.addInterface( rxBroadcaster );
+ rxBroadcaster->addLinguServiceEventListener(
+ (linguistic2::XLinguServiceEventListener *) this );
+ }
+ return bRes;
+}
+
+
+BOOL LngSvcMgrListenerHelper::RemoveLngSvcEvtBroadcaster(
+ const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
+{
+ BOOL bRes = FALSE;
+ if (rxBroadcaster.is())
+ {
+ aLngSvcEvtBroadcasters.removeInterface( rxBroadcaster );
+ rxBroadcaster->removeLinguServiceEventListener(
+ (linguistic2::XLinguServiceEventListener *) this );
+ }
+ return bRes;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+LngSvcMgr::LngSvcMgr() :
+ utl::ConfigItem( String::CreateFromAscii( "Office.Linguistic" ) ),
+ aEvtListeners ( GetLinguMutex() )
+{
+ bHasAvailSpellLocales =
+ bHasAvailGrammarLocales =
+ bHasAvailHyphLocales =
+ bHasAvailThesLocales =
+ bDisposing = FALSE;
+
+ pSpellDsp = 0;
+ pGrammarDsp = 0;
+ pHyphDsp = 0;
+ pThesDsp = 0;
+
+ pAvailSpellSvcs = 0;
+ pAvailGrammarSvcs = 0;
+ pAvailHyphSvcs = 0;
+ pAvailThesSvcs = 0;
+ pListenerHelper = 0;
+
+ // request notify events when properties (i.e. something in the subtree) changes
+ uno::Sequence< OUString > aNames(4);
+ OUString *pNames = aNames.getArray();
+ pNames[0] = A2OU( "ServiceManager/SpellCheckerList" );
+ pNames[1] = A2OU( "ServiceManager/GrammarCheckerList" );
+ pNames[2] = A2OU( "ServiceManager/HyphenatorList" );
+ pNames[3] = A2OU( "ServiceManager/ThesaurusList" );
+ EnableNotification( aNames );
+}
+
+
+LngSvcMgr::~LngSvcMgr()
+{
+ // memory for pSpellDsp, pHyphDsp, pThesDsp, pListenerHelper
+ // will be freed in the destructor of the respective Reference's
+ // xSpellDsp, xGrammarDsp, xHyphDsp, xThesDsp
+
+ delete pAvailSpellSvcs;
+ delete pAvailGrammarSvcs;
+ delete pAvailHyphSvcs;
+ delete pAvailThesSvcs;
+}
+
+
+void LngSvcMgr::Notify( const uno::Sequence< OUString > &rPropertyNames )
+{
+ const OUString aSpellCheckerList( A2OU("ServiceManager/SpellCheckerList") );
+ const OUString aGrammarCheckerList( A2OU("ServiceManager/GrammarCheckerList") );
+ const OUString aHyphenatorList( A2OU("ServiceManager/HyphenatorList") );
+ const OUString aThesaurusList( A2OU("ServiceManager/ThesaurusList") );
+
+ const uno::Sequence< OUString > aSpellCheckerListEntries( GetNodeNames( aSpellCheckerList ) );
+ const uno::Sequence< OUString > aGrammarCheckerListEntries( GetNodeNames( aGrammarCheckerList ) );
+ const uno::Sequence< OUString > aHyphenatorListEntries( GetNodeNames( aHyphenatorList ) );
+ const uno::Sequence< OUString > aThesaurusListEntries( GetNodeNames( aThesaurusList ) );
+
+ uno::Sequence< uno::Any > aValues;
+ uno::Sequence< OUString > aNames( 1 );
+ OUString *pNames = aNames.getArray();
+
+ sal_Int32 nLen = rPropertyNames.getLength();
+ const OUString *pPropertyNames = rPropertyNames.getConstArray();
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ // property names look like
+ // "ServiceManager/ThesaurusList/de-CH"
+
+ const OUString &rName = pPropertyNames[i];
+ sal_Int32 nKeyStart;
+ nKeyStart = rName.lastIndexOf( '/' );
+ OUString aKeyText;
+ if (nKeyStart != -1)
+ aKeyText = rName.copy( nKeyStart + 1 );
+ DBG_ASSERT( aKeyText.getLength() != 0, "unexpected key (lang::Locale) string" );
+ if (0 == rName.compareTo( aSpellCheckerList, aSpellCheckerList.getLength() ))
+ {
+ // delete old cached data, needs to be acquired new on demand
+ delete pAvailSpellSvcs; pAvailSpellSvcs = 0;
+
+ OUString aNode( aSpellCheckerList );
+ if (lcl_SeqHasString( aSpellCheckerListEntries, aKeyText ))
+ {
+ OUString aPropName( aNode );
+ aPropName += OUString::valueOf( (sal_Unicode) '/' );
+ aPropName += aKeyText;
+ pNames[0] = aPropName;
+ aValues = /*aCfg.*/GetProperties( aNames );
+ uno::Sequence< OUString > aSvcImplNames;
+ if (aValues.getLength())
+ aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
+
+ LanguageType nLang = LANGUAGE_NONE;
+ if (0 != aKeyText.getLength())
+ nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
+
+ GetSpellCheckerDsp_Impl( sal_False ); // don't set service list, it will be done below
+ pSpellDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
+ }
+ }
+ else if (0 == rName.compareTo( aGrammarCheckerList, aGrammarCheckerList.getLength() ))
+ {
+ // delete old cached data, needs to be acquired new on demand
+ delete pAvailGrammarSvcs; pAvailGrammarSvcs = 0;
+
+ OUString aNode( aGrammarCheckerList );
+ if (lcl_SeqHasString( aGrammarCheckerListEntries, aKeyText ))
+ {
+ OUString aPropName( aNode );
+ aPropName += OUString::valueOf( (sal_Unicode) '/' );
+ aPropName += aKeyText;
+ pNames[0] = aPropName;
+ aValues = /*aCfg.*/GetProperties( aNames );
+ uno::Sequence< OUString > aSvcImplNames;
+ if (aValues.getLength())
+ aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
+
+ LanguageType nLang = LANGUAGE_NONE;
+ if (0 != aKeyText.getLength())
+ nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
+
+ if (SvtLinguConfig().HasGrammarChecker())
+ {
+ GetGrammarCheckerDsp_Impl( sal_False ); // don't set service list, it will be done below
+ pGrammarDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
+ }
+ }
+ }
+ else if (0 == rName.compareTo( aHyphenatorList, aHyphenatorList.getLength() ))
+ {
+ // delete old cached data, needs to be acquired new on demand
+ delete pAvailHyphSvcs; pAvailHyphSvcs = 0;
+
+ OUString aNode( aHyphenatorList );
+ if (lcl_SeqHasString( aHyphenatorListEntries, aKeyText ))
+ {
+ OUString aPropName( aNode );
+ aPropName += OUString::valueOf( (sal_Unicode) '/' );
+ aPropName += aKeyText;
+ pNames[0] = aPropName;
+ aValues = /*aCfg.*/GetProperties( aNames );
+ uno::Sequence< OUString > aSvcImplNames;
+ if (aValues.getLength())
+ aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
+
+ LanguageType nLang = LANGUAGE_NONE;
+ if (0 != aKeyText.getLength())
+ nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
+
+ GetHyphenatorDsp_Impl( sal_False ); // don't set service list, it will be done below
+ pHyphDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
+ }
+ }
+ else if (0 == rName.compareTo( aThesaurusList, aThesaurusList.getLength() ))
+ {
+ // delete old cached data, needs to be acquired new on demand
+ delete pAvailThesSvcs; pAvailThesSvcs = 0;
+
+ OUString aNode( aThesaurusList );
+ if (lcl_SeqHasString( aThesaurusListEntries, aKeyText ))
+ {
+ OUString aPropName( aNode );
+ aPropName += OUString::valueOf( (sal_Unicode) '/' );
+ aPropName += aKeyText;
+ pNames[0] = aPropName;
+ aValues = /*aCfg.*/GetProperties( aNames );
+ uno::Sequence< OUString > aSvcImplNames;
+ if (aValues.getLength())
+ aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
+
+ LanguageType nLang = LANGUAGE_NONE;
+ if (0 != aKeyText.getLength())
+ nLang = MsLangId::convertIsoStringToLanguage( aKeyText );
+
+ GetThesaurusDsp_Impl( sal_False ); // don't set service list, it will be done below
+ pThesDsp->SetServiceList( CreateLocale(nLang), aSvcImplNames );
+ }
+ }
+ else
+ {
+ DBG_ASSERT( 0, "nofified for unexpected property" );
+ }
+ }
+}
+
+
+void LngSvcMgr::Commit()
+{
+ // everything necessary should have already been done by 'SaveCfgSvcs'
+ // called from within 'setConfiguredServices'.
+ // Also this class usually exits only when the Office i sbeing shutdown.
+}
+
+
+void LngSvcMgr::GetListenerHelper_Impl()
+{
+ if (!pListenerHelper)
+ {
+ pListenerHelper = new LngSvcMgrListenerHelper( *this,
+ (XLinguServiceManager *) this, linguistic::GetDictionaryList() );
+ xListenerHelper = (linguistic2::XLinguServiceEventListener *) pListenerHelper;
+ }
+}
+
+
+void LngSvcMgr::GetSpellCheckerDsp_Impl( sal_Bool bSetSvcList )
+{
+ if (!pSpellDsp)
+ {
+ pSpellDsp = new SpellCheckerDispatcher( *this );
+ xSpellDsp = pSpellDsp;
+ if (bSetSvcList)
+ SetCfgServiceLists( *pSpellDsp );
+ }
+}
+
+
+void LngSvcMgr::GetGrammarCheckerDsp_Impl( sal_Bool bSetSvcList )
+{
+ if (!pGrammarDsp && SvtLinguConfig().HasGrammarChecker())
+ {
+ //! since the grammar checking iterator needs to be a one instance service
+ //! we need to create it the correct way!
+ uno::Reference< linguistic2::XProofreadingIterator > xGCI;
+ try
+ {
+ uno::Reference< lang::XMultiServiceFactory > xMgr(
+ utl::getProcessServiceFactory(), uno::UNO_QUERY_THROW );
+ xGCI = uno::Reference< linguistic2::XProofreadingIterator >(
+ xMgr->createInstance( A2OU( SN_GRAMMARCHECKINGITERATOR ) ), uno::UNO_QUERY_THROW );
+ }
+ catch (uno::Exception &)
+ {
+ }
+ DBG_ASSERT( xGCI.is(), "instantiating grammar checking iterator failed" );
+
+ if (xGCI.is())
+ {
+ pGrammarDsp = dynamic_cast< GrammarCheckingIterator * >(xGCI.get());
+ xGrammarDsp = xGCI;
+ DBG_ASSERT( pGrammarDsp, "failed to get implementation" );
+ if (bSetSvcList)
+ SetCfgServiceLists( *pGrammarDsp );
+ }
+ }
+}
+
+
+void LngSvcMgr::GetHyphenatorDsp_Impl( sal_Bool bSetSvcList )
+{
+ if (!pHyphDsp)
+ {
+ pHyphDsp = new HyphenatorDispatcher( *this );
+ xHyphDsp = pHyphDsp;
+ if (bSetSvcList)
+ SetCfgServiceLists( *pHyphDsp );
+ }
+}
+
+
+void LngSvcMgr::GetThesaurusDsp_Impl( sal_Bool bSetSvcList )
+{
+ if (!pThesDsp)
+ {
+ pThesDsp = new ThesaurusDispatcher;
+ xThesDsp = pThesDsp;
+ if (bSetSvcList)
+ SetCfgServiceLists( *pThesDsp );
+ }
+}
+
+
+void LngSvcMgr::GetAvailableSpellSvcs_Impl()
+{
+ if (!pAvailSpellSvcs)
+ {
+ pAvailSpellSvcs = new SvcInfoArray;
+
+ uno::Reference< lang::XMultiServiceFactory > xFac( utl::getProcessServiceFactory() );
+ if (xFac.is())
+ {
+ uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
+ uno::Reference< container::XEnumeration > xEnum;
+ if (xEnumAccess.is())
+ xEnum = xEnumAccess->createContentEnumeration(
+ A2OU( SN_SPELLCHECKER ) );
+
+ if (xEnum.is())
+ {
+ while (xEnum->hasMoreElements())
+ {
+ uno::Any aCurrent = xEnum->nextElement();
+ uno::Reference< lang::XSingleComponentFactory > xCompFactory;
+ uno::Reference< lang::XSingleServiceFactory > xFactory;
+
+ uno::Reference< linguistic2::XSpellChecker > xSvc;
+ if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
+ {
+ try
+ {
+ uno::Reference < uno::XComponentContext > xContext;
+ uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
+
+ xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
+ xSvc = uno::Reference< linguistic2::XSpellChecker >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
+ }
+ catch (uno::Exception &rEx)
+ {
+ (void) rEx;
+ DBG_ASSERT( 0, "createInstance failed" );
+ }
+ }
+
+ if (xSvc.is())
+ {
+ OUString aImplName;
+ uno::Sequence< INT16 > aLanguages;
+ uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
+ if (xInfo.is())
+ aImplName = xInfo->getImplementationName();
+ DBG_ASSERT( aImplName.getLength(),
+ "empty implementation name" );
+ uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
+ DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
+ if (xSuppLoc.is()) {
+ uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
+ aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
+ }
+
+ pAvailSpellSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void LngSvcMgr::GetAvailableGrammarSvcs_Impl()
+{
+ if (!pAvailGrammarSvcs)
+ {
+ pAvailGrammarSvcs = new SvcInfoArray;
+
+ uno::Reference< lang::XMultiServiceFactory > xFac( utl::getProcessServiceFactory() );
+ if (xFac.is())
+ {
+ uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
+ uno::Reference< container::XEnumeration > xEnum;
+ if (xEnumAccess.is())
+ xEnum = xEnumAccess->createContentEnumeration(
+ A2OU( SN_GRAMMARCHECKER ) );
+
+ if (xEnum.is())
+ {
+ while (xEnum->hasMoreElements())
+ {
+ uno::Any aCurrent = xEnum->nextElement();
+ uno::Reference< lang::XSingleComponentFactory > xCompFactory;
+ uno::Reference< lang::XSingleServiceFactory > xFactory;
+
+ uno::Reference< linguistic2::XProofreader > xSvc;
+ if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
+ {
+ try
+ {
+ uno::Reference < uno::XComponentContext > xContext;
+ uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
+
+ xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
+ xSvc = uno::Reference< linguistic2::XProofreader >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
+ }
+ catch (uno::Exception &rEx)
+ {
+ (void) rEx;
+ DBG_ASSERT( 0, "createInstance failed" );
+ }
+ }
+
+ if (xSvc.is())
+ {
+ OUString aImplName;
+ uno::Sequence< INT16 > aLanguages;
+ uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
+ if (xInfo.is())
+ aImplName = xInfo->getImplementationName();
+ DBG_ASSERT( aImplName.getLength(),
+ "empty implementation name" );
+ uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
+ DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
+ if (xSuppLoc.is()) {
+ uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
+ aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
+ }
+
+ pAvailGrammarSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void LngSvcMgr::GetAvailableHyphSvcs_Impl()
+{
+ if (!pAvailHyphSvcs)
+ {
+ pAvailHyphSvcs = new SvcInfoArray;
+ uno::Reference< lang::XMultiServiceFactory > xFac( utl::getProcessServiceFactory() );
+ if (xFac.is())
+ {
+ uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
+ uno::Reference< container::XEnumeration > xEnum;
+ if (xEnumAccess.is())
+ xEnum = xEnumAccess->createContentEnumeration( A2OU( SN_HYPHENATOR ) );
+
+ if (xEnum.is())
+ {
+ while (xEnum->hasMoreElements())
+ {
+ uno::Any aCurrent = xEnum->nextElement();
+ uno::Reference< lang::XSingleComponentFactory > xCompFactory;
+ uno::Reference< lang::XSingleServiceFactory > xFactory;
+
+ uno::Reference< linguistic2::XHyphenator > xSvc;
+ if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
+ {
+ try
+ {
+ uno::Reference < uno::XComponentContext > xContext;
+ uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
+
+ xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
+ xSvc = uno::Reference< linguistic2::XHyphenator >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
+
+ }
+ catch (uno::Exception &rEx)
+ {
+ (void) rEx;
+ DBG_ASSERT( 0, "createInstance failed" );
+ }
+ }
+
+ if (xSvc.is())
+ {
+ OUString aImplName;
+ uno::Sequence< INT16 > aLanguages;
+ uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
+ if (xInfo.is())
+ aImplName = xInfo->getImplementationName();
+ DBG_ASSERT( aImplName.getLength(),
+ "empty implementation name" );
+ uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
+ DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
+ if (xSuppLoc.is()) {
+ uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
+ aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
+ }
+
+ pAvailHyphSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void LngSvcMgr::GetAvailableThesSvcs_Impl()
+{
+ if (!pAvailThesSvcs)
+ {
+ pAvailThesSvcs = new SvcInfoArray;
+
+ uno::Reference< lang::XMultiServiceFactory > xFac( utl::getProcessServiceFactory() );
+ if (xFac.is())
+ {
+ uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY );
+ uno::Reference< container::XEnumeration > xEnum;
+ if (xEnumAccess.is())
+ xEnum = xEnumAccess->createContentEnumeration(
+ A2OU( SN_THESAURUS ) );
+
+ if (xEnum.is())
+ {
+ while (xEnum->hasMoreElements())
+ {
+ uno::Any aCurrent = xEnum->nextElement();
+
+ uno::Reference< lang::XSingleComponentFactory > xCompFactory;
+ uno::Reference< lang::XSingleServiceFactory > xFactory;
+
+ uno::Reference< linguistic2::XThesaurus > xSvc;
+ if ( cppu::extractInterface( xCompFactory, aCurrent ) || ::cppu::extractInterface( xFactory, aCurrent ) )
+ {
+ try
+ {
+ uno::Reference < uno::XComponentContext > xContext;
+ uno::Reference< beans::XPropertySet > xProps( xFac, uno::UNO_QUERY );
+
+ xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext;
+ xSvc = uno::Reference< linguistic2::XThesaurus >( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY );
+ }
+ catch (uno::Exception &rEx)
+ {
+ (void) rEx;
+ DBG_ASSERT( 0, "createInstance failed" );
+ }
+ }
+
+ if (xSvc.is())
+ {
+ OUString aImplName;
+ uno::Sequence< INT16 > aLanguages;
+ uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY );
+ if (xInfo.is())
+ aImplName = xInfo->getImplementationName();
+ DBG_ASSERT( aImplName.getLength(),
+ "empty implementation name" );
+ uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY );
+ DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" );
+ if (xSuppLoc.is()) {
+ uno::Sequence<lang::Locale> aLocaleSequence(xSuppLoc->getLocales());
+ aLanguages = LocaleSeqToLangSeq( aLocaleSequence );
+ }
+
+ pAvailThesSvcs->push_back( new SvcInfo( aImplName, aLanguages ) );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void LngSvcMgr::SetCfgServiceLists( SpellCheckerDispatcher &rSpellDsp )
+{
+ RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Spell" );
+
+ String aNode( String::CreateFromAscii( "ServiceManager/SpellCheckerList" ) );
+ uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
+ OUString *pNames = aNames.getArray();
+ INT32 nLen = aNames.getLength();
+
+ // append path prefix need for 'GetProperties' call below
+ String aPrefix( aNode );
+ aPrefix.Append( (sal_Unicode) '/' );
+ for (int i = 0; i < nLen; ++i)
+ {
+ OUString aTmp( aPrefix );
+ aTmp += pNames[i];
+ pNames[i] = aTmp;
+ }
+
+ uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
+ if (nLen && nLen == aValues.getLength())
+ {
+ const uno::Any *pValues = aValues.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ uno::Sequence< OUString > aSvcImplNames;
+ if (pValues[i] >>= aSvcImplNames)
+ {
+#if OSL_DEBUG_LEVEL > 1
+// INT32 nSvcs = aSvcImplNames.getLength();
+// const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
+#endif
+ String aLocaleStr( pNames[i] );
+ xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
+ aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
+ lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
+ rSpellDsp.SetServiceList( aLocale, aSvcImplNames );
+ }
+ }
+ }
+}
+
+
+void LngSvcMgr::SetCfgServiceLists( GrammarCheckingIterator &rGrammarDsp )
+{
+ RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Grammar" );
+
+ String aNode( String::CreateFromAscii( "ServiceManager/GrammarCheckerList" ) );
+ uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
+ OUString *pNames = aNames.getArray();
+ INT32 nLen = aNames.getLength();
+
+ // append path prefix need for 'GetProperties' call below
+ String aPrefix( aNode );
+ aPrefix.Append( (sal_Unicode) '/' );
+ for (int i = 0; i < nLen; ++i)
+ {
+ OUString aTmp( aPrefix );
+ aTmp += pNames[i];
+ pNames[i] = aTmp;
+ }
+
+ uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
+ if (nLen && nLen == aValues.getLength())
+ {
+ const uno::Any *pValues = aValues.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ uno::Sequence< OUString > aSvcImplNames;
+ if (pValues[i] >>= aSvcImplNames)
+ {
+ // there should only be one grammar checker in use per language...
+ if (aSvcImplNames.getLength() > 1)
+ aSvcImplNames.realloc(1);
+
+#if OSL_DEBUG_LEVEL > 1
+// INT32 nSvcs = aSvcImplNames.getLength();
+// const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
+#endif
+ String aLocaleStr( pNames[i] );
+ xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
+ aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
+ lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
+ rGrammarDsp.SetServiceList( aLocale, aSvcImplNames );
+ }
+ }
+ }
+}
+
+
+void LngSvcMgr::SetCfgServiceLists( HyphenatorDispatcher &rHyphDsp )
+{
+ RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Hyph" );
+
+ String aNode( String::CreateFromAscii( "ServiceManager/HyphenatorList" ) );
+ uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
+ OUString *pNames = aNames.getArray();
+ INT32 nLen = aNames.getLength();
+
+ // append path prefix need for 'GetProperties' call below
+ String aPrefix( aNode );
+ aPrefix.Append( (sal_Unicode) '/' );
+ for (int i = 0; i < nLen; ++i)
+ {
+ OUString aTmp( aPrefix );
+ aTmp += pNames[i];
+ pNames[i] = aTmp;
+ }
+
+ uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
+ if (nLen && nLen == aValues.getLength())
+ {
+ const uno::Any *pValues = aValues.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ uno::Sequence< OUString > aSvcImplNames;
+ if (pValues[i] >>= aSvcImplNames)
+ {
+ // there should only be one hyphenator in use per language...
+ if (aSvcImplNames.getLength() > 1)
+ aSvcImplNames.realloc(1);
+
+#if OSL_DEBUG_LEVEL > 1
+// INT32 nSvcs = aSvcImplNames.getLength();
+// const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
+#endif
+ String aLocaleStr( pNames[i] );
+ xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
+ aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
+ lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
+ rHyphDsp.SetServiceList( aLocale, aSvcImplNames );
+ }
+ }
+ }
+}
+
+
+void LngSvcMgr::SetCfgServiceLists( ThesaurusDispatcher &rThesDsp )
+{
+ RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SetCfgServiceLists - Thes" );
+
+ String aNode( String::CreateFromAscii( "ServiceManager/ThesaurusList" ) );
+ uno::Sequence< OUString > aNames( /*aCfg.*/GetNodeNames( aNode ) );
+ OUString *pNames = aNames.getArray();
+ INT32 nLen = aNames.getLength();
+
+ // append path prefix need for 'GetProperties' call below
+ String aPrefix( aNode );
+ aPrefix.Append( (sal_Unicode) '/' );
+ for (int i = 0; i < nLen; ++i)
+ {
+ OUString aTmp( aPrefix );
+ aTmp += pNames[i];
+ pNames[i] = aTmp;
+ }
+
+ uno::Sequence< uno::Any > aValues( /*aCfg.*/GetProperties( aNames ) );
+ if (nLen && nLen == aValues.getLength())
+ {
+ const uno::Any *pValues = aValues.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ uno::Sequence< OUString > aSvcImplNames;
+ if (pValues[i] >>= aSvcImplNames)
+ {
+#if OSL_DEBUG_LEVEL > 1
+// INT32 nSvcs = aSvcImplNames.getLength();
+// const OUString *pSvcImplNames = aSvcImplNames.getConstArray();
+#endif
+ String aLocaleStr( pNames[i] );
+ xub_StrLen nSeperatorPos = aLocaleStr.SearchBackward( sal_Unicode( '/' ) );
+ aLocaleStr = aLocaleStr.Copy( nSeperatorPos + 1 );
+ lang::Locale aLocale( CreateLocale( MsLangId::convertIsoStringToLanguage(aLocaleStr) ) );
+ rThesDsp.SetServiceList( aLocale, aSvcImplNames );
+ }
+ }
+ }
+}
+
+
+uno::Reference< linguistic2::XSpellChecker > SAL_CALL
+ LngSvcMgr::getSpellChecker()
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+#if OSL_DEBUG_LEVEL > 1
+ getAvailableLocales( A2OU( SN_SPELLCHECKER ));
+#endif
+
+ uno::Reference< linguistic2::XSpellChecker > xRes;
+ if (!bDisposing)
+ {
+ if (!xSpellDsp.is())
+ GetSpellCheckerDsp_Impl();
+ xRes = xSpellDsp;
+ }
+ return xRes;
+}
+
+
+uno::Reference< linguistic2::XHyphenator > SAL_CALL
+ LngSvcMgr::getHyphenator()
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+#if OSL_DEBUG_LEVEL > 1
+ getAvailableLocales( A2OU( SN_HYPHENATOR ));
+#endif
+
+ uno::Reference< linguistic2::XHyphenator > xRes;
+ if (!bDisposing)
+ {
+ if (!xHyphDsp.is())
+ GetHyphenatorDsp_Impl();
+ xRes = xHyphDsp;
+ }
+ return xRes;
+}
+
+
+uno::Reference< linguistic2::XThesaurus > SAL_CALL
+ LngSvcMgr::getThesaurus()
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+#if OSL_DEBUG_LEVEL > 1
+ getAvailableLocales( A2OU( SN_THESAURUS ));
+#endif
+
+ uno::Reference< linguistic2::XThesaurus > xRes;
+ if (!bDisposing)
+ {
+ if (!xThesDsp.is())
+ GetThesaurusDsp_Impl();
+ xRes = xThesDsp;
+ }
+ return xRes;
+}
+
+
+sal_Bool SAL_CALL
+ LngSvcMgr::addLinguServiceManagerListener(
+ const uno::Reference< lang::XEventListener >& xListener )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = FALSE;
+ if (!bDisposing && xListener.is())
+ {
+ if (!pListenerHelper)
+ GetListenerHelper_Impl();
+ bRes = pListenerHelper->AddLngSvcMgrListener( xListener );
+ }
+ return bRes;
+}
+
+
+sal_Bool SAL_CALL
+ LngSvcMgr::removeLinguServiceManagerListener(
+ const uno::Reference< lang::XEventListener >& xListener )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = FALSE;
+ if (!bDisposing && xListener.is())
+ {
+ DBG_ASSERT( pListenerHelper, "listener removed without being added" );
+ if (!pListenerHelper)
+ GetListenerHelper_Impl();
+ bRes = pListenerHelper->RemoveLngSvcMgrListener( xListener );
+ }
+ return bRes;
+}
+
+
+uno::Sequence< OUString > SAL_CALL
+ LngSvcMgr::getAvailableServices(
+ const OUString& rServiceName,
+ const lang::Locale& rLocale )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Sequence< OUString > aRes;
+ const SvcInfoArray *pInfoArray = 0;
+
+ if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
+ {
+ // don't used cached data here (force re-evaluation in order to have downloaded dictionaries
+ // already found without the need to restart the office
+ delete pAvailSpellSvcs; pAvailSpellSvcs = 0;
+ GetAvailableSpellSvcs_Impl();
+ pInfoArray = pAvailSpellSvcs;
+ }
+ else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
+ {
+ // don't used cached data here (force re-evaluation in order to have downloaded dictionaries
+ // already found without the need to restart the office
+ delete pAvailGrammarSvcs; pAvailGrammarSvcs = 0;
+ GetAvailableGrammarSvcs_Impl();
+ pInfoArray = pAvailGrammarSvcs;
+ }
+ else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
+ {
+ // don't used cached data here (force re-evaluation in order to have downloaded dictionaries
+ // already found without the need to restart the office
+ delete pAvailHyphSvcs; pAvailHyphSvcs = 0;
+ GetAvailableHyphSvcs_Impl();
+ pInfoArray = pAvailHyphSvcs;
+ }
+ else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
+ {
+ // don't used cached data here (force re-evaluation in order to have downloaded dictionaries
+ // already found without the need to restart the office
+ delete pAvailThesSvcs; pAvailThesSvcs = 0;
+ GetAvailableThesSvcs_Impl();
+ pInfoArray = pAvailThesSvcs;
+ }
+
+ if (pInfoArray)
+ {
+ // resize to max number of entries
+ size_t nMaxCnt = pInfoArray->size();
+ aRes.realloc( nMaxCnt );
+ OUString *pImplName = aRes.getArray();
+
+ USHORT nCnt = 0;
+ LanguageType nLanguage = LocaleToLanguage( rLocale );
+ for (size_t i = 0; i < nMaxCnt; ++i)
+ {
+ const SvcInfo *pInfo = (*pInfoArray)[i];
+ if (LANGUAGE_NONE == nLanguage
+ || (pInfo && pInfo->HasLanguage( nLanguage )))
+ {
+ pImplName[ nCnt++ ] = pInfo->aSvcImplName;
+ }
+ }
+
+ // resize to actual number of entries
+ if (nCnt != nMaxCnt)
+ aRes.realloc( nCnt );
+ }
+
+ return aRes;
+}
+
+
+uno::Sequence< lang::Locale > SAL_CALL
+ LngSvcMgr::getAvailableLocales(
+ const OUString& rServiceName )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Sequence< lang::Locale > aRes;
+
+ uno::Sequence< lang::Locale > *pAvailLocales = NULL;
+ BOOL *pHasAvailLocales = NULL;
+ if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
+ {
+ pAvailLocales = &aAvailSpellLocales;
+ pHasAvailLocales = &bHasAvailSpellLocales;
+ }
+ else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
+ {
+ pAvailLocales = &aAvailGrammarLocales;
+ pHasAvailLocales = &bHasAvailGrammarLocales;
+ }
+ else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
+ {
+ pAvailLocales = &aAvailHyphLocales;
+ pHasAvailLocales = &bHasAvailHyphLocales;
+ }
+ else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
+ {
+ pAvailLocales = &aAvailThesLocales;
+ pHasAvailLocales = &bHasAvailThesLocales;
+ }
+
+ // about pHasAvailLocales: nowadays (with OOo lingu in SO) we want to know immediately about
+ // new downloaded dictionaries and have them ready right away if the Tools/Options...
+ // is used to activate them. Thus we can not rely anymore on buffered data.
+ if (pAvailLocales /*&& pHasAvailLocales */)
+ {
+// if (!*pHasAvailLocales)
+// {
+ *pAvailLocales = GetAvailLocales(
+ getAvailableServices( rServiceName, lang::Locale() ) );
+// *pHasAvailLocales = TRUE;
+// }
+ aRes = *pAvailLocales;
+ }
+
+ return aRes;
+}
+
+static BOOL IsEqSvcList( const uno::Sequence< OUString > &rList1,
+ const uno::Sequence< OUString > &rList2 )
+{
+ // returns TRUE iff both sequences are equal
+
+ BOOL bRes = FALSE;
+ INT32 nLen = rList1.getLength();
+ if (rList2.getLength() == nLen)
+ {
+ const OUString *pStr1 = rList1.getConstArray();
+ const OUString *pStr2 = rList2.getConstArray();
+ bRes = TRUE;
+ for (INT32 i = 0; i < nLen && bRes; ++i)
+ {
+ if (*pStr1++ != *pStr2++)
+ bRes = FALSE;
+ }
+ }
+ return bRes;
+}
+
+
+void SAL_CALL
+ LngSvcMgr::setConfiguredServices(
+ const OUString& rServiceName,
+ const lang::Locale& rLocale,
+ const uno::Sequence< OUString >& rServiceImplNames )
+ throw(uno::RuntimeException)
+{
+ RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::setConfiguredServices" );
+
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+#if OSL_DEBUG_LEVEL > 1
+// const OUString *pImplNames = rServiceImplNames.getConstArray();
+#endif
+
+ LanguageType nLanguage = LocaleToLanguage( rLocale );
+ if (LANGUAGE_NONE != nLanguage)
+ {
+ if (0 == rServiceName.compareToAscii( SN_SPELLCHECKER ))
+ {
+ if (!xSpellDsp.is())
+ GetSpellCheckerDsp_Impl();
+ BOOL bChanged = !IsEqSvcList( rServiceImplNames,
+ pSpellDsp->GetServiceList( rLocale ) );
+ if (bChanged)
+ {
+ pSpellDsp->SetServiceList( rLocale, rServiceImplNames );
+ SaveCfgSvcs( A2OU( SN_SPELLCHECKER ) );
+
+ if (pListenerHelper && bChanged)
+ pListenerHelper->AddLngSvcEvt(
+ linguistic2::LinguServiceEventFlags::SPELL_CORRECT_WORDS_AGAIN |
+ linguistic2::LinguServiceEventFlags::SPELL_WRONG_WORDS_AGAIN );
+ }
+ }
+ else if (0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ))
+ {
+ if (!xGrammarDsp.is())
+ GetGrammarCheckerDsp_Impl();
+ BOOL bChanged = !IsEqSvcList( rServiceImplNames,
+ pGrammarDsp->GetServiceList( rLocale ) );
+ if (bChanged)
+ {
+ pGrammarDsp->SetServiceList( rLocale, rServiceImplNames );
+ SaveCfgSvcs( A2OU( SN_GRAMMARCHECKER ) );
+
+ if (pListenerHelper && bChanged)
+ pListenerHelper->AddLngSvcEvt(
+ linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN );
+ }
+ }
+ else if (0 == rServiceName.compareToAscii( SN_HYPHENATOR ))
+ {
+ if (!xHyphDsp.is())
+ GetHyphenatorDsp_Impl();
+ BOOL bChanged = !IsEqSvcList( rServiceImplNames,
+ pHyphDsp->GetServiceList( rLocale ) );
+ if (bChanged)
+ {
+ pHyphDsp->SetServiceList( rLocale, rServiceImplNames );
+ SaveCfgSvcs( A2OU( SN_HYPHENATOR ) );
+
+ if (pListenerHelper && bChanged)
+ pListenerHelper->AddLngSvcEvt(
+ linguistic2::LinguServiceEventFlags::HYPHENATE_AGAIN );
+ }
+ }
+ else if (0 == rServiceName.compareToAscii( SN_THESAURUS ))
+ {
+ if (!xThesDsp.is())
+ GetThesaurusDsp_Impl();
+ BOOL bChanged = !IsEqSvcList( rServiceImplNames,
+ pThesDsp->GetServiceList( rLocale ) );
+ if (bChanged)
+ {
+ pThesDsp->SetServiceList( rLocale, rServiceImplNames );
+ SaveCfgSvcs( A2OU( SN_THESAURUS ) );
+ }
+ }
+ }
+}
+
+
+BOOL LngSvcMgr::SaveCfgSvcs( const String &rServiceName )
+{
+ RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SaveCfgSvcs" );
+
+ BOOL bRes = FALSE;
+
+ LinguDispatcher *pDsp = 0;
+ uno::Sequence< lang::Locale > aLocales;
+
+ if (0 == rServiceName.CompareToAscii( SN_SPELLCHECKER ))
+ {
+ if (!pSpellDsp)
+ GetSpellCheckerDsp_Impl();
+ pDsp = pSpellDsp;
+ aLocales = getAvailableLocales( A2OU( SN_SPELLCHECKER ) );
+ }
+ else if (0 == rServiceName.CompareToAscii( SN_GRAMMARCHECKER ))
+ {
+ if (!pGrammarDsp)
+ GetGrammarCheckerDsp_Impl();
+ pDsp = pGrammarDsp;
+ aLocales = getAvailableLocales( A2OU( SN_GRAMMARCHECKER ) );
+ }
+ else if (0 == rServiceName.CompareToAscii( SN_HYPHENATOR ))
+ {
+ if (!pHyphDsp)
+ GetHyphenatorDsp_Impl();
+ pDsp = pHyphDsp;
+ aLocales = getAvailableLocales( A2OU( SN_HYPHENATOR ) );
+ }
+ else if (0 == rServiceName.CompareToAscii( SN_THESAURUS ))
+ {
+ if (!pThesDsp)
+ GetThesaurusDsp_Impl();
+ pDsp = pThesDsp;
+ aLocales = getAvailableLocales( A2OU( SN_THESAURUS ) );
+ }
+
+ if (pDsp && aLocales.getLength())
+ {
+ INT32 nLen = aLocales.getLength();
+ const lang::Locale *pLocale = aLocales.getConstArray();
+
+ uno::Sequence< beans::PropertyValue > aValues( nLen );
+ beans::PropertyValue *pValues = aValues.getArray();
+ beans::PropertyValue *pValue = pValues;
+
+ // get node name to be used
+ const char *pNodeName = NULL;
+ if (pDsp == pSpellDsp)
+ pNodeName = "ServiceManager/SpellCheckerList";
+ else if (pDsp == pGrammarDsp)
+ pNodeName = "ServiceManager/GrammarCheckerList";
+ else if (pDsp == pHyphDsp)
+ pNodeName = "ServiceManager/HyphenatorList";
+ else if (pDsp == pThesDsp)
+ pNodeName = "ServiceManager/ThesaurusList";
+ else
+ {
+ DBG_ASSERT( 0, "node name missing" );
+ }
+ OUString aNodeName( A2OU(pNodeName) );
+
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ uno::Sequence< OUString > aSvcImplNames;
+ aSvcImplNames = pDsp->GetServiceList( pLocale[i] );
+
+#if OSL_DEBUG_LEVEL > 1
+ INT32 nSvcs = aSvcImplNames.getLength();
+ const OUString *pSvcImplName = aSvcImplNames.getConstArray();
+ for (INT32 j = 0; j < nSvcs; ++j)
+ {
+ OUString aImplName( pSvcImplName[j] );
+ }
+#endif
+ // build value to be written back to configuration
+ uno::Any aCfgAny;
+ if ((pDsp == pHyphDsp || pDsp == pGrammarDsp) && aSvcImplNames.getLength() > 1)
+ aSvcImplNames.realloc(1); // there should be only one entry for hyphenators or grammar checkers (because they are not chained)
+ aCfgAny <<= aSvcImplNames;
+ DBG_ASSERT( aCfgAny.hasValue(), "missing value for 'Any' type" );
+
+ OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString(
+ LocaleToLanguage( pLocale[i] ) ) );
+ pValue->Value = aCfgAny;
+ pValue->Name = aNodeName;
+ pValue->Name += OUString::valueOf( (sal_Unicode) '/' );
+ pValue->Name += aCfgLocaleStr;
+ pValue++;
+ }
+ {
+ RTL_LOGFILE_CONTEXT( aLog, "linguistic: LngSvcMgr::SaveCfgSvcs - ReplaceSetProperties" );
+ // change, add new or replace existing entries.
+ bRes |= /*aCfg.*/ReplaceSetProperties( aNodeName, aValues );
+ }
+ }
+
+ return bRes;
+}
+
+
+static uno::Sequence< OUString > GetLangSvcList( const uno::Any &rVal )
+{
+ uno::Sequence< OUString > aRes;
+
+ if (rVal.hasValue())
+ {
+ rVal >>= aRes;
+#if OSL_DEBUG_LEVEL > 1
+ INT32 nSvcs = aRes.getLength();
+ if (nSvcs)
+ {
+ const OUString *pSvcName = aRes.getConstArray();
+ for (INT32 j = 0; j < nSvcs; ++j)
+ {
+ OUString aImplName( pSvcName[j] );
+ DBG_ASSERT( aImplName.getLength(), "service impl-name missing" );
+ }
+ }
+#endif
+ }
+
+ return aRes;
+}
+
+
+static uno::Sequence< OUString > GetLangSvc( const uno::Any &rVal )
+{
+ uno::Sequence< OUString > aRes;
+ if (!rVal.hasValue())
+ return aRes;
+
+ // allowing for a sequence here as well (even though it should only
+ // be a string) makes coding easier in other places since one needs
+ // not make a special case for writing a string only and not a
+ // sequence of strings.
+ if (rVal >>= aRes)
+ {
+ // but only the first string should be used.
+ if (aRes.getLength() > 1)
+ aRes.realloc(1);
+ }
+ else
+ {
+ OUString aImplName;
+ if ((rVal >>= aImplName) && aImplName.getLength() != 0)
+ {
+ aRes.realloc(1);
+ aRes.getArray()[0] = aImplName;
+ }
+ else
+ {
+ DBG_ASSERT( 0, "GetLangSvc: unexpected type encountered" );
+ }
+ }
+
+ return aRes;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+uno::Sequence< OUString > SAL_CALL
+ LngSvcMgr::getConfiguredServices(
+ const OUString& rServiceName,
+ const lang::Locale& rLocale )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Sequence< OUString > aSvcImplNames;
+
+ LanguageType nLanguage = LocaleToLanguage( rLocale );
+ OUString aCfgLocale( MsLangId::convertLanguageToIsoString( nLanguage ) );
+
+ uno::Sequence< uno::Any > aValues;
+ uno::Sequence< OUString > aNames( 1 );
+ OUString *pNames = aNames.getArray();
+ if ( 0 == rServiceName.compareToAscii( SN_SPELLCHECKER ) )
+ {
+ OUString aNode( OUString::createFromAscii( "ServiceManager/SpellCheckerList" ));
+ const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
+ if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
+ {
+ OUString aPropName( aNode );
+ aPropName += OUString::valueOf( (sal_Unicode) '/' );
+ aPropName += aCfgLocale;
+ pNames[0] = aPropName;
+ aValues = /*aCfg.*/GetProperties( aNames );
+ if (aValues.getLength())
+ aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
+ }
+ }
+ else if ( 0 == rServiceName.compareToAscii( SN_GRAMMARCHECKER ) )
+ {
+ OUString aNode( OUString::createFromAscii( "ServiceManager/GrammarCheckerList" ));
+ const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
+ if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
+ {
+ OUString aPropName( aNode );
+ aPropName += OUString::valueOf( (sal_Unicode) '/' );
+ aPropName += aCfgLocale;
+ pNames[0] = aPropName;
+ aValues = /*aCfg.*/GetProperties( aNames );
+ if (aValues.getLength())
+ aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
+ }
+ }
+ else if ( 0 == rServiceName.compareToAscii( SN_HYPHENATOR ) )
+ {
+ OUString aNode( OUString::createFromAscii( "ServiceManager/HyphenatorList" ));
+ const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
+ if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
+ {
+ OUString aPropName( aNode );
+ aPropName += OUString::valueOf( (sal_Unicode) '/' );
+ aPropName += aCfgLocale;
+ pNames[0] = aPropName;
+ aValues = /*aCfg.*/GetProperties( aNames );
+ if (aValues.getLength())
+ aSvcImplNames = GetLangSvc( aValues.getConstArray()[0] );
+ }
+ }
+ else if ( 0 == rServiceName.compareToAscii( SN_THESAURUS ) )
+ {
+ OUString aNode( OUString::createFromAscii( "ServiceManager/ThesaurusList" ));
+ const uno::Sequence< OUString > aNodeEntries( GetNodeNames( aNode ) );
+ if (lcl_SeqHasString( aNodeEntries, aCfgLocale ))
+ {
+ OUString aPropName( aNode );
+ aPropName += OUString::valueOf( (sal_Unicode) '/' );
+ aPropName += aCfgLocale;
+ pNames[0] = aPropName;
+ aValues = /*aCfg.*/GetProperties( aNames );
+ if (aValues.getLength())
+ aSvcImplNames = GetLangSvcList( aValues.getConstArray()[0] );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ const OUString *pImplNames = aSvcImplNames.getConstArray();
+ (void) pImplNames;
+#endif
+ return aSvcImplNames;
+}
+
+
+void SAL_CALL
+ LngSvcMgr::dispose()
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bDisposing)
+ {
+ bDisposing = TRUE;
+
+ // require listeners to release this object
+ lang::EventObject aEvtObj( (XLinguServiceManager *) this );
+ aEvtListeners.disposeAndClear( aEvtObj );
+
+ if (pListenerHelper)
+ pListenerHelper->DisposeAndClear( aEvtObj );
+ }
+}
+
+
+void SAL_CALL
+ LngSvcMgr::addEventListener(
+ const uno::Reference< lang::XEventListener >& xListener )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ if (!bDisposing && xListener.is())
+ {
+ aEvtListeners.addInterface( xListener );
+ }
+}
+
+
+void SAL_CALL
+ LngSvcMgr::removeEventListener(
+ const uno::Reference< lang::XEventListener >& xListener )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ if (xListener.is())
+ {
+ aEvtListeners.removeInterface( xListener );
+ }
+}
+
+
+BOOL LngSvcMgr::AddLngSvcEvtBroadcaster(
+ const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
+{
+ BOOL bRes = FALSE;
+ if (rxBroadcaster.is())
+ {
+ if (!pListenerHelper)
+ GetListenerHelper_Impl();
+ bRes = pListenerHelper->AddLngSvcEvtBroadcaster( rxBroadcaster );
+ }
+ return bRes;
+}
+
+
+BOOL LngSvcMgr::RemoveLngSvcEvtBroadcaster(
+ const uno::Reference< linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster )
+{
+ BOOL bRes = FALSE;
+ if (rxBroadcaster.is())
+ {
+ DBG_ASSERT( pListenerHelper, "pListenerHelper non existent" );
+ if (!pListenerHelper)
+ GetListenerHelper_Impl();
+ bRes = pListenerHelper->RemoveLngSvcEvtBroadcaster( rxBroadcaster );
+ }
+ return bRes;
+}
+
+
+OUString SAL_CALL
+ LngSvcMgr::getImplementationName()
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+ return getImplementationName_Static();
+}
+
+
+sal_Bool SAL_CALL
+ LngSvcMgr::supportsService( const OUString& ServiceName )
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Sequence< OUString > aSNL = getSupportedServiceNames();
+ const OUString * pArray = aSNL.getConstArray();
+ for( INT32 i = 0; i < aSNL.getLength(); i++ )
+ if( pArray[i] == ServiceName )
+ return TRUE;
+ return FALSE;
+}
+
+
+uno::Sequence< OUString > SAL_CALL
+ LngSvcMgr::getSupportedServiceNames()
+ throw(uno::RuntimeException)
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+ return getSupportedServiceNames_Static();
+}
+
+
+uno::Sequence< OUString > LngSvcMgr::getSupportedServiceNames_Static()
+ throw()
+{
+ osl::MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Sequence< OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich
+ aSNS.getArray()[0] = A2OU( SN_LINGU_SERVCICE_MANAGER );
+ return aSNS;
+}
+
+
+uno::Reference< uno::XInterface > SAL_CALL LngSvcMgr_CreateInstance(
+ const uno::Reference< lang::XMultiServiceFactory > & /*rSMgr*/ )
+ throw(uno::Exception)
+{
+ uno::Reference< uno::XInterface > xService = (cppu::OWeakObject*) new LngSvcMgr;
+ return xService;
+}
+
+
+
+sal_Bool SAL_CALL LngSvcMgr_writeInfo(
+ void * /*pServiceManager*/,
+ registry::XRegistryKey * pRegistryKey )
+{
+ try
+ {
+ String aImpl( '/' );
+ aImpl += LngSvcMgr::getImplementationName_Static().getStr();
+ aImpl.AppendAscii( "/UNO/SERVICES" );
+ uno::Reference< registry::XRegistryKey > xNewKey =
+ pRegistryKey->createKey( aImpl );
+ uno::Sequence< OUString > aServices = LngSvcMgr::getSupportedServiceNames_Static();
+ for( INT32 i = 0; i < aServices.getLength(); i++ )
+ xNewKey->createKey( aServices.getConstArray()[i] );
+
+ return sal_True;
+ }
+ catch(uno::Exception &)
+ {
+ return sal_False;
+ }
+}
+
+void * SAL_CALL LngSvcMgr_getFactory(
+ const sal_Char * pImplName,
+ lang::XMultiServiceFactory * pServiceManager,
+ void * /*pRegistryKey*/ )
+{
+
+ void * pRet = 0;
+ if ( !LngSvcMgr::getImplementationName_Static().compareToAscii( pImplName ) )
+ {
+ uno::Reference< lang::XSingleServiceFactory > xFactory =
+ cppu::createOneInstanceFactory(
+ pServiceManager,
+ LngSvcMgr::getImplementationName_Static(),
+ LngSvcMgr_CreateInstance,
+ LngSvcMgr::getSupportedServiceNames_Static());
+ // acquire, because we return an interface pointer instead of a reference
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+ return pRet;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/lngsvcmgr.hxx b/linguistic/source/lngsvcmgr.hxx
new file mode 100644
index 000000000000..953e531960bf
--- /dev/null
+++ b/linguistic/source/lngsvcmgr.hxx
@@ -0,0 +1,199 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_LNGSVCMGR_HXX_
+#define _LINGUISTIC_LNGSVCMGR_HXX_
+
+#include <uno/lbnames.h> // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
+#include <cppuhelper/implbase4.hxx> // helper for implementations
+#include <cppuhelper/interfacecontainer.h> //OMultiTypeInterfaceContainerHelper
+
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/linguistic2/XLinguServiceManager.hpp>
+#include <com/sun/star/linguistic2/XAvailableLocales.hpp>
+#include <unotools/configitem.hxx>
+
+//#include <vcl/timer.hxx>
+
+#include "misc.hxx"
+#include "defs.hxx"
+
+class SpellCheckerDispatcher;
+class HyphenatorDispatcher;
+class ThesaurusDispatcher;
+class GrammarCheckingIterator;
+class LngSvcMgrListenerHelper;
+struct SvcInfo;
+
+namespace com { namespace sun { namespace star { namespace linguistic2 {
+ class XLinguServiceEventBroadcaster;
+ class XSpellChecker;
+ class XProofreader;
+ class XProofreadingIterator;
+ class XHyphenator;
+ class XThesaurus;
+} } } }
+
+///////////////////////////////////////////////////////////////////////////
+
+
+class LngSvcMgr :
+ public cppu::WeakImplHelper4
+ <
+ com::sun::star::linguistic2::XLinguServiceManager,
+ com::sun::star::linguistic2::XAvailableLocales,
+ com::sun::star::lang::XComponent,
+ com::sun::star::lang::XServiceInfo
+ >,
+ private utl::ConfigItem
+{
+ friend class LngSvcMgrListenerHelper;
+
+ ::cppu::OInterfaceContainerHelper aEvtListeners;
+
+ com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XSpellChecker > xSpellDsp;
+ com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XProofreadingIterator > xGrammarDsp;
+ com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XHyphenator > xHyphDsp;
+ com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XThesaurus > xThesDsp;
+
+ com::sun::star::uno::Reference<
+ ::com::sun::star::lang::XEventListener > xListenerHelper;
+
+ com::sun::star::uno::Sequence<
+ com::sun::star::lang::Locale > aAvailSpellLocales;
+ com::sun::star::uno::Sequence<
+ com::sun::star::lang::Locale > aAvailGrammarLocales;
+ com::sun::star::uno::Sequence<
+ com::sun::star::lang::Locale > aAvailHyphLocales;
+ com::sun::star::uno::Sequence<
+ com::sun::star::lang::Locale > aAvailThesLocales;
+
+ SpellCheckerDispatcher * pSpellDsp;
+ GrammarCheckingIterator * pGrammarDsp;
+ HyphenatorDispatcher * pHyphDsp;
+ ThesaurusDispatcher * pThesDsp;
+
+ LngSvcMgrListenerHelper * pListenerHelper;
+
+ typedef std::vector< SvcInfo * > SvcInfoArray;
+ SvcInfoArray * pAvailSpellSvcs;
+ SvcInfoArray * pAvailGrammarSvcs;
+ SvcInfoArray * pAvailHyphSvcs;
+ SvcInfoArray * pAvailThesSvcs;
+
+ BOOL bDisposing;
+ BOOL bHasAvailSpellLocales;
+ BOOL bHasAvailGrammarLocales;
+ BOOL bHasAvailHyphLocales;
+ BOOL bHasAvailThesLocales;
+
+ // disallow copy-constructor and assignment-operator for now
+ LngSvcMgr(const LngSvcMgr &);
+ LngSvcMgr & operator = (const LngSvcMgr &);
+
+ void GetAvailableSpellSvcs_Impl();
+ void GetAvailableGrammarSvcs_Impl();
+ void GetAvailableHyphSvcs_Impl();
+ void GetAvailableThesSvcs_Impl();
+ void GetListenerHelper_Impl();
+
+ void GetSpellCheckerDsp_Impl( sal_Bool bSetSvcList = sal_True );
+ void GetGrammarCheckerDsp_Impl( sal_Bool bSetSvcList = sal_True );
+ void GetHyphenatorDsp_Impl( sal_Bool bSetSvcList = sal_True );
+ void GetThesaurusDsp_Impl( sal_Bool bSetSvcList = sal_True );
+
+ void SetCfgServiceLists( SpellCheckerDispatcher &rSpellDsp );
+ void SetCfgServiceLists( GrammarCheckingIterator &rGrammarDsp );
+ void SetCfgServiceLists( HyphenatorDispatcher &rHyphDsp );
+ void SetCfgServiceLists( ThesaurusDispatcher &rThesDsp );
+
+ BOOL SaveCfgSvcs( const String &rServiceName );
+
+ void SetAvailableCfgServiceLists( LinguDispatcher &rDispatcher,
+ const SvcInfoArray &rAvailSvcs );
+
+ // utl::ConfigItem (to allow for listening of changes of relevant properties)
+ virtual void Notify( const com::sun::star::uno::Sequence< rtl::OUString > &rPropertyNames );
+ virtual void Commit();
+
+public:
+ LngSvcMgr();
+ virtual ~LngSvcMgr();
+
+ // XLinguServiceManager
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XSpellChecker > SAL_CALL getSpellChecker( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XHyphenator > SAL_CALL getHyphenator( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XThesaurus > SAL_CALL getThesaurus( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL addLinguServiceManagerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL removeLinguServiceManagerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getAvailableServices( const ::rtl::OUString& aServiceName, const ::com::sun::star::lang::Locale& aLocale ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setConfiguredServices( const ::rtl::OUString& aServiceName, const ::com::sun::star::lang::Locale& aLocale, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aServiceImplNames ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getConfiguredServices( const ::rtl::OUString& aServiceName, const ::com::sun::star::lang::Locale& aLocale ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XAvailableLocales
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > SAL_CALL getAvailableLocales( const ::rtl::OUString& aServiceName ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException);
+
+
+ static inline ::rtl::OUString getImplementationName_Static();
+ static ::com::sun::star::uno::Sequence< ::rtl::OUString > getSupportedServiceNames_Static() throw();
+
+ BOOL AddLngSvcEvtBroadcaster(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
+ BOOL RemoveLngSvcEvtBroadcaster(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XLinguServiceEventBroadcaster > &rxBroadcaster );
+};
+
+
+inline ::rtl::OUString LngSvcMgr::getImplementationName_Static()
+{
+ return A2OU( "com.sun.star.lingu2.LngSvcMgr" );
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/makefile.mk b/linguistic/source/makefile.mk
new file mode 100644
index 000000000000..3f68afb30575
--- /dev/null
+++ b/linguistic/source/makefile.mk
@@ -0,0 +1,111 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..
+
+PRJNAME=linguistic
+TARGET=lng
+ENABLE_EXCEPTIONS=TRUE
+
+#----- Settings ---------------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES = \
+ $(SLO)$/convdiclist.obj\
+ $(SLO)$/convdic.obj\
+ $(SLO)$/convdicxml.obj\
+ $(SLO)$/dicimp.obj\
+ $(SLO)$/dlistimp.obj\
+ $(SLO)$/hhconvdic.obj\
+ $(SLO)$/hyphdsp.obj\
+ $(SLO)$/hyphdta.obj\
+ $(SLO)$/iprcache.obj\
+ $(SLO)$/lngopt.obj\
+ $(SLO)$/lngprophelp.obj\
+ $(SLO)$/lngreg.obj\
+ $(SLO)$/lngsvcmgr.obj\
+ $(SLO)$/misc.obj\
+ $(SLO)$/misc2.obj\
+ $(SLO)$/spelldsp.obj\
+ $(SLO)$/spelldta.obj\
+ $(SLO)$/thesdsp.obj\
+ $(SLO)$/thesdta.obj\
+ $(SLO)$/gciterator.obj
+
+SHL1TARGET= $(TARGET)$(DLLPOSTFIX)
+
+SHL1STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(COMPHELPERLIB) \
+ $(VOSLIB) \
+ $(TOOLSLIB) \
+ $(I18NISOLANGLIB) \
+ $(SVLLIB) \
+ $(SALLIB) \
+ $(XMLOFFLIB) \
+ $(UCBHELPERLIB) \
+ $(UNOTOOLSLIB) \
+ $(ICUUCLIB)
+
+# build DLL
+SHL1LIBS= $(SLB)$/$(TARGET).lib
+SHL1DEPN= $(SLB)$/$(TARGET).lib
+SHL1DEF= $(MISC)$/$(SHL1TARGET).def
+#SHL1VERSIONMAP= $(TARGET).map
+SHL1IMPLIB= ilng
+
+# build DEF file
+DEF1NAME =$(SHL1TARGET)
+DEF1DEPN =$(MISC)$/$(SHL1TARGET).flt
+DEFLIB1NAME =$(TARGET)
+DEF1DES =Linguistic main DLL
+#DEF1EXPORTFILE= exports.dxp
+
+
+.IF "$(GUI)"=="WNT"
+DEF1EXPORT1 = component_writeInfo
+DEF1EXPORT2 = component_getFactory
+DEF1EXPORT3 = component_getImplementationEnvironment
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+
+.INCLUDE : target.mk
+
+
+$(MISC)$/$(SHL1TARGET).flt: makefile.mk
+ @echo ------------------------------
+ @echo Making: $@
+ @echo lcl > $@
+ @echo component >> $@
+ @echo __CT >> $@
+
diff --git a/linguistic/source/misc.cxx b/linguistic/source/misc.cxx
new file mode 100644
index 000000000000..7fb35b26a908
--- /dev/null
+++ b/linguistic/source/misc.cxx
@@ -0,0 +1,1009 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+#include <tools/string.hxx>
+#include <tools/fsys.hxx>
+#include <tools/debug.hxx>
+#include <unotools/pathoptions.hxx>
+#include <svl/lngmisc.hxx>
+#include <ucbhelper/content.hxx>
+#include <i18npool/mslangid.hxx>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/frame/XDesktop.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/linguistic2/DictionaryType.hpp>
+#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
+#include <unotools/processfactory.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/syslocale.hxx>
+
+#include <rtl/instance.hxx>
+
+#include "misc.hxx"
+#include "defs.hxx"
+#include "lngprops.hxx"
+#include "hyphdta.hxx"
+#include <i18npool/mslangid.hxx>
+
+using namespace utl;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::i18n;
+using namespace com::sun::star::linguistic2;
+
+namespace linguistic
+{
+
+///////////////////////////////////////////////////////////////////////////
+
+//!! multi-thread safe mutex for all platforms !!
+struct LinguMutex : public rtl::Static< osl::Mutex, LinguMutex >
+{
+};
+
+osl::Mutex & GetLinguMutex()
+{
+ return LinguMutex::get();
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+LocaleDataWrapper & GetLocaleDataWrapper( INT16 nLang )
+{
+ static LocaleDataWrapper aLclDtaWrp(
+ getProcessServiceFactory(),
+ CreateLocale( SvtSysLocale().GetUILanguage() ) );
+
+ const Locale &rLcl = aLclDtaWrp.getLoadedLocale();
+ Locale aLcl( CreateLocale( nLang ) );
+ if (aLcl.Language != rLcl.Language ||
+ aLcl.Country != rLcl.Country ||
+ aLcl.Variant != rLcl.Variant)
+ aLclDtaWrp.setLocale( aLcl );
+ return aLclDtaWrp;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ returns text-encoding used for ByteString unicode String conversion
+ */
+rtl_TextEncoding GetTextEncoding( INT16 nLanguage )
+{
+ DBG_ASSERT( nLanguage != LANGUAGE_NONE, "invalid language argument" );
+ static INT16 nLastLanguage = LANGUAGE_NONE;
+
+ // set default value for unknown languages
+ static rtl_TextEncoding nEncoding = RTL_TEXTENCODING_DONTKNOW;
+
+ if (nLastLanguage != nLanguage)
+ {
+ //!! IPR uses textencodings Latin-1, Latin-2, Latin-5 and Latin-7 !!
+
+ nLastLanguage = nLanguage;
+ switch (nLanguage)
+ {
+ case LANGUAGE_GERMAN :
+ case LANGUAGE_GERMAN_SWISS :
+ case LANGUAGE_ENGLISH_US :
+ case LANGUAGE_ENGLISH_UK :
+ case LANGUAGE_FRENCH :
+ case LANGUAGE_ITALIAN :
+ case LANGUAGE_SPANISH :
+ case LANGUAGE_CATALAN :
+ case LANGUAGE_PORTUGUESE :
+ case LANGUAGE_PORTUGUESE_BRAZILIAN :
+ case LANGUAGE_DANISH :
+ case LANGUAGE_DUTCH :
+ case LANGUAGE_SWEDISH :
+ case LANGUAGE_FINNISH :
+ case LANGUAGE_NORWEGIAN_BOKMAL :
+ case LANGUAGE_NORWEGIAN_NYNORSK :
+ case LANGUAGE_AFRIKAANS :
+ case LANGUAGE_ENGLISH_EIRE :
+ case LANGUAGE_ENGLISH_AUS :
+#ifdef WNT
+ nEncoding = RTL_TEXTENCODING_MS_1252; break;
+#else
+ nEncoding = RTL_TEXTENCODING_ISO_8859_1; break;
+#endif
+ case LANGUAGE_CZECH :
+ case LANGUAGE_HUNGARIAN :
+ case LANGUAGE_POLISH :
+#ifdef WNT
+ nEncoding = RTL_TEXTENCODING_MS_1250; break;
+#else
+ nEncoding = RTL_TEXTENCODING_ISO_8859_2; break;
+#endif
+ case LANGUAGE_RUSSIAN :
+#ifdef WNT
+ nEncoding = RTL_TEXTENCODING_MS_1251; break;
+#else
+ nEncoding = RTL_TEXTENCODING_ISO_8859_5; break;
+#endif
+ case LANGUAGE_GREEK :
+#ifdef WNT
+ nEncoding = RTL_TEXTENCODING_MS_1253; break;
+#else
+ nEncoding = RTL_TEXTENCODING_ISO_8859_7; break;
+#endif
+ default:
+ DBG_ASSERT( 0, "unexpected language" );
+ }
+ }
+
+ return nEncoding;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static inline sal_Int32 Minimum( sal_Int32 n1, sal_Int32 n2, sal_Int32 n3 )
+{
+ sal_Int32 nMin = n1 < n2 ? n1 : n2;
+ return nMin < n3 ? nMin : n3;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+class IntArray2D
+{
+private:
+ sal_Int32 *pData;
+ int n1, n2;
+
+public:
+ IntArray2D( int nDim1, int nDim2 );
+ ~IntArray2D();
+
+ sal_Int32 & Value( int i, int k );
+};
+
+IntArray2D::IntArray2D( int nDim1, int nDim2 )
+{
+ n1 = nDim1;
+ n2 = nDim2;
+ pData = new sal_Int32[n1 * n2];
+}
+
+IntArray2D::~IntArray2D()
+{
+ delete[] pData;
+}
+
+sal_Int32 & IntArray2D::Value( int i, int k )
+{
+ DBG_ASSERT( 0 <= i && i < n1, "first index out of range" );
+ DBG_ASSERT( 0 <= k && k < n2, "first index out of range" );
+ DBG_ASSERT( i * n2 + k < n1 * n2, "index out of range" );
+ return pData[ i * n2 + k ];
+}
+
+
+sal_Int32 LevDistance( const OUString &rTxt1, const OUString &rTxt2 )
+{
+ sal_Int32 nLen1 = rTxt1.getLength();
+ sal_Int32 nLen2 = rTxt2.getLength();
+
+ if (nLen1 == 0)
+ return nLen2;
+ if (nLen2 == 0)
+ return nLen1;
+
+ IntArray2D aData( nLen1 + 1, nLen2 + 1 );
+
+ sal_Int32 i, k;
+ for (i = 0; i <= nLen1; ++i)
+ aData.Value(i, 0) = i;
+ for (k = 0; k <= nLen2; ++k)
+ aData.Value(0, k) = k;
+ for (i = 1; i <= nLen1; ++i)
+ {
+ for (k = 1; k <= nLen2; ++k)
+ {
+ sal_Unicode c1i = rTxt1.getStr()[i - 1];
+ sal_Unicode c2k = rTxt2.getStr()[k - 1];
+ sal_Int32 nCost = c1i == c2k ? 0 : 1;
+ sal_Int32 nNew = Minimum( aData.Value(i-1, k ) + 1,
+ aData.Value(i , k-1) + 1,
+ aData.Value(i-1, k-1) + nCost );
+ // take transposition (exchange with left or right char) in account
+ if (2 < i && 2 < k)
+ {
+ int nT = aData.Value(i-2, k-2) + 1;
+ if (rTxt1.getStr()[i - 2] != c1i)
+ ++nT;
+ if (rTxt2.getStr()[k - 2] != c2k)
+ ++nT;
+ if (nT < nNew)
+ nNew = nT;
+ }
+
+ aData.Value(i, k) = nNew;
+ }
+ }
+ sal_Int32 nDist = aData.Value(nLen1, nLen2);
+ return nDist;
+ }
+
+///////////////////////////////////////////////////////////////////////////
+
+BOOL IsUseDicList( const PropertyValues &rProperties,
+ const uno::Reference< XPropertySet > &rxProp )
+{
+ BOOL bRes = TRUE;
+
+ INT32 nLen = rProperties.getLength();
+ const PropertyValue *pVal = rProperties.getConstArray();
+ INT32 i;
+
+ for ( i = 0; i < nLen; ++i)
+ {
+ if (UPH_IS_USE_DICTIONARY_LIST == pVal[i].Handle)
+ {
+ pVal[i].Value >>= bRes;
+ break;
+ }
+ }
+ if (i >= nLen) // no temporary value found in 'rProperties'
+ {
+ uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
+ if (xFast.is())
+ xFast->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST ) >>= bRes;
+ }
+
+ return bRes;
+}
+
+
+BOOL IsIgnoreControlChars( const PropertyValues &rProperties,
+ const uno::Reference< XPropertySet > &rxProp )
+{
+ BOOL bRes = TRUE;
+
+ INT32 nLen = rProperties.getLength();
+ const PropertyValue *pVal = rProperties.getConstArray();
+ INT32 i;
+
+ for ( i = 0; i < nLen; ++i)
+ {
+ if (UPH_IS_IGNORE_CONTROL_CHARACTERS == pVal[i].Handle)
+ {
+ pVal[i].Value >>= bRes;
+ break;
+ }
+ }
+ if (i >= nLen) // no temporary value found in 'rProperties'
+ {
+ uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
+ if (xFast.is())
+ xFast->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS ) >>= bRes;
+ }
+
+ return bRes;
+}
+
+
+static BOOL lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry )
+{
+ BOOL bRes = FALSE;
+ if (xEntry.is())
+ {
+ // there has to be (at least one) '=' denoting a hyphenation position
+ // and it must not be before any character of the word
+ sal_Int32 nIdx = xEntry->getDictionaryWord().indexOf( '=' );
+ bRes = nIdx != -1 && nIdx != 0;
+ }
+ return bRes;
+}
+
+
+uno::Reference< XDictionaryEntry > SearchDicList(
+ const uno::Reference< XDictionaryList > &xDicList,
+ const OUString &rWord, INT16 nLanguage,
+ BOOL bSearchPosDics, BOOL bSearchSpellEntry )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ uno::Reference< XDictionaryEntry > xEntry;
+
+ if (!xDicList.is())
+ return xEntry;
+
+ const uno::Sequence< uno::Reference< XDictionary > >
+ aDics( xDicList->getDictionaries() );
+ const uno::Reference< XDictionary >
+ *pDic = aDics.getConstArray();
+ INT32 nDics = xDicList->getCount();
+
+ INT32 i;
+ for (i = 0; i < nDics; i++)
+ {
+ uno::Reference< XDictionary > axDic( pDic[i], UNO_QUERY );
+
+ DictionaryType eType = axDic->getDictionaryType();
+ INT16 nLang = LocaleToLanguage( axDic->getLocale() );
+
+ if ( axDic.is() && axDic->isActive()
+ && (nLang == nLanguage || nLang == LANGUAGE_NONE) )
+ {
+ DBG_ASSERT( eType != DictionaryType_MIXED,
+ "lng : unexpected dictionary type" );
+
+ if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE)
+ || ( bSearchPosDics && eType == DictionaryType_POSITIVE))
+ {
+ if ( (xEntry = axDic->getEntry( rWord )).is() )
+ {
+ if (bSearchSpellEntry || lcl_HasHyphInfo( xEntry ))
+ break;
+ }
+ xEntry = 0;
+ }
+ }
+ }
+
+ return xEntry;
+}
+
+
+sal_Bool SaveDictionaries( const uno::Reference< XDictionaryList > &xDicList )
+{
+ if (!xDicList.is())
+ return sal_True;
+
+ sal_Bool bRet = sal_True;
+
+ Sequence< uno::Reference< XDictionary > > aDics( xDicList->getDictionaries() );
+ const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
+ INT32 nCount = aDics.getLength();
+ for (INT32 i = 0; i < nCount; i++)
+ {
+ try
+ {
+ uno::Reference< frame::XStorable > xStor( pDic[i], UNO_QUERY );
+ if (xStor.is())
+ {
+ if (!xStor->isReadonly() && xStor->hasLocation())
+ xStor->store();
+ }
+ }
+ catch(uno::Exception &)
+ {
+ bRet = sal_False;
+ }
+ }
+
+ return bRet;
+}
+
+
+sal_uInt8 AddEntryToDic(
+ uno::Reference< XDictionary > &rxDic,
+ const OUString &rWord, sal_Bool bIsNeg,
+ const OUString &rRplcTxt, sal_Int16 /* nRplcLang */,
+ sal_Bool bStripDot )
+{
+ if (!rxDic.is())
+ return DIC_ERR_NOT_EXISTS;
+
+ OUString aTmp( rWord );
+ if (bStripDot)
+ {
+ sal_Int32 nLen = rWord.getLength();
+ if (nLen > 0 && '.' == rWord[ nLen - 1])
+ {
+ // remove trailing '.'
+ // (this is the official way to do this :-( )
+ aTmp = aTmp.copy( 0, nLen - 1 );
+ }
+ }
+ sal_Bool bAddOk = rxDic->add( aTmp, bIsNeg, rRplcTxt );
+
+ sal_uInt8 nRes = DIC_ERR_NONE;
+ if (!bAddOk)
+ {
+ if (rxDic->isFull())
+ nRes = DIC_ERR_FULL;
+ else
+ {
+ uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
+ if (xStor.is() && xStor->isReadonly())
+ nRes = DIC_ERR_READONLY;
+ else
+ nRes = DIC_ERR_UNKNOWN;
+ }
+ }
+
+ return nRes;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+LanguageType LocaleToLanguage( const Locale& rLocale )
+{
+ // empty Locale -> LANGUAGE_NONE
+ if ( rLocale.Language.getLength() == 0 )
+ return LANGUAGE_NONE;
+
+ return MsLangId::convertLocaleToLanguage( rLocale );
+}
+
+
+Locale& LanguageToLocale( Locale& rLocale, LanguageType eLang )
+{
+ if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */)
+ MsLangId::convertLanguageToLocale( eLang, rLocale );
+
+ return rLocale;
+}
+
+Locale CreateLocale( LanguageType eLang )
+{
+ Locale aLocale;
+ if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */)
+ return MsLangId::convertLanguageToLocale( eLang );
+
+ return aLocale;
+}
+
+uno::Sequence< Locale > LangSeqToLocaleSeq( const uno::Sequence< INT16 > &rLangSeq )
+{
+ const INT16 *pLang = rLangSeq.getConstArray();
+ INT32 nCount = rLangSeq.getLength();
+
+ uno::Sequence< Locale > aLocales( nCount );
+ Locale *pLocale = aLocales.getArray();
+ for (INT32 i = 0; i < nCount; ++i)
+ {
+ LanguageToLocale( pLocale[i], pLang[ i ] );
+ }
+
+ return aLocales;
+}
+
+uno::Sequence< INT16 >
+ LocaleSeqToLangSeq( uno::Sequence< Locale > &rLocaleSeq )
+{
+ const Locale *pLocale = rLocaleSeq.getConstArray();
+ INT32 nCount = rLocaleSeq.getLength();
+
+ uno::Sequence< INT16 > aLangs( nCount );
+ INT16 *pLang = aLangs.getArray();
+ for (INT32 i = 0; i < nCount; ++i)
+ {
+ pLang[i] = LocaleToLanguage( pLocale[i] );
+ }
+
+ return aLangs;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+BOOL IsReadOnly( const String &rURL, BOOL *pbExist )
+{
+ BOOL bRes = FALSE;
+ BOOL bExists = FALSE;
+
+ if (rURL.Len() > 0)
+ {
+ try
+ {
+ uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xCmdEnv;
+ ::ucbhelper::Content aContent( rURL, xCmdEnv );
+
+ bExists = aContent.isDocument();
+ if (bExists)
+ {
+ Any aAny( aContent.getPropertyValue( A2OU( "IsReadOnly" ) ) );
+ aAny >>= bRes;
+ }
+ }
+ catch (Exception &)
+ {
+ bRes = TRUE;
+ }
+ }
+
+ if (pbExist)
+ *pbExist = bExists;
+ return bRes;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+
+static BOOL GetAltSpelling( INT16 &rnChgPos, INT16 &rnChgLen, OUString &rRplc,
+ uno::Reference< XHyphenatedWord > &rxHyphWord )
+{
+ BOOL bRes = rxHyphWord->isAlternativeSpelling();
+ if (bRes)
+ {
+ OUString aWord( rxHyphWord->getWord() ),
+ aHyphenatedWord( rxHyphWord->getHyphenatedWord() );
+ INT16 nHyphenationPos = rxHyphWord->getHyphenationPos();
+ /*INT16 nHyphenPos = rxHyphWord->getHyphenPos()*/;
+ const sal_Unicode *pWord = aWord.getStr(),
+ *pAltWord = aHyphenatedWord.getStr();
+
+ // at least char changes directly left or right to the hyphen
+ // should(!) be handled properly...
+ //! nHyphenationPos and nHyphenPos differ at most by 1 (see above)
+ //! Beware: eg "Schiffahrt" in German (pre spelling reform)
+ //! proves to be a bit nasty (nChgPosLeft and nChgPosRight overlap
+ //! to an extend.)
+
+ // find first different char from left
+ sal_Int32 nPosL = 0,
+ nAltPosL = 0;
+ for (INT16 i = 0 ; pWord[ nPosL ] == pAltWord[ nAltPosL ]; nPosL++, nAltPosL++, i++)
+ {
+ // restrict changes area beginning to the right to
+ // the char immediately following the hyphen.
+ //! serves to insert the additional "f" in "Schiffahrt" at
+ //! position 5 rather than position 6.
+ if (i >= nHyphenationPos + 1)
+ break;
+ }
+
+ // find first different char from right
+ sal_Int32 nPosR = aWord.getLength() - 1,
+ nAltPosR = aHyphenatedWord.getLength() - 1;
+ for ( ; nPosR >= nPosL && nAltPosR >= nAltPosL
+ && pWord[ nPosR ] == pAltWord[ nAltPosR ];
+ nPosR--, nAltPosR--)
+ ;
+
+ rnChgPos = sal::static_int_cast< INT16 >(nPosL);
+ rnChgLen = sal::static_int_cast< INT16 >(nPosR - nPosL + 1);
+ DBG_ASSERT( rnChgLen >= 0, "nChgLen < 0");
+
+ sal_Int32 nTxtStart = nPosL;
+ sal_Int32 nTxtLen = nAltPosL - nPosL + 1;
+ rRplc = aHyphenatedWord.copy( nTxtStart, nTxtLen );
+ }
+ return bRes;
+}
+
+
+static INT16 GetOrigWordPos( const OUString &rOrigWord, INT16 nPos )
+{
+ INT32 nLen = rOrigWord.getLength();
+ INT32 i = -1;
+ while (nPos >= 0 && i++ < nLen)
+ {
+ sal_Unicode cChar = rOrigWord[i];
+ BOOL bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
+ if (!bSkip)
+ --nPos;
+ }
+ return sal::static_int_cast< INT16 >((0 <= i && i < nLen) ? i : -1);
+}
+
+
+INT32 GetPosInWordToCheck( const OUString &rTxt, INT32 nPos )
+{
+ INT32 nRes = -1;
+ INT32 nLen = rTxt.getLength();
+ if (0 <= nPos && nPos < nLen)
+ {
+ nRes = 0;
+ for (INT32 i = 0; i < nPos; ++i)
+ {
+ sal_Unicode cChar = rTxt[i];
+ BOOL bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
+ if (!bSkip)
+ ++nRes;
+ }
+ }
+ return nRes;
+}
+
+
+uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars(
+ const OUString &rOrigWord,
+ uno::Reference< XHyphenatedWord > &rxHyphWord )
+{
+ uno::Reference< XHyphenatedWord > xRes;
+ if (rOrigWord.getLength() && rxHyphWord.is())
+ {
+ INT16 nChgPos = 0,
+ nChgLen = 0;
+ OUString aRplc;
+ BOOL bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord );
+#if OSL_DEBUG_LEVEL > 1
+ OUString aWord( rxHyphWord->getWord() );
+#endif
+
+ OUString aOrigHyphenatedWord;
+ INT16 nOrigHyphenPos = -1;
+ INT16 nOrigHyphenationPos = -1;
+ if (!bAltSpelling)
+ {
+ aOrigHyphenatedWord = rOrigWord;
+ nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() );
+ nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() );
+ }
+ else
+ {
+ //! should at least work with the German words
+ //! B�-c-k-er and Sc-hif-fah-rt
+
+ OUString aLeft, aRight;
+ INT16 nPos = GetOrigWordPos( rOrigWord, nChgPos );
+
+ // get words like Sc-hif-fah-rt to work correct
+ INT16 nHyphenationPos = rxHyphWord->getHyphenationPos();
+ if (nChgPos > nHyphenationPos)
+ --nPos;
+
+ aLeft = rOrigWord.copy( 0, nPos );
+ aRight = rOrigWord.copy( nPos + nChgLen );
+
+ aOrigHyphenatedWord = aLeft;
+ aOrigHyphenatedWord += aRplc;
+ aOrigHyphenatedWord += aRight;
+
+ nOrigHyphenPos = sal::static_int_cast< INT16 >(aLeft.getLength() +
+ rxHyphWord->getHyphenPos() - nChgPos);
+ nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos );
+ }
+
+ if (nOrigHyphenPos == -1 || nOrigHyphenationPos == -1)
+ {
+ DBG_ASSERT( 0, "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
+ }
+ else
+ {
+ INT16 nLang = LocaleToLanguage( rxHyphWord->getLocale() );
+ xRes = new HyphenatedWord(
+ rOrigWord, nLang, nOrigHyphenationPos,
+ aOrigHyphenatedWord, nOrigHyphenPos );
+ }
+
+ }
+ return xRes;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+
+static CharClass & lcl_GetCharClass()
+{
+ static CharClass aCC( CreateLocale( LANGUAGE_ENGLISH_US ) );
+ return aCC;
+}
+
+
+osl::Mutex & lcl_GetCharClassMutex()
+{
+ static osl::Mutex aMutex;
+ return aMutex;
+}
+
+
+BOOL IsUpper( const String &rText, xub_StrLen nPos, xub_StrLen nLen, INT16 nLanguage )
+{
+ MutexGuard aGuard( lcl_GetCharClassMutex() );
+
+ CharClass &rCC = lcl_GetCharClass();
+ rCC.setLocale( CreateLocale( nLanguage ) );
+ sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen );
+ return (nFlags & KCharacterType::UPPER)
+ && !(nFlags & KCharacterType::LOWER);
+}
+
+
+BOOL IsLower( const String &rText, xub_StrLen nPos, xub_StrLen nLen, INT16 nLanguage )
+{
+ MutexGuard aGuard( lcl_GetCharClassMutex() );
+
+ CharClass &rCC = lcl_GetCharClass();
+ rCC.setLocale( CreateLocale( nLanguage ) );
+ sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen );
+ return (nFlags & KCharacterType::LOWER)
+ && !(nFlags & KCharacterType::UPPER);
+}
+
+
+String ToLower( const String &rText, INT16 nLanguage )
+{
+ MutexGuard aGuard( lcl_GetCharClassMutex() );
+
+ CharClass &rCC = lcl_GetCharClass();
+ rCC.setLocale( CreateLocale( nLanguage ) );
+ return rCC.lower( rText );
+}
+
+
+String ToUpper( const String &rText, INT16 nLanguage )
+{
+ MutexGuard aGuard( lcl_GetCharClassMutex() );
+
+ CharClass &rCC = lcl_GetCharClass();
+ rCC.setLocale( CreateLocale( nLanguage ) );
+ return rCC.upper( rText );
+}
+
+
+String ToTitle( const String &rText, INT16 nLanguage )
+{
+ MutexGuard aGuard( lcl_GetCharClassMutex() );
+
+ CharClass &rCC = lcl_GetCharClass();
+ rCC.setLocale( CreateLocale( nLanguage ) );
+ return rCC.toTitle( rText, 0, rText.Len() );
+}
+
+
+sal_Unicode ToLower( const sal_Unicode cChar, INT16 nLanguage )
+{
+ MutexGuard aGuard( lcl_GetCharClassMutex() );
+
+ CharClass &rCC = lcl_GetCharClass();
+ rCC.setLocale( CreateLocale( nLanguage ) );
+ return rCC.lower( cChar ).GetChar(0);
+}
+
+
+sal_Unicode ToUpper( const sal_Unicode cChar, INT16 nLanguage )
+{
+ MutexGuard aGuard( lcl_GetCharClassMutex() );
+
+ CharClass &rCC = lcl_GetCharClass();
+ rCC.setLocale( CreateLocale( nLanguage ) );
+ return rCC.upper( cChar ).GetChar(0);
+}
+
+// sorted(!) array of unicode ranges for code points that are exclusively(!) used as numbers
+// and thus may NOT not be part of names or words like the Chinese/Japanese number characters
+static const sal_uInt32 the_aDigitZeroes [] =
+{
+ 0x00000030, //0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE
+ 0x00000660, //0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+ 0x000006F0, //06F9 ; Decimal # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+ 0x000007C0, //07C9 ; Decimal # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
+ 0x00000966, //096F ; Decimal # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+ 0x000009E6, //09EF ; Decimal # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+ 0x00000A66, //0A6F ; Decimal # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+ 0x00000AE6, //0AEF ; Decimal # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+ 0x00000B66, //0B6F ; Decimal # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+ 0x00000BE6, //0BEF ; Decimal # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+ 0x00000C66, //0C6F ; Decimal # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+ 0x00000CE6, //0CEF ; Decimal # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+ 0x00000D66, //0D6F ; Decimal # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+ 0x00000E50, //0E59 ; Decimal # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
+ 0x00000ED0, //0ED9 ; Decimal # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
+ 0x00000F20, //0F29 ; Decimal # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+ 0x00001040, //1049 ; Decimal # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+ 0x00001090, //1099 ; Decimal # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+ 0x000017E0, //17E9 ; Decimal # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+ 0x00001810, //1819 ; Decimal # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+ 0x00001946, //194F ; Decimal # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+ 0x000019D0, //19D9 ; Decimal # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+ 0x00001B50, //1B59 ; Decimal # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+ 0x00001BB0, //1BB9 ; Decimal # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+ 0x00001C40, //1C49 ; Decimal # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+ 0x00001C50, //1C59 ; Decimal # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+ 0x0000A620, //A629 ; Decimal # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
+ 0x0000A8D0, //A8D9 ; Decimal # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+ 0x0000A900, //A909 ; Decimal # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+ 0x0000AA50, //AA59 ; Decimal # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+ 0x0000FF10, //FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+ 0x000104A0, //104A9 ; Decimal # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+ 0x0001D7CE //1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+};
+
+BOOL HasDigits( const OUString &rText )
+{
+ static const int nNumDigitZeroes = sizeof(the_aDigitZeroes) / sizeof(the_aDigitZeroes[0]);
+ const sal_Int32 nLen = rText.getLength();
+
+ sal_Int32 i = 0;
+ while (i < nLen) // for all characters ...
+ {
+ const sal_uInt32 nCodePoint = rText.iterateCodePoints( &i ); // handle unicode surrogates correctly...
+ for (int j = 0; j < nNumDigitZeroes; ++j) // ... check in all 0..9 ranges
+ {
+ sal_uInt32 nDigitZero = the_aDigitZeroes[ j ];
+ if (nDigitZero > nCodePoint)
+ break;
+ if (/*nDigitZero <= nCodePoint &&*/ nCodePoint <= nDigitZero + 9)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+BOOL IsNumeric( const String &rText )
+{
+ BOOL bRes = FALSE;
+ xub_StrLen nLen = rText.Len();
+ if (nLen)
+ {
+ bRes = TRUE;
+ xub_StrLen i = 0;
+ while (i < nLen)
+ {
+ sal_Unicode cChar = rText.GetChar( i++ );
+ if ( !((sal_Unicode)'0' <= cChar && cChar <= (sal_Unicode)'9') )
+ {
+ bRes = FALSE;
+ break;
+ }
+ }
+ }
+ return bRes;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+uno::Reference< XInterface > GetOneInstanceService( const char *pServiceName )
+{
+ uno::Reference< XInterface > xRef;
+
+ if (pServiceName)
+ {
+ uno::Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
+ if (xMgr.is())
+ {
+ try
+ {
+ xRef = xMgr->createInstance( A2OU( pServiceName ) );
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "createInstance failed" );
+ }
+ }
+ }
+
+ return xRef;
+}
+
+uno::Reference< XPropertySet > GetLinguProperties()
+{
+ return uno::Reference< XPropertySet > (
+ GetOneInstanceService( SN_LINGU_PROPERTIES ), UNO_QUERY );
+}
+
+uno::Reference< XSearchableDictionaryList > GetSearchableDictionaryList()
+{
+ return uno::Reference< XSearchableDictionaryList > (
+ GetOneInstanceService( SN_DICTIONARY_LIST ), UNO_QUERY );
+}
+
+uno::Reference< XDictionaryList > GetDictionaryList()
+{
+ return uno::Reference< XDictionaryList > (
+ GetOneInstanceService( SN_DICTIONARY_LIST ), UNO_QUERY );
+}
+
+uno::Reference< XDictionary > GetIgnoreAllList()
+{
+ uno::Reference< XDictionary > xRes;
+ uno::Reference< XDictionaryList > xDL( GetDictionaryList() );
+ if (xDL.is())
+ xRes = xDL->getDictionaryByName( A2OU("IgnoreAllList") );
+ return xRes;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+AppExitListener::AppExitListener()
+{
+ // add object to Desktop EventListeners in order to properly call
+ // the AtExit function at appliction exit.
+ uno::Reference< XMultiServiceFactory > xMgr = getProcessServiceFactory();
+
+ if (xMgr.is())
+ {
+ try
+ {
+ xDesktop = uno::Reference< frame::XDesktop >(
+ xMgr->createInstance( A2OU( SN_DESKTOP ) ), UNO_QUERY );
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "createInstance failed" );
+ }
+ }
+}
+
+AppExitListener::~AppExitListener()
+{
+}
+
+
+void AppExitListener::Activate()
+{
+ if (xDesktop.is())
+ xDesktop->addTerminateListener( this );
+}
+
+
+void AppExitListener::Deactivate()
+{
+ if (xDesktop.is())
+ xDesktop->removeTerminateListener( this );
+}
+
+
+void SAL_CALL
+ AppExitListener::disposing( const EventObject& rEvtSource )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (xDesktop.is() && rEvtSource.Source == xDesktop)
+ {
+ xDesktop = NULL; //! release reference to desktop
+ }
+}
+
+
+void SAL_CALL
+ AppExitListener::queryTermination( const EventObject& /*rEvtSource*/ )
+ throw(frame::TerminationVetoException, RuntimeException)
+{
+ //MutexGuard aGuard( GetLinguMutex() );
+}
+
+
+void SAL_CALL
+ AppExitListener::notifyTermination( const EventObject& rEvtSource )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (xDesktop.is() && rEvtSource.Source == xDesktop)
+ {
+ AtExit();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+} // namespace linguistic
+
diff --git a/linguistic/source/misc2.cxx b/linguistic/source/misc2.cxx
new file mode 100644
index 000000000000..df7bc2f9f636
--- /dev/null
+++ b/linguistic/source/misc2.cxx
@@ -0,0 +1,300 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+#include <tools/string.hxx>
+#include <tools/fsys.hxx>
+#include <tools/urlobj.hxx>
+#include <ucbhelper/content.hxx>
+#include <tools/debug.hxx>
+#include <unotools/pathoptions.hxx>
+#include <unotools/processfactory.hxx>
+#include <unotools/localfilehelper.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/ucbhelper.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Reference.h>
+
+#include "misc.hxx"
+
+using namespace com::sun::star;
+
+namespace linguistic
+{
+
+///////////////////////////////////////////////////////////////////////////
+
+BOOL FileExists( const String &rMainURL )
+{
+ BOOL bExists = FALSE;
+ if (rMainURL.Len())
+ {
+ try
+ {
+ ::ucbhelper::Content aContent( rMainURL,
+ uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >());
+ bExists = aContent.isDocument();
+ }
+ catch (uno::Exception &)
+ {
+ }
+ }
+ return bExists;
+}
+
+
+#ifdef TL_OUTDATED
+
+String GetFileURL( SvtPathOptions::Pathes ePath, const String &rFileName )
+{
+ String aURL;
+ if (rFileName.Len())
+ {
+ INetURLObject aURLObj;
+ aURLObj.SetSmartProtocol( INET_PROT_FILE );
+ aURLObj.SetSmartURL( GetModulePath(ePath) );
+ aURLObj.Append( rFileName );
+ if (aURLObj.HasError())
+ {
+ DBG_ASSERT(!aURLObj.HasError(), "lng : invalid URL");
+ }
+ aURL = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
+ }
+ return aURL;
+}
+
+
+String GetModulePath( SvtPathOptions::Pathes ePath, BOOL bAddAccessDelim )
+{
+ String aRes;
+
+ SvtPathOptions aPathOpt;
+ switch (ePath)
+ {
+ case SvtPathOptions::PATH_MODULE :
+ aRes = aPathOpt.GetModulePath();
+ break;
+ case SvtPathOptions::PATH_LINGUISTIC :
+ {
+ String aTmp( aPathOpt.GetLinguisticPath() );
+ utl::LocalFileHelper::ConvertURLToPhysicalName( aTmp, aRes );
+ break;
+ }
+/*
+ case SvtPathOptions::PATH_USERDICTIONARY :
+ {
+ String aTmp( aPathOpt.GetUserDictionaryPath() );
+ utl::LocalFileHelper::ConvertURLToPhysicalName( aTmp, aRes );
+ break;
+ }
+*/
+ default:
+ DBG_ASSERT( 0, "unexpected argument (path)" );
+ }
+ if (bAddAccessDelim && aRes.Len())
+ {
+#ifdef WNT
+ aRes += '\\';
+#else
+ aRes += '/';
+#endif
+ }
+
+ return aRes;
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+
+rtl::OUString StripTrailingChars( rtl::OUString &rTxt, sal_Unicode cChar )
+{
+ sal_Int32 nTrailing = 0;
+ sal_Int32 nTxtLen = rTxt.getLength();
+ sal_Int32 nIdx = nTxtLen - 1;
+ while (nIdx >= 0 && rTxt[ nIdx-- ] == cChar)
+ ++nTrailing;
+
+ rtl::OUString aRes( rTxt.copy( nTxtLen - nTrailing ) );
+ rTxt = rTxt.copy( 0, nTxtLen - nTrailing );
+ return aRes;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static uno::Sequence< rtl::OUString > GetMultiPaths_Impl(
+ const rtl::OUString &rPathPrefix,
+ sal_Int16 nPathFlags )
+{
+ uno::Sequence< rtl::OUString > aRes;
+ uno::Sequence< rtl::OUString > aInternalPaths;
+ uno::Sequence< rtl::OUString > aUserPaths;
+ rtl::OUString aWritablePath;
+
+ bool bSuccess = true;
+ uno::Reference< lang::XMultiServiceFactory > xMgr( utl::getProcessServiceFactory() );
+ if (xMgr.is())
+ {
+ try
+ {
+ String aInternal( rPathPrefix );
+ String aUser( rPathPrefix );
+ String aWriteable( rPathPrefix );
+ aInternal .AppendAscii( "_internal" );
+ aUser .AppendAscii( "_user" );
+ aWriteable.AppendAscii( "_writable" );
+
+ uno::Reference< beans::XPropertySet > xPathSettings( xMgr->createInstance(
+ A2OU( "com.sun.star.util.PathSettings" ) ), uno::UNO_QUERY_THROW );
+ xPathSettings->getPropertyValue( aInternal ) >>= aInternalPaths;
+ xPathSettings->getPropertyValue( aUser ) >>= aUserPaths;
+ xPathSettings->getPropertyValue( aWriteable ) >>= aWritablePath;
+ }
+ catch (uno::Exception &)
+ {
+ bSuccess = false;
+ }
+ }
+ if (bSuccess)
+ {
+ // build resulting sequence by adding the pathes in the following order:
+ // 1. writable path
+ // 2. all user pathes
+ // 3. all internal pathes
+ sal_Int32 nMaxEntries = aInternalPaths.getLength() + aUserPaths.getLength();
+ if (aWritablePath.getLength() > 0)
+ ++nMaxEntries;
+ aRes.realloc( nMaxEntries );
+ rtl::OUString *pRes = aRes.getArray();
+ sal_Int32 nCount = 0; // number of actually added entries
+ if ((nPathFlags & PATH_FLAG_WRITABLE) && aWritablePath.getLength() != 0)
+ pRes[ nCount++ ] = aWritablePath;
+ for (int i = 0; i < 2; ++i)
+ {
+ const uno::Sequence< rtl::OUString > &rPathSeq = i == 0 ? aUserPaths : aInternalPaths;
+ const rtl::OUString *pPathSeq = rPathSeq.getConstArray();
+ for (sal_Int32 k = 0; k < rPathSeq.getLength(); ++k)
+ {
+ const bool bAddUser = &rPathSeq == &aUserPaths && (nPathFlags & PATH_FLAG_USER);
+ const bool bAddInternal = &rPathSeq == &aInternalPaths && (nPathFlags & PATH_FLAG_INTERNAL);
+ if ((bAddUser || bAddInternal) && pPathSeq[k].getLength() > 0)
+ pRes[ nCount++ ] = pPathSeq[k];
+ }
+ }
+ aRes.realloc( nCount );
+ }
+
+ return aRes;
+}
+
+rtl::OUString GetDictionaryWriteablePath()
+{
+ uno::Sequence< rtl::OUString > aPaths( GetMultiPaths_Impl( A2OU("Dictionary"), PATH_FLAG_WRITABLE ) );
+ DBG_ASSERT( aPaths.getLength() == 1, "Dictionary_writable path corrupted?" );
+ String aRes;
+ if (aPaths.getLength() > 0)
+ aRes = aPaths[0];
+ return aRes;
+}
+
+uno::Sequence< rtl::OUString > GetDictionaryPaths( sal_Int16 nPathFlags )
+{
+ return GetMultiPaths_Impl( A2OU("Dictionary"), nPathFlags );
+}
+
+uno::Sequence< rtl::OUString > GetLinguisticPaths( sal_Int16 nPathFlags )
+{
+ return GetMultiPaths_Impl( A2OU("Linguistic"), nPathFlags );
+}
+
+String GetWritableDictionaryURL( const String &rDicName )
+{
+ // new user writable dictionaries should be created in the 'writable' path
+ String aDirName( GetDictionaryWriteablePath() );
+
+ // build URL to use for a new (persistent) dictionary
+ INetURLObject aURLObj;
+ aURLObj.SetSmartProtocol( INET_PROT_FILE );
+ aURLObj.SetSmartURL( aDirName );
+ DBG_ASSERT(!aURLObj.HasError(), "lng : invalid URL");
+ aURLObj.Append( rDicName, INetURLObject::ENCODE_ALL );
+ DBG_ASSERT(!aURLObj.HasError(), "lng : invalid URL");
+
+ return aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
+}
+
+
+String SearchFileInPaths(
+ const String &rFile,
+ const uno::Sequence< rtl::OUString > &rPaths )
+{
+ //!! see also SvtPathOptions::SearchFile for the riginal code
+
+ String aRes;
+
+ // check in all paths...
+ const sal_Int32 nPaths = rPaths.getLength();
+ for (sal_Int32 k = 0; k < nPaths; ++k)
+ {
+ BOOL bIsURL = TRUE;
+ INetURLObject aObj( rPaths[k] );
+ if ( aObj.HasError() )
+ {
+ bIsURL = FALSE;
+ String aURL;
+ if ( utl::LocalFileHelper::ConvertPhysicalNameToURL( rPaths[k], aURL ) )
+ aObj.SetURL( aURL );
+ }
+
+ xub_StrLen i, nCount = rFile.GetTokenCount( '/' );
+ for ( i = 0; i < nCount; ++i )
+ aObj.insertName( rFile.GetToken( i, '/' ) );
+ bool bRet = ::utl::UCBContentHelper::Exists( aObj.GetMainURL( INetURLObject::NO_DECODE ) );
+
+ if ( bRet )
+ {
+ if ( !bIsURL )
+ ::utl::LocalFileHelper::ConvertURLToPhysicalName(
+ aObj.GetMainURL( INetURLObject::NO_DECODE ), aRes );
+ else
+ aRes = aObj.GetMainURL( INetURLObject::NO_DECODE );
+ break;
+ }
+ }
+
+ return aRes;
+}
+
+
+} // namespace linguistic
+
+
diff --git a/linguistic/source/spelldsp.cxx b/linguistic/source/spelldsp.cxx
new file mode 100644
index 000000000000..2c9c99296ad7
--- /dev/null
+++ b/linguistic/source/spelldsp.cxx
@@ -0,0 +1,871 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
+#include <com/sun/star/linguistic2/SpellFailure.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+
+#include <cppuhelper/factory.hxx> // helper for factories
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/processfactory.hxx>
+#include <tools/debug.hxx>
+#include <svl/lngmisc.hxx>
+#include <osl/mutex.hxx>
+
+#include <vector>
+
+#include "spelldsp.hxx"
+#include "spelldta.hxx"
+#include "lngsvcmgr.hxx"
+#include "lngprops.hxx"
+
+
+using namespace utl;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::linguistic2;
+using namespace linguistic;
+
+///////////////////////////////////////////////////////////////////////////
+// ProposalList: list of proposals for misspelled words
+// The order of strings in the array should be left unchanged because the
+// spellchecker should have put the more likely suggestions at the top.
+// New entries will be added to the end but duplicates are to be avoided.
+// Removing entries is done by assigning the empty string.
+// The sequence is constructed from all non empty strings in the original
+// while maintaining the order.
+//
+class ProposalList
+{
+ std::vector< OUString > aVec;
+
+ BOOL HasEntry( const OUString &rText ) const;
+
+ // make copy c-tor and assignment operator private
+ ProposalList( const ProposalList & );
+ ProposalList & operator = ( const ProposalList & );
+
+public:
+ ProposalList() {}
+
+ //size_t Size() const { return aVec.size(); }
+ size_t Count() const;
+ void Prepend( const OUString &rText );
+ void Append( const OUString &rNew );
+ void Append( const std::vector< OUString > &rNew );
+ void Append( const Sequence< OUString > &rNew );
+ void Remove( const OUString &rText );
+ Sequence< OUString > GetSequence() const;
+};
+
+
+BOOL ProposalList::HasEntry( const OUString &rText ) const
+{
+ BOOL bFound = FALSE;
+ size_t nCnt = aVec.size();
+ for (size_t i = 0; !bFound && i < nCnt; ++i)
+ {
+ if (aVec[i] == rText)
+ bFound = TRUE;
+ }
+ return bFound;
+}
+
+void ProposalList::Prepend( const OUString &rText )
+{
+ if (!HasEntry( rText ))
+ aVec.insert( aVec.begin(), rText );
+}
+
+void ProposalList::Append( const OUString &rText )
+{
+ if (!HasEntry( rText ))
+ aVec.push_back( rText );
+}
+
+void ProposalList::Append( const std::vector< OUString > &rNew )
+{
+ size_t nLen = rNew.size();
+ for ( size_t i = 0; i < nLen; ++i)
+ {
+ const OUString &rText = rNew[i];
+ if (!HasEntry( rText ))
+ Append( rText );
+ }
+}
+
+void ProposalList::Append( const Sequence< OUString > &rNew )
+{
+ INT32 nLen = rNew.getLength();
+ const OUString *pNew = rNew.getConstArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ const OUString &rText = pNew[i];
+ if (!HasEntry( rText ))
+ Append( rText );
+ }
+}
+
+size_t ProposalList::Count() const
+{
+ // returns the number of non-empty strings in the vector
+
+ size_t nRes = 0;
+ size_t nLen = aVec.size();
+ for (size_t i = 0; i < nLen; ++i)
+ {
+ if (aVec[i].getLength() != 0)
+ ++nRes;
+ }
+ return nRes;
+}
+
+Sequence< OUString > ProposalList::GetSequence() const
+{
+ INT32 nCount = Count();
+ INT32 nIdx = 0;
+ Sequence< OUString > aRes( nCount );
+ OUString *pRes = aRes.getArray();
+ INT32 nLen = aVec.size();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ const OUString &rText = aVec[i];
+ DBG_ASSERT( nIdx < nCount, "index our of range" );
+ if (nIdx < nCount && rText.getLength() > 0)
+ pRes[ nIdx++ ] = rText;
+ }
+ return aRes;
+}
+
+void ProposalList::Remove( const OUString &rText )
+{
+ size_t nLen = aVec.size();
+ for (size_t i = 0; i < nLen; ++i)
+ {
+ OUString &rEntry = aVec[i];
+ if (rEntry == rText)
+ {
+ rEntry = OUString();
+ break; // there should be only one matching entry
+ }
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+BOOL SvcListHasLanguage(
+ const LangSvcEntries_Spell &rEntry,
+ LanguageType nLanguage )
+{
+ BOOL bHasLanguage = FALSE;
+ Locale aTmpLocale;
+
+ const Reference< XSpellChecker > *pRef = rEntry.aSvcRefs .getConstArray();
+ sal_Int32 nLen = rEntry.aSvcRefs.getLength();
+ for (INT32 k = 0; k < nLen && !bHasLanguage; ++k)
+ {
+ if (pRef[k].is())
+ {
+ if (0 == aTmpLocale.Language.getLength())
+ aTmpLocale = CreateLocale( nLanguage );
+ bHasLanguage = pRef[k]->hasLocale( aTmpLocale );
+ }
+ }
+
+ return bHasLanguage;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+
+SpellCheckerDispatcher::SpellCheckerDispatcher( LngSvcMgr &rLngSvcMgr ) :
+ rMgr (rLngSvcMgr)
+{
+ pCache = NULL;
+}
+
+
+SpellCheckerDispatcher::~SpellCheckerDispatcher()
+{
+ ClearSvcList();
+ delete pCache;
+}
+
+
+void SpellCheckerDispatcher::ClearSvcList()
+{
+ // release memory for each table entry
+ SpellSvcByLangMap_t aTmp;
+ aSvcMap.swap( aTmp );
+}
+
+
+Sequence< Locale > SAL_CALL SpellCheckerDispatcher::getLocales()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) );
+ Locale *pLocales = aLocales.getArray();
+ SpellSvcByLangMap_t::const_iterator aIt;
+ for (aIt = aSvcMap.begin(); aIt != aSvcMap.end(); ++aIt)
+ {
+ *pLocales++ = CreateLocale( aIt->first );
+ }
+ return aLocales;
+}
+
+
+sal_Bool SAL_CALL SpellCheckerDispatcher::hasLocale( const Locale& rLocale )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ SpellSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LocaleToLanguage( rLocale ) ) );
+ return aIt != aSvcMap.end();
+}
+
+
+sal_Bool SAL_CALL
+ SpellCheckerDispatcher::isValid( const OUString& rWord, const Locale& rLocale,
+ const PropertyValues& rProperties )
+ throw(IllegalArgumentException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return isValid_Impl( rWord, LocaleToLanguage( rLocale ), rProperties, TRUE );
+}
+
+
+Reference< XSpellAlternatives > SAL_CALL
+ SpellCheckerDispatcher::spell( const OUString& rWord, const Locale& rLocale,
+ const PropertyValues& rProperties )
+ throw(IllegalArgumentException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return spell_Impl( rWord, LocaleToLanguage( rLocale ), rProperties, TRUE );
+}
+
+
+// returns the overall result of cross-checking with all user-dictionaries
+// including the IgnoreAll list
+static Reference< XDictionaryEntry > lcl_GetRulingDictionaryEntry(
+ const OUString &rWord,
+ LanguageType nLanguage )
+{
+ Reference< XDictionaryEntry > xRes;
+
+ // the order of winning from top to bottom is:
+ // 1) IgnoreAll list will always win
+ // 2) Negative dictionaries will win over positive dictionaries
+ Reference< XDictionary > xIgnoreAll( GetIgnoreAllList() );
+ if (xIgnoreAll.is())
+ xRes = xIgnoreAll->getEntry( rWord );
+ if (!xRes.is())
+ {
+ Reference< XDictionaryList > xDList( GetDictionaryList() );
+ Reference< XDictionaryEntry > xNegEntry( SearchDicList( xDList,
+ rWord, nLanguage, FALSE, TRUE ) );
+ if (xNegEntry.is())
+ xRes = xNegEntry;
+ else
+ {
+ Reference< XDictionaryEntry > xPosEntry( SearchDicList( xDList,
+ rWord, nLanguage, TRUE, TRUE ) );
+ if (xPosEntry.is())
+ xRes = xPosEntry;
+ }
+ }
+
+ return xRes;
+}
+
+
+BOOL SpellCheckerDispatcher::isValid_Impl(
+ const OUString& rWord,
+ LanguageType nLanguage,
+ const PropertyValues& rProperties,
+ BOOL bCheckDics)
+ throw( RuntimeException, IllegalArgumentException )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ BOOL bRes = TRUE;
+
+ if (nLanguage == LANGUAGE_NONE || !rWord.getLength())
+ return bRes;
+
+ // search for entry with that language
+ SpellSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
+ LangSvcEntries_Spell *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
+
+ if (!pEntry)
+ {
+#ifdef LINGU_EXCEPTIONS
+ throw IllegalArgumentException();
+#endif
+ }
+ else
+ {
+ OUString aChkWord( rWord );
+ Locale aLocale( CreateLocale( nLanguage ) );
+
+ // replace typographical apostroph by ascii apostroph
+ String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
+ DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
+ if (aSingleQuote.Len())
+ aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
+
+ RemoveHyphens( aChkWord );
+ if (IsIgnoreControlChars( rProperties, GetPropSet() ))
+ RemoveControlChars( aChkWord );
+
+ INT32 nLen = pEntry->aSvcRefs.getLength();
+ DBG_ASSERT( nLen == pEntry->aSvcImplNames.getLength(),
+ "lng : sequence length mismatch");
+ DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
+ "lng : index out of range");
+
+ INT32 i = 0;
+ BOOL bTmpRes = TRUE;
+ BOOL bTmpResValid = FALSE;
+
+ // try already instantiated services first
+ {
+ const Reference< XSpellChecker > *pRef =
+ pEntry->aSvcRefs.getConstArray();
+ while (i <= pEntry->nLastTriedSvcIndex
+ && (!bTmpResValid || FALSE == bTmpRes))
+ {
+ bTmpResValid = TRUE;
+ if (pRef[i].is() && pRef[i]->hasLocale( aLocale ))
+ {
+ bTmpRes = GetCache().CheckWord( aChkWord, nLanguage );
+ if (!bTmpRes)
+ {
+ bTmpRes = pRef[i]->isValid( aChkWord, aLocale, rProperties );
+
+ // Add correct words to the cache.
+ // But not those that are correct only because of
+ // the temporary supplied settings.
+ if (bTmpRes && 0 == rProperties.getLength())
+ GetCache().AddWord( aChkWord, nLanguage );
+ }
+ }
+ else
+ bTmpResValid = FALSE;
+
+ if (bTmpResValid)
+ bRes = bTmpRes;
+
+ ++i;
+ }
+ }
+
+ // if still no result instantiate new services and try those
+ if ((!bTmpResValid || FALSE == bTmpRes)
+ && pEntry->nLastTriedSvcIndex < nLen - 1)
+ {
+ const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
+ Reference< XSpellChecker > *pRef = pEntry->aSvcRefs .getArray();
+
+ Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
+ if (xMgr.is())
+ {
+ // build service initialization argument
+ Sequence< Any > aArgs(2);
+ aArgs.getArray()[0] <<= GetPropSet();
+ //! The dispatcher searches the dictionary-list
+ //! thus the service needs not to now about it
+ //aArgs.getArray()[1] <<= GetDicList();
+
+ while (i < nLen && (!bTmpResValid || FALSE == bTmpRes))
+ {
+ // create specific service via it's implementation name
+ Reference< XSpellChecker > xSpell;
+ try
+ {
+ xSpell = Reference< XSpellChecker >(
+ xMgr->createInstanceWithArguments(
+ pImplNames[i], aArgs ), UNO_QUERY );
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "createInstanceWithArguments failed" );
+ }
+ pRef [i] = xSpell;
+
+ Reference< XLinguServiceEventBroadcaster >
+ xBroadcaster( xSpell, UNO_QUERY );
+ if (xBroadcaster.is())
+ rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
+
+ bTmpResValid = TRUE;
+ if (xSpell.is() && xSpell->hasLocale( aLocale ))
+ {
+ bTmpRes = GetCache().CheckWord( aChkWord, nLanguage );
+ if (!bTmpRes)
+ {
+ bTmpRes = xSpell->isValid( aChkWord, aLocale, rProperties );
+
+ // Add correct words to the cache.
+ // But not those that are correct only because of
+ // the temporary supplied settings.
+ if (bTmpRes && 0 == rProperties.getLength())
+ GetCache().AddWord( aChkWord, nLanguage );
+ }
+ }
+ else
+ bTmpResValid = FALSE;
+
+ if (bTmpResValid)
+ bRes = bTmpRes;
+
+ pEntry->nLastTriedSvcIndex = (INT16) i;
+ ++i;
+ }
+
+ // if language is not supported by any of the services
+ // remove it from the list.
+ if (i == nLen)
+ {
+ if (!SvcListHasLanguage( *pEntry, nLanguage ))
+ aSvcMap.erase( nLanguage );
+ }
+ }
+ }
+
+ // cross-check against results from dictionaries which have precedence!
+ if (bCheckDics &&
+ GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
+ {
+ Reference< XDictionaryEntry > xTmp( lcl_GetRulingDictionaryEntry( aChkWord, nLanguage ) );
+ if (xTmp.is())
+ bRes = !xTmp->isNegative();
+ }
+ }
+
+ return bRes;
+}
+
+
+Reference< XSpellAlternatives > SpellCheckerDispatcher::spell_Impl(
+ const OUString& rWord,
+ LanguageType nLanguage,
+ const PropertyValues& rProperties,
+ BOOL bCheckDics )
+ throw(IllegalArgumentException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Reference< XSpellAlternatives > xRes;
+
+ if (nLanguage == LANGUAGE_NONE || !rWord.getLength())
+ return xRes;
+
+ // search for entry with that language
+ SpellSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
+ LangSvcEntries_Spell *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
+
+ if (!pEntry)
+ {
+#ifdef LINGU_EXCEPTIONS
+ throw IllegalArgumentException();
+#endif
+ }
+ else
+ {
+ OUString aChkWord( rWord );
+ Locale aLocale( CreateLocale( nLanguage ) );
+
+ // replace typographical apostroph by ascii apostroph
+ String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
+ DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
+ if (aSingleQuote.Len())
+ aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
+
+ RemoveHyphens( aChkWord );
+ if (IsIgnoreControlChars( rProperties, GetPropSet() ))
+ RemoveControlChars( aChkWord );
+
+ INT32 nLen = pEntry->aSvcRefs.getLength();
+ DBG_ASSERT( nLen == pEntry->aSvcImplNames.getLength(),
+ "lng : sequence length mismatch");
+ DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
+ "lng : index out of range");
+
+ INT32 i = 0;
+ Reference< XSpellAlternatives > xTmpRes;
+ BOOL bTmpResValid = FALSE;
+
+ // try already instantiated services first
+ {
+ const Reference< XSpellChecker > *pRef = pEntry->aSvcRefs.getConstArray();
+ sal_Int32 nNumSugestions = -1;
+ while (i <= pEntry->nLastTriedSvcIndex
+ && (!bTmpResValid || xTmpRes.is()) )
+ {
+ bTmpResValid = TRUE;
+ if (pRef[i].is() && pRef[i]->hasLocale( aLocale ))
+ {
+ BOOL bOK = GetCache().CheckWord( aChkWord, nLanguage );
+ if (bOK)
+ xTmpRes = NULL;
+ else
+ {
+ xTmpRes = pRef[i]->spell( aChkWord, aLocale, rProperties );
+
+ // Add correct words to the cache.
+ // But not those that are correct only because of
+ // the temporary supplied settings.
+ if (!xTmpRes.is() && 0 == rProperties.getLength())
+ GetCache().AddWord( aChkWord, nLanguage );
+ }
+ }
+ else
+ bTmpResValid = FALSE;
+
+ // return first found result if the word is not known by any checker.
+ // But if that result has no suggestions use the first one that does
+ // provide suggestions for the misspelled word.
+ if (!xRes.is() && bTmpResValid)
+ {
+ xRes = xTmpRes;
+ nNumSugestions = 0;
+ if (xRes.is())
+ nNumSugestions = xRes->getAlternatives().getLength();
+ }
+ sal_Int32 nTmpNumSugestions = 0;
+ if (xTmpRes.is() && bTmpResValid)
+ nTmpNumSugestions = xTmpRes->getAlternatives().getLength();
+ if (xRes.is() && nNumSugestions == 0 && nTmpNumSugestions > 0)
+ {
+ xRes = xTmpRes;
+ nNumSugestions = nTmpNumSugestions;
+ }
+
+ ++i;
+ }
+ }
+
+ // if still no result instantiate new services and try those
+ if ((!bTmpResValid || xTmpRes.is())
+ && pEntry->nLastTriedSvcIndex < nLen - 1)
+ {
+ const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
+ Reference< XSpellChecker > *pRef = pEntry->aSvcRefs .getArray();
+
+ Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
+ if (xMgr.is())
+ {
+ // build service initialization argument
+ Sequence< Any > aArgs(2);
+ aArgs.getArray()[0] <<= GetPropSet();
+ //! The dispatcher searches the dictionary-list
+ //! thus the service needs not to now about it
+ //aArgs.getArray()[1] <<= GetDicList();
+
+ sal_Int32 nNumSugestions = -1;
+ while (i < nLen && (!bTmpResValid || xTmpRes.is()))
+ {
+ // create specific service via it's implementation name
+ Reference< XSpellChecker > xSpell;
+ try
+ {
+ xSpell = Reference< XSpellChecker >(
+ xMgr->createInstanceWithArguments(
+ pImplNames[i], aArgs ), UNO_QUERY );
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "createInstanceWithArguments failed" );
+ }
+ pRef [i] = xSpell;
+
+ Reference< XLinguServiceEventBroadcaster >
+ xBroadcaster( xSpell, UNO_QUERY );
+ if (xBroadcaster.is())
+ rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
+
+ bTmpResValid = TRUE;
+ if (xSpell.is() && xSpell->hasLocale( aLocale ))
+ {
+ BOOL bOK = GetCache().CheckWord( aChkWord, nLanguage );
+ if (bOK)
+ xTmpRes = NULL;
+ else
+ {
+ xTmpRes = xSpell->spell( aChkWord, aLocale, rProperties );
+
+ // Add correct words to the cache.
+ // But not those that are correct only because of
+ // the temporary supplied settings.
+ if (!xTmpRes.is() && 0 == rProperties.getLength())
+ GetCache().AddWord( aChkWord, nLanguage );
+ }
+ }
+ else
+ bTmpResValid = FALSE;
+
+ // return first found result if the word is not known by any checker.
+ // But if that result has no suggestions use the first one that does
+ // provide suggestions for the misspelled word.
+ if (!xRes.is() && bTmpResValid)
+ {
+ xRes = xTmpRes;
+ nNumSugestions = 0;
+ if (xRes.is())
+ nNumSugestions = xRes->getAlternatives().getLength();
+ }
+ sal_Int32 nTmpNumSugestions = 0;
+ if (xTmpRes.is() && bTmpResValid)
+ nTmpNumSugestions = xTmpRes->getAlternatives().getLength();
+ if (xRes.is() && nNumSugestions == 0 && nTmpNumSugestions > 0)
+ {
+ xRes = xTmpRes;
+ nNumSugestions = nTmpNumSugestions;
+ }
+
+ pEntry->nLastTriedSvcIndex = (INT16) i;
+ ++i;
+ }
+
+ // if language is not supported by any of the services
+ // remove it from the list.
+ if (i == nLen)
+ {
+ if (!SvcListHasLanguage( *pEntry, nLanguage ))
+ aSvcMap.erase( nLanguage );
+ }
+ }
+ }
+
+ // if word is finally found to be correct
+ // clear previously remembered alternatives
+ if (bTmpResValid && !xTmpRes.is())
+ xRes = NULL;
+
+ // list of proposals found (to be checked against entries of
+ // neagtive dictionaries)
+ ProposalList aProposalList;
+// Sequence< OUString > aProposals;
+ INT16 eFailureType = -1; // no failure
+ if (xRes.is())
+ {
+ aProposalList.Append( xRes->getAlternatives() );
+// aProposals = xRes->getAlternatives();
+ eFailureType = xRes->getFailureType();
+ }
+ Reference< XDictionaryList > xDList;
+ if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
+ xDList = Reference< XDictionaryList >( GetDicList(), UNO_QUERY );
+
+ // cross-check against results from user-dictionaries which have precedence!
+ if (bCheckDics && xDList.is())
+ {
+ Reference< XDictionaryEntry > xTmp( lcl_GetRulingDictionaryEntry( aChkWord, nLanguage ) );
+ if (xTmp.is())
+ {
+ if (xTmp->isNegative()) // positive entry found
+ {
+ eFailureType = SpellFailure::IS_NEGATIVE_WORD;
+
+ // replacement text to be added to suggestions, if not empty
+ OUString aAddRplcTxt( xTmp->getReplacementText() );
+
+ // replacement text must not be in negative dictionary itself
+ if (aAddRplcTxt.getLength() &&
+ !SearchDicList( xDList, aAddRplcTxt, nLanguage, FALSE, TRUE ).is())
+ {
+ aProposalList.Prepend( aAddRplcTxt );
+ }
+ }
+ else // positive entry found
+ {
+ xRes = NULL;
+ eFailureType = -1; // no failure
+ }
+ }
+ }
+
+ if (eFailureType != -1) // word misspelled or found in negative user-dictionary
+ {
+ // search suitable user-dictionaries for suggestions that are
+ // similar to the misspelled word
+ std::vector< OUString > aDicListProps; // list of proposals from user-dictionaries
+ SearchSimilarText( aChkWord, nLanguage, xDList, aDicListProps );
+ aProposalList.Append( aDicListProps );
+ Sequence< OUString > aProposals = aProposalList.GetSequence();
+
+ // remove entries listed in negative dictionaries
+ // (we don't want to display suggestions that will be regarded as misspelledlater on)
+ if (bCheckDics && xDList.is())
+ SeqRemoveNegEntries( aProposals, xDList, nLanguage );
+
+ uno::Reference< linguistic2::XSetSpellAlternatives > xSetAlt( xRes, uno::UNO_QUERY );
+ if (xSetAlt.is())
+ {
+ xSetAlt->setAlternatives( aProposals );
+ xSetAlt->setFailureType( eFailureType );
+ }
+ else
+ {
+ if (xRes.is())
+ {
+ DBG_ASSERT( 0, "XSetSpellAlternatives not implemented!" );
+ }
+ else if (aProposals.getLength() > 0)
+ {
+ // no xRes but Proposals found from the user-dictionaries.
+ // Thus we need to create an xRes...
+ xRes = new linguistic::SpellAlternatives( rWord, nLanguage,
+ SpellFailure::IS_NEGATIVE_WORD, aProposals );
+ }
+ }
+ }
+ }
+
+ return xRes;
+}
+
+uno::Sequence< sal_Int16 > SAL_CALL SpellCheckerDispatcher::getLanguages( )
+throw (uno::RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ uno::Sequence< Locale > aTmp( getLocales() );
+ uno::Sequence< INT16 > aRes( LocaleSeqToLangSeq( aTmp ) );
+ return aRes;
+}
+
+
+sal_Bool SAL_CALL SpellCheckerDispatcher::hasLanguage(
+ sal_Int16 nLanguage )
+throw (uno::RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ Locale aLocale( CreateLocale( nLanguage ) );
+ return hasLocale( aLocale );
+}
+
+
+sal_Bool SAL_CALL SpellCheckerDispatcher::isValid(
+ const OUString& rWord,
+ sal_Int16 nLanguage,
+ const uno::Sequence< beans::PropertyValue >& rProperties )
+throw (lang::IllegalArgumentException, uno::RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ Locale aLocale( CreateLocale( nLanguage ) );
+ return isValid( rWord, aLocale, rProperties);
+}
+
+
+uno::Reference< linguistic2::XSpellAlternatives > SAL_CALL SpellCheckerDispatcher::spell(
+ const OUString& rWord,
+ sal_Int16 nLanguage,
+ const uno::Sequence< beans::PropertyValue >& rProperties )
+throw (lang::IllegalArgumentException, uno::RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ Locale aLocale( CreateLocale( nLanguage ) );
+ return spell( rWord, aLocale, rProperties);
+}
+
+
+void SpellCheckerDispatcher::SetServiceList( const Locale &rLocale,
+ const Sequence< OUString > &rSvcImplNames )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ if (pCache)
+ pCache->Flush(); // new services may spell differently...
+
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+
+ INT32 nLen = rSvcImplNames.getLength();
+ if (0 == nLen)
+ // remove entry
+ aSvcMap.erase( nLanguage );
+ else
+ {
+ // modify/add entry
+ LangSvcEntries_Spell *pEntry = aSvcMap[ nLanguage ].get();
+ if (pEntry)
+ {
+ pEntry->Clear();
+ pEntry->aSvcImplNames = rSvcImplNames;
+ pEntry->aSvcRefs = Sequence< Reference < XSpellChecker > > ( nLen );
+ }
+ else
+ {
+ boost::shared_ptr< LangSvcEntries_Spell > pTmpEntry( new LangSvcEntries_Spell( rSvcImplNames ) );
+ pTmpEntry->aSvcRefs = Sequence< Reference < XSpellChecker > >( nLen );
+ aSvcMap[ nLanguage ] = pTmpEntry;
+ }
+ }
+}
+
+
+Sequence< OUString >
+ SpellCheckerDispatcher::GetServiceList( const Locale &rLocale ) const
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Sequence< OUString > aRes;
+
+ // search for entry with that language and use data from that
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+ SpellCheckerDispatcher *pThis = (SpellCheckerDispatcher *) this;
+ const SpellSvcByLangMap_t::iterator aIt( pThis->aSvcMap.find( nLanguage ) );
+ const LangSvcEntries_Spell *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
+ if (pEntry)
+ aRes = pEntry->aSvcImplNames;
+
+ return aRes;
+}
+
+
+LinguDispatcher::DspType SpellCheckerDispatcher::GetDspType() const
+{
+ return DSP_SPELL;
+}
+
+void SpellCheckerDispatcher::FlushSpellCache()
+{
+ if (pCache)
+ pCache->Flush();
+}
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/spelldsp.hxx b/linguistic/source/spelldsp.hxx
new file mode 100644
index 000000000000..28807ac7a800
--- /dev/null
+++ b/linguistic/source/spelldsp.hxx
@@ -0,0 +1,163 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_SPELLDSP_HXX_
+#define _LINGUISTIC_SPELLDSP_HXX_
+
+#include "lngopt.hxx"
+#include "misc.hxx"
+#include "iprcache.hxx"
+
+#include <uno/lbnames.h> // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
+#include <cppuhelper/implbase1.hxx>
+#include <cppuhelper/implbase2.hxx>
+#include <cppuhelper/implbase7.hxx>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceDisplayName.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
+#include <com/sun/star/linguistic2/XSpellChecker.hpp>
+#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
+#include <com/sun/star/linguistic2/XLinguServiceEventBroadcaster.hpp>
+
+#include <boost/shared_ptr.hpp>
+#include <map>
+
+class LngSvcMgr;
+
+///////////////////////////////////////////////////////////////////////////
+
+class SpellCheckerDispatcher :
+ public cppu::WeakImplHelper2
+ <
+ ::com::sun::star::linguistic2::XSpellChecker1,
+ ::com::sun::star::linguistic2::XSpellChecker
+ >,
+ public LinguDispatcher
+{
+ typedef boost::shared_ptr< LangSvcEntries_Spell > LangSvcEntries_Spell_Ptr_t;
+ typedef std::map< LanguageType, LangSvcEntries_Spell_Ptr_t > SpellSvcByLangMap_t;
+ SpellSvcByLangMap_t aSvcMap;
+ LinguOptions aOpt;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet > xPropSet;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XSearchableDictionaryList > xDicList;
+
+ LngSvcMgr &rMgr;
+ linguistic::SpellCache *pCache; // Spell Cache (holds known words)
+
+ // disallow copy-constructor and assignment-operator for now
+ SpellCheckerDispatcher(const SpellCheckerDispatcher &);
+ SpellCheckerDispatcher & operator = (const SpellCheckerDispatcher &);
+
+ inline linguistic::SpellCache & GetCache() const;
+
+ inline ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet >
+ GetPropSet();
+ inline ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XSearchableDictionaryList >
+ GetDicList();
+
+ void ClearSvcList();
+
+ BOOL isValid_Impl(const ::rtl::OUString& aWord, LanguageType nLanguage,
+ const ::com::sun::star::beans::PropertyValues& aProperties,
+ BOOL bCheckDics)
+ throw( ::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IllegalArgumentException );
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XSpellAlternatives >
+ spell_Impl(const ::rtl::OUString& aWord, LanguageType nLanguage,
+ const ::com::sun::star::beans::PropertyValues& aProperties,
+ BOOL bCheckDics)
+ throw( ::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IllegalArgumentException );
+
+public:
+ SpellCheckerDispatcher( LngSvcMgr &rLngSvcMgr );
+ virtual ~SpellCheckerDispatcher();
+
+ // XSupportedLocales (for XSpellChecker)
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > SAL_CALL getLocales() throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL hasLocale( const ::com::sun::star::lang::Locale& aLocale ) throw(::com::sun::star::uno::RuntimeException);
+
+ // XSpellChecker
+ virtual sal_Bool SAL_CALL isValid( const ::rtl::OUString& aWord, const ::com::sun::star::lang::Locale& aLocale, const ::com::sun::star::beans::PropertyValues& aProperties ) throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XSpellAlternatives > SAL_CALL spell( const ::rtl::OUString& aWord, const ::com::sun::star::lang::Locale& aLocale, const ::com::sun::star::beans::PropertyValues& aProperties ) throw(::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+
+ // XSupportedLanguages
+ virtual ::com::sun::star::uno::Sequence< ::sal_Int16 > SAL_CALL getLanguages( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL hasLanguage( ::sal_Int16 nLanguage ) throw (::com::sun::star::uno::RuntimeException);
+
+ // XSpellChecker1
+ virtual ::sal_Bool SAL_CALL isValid( const ::rtl::OUString& aWord, ::sal_Int16 nLanguage, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProperties ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XSpellAlternatives > SAL_CALL spell( const ::rtl::OUString& aWord, ::sal_Int16 nLanguage, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProperties ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);
+
+ // LinguDispatcher
+ virtual void SetServiceList( const ::com::sun::star::lang::Locale &rLocale, const ::com::sun::star::uno::Sequence< rtl::OUString > &rSvcImplNames );
+ virtual ::com::sun::star::uno::Sequence< rtl::OUString > GetServiceList( const ::com::sun::star::lang::Locale &rLocale ) const;
+ virtual DspType GetDspType() const;
+
+ void FlushSpellCache();
+};
+
+
+inline linguistic::SpellCache & SpellCheckerDispatcher::GetCache() const
+{
+ if (!pCache)
+ ((SpellCheckerDispatcher *) this)->pCache = new linguistic::SpellCache();
+ return *pCache;
+}
+
+
+inline ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet >
+ SpellCheckerDispatcher::GetPropSet()
+{
+ return xPropSet.is() ?
+ xPropSet : xPropSet = linguistic::GetLinguProperties();
+}
+
+
+inline ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XSearchableDictionaryList >
+ SpellCheckerDispatcher::GetDicList()
+{
+ return xDicList.is() ?
+ xDicList : xDicList = linguistic::GetSearchableDictionaryList();
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/spelldta.cxx b/linguistic/source/spelldta.cxx
new file mode 100644
index 000000000000..cb7578f54852
--- /dev/null
+++ b/linguistic/source/spelldta.cxx
@@ -0,0 +1,366 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+#include <com/sun/star/uno/Reference.h>
+
+#include <com/sun/star/linguistic2/SpellFailure.hpp>
+#include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
+#include <tools/debug.hxx>
+#include <unotools/processfactory.hxx>
+#include <osl/mutex.hxx>
+
+#include <vector>
+
+#include "spelldta.hxx"
+#include "lngsvcmgr.hxx"
+
+
+using namespace utl;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::linguistic2;
+
+namespace linguistic
+{
+
+///////////////////////////////////////////////////////////////////////////
+
+
+#define MAX_PROPOSALS 40
+
+Reference< XSpellAlternatives > MergeProposals(
+ Reference< XSpellAlternatives > &rxAlt1,
+ Reference< XSpellAlternatives > &rxAlt2)
+{
+ Reference< XSpellAlternatives > xMerged;
+
+ if (!rxAlt1.is())
+ xMerged = rxAlt2;
+ else if (!rxAlt2.is())
+ xMerged = rxAlt1;
+ else
+ {
+ INT32 nAltCount1 = rxAlt1->getAlternativesCount();
+ Sequence< OUString > aAlt1( rxAlt1->getAlternatives() );
+ const OUString *pAlt1 = aAlt1.getConstArray();
+
+ INT32 nAltCount2 = rxAlt2->getAlternativesCount();
+ Sequence< OUString > aAlt2( rxAlt2->getAlternatives() );
+ const OUString *pAlt2 = aAlt2.getConstArray();
+
+ INT32 nCountNew = Min( nAltCount1 + nAltCount2, (INT32) MAX_PROPOSALS );
+ Sequence< OUString > aAltNew( nCountNew );
+ OUString *pAltNew = aAltNew.getArray();
+
+ INT32 nIndex = 0;
+ INT32 i = 0;
+ for (int j = 0; j < 2; j++)
+ {
+ INT32 nCount = j == 0 ? nAltCount1 : nAltCount2;
+ const OUString *pAlt = j == 0 ? pAlt1 : pAlt2;
+ for (i = 0; i < nCount && nIndex < MAX_PROPOSALS; i++)
+ {
+ if (pAlt[i].getLength())
+ pAltNew[ nIndex++ ] = pAlt[ i ];
+ }
+ }
+ DBG_ASSERT(nIndex == nCountNew, "lng : wrong number of proposals");
+
+ SpellAlternatives *pSpellAlt = new SpellAlternatives;
+ pSpellAlt->SetWordLanguage( rxAlt1->getWord(),
+ LocaleToLanguage( rxAlt1->getLocale() ) );
+ pSpellAlt->SetFailureType( rxAlt1->getFailureType() );
+ pSpellAlt->SetAlternatives( aAltNew );
+ xMerged = pSpellAlt;
+ }
+
+ return xMerged;
+}
+
+
+BOOL SeqHasEntry(
+ const Sequence< OUString > &rSeq,
+ const OUString &rTxt)
+{
+ BOOL bRes = FALSE;
+ INT32 nLen = rSeq.getLength();
+ const OUString *pEntry = rSeq.getConstArray();
+ for (INT32 i = 0; i < nLen && !bRes; ++i)
+ {
+ if (rTxt == pEntry[i])
+ bRes = TRUE;
+ }
+ return bRes;
+}
+
+
+void SearchSimilarText( const OUString &rText, INT16 nLanguage,
+ Reference< XDictionaryList > &xDicList,
+ std::vector< OUString > & rDicListProps )
+{
+ if (!xDicList.is())
+ return;
+
+ const uno::Sequence< Reference< XDictionary > >
+ aDics( xDicList->getDictionaries() );
+ const Reference< XDictionary >
+ *pDic = aDics.getConstArray();
+ INT32 nDics = xDicList->getCount();
+
+ for (INT32 i = 0; i < nDics; i++)
+ {
+ Reference< XDictionary > xDic( pDic[i], UNO_QUERY );
+
+ INT16 nLang = LocaleToLanguage( xDic->getLocale() );
+
+ if ( xDic.is() && xDic->isActive()
+ && (nLang == nLanguage || nLang == LANGUAGE_NONE) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ DictionaryType eType = xDic->getDictionaryType();
+ (void) eType;
+ DBG_ASSERT( eType != DictionaryType_MIXED, "unexpected dictionary type" );
+#endif
+ const Sequence< Reference< XDictionaryEntry > > aEntries = xDic->getEntries();
+ const Reference< XDictionaryEntry > *pEntries = aEntries.getConstArray();
+ INT32 nLen = aEntries.getLength();
+ for (INT32 k = 0; k < nLen; ++k)
+ {
+ String aEntryTxt;
+ if (pEntries[k].is())
+ {
+ aEntryTxt = pEntries[k]->getDictionaryWord();
+ // remove characters used to determine hyphenation positions
+ aEntryTxt.EraseAllChars( '=' );
+ }
+ if (aEntryTxt.Len() > 0 && LevDistance( rText, aEntryTxt ) <= 2)
+ rDicListProps.push_back( aEntryTxt );
+ }
+ }
+ }
+}
+
+
+void SeqRemoveNegEntries( Sequence< OUString > &rSeq,
+ Reference< XDictionaryList > &rxDicList,
+ INT16 nLanguage )
+{
+ static const OUString aEmpty;
+ BOOL bSthRemoved = FALSE;
+ INT32 nLen = rSeq.getLength();
+ OUString *pEntries = rSeq.getArray();
+ for (INT32 i = 0; i < nLen; ++i)
+ {
+ Reference< XDictionaryEntry > xNegEntry( SearchDicList( rxDicList,
+ pEntries[i], nLanguage, FALSE, TRUE ) );
+ if (xNegEntry.is())
+ {
+ pEntries[i] = aEmpty;
+ bSthRemoved = TRUE;
+ }
+ }
+ if (bSthRemoved)
+ {
+ Sequence< OUString > aNew;
+ // merge sequence without duplicates and empty strings in new empty sequence
+ aNew = MergeProposalSeqs( aNew, rSeq, FALSE );
+ rSeq = aNew;
+ }
+}
+
+
+Sequence< OUString > MergeProposalSeqs(
+ Sequence< OUString > &rAlt1,
+ Sequence< OUString > &rAlt2,
+ BOOL bAllowDuplicates )
+{
+ Sequence< OUString > aMerged;
+
+ if (0 == rAlt1.getLength() && bAllowDuplicates)
+ aMerged = rAlt2;
+ else if (0 == rAlt2.getLength() && bAllowDuplicates)
+ aMerged = rAlt1;
+ else
+ {
+ INT32 nAltCount1 = rAlt1.getLength();
+ const OUString *pAlt1 = rAlt1.getConstArray();
+ INT32 nAltCount2 = rAlt2.getLength();
+ const OUString *pAlt2 = rAlt2.getConstArray();
+
+ INT32 nCountNew = Min( nAltCount1 + nAltCount2, (INT32) MAX_PROPOSALS );
+ aMerged.realloc( nCountNew );
+ OUString *pMerged = aMerged.getArray();
+
+ INT32 nIndex = 0;
+ INT32 i = 0;
+ for (int j = 0; j < 2; j++)
+ {
+ INT32 nCount = j == 0 ? nAltCount1 : nAltCount2;
+ const OUString *pAlt = j == 0 ? pAlt1 : pAlt2;
+ for (i = 0; i < nCount && nIndex < MAX_PROPOSALS; i++)
+ {
+ if (pAlt[i].getLength() &&
+ (bAllowDuplicates || !SeqHasEntry(aMerged, pAlt[i] )))
+ pMerged[ nIndex++ ] = pAlt[ i ];
+ }
+ }
+ //DBG_ASSERT(nIndex == nCountNew, "wrong number of proposals");
+ aMerged.realloc( nIndex );
+ }
+
+ return aMerged;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+
+SpellAlternatives::SpellAlternatives()
+{
+ nLanguage = LANGUAGE_NONE;
+ nType = SpellFailure::IS_NEGATIVE_WORD;
+}
+
+
+SpellAlternatives::SpellAlternatives(
+ const OUString &rWord, INT16 nLang,
+ INT16 nFailureType, const OUString &rRplcWord ) :
+ aAlt ( Sequence< OUString >(1) ),
+ aWord (rWord),
+ nType (nFailureType),
+ nLanguage (nLang)
+{
+ if (rRplcWord.getLength())
+ aAlt.getArray()[ 0 ] = rRplcWord;
+ else
+ aAlt.realloc( 0 );
+}
+
+
+SpellAlternatives::SpellAlternatives(
+ const OUString &rWord, INT16 nLang, INT16 nFailureType,
+ const Sequence< OUString > &rAlternatives ) :
+ aAlt (rAlternatives),
+ aWord (rWord),
+ nType (nFailureType),
+ nLanguage (nLang)
+{
+}
+
+
+SpellAlternatives::~SpellAlternatives()
+{
+}
+
+
+OUString SAL_CALL SpellAlternatives::getWord()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aWord;
+}
+
+
+Locale SAL_CALL SpellAlternatives::getLocale()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return CreateLocale( nLanguage );
+}
+
+
+sal_Int16 SAL_CALL SpellAlternatives::getFailureType()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return nType;
+}
+
+
+sal_Int16 SAL_CALL SpellAlternatives::getAlternativesCount()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return (INT16) aAlt.getLength();
+}
+
+
+Sequence< OUString > SAL_CALL SpellAlternatives::getAlternatives()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aAlt;
+}
+
+
+void SAL_CALL SpellAlternatives::setAlternatives( const uno::Sequence< OUString >& rAlternatives )
+throw (uno::RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ aAlt = rAlternatives;
+}
+
+
+void SAL_CALL SpellAlternatives::setFailureType( sal_Int16 nFailureType )
+throw (uno::RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ nType = nFailureType;
+}
+
+
+void SpellAlternatives::SetWordLanguage(const OUString &rWord, INT16 nLang)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ aWord = rWord;
+ nLanguage = nLang;
+}
+
+
+void SpellAlternatives::SetFailureType(INT16 nTypeP)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ nType = nTypeP;
+}
+
+
+void SpellAlternatives::SetAlternatives( const Sequence< OUString > &rAlt )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ aAlt = rAlt;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+} // namespace linguistic
+
diff --git a/linguistic/source/thesdsp.cxx b/linguistic/source/thesdsp.cxx
new file mode 100644
index 000000000000..6bd61ef408dd
--- /dev/null
+++ b/linguistic/source/thesdsp.cxx
@@ -0,0 +1,282 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+#include <i18npool/lang.h>
+#include <tools/debug.hxx>
+#include <svl/lngmisc.hxx>
+
+#include <cppuhelper/factory.hxx> // helper for factories
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <unotools/processfactory.hxx>
+#include <osl/mutex.hxx>
+
+#include "thesdsp.hxx"
+#include "lngprops.hxx"
+
+using namespace utl;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::linguistic2;
+using namespace linguistic;
+
+///////////////////////////////////////////////////////////////////////////
+
+static BOOL SvcListHasLanguage(
+ const Sequence< Reference< XThesaurus > > &rRefs,
+ const Locale &rLocale )
+{
+ BOOL bHasLanguage = FALSE;
+
+ const Reference< XThesaurus > *pRef = rRefs.getConstArray();
+ INT32 nLen = rRefs.getLength();
+ for (INT32 k = 0; k < nLen && !bHasLanguage; ++k)
+ {
+ if (pRef[k].is())
+ bHasLanguage = pRef[k]->hasLocale( rLocale );
+ }
+
+ return bHasLanguage;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+
+ThesaurusDispatcher::ThesaurusDispatcher()
+{
+}
+
+
+ThesaurusDispatcher::~ThesaurusDispatcher()
+{
+ ClearSvcList();
+}
+
+
+void ThesaurusDispatcher::ClearSvcList()
+{
+ // release memory for each table entry
+ ThesSvcByLangMap_t aTmp;
+ aSvcMap.swap( aTmp );
+}
+
+
+Sequence< Locale > SAL_CALL
+ ThesaurusDispatcher::getLocales()
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) );
+ Locale *pLocales = aLocales.getArray();
+ ThesSvcByLangMap_t::const_iterator aIt;
+ for (aIt = aSvcMap.begin(); aIt != aSvcMap.end(); ++aIt)
+ {
+ *pLocales++ = CreateLocale( aIt->first );
+ }
+ return aLocales;
+}
+
+
+sal_Bool SAL_CALL
+ ThesaurusDispatcher::hasLocale( const Locale& rLocale )
+ throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ ThesSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LocaleToLanguage( rLocale ) ) );
+ return aIt != aSvcMap.end();
+}
+
+
+Sequence< Reference< XMeaning > > SAL_CALL
+ ThesaurusDispatcher::queryMeanings(
+ const OUString& rTerm, const Locale& rLocale,
+ const PropertyValues& rProperties )
+ throw(IllegalArgumentException, RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Sequence< Reference< XMeaning > > aMeanings;
+
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+ if (nLanguage == LANGUAGE_NONE || !rTerm.getLength())
+ return aMeanings;
+
+ // search for entry with that language
+ ThesSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
+ LangSvcEntries_Thes *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
+
+ if (!pEntry)
+ {
+#ifdef LINGU_EXCEPTIONS
+ throw IllegalArgumentException();
+#endif
+ }
+ else
+ {
+ OUString aChkWord( rTerm );
+ aChkWord = aChkWord.replace( SVT_HARD_SPACE, ' ' );
+ RemoveHyphens( aChkWord );
+ if (IsIgnoreControlChars( rProperties, GetPropSet() ))
+ RemoveControlChars( aChkWord );
+
+ INT32 nLen = pEntry->aSvcRefs.getLength();
+ DBG_ASSERT( nLen == pEntry->aSvcImplNames.getLength(),
+ "lng : sequence length mismatch");
+ DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
+ "lng : index out of range");
+
+ INT32 i = 0;
+
+ // try already instantiated services first
+ {
+ const Reference< XThesaurus > *pRef = pEntry->aSvcRefs.getConstArray();
+ while (i <= pEntry->nLastTriedSvcIndex
+ && aMeanings.getLength() == 0)
+ {
+ if (pRef[i].is() && pRef[i]->hasLocale( rLocale ))
+ aMeanings = pRef[i]->queryMeanings( aChkWord, rLocale, rProperties );
+ ++i;
+ }
+ }
+
+ // if still no result instantiate new services and try those
+ if (aMeanings.getLength() == 0
+ && pEntry->nLastTriedSvcIndex < nLen - 1)
+ {
+ const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
+ Reference< XThesaurus > *pRef = pEntry->aSvcRefs.getArray();
+
+ Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
+ if (xMgr.is())
+ {
+ // build service initialization argument
+ Sequence< Any > aArgs(1);
+ aArgs.getArray()[0] <<= GetPropSet();
+
+ while (i < nLen && aMeanings.getLength() == 0)
+ {
+ // create specific service via it's implementation name
+ Reference< XThesaurus > xThes;
+ try
+ {
+ xThes = Reference< XThesaurus >(
+ xMgr->createInstanceWithArguments(
+ pImplNames[i], aArgs ), UNO_QUERY );
+ }
+ catch (uno::Exception &)
+ {
+ DBG_ASSERT( 0, "createInstanceWithArguments failed" );
+ }
+ pRef[i] = xThes;
+
+ if (xThes.is() && xThes->hasLocale( rLocale ))
+ aMeanings = xThes->queryMeanings( aChkWord, rLocale, rProperties );
+
+ pEntry->nLastTriedSvcIndex = (INT16) i;
+ ++i;
+ }
+
+ // if language is not supported by any of the services
+ // remove it from the list.
+ if (i == nLen && aMeanings.getLength() == 0)
+ {
+ if (!SvcListHasLanguage( pEntry->aSvcRefs, rLocale ))
+ aSvcMap.erase( nLanguage );
+ }
+ }
+ }
+ }
+
+ return aMeanings;
+}
+
+
+void ThesaurusDispatcher::SetServiceList( const Locale &rLocale,
+ const Sequence< OUString > &rSvcImplNames )
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+
+ INT32 nLen = rSvcImplNames.getLength();
+ if (0 == nLen)
+ // remove entry
+ aSvcMap.erase( nLanguage );
+ else
+ {
+ // modify/add entry
+ LangSvcEntries_Thes *pEntry = aSvcMap[ nLanguage ].get();
+ if (pEntry)
+ {
+ pEntry->Clear();
+ pEntry->aSvcImplNames = rSvcImplNames;
+ pEntry->aSvcRefs = Sequence< Reference < XThesaurus > >( nLen );
+ }
+ else
+ {
+ boost::shared_ptr< LangSvcEntries_Thes > pTmpEntry( new LangSvcEntries_Thes( rSvcImplNames ) );
+ pTmpEntry->aSvcRefs = Sequence< Reference < XThesaurus > >( nLen );
+ aSvcMap[ nLanguage ] = pTmpEntry;
+ }
+ }
+}
+
+
+Sequence< OUString >
+ ThesaurusDispatcher::GetServiceList( const Locale &rLocale ) const
+{
+ MutexGuard aGuard( GetLinguMutex() );
+
+ Sequence< OUString > aRes;
+
+ // search for entry with that language and use data from that
+ INT16 nLanguage = LocaleToLanguage( rLocale );
+ ThesaurusDispatcher *pThis = (ThesaurusDispatcher *) this;
+ const ThesSvcByLangMap_t::iterator aIt( pThis->aSvcMap.find( nLanguage ) );
+ const LangSvcEntries_Thes *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
+ if (pEntry)
+ aRes = pEntry->aSvcImplNames;
+
+ return aRes;
+}
+
+
+LinguDispatcher::DspType ThesaurusDispatcher::GetDspType() const
+{
+ return DSP_THES;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
diff --git a/linguistic/source/thesdsp.hxx b/linguistic/source/thesdsp.hxx
new file mode 100644
index 000000000000..e7eeeff120ee
--- /dev/null
+++ b/linguistic/source/thesdsp.hxx
@@ -0,0 +1,129 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _LINGUISTIC_THESDSP_HXX_
+#define _LINGUISTIC_THESDSP_HXX_
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Sequence.h>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceDisplayName.hpp>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/linguistic2/XThesaurus.hpp>
+
+#include <uno/lbnames.h> // CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
+#include <cppuhelper/implbase1.hxx> // helper for implementations
+#include <cppuhelper/implbase5.hxx> // helper for implementations
+#include <cppuhelper/interfacecontainer.h>
+
+#include <vos/mutex.hxx>
+
+#include <boost/shared_ptr.hpp>
+#include <map>
+
+#include "lngopt.hxx"
+
+
+///////////////////////////////////////////////////////////////////////////
+
+class ThesaurusDispatcher :
+ public cppu::WeakImplHelper1
+ <
+ ::com::sun::star::linguistic2::XThesaurus
+ >,
+ public LinguDispatcher
+{
+ typedef boost::shared_ptr< LangSvcEntries_Thes > LangSvcEntries_Thes_Ptr_t;
+ typedef std::map< LanguageType, LangSvcEntries_Thes_Ptr_t > ThesSvcByLangMap_t;
+ ThesSvcByLangMap_t aSvcMap;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet > xPropSet;
+
+ // disallow copy-constructor and assignment-operator for now
+ ThesaurusDispatcher(const ThesaurusDispatcher &);
+ ThesaurusDispatcher & operator = (const ThesaurusDispatcher &);
+
+ inline ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet >
+ GetPropSet();
+
+ void ClearSvcList();
+
+public:
+ ThesaurusDispatcher();
+ virtual ~ThesaurusDispatcher();
+
+ // XSupportedLocales
+ virtual ::com::sun::star::uno::Sequence<
+ ::com::sun::star::lang::Locale > SAL_CALL
+ getLocales()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL
+ hasLocale( const ::com::sun::star::lang::Locale& aLocale )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ // XThesaurus
+ virtual ::com::sun::star::uno::Sequence<
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::linguistic2::XMeaning > > SAL_CALL
+ queryMeanings( const ::rtl::OUString& aTerm,
+ const ::com::sun::star::lang::Locale& aLocale,
+ const ::com::sun::star::beans::PropertyValues& aProperties )
+ throw(::com::sun::star::lang::IllegalArgumentException,
+ ::com::sun::star::uno::RuntimeException);
+
+ // LinguDispatcher
+ virtual void
+ SetServiceList( const ::com::sun::star::lang::Locale &rLocale,
+ const ::com::sun::star::uno::Sequence<
+ rtl::OUString > &rSvcImplNames );
+ virtual ::com::sun::star::uno::Sequence< rtl::OUString >
+ GetServiceList( const ::com::sun::star::lang::Locale &rLocale ) const;
+ virtual DspType
+ GetDspType() const;
+};
+
+
+inline ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet >
+ ThesaurusDispatcher::GetPropSet()
+{
+ return xPropSet.is() ?
+ xPropSet : xPropSet = linguistic::GetLinguProperties();
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/linguistic/source/thesdta.cxx b/linguistic/source/thesdta.cxx
new file mode 100644
index 000000000000..85a57e000f3e
--- /dev/null
+++ b/linguistic/source/thesdta.cxx
@@ -0,0 +1,83 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_linguistic.hxx"
+#include <tools/debug.hxx>
+#include <osl/mutex.hxx>
+
+#include <misc.hxx>
+
+#include "thesdta.hxx"
+
+//using namespace utl;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::linguistic2;
+using namespace linguistic;
+
+
+namespace linguistic
+{
+
+///////////////////////////////////////////////////////////////////////////
+
+
+ThesaurusMeaning::ThesaurusMeaning(const OUString &rText,
+ const OUString &rLookUpText, INT16 nLookUpLang ) :
+ aText (rText),
+ aLookUpText (rLookUpText),
+ nLookUpLanguage (nLookUpLang)
+{
+}
+
+ThesaurusMeaning::~ThesaurusMeaning()
+{
+}
+
+OUString SAL_CALL
+ ThesaurusMeaning::getMeaning() throw(RuntimeException)
+{
+ MutexGuard aGuard( GetLinguMutex() );
+ return aText;
+}
+
+/*
+uno::Sequence< OUString > SAL_CALL ThesaurusMeaning::querySynonyms()
+ throw(RuntimeException)
+{
+}
+*/
+
+///////////////////////////////////////////////////////////////////////////
+
+} // namespace linguistic
+