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 <string.h> 28 29 #include "iprcache.hxx" 30 #include "linguistic/misc.hxx" 31 32 #include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp> 33 #include <tools/debug.hxx> 34 #include <osl/mutex.hxx> 35 36 //#define IPR_DEF_CACHE_SIZE 503 37 #define IPR_DEF_CACHE_MAX 375 38 #define IPR_DEF_CACHE_MAXINPUT 200 39 40 #ifdef DBG_STATISTIC 41 #include <tools/stream.hxx> 42 43 //#define IPR_CACHE_SIZE nTblSize 44 #define IPR_CACHE_MAX nMax 45 #define IPR_CACHE_MAXINPUT nMaxInput 46 47 #else 48 49 //#define IPR_CACHE_SIZE IPR_DEF_CACHE_SIZE 50 #define IPR_CACHE_MAX IPR_DEF_CACHE_MAX 51 #define IPR_CACHE_MAXINPUT IPR_DEF_CACHE_MAXINPUT 52 53 #endif 54 #include <unotools/processfactory.hxx> 55 56 #include <linguistic/lngprops.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::beans; 63 using namespace com::sun::star::lang; 64 using namespace com::sun::star::uno; 65 using namespace com::sun::star::linguistic2; 66 67 68 namespace linguistic 69 { 70 71 /////////////////////////////////////////////////////////////////////////// 72 73 #define NUM_FLUSH_PROPS 6 74 75 static const struct 76 { 77 const char *pPropName; 78 sal_Int32 nPropHdl; 79 } aFlushProperties[ NUM_FLUSH_PROPS ] = 80 { 81 { UPN_IS_USE_DICTIONARY_LIST, UPH_IS_USE_DICTIONARY_LIST }, 82 { UPN_IS_IGNORE_CONTROL_CHARACTERS, UPH_IS_IGNORE_CONTROL_CHARACTERS }, 83 { UPN_IS_SPELL_UPPER_CASE, UPH_IS_SPELL_UPPER_CASE }, 84 { UPN_IS_SPELL_WITH_DIGITS, UPH_IS_SPELL_WITH_DIGITS }, 85 { UPN_IS_SPELL_CAPITALIZATION, UPH_IS_SPELL_CAPITALIZATION } 86 }; 87 88 89 static void lcl_AddAsPropertyChangeListener( 90 Reference< XPropertyChangeListener > xListener, 91 Reference< XPropertySet > &rPropSet ) 92 { 93 if (xListener.is() && rPropSet.is()) 94 { 95 for (int i = 0; i < NUM_FLUSH_PROPS; ++i) 96 { 97 rPropSet->addPropertyChangeListener( 98 A2OU(aFlushProperties[i].pPropName), xListener ); 99 } 100 } 101 } 102 103 104 static void lcl_RemoveAsPropertyChangeListener( 105 Reference< XPropertyChangeListener > xListener, 106 Reference< XPropertySet > &rPropSet ) 107 { 108 if (xListener.is() && rPropSet.is()) 109 { 110 for (int i = 0; i < NUM_FLUSH_PROPS; ++i) 111 { 112 rPropSet->removePropertyChangeListener( 113 A2OU(aFlushProperties[i].pPropName), xListener ); 114 } 115 } 116 } 117 118 119 static sal_Bool lcl_IsFlushProperty( sal_Int32 nHandle ) 120 { 121 int i; 122 for (i = 0; i < NUM_FLUSH_PROPS; ++i) 123 { 124 if (nHandle == aFlushProperties[i].nPropHdl) 125 break; 126 } 127 return i < NUM_FLUSH_PROPS; 128 } 129 130 131 FlushListener::FlushListener( Flushable *pFO ) 132 { 133 SetFlushObj( pFO ); 134 } 135 136 137 FlushListener::~FlushListener() 138 { 139 } 140 141 142 void FlushListener::SetDicList( Reference<XDictionaryList> &rDL ) 143 { 144 MutexGuard aGuard( GetLinguMutex() ); 145 146 if (xDicList != rDL) 147 { 148 if (xDicList.is()) 149 xDicList->removeDictionaryListEventListener( this ); 150 151 xDicList = rDL; 152 if (xDicList.is()) 153 xDicList->addDictionaryListEventListener( this, sal_False ); 154 } 155 } 156 157 158 void FlushListener::SetPropSet( Reference< XPropertySet > &rPS ) 159 { 160 MutexGuard aGuard( GetLinguMutex() ); 161 162 if (xPropSet != rPS) 163 { 164 if (xPropSet.is()) 165 lcl_RemoveAsPropertyChangeListener( this, xPropSet ); 166 167 xPropSet = rPS; 168 if (xPropSet.is()) 169 lcl_AddAsPropertyChangeListener( this, xPropSet ); 170 } 171 } 172 173 174 void SAL_CALL FlushListener::disposing( const EventObject& rSource ) 175 throw(RuntimeException) 176 { 177 MutexGuard aGuard( GetLinguMutex() ); 178 179 if (xDicList.is() && rSource.Source == xDicList) 180 { 181 xDicList->removeDictionaryListEventListener( this ); 182 xDicList = NULL; //! release reference 183 } 184 if (xPropSet.is() && rSource.Source == xPropSet) 185 { 186 lcl_RemoveAsPropertyChangeListener( this, xPropSet ); 187 xPropSet = NULL; //! release reference 188 } 189 } 190 191 192 void SAL_CALL FlushListener::processDictionaryListEvent( 193 const DictionaryListEvent& rDicListEvent ) 194 throw(RuntimeException) 195 { 196 MutexGuard aGuard( GetLinguMutex() ); 197 198 if (rDicListEvent.Source == xDicList) 199 { 200 sal_Int16 nEvt = rDicListEvent.nCondensedEvent; 201 sal_Int16 nFlushFlags = 202 DictionaryListEventFlags::ADD_NEG_ENTRY | 203 DictionaryListEventFlags::DEL_POS_ENTRY | 204 DictionaryListEventFlags::ACTIVATE_NEG_DIC | 205 DictionaryListEventFlags::DEACTIVATE_POS_DIC; 206 sal_Bool bFlush = 0 != (nEvt & nFlushFlags); 207 208 DBG_ASSERT( pFlushObj, "missing object (NULL pointer)" ); 209 if (bFlush && pFlushObj != NULL) 210 pFlushObj->Flush(); 211 } 212 } 213 214 215 void SAL_CALL FlushListener::propertyChange( 216 const PropertyChangeEvent& rEvt ) 217 throw(RuntimeException) 218 { 219 MutexGuard aGuard( GetLinguMutex() ); 220 221 if (rEvt.Source == xPropSet) 222 { 223 sal_Bool bFlush = lcl_IsFlushProperty( rEvt.PropertyHandle ); 224 225 DBG_ASSERT( pFlushObj, "missing object (NULL pointer)" ); 226 if (bFlush && pFlushObj != NULL) 227 pFlushObj->Flush(); 228 } 229 } 230 231 232 /////////////////////////////////////////////////////////////////////////// 233 234 SpellCache::SpellCache() 235 { 236 pFlushLstnr = new FlushListener( this ); 237 xFlushLstnr = pFlushLstnr; 238 Reference<XDictionaryList> aDictionaryList(GetDictionaryList()); 239 pFlushLstnr->SetDicList( aDictionaryList ); //! after reference is established 240 Reference<XPropertySet> aPropertySet(GetLinguProperties()); 241 pFlushLstnr->SetPropSet( aPropertySet ); //! after reference is established 242 } 243 244 SpellCache::~SpellCache() 245 { 246 Reference<XDictionaryList> aEmptyList; 247 Reference<XPropertySet> aEmptySet; 248 pFlushLstnr->SetDicList( aEmptyList ); 249 pFlushLstnr->SetPropSet( aEmptySet ); 250 } 251 252 void SpellCache::Flush() 253 { 254 MutexGuard aGuard( GetLinguMutex() ); 255 // clear word list 256 LangWordList_t aEmpty; 257 aWordLists.swap( aEmpty ); 258 } 259 260 bool SpellCache::CheckWord( const OUString& rWord, LanguageType nLang ) 261 { 262 MutexGuard aGuard( GetLinguMutex() ); 263 WordList_t &rList = aWordLists[ nLang ]; 264 const WordList_t::const_iterator aIt = rList.find( rWord ); 265 return aIt != rList.end(); 266 } 267 268 void SpellCache::AddWord( const OUString& rWord, LanguageType nLang ) 269 { 270 MutexGuard aGuard( GetLinguMutex() ); 271 WordList_t & rList = aWordLists[ nLang ]; 272 // occasional clean-up... 273 if (rList.size() > 500) 274 rList.clear(); 275 rList.insert( rWord ); 276 } 277 /////////////////////////////////////////////////////////////////////////// 278 279 } // namespace linguistic 280 281