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 // uno 25 import com.sun.star.lib.uno.helper.ComponentBase; 26 import com.sun.star.uno.UnoRuntime; 27 28 // factories 29 import com.sun.star.lang.XMultiServiceFactory; 30 import com.sun.star.lang.XSingleServiceFactory; 31 32 // supported Interfaces 33 import com.sun.star.linguistic2.XSpellChecker; 34 import com.sun.star.linguistic2.XLinguServiceEventBroadcaster; 35 import com.sun.star.lang.XInitialization; 36 import com.sun.star.lang.XComponent; 37 import com.sun.star.lang.XServiceInfo; 38 import com.sun.star.lang.XServiceDisplayName; 39 40 // Exceptions 41 import com.sun.star.uno.Exception; 42 import com.sun.star.uno.RuntimeException; 43 import com.sun.star.lang.IllegalArgumentException; 44 45 //used Interfaces 46 import com.sun.star.linguistic2.XLinguServiceEventListener; 47 import com.sun.star.linguistic2.XSpellAlternatives; 48 import com.sun.star.linguistic2.SpellFailure; 49 import com.sun.star.lang.Locale; 50 import com.sun.star.lang.XEventListener; 51 import com.sun.star.lang.EventObject; 52 import com.sun.star.beans.XPropertySet; 53 import com.sun.star.beans.PropertyValue; 54 import com.sun.star.uno.AnyConverter; 55 import com.sun.star.lang.XTypeProvider; 56 import com.sun.star.uno.XInterface; 57 import com.sun.star.uno.Type; 58 59 import java.util.ArrayList; 60 61 public class SampleSpellChecker extends ComponentBase implements 62 XSpellChecker, 63 XLinguServiceEventBroadcaster, 64 XInitialization, 65 XServiceDisplayName, 66 XServiceInfo 67 { 68 PropChgHelper_Spell aPropChgHelper; 69 ArrayList aEvtListeners; 70 boolean bDisposing; 71 SampleSpellChecker()72 public SampleSpellChecker() 73 { 74 // names of relevant properties to be used 75 String[] aProps = new String[] 76 { 77 "IsIgnoreControlCharacters", 78 "IsUseDictionaryList", 79 "IsGermanPreReform", 80 "IsSpellUpperCase", 81 "IsSpellWithDigits", 82 "IsSpellCapitalization" 83 }; 84 aPropChgHelper = new PropChgHelper_Spell( (XSpellChecker) this, aProps ); 85 aEvtListeners = new ArrayList(); 86 bDisposing = false; 87 } 88 IsEqual( Locale aLoc1, Locale aLoc2 )89 private boolean IsEqual( Locale aLoc1, Locale aLoc2 ) 90 { 91 return aLoc1.Language.equals( aLoc2.Language ) && 92 aLoc1.Country .equals( aLoc2.Country ) && 93 aLoc1.Variant .equals( aLoc2.Variant ); 94 } 95 GetValueToUse( String aPropName, boolean bDefaultVal, PropertyValue[] aProps )96 private boolean GetValueToUse( 97 String aPropName, 98 boolean bDefaultVal, 99 PropertyValue[] aProps ) 100 { 101 boolean bRes = bDefaultVal; 102 103 try 104 { 105 // use temporary value if supplied 106 for (int i = 0; i < aProps.length; ++i) 107 { 108 if (aPropName.equals( aProps[i].Name )) 109 { 110 Object aObj = aProps[i].Value; 111 if (AnyConverter.isBoolean( aObj )) 112 { 113 bRes = AnyConverter.toBoolean( aObj ); 114 return bRes; 115 } 116 } 117 } 118 119 // otherwise use value from property set (if available) 120 XPropertySet xPropSet = aPropChgHelper.GetPropSet(); 121 if (xPropSet != null) // should always be the case 122 { 123 Object aObj = xPropSet.getPropertyValue( aPropName ); 124 if (AnyConverter.isBoolean( aObj )) 125 bRes = AnyConverter.toBoolean( aObj ); 126 } 127 } 128 catch (Exception e) { 129 bRes = bDefaultVal; 130 } 131 132 return bRes; 133 } 134 IsUpper( String aWord, Locale aLocale )135 private boolean IsUpper( String aWord, Locale aLocale ) 136 { 137 java.util.Locale aLang = new java.util.Locale( 138 aLocale.Language, aLocale.Country, aLocale.Variant ); 139 return aWord.equals( aWord.toUpperCase( aLang ) ); 140 } 141 HasDigits( String aWord )142 private boolean HasDigits( String aWord ) 143 { 144 int nLen = aWord.length(); 145 for (int i = 0; i < nLen; ++i) 146 { 147 if (Character.isDigit( aWord.charAt(i) )) 148 return true; 149 } 150 return false; 151 } 152 GetSpellFailure( String aWord, Locale aLocale, PropertyValue[] aProperties )153 private short GetSpellFailure( 154 String aWord, 155 Locale aLocale, 156 PropertyValue[] aProperties ) 157 { 158 short nRes = -1; 159 160 //!! This code needs to be replaced by code calling the actual 161 //!! implementation of your spellchecker 162 boolean bIsGermanPreReform = GetValueToUse( "IsGermanPreReform", false, aProperties ); 163 if (IsEqual( aLocale, new Locale( "de", "DE", "" ) )) 164 { 165 if (bIsGermanPreReform && aWord.equals( "Schifffahrt" )) 166 nRes = SpellFailure.SPELLING_ERROR; 167 else if (!bIsGermanPreReform && aWord.equals( "Schiffahrt" )) 168 nRes = SpellFailure.SPELLING_ERROR; 169 } 170 else if (IsEqual( aLocale, new Locale( "en", "US", "" ) )) 171 { 172 // words with 'u', 'U' and 'arizona' are defined to be incorrect 173 boolean bIsValid = !(aWord.indexOf( "u" ) != -1 || aWord.indexOf( "U" ) != -1) 174 && !aWord.equals( "arizona" ); 175 176 if (!bIsValid) 177 { 178 // default value (no other SpellFailure type is applicable) 179 nRes = SpellFailure.SPELLING_ERROR; 180 181 if (aWord.equals( "arizona" )) 182 nRes = SpellFailure.CAPTION_ERROR; 183 else if (aWord.equals( "house" )) 184 nRes = SpellFailure.SPELLING_ERROR; 185 else if (aWord.equals( "course" )) 186 nRes = SpellFailure.IS_NEGATIVE_WORD; 187 } 188 } 189 190 return nRes; 191 } 192 GetProposals( String aWord, Locale aLocale, PropertyValue[] aProperties )193 private XSpellAlternatives GetProposals( 194 String aWord, 195 Locale aLocale, 196 PropertyValue[] aProperties ) 197 { 198 short nType = SpellFailure.SPELLING_ERROR; 199 String[] aProposals = null; 200 201 // get values of relevant properties that may be used. 202 //! The values for 'IsIgnoreControlCharacters' and 'IsUseDictionaryList' 203 //! are handled by the dispatcher! Thus there is no need to access 204 //! them here. 205 boolean bIsGermanPreReform = GetValueToUse( "IsGermanPreReform", false, aProperties ); 206 boolean bIsSpellWithDigits = GetValueToUse( "IsSpellWithDigits", false, aProperties ); 207 boolean bIsSpellUpperCase = GetValueToUse( "IsSpellUpperCase", false, aProperties ); 208 boolean bIsSpellCapitalization = GetValueToUse( "IsSpellCapitalization", true, aProperties ); 209 210 //!! This code needs to be replaced by code calling the actual 211 //!! implementation of your spellchecker 212 if (IsEqual( aLocale, new Locale( "de", "DE", "" ) )) 213 { 214 if (bIsGermanPreReform && aWord.equals( "Schifffahrt" )) 215 { 216 nType = SpellFailure.SPELLING_ERROR; 217 aProposals = new String[]{ "Schiffahrt" }; 218 } 219 else if (!bIsGermanPreReform && aWord.equals( "Schiffahrt" )) 220 { 221 nType = SpellFailure.SPELLING_ERROR; 222 aProposals = new String[]{ "Schifffahrt" }; 223 } 224 } 225 else if (IsEqual( aLocale, new Locale( "en", "US", "" ) )) 226 { 227 if (aWord.equals( "arizona" )) 228 { 229 nType = SpellFailure.CAPTION_ERROR; 230 aProposals = new String[]{ "Arizona" }; 231 } 232 else if (aWord.equals( "house" )) 233 { 234 nType = SpellFailure.SPELLING_ERROR; 235 aProposals = new String[]{ "horse", "home" }; 236 } 237 else if (aWord.equals( "course" )) 238 { 239 nType = SpellFailure.IS_NEGATIVE_WORD; 240 aProposals = new String[]{ "line", "plan", "approach" }; 241 } 242 } 243 244 // always return a result if word is incorrect, 245 // proposals may be empty though. 246 return new XSpellAlternatives_impl( aWord, aLocale, 247 nType, aProposals ); 248 } 249 250 // __________ interface methods __________ 251 252 253 //***************** 254 //XSupportedLocales 255 //***************** getLocales()256 public Locale[] getLocales() 257 throws com.sun.star.uno.RuntimeException 258 { 259 Locale aLocales[] = 260 { 261 new Locale( "de", "DE", "" ), 262 new Locale( "en", "US", "" ) 263 }; 264 265 return aLocales; 266 } 267 hasLocale( Locale aLocale )268 public boolean hasLocale( Locale aLocale ) 269 throws com.sun.star.uno.RuntimeException 270 { 271 boolean bRes = false; 272 if ( IsEqual( aLocale, new Locale( "de", "DE", "" ) ) || 273 IsEqual( aLocale, new Locale( "en", "US", "" ) )) 274 bRes = true; 275 return bRes; 276 } 277 278 279 //************* 280 //XSpellChecker 281 //************* isValid( String aWord, Locale aLocale, PropertyValue[] aProperties )282 public boolean isValid( 283 String aWord, Locale aLocale, 284 PropertyValue[] aProperties ) 285 throws com.sun.star.uno.RuntimeException, 286 IllegalArgumentException 287 { 288 if (IsEqual( aLocale, new Locale() ) || aWord.length() == 0) 289 return true; 290 291 // linguistic is currently not allowed to throw exceptions 292 // thus we return null which means 'word cannot be spelled' 293 if (!hasLocale( aLocale )) 294 return true; 295 296 // get values of relevant properties that may be used. 297 //! The values for 'IsIgnoreControlCharacters' and 'IsUseDictionaryList' 298 //! are handled by the dispatcher! Thus there is no need to access 299 //! them here. 300 boolean bIsGermanPreReform = GetValueToUse( "IsGermanPreReform", false, aProperties ); 301 boolean bIsSpellWithDigits = GetValueToUse( "IsSpellWithDigits", false, aProperties ); 302 boolean bIsSpellUpperCase = GetValueToUse( "IsSpellUpperCase", false, aProperties ); 303 boolean bIsSpellCapitalization = GetValueToUse( "IsSpellCapitalization", true, aProperties ); 304 305 short nFailure = GetSpellFailure( aWord, aLocale, aProperties ); 306 if (nFailure != -1) 307 { 308 // postprocess result for errors that should be ignored 309 if ( (!bIsSpellUpperCase && IsUpper( aWord, aLocale )) 310 || (!bIsSpellWithDigits && HasDigits( aWord )) 311 || (!bIsSpellCapitalization 312 && nFailure == SpellFailure.CAPTION_ERROR) 313 ) 314 nFailure = -1; 315 } 316 317 return nFailure == -1; 318 } 319 320 spell( String aWord, Locale aLocale, PropertyValue[] aProperties )321 public XSpellAlternatives spell( 322 String aWord, Locale aLocale, 323 PropertyValue[] aProperties ) 324 throws com.sun.star.uno.RuntimeException, 325 IllegalArgumentException 326 { 327 if (IsEqual( aLocale, new Locale() ) || aWord.length() == 0) 328 return null; 329 330 // linguistic is currently not allowed to throw exceptions 331 // thus we return null which means 'word cannot be spelled' 332 if (!hasLocale( aLocale )) 333 return null; 334 335 XSpellAlternatives xRes = null; 336 if (!isValid( aWord, aLocale, aProperties )) 337 { 338 xRes = GetProposals( aWord, aLocale, aProperties ); 339 } 340 return xRes; 341 } 342 343 344 //***************************** 345 //XLinguServiceEventBroadcaster 346 //***************************** addLinguServiceEventListener( XLinguServiceEventListener xLstnr )347 public boolean addLinguServiceEventListener ( 348 XLinguServiceEventListener xLstnr ) 349 throws com.sun.star.uno.RuntimeException 350 { 351 boolean bRes = false; 352 if (!bDisposing && xLstnr != null) 353 bRes = aPropChgHelper.addLinguServiceEventListener( xLstnr ); 354 return bRes; 355 } 356 removeLinguServiceEventListener( XLinguServiceEventListener xLstnr )357 public boolean removeLinguServiceEventListener( 358 XLinguServiceEventListener xLstnr ) 359 throws com.sun.star.uno.RuntimeException 360 { 361 boolean bRes = false; 362 if (!bDisposing && xLstnr != null) 363 bRes = aPropChgHelper.removeLinguServiceEventListener( xLstnr ); 364 return bRes; 365 } 366 367 //******************** 368 // XServiceDisplayName 369 //******************** getServiceDisplayName( Locale aLocale )370 public String getServiceDisplayName( Locale aLocale ) 371 throws com.sun.star.uno.RuntimeException 372 { 373 return "Java Samples"; 374 } 375 376 //**************** 377 // XInitialization 378 //**************** initialize( Object[] aArguments )379 public void initialize( Object[] aArguments ) 380 throws com.sun.star.uno.Exception, 381 com.sun.star.uno.RuntimeException 382 { 383 int nLen = aArguments.length; 384 if (2 == nLen) 385 { 386 XPropertySet xPropSet = (XPropertySet)UnoRuntime.queryInterface( 387 XPropertySet.class, aArguments[0]); 388 // start listening to property changes 389 aPropChgHelper.AddAsListenerTo( xPropSet ); 390 } 391 } 392 393 //************* 394 // XServiceInfo 395 //************* supportsService( String aServiceName )396 public boolean supportsService( String aServiceName ) 397 throws com.sun.star.uno.RuntimeException 398 { 399 String[] aServices = getSupportedServiceNames_Static(); 400 int i, nLength = aServices.length; 401 boolean bResult = false; 402 403 for( i = 0; !bResult && i < nLength; ++i ) 404 bResult = aServiceName.equals( aServices[ i ] ); 405 406 return bResult; 407 } 408 getImplementationName()409 public String getImplementationName() 410 throws com.sun.star.uno.RuntimeException 411 { 412 return _aSvcImplName; 413 } 414 getSupportedServiceNames()415 public String[] getSupportedServiceNames() 416 throws com.sun.star.uno.RuntimeException 417 { 418 return getSupportedServiceNames_Static(); 419 } 420 421 // __________ static things __________ 422 423 public static String _aSvcImplName = SampleSpellChecker.class.getName(); 424 getSupportedServiceNames_Static()425 public static String[] getSupportedServiceNames_Static() 426 { 427 String[] aResult = { "com.sun.star.linguistic2.SpellChecker" }; 428 return aResult; 429 } 430 431 432 /** 433 * Returns a factory for creating the service. 434 * This method is called by the <code>JavaLoader</code> 435 * <p> 436 * @return returns a <code>XSingleServiceFactory</code> for creating the component 437 * @param implName the name of the implementation for which a service is desired 438 * @param multiFactory the service manager to be used if needed 439 * @param regKey the registryKey 440 * @see com.sun.star.comp.loader.JavaLoader 441 */ __getServiceFactory( String aImplName, XMultiServiceFactory xMultiFactory, com.sun.star.registry.XRegistryKey xRegKey )442 public static XSingleServiceFactory __getServiceFactory( 443 String aImplName, 444 XMultiServiceFactory xMultiFactory, 445 com.sun.star.registry.XRegistryKey xRegKey ) 446 { 447 XSingleServiceFactory xSingleServiceFactory = null; 448 if( aImplName.equals( _aSvcImplName ) ) 449 { 450 xSingleServiceFactory = new OneInstanceFactory( 451 SampleSpellChecker.class, _aSvcImplName, 452 getSupportedServiceNames_Static(), 453 xMultiFactory ); 454 } 455 return xSingleServiceFactory; 456 } 457 458 /** 459 * Writes the service information into the given registry key. 460 * This method is called by the <code>JavaLoader</code> 461 * <p> 462 * @return returns true if the operation succeeded 463 * @param xRegKey the registryKey 464 * @see com.sun.star.comp.loader.JavaLoader 465 */ 466 // This method not longer necessary since OOo 3.4 where the component registration 467 // was changed to passive component registration. For more details see 468 // https://wiki.openoffice.org/wiki/Passive_Component_Registration 469 470 // public static boolean __writeRegistryServiceInfo( 471 // com.sun.star.registry.XRegistryKey xRegKey ) 472 // { 473 // boolean bResult = true; 474 // String[] aServices = getSupportedServiceNames_Static(); 475 // int i, nLength = aServices.length; 476 // for( i = 0; i < nLength; ++i ) 477 // { 478 // bResult = bResult && com.sun.star.comp.loader.FactoryHelper.writeRegistryServiceInfo( 479 // _aSvcImplName, aServices[i], xRegKey ); 480 // } 481 // return bResult; 482 // } 483 } 484 485