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