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