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