xref: /trunk/main/linguistic/source/dlistimp.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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/mslangid.hxx>
33 #include <osl/file.hxx>
34 #include <tools/fsys.hxx>
35 #include <tools/stream.hxx>
36 #include <tools/urlobj.hxx>
37 #include <i18npool/mslangid.hxx>
38 #include <unotools/pathoptions.hxx>
39 #include <unotools/useroptions.hxx>
40 #include <cppuhelper/factory.hxx>   // helper for factories
41 #include <unotools/localfilehelper.hxx>
42 #include <comphelper/processfactory.hxx>
43 #include <unotools/ucbstreamhelper.hxx>
44 #include <com/sun/star/frame/XStorable.hpp>
45 #include <com/sun/star/lang/Locale.hpp>
46 #include <com/sun/star/uno/Reference.h>
47 #include <com/sun/star/linguistic2/DictionaryEventFlags.hpp>
48 #include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
49 #include <com/sun/star/registry/XRegistryKey.hpp>
50 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
51 
52 #include "defs.hxx"
53 #include "dlistimp.hxx"
54 #include "dicimp.hxx"
55 #include "lngopt.hxx"
56 
57 #include "defs.hxx"
58 #include "dlistimp.hxx"
59 #include "dicimp.hxx"
60 #include "lngopt.hxx"
61 
62 //using namespace utl;
63 using namespace osl;
64 using namespace rtl;
65 using namespace com::sun::star;
66 using namespace com::sun::star::lang;
67 using namespace com::sun::star::uno;
68 using namespace com::sun::star::linguistic2;
69 using namespace linguistic;
70 
71 ///////////////////////////////////////////////////////////////////////////
72 
73 static sal_Bool IsVers2OrNewer( const String& rFileURL, sal_uInt16& nLng, sal_Bool& bNeg );
74 
75 static void AddInternal( const uno::Reference< XDictionary > &rDic,
76                          const rtl::OUString& rNew );
77 static void AddUserData( const uno::Reference< XDictionary > &rDic );
78 
79 ///////////////////////////////////////////////////////////////////////////
80 
81 class DicEvtListenerHelper :
82     public cppu::WeakImplHelper1
83     <
84         XDictionaryEventListener
85     >
86 {
87     cppu::OInterfaceContainerHelper         aDicListEvtListeners;
88     uno::Sequence< DictionaryEvent >        aCollectDicEvt;
89     uno::Reference< XDictionaryList >       xMyDicList;
90 
91     sal_Int16                               nCondensedEvt;
92     sal_Int16                               nNumCollectEvtListeners,
93                                         nNumVerboseListeners;
94 
95 public:
96     DicEvtListenerHelper( const uno::Reference< XDictionaryList > &rxDicList );
97     virtual ~DicEvtListenerHelper();
98 
99     // XEventListener
100     virtual void SAL_CALL
101         disposing( const EventObject& rSource )
102             throw(RuntimeException);
103 
104     // XDictionaryEventListener
105     virtual void SAL_CALL
106         processDictionaryEvent( const DictionaryEvent& rDicEvent )
107             throw(RuntimeException);
108 
109     // non-UNO functions
110     void    DisposeAndClear( const EventObject &rEvtObj );
111 
112     sal_Bool    AddDicListEvtListener(
113                 const uno::Reference< XDictionaryListEventListener >& rxListener,
114                 sal_Bool bReceiveVerbose );
115     sal_Bool    RemoveDicListEvtListener(
116                 const uno::Reference< XDictionaryListEventListener >& rxListener );
117     sal_Int16   BeginCollectEvents();
118     sal_Int16   EndCollectEvents();
119     sal_Int16   FlushEvents();
120     void    ClearEvents()   { nCondensedEvt = 0; }
121 };
122 
123 
124 DicEvtListenerHelper::DicEvtListenerHelper(
125         const uno::Reference< XDictionaryList > &rxDicList ) :
126     aDicListEvtListeners    ( GetLinguMutex() ),
127     xMyDicList              ( rxDicList )
128 {
129     nCondensedEvt   = 0;
130     nNumCollectEvtListeners = nNumVerboseListeners  = 0;
131 }
132 
133 
134 DicEvtListenerHelper::~DicEvtListenerHelper()
135 {
136     DBG_ASSERT(aDicListEvtListeners.getLength() == 0,
137         "lng : event listeners are still existing");
138 }
139 
140 
141 void DicEvtListenerHelper::DisposeAndClear( const EventObject &rEvtObj )
142 {
143     aDicListEvtListeners.disposeAndClear( rEvtObj );
144 }
145 
146 
147 void SAL_CALL DicEvtListenerHelper::disposing( const EventObject& rSource )
148         throw(RuntimeException)
149 {
150     osl::MutexGuard aGuard( GetLinguMutex() );
151 
152     uno::Reference< XInterface > xSrc( rSource.Source );
153 
154     // remove event object from EventListener list
155     if (xSrc.is())
156         aDicListEvtListeners.removeInterface( xSrc );
157 
158     // if object is a dictionary then remove it from the dictionary list
159     // Note: this will probably happen only if someone makes a XDictionary
160     // implementation of his own that is also a XComponent.
161     uno::Reference< XDictionary > xDic( xSrc, UNO_QUERY );
162     if (xDic.is())
163     {
164         xMyDicList->removeDictionary( xDic );
165     }
166 }
167 
168 
169 void SAL_CALL DicEvtListenerHelper::processDictionaryEvent(
170             const DictionaryEvent& rDicEvent )
171         throw(RuntimeException)
172 {
173     osl::MutexGuard aGuard( GetLinguMutex() );
174 
175     uno::Reference< XDictionary > xDic( rDicEvent.Source, UNO_QUERY );
176     DBG_ASSERT(xDic.is(), "lng : missing event source");
177 
178     // assert that there is a corresponding dictionary entry if one was
179     // added or deleted
180     uno::Reference< XDictionaryEntry > xDicEntry( rDicEvent.xDictionaryEntry, UNO_QUERY );
181     DBG_ASSERT( !(rDicEvent.nEvent &
182                     (DictionaryEventFlags::ADD_ENTRY | DictionaryEventFlags::DEL_ENTRY))
183                 || xDicEntry.is(),
184                 "lng : missing dictionary entry" );
185 
186     /*sal_Bool bActiveDicsModified = sal_False;*/
187     //
188     // evaluate DictionaryEvents and update data for next DictionaryListEvent
189     //
190     DictionaryType eDicType = xDic->getDictionaryType();
191     DBG_ASSERT(eDicType != DictionaryType_MIXED,
192         "lng : unexpected dictionary type");
193     if ((rDicEvent.nEvent & DictionaryEventFlags::ADD_ENTRY) && xDic->isActive())
194         nCondensedEvt |= xDicEntry->isNegative() ?
195             DictionaryListEventFlags::ADD_NEG_ENTRY :
196             DictionaryListEventFlags::ADD_POS_ENTRY;
197     if ((rDicEvent.nEvent & DictionaryEventFlags::DEL_ENTRY) && xDic->isActive())
198         nCondensedEvt |= xDicEntry->isNegative() ?
199             DictionaryListEventFlags::DEL_NEG_ENTRY :
200             DictionaryListEventFlags::DEL_POS_ENTRY;
201     if ((rDicEvent.nEvent & DictionaryEventFlags::ENTRIES_CLEARED) && xDic->isActive())
202         nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
203             DictionaryListEventFlags::DEL_NEG_ENTRY :
204             DictionaryListEventFlags::DEL_POS_ENTRY;
205     if ((rDicEvent.nEvent & DictionaryEventFlags::CHG_LANGUAGE) && xDic->isActive())
206         nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
207             DictionaryListEventFlags::DEACTIVATE_NEG_DIC
208                 | DictionaryListEventFlags::ACTIVATE_NEG_DIC :
209             DictionaryListEventFlags::DEACTIVATE_POS_DIC
210                 | DictionaryListEventFlags::ACTIVATE_POS_DIC;
211     if ((rDicEvent.nEvent & DictionaryEventFlags::ACTIVATE_DIC))
212         nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
213             DictionaryListEventFlags::ACTIVATE_NEG_DIC :
214             DictionaryListEventFlags::ACTIVATE_POS_DIC;
215     if ((rDicEvent.nEvent & DictionaryEventFlags::DEACTIVATE_DIC))
216         nCondensedEvt |= eDicType == DictionaryType_NEGATIVE ?
217             DictionaryListEventFlags::DEACTIVATE_NEG_DIC :
218             DictionaryListEventFlags::DEACTIVATE_POS_DIC;
219 
220     // update list of collected events if needs to be
221     if (nNumVerboseListeners > 0)
222     {
223         sal_Int32 nColEvts = aCollectDicEvt.getLength();
224         aCollectDicEvt.realloc( nColEvts + 1 );
225         aCollectDicEvt.getArray()[ nColEvts ] = rDicEvent;
226     }
227 
228     if (nNumCollectEvtListeners == 0 && nCondensedEvt != 0)
229         FlushEvents();
230 }
231 
232 
233 sal_Bool DicEvtListenerHelper::AddDicListEvtListener(
234             const uno::Reference< XDictionaryListEventListener >& xListener,
235             sal_Bool /*bReceiveVerbose*/ )
236 {
237     DBG_ASSERT( xListener.is(), "empty reference" );
238     sal_Int32   nCount = aDicListEvtListeners.getLength();
239     return aDicListEvtListeners.addInterface( xListener ) != nCount;
240 }
241 
242 
243 sal_Bool DicEvtListenerHelper::RemoveDicListEvtListener(
244             const uno::Reference< XDictionaryListEventListener >& xListener )
245 {
246     DBG_ASSERT( xListener.is(), "empty reference" );
247     sal_Int32   nCount = aDicListEvtListeners.getLength();
248     return aDicListEvtListeners.removeInterface( xListener ) != nCount;
249 }
250 
251 
252 sal_Int16 DicEvtListenerHelper::BeginCollectEvents()
253 {
254     return ++nNumCollectEvtListeners;
255 }
256 
257 
258 sal_Int16 DicEvtListenerHelper::EndCollectEvents()
259 {
260     DBG_ASSERT(nNumCollectEvtListeners > 0, "lng: mismatched function call");
261     if (nNumCollectEvtListeners > 0)
262     {
263         FlushEvents();
264         nNumCollectEvtListeners--;
265     }
266 
267     return nNumCollectEvtListeners;
268 }
269 
270 
271 sal_Int16 DicEvtListenerHelper::FlushEvents()
272 {
273     if (0 != nCondensedEvt)
274     {
275         // build DictionaryListEvent to pass on to listeners
276         uno::Sequence< DictionaryEvent > aDicEvents;
277         if (nNumVerboseListeners > 0)
278             aDicEvents = aCollectDicEvt;
279         DictionaryListEvent aEvent( xMyDicList, nCondensedEvt, aDicEvents );
280 
281         // pass on event
282         cppu::OInterfaceIteratorHelper aIt( aDicListEvtListeners );
283         while (aIt.hasMoreElements())
284         {
285             uno::Reference< XDictionaryListEventListener > xRef( aIt.next(), UNO_QUERY );
286             if (xRef.is())
287                 xRef->processDictionaryListEvent( aEvent );
288         }
289 
290         // clear "list" of events
291         nCondensedEvt = 0;
292         aCollectDicEvt.realloc( 0 );
293     }
294 
295     return nNumCollectEvtListeners;
296 }
297 
298 
299 ///////////////////////////////////////////////////////////////////////////
300 
301 
302 void DicList::MyAppExitListener::AtExit()
303 {
304     rMyDicList.SaveDics();
305 }
306 
307 
308 DicList::DicList() :
309     aEvtListeners   ( GetLinguMutex() )
310 {
311     pDicEvtLstnrHelper  = new DicEvtListenerHelper( this );
312     xDicEvtLstnrHelper  = pDicEvtLstnrHelper;
313     bDisposing = sal_False;
314     bInCreation = sal_False;
315 
316     pExitListener = new MyAppExitListener( *this );
317     xExitListener = pExitListener;
318     pExitListener->Activate();
319 }
320 
321 DicList::~DicList()
322 {
323     pExitListener->Deactivate();
324 }
325 
326 
327 void DicList::SearchForDictionaries(
328     DictionaryVec_t&rDicList,
329     const String &rDicDirURL,
330     sal_Bool bIsWriteablePath )
331 {
332     osl::MutexGuard aGuard( GetLinguMutex() );
333 
334     const uno::Sequence< rtl::OUString > aDirCnt( utl::LocalFileHelper::
335                                         GetFolderContents( rDicDirURL, sal_False ) );
336     const rtl::OUString *pDirCnt = aDirCnt.getConstArray();
337     sal_Int32 nEntries = aDirCnt.getLength();
338 
339     String aDCN( String::CreateFromAscii( "dcn" ) );
340     String aDCP( String::CreateFromAscii( "dcp" ) );
341     for (sal_Int32 i = 0;  i < nEntries;  ++i)
342     {
343         String  aURL( pDirCnt[i] );
344         sal_uInt16  nLang = LANGUAGE_NONE;
345         sal_Bool    bNeg  = sal_False;
346 
347         if(!::IsVers2OrNewer( aURL, nLang, bNeg ))
348         {
349             // Wenn kein
350             xub_StrLen nPos  = aURL.Search('.');
351             String aExt(aURL.Copy(nPos + 1));
352             aExt.ToLowerAscii();
353 
354             if(aExt == aDCN)       // negativ
355                 bNeg = sal_True;
356             else if(aExt == aDCP)  // positiv
357                 bNeg = sal_False;
358             else
359                 continue;          // andere Files
360         }
361 
362         // Aufnehmen in die Liste der Dictionaries
363         // Wenn existent nicht aufnehmen
364         //
365         sal_Int16 nSystemLanguage = MsLangId::getSystemLanguage();
366         String aTmp1 = ToLower( aURL, nSystemLanguage );
367         xub_StrLen nPos = aTmp1.SearchBackward( '/' );
368         if (STRING_NOTFOUND != nPos)
369             aTmp1 = aTmp1.Copy( nPos + 1 );
370         String aTmp2;
371         size_t j;
372         size_t nCount = rDicList.size();
373         for(j = 0;  j < nCount;  j++)
374         {
375             aTmp2 = rDicList[j]->getName().getStr();
376             aTmp2 = ToLower( aTmp2, nSystemLanguage );
377             if(aTmp1 == aTmp2)
378                 break;
379         }
380         if(j >= nCount)     // dictionary not yet in DicList
381         {
382             // get decoded dictionary file name
383             INetURLObject aURLObj( aURL );
384             String aDicName = aURLObj.getName( INetURLObject::LAST_SEGMENT,
385                         true, INetURLObject::DECODE_WITH_CHARSET,
386                         RTL_TEXTENCODING_UTF8 );
387 
388             DictionaryType eType = bNeg ? DictionaryType_NEGATIVE : DictionaryType_POSITIVE;
389             uno::Reference< XDictionary > xDic =
390                         new DictionaryNeo( aDicName, nLang, eType, aURL, bIsWriteablePath );
391 
392             addDictionary( xDic );
393             nCount++;
394         }
395     }
396 }
397 
398 
399 sal_Int32 DicList::GetDicPos(const uno::Reference< XDictionary > &xDic)
400 {
401     osl::MutexGuard aGuard( GetLinguMutex() );
402 
403     sal_Int32 nPos = -1;
404     DictionaryVec_t& rDicList = GetOrCreateDicList();
405     size_t n = rDicList.size();
406     for (size_t i = 0;  i < n;  i++)
407     {
408         if ( rDicList[i] == xDic )
409             return i;
410     }
411     return nPos;
412 }
413 
414 
415 uno::Reference< XInterface > SAL_CALL
416     DicList_CreateInstance( const uno::Reference< XMultiServiceFactory > & /*rSMgr*/ )
417             throw(Exception)
418 {
419     uno::Reference< XInterface > xService = (cppu::OWeakObject *) new DicList;
420     return xService;
421 }
422 
423 sal_Int16 SAL_CALL DicList::getCount() throw(RuntimeException)
424 {
425     osl::MutexGuard aGuard( GetLinguMutex() );
426     return static_cast< sal_Int16 >(GetOrCreateDicList().size());
427 }
428 
429 uno::Sequence< uno::Reference< XDictionary > > SAL_CALL
430         DicList::getDictionaries()
431             throw(RuntimeException)
432 {
433     osl::MutexGuard aGuard( GetLinguMutex() );
434 
435     DictionaryVec_t& rDicList = GetOrCreateDicList();
436 
437     uno::Sequence< uno::Reference< XDictionary > > aDics( rDicList.size() );
438     uno::Reference< XDictionary > *pDic = aDics.getArray();
439 
440     sal_Int32 n = (sal_uInt16) aDics.getLength();
441     for (sal_Int32 i = 0;  i < n;  i++)
442         pDic[i] = rDicList[i];
443 
444     return aDics;
445 }
446 
447 uno::Reference< XDictionary > SAL_CALL
448         DicList::getDictionaryByName( const rtl::OUString& aDictionaryName )
449             throw(RuntimeException)
450 {
451     osl::MutexGuard aGuard( GetLinguMutex() );
452 
453     uno::Reference< XDictionary > xDic;
454     DictionaryVec_t& rDicList = GetOrCreateDicList();
455     size_t nCount = rDicList.size();
456     for (size_t i = 0;  i < nCount;  i++)
457     {
458         const uno::Reference< XDictionary > &rDic = rDicList[i];
459         if (rDic.is()  &&  rDic->getName() == aDictionaryName)
460         {
461             xDic = rDic;
462             break;
463         }
464     }
465 
466     return xDic;
467 }
468 
469 sal_Bool SAL_CALL DicList::addDictionary(
470             const uno::Reference< XDictionary >& xDictionary )
471         throw(RuntimeException)
472 {
473     osl::MutexGuard aGuard( GetLinguMutex() );
474 
475     if (bDisposing)
476         return sal_False;
477 
478     sal_Bool bRes = sal_False;
479     if (xDictionary.is())
480     {
481         DictionaryVec_t& rDicList = GetOrCreateDicList();
482         rDicList.push_back( xDictionary );
483         bRes = sal_True;
484 
485         // add listener helper to the dictionaries listener lists
486         xDictionary->addDictionaryEventListener( xDicEvtLstnrHelper );
487     }
488     return bRes;
489 }
490 
491 sal_Bool SAL_CALL
492     DicList::removeDictionary( const uno::Reference< XDictionary >& xDictionary )
493         throw(RuntimeException)
494 {
495     osl::MutexGuard aGuard( GetLinguMutex() );
496 
497     if (bDisposing)
498         return sal_False;
499 
500     sal_Bool  bRes = sal_False;
501     sal_Int32 nPos = GetDicPos( xDictionary );
502     if (nPos >= 0)
503     {
504         // remove dictionary list from the dictionaries listener lists
505         DictionaryVec_t& rDicList = GetOrCreateDicList();
506         uno::Reference< XDictionary > xDic( rDicList[ nPos ] );
507         DBG_ASSERT(xDic.is(), "lng : empty reference");
508         if (xDic.is())
509         {
510             // deactivate dictionary if not already done
511             xDic->setActive( sal_False );
512 
513             xDic->removeDictionaryEventListener( xDicEvtLstnrHelper );
514         }
515 
516         // remove element at nPos
517         rDicList.erase( rDicList.begin() + nPos );
518         bRes = sal_True;
519     }
520     return bRes;
521 }
522 
523 sal_Bool SAL_CALL DicList::addDictionaryListEventListener(
524             const uno::Reference< XDictionaryListEventListener >& xListener,
525             sal_Bool bReceiveVerbose )
526         throw(RuntimeException)
527 {
528     osl::MutexGuard aGuard( GetLinguMutex() );
529 
530     if (bDisposing)
531         return sal_False;
532 
533     DBG_ASSERT(!bReceiveVerbose, "lng : not yet supported");
534 
535     sal_Bool bRes = sal_False;
536     if (xListener.is()) //! don't add empty references
537     {
538         bRes = pDicEvtLstnrHelper->
539                         AddDicListEvtListener( xListener, bReceiveVerbose );
540     }
541     return bRes;
542 }
543 
544 sal_Bool SAL_CALL DicList::removeDictionaryListEventListener(
545             const uno::Reference< XDictionaryListEventListener >& xListener )
546         throw(RuntimeException)
547 {
548     osl::MutexGuard aGuard( GetLinguMutex() );
549 
550     if (bDisposing)
551         return sal_False;
552 
553     sal_Bool bRes = sal_False;
554     if(xListener.is())
555     {
556         bRes = pDicEvtLstnrHelper->RemoveDicListEvtListener( xListener );
557     }
558     return bRes;
559 }
560 
561 sal_Int16 SAL_CALL DicList::beginCollectEvents() throw(RuntimeException)
562 {
563     osl::MutexGuard aGuard( GetLinguMutex() );
564     return pDicEvtLstnrHelper->BeginCollectEvents();
565 }
566 
567 sal_Int16 SAL_CALL DicList::endCollectEvents() throw(RuntimeException)
568 {
569     osl::MutexGuard aGuard( GetLinguMutex() );
570     return pDicEvtLstnrHelper->EndCollectEvents();
571 }
572 
573 sal_Int16 SAL_CALL DicList::flushEvents() throw(RuntimeException)
574 {
575     osl::MutexGuard aGuard( GetLinguMutex() );
576     return pDicEvtLstnrHelper->FlushEvents();
577 }
578 
579 uno::Reference< XDictionary > SAL_CALL
580     DicList::createDictionary( const rtl::OUString& rName, const Locale& rLocale,
581             DictionaryType eDicType, const rtl::OUString& rURL )
582         throw(RuntimeException)
583 {
584     osl::MutexGuard aGuard( GetLinguMutex() );
585 
586     sal_Int16 nLanguage = LocaleToLanguage( rLocale );
587     bool bIsWriteablePath = rURL.match( GetDictionaryWriteablePath(), 0 );
588     return new DictionaryNeo( rName, nLanguage, eDicType, rURL, bIsWriteablePath );
589 }
590 
591 
592 uno::Reference< XDictionaryEntry > SAL_CALL
593     DicList::queryDictionaryEntry( const rtl::OUString& rWord, const Locale& rLocale,
594             sal_Bool bSearchPosDics, sal_Bool bSearchSpellEntry )
595         throw(RuntimeException)
596 {
597     osl::MutexGuard aGuard( GetLinguMutex() );
598     return SearchDicList( this, rWord, LocaleToLanguage( rLocale ),
599                             bSearchPosDics, bSearchSpellEntry );
600 }
601 
602 
603 void SAL_CALL
604     DicList::dispose()
605         throw(RuntimeException)
606 {
607     osl::MutexGuard aGuard( GetLinguMutex() );
608 
609     if (!bDisposing)
610     {
611         bDisposing = sal_True;
612         EventObject aEvtObj( (XDictionaryList *) this );
613 
614         aEvtListeners.disposeAndClear( aEvtObj );
615         if (pDicEvtLstnrHelper)
616             pDicEvtLstnrHelper->DisposeAndClear( aEvtObj );
617 
618         //! avoid creation of dictionaries if not already done
619         if (aDicList.size() > 0)
620         {
621             DictionaryVec_t& rDicList = GetOrCreateDicList();
622             size_t nCount = rDicList.size();
623             for (size_t i = 0;  i < nCount;  i++)
624             {
625                 uno::Reference< XDictionary > xDic( rDicList[i], UNO_QUERY );
626 
627                 // save (modified) dictionaries
628                 uno::Reference< frame::XStorable >  xStor( xDic , UNO_QUERY );
629                 if (xStor.is())
630                 {
631                     try
632                     {
633                         if (!xStor->isReadonly() && xStor->hasLocation())
634                             xStor->store();
635                     }
636                     catch(Exception &)
637                     {
638                     }
639                 }
640 
641                 // release references to (members of) this object hold by
642                 // dictionaries
643                 if (xDic.is())
644                     xDic->removeDictionaryEventListener( xDicEvtLstnrHelper );
645             }
646         }
647     }
648 }
649 
650 void SAL_CALL
651     DicList::addEventListener( const uno::Reference< XEventListener >& rxListener )
652         throw(RuntimeException)
653 {
654     osl::MutexGuard aGuard( GetLinguMutex() );
655 
656     if (!bDisposing && rxListener.is())
657         aEvtListeners.addInterface( rxListener );
658 }
659 
660 void SAL_CALL
661     DicList::removeEventListener( const uno::Reference< XEventListener >& rxListener )
662         throw(RuntimeException)
663 {
664     osl::MutexGuard aGuard( GetLinguMutex() );
665 
666     if (!bDisposing && rxListener.is())
667         aEvtListeners.removeInterface( rxListener );
668 }
669 
670 void DicList::_CreateDicList()
671 {
672     bInCreation = sal_True;
673 
674     // look for dictionaries
675     const rtl::OUString aWriteablePath( GetDictionaryWriteablePath() );
676     uno::Sequence< rtl::OUString > aPaths( GetDictionaryPaths() );
677     const rtl::OUString *pPaths = aPaths.getConstArray();
678     for (sal_Int32 i = 0;  i < aPaths.getLength();  ++i)
679     {
680         const sal_Bool bIsWriteablePath = (pPaths[i] == aWriteablePath);
681         SearchForDictionaries( aDicList, pPaths[i], bIsWriteablePath );
682     }
683 
684     // create IgnoreAllList dictionary with empty URL (non persistent)
685     // and add it to list
686     rtl::OUString aDicName( A2OU( "IgnoreAllList" ) );
687     uno::Reference< XDictionary > xIgnAll(
688             createDictionary( aDicName, CreateLocale( LANGUAGE_NONE ),
689                               DictionaryType_POSITIVE, rtl::OUString() ) );
690     if (xIgnAll.is())
691     {
692         AddUserData( xIgnAll );
693         xIgnAll->setActive( sal_True );
694         addDictionary( xIgnAll );
695     }
696 
697 
698     // evaluate list of dictionaries to be activated from configuration
699     //
700     //! to suppress overwriting the list of active dictionaries in the
701     //! configuration with incorrect arguments during the following
702     //! activation of the dictionaries
703     pDicEvtLstnrHelper->BeginCollectEvents();
704     //
705     const uno::Sequence< rtl::OUString > aActiveDics( aOpt.GetActiveDics() );
706     const rtl::OUString *pActiveDic = aActiveDics.getConstArray();
707     sal_Int32 nLen = aActiveDics.getLength();
708     for (sal_Int32 i = 0;  i < nLen;  ++i)
709     {
710         if (pActiveDic[i].getLength())
711         {
712             uno::Reference< XDictionary > xDic( getDictionaryByName( pActiveDic[i] ) );
713             if (xDic.is())
714                 xDic->setActive( sal_True );
715         }
716     }
717 
718     // suppress collected events during creation of the dictionary list.
719     // there should be no events during creation.
720     pDicEvtLstnrHelper->ClearEvents();
721 
722     pDicEvtLstnrHelper->EndCollectEvents();
723 
724     bInCreation = sal_False;
725 }
726 
727 
728 void DicList::SaveDics()
729 {
730     // save dics only if they have already been used/created.
731     //! don't create them just for the purpose of saving them !
732     if (aDicList.size() > 0)
733     {
734         // save (modified) dictionaries
735         DictionaryVec_t& rDicList = GetOrCreateDicList();
736         size_t nCount = rDicList.size();;
737         for (size_t i = 0;  i < nCount;  i++)
738         {
739             // save (modified) dictionaries
740             uno::Reference< frame::XStorable >  xStor( rDicList[i], UNO_QUERY );
741             if (xStor.is())
742             {
743                 try
744                 {
745                     if (!xStor->isReadonly() && xStor->hasLocation())
746                         xStor->store();
747                 }
748                 catch(Exception &)
749                 {
750                 }
751             }
752         }
753     }
754 }
755 
756 
757 ///////////////////////////////////////////////////////////////////////////
758 // Service specific part
759 //
760 
761 rtl::OUString SAL_CALL DicList::getImplementationName(  ) throw(RuntimeException)
762 {
763     osl::MutexGuard aGuard( GetLinguMutex() );
764     return getImplementationName_Static();
765 }
766 
767 
768 sal_Bool SAL_CALL DicList::supportsService( const rtl::OUString& ServiceName )
769         throw(RuntimeException)
770 {
771     osl::MutexGuard aGuard( GetLinguMutex() );
772 
773     uno::Sequence< rtl::OUString > aSNL = getSupportedServiceNames();
774     const rtl::OUString * pArray = aSNL.getConstArray();
775     for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
776         if( pArray[i] == ServiceName )
777             return sal_True;
778     return sal_False;
779 }
780 
781 
782 uno::Sequence< rtl::OUString > SAL_CALL DicList::getSupportedServiceNames(  )
783         throw(RuntimeException)
784 {
785     osl::MutexGuard aGuard( GetLinguMutex() );
786     return getSupportedServiceNames_Static();
787 }
788 
789 
790 uno::Sequence< rtl::OUString > DicList::getSupportedServiceNames_Static() throw()
791 {
792     osl::MutexGuard aGuard( GetLinguMutex() );
793 
794     uno::Sequence< rtl::OUString > aSNS( 1 );   // auch mehr als 1 Service moeglich
795     aSNS.getArray()[0] = A2OU( SN_DICTIONARY_LIST );
796     return aSNS;
797 }
798 
799 void * SAL_CALL DicList_getFactory( const sal_Char * pImplName,
800         XMultiServiceFactory * pServiceManager, void *  )
801 {
802     void * pRet = 0;
803     if ( !DicList::getImplementationName_Static().compareToAscii( pImplName ) )
804     {
805         uno::Reference< XSingleServiceFactory > xFactory =
806             cppu::createOneInstanceFactory(
807                 pServiceManager,
808                 DicList::getImplementationName_Static(),
809                 DicList_CreateInstance,
810                 DicList::getSupportedServiceNames_Static());
811         // acquire, because we return an interface pointer instead of a reference
812         xFactory->acquire();
813         pRet = xFactory.get();
814     }
815     return pRet;
816 }
817 
818 ///////////////////////////////////////////////////////////////////////////
819 
820 xub_StrLen lcl_GetToken( String &rToken,
821             const String &rText, xub_StrLen nPos, const String &rDelim )
822 {
823     xub_StrLen nRes = STRING_LEN;
824 
825     if (rText.Len() == 0  ||  nPos >= rText.Len())
826         rToken = String();
827     else if (rDelim.Len() == 0)
828     {
829         rToken = rText;
830         if (rToken.Len())
831             nRes = rText.Len();
832     }
833     else
834     {
835         xub_StrLen  i;
836         for (i = nPos;  i < rText.Len();  ++i)
837         {
838             if (STRING_NOTFOUND != rDelim.Search( rText.GetChar(i) ))
839                 break;
840         }
841 
842         if (i >= rText.Len())   // delimeter not found
843             rToken  = rText.Copy( nPos );
844         else
845             rToken  = rText.Copy( nPos, sal::static_int_cast< xub_StrLen >((sal_Int32) i - nPos) );
846         nRes    = i + 1;    // continue after found delimeter
847     }
848 
849     return nRes;
850 }
851 
852 
853 static void AddInternal(
854         const uno::Reference<XDictionary> &rDic,
855         const rtl::OUString& rNew )
856 {
857     if (rDic.is())
858     {
859         //! TL TODO: word iterator should be used to break up the text
860         static const char *pDefWordDelim =
861                 "!\"#$%&'()*+,-./:;<=>?[]\\_^`{|}~\t \n";
862         ByteString aDummy( pDefWordDelim );
863         String aDelim( aDummy, osl_getThreadTextEncoding() );
864         aDelim.EraseAllChars( '.' );
865 
866         String      aToken;
867         xub_StrLen  nPos = 0;
868         while (STRING_LEN !=
869                     (nPos = lcl_GetToken( aToken, rNew, nPos, aDelim )))
870         {
871             if( aToken.Len()  &&  !IsNumeric( aToken ) )
872             {
873                 rDic->add( aToken, sal_False, rtl::OUString() );
874             }
875         }
876     }
877 }
878 
879 static void AddUserData( const uno::Reference< XDictionary > &rDic )
880 {
881     if (rDic.is())
882     {
883         SvtUserOptions aUserOpt;
884         AddInternal( rDic, aUserOpt.GetFullName() );
885         AddInternal( rDic, aUserOpt.GetCompany() );
886         AddInternal( rDic, aUserOpt.GetStreet() );
887         AddInternal( rDic, aUserOpt.GetCity() );
888         AddInternal( rDic, aUserOpt.GetTitle() );
889         AddInternal( rDic, aUserOpt.GetPosition() );
890         AddInternal( rDic, aUserOpt.GetEmail() );
891     }
892 }
893 
894 ///////////////////////////////////////////////////////////////////////////
895 
896 #if defined _MSC_VER
897 #pragma optimize("g",off)
898 #endif
899 
900 static sal_Bool IsVers2OrNewer( const String& rFileURL, sal_uInt16& nLng, sal_Bool& bNeg )
901 {
902     if (rFileURL.Len() == 0)
903         return sal_False;
904     String aDIC( GetDicExtension() );
905     String aExt;
906     xub_StrLen nPos = rFileURL.SearchBackward( '.' );
907     if (STRING_NOTFOUND != nPos)
908         aExt = rFileURL.Copy( nPos + 1 );
909     aExt.ToLowerAscii();
910 
911     if(aExt != aDIC)
912         return sal_False;
913 
914     // get stream to be used
915     uno::Reference< lang::XMultiServiceFactory > xServiceFactory( comphelper::getProcessServiceFactory() );
916 
917     // get XInputStream stream
918     uno::Reference< io::XInputStream > xStream;
919     try
920     {
921         uno::Reference< ucb::XSimpleFileAccess > xAccess( xServiceFactory->createInstance(
922                 A2OU( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY_THROW );
923         xStream = xAccess->openFileRead( rFileURL );
924     }
925     catch (uno::Exception & e)
926     {
927         DBG_ASSERT( 0, "failed to get input stream" );
928         (void) e;
929     }
930     DBG_ASSERT( xStream.is(), "failed to get stream for read" );
931     if (!xStream.is())
932         return sal_False;
933 
934     SvStreamPtr pStream = SvStreamPtr( utl::UcbStreamHelper::CreateStream( xStream ) );
935 
936     int nDicVersion = ReadDicVersion(pStream, nLng, bNeg);
937     if (2 == nDicVersion || nDicVersion >= 5)
938         return sal_True;
939 
940     return sal_False;
941 }
942 
943 ///////////////////////////////////////////////////////////////////////////
944 
945