xref: /aoo42x/main/linguistic/source/convdic.cxx (revision cdf0e10c)
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 <cppuhelper/factory.hxx>
32 #include <i18npool/lang.h>
33 #include <osl/mutex.hxx>
34 #include <tools/debug.hxx>
35 #include <tools/fsys.hxx>
36 #include <tools/stream.hxx>
37 #include <tools/stream.hxx>
38 #include <tools/string.hxx>
39 #include <tools/urlobj.hxx>
40 #include <ucbhelper/content.hxx>
41 #include <unotools/processfactory.hxx>
42 #include <unotools/streamwrap.hxx>
43 #include <unotools/ucbstreamhelper.hxx>
44 
45 #include <com/sun/star/linguistic2/XConversionDictionary.hpp>
46 #include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
47 #include <com/sun/star/linguistic2/XConversionPropertyType.hpp>
48 #include <com/sun/star/linguistic2/ConversionPropertyType.hpp>
49 #include <com/sun/star/util/XFlushable.hpp>
50 #include <com/sun/star/lang/Locale.hpp>
51 #include <com/sun/star/lang/EventObject.hpp>
52 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
53 #include <com/sun/star/uno/Reference.h>
54 #include <com/sun/star/registry/XRegistryKey.hpp>
55 #include <com/sun/star/util/XFlushListener.hpp>
56 #include <com/sun/star/io/XActiveDataSource.hpp>
57 #include <com/sun/star/io/XActiveDataSource.hpp>
58 #include <com/sun/star/io/XInputStream.hpp>
59 #include <com/sun/star/io/XOutputStream.hpp>
60 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
61 #include <com/sun/star/document/XFilter.hpp>
62 #include <com/sun/star/beans/PropertyValue.hpp>
63 #include <com/sun/star/xml/sax/InputSource.hpp>
64 #include <com/sun/star/xml/sax/XParser.hpp>
65 
66 
67 #include "convdic.hxx"
68 #include "convdicxml.hxx"
69 #include "linguistic/misc.hxx"
70 #include "defs.hxx"
71 
72 using namespace std;
73 using namespace utl;
74 using namespace osl;
75 using namespace rtl;
76 using namespace com::sun::star;
77 using namespace com::sun::star::lang;
78 using namespace com::sun::star::uno;
79 using namespace com::sun::star::linguistic2;
80 using namespace linguistic;
81 
82 #define SN_CONV_DICTIONARY      "com.sun.star.linguistic2.ConversionDictionary"
83 #define SN_HCD_CONV_DICTIONARY  "com.sun.star.linguistic2.HangulHanjaConversionDictionary"
84 
85 
86 ///////////////////////////////////////////////////////////////////////////
87 void ReadThroughDic( const String &rMainURL, ConvDicXMLImport &rImport )
88 {
89     if (rMainURL.Len() == 0)
90         return;
91     DBG_ASSERT(!INetURLObject( rMainURL ).HasError(), "invalid URL");
92 
93     uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() );
94 
95     // get xInputStream stream
96     uno::Reference< io::XInputStream > xIn;
97     try
98     {
99         uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance(
100                 A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW );
101         xIn = xAccess->openFileRead( rMainURL );
102     }
103     catch (uno::Exception & e)
104     {
105         DBG_ASSERT( 0, "failed to get input stream" );
106         (void) e;
107     }
108     if (!xIn.is())
109         return;
110 
111     SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xIn ) );
112 
113     sal_uLong nError = sal::static_int_cast< sal_uLong >(-1);
114 
115     // prepare ParserInputSource
116     xml::sax::InputSource aParserInput;
117     aParserInput.aInputStream = xIn;
118 
119     // get parser
120 	uno::Reference< xml::sax::XParser > xParser;
121 	try
122 	{
123 		xParser = uno::Reference< xml::sax::XParser >( xServiceFactory->createInstance(
124             A2OU( "com.sun.star.xml.sax.Parser" ) ), UNO_QUERY );
125 	}
126 	catch (uno::Exception &)
127 	{
128 	}
129 	DBG_ASSERT( xParser.is(), "Can't create parser" );
130     if (!xParser.is())
131         return;
132 
133     // get filter
134     //ConvDicXMLImport *pImport = new ConvDicXMLImport( this, rMainURL );
135     //!! keep a reference until everything is done to
136     //!! ensure the proper lifetime of the object
137     uno::Reference < xml::sax::XDocumentHandler > xFilter(
138             (xml::sax::XExtendedDocumentHandler *) &rImport, UNO_QUERY );
139 
140     // connect parser and filter
141     xParser->setDocumentHandler( xFilter );
142 
143     // finally, parser the stream
144     try
145     {
146         xParser->parseStream( aParserInput );   // implicitly calls ConvDicXMLImport::CreateContext
147         if (rImport.GetSuccess())
148             nError = 0;
149     }
150     catch( xml::sax::SAXParseException& )
151     {
152 //        if( bEncrypted )
153 //            nError = ERRCODE_SFX_WRONGPASSWORD;
154     }
155     catch( xml::sax::SAXException& )
156     {
157 //        if( bEncrypted )
158 //            nError = ERRCODE_SFX_WRONGPASSWORD;
159     }
160     catch( io::IOException& )
161     {
162     }
163 }
164 
165 sal_Bool IsConvDic( const String &rFileURL, sal_Int16 &nLang, sal_Int16 &nConvType )
166 {
167     sal_Bool bRes = sal_False;
168 
169     if (rFileURL.Len() == 0)
170         return bRes;
171 
172     // check if file extension matches CONV_DIC_EXT
173     String aExt;
174     xub_StrLen nPos = rFileURL.SearchBackward( '.' );
175     if (STRING_NOTFOUND != nPos)
176         aExt = rFileURL.Copy( nPos + 1 );
177     aExt.ToLowerAscii();
178     if (!aExt.EqualsAscii( CONV_DIC_EXT ))
179         return bRes;
180 
181     // first argument being 0 should stop the file from being parsed
182     // up to the end (reading all entries) when the required
183     // data (language, conversion type) is found.
184     ConvDicXMLImport *pImport = new ConvDicXMLImport( 0, rFileURL );
185 
186     //!! keep a first reference to ensure the lifetime of the object !!
187     uno::Reference< XInterface > xRef( (document::XFilter *) pImport, UNO_QUERY );
188 
189     ReadThroughDic( rFileURL, *pImport );    // will implicitly add the entries
190     bRes =  pImport->GetLanguage() != LANGUAGE_NONE &&
191             pImport->GetConversionType() != -1;
192     DBG_ASSERT( bRes, "conversion dictionary corrupted?" );
193 
194     if (bRes)
195     {
196         nLang       = pImport->GetLanguage();
197         nConvType   = pImport->GetConversionType();
198     }
199 
200     return bRes;
201 }
202 
203 
204 ///////////////////////////////////////////////////////////////////////////
205 
206 ConvDic::ConvDic(
207         const String &rName,
208         sal_Int16 nLang,
209         sal_Int16 nConvType,
210              sal_Bool bBiDirectional,
211         const String &rMainURL) :
212     aFlushListeners( GetLinguMutex() )
213 {
214     aName           = rName;
215     nLanguage       = nLang;
216     nConversionType = nConvType;
217     aMainURL        = rMainURL;
218 
219     if (bBiDirectional)
220         pFromRight = std::auto_ptr< ConvMap >( new ConvMap );
221     if (nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL)
222         pConvPropType = std::auto_ptr< PropTypeMap >( new PropTypeMap );
223 
224     nMaxLeftCharCount = nMaxRightCharCount = 0;
225     bMaxCharCountIsValid = sal_True;
226 
227     bNeedEntries = sal_True;
228     bIsModified  = bIsActive = sal_False;
229     bIsReadonly = sal_False;
230 
231     if( rMainURL.Len() > 0 )
232     {
233         sal_Bool bExists = sal_False;
234         bIsReadonly = IsReadOnly( rMainURL, &bExists );
235 
236         if( !bExists )  // new empty dictionary
237         {
238             bNeedEntries = sal_False;
239             //! create physical representation of an **empty** dictionary
240             //! that could be found by the dictionary-list implementation
241             // (Note: empty dictionaries are not just empty files!)
242             Save();
243             bIsReadonly = IsReadOnly( rMainURL );   // will be sal_False if Save was succesfull
244         }
245     }
246     else
247     {
248         bNeedEntries = sal_False;
249     }
250 }
251 
252 
253 ConvDic::~ConvDic()
254 {
255 }
256 
257 
258 void ConvDic::Load()
259 {
260     DBG_ASSERT( !bIsModified, "dictionary is modified. Really do 'Load'?" );
261 
262     //!! prevent function from being called recursively via HasEntry, AddEntry
263     bNeedEntries = sal_False;
264     ConvDicXMLImport *pImport = new ConvDicXMLImport( this, aMainURL );
265     //!! keep a first reference to ensure the lifetime of the object !!
266     uno::Reference< XInterface > xRef( (document::XFilter *) pImport, UNO_QUERY );
267     ReadThroughDic( aMainURL, *pImport );    // will implicitly add the entries
268     bIsModified = sal_False;
269 }
270 
271 
272 void ConvDic::Save()
273 {
274     DBG_ASSERT( !bNeedEntries, "saving while entries missing" );
275     if (aMainURL.Len() == 0 || bNeedEntries)
276         return;
277     DBG_ASSERT(!INetURLObject( aMainURL ).HasError(), "invalid URL");
278 
279     uno::Reference< lang::XMultiServiceFactory > xServiceFactory( utl::getProcessServiceFactory() );
280 
281     // get XOutputStream stream
282     uno::Reference< io::XStream > xStream;
283     try
284     {
285         uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance(
286                 A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW );
287         xStream = xAccess->openFileReadWrite( aMainURL );
288     }
289     catch (uno::Exception & e)
290     {
291         DBG_ASSERT( 0, "failed to get input stream" );
292         (void) e;
293     }
294     if (!xStream.is())
295         return;
296 
297     SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) );
298 
299     // get XML writer
300     uno::Reference< io::XActiveDataSource > xSaxWriter;
301     if (xServiceFactory.is())
302     {
303 		try
304 		{
305 			xSaxWriter = uno::Reference< io::XActiveDataSource >(
306                 	xServiceFactory->createInstance(
307 					OUString::createFromAscii( "com.sun.star.xml.sax.Writer" ) ), UNO_QUERY );
308 		}
309 		catch (uno::Exception &)
310 		{
311 		}
312     }
313     DBG_ASSERT( xSaxWriter.is(), "can't instantiate XML writer" );
314 
315     if (xSaxWriter.is() && xStream.is())
316     {
317         // connect XML writer to output stream
318         xSaxWriter->setOutputStream( xStream->getOutputStream() );
319 
320         // prepare arguments (prepend doc handler to given arguments)
321         uno::Reference< xml::sax::XDocumentHandler > xDocHandler( xSaxWriter, UNO_QUERY );
322         ConvDicXMLExport *pExport = new ConvDicXMLExport( *this, aMainURL, xDocHandler );
323         //!! keep a first(!) reference until everything is done to
324         //!! ensure the proper lifetime of the object
325         uno::Reference< document::XFilter > aRef( (document::XFilter *) pExport );
326         sal_Bool bRet = pExport->Export();     // write entries to file
327         DBG_ASSERT( !pStream->GetError(), "I/O error while writing to stream" );
328         if (bRet)
329             bIsModified = sal_False;
330     }
331     DBG_ASSERT( !bIsModified, "dictionary still modified after save. Save failed?" );
332 }
333 
334 
335 ConvMap::iterator ConvDic::GetEntry( ConvMap &rMap, const rtl::OUString &rFirstText, const rtl::OUString &rSecondText )
336 {
337     pair< ConvMap::iterator, ConvMap::iterator > aRange =
338             rMap.equal_range( rFirstText );
339     ConvMap::iterator aPos = rMap.end();
340     for (ConvMap::iterator aIt = aRange.first;
341          aIt != aRange.second  &&  aPos == rMap.end();
342          ++aIt)
343     {
344         if ((*aIt).second == rSecondText)
345             aPos = aIt;
346     }
347     return aPos;
348 }
349 
350 
351 sal_Bool ConvDic::HasEntry( const OUString &rLeftText, const OUString &rRightText )
352 {
353     if (bNeedEntries)
354         Load();
355     ConvMap::iterator aIt = GetEntry( aFromLeft, rLeftText, rRightText );
356     return aIt != aFromLeft.end();
357 }
358 
359 
360 void ConvDic::AddEntry( const OUString &rLeftText, const OUString &rRightText )
361 {
362     if (bNeedEntries)
363         Load();
364 
365     DBG_ASSERT(!HasEntry( rLeftText, rRightText), "entry already exists" );
366     aFromLeft .insert( ConvMap::value_type( rLeftText, rRightText ) );
367     if (pFromRight.get())
368         pFromRight->insert( ConvMap::value_type( rRightText, rLeftText ) );
369 
370     if (bMaxCharCountIsValid)
371     {
372         if (rLeftText.getLength() > nMaxLeftCharCount)
373             nMaxLeftCharCount   = (sal_Int16) rLeftText.getLength();
374         if (pFromRight.get() && rRightText.getLength() > nMaxRightCharCount)
375             nMaxRightCharCount  = (sal_Int16) rRightText.getLength();
376     }
377 
378     bIsModified = sal_True;
379 }
380 
381 
382 void ConvDic::RemoveEntry( const OUString &rLeftText, const OUString &rRightText )
383 {
384     if (bNeedEntries)
385         Load();
386 
387     ConvMap::iterator aLeftIt  = GetEntry( aFromLeft,  rLeftText,  rRightText );
388     DBG_ASSERT( aLeftIt  != aFromLeft.end(),  "left map entry missing" );
389     aFromLeft .erase( aLeftIt );
390 
391     if (pFromRight.get())
392     {
393         ConvMap::iterator aRightIt = GetEntry( *pFromRight, rRightText, rLeftText );
394         DBG_ASSERT( aRightIt != pFromRight->end(), "right map entry missing" );
395         pFromRight->erase( aRightIt );
396     }
397 
398     bIsModified = sal_True;
399     bMaxCharCountIsValid = sal_False;
400 }
401 
402 
403 OUString SAL_CALL ConvDic::getName(  )
404     throw (RuntimeException)
405 {
406     MutexGuard  aGuard( GetLinguMutex() );
407     return aName;
408 }
409 
410 
411 Locale SAL_CALL ConvDic::getLocale(  )
412     throw (RuntimeException)
413 {
414     MutexGuard  aGuard( GetLinguMutex() );
415     return CreateLocale( nLanguage );
416 }
417 
418 
419 sal_Int16 SAL_CALL ConvDic::getConversionType(  )
420     throw (RuntimeException)
421 {
422     MutexGuard  aGuard( GetLinguMutex() );
423     return nConversionType;
424 }
425 
426 
427 void SAL_CALL ConvDic::setActive( sal_Bool bActivate )
428     throw (RuntimeException)
429 {
430     MutexGuard  aGuard( GetLinguMutex() );
431     bIsActive = bActivate;
432 }
433 
434 
435 sal_Bool SAL_CALL ConvDic::isActive(  )
436     throw (RuntimeException)
437 {
438     MutexGuard  aGuard( GetLinguMutex() );
439     return bIsActive;
440 }
441 
442 
443 void SAL_CALL ConvDic::clear(  )
444     throw (RuntimeException)
445 {
446     MutexGuard  aGuard( GetLinguMutex() );
447     aFromLeft .clear();
448     if (pFromRight.get())
449         pFromRight->clear();
450     bNeedEntries    = sal_False;
451     bIsModified     = sal_True;
452     nMaxLeftCharCount       = 0;
453     nMaxRightCharCount      = 0;
454     bMaxCharCountIsValid    = sal_True;
455 }
456 
457 
458 uno::Sequence< OUString > SAL_CALL ConvDic::getConversions(
459         const OUString& aText,
460         sal_Int32 nStartPos,
461         sal_Int32 nLength,
462         ConversionDirection eDirection,
463         sal_Int32 /*nTextConversionOptions*/ )
464     throw (IllegalArgumentException, RuntimeException)
465 {
466     MutexGuard  aGuard( GetLinguMutex() );
467 
468     if (!pFromRight.get() && eDirection == ConversionDirection_FROM_RIGHT)
469         return uno::Sequence< OUString >();
470 
471     if (bNeedEntries)
472         Load();
473 
474     OUString aLookUpText( aText.copy(nStartPos, nLength) );
475     ConvMap &rConvMap = eDirection == ConversionDirection_FROM_LEFT ?
476                                 aFromLeft : *pFromRight;
477     pair< ConvMap::iterator, ConvMap::iterator > aRange =
478             rConvMap.equal_range( aLookUpText );
479 
480     sal_Int32 nCount = 0;
481     ConvMap::iterator aIt;
482     for (aIt = aRange.first;  aIt != aRange.second;  ++aIt)
483         ++nCount;
484 
485     uno::Sequence< OUString > aRes( nCount );
486     OUString *pRes = aRes.getArray();
487     sal_Int32 i = 0;
488     for (aIt = aRange.first;  aIt != aRange.second;  ++aIt)
489         pRes[i++] = (*aIt).second;
490 
491     return aRes;
492 }
493 
494 
495 static sal_Bool lcl_SeqHasEntry(
496     const OUString *pSeqStart,  // first element to check
497     sal_Int32 nToCheck,             // number of elements to check
498     const OUString &rText)
499 {
500     sal_Bool bRes = sal_False;
501     if (pSeqStart && nToCheck > 0)
502     {
503         const OUString *pDone = pSeqStart + nToCheck;   // one behind last to check
504         while (!bRes && pSeqStart != pDone)
505         {
506             if (*pSeqStart++ == rText)
507                 bRes = sal_True;
508         }
509     }
510     return bRes;
511 }
512 
513 uno::Sequence< OUString > SAL_CALL ConvDic::getConversionEntries(
514         ConversionDirection eDirection )
515     throw (RuntimeException)
516 {
517     MutexGuard  aGuard( GetLinguMutex() );
518 
519     if (!pFromRight.get() && eDirection == ConversionDirection_FROM_RIGHT)
520         return uno::Sequence< OUString >();
521 
522     if (bNeedEntries)
523         Load();
524 
525     ConvMap &rConvMap = eDirection == ConversionDirection_FROM_LEFT ?
526                                 aFromLeft : *pFromRight;
527     uno::Sequence< OUString > aRes( rConvMap.size() );
528     OUString *pRes = aRes.getArray();
529     ConvMap::iterator aIt = rConvMap.begin();
530     sal_Int32 nIdx = 0;
531     while (aIt != rConvMap.end())
532     {
533         OUString aCurEntry( (*aIt).first );
534         // skip duplicate entries ( duplicate = duplicate entries
535 		// respective to the evaluated side (FROM_LEFT or FROM_RIGHT).
536 		// Thus if FROM_LEFT is evaluated for pairs (A,B) and (A,C)
537 		// only one entry for A will be returned in the result)
538         if (nIdx == 0 || !lcl_SeqHasEntry( pRes, nIdx, aCurEntry ))
539             pRes[ nIdx++ ] = aCurEntry;
540         ++aIt;
541     }
542 	aRes.realloc( nIdx );
543 
544     return aRes;
545 }
546 
547 
548 void SAL_CALL ConvDic::addEntry(
549         const OUString& aLeftText,
550         const OUString& aRightText )
551     throw (IllegalArgumentException, container::ElementExistException, RuntimeException)
552 {
553     MutexGuard  aGuard( GetLinguMutex() );
554     if (bNeedEntries)
555         Load();
556     if (HasEntry( aLeftText, aRightText ))
557         throw container::ElementExistException();
558     AddEntry( aLeftText, aRightText );
559 }
560 
561 
562 void SAL_CALL ConvDic::removeEntry(
563         const OUString& aLeftText,
564         const OUString& aRightText )
565     throw (container::NoSuchElementException, RuntimeException)
566 {
567     MutexGuard  aGuard( GetLinguMutex() );
568     if (bNeedEntries)
569         Load();
570     if (!HasEntry( aLeftText, aRightText ))
571         throw container::NoSuchElementException();
572     RemoveEntry( aLeftText, aRightText );
573 }
574 
575 
576 sal_Int16 SAL_CALL ConvDic::getMaxCharCount( ConversionDirection eDirection )
577     throw (RuntimeException)
578 {
579     MutexGuard  aGuard( GetLinguMutex() );
580 
581     if (!pFromRight.get() && eDirection == ConversionDirection_FROM_RIGHT)
582     {
583         DBG_ASSERT( nMaxRightCharCount == 0, "max right char count should be 0" );
584         return 0;
585     }
586 
587     if (bNeedEntries)
588         Load();
589 
590     if (!bMaxCharCountIsValid)
591     {
592         nMaxLeftCharCount   = 0;
593         ConvMap::iterator aIt = aFromLeft.begin();
594         while (aIt != aFromLeft.end())
595         {
596             sal_Int16 nTmp = (sal_Int16) (*aIt).first.getLength();
597             if (nTmp > nMaxLeftCharCount)
598                 nMaxLeftCharCount = nTmp;
599             ++aIt;
600         }
601 
602         nMaxRightCharCount  = 0;
603         if (pFromRight.get())
604         {
605             aIt = pFromRight->begin();
606             while (aIt != pFromRight->end())
607             {
608                 sal_Int16 nTmp = (sal_Int16) (*aIt).first.getLength();
609                 if (nTmp > nMaxRightCharCount)
610                     nMaxRightCharCount = nTmp;
611                 ++aIt;
612             }
613         }
614 
615         bMaxCharCountIsValid = sal_True;
616     }
617     sal_Int16 nRes = eDirection == ConversionDirection_FROM_LEFT ?
618             nMaxLeftCharCount : nMaxRightCharCount;
619     DBG_ASSERT( nRes >= 0, "invalid MaxCharCount" );
620     return nRes;
621 }
622 
623 
624 void SAL_CALL ConvDic::setPropertyType(
625         const OUString& rLeftText,
626         const OUString& rRightText,
627         sal_Int16 nPropertyType )
628     throw (container::NoSuchElementException, IllegalArgumentException, RuntimeException)
629 {
630     sal_Bool bHasElement = HasEntry( rLeftText, rRightText);
631     if (!bHasElement)
632         throw container::NoSuchElementException();
633 
634     // currently we assume that entries with the same left text have the
635     // same PropertyType even if the right text is different...
636     if (pConvPropType.get())
637         pConvPropType->insert( PropTypeMap::value_type( rLeftText, nPropertyType ) );
638     bIsModified = sal_True;
639 }
640 
641 
642 sal_Int16 SAL_CALL ConvDic::getPropertyType(
643         const OUString& rLeftText,
644         const OUString& rRightText )
645     throw (container::NoSuchElementException, RuntimeException)
646 {
647     sal_Bool bHasElement = HasEntry( rLeftText, rRightText);
648     if (!bHasElement)
649         throw container::NoSuchElementException();
650 
651     sal_Int16 nRes = ConversionPropertyType::NOT_DEFINED;
652     if (pConvPropType.get())
653     {
654         // still assuming that entries with same left text have same PropertyType
655         // even if they have different right text...
656         PropTypeMap::iterator aIt = pConvPropType->find( rLeftText );
657         if (aIt != pConvPropType->end())
658             nRes = (*aIt).second;
659     }
660     return nRes;
661 }
662 
663 
664 void SAL_CALL ConvDic::flush(  )
665     throw (RuntimeException)
666 {
667     MutexGuard  aGuard( GetLinguMutex() );
668 
669     if (!bIsModified)
670         return;
671 
672     Save();
673 
674     // notify listeners
675     EventObject aEvtObj;
676     aEvtObj.Source = uno::Reference< XFlushable >( this );
677     cppu::OInterfaceIteratorHelper aIt( aFlushListeners );
678     while (aIt.hasMoreElements())
679     {
680         uno::Reference< util::XFlushListener > xRef( aIt.next(), UNO_QUERY );
681         if (xRef.is())
682             xRef->flushed( aEvtObj );
683     }
684 }
685 
686 
687 void SAL_CALL ConvDic::addFlushListener(
688         const uno::Reference< util::XFlushListener >& rxListener )
689     throw (RuntimeException)
690 {
691     MutexGuard  aGuard( GetLinguMutex() );
692     if (rxListener.is())
693         aFlushListeners.addInterface( rxListener );
694 }
695 
696 
697 void SAL_CALL ConvDic::removeFlushListener(
698         const uno::Reference< util::XFlushListener >& rxListener )
699     throw (RuntimeException)
700 {
701     MutexGuard  aGuard( GetLinguMutex() );
702     if (rxListener.is())
703         aFlushListeners.removeInterface( rxListener );
704 }
705 
706 
707 OUString SAL_CALL ConvDic::getImplementationName(  )
708     throw (RuntimeException)
709 {
710     MutexGuard  aGuard( GetLinguMutex() );
711     return getImplementationName_Static();
712 }
713 
714 
715 sal_Bool SAL_CALL ConvDic::supportsService( const OUString& rServiceName )
716     throw (RuntimeException)
717 {
718     MutexGuard  aGuard( GetLinguMutex() );
719     sal_Bool bRes = sal_False;
720     if (rServiceName.equalsAscii( SN_CONV_DICTIONARY ))
721         bRes = sal_True;
722     return bRes;
723 }
724 
725 
726 uno::Sequence< OUString > SAL_CALL ConvDic::getSupportedServiceNames(  )
727     throw (RuntimeException)
728 {
729     MutexGuard  aGuard( GetLinguMutex() );
730     return getSupportedServiceNames_Static();
731 }
732 
733 
734 uno::Sequence< OUString > ConvDic::getSupportedServiceNames_Static()
735     throw()
736 {
737     uno::Sequence< OUString > aSNS( 1 );
738     aSNS.getArray()[0] = A2OU( SN_CONV_DICTIONARY );
739     return aSNS;
740 }
741 
742 ///////////////////////////////////////////////////////////////////////////
743 
744 
745