xref: /aoo41x/main/linguistic/source/dlistimp.cxx (revision 3b8558fd)
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