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