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