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 #include <i18npool/lang.h> 31 #include <tools/debug.hxx> 32 #include <svl/lngmisc.hxx> 33 34 #include <cppuhelper/factory.hxx> // helper for factories 35 #include <com/sun/star/registry/XRegistryKey.hpp> 36 #include <com/sun/star/beans/XPropertySet.hpp> 37 #include <unotools/processfactory.hxx> 38 #include <osl/mutex.hxx> 39 40 #include "thesdsp.hxx" 41 #include "linguistic/lngprops.hxx" 42 43 using namespace utl; 44 using namespace osl; 45 using namespace rtl; 46 using namespace com::sun::star; 47 using namespace com::sun::star::beans; 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 sal_Bool SvcListHasLanguage( 56 const Sequence< Reference< XThesaurus > > &rRefs, 57 const Locale &rLocale ) 58 { 59 sal_Bool bHasLanguage = sal_False; 60 61 const Reference< XThesaurus > *pRef = rRefs.getConstArray(); 62 sal_Int32 nLen = rRefs.getLength(); 63 for (sal_Int32 k = 0; k < nLen && !bHasLanguage; ++k) 64 { 65 if (pRef[k].is()) 66 bHasLanguage = pRef[k]->hasLocale( rLocale ); 67 } 68 69 return bHasLanguage; 70 } 71 72 /////////////////////////////////////////////////////////////////////////// 73 74 75 ThesaurusDispatcher::ThesaurusDispatcher() 76 { 77 } 78 79 80 ThesaurusDispatcher::~ThesaurusDispatcher() 81 { 82 ClearSvcList(); 83 } 84 85 86 void ThesaurusDispatcher::ClearSvcList() 87 { 88 // release memory for each table entry 89 ThesSvcByLangMap_t aTmp; 90 aSvcMap.swap( aTmp ); 91 } 92 93 94 Sequence< Locale > SAL_CALL 95 ThesaurusDispatcher::getLocales() 96 throw(RuntimeException) 97 { 98 MutexGuard aGuard( GetLinguMutex() ); 99 100 Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) ); 101 Locale *pLocales = aLocales.getArray(); 102 ThesSvcByLangMap_t::const_iterator aIt; 103 for (aIt = aSvcMap.begin(); aIt != aSvcMap.end(); ++aIt) 104 { 105 *pLocales++ = CreateLocale( aIt->first ); 106 } 107 return aLocales; 108 } 109 110 111 sal_Bool SAL_CALL 112 ThesaurusDispatcher::hasLocale( const Locale& rLocale ) 113 throw(RuntimeException) 114 { 115 MutexGuard aGuard( GetLinguMutex() ); 116 ThesSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LocaleToLanguage( rLocale ) ) ); 117 return aIt != aSvcMap.end(); 118 } 119 120 121 Sequence< Reference< XMeaning > > SAL_CALL 122 ThesaurusDispatcher::queryMeanings( 123 const OUString& rTerm, const Locale& rLocale, 124 const PropertyValues& rProperties ) 125 throw(IllegalArgumentException, RuntimeException) 126 { 127 MutexGuard aGuard( GetLinguMutex() ); 128 129 Sequence< Reference< XMeaning > > aMeanings; 130 131 sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 132 if (nLanguage == LANGUAGE_NONE || !rTerm.getLength()) 133 return aMeanings; 134 135 // search for entry with that language 136 ThesSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) ); 137 LangSvcEntries_Thes *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL; 138 139 if (!pEntry) 140 { 141 #ifdef LINGU_EXCEPTIONS 142 throw IllegalArgumentException(); 143 #endif 144 } 145 else 146 { 147 OUString aChkWord( rTerm ); 148 aChkWord = aChkWord.replace( SVT_HARD_SPACE, ' ' ); 149 RemoveHyphens( aChkWord ); 150 if (IsIgnoreControlChars( rProperties, GetPropSet() )) 151 RemoveControlChars( aChkWord ); 152 153 sal_Int32 nLen = pEntry->aSvcRefs.getLength(); 154 DBG_ASSERT( nLen == pEntry->aSvcImplNames.getLength(), 155 "lng : sequence length mismatch"); 156 DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen, 157 "lng : index out of range"); 158 159 sal_Int32 i = 0; 160 161 // try already instantiated services first 162 { 163 const Reference< XThesaurus > *pRef = pEntry->aSvcRefs.getConstArray(); 164 while (i <= pEntry->nLastTriedSvcIndex 165 && aMeanings.getLength() == 0) 166 { 167 if (pRef[i].is() && pRef[i]->hasLocale( rLocale )) 168 aMeanings = pRef[i]->queryMeanings( aChkWord, rLocale, rProperties ); 169 ++i; 170 } 171 } 172 173 // if still no result instantiate new services and try those 174 if (aMeanings.getLength() == 0 175 && pEntry->nLastTriedSvcIndex < nLen - 1) 176 { 177 const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray(); 178 Reference< XThesaurus > *pRef = pEntry->aSvcRefs.getArray(); 179 180 Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); 181 if (xMgr.is()) 182 { 183 // build service initialization argument 184 Sequence< Any > aArgs(1); 185 aArgs.getArray()[0] <<= GetPropSet(); 186 187 while (i < nLen && aMeanings.getLength() == 0) 188 { 189 // create specific service via it's implementation name 190 Reference< XThesaurus > xThes; 191 try 192 { 193 xThes = Reference< XThesaurus >( 194 xMgr->createInstanceWithArguments( 195 pImplNames[i], aArgs ), UNO_QUERY ); 196 } 197 catch (uno::Exception &) 198 { 199 DBG_ASSERT( 0, "createInstanceWithArguments failed" ); 200 } 201 pRef[i] = xThes; 202 203 if (xThes.is() && xThes->hasLocale( rLocale )) 204 aMeanings = xThes->queryMeanings( aChkWord, rLocale, rProperties ); 205 206 pEntry->nLastTriedSvcIndex = (sal_Int16) i; 207 ++i; 208 } 209 210 // if language is not supported by any of the services 211 // remove it from the list. 212 if (i == nLen && aMeanings.getLength() == 0) 213 { 214 if (!SvcListHasLanguage( pEntry->aSvcRefs, rLocale )) 215 aSvcMap.erase( nLanguage ); 216 } 217 } 218 } 219 } 220 221 return aMeanings; 222 } 223 224 225 void ThesaurusDispatcher::SetServiceList( const Locale &rLocale, 226 const Sequence< OUString > &rSvcImplNames ) 227 { 228 MutexGuard aGuard( GetLinguMutex() ); 229 230 sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 231 232 sal_Int32 nLen = rSvcImplNames.getLength(); 233 if (0 == nLen) 234 // remove entry 235 aSvcMap.erase( nLanguage ); 236 else 237 { 238 // modify/add entry 239 LangSvcEntries_Thes *pEntry = aSvcMap[ nLanguage ].get(); 240 if (pEntry) 241 { 242 pEntry->Clear(); 243 pEntry->aSvcImplNames = rSvcImplNames; 244 pEntry->aSvcRefs = Sequence< Reference < XThesaurus > >( nLen ); 245 } 246 else 247 { 248 boost::shared_ptr< LangSvcEntries_Thes > pTmpEntry( new LangSvcEntries_Thes( rSvcImplNames ) ); 249 pTmpEntry->aSvcRefs = Sequence< Reference < XThesaurus > >( nLen ); 250 aSvcMap[ nLanguage ] = pTmpEntry; 251 } 252 } 253 } 254 255 256 Sequence< OUString > 257 ThesaurusDispatcher::GetServiceList( const Locale &rLocale ) const 258 { 259 MutexGuard aGuard( GetLinguMutex() ); 260 261 Sequence< OUString > aRes; 262 263 // search for entry with that language and use data from that 264 sal_Int16 nLanguage = LocaleToLanguage( rLocale ); 265 ThesaurusDispatcher *pThis = (ThesaurusDispatcher *) this; 266 const ThesSvcByLangMap_t::iterator aIt( pThis->aSvcMap.find( nLanguage ) ); 267 const LangSvcEntries_Thes *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL; 268 if (pEntry) 269 aRes = pEntry->aSvcImplNames; 270 271 return aRes; 272 } 273 274 275 LinguDispatcher::DspType ThesaurusDispatcher::GetDspType() const 276 { 277 return DSP_THES; 278 } 279 280 281 /////////////////////////////////////////////////////////////////////////// 282 283