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