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