1*3b8558fdSAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
3*3b8558fdSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4*3b8558fdSAndrew Rist * or more contributor license agreements. See the NOTICE file
5*3b8558fdSAndrew Rist * distributed with this work for additional information
6*3b8558fdSAndrew Rist * regarding copyright ownership. The ASF licenses this file
7*3b8558fdSAndrew Rist * to you under the Apache License, Version 2.0 (the
8*3b8558fdSAndrew Rist * "License"); you may not use this file except in compliance
9*3b8558fdSAndrew Rist * with the License. You may obtain a copy of the License at
10*3b8558fdSAndrew Rist *
11*3b8558fdSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12*3b8558fdSAndrew Rist *
13*3b8558fdSAndrew Rist * Unless required by applicable law or agreed to in writing,
14*3b8558fdSAndrew Rist * software distributed under the License is distributed on an
15*3b8558fdSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*3b8558fdSAndrew Rist * KIND, either express or implied. See the License for the
17*3b8558fdSAndrew Rist * specific language governing permissions and limitations
18*3b8558fdSAndrew Rist * under the License.
19*3b8558fdSAndrew Rist *
20*3b8558fdSAndrew Rist *************************************************************/
21*3b8558fdSAndrew Rist
22*3b8558fdSAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_linguistic.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir
28cdf0e10cSrcweir #include <cppuhelper/factory.hxx> // helper for factories
29cdf0e10cSrcweir #include <com/sun/star/registry/XRegistryKey.hpp>
30cdf0e10cSrcweir #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
31cdf0e10cSrcweir #include <com/sun/star/linguistic2/XHyphenatedWord.hpp>
32cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
33cdf0e10cSrcweir #include <i18npool/lang.h>
34cdf0e10cSrcweir #include <unotools/localedatawrapper.hxx>
35cdf0e10cSrcweir #include <tools/debug.hxx>
36cdf0e10cSrcweir #include <svl/lngmisc.hxx>
37cdf0e10cSrcweir #include <unotools/processfactory.hxx>
38cdf0e10cSrcweir #include <osl/mutex.hxx>
39cdf0e10cSrcweir
40cdf0e10cSrcweir #include "hyphdsp.hxx"
41cdf0e10cSrcweir #include "linguistic/hyphdta.hxx"
42cdf0e10cSrcweir #include "linguistic/lngprops.hxx"
43cdf0e10cSrcweir #include "lngsvcmgr.hxx"
44cdf0e10cSrcweir
45cdf0e10cSrcweir
46cdf0e10cSrcweir using namespace utl;
47cdf0e10cSrcweir using namespace osl;
48cdf0e10cSrcweir using namespace rtl;
49cdf0e10cSrcweir using namespace com::sun::star;
50cdf0e10cSrcweir using namespace com::sun::star::beans;
51cdf0e10cSrcweir using namespace com::sun::star::lang;
52cdf0e10cSrcweir using namespace com::sun::star::uno;
53cdf0e10cSrcweir using namespace com::sun::star::linguistic2;
54cdf0e10cSrcweir using namespace linguistic;
55cdf0e10cSrcweir
56cdf0e10cSrcweir ///////////////////////////////////////////////////////////////////////////
57cdf0e10cSrcweir
HyphenatorDispatcher(LngSvcMgr & rLngSvcMgr)58cdf0e10cSrcweir HyphenatorDispatcher::HyphenatorDispatcher( LngSvcMgr &rLngSvcMgr ) :
59cdf0e10cSrcweir rMgr (rLngSvcMgr)
60cdf0e10cSrcweir {
61cdf0e10cSrcweir }
62cdf0e10cSrcweir
63cdf0e10cSrcweir
~HyphenatorDispatcher()64cdf0e10cSrcweir HyphenatorDispatcher::~HyphenatorDispatcher()
65cdf0e10cSrcweir {
66cdf0e10cSrcweir ClearSvcList();
67cdf0e10cSrcweir }
68cdf0e10cSrcweir
69cdf0e10cSrcweir
ClearSvcList()70cdf0e10cSrcweir void HyphenatorDispatcher::ClearSvcList()
71cdf0e10cSrcweir {
72cdf0e10cSrcweir // release memory for each table entry
73cdf0e10cSrcweir HyphSvcByLangMap_t aTmp;
74cdf0e10cSrcweir aSvcMap.swap( aTmp );
75cdf0e10cSrcweir }
76cdf0e10cSrcweir
77cdf0e10cSrcweir
buildHyphWord(const OUString rOrigWord,const Reference<XDictionaryEntry> & xEntry,sal_Int16 nLang,sal_Int16 nMaxLeading)78cdf0e10cSrcweir Reference<XHyphenatedWord> HyphenatorDispatcher::buildHyphWord(
79cdf0e10cSrcweir const OUString rOrigWord,
80cdf0e10cSrcweir const Reference<XDictionaryEntry> &xEntry,
81cdf0e10cSrcweir sal_Int16 nLang, sal_Int16 nMaxLeading )
82cdf0e10cSrcweir {
83cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() );
84cdf0e10cSrcweir
85cdf0e10cSrcweir Reference< XHyphenatedWord > xRes;
86cdf0e10cSrcweir
87cdf0e10cSrcweir if (xEntry.is())
88cdf0e10cSrcweir {
89cdf0e10cSrcweir OUString aText( xEntry->getDictionaryWord() );
90cdf0e10cSrcweir sal_Int32 nTextLen = aText.getLength();
91cdf0e10cSrcweir
92cdf0e10cSrcweir // trailing '=' means "hyphenation should not be possible"
93cdf0e10cSrcweir if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=')
94cdf0e10cSrcweir {
95cdf0e10cSrcweir sal_Int16 nHyphenationPos = -1;
96cdf0e10cSrcweir
97cdf0e10cSrcweir OUStringBuffer aTmp( nTextLen );
98cdf0e10cSrcweir sal_Bool bSkip = sal_False;
99cdf0e10cSrcweir sal_Int32 nHyphIdx = -1;
100cdf0e10cSrcweir sal_Int32 nLeading = 0;
101cdf0e10cSrcweir for (sal_Int32 i = 0; i < nTextLen; i++)
102cdf0e10cSrcweir {
103cdf0e10cSrcweir sal_Unicode cTmp = aText[i];
104cdf0e10cSrcweir if (cTmp != '=')
105cdf0e10cSrcweir {
106cdf0e10cSrcweir aTmp.append( cTmp );
107cdf0e10cSrcweir nLeading++;
108cdf0e10cSrcweir bSkip = sal_False;
109cdf0e10cSrcweir nHyphIdx++;
110cdf0e10cSrcweir }
111cdf0e10cSrcweir else
112cdf0e10cSrcweir {
113cdf0e10cSrcweir if (!bSkip && nHyphIdx >= 0)
114cdf0e10cSrcweir {
115cdf0e10cSrcweir if (nLeading <= nMaxLeading)
116cdf0e10cSrcweir nHyphenationPos = (sal_Int16) nHyphIdx;
117cdf0e10cSrcweir }
118cdf0e10cSrcweir bSkip = sal_True; //! multiple '=' should count as one only
119cdf0e10cSrcweir }
120cdf0e10cSrcweir }
121cdf0e10cSrcweir
122cdf0e10cSrcweir if (nHyphenationPos > 0)
123cdf0e10cSrcweir {
124cdf0e10cSrcweir aText = aTmp.makeStringAndClear();
125cdf0e10cSrcweir
126cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
127cdf0e10cSrcweir {
128cdf0e10cSrcweir if (aText != rOrigWord)
129cdf0e10cSrcweir {
130cdf0e10cSrcweir // both words should only differ by a having a trailing '.'
131cdf0e10cSrcweir // character or not...
132cdf0e10cSrcweir OUString aShorter, aLonger;
133cdf0e10cSrcweir if (aText.getLength() <= rOrigWord.getLength())
134cdf0e10cSrcweir {
135cdf0e10cSrcweir aShorter = aText;
136cdf0e10cSrcweir aLonger = rOrigWord;
137cdf0e10cSrcweir }
138cdf0e10cSrcweir else
139cdf0e10cSrcweir {
140cdf0e10cSrcweir aShorter = rOrigWord;
141cdf0e10cSrcweir aLonger = aText;
142cdf0e10cSrcweir }
143cdf0e10cSrcweir xub_StrLen nS = sal::static_int_cast< xub_StrLen >( aShorter.getLength() );
144cdf0e10cSrcweir xub_StrLen nL = sal::static_int_cast< xub_StrLen >( aLonger.getLength() );
145cdf0e10cSrcweir if (nS > 0 && nL > 0)
146cdf0e10cSrcweir {
147cdf0e10cSrcweir DBG_ASSERT( (nS + 1 == nL) && aLonger[nL-1] == (sal_Unicode) '.',
148cdf0e10cSrcweir "HyphenatorDispatcher::buildHyphWord: unexpected difference between words!" );
149cdf0e10cSrcweir }
150cdf0e10cSrcweir }
151cdf0e10cSrcweir }
152cdf0e10cSrcweir #endif
153cdf0e10cSrcweir //! take care of #i22591#
154cdf0e10cSrcweir aText = rOrigWord;
155cdf0e10cSrcweir
156cdf0e10cSrcweir DBG_ASSERT( aText == rOrigWord, "failed to " );
157cdf0e10cSrcweir xRes = new HyphenatedWord( aText, nLang, nHyphenationPos,
158cdf0e10cSrcweir aText, nHyphenationPos );
159cdf0e10cSrcweir }
160cdf0e10cSrcweir }
161cdf0e10cSrcweir }
162cdf0e10cSrcweir
163cdf0e10cSrcweir return xRes;
164cdf0e10cSrcweir }
165cdf0e10cSrcweir
166cdf0e10cSrcweir
buildPossHyphens(const Reference<XDictionaryEntry> & xEntry,sal_Int16 nLanguage)167cdf0e10cSrcweir Reference< XPossibleHyphens > HyphenatorDispatcher::buildPossHyphens(
168cdf0e10cSrcweir const Reference< XDictionaryEntry > &xEntry, sal_Int16 nLanguage )
169cdf0e10cSrcweir {
170cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() );
171cdf0e10cSrcweir
172cdf0e10cSrcweir Reference<XPossibleHyphens> xRes;
173cdf0e10cSrcweir
174cdf0e10cSrcweir if (xEntry.is())
175cdf0e10cSrcweir {
176cdf0e10cSrcweir // text with hyphenation info
177cdf0e10cSrcweir OUString aText( xEntry->getDictionaryWord() );
178cdf0e10cSrcweir sal_Int32 nTextLen = aText.getLength();
179cdf0e10cSrcweir
180cdf0e10cSrcweir // trailing '=' means "hyphenation should not be possible"
181cdf0e10cSrcweir if (nTextLen > 0 && aText[ nTextLen - 1 ] != '=')
182cdf0e10cSrcweir {
183cdf0e10cSrcweir // sequence to hold hyphenation positions
184cdf0e10cSrcweir Sequence< sal_Int16 > aHyphPos( nTextLen );
185cdf0e10cSrcweir sal_Int16 *pPos = aHyphPos.getArray();
186cdf0e10cSrcweir sal_Int32 nHyphCount = 0;
187cdf0e10cSrcweir
188cdf0e10cSrcweir OUStringBuffer aTmp( nTextLen );
189cdf0e10cSrcweir sal_Bool bSkip = sal_False;
190cdf0e10cSrcweir sal_Int32 nHyphIdx = -1;
191cdf0e10cSrcweir for (sal_Int32 i = 0; i < nTextLen; i++)
192cdf0e10cSrcweir {
193cdf0e10cSrcweir sal_Unicode cTmp = aText[i];
194cdf0e10cSrcweir if (cTmp != '=')
195cdf0e10cSrcweir {
196cdf0e10cSrcweir aTmp.append( cTmp );
197cdf0e10cSrcweir bSkip = sal_False;
198cdf0e10cSrcweir nHyphIdx++;
199cdf0e10cSrcweir }
200cdf0e10cSrcweir else
201cdf0e10cSrcweir {
202cdf0e10cSrcweir if (!bSkip && nHyphIdx >= 0)
203cdf0e10cSrcweir pPos[ nHyphCount++ ] = (sal_Int16) nHyphIdx;
204cdf0e10cSrcweir bSkip = sal_True; //! multiple '=' should count as one only
205cdf0e10cSrcweir }
206cdf0e10cSrcweir }
207cdf0e10cSrcweir
208cdf0e10cSrcweir // ignore (multiple) trailing '='
209cdf0e10cSrcweir if (bSkip && nHyphIdx >= 0)
210cdf0e10cSrcweir {
211cdf0e10cSrcweir nHyphCount--;
212cdf0e10cSrcweir }
213cdf0e10cSrcweir DBG_ASSERT( nHyphCount >= 0, "lng : invalid hyphenation count");
214cdf0e10cSrcweir
215cdf0e10cSrcweir if (nHyphCount > 0)
216cdf0e10cSrcweir {
217cdf0e10cSrcweir aHyphPos.realloc( nHyphCount );
218cdf0e10cSrcweir xRes = new PossibleHyphens( aTmp.makeStringAndClear(), nLanguage,
219cdf0e10cSrcweir aText, aHyphPos );
220cdf0e10cSrcweir }
221cdf0e10cSrcweir }
222cdf0e10cSrcweir }
223cdf0e10cSrcweir
224cdf0e10cSrcweir return xRes;
225cdf0e10cSrcweir }
226cdf0e10cSrcweir
227cdf0e10cSrcweir
getLocales()228cdf0e10cSrcweir Sequence< Locale > SAL_CALL HyphenatorDispatcher::getLocales()
229cdf0e10cSrcweir throw(RuntimeException)
230cdf0e10cSrcweir {
231cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() );
232cdf0e10cSrcweir
233cdf0e10cSrcweir Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) );
234cdf0e10cSrcweir Locale *pLocales = aLocales.getArray();
235cdf0e10cSrcweir HyphSvcByLangMap_t::const_iterator aIt;
236cdf0e10cSrcweir for (aIt = aSvcMap.begin(); aIt != aSvcMap.end(); ++aIt)
237cdf0e10cSrcweir {
238cdf0e10cSrcweir *pLocales++ = CreateLocale( aIt->first );
239cdf0e10cSrcweir }
240cdf0e10cSrcweir return aLocales;
241cdf0e10cSrcweir }
242cdf0e10cSrcweir
243cdf0e10cSrcweir
hasLocale(const Locale & rLocale)244cdf0e10cSrcweir sal_Bool SAL_CALL HyphenatorDispatcher::hasLocale(const Locale& rLocale)
245cdf0e10cSrcweir throw(RuntimeException)
246cdf0e10cSrcweir {
247cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() );
248cdf0e10cSrcweir HyphSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LocaleToLanguage( rLocale ) ) );
249cdf0e10cSrcweir return aIt != aSvcMap.end();
250cdf0e10cSrcweir }
251cdf0e10cSrcweir
252cdf0e10cSrcweir
253cdf0e10cSrcweir Reference< XHyphenatedWord > SAL_CALL
hyphenate(const OUString & rWord,const Locale & rLocale,sal_Int16 nMaxLeading,const PropertyValues & rProperties)254cdf0e10cSrcweir HyphenatorDispatcher::hyphenate(
255cdf0e10cSrcweir const OUString& rWord, const Locale& rLocale, sal_Int16 nMaxLeading,
256cdf0e10cSrcweir const PropertyValues& rProperties )
257cdf0e10cSrcweir throw(IllegalArgumentException, RuntimeException)
258cdf0e10cSrcweir {
259cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() );
260cdf0e10cSrcweir
261cdf0e10cSrcweir Reference< XHyphenatedWord > xRes;
262cdf0e10cSrcweir
263cdf0e10cSrcweir sal_Int32 nWordLen = rWord.getLength();
264cdf0e10cSrcweir sal_Int16 nLanguage = LocaleToLanguage( rLocale );
265cdf0e10cSrcweir if (nLanguage == LANGUAGE_NONE || !nWordLen ||
266cdf0e10cSrcweir nMaxLeading == 0 || nMaxLeading == nWordLen)
267cdf0e10cSrcweir return xRes;
268cdf0e10cSrcweir
269cdf0e10cSrcweir // search for entry with that language
270cdf0e10cSrcweir HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
271cdf0e10cSrcweir LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
272cdf0e10cSrcweir
273cdf0e10cSrcweir sal_Bool bWordModified = sal_False;
274cdf0e10cSrcweir if (!pEntry || (nMaxLeading < 0 || nMaxLeading > nWordLen))
275cdf0e10cSrcweir {
276cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS
277cdf0e10cSrcweir throw IllegalArgumentException();
278cdf0e10cSrcweir #else
279cdf0e10cSrcweir return NULL;
280cdf0e10cSrcweir #endif
281cdf0e10cSrcweir }
282cdf0e10cSrcweir else
283cdf0e10cSrcweir {
284cdf0e10cSrcweir OUString aChkWord( rWord );
285cdf0e10cSrcweir
286cdf0e10cSrcweir // replace typographical apostroph by ascii apostroph
287cdf0e10cSrcweir String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
288cdf0e10cSrcweir DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
289cdf0e10cSrcweir if (aSingleQuote.Len())
290cdf0e10cSrcweir aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
291cdf0e10cSrcweir
292cdf0e10cSrcweir bWordModified |= RemoveHyphens( aChkWord );
293cdf0e10cSrcweir if (IsIgnoreControlChars( rProperties, GetPropSet() ))
294cdf0e10cSrcweir bWordModified |= RemoveControlChars( aChkWord );
295cdf0e10cSrcweir sal_Int16 nChkMaxLeading = (sal_Int16) GetPosInWordToCheck( rWord, nMaxLeading );
296cdf0e10cSrcweir
297cdf0e10cSrcweir // check for results from (positive) dictionaries which have precedence!
298cdf0e10cSrcweir Reference< XDictionaryEntry > xEntry;
299cdf0e10cSrcweir
300cdf0e10cSrcweir if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
301cdf0e10cSrcweir {
302cdf0e10cSrcweir xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
303cdf0e10cSrcweir sal_True, sal_False );
304cdf0e10cSrcweir }
305cdf0e10cSrcweir
306cdf0e10cSrcweir if (xEntry.is())
307cdf0e10cSrcweir {
308cdf0e10cSrcweir //! because queryDictionaryEntry (in the end DictionaryNeo::getEntry)
309cdf0e10cSrcweir //! does not distinguish betwee "XYZ" and "XYZ." in order to avoid
310cdf0e10cSrcweir //! to require them as different entry we have to supply the
311cdf0e10cSrcweir //! original word here as well so it can be used in th result
312cdf0e10cSrcweir //! otherwise a strange effect may occur (see #i22591#)
313cdf0e10cSrcweir xRes = buildHyphWord( rWord, xEntry, nLanguage, nChkMaxLeading );
314cdf0e10cSrcweir }
315cdf0e10cSrcweir else
316cdf0e10cSrcweir {
317cdf0e10cSrcweir sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
318cdf0e10cSrcweir DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
319cdf0e10cSrcweir "lng : index out of range");
320cdf0e10cSrcweir
321cdf0e10cSrcweir sal_Int32 i = 0;
322cdf0e10cSrcweir Reference< XHyphenator > xHyph;
323cdf0e10cSrcweir if (pEntry->aSvcRefs.getLength() > 0)
324cdf0e10cSrcweir xHyph = pEntry->aSvcRefs[0];
325cdf0e10cSrcweir
326cdf0e10cSrcweir // try already instantiated service
327cdf0e10cSrcweir if (i <= pEntry->nLastTriedSvcIndex)
328cdf0e10cSrcweir {
329cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale ))
330cdf0e10cSrcweir xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading,
331cdf0e10cSrcweir rProperties );
332cdf0e10cSrcweir ++i;
333cdf0e10cSrcweir }
334cdf0e10cSrcweir else if (pEntry->nLastTriedSvcIndex < nLen - 1)
335cdf0e10cSrcweir // instantiate services and try it
336cdf0e10cSrcweir {
337cdf0e10cSrcweir // const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
338cdf0e10cSrcweir Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
339cdf0e10cSrcweir
340cdf0e10cSrcweir Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
341cdf0e10cSrcweir if (xMgr.is())
342cdf0e10cSrcweir {
343cdf0e10cSrcweir // build service initialization argument
344cdf0e10cSrcweir Sequence< Any > aArgs(2);
345cdf0e10cSrcweir aArgs.getArray()[0] <<= GetPropSet();
346cdf0e10cSrcweir //! The dispatcher searches the dictionary-list
347cdf0e10cSrcweir //! thus the service needs not to now about it
348cdf0e10cSrcweir //aArgs.getArray()[1] <<= GetDicList();
349cdf0e10cSrcweir
350cdf0e10cSrcweir // create specific service via it's implementation name
351cdf0e10cSrcweir try
352cdf0e10cSrcweir {
353cdf0e10cSrcweir xHyph = Reference< XHyphenator >(
354cdf0e10cSrcweir xMgr->createInstanceWithArguments(
355cdf0e10cSrcweir pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
356cdf0e10cSrcweir }
357cdf0e10cSrcweir catch (uno::Exception &)
358cdf0e10cSrcweir {
359cdf0e10cSrcweir DBG_ASSERT( 0, "createInstanceWithArguments failed" );
360cdf0e10cSrcweir }
361cdf0e10cSrcweir pRef [i] = xHyph;
362cdf0e10cSrcweir
363cdf0e10cSrcweir Reference< XLinguServiceEventBroadcaster >
364cdf0e10cSrcweir xBroadcaster( xHyph, UNO_QUERY );
365cdf0e10cSrcweir if (xBroadcaster.is())
366cdf0e10cSrcweir rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
367cdf0e10cSrcweir
368cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale ))
369cdf0e10cSrcweir xRes = xHyph->hyphenate( aChkWord, rLocale, nChkMaxLeading,
370cdf0e10cSrcweir rProperties );
371cdf0e10cSrcweir
372cdf0e10cSrcweir pEntry->nLastTriedSvcIndex = (sal_Int16) i;
373cdf0e10cSrcweir ++i;
374cdf0e10cSrcweir
375cdf0e10cSrcweir // if language is not supported by the services
376cdf0e10cSrcweir // remove it from the list.
377cdf0e10cSrcweir if (xHyph.is() && !xHyph->hasLocale( rLocale ))
378cdf0e10cSrcweir aSvcMap.erase( nLanguage );
379cdf0e10cSrcweir }
380cdf0e10cSrcweir }
381cdf0e10cSrcweir } // if (xEntry.is())
382cdf0e10cSrcweir }
383cdf0e10cSrcweir
384cdf0e10cSrcweir if (bWordModified && xRes.is())
385cdf0e10cSrcweir xRes = RebuildHyphensAndControlChars( rWord, xRes );
386cdf0e10cSrcweir
387cdf0e10cSrcweir if (xRes.is() && xRes->getWord() != rWord)
388cdf0e10cSrcweir {
389cdf0e10cSrcweir xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(),
390cdf0e10cSrcweir xRes->getHyphenatedWord(),
391cdf0e10cSrcweir xRes->getHyphenPos() );
392cdf0e10cSrcweir }
393cdf0e10cSrcweir
394cdf0e10cSrcweir return xRes;
395cdf0e10cSrcweir }
396cdf0e10cSrcweir
397cdf0e10cSrcweir
398cdf0e10cSrcweir Reference< XHyphenatedWord > SAL_CALL
queryAlternativeSpelling(const OUString & rWord,const Locale & rLocale,sal_Int16 nIndex,const PropertyValues & rProperties)399cdf0e10cSrcweir HyphenatorDispatcher::queryAlternativeSpelling(
400cdf0e10cSrcweir const OUString& rWord, const Locale& rLocale, sal_Int16 nIndex,
401cdf0e10cSrcweir const PropertyValues& rProperties )
402cdf0e10cSrcweir throw(IllegalArgumentException, RuntimeException)
403cdf0e10cSrcweir {
404cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() );
405cdf0e10cSrcweir
406cdf0e10cSrcweir Reference< XHyphenatedWord > xRes;
407cdf0e10cSrcweir
408cdf0e10cSrcweir sal_Int32 nWordLen = rWord.getLength();
409cdf0e10cSrcweir sal_Int16 nLanguage = LocaleToLanguage( rLocale );
410cdf0e10cSrcweir if (nLanguage == LANGUAGE_NONE || !nWordLen)
411cdf0e10cSrcweir return xRes;
412cdf0e10cSrcweir
413cdf0e10cSrcweir // search for entry with that language
414cdf0e10cSrcweir HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
415cdf0e10cSrcweir LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
416cdf0e10cSrcweir
417cdf0e10cSrcweir sal_Bool bWordModified = sal_False;
418cdf0e10cSrcweir if (!pEntry || !(0 <= nIndex && nIndex <= nWordLen - 2))
419cdf0e10cSrcweir {
420cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS
421cdf0e10cSrcweir throw IllegalArgumentException();
422cdf0e10cSrcweir #else
423cdf0e10cSrcweir return NULL;
424cdf0e10cSrcweir #endif
425cdf0e10cSrcweir }
426cdf0e10cSrcweir else
427cdf0e10cSrcweir {
428cdf0e10cSrcweir OUString aChkWord( rWord );
429cdf0e10cSrcweir
430cdf0e10cSrcweir // replace typographical apostroph by ascii apostroph
431cdf0e10cSrcweir String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
432cdf0e10cSrcweir DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
433cdf0e10cSrcweir if (aSingleQuote.Len())
434cdf0e10cSrcweir aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
435cdf0e10cSrcweir
436cdf0e10cSrcweir bWordModified |= RemoveHyphens( aChkWord );
437cdf0e10cSrcweir if (IsIgnoreControlChars( rProperties, GetPropSet() ))
438cdf0e10cSrcweir bWordModified |= RemoveControlChars( aChkWord );
439cdf0e10cSrcweir sal_Int16 nChkIndex = (sal_Int16) GetPosInWordToCheck( rWord, nIndex );
440cdf0e10cSrcweir
441cdf0e10cSrcweir // check for results from (positive) dictionaries which have precedence!
442cdf0e10cSrcweir Reference< XDictionaryEntry > xEntry;
443cdf0e10cSrcweir
444cdf0e10cSrcweir if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
445cdf0e10cSrcweir {
446cdf0e10cSrcweir xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
447cdf0e10cSrcweir sal_True, sal_False );
448cdf0e10cSrcweir }
449cdf0e10cSrcweir
450cdf0e10cSrcweir if (xEntry.is())
451cdf0e10cSrcweir {
452cdf0e10cSrcweir //! alternative spellings not yet supported by dictionaries
453cdf0e10cSrcweir }
454cdf0e10cSrcweir else
455cdf0e10cSrcweir {
456cdf0e10cSrcweir sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
457cdf0e10cSrcweir DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
458cdf0e10cSrcweir "lng : index out of range");
459cdf0e10cSrcweir
460cdf0e10cSrcweir sal_Int32 i = 0;
461cdf0e10cSrcweir Reference< XHyphenator > xHyph;
462cdf0e10cSrcweir if (pEntry->aSvcRefs.getLength() > 0)
463cdf0e10cSrcweir xHyph = pEntry->aSvcRefs[0];
464cdf0e10cSrcweir
465cdf0e10cSrcweir // try already instantiated service
466cdf0e10cSrcweir if (i <= pEntry->nLastTriedSvcIndex)
467cdf0e10cSrcweir {
468cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale ))
469cdf0e10cSrcweir xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale,
470cdf0e10cSrcweir nChkIndex, rProperties );
471cdf0e10cSrcweir ++i;
472cdf0e10cSrcweir }
473cdf0e10cSrcweir else if (pEntry->nLastTriedSvcIndex < nLen - 1)
474cdf0e10cSrcweir // instantiate services and try it
475cdf0e10cSrcweir {
476cdf0e10cSrcweir // const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
477cdf0e10cSrcweir Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
478cdf0e10cSrcweir
479cdf0e10cSrcweir Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
480cdf0e10cSrcweir if (xMgr.is())
481cdf0e10cSrcweir {
482cdf0e10cSrcweir // build service initialization argument
483cdf0e10cSrcweir Sequence< Any > aArgs(2);
484cdf0e10cSrcweir aArgs.getArray()[0] <<= GetPropSet();
485cdf0e10cSrcweir //! The dispatcher searches the dictionary-list
486cdf0e10cSrcweir //! thus the service needs not to now about it
487cdf0e10cSrcweir //aArgs.getArray()[1] <<= GetDicList();
488cdf0e10cSrcweir
489cdf0e10cSrcweir // create specific service via it's implementation name
490cdf0e10cSrcweir try
491cdf0e10cSrcweir {
492cdf0e10cSrcweir xHyph = Reference< XHyphenator >(
493cdf0e10cSrcweir xMgr->createInstanceWithArguments(
494cdf0e10cSrcweir pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
495cdf0e10cSrcweir }
496cdf0e10cSrcweir catch (uno::Exception &)
497cdf0e10cSrcweir {
498cdf0e10cSrcweir DBG_ASSERT( 0, "createInstanceWithArguments failed" );
499cdf0e10cSrcweir }
500cdf0e10cSrcweir pRef [i] = xHyph;
501cdf0e10cSrcweir
502cdf0e10cSrcweir Reference< XLinguServiceEventBroadcaster >
503cdf0e10cSrcweir xBroadcaster( xHyph, UNO_QUERY );
504cdf0e10cSrcweir if (xBroadcaster.is())
505cdf0e10cSrcweir rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
506cdf0e10cSrcweir
507cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale ))
508cdf0e10cSrcweir xRes = xHyph->queryAlternativeSpelling( aChkWord, rLocale,
509cdf0e10cSrcweir nChkIndex, rProperties );
510cdf0e10cSrcweir
511cdf0e10cSrcweir pEntry->nLastTriedSvcIndex = (sal_Int16) i;
512cdf0e10cSrcweir ++i;
513cdf0e10cSrcweir
514cdf0e10cSrcweir // if language is not supported by the services
515cdf0e10cSrcweir // remove it from the list.
516cdf0e10cSrcweir if (xHyph.is() && !xHyph->hasLocale( rLocale ))
517cdf0e10cSrcweir aSvcMap.erase( nLanguage );
518cdf0e10cSrcweir }
519cdf0e10cSrcweir }
520cdf0e10cSrcweir } // if (xEntry.is())
521cdf0e10cSrcweir }
522cdf0e10cSrcweir
523cdf0e10cSrcweir if (bWordModified && xRes.is())
524cdf0e10cSrcweir xRes = RebuildHyphensAndControlChars( rWord, xRes );
525cdf0e10cSrcweir
526cdf0e10cSrcweir if (xRes.is() && xRes->getWord() != rWord)
527cdf0e10cSrcweir {
528cdf0e10cSrcweir xRes = new HyphenatedWord( rWord, nLanguage, xRes->getHyphenationPos(),
529cdf0e10cSrcweir xRes->getHyphenatedWord(),
530cdf0e10cSrcweir xRes->getHyphenPos() );
531cdf0e10cSrcweir }
532cdf0e10cSrcweir
533cdf0e10cSrcweir return xRes;
534cdf0e10cSrcweir }
535cdf0e10cSrcweir
536cdf0e10cSrcweir
537cdf0e10cSrcweir Reference< XPossibleHyphens > SAL_CALL
createPossibleHyphens(const OUString & rWord,const Locale & rLocale,const PropertyValues & rProperties)538cdf0e10cSrcweir HyphenatorDispatcher::createPossibleHyphens(
539cdf0e10cSrcweir const OUString& rWord, const Locale& rLocale,
540cdf0e10cSrcweir const PropertyValues& rProperties )
541cdf0e10cSrcweir throw(IllegalArgumentException, RuntimeException)
542cdf0e10cSrcweir {
543cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() );
544cdf0e10cSrcweir
545cdf0e10cSrcweir Reference< XPossibleHyphens > xRes;
546cdf0e10cSrcweir
547cdf0e10cSrcweir sal_Int16 nLanguage = LocaleToLanguage( rLocale );
548cdf0e10cSrcweir if (nLanguage == LANGUAGE_NONE || !rWord.getLength())
549cdf0e10cSrcweir return xRes;
550cdf0e10cSrcweir
551cdf0e10cSrcweir // search for entry with that language
552cdf0e10cSrcweir HyphSvcByLangMap_t::iterator aIt( aSvcMap.find( nLanguage ) );
553cdf0e10cSrcweir LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
554cdf0e10cSrcweir
555cdf0e10cSrcweir if (!pEntry)
556cdf0e10cSrcweir {
557cdf0e10cSrcweir #ifdef LINGU_EXCEPTIONS
558cdf0e10cSrcweir throw IllegalArgumentException();
559cdf0e10cSrcweir #endif
560cdf0e10cSrcweir }
561cdf0e10cSrcweir else
562cdf0e10cSrcweir {
563cdf0e10cSrcweir OUString aChkWord( rWord );
564cdf0e10cSrcweir
565cdf0e10cSrcweir // replace typographical apostroph by ascii apostroph
566cdf0e10cSrcweir String aSingleQuote( GetLocaleDataWrapper( nLanguage ).getQuotationMarkEnd() );
567cdf0e10cSrcweir DBG_ASSERT( 1 == aSingleQuote.Len(), "unexpectend length of quotation mark" );
568cdf0e10cSrcweir if (aSingleQuote.Len())
569cdf0e10cSrcweir aChkWord = aChkWord.replace( aSingleQuote.GetChar(0), '\'' );
570cdf0e10cSrcweir
571cdf0e10cSrcweir RemoveHyphens( aChkWord );
572cdf0e10cSrcweir if (IsIgnoreControlChars( rProperties, GetPropSet() ))
573cdf0e10cSrcweir RemoveControlChars( aChkWord );
574cdf0e10cSrcweir
575cdf0e10cSrcweir // check for results from (positive) dictionaries which have precedence!
576cdf0e10cSrcweir Reference< XDictionaryEntry > xEntry;
577cdf0e10cSrcweir
578cdf0e10cSrcweir if (GetDicList().is() && IsUseDicList( rProperties, GetPropSet() ))
579cdf0e10cSrcweir {
580cdf0e10cSrcweir xEntry = GetDicList()->queryDictionaryEntry( aChkWord, rLocale,
581cdf0e10cSrcweir sal_True, sal_False );
582cdf0e10cSrcweir }
583cdf0e10cSrcweir
584cdf0e10cSrcweir if (xEntry.is())
585cdf0e10cSrcweir {
586cdf0e10cSrcweir xRes = buildPossHyphens( xEntry, nLanguage );
587cdf0e10cSrcweir }
588cdf0e10cSrcweir else
589cdf0e10cSrcweir {
590cdf0e10cSrcweir sal_Int32 nLen = pEntry->aSvcImplNames.getLength() > 0 ? 1 : 0;
591cdf0e10cSrcweir DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
592cdf0e10cSrcweir "lng : index out of range");
593cdf0e10cSrcweir
594cdf0e10cSrcweir sal_Int32 i = 0;
595cdf0e10cSrcweir Reference< XHyphenator > xHyph;
596cdf0e10cSrcweir if (pEntry->aSvcRefs.getLength() > 0)
597cdf0e10cSrcweir xHyph = pEntry->aSvcRefs[0];
598cdf0e10cSrcweir
599cdf0e10cSrcweir // try already instantiated service
600cdf0e10cSrcweir if (i <= pEntry->nLastTriedSvcIndex)
601cdf0e10cSrcweir {
602cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale ))
603cdf0e10cSrcweir xRes = xHyph->createPossibleHyphens( aChkWord, rLocale,
604cdf0e10cSrcweir rProperties );
605cdf0e10cSrcweir ++i;
606cdf0e10cSrcweir }
607cdf0e10cSrcweir else if (pEntry->nLastTriedSvcIndex < nLen - 1)
608cdf0e10cSrcweir // instantiate services and try it
609cdf0e10cSrcweir {
610cdf0e10cSrcweir // const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
611cdf0e10cSrcweir Reference< XHyphenator > *pRef = pEntry->aSvcRefs.getArray();
612cdf0e10cSrcweir
613cdf0e10cSrcweir Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() );
614cdf0e10cSrcweir if (xMgr.is())
615cdf0e10cSrcweir {
616cdf0e10cSrcweir // build service initialization argument
617cdf0e10cSrcweir Sequence< Any > aArgs(2);
618cdf0e10cSrcweir aArgs.getArray()[0] <<= GetPropSet();
619cdf0e10cSrcweir //! The dispatcher searches the dictionary-list
620cdf0e10cSrcweir //! thus the service needs not to now about it
621cdf0e10cSrcweir //aArgs.getArray()[1] <<= GetDicList();
622cdf0e10cSrcweir
623cdf0e10cSrcweir // create specific service via it's implementation name
624cdf0e10cSrcweir try
625cdf0e10cSrcweir {
626cdf0e10cSrcweir xHyph = Reference< XHyphenator >(
627cdf0e10cSrcweir xMgr->createInstanceWithArguments(
628cdf0e10cSrcweir pEntry->aSvcImplNames[0], aArgs ), UNO_QUERY );
629cdf0e10cSrcweir }
630cdf0e10cSrcweir catch (uno::Exception &)
631cdf0e10cSrcweir {
632cdf0e10cSrcweir DBG_ASSERT( 0, "createWithArguments failed" );
633cdf0e10cSrcweir }
634cdf0e10cSrcweir pRef [i] = xHyph;
635cdf0e10cSrcweir
636cdf0e10cSrcweir Reference< XLinguServiceEventBroadcaster >
637cdf0e10cSrcweir xBroadcaster( xHyph, UNO_QUERY );
638cdf0e10cSrcweir if (xBroadcaster.is())
639cdf0e10cSrcweir rMgr.AddLngSvcEvtBroadcaster( xBroadcaster );
640cdf0e10cSrcweir
641cdf0e10cSrcweir if (xHyph.is() && xHyph->hasLocale( rLocale ))
642cdf0e10cSrcweir xRes = xHyph->createPossibleHyphens( aChkWord, rLocale,
643cdf0e10cSrcweir rProperties );
644cdf0e10cSrcweir
645cdf0e10cSrcweir pEntry->nLastTriedSvcIndex = (sal_Int16) i;
646cdf0e10cSrcweir ++i;
647cdf0e10cSrcweir
648cdf0e10cSrcweir // if language is not supported by the services
649cdf0e10cSrcweir // remove it from the list.
650cdf0e10cSrcweir if (xHyph.is() && !xHyph->hasLocale( rLocale ))
651cdf0e10cSrcweir aSvcMap.erase( nLanguage );
652cdf0e10cSrcweir }
653cdf0e10cSrcweir }
654cdf0e10cSrcweir } // if (xEntry.is())
655cdf0e10cSrcweir }
656cdf0e10cSrcweir
657cdf0e10cSrcweir if (xRes.is() && xRes->getWord() != rWord)
658cdf0e10cSrcweir {
659cdf0e10cSrcweir xRes = new PossibleHyphens( rWord, nLanguage,
660cdf0e10cSrcweir xRes->getPossibleHyphens(),
661cdf0e10cSrcweir xRes->getHyphenationPositions() );
662cdf0e10cSrcweir }
663cdf0e10cSrcweir
664cdf0e10cSrcweir return xRes;
665cdf0e10cSrcweir }
666cdf0e10cSrcweir
667cdf0e10cSrcweir
SetServiceList(const Locale & rLocale,const Sequence<OUString> & rSvcImplNames)668cdf0e10cSrcweir void HyphenatorDispatcher::SetServiceList( const Locale &rLocale,
669cdf0e10cSrcweir const Sequence< OUString > &rSvcImplNames )
670cdf0e10cSrcweir {
671cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() );
672cdf0e10cSrcweir
673cdf0e10cSrcweir sal_Int16 nLanguage = LocaleToLanguage( rLocale );
674cdf0e10cSrcweir
675cdf0e10cSrcweir sal_Int32 nLen = rSvcImplNames.getLength();
676cdf0e10cSrcweir if (0 == nLen)
677cdf0e10cSrcweir // remove entry
678cdf0e10cSrcweir aSvcMap.erase( nLanguage );
679cdf0e10cSrcweir else
680cdf0e10cSrcweir {
681cdf0e10cSrcweir // modify/add entry
682cdf0e10cSrcweir LangSvcEntries_Hyph *pEntry = aSvcMap[ nLanguage ].get();
683cdf0e10cSrcweir // only one hypenator can be in use for a language...
684cdf0e10cSrcweir //const OUString &rSvcImplName = rSvcImplNames.getConstArray()[0];
685cdf0e10cSrcweir if (pEntry)
686cdf0e10cSrcweir {
687cdf0e10cSrcweir pEntry->Clear();
688cdf0e10cSrcweir pEntry->aSvcImplNames = rSvcImplNames;
689cdf0e10cSrcweir pEntry->aSvcImplNames.realloc(1);
690cdf0e10cSrcweir pEntry->aSvcRefs = Sequence< Reference < XHyphenator > > ( 1 );
691cdf0e10cSrcweir }
692cdf0e10cSrcweir else
693cdf0e10cSrcweir {
694cdf0e10cSrcweir boost::shared_ptr< LangSvcEntries_Hyph > pTmpEntry( new LangSvcEntries_Hyph( rSvcImplNames[0] ) );
695cdf0e10cSrcweir pTmpEntry->aSvcRefs = Sequence< Reference < XHyphenator > >( 1 );
696cdf0e10cSrcweir aSvcMap[ nLanguage ] = pTmpEntry;
697cdf0e10cSrcweir }
698cdf0e10cSrcweir }
699cdf0e10cSrcweir }
700cdf0e10cSrcweir
701cdf0e10cSrcweir
702cdf0e10cSrcweir Sequence< OUString >
GetServiceList(const Locale & rLocale) const703cdf0e10cSrcweir HyphenatorDispatcher::GetServiceList( const Locale &rLocale ) const
704cdf0e10cSrcweir {
705cdf0e10cSrcweir MutexGuard aGuard( GetLinguMutex() );
706cdf0e10cSrcweir
707cdf0e10cSrcweir Sequence< OUString > aRes;
708cdf0e10cSrcweir
709cdf0e10cSrcweir // search for entry with that language and use data from that
710cdf0e10cSrcweir sal_Int16 nLanguage = LocaleToLanguage( rLocale );
711cdf0e10cSrcweir HyphenatorDispatcher *pThis = (HyphenatorDispatcher *) this;
712cdf0e10cSrcweir const HyphSvcByLangMap_t::iterator aIt( pThis->aSvcMap.find( nLanguage ) );
713cdf0e10cSrcweir const LangSvcEntries_Hyph *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
714cdf0e10cSrcweir if (pEntry)
715cdf0e10cSrcweir {
716cdf0e10cSrcweir aRes = pEntry->aSvcImplNames;
717cdf0e10cSrcweir if (aRes.getLength() > 0)
718cdf0e10cSrcweir aRes.realloc(1);
719cdf0e10cSrcweir }
720cdf0e10cSrcweir
721cdf0e10cSrcweir return aRes;
722cdf0e10cSrcweir }
723cdf0e10cSrcweir
724cdf0e10cSrcweir
GetDspType() const725cdf0e10cSrcweir LinguDispatcher::DspType HyphenatorDispatcher::GetDspType() const
726cdf0e10cSrcweir {
727cdf0e10cSrcweir return DSP_HYPH;
728cdf0e10cSrcweir }
729cdf0e10cSrcweir
730cdf0e10cSrcweir
731cdf0e10cSrcweir ///////////////////////////////////////////////////////////////////////////
732cdf0e10cSrcweir
733