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