1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_linguistic.hxx"
30 
31 #include <tools/fsys.hxx>
32 #include <tools/stream.hxx>
33 #include <tools/urlobj.hxx>
34 #include <unotools/pathoptions.hxx>
35 #include <unotools/useroptions.hxx>
36 #include <unotools/lingucfg.hxx>
37 #include <rtl/instance.hxx>
38 #include <cppuhelper/factory.hxx>	// helper for factories
39 #include <unotools/localfilehelper.hxx>
40 #include <com/sun/star/linguistic2/XConversionDictionaryList.hpp>
41 #include <com/sun/star/linguistic2/XConversionDictionary.hpp>
42 #include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
43 #include <com/sun/star/util/XFlushable.hpp>
44 #include <com/sun/star/lang/Locale.hpp>
45 #ifndef _COM_SUN_STAR_UNO_REFERENCE_HPP_
46 #include <com/sun/star/uno/Reference.h>
47 #endif
48 #include <com/sun/star/registry/XRegistryKey.hpp>
49 #include <com/sun/star/container/XNameContainer.hpp>
50 
51 #include <ucbhelper/content.hxx>
52 
53 #include "convdiclist.hxx"
54 #include "convdic.hxx"
55 #include "hhconvdic.hxx"
56 #include "linguistic/misc.hxx"
57 #include "defs.hxx"
58 
59 //using namespace utl;
60 using namespace osl;
61 using namespace rtl;
62 using namespace com::sun::star;
63 using namespace com::sun::star::lang;
64 using namespace com::sun::star::uno;
65 using namespace com::sun::star::container;
66 using namespace com::sun::star::linguistic2;
67 using namespace linguistic;
68 
69 #define SN_CONV_DICTIONARY_LIST  "com.sun.star.linguistic2.ConversionDictionaryList"
70 
71 
72 ///////////////////////////////////////////////////////////////////////////
73 
74 bool operator == ( const Locale &r1, const Locale &r2 )
75 {
76     return  r1.Language == r2.Language &&
77             r1.Country  == r2.Country  &&
78             r1.Variant  == r2.Variant;
79 }
80 
81 ///////////////////////////////////////////////////////////////////////////
82 
83 String GetConvDicMainURL( const String &rDicName, const String &rDirectoryURL )
84 {
85     // build URL to use for new (persistent) dictionaries
86 
87     String aFullDicName( rDicName );
88     aFullDicName.AppendAscii( CONV_DIC_DOT_EXT );
89 
90     INetURLObject aURLObj;
91     aURLObj.SetSmartProtocol( INET_PROT_FILE );
92     aURLObj.SetSmartURL( rDirectoryURL );
93     aURLObj.Append( aFullDicName, INetURLObject::ENCODE_ALL );
94     DBG_ASSERT(!aURLObj.HasError(), "invalid URL");
95     if (aURLObj.HasError())
96         return String();
97     else
98         return aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
99 }
100 
101 ///////////////////////////////////////////////////////////////////////////
102 
103 class ConvDicNameContainer :
104     public cppu::WeakImplHelper1
105     <
106         ::com::sun::star::container::XNameContainer
107     >
108 {
109     uno::Sequence< uno::Reference< XConversionDictionary > >   aConvDics;
110     ConvDicList     &rConvDicList;
111 
112     // disallow copy-constructor and assignment-operator for now
113     ConvDicNameContainer(const ConvDicNameContainer &);
114     ConvDicNameContainer & operator = (const ConvDicNameContainer &);
115 
116     sal_Int32 GetIndexByName_Impl( const OUString& rName );
117 
118 public:
119     ConvDicNameContainer( ConvDicList &rMyConvDicList );
120     virtual ~ConvDicNameContainer();
121 
122     // XElementAccess
123     virtual ::com::sun::star::uno::Type SAL_CALL getElementType(  ) throw (::com::sun::star::uno::RuntimeException);
124     virtual sal_Bool SAL_CALL hasElements(  ) throw (::com::sun::star::uno::RuntimeException);
125 
126     // XNameAccess
127     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);
128     virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames(  ) throw (::com::sun::star::uno::RuntimeException);
129     virtual sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (::com::sun::star::uno::RuntimeException);
130 
131     // XNameReplace
132     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);
133 
134     // XNameContainer
135     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);
136     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);
137 
138 
139     // looks for conversion dictionaries with the specified extension
140     // in the directory and adds them to the container
141     void AddConvDics( const String &rSearchDirPathURL, const String &rExtension );
142 
143     // calls Flush for the dictionaries that support XFlushable
144     void    FlushDics() const;
145 
146     sal_Int32   GetCount() const    { return aConvDics.getLength(); }
147     uno::Reference< XConversionDictionary > GetByName( const OUString& rName );
148 
149     const uno::Reference< XConversionDictionary >    GetByIndex( sal_Int32 nIdx )
150     {
151         return aConvDics.getConstArray()[nIdx];
152     }
153 };
154 
155 
156 ConvDicNameContainer::ConvDicNameContainer( ConvDicList &rMyConvDicList ) :
157     rConvDicList( rMyConvDicList )
158 {
159 }
160 
161 
162 ConvDicNameContainer::~ConvDicNameContainer()
163 {
164 }
165 
166 
167 void ConvDicNameContainer::FlushDics() const
168 {
169     sal_Int32 nLen = aConvDics.getLength();
170     const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
171     for (sal_Int32 i = 0;  i < nLen;  ++i)
172     {
173         uno::Reference< util::XFlushable > xFlush( pDic[i] , UNO_QUERY );
174         if (xFlush.is())
175         {
176             try
177             {
178                 xFlush->flush();
179             }
180             catch(Exception &)
181             {
182                 DBG_ERROR( "flushing of conversion dictionary failed" );
183             }
184         }
185     }
186 }
187 
188 
189 sal_Int32 ConvDicNameContainer::GetIndexByName_Impl(
190         const OUString& rName )
191 {
192     sal_Int32 nRes = -1;
193     sal_Int32 nLen = aConvDics.getLength();
194     const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
195     for (sal_Int32 i = 0;  i < nLen && nRes == -1;  ++i)
196     {
197         if (rName == pDic[i]->getName())
198             nRes = i;
199     }
200     return nRes;
201 }
202 
203 
204 uno::Reference< XConversionDictionary > ConvDicNameContainer::GetByName(
205         const OUString& rName )
206 {
207     uno::Reference< XConversionDictionary > xRes;
208     sal_Int32 nIdx = GetIndexByName_Impl( rName );
209     if ( nIdx != -1)
210         xRes = aConvDics.getArray()[nIdx];
211     return xRes;
212 }
213 
214 
215 uno::Type SAL_CALL ConvDicNameContainer::getElementType(  )
216     throw (RuntimeException)
217 {
218     MutexGuard  aGuard( GetLinguMutex() );
219     return uno::Type( ::getCppuType( (uno::Reference< XConversionDictionary > *) 0) );
220 }
221 
222 
223 sal_Bool SAL_CALL ConvDicNameContainer::hasElements(  )
224     throw (RuntimeException)
225 {
226     MutexGuard  aGuard( GetLinguMutex() );
227     return aConvDics.getLength() > 0;
228 }
229 
230 
231 uno::Any SAL_CALL ConvDicNameContainer::getByName( const OUString& rName )
232     throw (NoSuchElementException, WrappedTargetException, RuntimeException)
233 {
234     MutexGuard  aGuard( GetLinguMutex() );
235     uno::Reference< XConversionDictionary > xRes( GetByName( rName ) );
236     if (!xRes.is())
237         throw NoSuchElementException();
238     return makeAny( xRes );
239 }
240 
241 
242 uno::Sequence< OUString > SAL_CALL ConvDicNameContainer::getElementNames(  )
243     throw (RuntimeException)
244 {
245     MutexGuard  aGuard( GetLinguMutex() );
246 
247     sal_Int32 nLen = aConvDics.getLength();
248     uno::Sequence< OUString > aRes( nLen );
249     OUString *pName = aRes.getArray();
250     const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
251     for (sal_Int32 i = 0;  i < nLen;  ++i)
252         pName[i] = pDic[i]->getName();
253     return aRes;
254 }
255 
256 
257 sal_Bool SAL_CALL ConvDicNameContainer::hasByName( const OUString& rName )
258     throw (RuntimeException)
259 {
260     MutexGuard  aGuard( GetLinguMutex() );
261     return GetByName( rName ).is();
262 }
263 
264 
265 void SAL_CALL ConvDicNameContainer::replaceByName(
266         const OUString& rName,
267         const uno::Any& rElement )
268     throw (IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException)
269 {
270     MutexGuard  aGuard( GetLinguMutex() );
271 
272     sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
273     if (nRplcIdx == -1)
274         throw NoSuchElementException();
275     uno::Reference< XConversionDictionary > xNew;
276     rElement >>= xNew;
277     if (!xNew.is() || xNew->getName() != rName)
278         throw IllegalArgumentException();
279     aConvDics.getArray()[ nRplcIdx ] = xNew;
280 }
281 
282 
283 void SAL_CALL ConvDicNameContainer::insertByName(
284         const OUString& rName,
285         const Any& rElement )
286     throw (IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException)
287 {
288     MutexGuard  aGuard( GetLinguMutex() );
289 
290     if (GetByName( rName ).is())
291         throw ElementExistException();
292     uno::Reference< XConversionDictionary > xNew;
293     rElement >>= xNew;
294     if (!xNew.is() || xNew->getName() != rName)
295         throw IllegalArgumentException();
296 
297     sal_Int32 nLen = aConvDics.getLength();
298     aConvDics.realloc( nLen + 1 );
299     aConvDics.getArray()[ nLen ] = xNew;
300 }
301 
302 
303 void SAL_CALL ConvDicNameContainer::removeByName( const OUString& rName )
304     throw (NoSuchElementException, WrappedTargetException, RuntimeException)
305 {
306     MutexGuard  aGuard( GetLinguMutex() );
307 
308     sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
309     if (nRplcIdx == -1)
310         throw NoSuchElementException();
311 
312 	// physically remove dictionary
313     uno::Reference< XConversionDictionary > xDel = aConvDics.getArray()[nRplcIdx];
314 	String aName( xDel->getName() );
315     String aDicMainURL( GetConvDicMainURL( aName, GetDictionaryWriteablePath() ) );
316 	INetURLObject aObj( aDicMainURL );
317 	DBG_ASSERT( aObj.GetProtocol() == INET_PROT_FILE, "+HangulHanjaOptionsDialog::OkHdl(): non-file URLs cannot be deleted" );
318 	if( aObj.GetProtocol() == INET_PROT_FILE )
319 	{
320 		try
321 		{
322 			::ucbhelper::Content	aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ),
323 									uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () );
324 			aCnt.executeCommand( OUString::createFromAscii( "delete" ), makeAny( sal_Bool( sal_True ) ) );
325 		}
326 		catch( ::com::sun::star::ucb::CommandAbortedException& )
327 		{
328 			DBG_ERRORFILE( "HangulHanjaOptionsDialog::OkHdl(): CommandAbortedException" );
329 		}
330 		catch( ... )
331 		{
332 			DBG_ERRORFILE( "HangulHanjaOptionsDialog::OkHdl(): Any other exception" );
333 		}
334 	}
335 
336     sal_Int32 nLen = aConvDics.getLength();
337     uno::Reference< XConversionDictionary > *pDic = aConvDics.getArray();
338     for (sal_Int32 i = nRplcIdx;  i < nLen - 1;  ++i)
339         pDic[i] = pDic[i + 1];
340     aConvDics.realloc( nLen - 1 );
341 }
342 
343 
344 void ConvDicNameContainer::AddConvDics(
345         const String &rSearchDirPathURL,
346         const String &rExtension )
347 {
348     const Sequence< OUString > aDirCnt(
349                 utl::LocalFileHelper::GetFolderContents( rSearchDirPathURL, sal_False ) );
350     const OUString *pDirCnt = aDirCnt.getConstArray();
351     sal_Int32 nEntries = aDirCnt.getLength();
352 
353     for (sal_Int32 i = 0;  i < nEntries;  ++i)
354     {
355         String  aURL( pDirCnt[i] );
356 
357         xub_StrLen nPos  = aURL.SearchBackward('.');
358         String  aExt(aURL.Copy(nPos + 1));
359         aExt.ToLowerAscii();
360         String  aSearchExt( rExtension );
361         aSearchExt.ToLowerAscii();
362         if(aExt != aSearchExt)
363             continue;          // skip other files
364 
365         sal_Int16 nLang;
366         sal_Int16 nConvType;
367         if (IsConvDic( aURL, nLang, nConvType ))
368         {
369             // get decoded dictionary file name
370             INetURLObject aURLObj( aURL );
371             String aDicName = aURLObj.getBase( INetURLObject::LAST_SEGMENT,
372                         true, INetURLObject::DECODE_WITH_CHARSET,
373                         RTL_TEXTENCODING_UTF8 );
374 
375             uno::Reference < XConversionDictionary > xDic;
376             if (nLang == LANGUAGE_KOREAN &&
377                 nConvType == ConversionDictionaryType::HANGUL_HANJA)
378             {
379                 xDic = new HHConvDic( aDicName, aURL );
380             }
381             else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
382                       nConvType == ConversionDictionaryType::SCHINESE_TCHINESE)
383             {
384                 xDic = new ConvDic( aDicName, nLang, nConvType, sal_False, aURL );
385             }
386 
387             if (xDic.is())
388             {
389                 uno::Any aAny;
390                 aAny <<= xDic;
391                 insertByName( xDic->getName(), aAny );
392             }
393         }
394     }
395 }
396 
397 ///////////////////////////////////////////////////////////////////////////
398 
399 namespace
400 {
401     struct StaticConvDicList : public rtl::StaticWithInit<
402         uno::Reference<XInterface>, StaticConvDicList> {
403         uno::Reference<XInterface> operator () () {
404             return (cppu::OWeakObject *) new ConvDicList;
405         }
406     };
407 }
408 
409 
410 void ConvDicList::MyAppExitListener::AtExit()
411 {
412     rMyDicList.FlushDics();
413     StaticConvDicList::get().clear();
414 }
415 
416 ConvDicList::ConvDicList() :
417     aEvtListeners( GetLinguMutex() )
418 {
419     pNameContainer = 0;
420     bDisposing = sal_False;
421 
422     pExitListener = new MyAppExitListener( *this );
423     xExitListener = pExitListener;
424     pExitListener->Activate();
425 }
426 
427 
428 ConvDicList::~ConvDicList()
429 {
430     // NameContainer will deleted when the reference xNameContainer
431     // is destroyed.
432     // delete pNameContainer;
433 
434 	if (!bDisposing && pNameContainer)
435 		pNameContainer->FlushDics();
436 
437     pExitListener->Deactivate();
438 }
439 
440 
441 void ConvDicList::FlushDics()
442 {
443     // check only pointer to avoid creating the container when
444     // the dictionaries were not accessed yet
445     if (pNameContainer)
446         pNameContainer->FlushDics();
447 }
448 
449 
450 ConvDicNameContainer & ConvDicList::GetNameContainer()
451 {
452     if (!pNameContainer)
453     {
454         pNameContainer = new ConvDicNameContainer( *this );
455         pNameContainer->AddConvDics( GetDictionaryWriteablePath(),
456                                      A2OU( CONV_DIC_EXT ) );
457         xNameContainer = pNameContainer;
458 
459         // access list of text conversion dictionaries to activate
460         SvtLinguOptions aOpt;
461         SvtLinguConfig().GetOptions( aOpt );
462         sal_Int32 nLen = aOpt.aActiveConvDics.getLength();
463         const OUString *pActiveConvDics = aOpt.aActiveConvDics.getConstArray();
464         for (sal_Int32 i = 0;  i < nLen;  ++i)
465         {
466             uno::Reference< XConversionDictionary > xDic =
467                     pNameContainer->GetByName( pActiveConvDics[i] );
468             if (xDic.is())
469                 xDic->setActive( sal_True );
470         }
471 
472 		// since there is no UI to active/deactivate the dictionaries
473 		// for chinese text conversion they should be activated by default
474 		uno::Reference< XConversionDictionary > xS2TDic(
475                     pNameContainer->GetByName( A2OU("ChineseS2T") ), UNO_QUERY );
476 		uno::Reference< XConversionDictionary > xT2SDic(
477                     pNameContainer->GetByName( A2OU("ChineseT2S") ), UNO_QUERY );
478             if (xS2TDic.is())
479                 xS2TDic->setActive( sal_True );
480             if (xT2SDic.is())
481                 xT2SDic->setActive( sal_True );
482 
483     }
484     return *pNameContainer;
485 }
486 
487 
488 uno::Reference< container::XNameContainer > SAL_CALL ConvDicList::getDictionaryContainer(  ) throw (RuntimeException)
489 {
490     MutexGuard  aGuard( GetLinguMutex() );
491     GetNameContainer();
492     DBG_ASSERT( xNameContainer.is(), "missing name container" );
493     return xNameContainer;
494 }
495 
496 
497 uno::Reference< XConversionDictionary > SAL_CALL ConvDicList::addNewDictionary(
498         const OUString& rName,
499         const Locale& rLocale,
500         sal_Int16 nConvDicType )
501     throw (NoSupportException, ElementExistException, RuntimeException)
502 {
503     MutexGuard  aGuard( GetLinguMutex() );
504 
505     sal_Int16 nLang = LocaleToLanguage( rLocale );
506 
507     if (GetNameContainer().hasByName( rName ))
508         throw ElementExistException();
509 
510     uno::Reference< XConversionDictionary > xRes;
511     String aDicMainURL( GetConvDicMainURL( rName, GetDictionaryWriteablePath() ) );
512     if (nLang == LANGUAGE_KOREAN &&
513         nConvDicType == ConversionDictionaryType::HANGUL_HANJA)
514     {
515         xRes = new HHConvDic( rName, aDicMainURL );
516     }
517     else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
518               nConvDicType == ConversionDictionaryType::SCHINESE_TCHINESE)
519     {
520         xRes = new ConvDic( rName, nLang, nConvDicType, sal_False, aDicMainURL );
521     }
522 
523     if (!xRes.is())
524         throw NoSupportException();
525     else
526     {
527         xRes->setActive( sal_True );
528         uno::Any aAny;
529         aAny <<= xRes;
530         GetNameContainer().insertByName( rName, aAny );
531     }
532     return xRes;
533 }
534 
535 
536 uno::Sequence< OUString > SAL_CALL ConvDicList::queryConversions(
537         const OUString& rText,
538         sal_Int32 nStartPos,
539         sal_Int32 nLength,
540         const Locale& rLocale,
541         sal_Int16 nConversionDictionaryType,
542         ConversionDirection eDirection,
543         sal_Int32 nTextConversionOptions )
544     throw (IllegalArgumentException, NoSupportException, RuntimeException)
545 {
546     MutexGuard  aGuard( GetLinguMutex() );
547 
548     /*sal_Int16 nLang = LocaleToLanguage( rLocale );*/
549 
550     sal_Int32 nCount = 0;
551     uno::Sequence< OUString > aRes( 20 );
552     OUString *pRes = aRes.getArray();
553 
554 	sal_Bool bSupported = sal_False;
555     sal_Int32 nLen = GetNameContainer().GetCount();
556     for (sal_Int32 i = 0;  i < nLen;  ++i)
557     {
558         const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
559 		sal_Bool bMatch =   xDic.is()  &&
560 							xDic->getLocale() == rLocale  &&
561 							xDic->getConversionType() == nConversionDictionaryType;
562 		bSupported |= bMatch;
563         if (bMatch  &&  xDic->isActive())
564         {
565             Sequence< OUString > aNewConv( xDic->getConversions(
566                                 rText, nStartPos, nLength,
567                                 eDirection, nTextConversionOptions ) );
568             sal_Int32 nNewLen = aNewConv.getLength();
569             if (nNewLen > 0)
570             {
571                 if (nCount + nNewLen > aRes.getLength())
572                 {
573                     aRes.realloc( nCount + nNewLen + 20 );
574                     pRes = aRes.getArray();
575                 }
576                 const OUString *pNewConv = aNewConv.getConstArray();
577                 for (sal_Int32 k = 0;  k < nNewLen;  ++k)
578                     pRes[nCount++] = pNewConv[k];
579             }
580         }
581     }
582 
583 	if (!bSupported)
584         throw NoSupportException();
585 
586     aRes.realloc( nCount );
587     return aRes;
588 }
589 
590 
591 sal_Int16 SAL_CALL ConvDicList::queryMaxCharCount(
592         const Locale& rLocale,
593         sal_Int16 nConversionDictionaryType,
594         ConversionDirection eDirection )
595     throw (RuntimeException)
596 {
597     MutexGuard  aGuard( GetLinguMutex() );
598 
599     sal_Int16 nRes = 0;
600     GetNameContainer();
601     sal_Int32 nLen = GetNameContainer().GetCount();
602     for (sal_Int32 i = 0;  i < nLen;  ++i)
603     {
604         const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
605         if (xDic.is()  &&
606             xDic->getLocale() == rLocale  &&
607             xDic->getConversionType() == nConversionDictionaryType)
608         {
609             sal_Int16 nC = xDic->getMaxCharCount( eDirection );
610             if (nC > nRes)
611                 nRes = nC;
612         }
613     }
614     return nRes;
615 }
616 
617 
618 void SAL_CALL ConvDicList::dispose(  )
619     throw (RuntimeException)
620 {
621     MutexGuard  aGuard( GetLinguMutex() );
622     if (!bDisposing)
623     {
624         bDisposing = sal_True;
625         EventObject aEvtObj( (XConversionDictionaryList *) this );
626         aEvtListeners.disposeAndClear( aEvtObj );
627 
628         FlushDics();
629     }
630 }
631 
632 
633 void SAL_CALL ConvDicList::addEventListener(
634         const uno::Reference< XEventListener >& rxListener )
635     throw (RuntimeException)
636 {
637     MutexGuard  aGuard( GetLinguMutex() );
638     if (!bDisposing && rxListener.is())
639         aEvtListeners.addInterface( rxListener );
640 }
641 
642 
643 void SAL_CALL ConvDicList::removeEventListener(
644         const uno::Reference< XEventListener >& rxListener )
645     throw (RuntimeException)
646 {
647     MutexGuard  aGuard( GetLinguMutex() );
648     if (!bDisposing && rxListener.is())
649         aEvtListeners.removeInterface( rxListener );
650 }
651 
652 
653 OUString SAL_CALL ConvDicList::getImplementationName(  )
654     throw (RuntimeException)
655 {
656     MutexGuard  aGuard( GetLinguMutex() );
657     return getImplementationName_Static();
658 }
659 
660 
661 sal_Bool SAL_CALL ConvDicList::supportsService( const OUString& rServiceName )
662     throw (RuntimeException)
663 {
664     MutexGuard  aGuard( GetLinguMutex() );
665     return rServiceName.equalsAscii( SN_CONV_DICTIONARY_LIST );
666 }
667 
668 
669 uno::Sequence< OUString > SAL_CALL ConvDicList::getSupportedServiceNames(  )
670     throw (RuntimeException)
671 {
672     MutexGuard  aGuard( GetLinguMutex() );
673     return getSupportedServiceNames_Static();
674 }
675 
676 
677 uno::Sequence< OUString > ConvDicList::getSupportedServiceNames_Static()
678     throw()
679 {
680     uno::Sequence< OUString > aSNS( 1 );
681     aSNS.getArray()[0] = A2OU( SN_CONV_DICTIONARY_LIST );
682     return aSNS;
683 }
684 
685 
686 ///////////////////////////////////////////////////////////////////////////
687 
688 uno::Reference< uno::XInterface > SAL_CALL ConvDicList_CreateInstance(
689         const uno::Reference< XMultiServiceFactory > & /*rSMgr*/ )
690     throw(Exception)
691 {
692     return StaticConvDicList::get();
693 }
694 
695 void * SAL_CALL ConvDicList_getFactory(
696         const sal_Char * pImplName,
697         XMultiServiceFactory * pServiceManager, void *  )
698 {
699     void * pRet = 0;
700     if ( !ConvDicList::getImplementationName_Static().compareToAscii( pImplName ) )
701     {
702         uno::Reference< XSingleServiceFactory > xFactory =
703             cppu::createOneInstanceFactory(
704                 pServiceManager,
705                 ConvDicList::getImplementationName_Static(),
706                 ConvDicList_CreateInstance,
707                 ConvDicList::getSupportedServiceNames_Static());
708         // acquire, because we return an interface pointer instead of a reference
709         xFactory->acquire();
710         pRet = xFactory.get();
711     }
712     return pRet;
713 }
714 
715 ///////////////////////////////////////////////////////////////////////////
716 
717