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