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