xref: /AOO41X/main/lingucomponent/source/spellcheck/macosxspell/macspellimp.cxx (revision b0844812064e3450486bf80ca0c2a3ca72742d45)
1*b0844812SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*b0844812SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*b0844812SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*b0844812SAndrew Rist  * distributed with this work for additional information
6*b0844812SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*b0844812SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*b0844812SAndrew Rist  * "License"); you may not use this file except in compliance
9*b0844812SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11*b0844812SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13*b0844812SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*b0844812SAndrew Rist  * software distributed under the License is distributed on an
15*b0844812SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b0844812SAndrew Rist  * KIND, either express or implied.  See the License for the
17*b0844812SAndrew Rist  * specific language governing permissions and limitations
18*b0844812SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20*b0844812SAndrew Rist  *************************************************************/
21*b0844812SAndrew Rist 
22*b0844812SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_lingucomponent.hxx"
26cdf0e10cSrcweir #include <com/sun/star/uno/Reference.h>
27cdf0e10cSrcweir #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #include <com/sun/star/linguistic2/SpellFailure.hpp>
30cdf0e10cSrcweir #include <cppuhelper/factory.hxx>	// helper for factories
31cdf0e10cSrcweir #include <com/sun/star/registry/XRegistryKey.hpp>
32cdf0e10cSrcweir #include <tools/debug.hxx>
33cdf0e10cSrcweir #include <unotools/processfactory.hxx>
34cdf0e10cSrcweir #include <osl/mutex.hxx>
35cdf0e10cSrcweir 
36cdf0e10cSrcweir //#include <hunspell.hxx>
37cdf0e10cSrcweir #include <dictmgr.hxx>
38cdf0e10cSrcweir #include <macspellimp.hxx>
39cdf0e10cSrcweir 
40cdf0e10cSrcweir //#include <linguistic/lngprops.hxx>
41cdf0e10cSrcweir #include <linguistic/spelldta.hxx>
42cdf0e10cSrcweir #include <unotools/pathoptions.hxx>
43cdf0e10cSrcweir #include <unotools/useroptions.hxx>
44cdf0e10cSrcweir #include <osl/file.hxx>
45cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
46cdf0e10cSrcweir 
47cdf0e10cSrcweir 
48cdf0e10cSrcweir using namespace utl;
49cdf0e10cSrcweir using namespace osl;
50cdf0e10cSrcweir using namespace rtl;
51cdf0e10cSrcweir using namespace com::sun::star;
52cdf0e10cSrcweir using namespace com::sun::star::beans;
53cdf0e10cSrcweir using namespace com::sun::star::lang;
54cdf0e10cSrcweir using namespace com::sun::star::uno;
55cdf0e10cSrcweir using namespace com::sun::star::linguistic2;
56cdf0e10cSrcweir using namespace linguistic;
57cdf0e10cSrcweir ///////////////////////////////////////////////////////////////////////////
58cdf0e10cSrcweir // dbg_dump for development
59cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
60cdf0e10cSrcweir #include <rtl/strbuf.hxx>
61cdf0e10cSrcweir #include <rtl/ustring.hxx>
62cdf0e10cSrcweir 
63cdf0e10cSrcweir const sal_Char *dbg_dump(const rtl::OString &rStr)
64cdf0e10cSrcweir {
65cdf0e10cSrcweir     static rtl::OStringBuffer aStr;
66cdf0e10cSrcweir 
67cdf0e10cSrcweir     aStr = rtl::OStringBuffer(rStr);
68cdf0e10cSrcweir     aStr.append(static_cast<char>(0));
69cdf0e10cSrcweir     return aStr.getStr();
70cdf0e10cSrcweir }
71cdf0e10cSrcweir 
72cdf0e10cSrcweir const sal_Char *dbg_dump(const rtl::OUString &rStr)
73cdf0e10cSrcweir {
74cdf0e10cSrcweir     return dbg_dump(rtl::OUStringToOString(rStr, RTL_TEXTENCODING_UTF8));
75cdf0e10cSrcweir }
76cdf0e10cSrcweir 
77cdf0e10cSrcweir const sal_Char *dbg_dump(rtl_String *pStr)
78cdf0e10cSrcweir {
79cdf0e10cSrcweir     return dbg_dump(rtl::OString(pStr));
80cdf0e10cSrcweir }
81cdf0e10cSrcweir 
82cdf0e10cSrcweir const sal_Char *dbg_dump(rtl_uString *pStr)
83cdf0e10cSrcweir {
84cdf0e10cSrcweir     return dbg_dump(rtl::OUString(pStr));
85cdf0e10cSrcweir }
86cdf0e10cSrcweir 
87cdf0e10cSrcweir #endif
88cdf0e10cSrcweir ///////////////////////////////////////////////////////////////////////////
89cdf0e10cSrcweir 
90cdf0e10cSrcweir MacSpellChecker::MacSpellChecker() :
91cdf0e10cSrcweir 	aEvtListeners	( GetLinguMutex() )
92cdf0e10cSrcweir {
93cdf0e10cSrcweir //    aDicts = NULL;
94cdf0e10cSrcweir 	aDEncs = NULL;
95cdf0e10cSrcweir 	aDLocs = NULL;
96cdf0e10cSrcweir 	aDNames = NULL;
97cdf0e10cSrcweir 	bDisposing = sal_False;
98cdf0e10cSrcweir 	pPropHelper = NULL;
99cdf0e10cSrcweir     numdict = 0;
100cdf0e10cSrcweir     NSApplicationLoad();
101cdf0e10cSrcweir 	NSAutoreleasePool* pool	= [[NSAutoreleasePool alloc] init];
102cdf0e10cSrcweir     macSpell = [NSSpellChecker sharedSpellChecker];
103cdf0e10cSrcweir     macTag = [NSSpellChecker uniqueSpellDocumentTag];
104cdf0e10cSrcweir     [pool release];
105cdf0e10cSrcweir }
106cdf0e10cSrcweir 
107cdf0e10cSrcweir 
108cdf0e10cSrcweir MacSpellChecker::~MacSpellChecker()
109cdf0e10cSrcweir {
110cdf0e10cSrcweir   // if (aDicts) {
111cdf0e10cSrcweir   //    for (int i = 0; i < numdict; i++) {
112cdf0e10cSrcweir   //           if (aDicts[i]) delete aDicts[i];
113cdf0e10cSrcweir   //           aDicts[i] = NULL;
114cdf0e10cSrcweir   //    }
115cdf0e10cSrcweir   //    delete[] aDicts;
116cdf0e10cSrcweir   // }
117cdf0e10cSrcweir   // aDicts = NULL;
118cdf0e10cSrcweir   numdict = 0;
119cdf0e10cSrcweir   if (aDEncs) delete[] aDEncs;
120cdf0e10cSrcweir   aDEncs = NULL;
121cdf0e10cSrcweir   if (aDLocs) delete[] aDLocs;
122cdf0e10cSrcweir   aDLocs = NULL;
123cdf0e10cSrcweir   if (aDNames) delete[] aDNames;
124cdf0e10cSrcweir   aDNames = NULL;
125cdf0e10cSrcweir   if (pPropHelper)
126cdf0e10cSrcweir 	 pPropHelper->RemoveAsPropListener();
127cdf0e10cSrcweir }
128cdf0e10cSrcweir 
129cdf0e10cSrcweir 
130cdf0e10cSrcweir PropertyHelper_Spell & MacSpellChecker::GetPropHelper_Impl()
131cdf0e10cSrcweir {
132cdf0e10cSrcweir 	if (!pPropHelper)
133cdf0e10cSrcweir 	{
134cdf0e10cSrcweir 		Reference< XPropertySet	>	xPropSet( GetLinguProperties(), UNO_QUERY );
135cdf0e10cSrcweir 
136cdf0e10cSrcweir 		pPropHelper	= new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
137cdf0e10cSrcweir 		xPropHelper = pPropHelper;
138cdf0e10cSrcweir 		pPropHelper->AddAsPropListener();	//! after a reference is established
139cdf0e10cSrcweir 	}
140cdf0e10cSrcweir 	return *pPropHelper;
141cdf0e10cSrcweir }
142cdf0e10cSrcweir 
143cdf0e10cSrcweir 
144cdf0e10cSrcweir Sequence< Locale > SAL_CALL MacSpellChecker::getLocales()
145cdf0e10cSrcweir 		throw(RuntimeException)
146cdf0e10cSrcweir {
147cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
148cdf0e10cSrcweir 
149cdf0e10cSrcweir         // this routine should return the locales supported by the installed
150cdf0e10cSrcweir         // dictionaries.  So here we need to parse both the user edited
151cdf0e10cSrcweir         // dictionary list and the shared dictionary list
152cdf0e10cSrcweir         // to see what dictionaries the admin/user has installed
153cdf0e10cSrcweir 
154cdf0e10cSrcweir         int numusr;          // number of user dictionary entries
155cdf0e10cSrcweir         int numshr;          // number of shared dictionary entries
156cdf0e10cSrcweir         dictentry * spdict;  // shared dict entry pointer
157cdf0e10cSrcweir         dictentry * updict;  // user dict entry pointer
158cdf0e10cSrcweir         SvtPathOptions aPathOpt;
159cdf0e10cSrcweir 		rtl_TextEncoding aEnc = RTL_TEXTENCODING_UTF8;
160cdf0e10cSrcweir 
161cdf0e10cSrcweir     	std::vector<objc_object *> postspdict;
162cdf0e10cSrcweir     	//std::vector<dictentry *> postspdict;
163cdf0e10cSrcweir         std::vector<dictentry *> postupdict;
164cdf0e10cSrcweir 
165cdf0e10cSrcweir 
166cdf0e10cSrcweir 	if (!numdict) {
167cdf0e10cSrcweir 
168cdf0e10cSrcweir         // invoke a dictionary manager to get the user dictionary list
169cdf0e10cSrcweir         // TODO How on Mac OS X?
170cdf0e10cSrcweir 
171cdf0e10cSrcweir         // invoke a second  dictionary manager to get the shared dictionary list
172cdf0e10cSrcweir         NSArray *aLocales = [NSLocale availableLocaleIdentifiers];
173cdf0e10cSrcweir 
174cdf0e10cSrcweir         //Test for existence of the dictionaries
175cdf0e10cSrcweir         for (unsigned int i = 0; i < [aLocales count]; i++)
176cdf0e10cSrcweir         {
177cdf0e10cSrcweir             if( [macSpell setLanguage:[aLocales objectAtIndex:i] ] )
178cdf0e10cSrcweir             {
179cdf0e10cSrcweir                 postspdict.push_back( [ aLocales objectAtIndex:i ] );
180cdf0e10cSrcweir             }
181cdf0e10cSrcweir         }
182cdf0e10cSrcweir 
183cdf0e10cSrcweir 	    numusr = postupdict.size();
184cdf0e10cSrcweir         numshr = postspdict.size();
185cdf0e10cSrcweir 
186cdf0e10cSrcweir         // we really should merge these and remove duplicates but since
187cdf0e10cSrcweir         // users can name their dictionaries anything they want it would
188cdf0e10cSrcweir         // be impossible to know if a real duplication exists unless we
189cdf0e10cSrcweir         // add some unique key to each myspell dictionary
190cdf0e10cSrcweir         numdict = numshr + numusr;
191cdf0e10cSrcweir 
192cdf0e10cSrcweir         if (numdict) {
193cdf0e10cSrcweir             aDLocs = new Locale [numdict];
194cdf0e10cSrcweir             aDEncs  = new rtl_TextEncoding [numdict];
195cdf0e10cSrcweir             aDNames = new OUString [numdict];
196cdf0e10cSrcweir             aSuppLocales.realloc(numdict);
197cdf0e10cSrcweir             Locale * pLocale = aSuppLocales.getArray();
198cdf0e10cSrcweir             int numlocs = 0;
199cdf0e10cSrcweir             int newloc;
200cdf0e10cSrcweir             int i,j;
201cdf0e10cSrcweir             int k = 0;
202cdf0e10cSrcweir 
203cdf0e10cSrcweir             //first add the user dictionaries
204cdf0e10cSrcweir             //TODO for MAC?
205cdf0e10cSrcweir 
206cdf0e10cSrcweir             // now add the shared dictionaries
207cdf0e10cSrcweir             for (i = 0; i < numshr; i++) {
208cdf0e10cSrcweir                 NSDictionary *aLocDict = [ NSLocale componentsFromLocaleIdentifier:postspdict[i] ];
209cdf0e10cSrcweir                 NSString* aLang = [ aLocDict objectForKey:NSLocaleLanguageCode ];
210cdf0e10cSrcweir                 NSString* aCountry = [ aLocDict objectForKey:NSLocaleCountryCode ];
211cdf0e10cSrcweir                 OUString lang([aLang cStringUsingEncoding: NSUTF8StringEncoding], [aLang length], aEnc);
212cdf0e10cSrcweir                 OUString country([ aCountry cStringUsingEncoding: NSUTF8StringEncoding], [aCountry length], aEnc);
213cdf0e10cSrcweir                 Locale nLoc( lang, country, OUString() );
214cdf0e10cSrcweir                 newloc = 1;
215cdf0e10cSrcweir                 //eliminate duplicates (is this needed for MacOS?)
216cdf0e10cSrcweir                 for (j = 0; j < numlocs; j++) {
217cdf0e10cSrcweir                     if (nLoc == pLocale[j]) newloc = 0;
218cdf0e10cSrcweir                 }
219cdf0e10cSrcweir                 if (newloc) {
220cdf0e10cSrcweir                     pLocale[numlocs] = nLoc;
221cdf0e10cSrcweir                     numlocs++;
222cdf0e10cSrcweir                 }
223cdf0e10cSrcweir                 aDLocs[k] = nLoc;
224cdf0e10cSrcweir                 //pointer to Hunspell dictionary - not needed for MAC
225cdf0e10cSrcweir                 //aDicts[k] = NULL;
226cdf0e10cSrcweir                 aDEncs[k] = 0;
227cdf0e10cSrcweir                 // Dictionary file names not valid for Mac Spell
228cdf0e10cSrcweir                 //aDNames[k] = aPathOpt.GetLinguisticPath() + A2OU("/ooo/") + A2OU(postspdict[i]->filename);
229cdf0e10cSrcweir                 k++;
230cdf0e10cSrcweir             }
231cdf0e10cSrcweir 
232cdf0e10cSrcweir             aSuppLocales.realloc(numlocs);
233cdf0e10cSrcweir 
234cdf0e10cSrcweir         } else {
235cdf0e10cSrcweir             /* no dictionary.lst found so register no dictionaries */
236cdf0e10cSrcweir             numdict = 0;
237cdf0e10cSrcweir             //aDicts = NULL;
238cdf0e10cSrcweir                 aDEncs  = NULL;
239cdf0e10cSrcweir                 aDLocs = NULL;
240cdf0e10cSrcweir                 aDNames = NULL;
241cdf0e10cSrcweir 	            aSuppLocales.realloc(0);
242cdf0e10cSrcweir             }
243cdf0e10cSrcweir 
244cdf0e10cSrcweir             /* de-allocation of memory is handled inside the DictMgr */
245cdf0e10cSrcweir             updict = NULL;
246cdf0e10cSrcweir             spdict = NULL;
247cdf0e10cSrcweir 
248cdf0e10cSrcweir         }
249cdf0e10cSrcweir 
250cdf0e10cSrcweir 	return aSuppLocales;
251cdf0e10cSrcweir }
252cdf0e10cSrcweir 
253cdf0e10cSrcweir 
254cdf0e10cSrcweir 
255cdf0e10cSrcweir sal_Bool SAL_CALL MacSpellChecker::hasLocale(const Locale& rLocale)
256cdf0e10cSrcweir 		throw(RuntimeException)
257cdf0e10cSrcweir {
258cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
259cdf0e10cSrcweir 
260cdf0e10cSrcweir 	sal_Bool bRes = sal_False;
261cdf0e10cSrcweir 	if (!aSuppLocales.getLength())
262cdf0e10cSrcweir 		getLocales();
263cdf0e10cSrcweir 
264cdf0e10cSrcweir 	sal_Int32 nLen = aSuppLocales.getLength();
265cdf0e10cSrcweir 	for (sal_Int32 i = 0;  i < nLen;  ++i)
266cdf0e10cSrcweir 	{
267cdf0e10cSrcweir 		const Locale *pLocale = aSuppLocales.getConstArray();
268cdf0e10cSrcweir 		if (rLocale == pLocale[i])
269cdf0e10cSrcweir 		{
270cdf0e10cSrcweir 			bRes = sal_True;
271cdf0e10cSrcweir 			break;
272cdf0e10cSrcweir 		}
273cdf0e10cSrcweir 	}
274cdf0e10cSrcweir 	return bRes;
275cdf0e10cSrcweir }
276cdf0e10cSrcweir 
277cdf0e10cSrcweir 
278cdf0e10cSrcweir sal_Int16 MacSpellChecker::GetSpellFailure( const OUString &rWord, const Locale &rLocale )
279cdf0e10cSrcweir {
280cdf0e10cSrcweir     rtl_TextEncoding aEnc;
281cdf0e10cSrcweir 
282cdf0e10cSrcweir 	// initialize a myspell object for each dictionary once
283cdf0e10cSrcweir         // (note: mutex is held higher up in isValid)
284cdf0e10cSrcweir 
285cdf0e10cSrcweir 
286cdf0e10cSrcweir 	sal_Int16 nRes = -1;
287cdf0e10cSrcweir 
288cdf0e10cSrcweir         // first handle smart quotes both single and double
289cdf0e10cSrcweir 	OUStringBuffer rBuf(rWord);
290cdf0e10cSrcweir         sal_Int32 n = rBuf.getLength();
291cdf0e10cSrcweir         sal_Unicode c;
292cdf0e10cSrcweir 	for (sal_Int32 ix=0; ix < n; ix++) {
293cdf0e10cSrcweir 	    c = rBuf.charAt(ix);
294cdf0e10cSrcweir             if ((c == 0x201C) || (c == 0x201D)) rBuf.setCharAt(ix,(sal_Unicode)0x0022);
295cdf0e10cSrcweir             if ((c == 0x2018) || (c == 0x2019)) rBuf.setCharAt(ix,(sal_Unicode)0x0027);
296cdf0e10cSrcweir         }
297cdf0e10cSrcweir         OUString nWord(rBuf.makeStringAndClear());
298cdf0e10cSrcweir 
299cdf0e10cSrcweir 	if (n)
300cdf0e10cSrcweir 	{
301cdf0e10cSrcweir         aEnc = 0;
302cdf0e10cSrcweir 		NSAutoreleasePool* pool	= [[NSAutoreleasePool alloc] init];
303cdf0e10cSrcweir         NSString* aNSStr = [[NSString alloc] initWithCharacters: nWord.getStr() length: nWord.getLength()];
304cdf0e10cSrcweir         NSString* aLang = [[NSString alloc] initWithCharacters: rLocale.Language.getStr() length: rLocale.Language.getLength()];
305cdf0e10cSrcweir         if(rLocale.Country.getLength()>0)
306cdf0e10cSrcweir         {
307cdf0e10cSrcweir             NSString* aCountry = [[NSString alloc] initWithCharacters: rLocale.Country.getStr() length: rLocale.Country.getLength()];
308cdf0e10cSrcweir             NSString* aTag = @"_";
309cdf0e10cSrcweir             NSString* aTaggedCountry = [aTag stringByAppendingString:aCountry];
310cdf0e10cSrcweir             [aLang autorelease];
311cdf0e10cSrcweir             aLang = [aLang  stringByAppendingString:aTaggedCountry];
312cdf0e10cSrcweir         }
313cdf0e10cSrcweir 
314cdf0e10cSrcweir         int aCount;
315cdf0e10cSrcweir         NSRange range = [macSpell checkSpellingOfString:aNSStr startingAt:0 language:aLang wrap:sal_False inSpellDocumentWithTag:macTag wordCount:&aCount];
316cdf0e10cSrcweir 		int rVal = 0;
317cdf0e10cSrcweir 		if(range.length>0)
318cdf0e10cSrcweir 		{
319cdf0e10cSrcweir 			rVal = -1;
320cdf0e10cSrcweir 		}
321cdf0e10cSrcweir 		else
322cdf0e10cSrcweir 		{
323cdf0e10cSrcweir 			rVal = 1;
324cdf0e10cSrcweir 		}
325cdf0e10cSrcweir         [pool release];
326cdf0e10cSrcweir         if (rVal != 1)
327cdf0e10cSrcweir         {
328cdf0e10cSrcweir             nRes = SpellFailure::SPELLING_ERROR;
329cdf0e10cSrcweir         } else {
330cdf0e10cSrcweir             return -1;
331cdf0e10cSrcweir         }
332cdf0e10cSrcweir     }
333cdf0e10cSrcweir 	return nRes;
334cdf0e10cSrcweir }
335cdf0e10cSrcweir 
336cdf0e10cSrcweir 
337cdf0e10cSrcweir 
338cdf0e10cSrcweir sal_Bool SAL_CALL
339cdf0e10cSrcweir 	MacSpellChecker::isValid( const OUString& rWord, const Locale& rLocale,
340cdf0e10cSrcweir 			const PropertyValues& rProperties )
341cdf0e10cSrcweir 		throw(IllegalArgumentException, RuntimeException)
342cdf0e10cSrcweir {
343cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
344cdf0e10cSrcweir 
345cdf0e10cSrcweir  	if (rLocale == Locale()  ||  !rWord.getLength())
346cdf0e10cSrcweir 		return sal_True;
347cdf0e10cSrcweir 
348cdf0e10cSrcweir 	if (!hasLocale( rLocale ))
349cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS
350cdf0e10cSrcweir 		throw( IllegalArgumentException() );
351cdf0e10cSrcweir #else
352cdf0e10cSrcweir 		return sal_True;
353cdf0e10cSrcweir #endif
354cdf0e10cSrcweir 
355cdf0e10cSrcweir 	// Get property values to be used.
356cdf0e10cSrcweir 	// These are be the default values set in the SN_LINGU_PROPERTIES
357cdf0e10cSrcweir 	// PropertySet which are overridden by the supplied ones from the
358cdf0e10cSrcweir 	// last argument.
359cdf0e10cSrcweir 	// You'll probably like to use a simplier solution than the provided
360cdf0e10cSrcweir 	// one using the PropertyHelper_Spell.
361cdf0e10cSrcweir 
362cdf0e10cSrcweir 	PropertyHelper_Spell &rHelper = GetPropHelper();
363cdf0e10cSrcweir 	rHelper.SetTmpPropVals( rProperties );
364cdf0e10cSrcweir 
365cdf0e10cSrcweir 	sal_Int16 nFailure = GetSpellFailure( rWord, rLocale );
366cdf0e10cSrcweir 	if (nFailure != -1)
367cdf0e10cSrcweir 	{
368cdf0e10cSrcweir 		sal_Int16 nLang = LocaleToLanguage( rLocale );
369cdf0e10cSrcweir 		// postprocess result for errors that should be ignored
370cdf0e10cSrcweir 		if (   (!rHelper.IsSpellUpperCase()  && IsUpper( rWord, nLang ))
371cdf0e10cSrcweir 			|| (!rHelper.IsSpellWithDigits() && HasDigits( rWord ))
372cdf0e10cSrcweir 			|| (!rHelper.IsSpellCapitalization()
373cdf0e10cSrcweir 				&&  nFailure == SpellFailure::CAPTION_ERROR)
374cdf0e10cSrcweir 		)
375cdf0e10cSrcweir 			nFailure = -1;
376cdf0e10cSrcweir 	}
377cdf0e10cSrcweir 
378cdf0e10cSrcweir 	return (nFailure == -1);
379cdf0e10cSrcweir }
380cdf0e10cSrcweir 
381cdf0e10cSrcweir 
382cdf0e10cSrcweir Reference< XSpellAlternatives >
383cdf0e10cSrcweir 	MacSpellChecker::GetProposals( const OUString &rWord, const Locale &rLocale )
384cdf0e10cSrcweir {
385cdf0e10cSrcweir 	// Retrieves the return values for the 'spell' function call in case
386cdf0e10cSrcweir 	// of a misspelled word.
387cdf0e10cSrcweir 	// Especially it may give a list of suggested (correct) words:
388cdf0e10cSrcweir 
389cdf0e10cSrcweir 	Reference< XSpellAlternatives > xRes;
390cdf0e10cSrcweir         // note: mutex is held by higher up by spell which covers both
391cdf0e10cSrcweir 
392cdf0e10cSrcweir     sal_Int16 nLang = LocaleToLanguage( rLocale );
393cdf0e10cSrcweir 	int count;
394cdf0e10cSrcweir 	Sequence< OUString > aStr( 0 );
395cdf0e10cSrcweir 
396cdf0e10cSrcweir         // first handle smart quotes (single and double)
397cdf0e10cSrcweir 	OUStringBuffer rBuf(rWord);
398cdf0e10cSrcweir         sal_Int32 n = rBuf.getLength();
399cdf0e10cSrcweir         sal_Unicode c;
400cdf0e10cSrcweir 	for (sal_Int32 ix=0; ix < n; ix++) {
401cdf0e10cSrcweir 	     c = rBuf.charAt(ix);
402cdf0e10cSrcweir              if ((c == 0x201C) || (c == 0x201D)) rBuf.setCharAt(ix,(sal_Unicode)0x0022);
403cdf0e10cSrcweir              if ((c == 0x2018) || (c == 0x2019)) rBuf.setCharAt(ix,(sal_Unicode)0x0027);
404cdf0e10cSrcweir         }
405cdf0e10cSrcweir         OUString nWord(rBuf.makeStringAndClear());
406cdf0e10cSrcweir 
407cdf0e10cSrcweir 	if (n)
408cdf0e10cSrcweir 	{
409cdf0e10cSrcweir 		NSAutoreleasePool* pool	= [[NSAutoreleasePool alloc] init];
410cdf0e10cSrcweir         NSString* aNSStr = [[NSString alloc] initWithCharacters: nWord.getStr() length: nWord.getLength()];
411cdf0e10cSrcweir         NSString* aLang = [[NSString alloc] initWithCharacters: rLocale.Language.getStr() length: rLocale.Language.getLength() ];
412cdf0e10cSrcweir         if(rLocale.Country.getLength()>0)
413cdf0e10cSrcweir         {
414cdf0e10cSrcweir             NSString* aCountry = [[NSString alloc] initWithCharacters: rLocale.Country.getStr() length: rLocale.Country.getLength() ];
415cdf0e10cSrcweir             NSString* aTag = @"_";
416cdf0e10cSrcweir             NSString* aTaggedCountry = [aTag stringByAppendingString:aCountry];
417cdf0e10cSrcweir             [aLang autorelease];
418cdf0e10cSrcweir             aLang = [aLang  stringByAppendingString:aTaggedCountry];
419cdf0e10cSrcweir         }
420cdf0e10cSrcweir         [macSpell setLanguage:aLang];
421cdf0e10cSrcweir         NSArray *guesses = [macSpell guessesForWord:aNSStr];
422cdf0e10cSrcweir         count = [guesses count];
423cdf0e10cSrcweir         if (count)
424cdf0e10cSrcweir         {
425cdf0e10cSrcweir            aStr.realloc( count );
426cdf0e10cSrcweir            OUString *pStr = aStr.getArray();
427cdf0e10cSrcweir                for (int ii=0; ii < count; ii++)
428cdf0e10cSrcweir                {
429cdf0e10cSrcweir                   // if needed add: if (suglst[ii] == NULL) continue;
430cdf0e10cSrcweir                   NSString* guess = [guesses objectAtIndex:ii];
431cdf0e10cSrcweir                   OUString cvtwrd((const sal_Unicode*)[guess cStringUsingEncoding:NSUnicodeStringEncoding], (sal_Int32)[guess length]);
432cdf0e10cSrcweir                   pStr[ii] = cvtwrd;
433cdf0e10cSrcweir                }
434cdf0e10cSrcweir         }
435cdf0e10cSrcweir        [pool release];
436cdf0e10cSrcweir 	}
437cdf0e10cSrcweir 
438cdf0e10cSrcweir             // now return an empty alternative for no suggestions or the list of alternatives if some found
439cdf0e10cSrcweir 	    SpellAlternatives *pAlt = new SpellAlternatives;
440cdf0e10cSrcweir             String aTmp(rWord);
441cdf0e10cSrcweir 	    pAlt->SetWordLanguage( aTmp, nLang );
442cdf0e10cSrcweir 	    pAlt->SetFailureType( SpellFailure::SPELLING_ERROR );
443cdf0e10cSrcweir 	    pAlt->SetAlternatives( aStr );
444cdf0e10cSrcweir 	    xRes = pAlt;
445cdf0e10cSrcweir         return xRes;
446cdf0e10cSrcweir 
447cdf0e10cSrcweir }
448cdf0e10cSrcweir 
449cdf0e10cSrcweir 
450cdf0e10cSrcweir 
451cdf0e10cSrcweir 
452cdf0e10cSrcweir Reference< XSpellAlternatives > SAL_CALL
453cdf0e10cSrcweir 	MacSpellChecker::spell( const OUString& rWord, const Locale& rLocale,
454cdf0e10cSrcweir 			const PropertyValues& rProperties )
455cdf0e10cSrcweir 		throw(IllegalArgumentException, RuntimeException)
456cdf0e10cSrcweir {
457cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
458cdf0e10cSrcweir 
459cdf0e10cSrcweir  	if (rLocale == Locale()  ||  !rWord.getLength())
460cdf0e10cSrcweir 		return NULL;
461cdf0e10cSrcweir 
462cdf0e10cSrcweir 	if (!hasLocale( rLocale ))
463cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS
464cdf0e10cSrcweir 		throw( IllegalArgumentException() );
465cdf0e10cSrcweir #else
466cdf0e10cSrcweir 		return NULL;
467cdf0e10cSrcweir #endif
468cdf0e10cSrcweir 
469cdf0e10cSrcweir 	Reference< XSpellAlternatives > xAlt;
470cdf0e10cSrcweir 	if (!isValid( rWord, rLocale, rProperties ))
471cdf0e10cSrcweir 	{
472cdf0e10cSrcweir 		xAlt =  GetProposals( rWord, rLocale );
473cdf0e10cSrcweir 	}
474cdf0e10cSrcweir 	return xAlt;
475cdf0e10cSrcweir }
476cdf0e10cSrcweir 
477cdf0e10cSrcweir 
478cdf0e10cSrcweir Reference< XInterface > SAL_CALL MacSpellChecker_CreateInstance(
479cdf0e10cSrcweir             const Reference< XMultiServiceFactory > & /*rSMgr*/ )
480cdf0e10cSrcweir 		throw(Exception)
481cdf0e10cSrcweir {
482cdf0e10cSrcweir 
483cdf0e10cSrcweir 	Reference< XInterface > xService = (cppu::OWeakObject*) new MacSpellChecker;
484cdf0e10cSrcweir 	return xService;
485cdf0e10cSrcweir }
486cdf0e10cSrcweir 
487cdf0e10cSrcweir 
488cdf0e10cSrcweir sal_Bool SAL_CALL
489cdf0e10cSrcweir 	MacSpellChecker::addLinguServiceEventListener(
490cdf0e10cSrcweir 			const Reference< XLinguServiceEventListener >& rxLstnr )
491cdf0e10cSrcweir 		throw(RuntimeException)
492cdf0e10cSrcweir {
493cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
494cdf0e10cSrcweir 
495cdf0e10cSrcweir 	sal_Bool bRes = sal_False;
496cdf0e10cSrcweir 	if (!bDisposing && rxLstnr.is())
497cdf0e10cSrcweir 	{
498cdf0e10cSrcweir 		bRes = GetPropHelper().addLinguServiceEventListener( rxLstnr );
499cdf0e10cSrcweir 	}
500cdf0e10cSrcweir 	return bRes;
501cdf0e10cSrcweir }
502cdf0e10cSrcweir 
503cdf0e10cSrcweir 
504cdf0e10cSrcweir sal_Bool SAL_CALL
505cdf0e10cSrcweir 	MacSpellChecker::removeLinguServiceEventListener(
506cdf0e10cSrcweir 			const Reference< XLinguServiceEventListener >& rxLstnr )
507cdf0e10cSrcweir 		throw(RuntimeException)
508cdf0e10cSrcweir {
509cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
510cdf0e10cSrcweir 
511cdf0e10cSrcweir 	sal_Bool bRes = sal_False;
512cdf0e10cSrcweir 	if (!bDisposing && rxLstnr.is())
513cdf0e10cSrcweir 	{
514cdf0e10cSrcweir 		DBG_ASSERT( xPropHelper.is(), "xPropHelper non existent" );
515cdf0e10cSrcweir 		bRes = GetPropHelper().removeLinguServiceEventListener( rxLstnr );
516cdf0e10cSrcweir 	}
517cdf0e10cSrcweir 	return bRes;
518cdf0e10cSrcweir }
519cdf0e10cSrcweir 
520cdf0e10cSrcweir 
521cdf0e10cSrcweir OUString SAL_CALL
522cdf0e10cSrcweir     MacSpellChecker::getServiceDisplayName( const Locale& /*rLocale*/ )
523cdf0e10cSrcweir 		throw(RuntimeException)
524cdf0e10cSrcweir {
525cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
526cdf0e10cSrcweir 	return A2OU( "Mac OS X Spell Checker" );
527cdf0e10cSrcweir }
528cdf0e10cSrcweir 
529cdf0e10cSrcweir 
530cdf0e10cSrcweir void SAL_CALL
531cdf0e10cSrcweir 	MacSpellChecker::initialize( const Sequence< Any >& rArguments )
532cdf0e10cSrcweir 		throw(Exception, RuntimeException)
533cdf0e10cSrcweir {
534cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
535cdf0e10cSrcweir 
536cdf0e10cSrcweir 	if (!pPropHelper)
537cdf0e10cSrcweir 	{
538cdf0e10cSrcweir 		sal_Int32 nLen = rArguments.getLength();
539cdf0e10cSrcweir 		if (2 == nLen)
540cdf0e10cSrcweir 		{
541cdf0e10cSrcweir 			Reference< XPropertySet	>	xPropSet;
542cdf0e10cSrcweir 			rArguments.getConstArray()[0] >>= xPropSet;
543cdf0e10cSrcweir 			//rArguments.getConstArray()[1] >>= xDicList;
544cdf0e10cSrcweir 
545cdf0e10cSrcweir 			//! Pointer allows for access of the non-UNO functions.
546cdf0e10cSrcweir 			//! And the reference to the UNO-functions while increasing
547cdf0e10cSrcweir 			//! the ref-count and will implicitly free the memory
548cdf0e10cSrcweir 			//! when the object is not longer used.
549cdf0e10cSrcweir 			pPropHelper = new PropertyHelper_Spell( (XSpellChecker *) this, xPropSet );
550cdf0e10cSrcweir 			xPropHelper = pPropHelper;
551cdf0e10cSrcweir 			pPropHelper->AddAsPropListener();	//! after a reference is established
552cdf0e10cSrcweir 		}
553cdf0e10cSrcweir 		else
554cdf0e10cSrcweir 			DBG_ERROR( "wrong number of arguments in sequence" );
555cdf0e10cSrcweir 
556cdf0e10cSrcweir 	}
557cdf0e10cSrcweir }
558cdf0e10cSrcweir 
559cdf0e10cSrcweir 
560cdf0e10cSrcweir void SAL_CALL
561cdf0e10cSrcweir 	MacSpellChecker::dispose()
562cdf0e10cSrcweir 		throw(RuntimeException)
563cdf0e10cSrcweir {
564cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
565cdf0e10cSrcweir 
566cdf0e10cSrcweir 	if (!bDisposing)
567cdf0e10cSrcweir 	{
568cdf0e10cSrcweir 		bDisposing = sal_True;
569cdf0e10cSrcweir 		EventObject	aEvtObj( (XSpellChecker *) this );
570cdf0e10cSrcweir 		aEvtListeners.disposeAndClear( aEvtObj );
571cdf0e10cSrcweir 	}
572cdf0e10cSrcweir }
573cdf0e10cSrcweir 
574cdf0e10cSrcweir 
575cdf0e10cSrcweir void SAL_CALL
576cdf0e10cSrcweir 	MacSpellChecker::addEventListener( const Reference< XEventListener >& rxListener )
577cdf0e10cSrcweir 		throw(RuntimeException)
578cdf0e10cSrcweir {
579cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
580cdf0e10cSrcweir 
581cdf0e10cSrcweir 	if (!bDisposing && rxListener.is())
582cdf0e10cSrcweir 		aEvtListeners.addInterface( rxListener );
583cdf0e10cSrcweir }
584cdf0e10cSrcweir 
585cdf0e10cSrcweir 
586cdf0e10cSrcweir void SAL_CALL
587cdf0e10cSrcweir 	MacSpellChecker::removeEventListener( const Reference< XEventListener >& rxListener )
588cdf0e10cSrcweir 		throw(RuntimeException)
589cdf0e10cSrcweir {
590cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
591cdf0e10cSrcweir 
592cdf0e10cSrcweir 	if (!bDisposing && rxListener.is())
593cdf0e10cSrcweir 		aEvtListeners.removeInterface( rxListener );
594cdf0e10cSrcweir }
595cdf0e10cSrcweir 
596cdf0e10cSrcweir 
597cdf0e10cSrcweir ///////////////////////////////////////////////////////////////////////////
598cdf0e10cSrcweir // Service specific part
599cdf0e10cSrcweir //
600cdf0e10cSrcweir 
601cdf0e10cSrcweir OUString SAL_CALL MacSpellChecker::getImplementationName()
602cdf0e10cSrcweir 		throw(RuntimeException)
603cdf0e10cSrcweir {
604cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
605cdf0e10cSrcweir 
606cdf0e10cSrcweir 	return getImplementationName_Static();
607cdf0e10cSrcweir }
608cdf0e10cSrcweir 
609cdf0e10cSrcweir 
610cdf0e10cSrcweir sal_Bool SAL_CALL MacSpellChecker::supportsService( const OUString& ServiceName )
611cdf0e10cSrcweir 		throw(RuntimeException)
612cdf0e10cSrcweir {
613cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
614cdf0e10cSrcweir 
615cdf0e10cSrcweir 	Sequence< OUString > aSNL = getSupportedServiceNames();
616cdf0e10cSrcweir 	const OUString * pArray = aSNL.getConstArray();
617cdf0e10cSrcweir 	for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
618cdf0e10cSrcweir 		if( pArray[i] == ServiceName )
619cdf0e10cSrcweir 			return sal_True;
620cdf0e10cSrcweir 	return sal_False;
621cdf0e10cSrcweir }
622cdf0e10cSrcweir 
623cdf0e10cSrcweir 
624cdf0e10cSrcweir Sequence< OUString > SAL_CALL MacSpellChecker::getSupportedServiceNames()
625cdf0e10cSrcweir 		throw(RuntimeException)
626cdf0e10cSrcweir {
627cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
628cdf0e10cSrcweir 
629cdf0e10cSrcweir 	return getSupportedServiceNames_Static();
630cdf0e10cSrcweir }
631cdf0e10cSrcweir 
632cdf0e10cSrcweir 
633cdf0e10cSrcweir Sequence< OUString > MacSpellChecker::getSupportedServiceNames_Static()
634cdf0e10cSrcweir 		throw()
635cdf0e10cSrcweir {
636cdf0e10cSrcweir 	MutexGuard	aGuard( GetLinguMutex() );
637cdf0e10cSrcweir 
638cdf0e10cSrcweir 	Sequence< OUString > aSNS( 1 );	// auch mehr als 1 Service moeglich
639cdf0e10cSrcweir 	aSNS.getArray()[0] = A2OU( SN_SPELLCHECKER );
640cdf0e10cSrcweir 	return aSNS;
641cdf0e10cSrcweir }
642cdf0e10cSrcweir 
643cdf0e10cSrcweir void * SAL_CALL MacSpellChecker_getFactory( const sal_Char * pImplName,
644cdf0e10cSrcweir 			XMultiServiceFactory * pServiceManager, void *  )
645cdf0e10cSrcweir {
646cdf0e10cSrcweir 	void * pRet = 0;
647cdf0e10cSrcweir 	if ( !MacSpellChecker::getImplementationName_Static().compareToAscii( pImplName ) )
648cdf0e10cSrcweir 	{
649cdf0e10cSrcweir 		Reference< XSingleServiceFactory > xFactory =
650cdf0e10cSrcweir 			cppu::createOneInstanceFactory(
651cdf0e10cSrcweir 				pServiceManager,
652cdf0e10cSrcweir 				MacSpellChecker::getImplementationName_Static(),
653cdf0e10cSrcweir 				MacSpellChecker_CreateInstance,
654cdf0e10cSrcweir 				MacSpellChecker::getSupportedServiceNames_Static());
655cdf0e10cSrcweir 		// acquire, because we return an interface pointer instead of a reference
656cdf0e10cSrcweir 		xFactory->acquire();
657cdf0e10cSrcweir 		pRet = xFactory.get();
658cdf0e10cSrcweir 	}
659cdf0e10cSrcweir 	return pRet;
660cdf0e10cSrcweir }
661cdf0e10cSrcweir 
662cdf0e10cSrcweir 
663cdf0e10cSrcweir ///////////////////////////////////////////////////////////////////////////
664