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