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