Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <sal/macros.h>
30 : : #include <tools/string.hxx>
31 : : #include <tools/fsys.hxx>
32 : : #include <tools/debug.hxx>
33 : : #include <unotools/pathoptions.hxx>
34 : : #include <svl/lngmisc.hxx>
35 : : #include <ucbhelper/content.hxx>
36 : : #include <i18npool/mslangid.hxx>
37 : : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
38 : : #include <com/sun/star/beans/XPropertySet.hpp>
39 : : #include <com/sun/star/beans/XFastPropertySet.hpp>
40 : : #include <com/sun/star/beans/XPropertyChangeListener.hpp>
41 : : #include <com/sun/star/frame/XTerminateListener.hpp>
42 : : #include <com/sun/star/frame/XDesktop.hpp>
43 : : #include <com/sun/star/frame/XStorable.hpp>
44 : :
45 : : #include <com/sun/star/beans/PropertyValues.hpp>
46 : : #include <com/sun/star/uno/Sequence.hxx>
47 : : #include <com/sun/star/uno/Reference.h>
48 : : #include <com/sun/star/linguistic2/DictionaryType.hpp>
49 : : #include <com/sun/star/linguistic2/XSearchableDictionaryList.hpp>
50 : : #include <comphelper/processfactory.hxx>
51 : : #include <unotools/localedatawrapper.hxx>
52 : : #include <unotools/syslocale.hxx>
53 : :
54 : : #include <rtl/instance.hxx>
55 : :
56 : : #include "linguistic/misc.hxx"
57 : : #include "defs.hxx"
58 : : #include "linguistic/lngprops.hxx"
59 : : #include "linguistic/hyphdta.hxx"
60 : : #include <i18npool/mslangid.hxx>
61 : :
62 : : using namespace osl;
63 : : using namespace com::sun::star;
64 : : using namespace com::sun::star::beans;
65 : : using namespace com::sun::star::lang;
66 : : using namespace com::sun::star::uno;
67 : : using namespace com::sun::star::i18n;
68 : : using namespace com::sun::star::linguistic2;
69 : :
70 : : using ::rtl::OUString;
71 : :
72 : : namespace linguistic
73 : : {
74 : :
75 : :
76 : : //!! multi-thread safe mutex for all platforms !!
77 : : struct LinguMutex : public rtl::Static< osl::Mutex, LinguMutex >
78 : : {
79 : : };
80 : :
81 : 5174902 : osl::Mutex & GetLinguMutex()
82 : : {
83 : 5174902 : return LinguMutex::get();
84 : : }
85 : :
86 : :
87 : 66114 : LocaleDataWrapper & GetLocaleDataWrapper( sal_Int16 nLang )
88 : : {
89 : : static LocaleDataWrapper aLclDtaWrp(
90 : : comphelper::getProcessServiceFactory(),
91 [ + + ][ + - ]: 66114 : CreateLocale( SvtSysLocale().GetUILanguage() ) );
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ # # ]
92 : :
93 [ + - ]: 66114 : const Locale &rLcl = aLclDtaWrp.getLoadedLocale();
94 [ + - ]: 66114 : Locale aLcl( CreateLocale( nLang ) );
95 [ + - + - : 198342 : if (aLcl.Language != rLcl.Language ||
- + ][ - + ]
96 : 66114 : aLcl.Country != rLcl.Country ||
97 : 66114 : aLcl.Variant != rLcl.Variant)
98 [ # # ]: 0 : aLclDtaWrp.setLocale( aLcl );
99 : 66114 : return aLclDtaWrp;
100 : : }
101 : :
102 : 0 : static inline sal_Int32 Minimum( sal_Int32 n1, sal_Int32 n2, sal_Int32 n3 )
103 : : {
104 [ # # ]: 0 : sal_Int32 nMin = n1 < n2 ? n1 : n2;
105 [ # # ]: 0 : return nMin < n3 ? nMin : n3;
106 : : }
107 : :
108 : : class IntArray2D
109 : : {
110 : : private:
111 : : sal_Int32 *pData;
112 : : int n1, n2;
113 : :
114 : : public:
115 : : IntArray2D( int nDim1, int nDim2 );
116 : : ~IntArray2D();
117 : :
118 : : sal_Int32 & Value( int i, int k );
119 : : };
120 : :
121 : 0 : IntArray2D::IntArray2D( int nDim1, int nDim2 )
122 : : {
123 : 0 : n1 = nDim1;
124 : 0 : n2 = nDim2;
125 : 0 : pData = new sal_Int32[n1 * n2];
126 : 0 : }
127 : :
128 : 0 : IntArray2D::~IntArray2D()
129 : : {
130 [ # # ]: 0 : delete[] pData;
131 : 0 : }
132 : :
133 : 0 : sal_Int32 & IntArray2D::Value( int i, int k )
134 : : {
135 : : DBG_ASSERT( 0 <= i && i < n1, "first index out of range" );
136 : : DBG_ASSERT( 0 <= k && k < n2, "first index out of range" );
137 : : DBG_ASSERT( i * n2 + k < n1 * n2, "index out of range" );
138 : 0 : return pData[ i * n2 + k ];
139 : : }
140 : :
141 : :
142 : 0 : sal_Int32 LevDistance( const OUString &rTxt1, const OUString &rTxt2 )
143 : : {
144 : 0 : sal_Int32 nLen1 = rTxt1.getLength();
145 : 0 : sal_Int32 nLen2 = rTxt2.getLength();
146 : :
147 [ # # ]: 0 : if (nLen1 == 0)
148 : 0 : return nLen2;
149 [ # # ]: 0 : if (nLen2 == 0)
150 : 0 : return nLen1;
151 : :
152 [ # # ]: 0 : IntArray2D aData( nLen1 + 1, nLen2 + 1 );
153 : :
154 : : sal_Int32 i, k;
155 [ # # ]: 0 : for (i = 0; i <= nLen1; ++i)
156 : 0 : aData.Value(i, 0) = i;
157 [ # # ]: 0 : for (k = 0; k <= nLen2; ++k)
158 : 0 : aData.Value(0, k) = k;
159 [ # # ]: 0 : for (i = 1; i <= nLen1; ++i)
160 : : {
161 [ # # ]: 0 : for (k = 1; k <= nLen2; ++k)
162 : : {
163 : 0 : sal_Unicode c1i = rTxt1.getStr()[i - 1];
164 : 0 : sal_Unicode c2k = rTxt2.getStr()[k - 1];
165 : 0 : sal_Int32 nCost = c1i == c2k ? 0 : 1;
166 : 0 : sal_Int32 nNew = Minimum( aData.Value(i-1, k ) + 1,
167 : 0 : aData.Value(i , k-1) + 1,
168 : 0 : aData.Value(i-1, k-1) + nCost );
169 : : // take transposition (exchange with left or right char) in account
170 [ # # ][ # # ]: 0 : if (2 < i && 2 < k)
171 : : {
172 : 0 : int nT = aData.Value(i-2, k-2) + 1;
173 [ # # ]: 0 : if (rTxt1.getStr()[i - 2] != c1i)
174 : 0 : ++nT;
175 [ # # ]: 0 : if (rTxt2.getStr()[k - 2] != c2k)
176 : 0 : ++nT;
177 [ # # ]: 0 : if (nT < nNew)
178 : 0 : nNew = nT;
179 : : }
180 : :
181 : 0 : aData.Value(i, k) = nNew;
182 : : }
183 : : }
184 : 0 : sal_Int32 nDist = aData.Value(nLen1, nLen2);
185 : 0 : return nDist;
186 : : }
187 : :
188 : :
189 : 65832 : sal_Bool IsUseDicList( const PropertyValues &rProperties,
190 : : const uno::Reference< XPropertySet > &rxProp )
191 : : {
192 : 65832 : sal_Bool bRes = sal_True;
193 : :
194 : 65832 : sal_Int32 nLen = rProperties.getLength();
195 : 65832 : const PropertyValue *pVal = rProperties.getConstArray();
196 : : sal_Int32 i;
197 : :
198 [ - + ]: 65832 : for ( i = 0; i < nLen; ++i)
199 : : {
200 [ # # ]: 0 : if (UPH_IS_USE_DICTIONARY_LIST == pVal[i].Handle)
201 : : {
202 : 0 : pVal[i].Value >>= bRes;
203 : 0 : break;
204 : : }
205 : : }
206 [ + - ]: 65832 : if (i >= nLen) // no temporary value found in 'rProperties'
207 : : {
208 [ + - ]: 65832 : uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
209 [ + - ]: 65832 : if (xFast.is())
210 [ + - ][ + - ]: 65832 : xFast->getFastPropertyValue( UPH_IS_USE_DICTIONARY_LIST ) >>= bRes;
211 : : }
212 : :
213 : 65832 : return bRes;
214 : : }
215 : :
216 : :
217 : 65832 : sal_Bool IsIgnoreControlChars( const PropertyValues &rProperties,
218 : : const uno::Reference< XPropertySet > &rxProp )
219 : : {
220 : 65832 : sal_Bool bRes = sal_True;
221 : :
222 : 65832 : sal_Int32 nLen = rProperties.getLength();
223 : 65832 : const PropertyValue *pVal = rProperties.getConstArray();
224 : : sal_Int32 i;
225 : :
226 [ - + ]: 65832 : for ( i = 0; i < nLen; ++i)
227 : : {
228 [ # # ]: 0 : if (UPH_IS_IGNORE_CONTROL_CHARACTERS == pVal[i].Handle)
229 : : {
230 : 0 : pVal[i].Value >>= bRes;
231 : 0 : break;
232 : : }
233 : : }
234 [ + - ]: 65832 : if (i >= nLen) // no temporary value found in 'rProperties'
235 : : {
236 [ + - ]: 65832 : uno::Reference< XFastPropertySet > xFast( rxProp, UNO_QUERY );
237 [ + - ]: 65832 : if (xFast.is())
238 [ + - ][ + - ]: 65832 : xFast->getFastPropertyValue( UPH_IS_IGNORE_CONTROL_CHARACTERS ) >>= bRes;
239 : : }
240 : :
241 : 65832 : return bRes;
242 : : }
243 : :
244 : :
245 : 0 : static sal_Bool lcl_HasHyphInfo( const uno::Reference<XDictionaryEntry> &xEntry )
246 : : {
247 : 0 : sal_Bool bRes = sal_False;
248 [ # # ]: 0 : if (xEntry.is())
249 : : {
250 : : // there has to be (at least one) '=' denoting a hyphenation position
251 : : // and it must not be before any character of the word
252 : 0 : sal_Int32 nIdx = xEntry->getDictionaryWord().indexOf( '=' );
253 [ # # ][ # # ]: 0 : bRes = nIdx != -1 && nIdx != 0;
254 : : }
255 : 0 : return bRes;
256 : : }
257 : :
258 : :
259 : 98061 : uno::Reference< XDictionaryEntry > SearchDicList(
260 : : const uno::Reference< XDictionaryList > &xDicList,
261 : : const OUString &rWord, sal_Int16 nLanguage,
262 : : sal_Bool bSearchPosDics, sal_Bool bSearchSpellEntry )
263 : : {
264 [ + - ][ + - ]: 98061 : MutexGuard aGuard( GetLinguMutex() );
265 : :
266 : 98061 : uno::Reference< XDictionaryEntry > xEntry;
267 : :
268 [ + - ]: 98061 : if (!xDicList.is())
269 : : return xEntry;
270 : :
271 : : const uno::Sequence< uno::Reference< XDictionary > >
272 [ + - ][ + - ]: 98061 : aDics( xDicList->getDictionaries() );
273 : : const uno::Reference< XDictionary >
274 : 98061 : *pDic = aDics.getConstArray();
275 [ + - ][ + - ]: 98061 : sal_Int32 nDics = xDicList->getCount();
276 : :
277 : : sal_Int32 i;
278 [ + + ]: 585856 : for (i = 0; i < nDics; i++)
279 : : {
280 [ + - ]: 487795 : uno::Reference< XDictionary > axDic( pDic[i], UNO_QUERY );
281 : :
282 [ + - ][ + - ]: 487795 : DictionaryType eType = axDic->getDictionaryType();
283 [ + - ][ + - ]: 487795 : sal_Int16 nLang = LocaleToLanguage( axDic->getLocale() );
[ + - ]
284 : :
285 [ + - ][ + - ]: 487795 : if ( axDic.is() && axDic->isActive()
[ + - ][ + + ]
[ + + ][ + + ]
[ + - ]
286 : : && (nLang == nLanguage || nLang == LANGUAGE_NONE) )
287 : : {
288 : : DBG_ASSERT( eType != DictionaryType_MIXED,
289 : : "lng : unexpected dictionary type" );
290 : :
291 [ + + ][ + - ]: 292928 : if ( (!bSearchPosDics && eType == DictionaryType_NEGATIVE)
[ + + ][ + - ]
292 : : || ( bSearchPosDics && eType == DictionaryType_POSITIVE))
293 : : {
294 [ + - ][ + - ]: 196241 : if ( (xEntry = axDic->getEntry( rWord )).is() )
[ + - ][ + + ]
295 : : {
296 [ - + ][ # # ]: 1255 : if (bSearchSpellEntry || lcl_HasHyphInfo( xEntry ))
[ # # ][ + - ]
297 : : break;
298 : : }
299 [ + - ]: 486540 : xEntry = 0;
300 : : }
301 : : }
302 [ + + ]: 487795 : }
303 : :
304 [ + - ][ + - ]: 98061 : return xEntry;
305 : : }
306 : :
307 : :
308 : 0 : sal_Bool SaveDictionaries( const uno::Reference< XDictionaryList > &xDicList )
309 : : {
310 [ # # ]: 0 : if (!xDicList.is())
311 : 0 : return sal_True;
312 : :
313 : 0 : sal_Bool bRet = sal_True;
314 : :
315 [ # # ][ # # ]: 0 : Sequence< uno::Reference< XDictionary > > aDics( xDicList->getDictionaries() );
316 : 0 : const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
317 : 0 : sal_Int32 nCount = aDics.getLength();
318 [ # # ]: 0 : for (sal_Int32 i = 0; i < nCount; i++)
319 : : {
320 : : try
321 : : {
322 [ # # ]: 0 : uno::Reference< frame::XStorable > xStor( pDic[i], UNO_QUERY );
323 [ # # ]: 0 : if (xStor.is())
324 : : {
325 [ # # ][ # # ]: 0 : if (!xStor->isReadonly() && xStor->hasLocation())
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
326 [ # # ][ # # ]: 0 : xStor->store();
327 [ # # ]: 0 : }
328 : : }
329 [ # # ]: 0 : catch(uno::Exception &)
330 : : {
331 : 0 : bRet = sal_False;
332 : : }
333 : : }
334 : :
335 [ # # ]: 0 : return bRet;
336 : : }
337 : :
338 : :
339 : 0 : sal_uInt8 AddEntryToDic(
340 : : uno::Reference< XDictionary > &rxDic,
341 : : const OUString &rWord, sal_Bool bIsNeg,
342 : : const OUString &rRplcTxt, sal_Int16 /* nRplcLang */,
343 : : sal_Bool bStripDot )
344 : : {
345 [ # # ]: 0 : if (!rxDic.is())
346 : 0 : return DIC_ERR_NOT_EXISTS;
347 : :
348 : 0 : OUString aTmp( rWord );
349 [ # # ]: 0 : if (bStripDot)
350 : : {
351 : 0 : sal_Int32 nLen = rWord.getLength();
352 [ # # ][ # # ]: 0 : if (nLen > 0 && '.' == rWord[ nLen - 1])
[ # # ]
353 : : {
354 : : // remove trailing '.'
355 : : // (this is the official way to do this :-( )
356 : 0 : aTmp = aTmp.copy( 0, nLen - 1 );
357 : : }
358 : : }
359 [ # # ][ # # ]: 0 : sal_Bool bAddOk = rxDic->add( aTmp, bIsNeg, rRplcTxt );
360 : :
361 : 0 : sal_uInt8 nRes = DIC_ERR_NONE;
362 [ # # ]: 0 : if (!bAddOk)
363 : : {
364 [ # # ][ # # ]: 0 : if (rxDic->isFull())
[ # # ]
365 : 0 : nRes = DIC_ERR_FULL;
366 : : else
367 : : {
368 [ # # ]: 0 : uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
369 [ # # ][ # # ]: 0 : if (xStor.is() && xStor->isReadonly())
[ # # ][ # # ]
[ # # ]
370 : 0 : nRes = DIC_ERR_READONLY;
371 : : else
372 : 0 : nRes = DIC_ERR_UNKNOWN;
373 : : }
374 : : }
375 : :
376 : 0 : return nRes;
377 : : }
378 : :
379 : :
380 : :
381 : 733873 : LanguageType LocaleToLanguage( const Locale& rLocale )
382 : : {
383 : : // empty Locale -> LANGUAGE_NONE
384 [ + + ]: 733873 : if ( rLocale.Language.isEmpty() )
385 : 241456 : return LANGUAGE_NONE;
386 : :
387 : 733873 : return MsLangId::convertLocaleToLanguage( rLocale );
388 : : }
389 : :
390 : :
391 : 487795 : Locale& LanguageToLocale( Locale& rLocale, LanguageType eLang )
392 : : {
393 [ + + ]: 487795 : if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */)
394 : 292928 : MsLangId::convertLanguageToLocale( eLang, rLocale );
395 : :
396 : 487795 : return rLocale;
397 : : }
398 : :
399 : 189810 : Locale CreateLocale( LanguageType eLang )
400 : : {
401 : 189810 : Locale aLocale;
402 [ + + ]: 189810 : if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */)
403 [ + - ]: 189759 : return MsLangId::convertLanguageToLocale( eLang );
404 : :
405 : 189810 : return aLocale;
406 : : }
407 : :
408 : : uno::Sequence< sal_Int16 >
409 : 192 : LocaleSeqToLangSeq( uno::Sequence< Locale > &rLocaleSeq )
410 : : {
411 : 192 : const Locale *pLocale = rLocaleSeq.getConstArray();
412 : 192 : sal_Int32 nCount = rLocaleSeq.getLength();
413 : :
414 : 192 : uno::Sequence< sal_Int16 > aLangs( nCount );
415 [ + - ]: 192 : sal_Int16 *pLang = aLangs.getArray();
416 [ + + ]: 7392 : for (sal_Int32 i = 0; i < nCount; ++i)
417 : : {
418 [ + - ]: 7200 : pLang[i] = LocaleToLanguage( pLocale[i] );
419 : : }
420 : :
421 : 192 : return aLangs;
422 : : }
423 : :
424 : :
425 : 0 : sal_Bool IsReadOnly( const String &rURL, sal_Bool *pbExist )
426 : : {
427 : 0 : sal_Bool bRes = sal_False;
428 : 0 : sal_Bool bExists = sal_False;
429 : :
430 [ # # ]: 0 : if (rURL.Len() > 0)
431 : : {
432 : : try
433 : : {
434 : 0 : uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > xCmdEnv;
435 [ # # ][ # # ]: 0 : ::ucbhelper::Content aContent( rURL, xCmdEnv );
436 : :
437 [ # # ]: 0 : bExists = aContent.isDocument();
438 [ # # ]: 0 : if (bExists)
439 : : {
440 [ # # ][ # # ]: 0 : Any aAny( aContent.getPropertyValue( A2OU( "IsReadOnly" ) ) );
441 : 0 : aAny >>= bRes;
442 [ # # ][ # # ]: 0 : }
443 : : }
444 [ # # ]: 0 : catch (Exception &)
445 : : {
446 : 0 : bRes = sal_True;
447 : : }
448 : : }
449 : :
450 [ # # ]: 0 : if (pbExist)
451 : 0 : *pbExist = bExists;
452 : 0 : return bRes;
453 : : }
454 : :
455 : :
456 : :
457 : 0 : static sal_Bool GetAltSpelling( sal_Int16 &rnChgPos, sal_Int16 &rnChgLen, OUString &rRplc,
458 : : uno::Reference< XHyphenatedWord > &rxHyphWord )
459 : : {
460 : 0 : sal_Bool bRes = rxHyphWord->isAlternativeSpelling();
461 [ # # ]: 0 : if (bRes)
462 : : {
463 [ # # ][ # # ]: 0 : OUString aWord( rxHyphWord->getWord() ),
464 [ # # ][ # # ]: 0 : aHyphenatedWord( rxHyphWord->getHyphenatedWord() );
465 [ # # ][ # # ]: 0 : sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
466 : : /*sal_Int16 nHyphenPos = rxHyphWord->getHyphenPos()*/;
467 : 0 : const sal_Unicode *pWord = aWord.getStr(),
468 : 0 : *pAltWord = aHyphenatedWord.getStr();
469 : :
470 : : // at least char changes directly left or right to the hyphen
471 : : // should(!) be handled properly...
472 : : //! nHyphenationPos and nHyphenPos differ at most by 1 (see above)
473 : : //! Beware: eg "Schiffahrt" in German (pre spelling reform)
474 : : //! proves to be a bit nasty (nChgPosLeft and nChgPosRight overlap
475 : : //! to an extend.)
476 : :
477 : : // find first different char from left
478 : 0 : sal_Int32 nPosL = 0,
479 : 0 : nAltPosL = 0;
480 [ # # ]: 0 : for (sal_Int16 i = 0 ; pWord[ nPosL ] == pAltWord[ nAltPosL ]; nPosL++, nAltPosL++, i++)
481 : : {
482 : : // restrict changes area beginning to the right to
483 : : // the char immediately following the hyphen.
484 : : //! serves to insert the additional "f" in "Schiffahrt" at
485 : : //! position 5 rather than position 6.
486 [ # # ]: 0 : if (i >= nHyphenationPos + 1)
487 : 0 : break;
488 : : }
489 : :
490 : : // find first different char from right
491 : 0 : sal_Int32 nPosR = aWord.getLength() - 1,
492 : 0 : nAltPosR = aHyphenatedWord.getLength() - 1;
493 [ # # ][ # # ]: 0 : for ( ; nPosR >= nPosL && nAltPosR >= nAltPosL
[ # # ][ # # ]
494 : 0 : && pWord[ nPosR ] == pAltWord[ nAltPosR ];
495 : : nPosR--, nAltPosR--)
496 : : ;
497 : :
498 : 0 : rnChgPos = sal::static_int_cast< sal_Int16 >(nPosL);
499 : 0 : rnChgLen = sal::static_int_cast< sal_Int16 >(nPosR - nPosL + 1);
500 : : DBG_ASSERT( rnChgLen >= 0, "nChgLen < 0");
501 : :
502 : 0 : sal_Int32 nTxtStart = nPosL;
503 : 0 : sal_Int32 nTxtLen = nAltPosL - nPosL + 1;
504 : 0 : rRplc = aHyphenatedWord.copy( nTxtStart, nTxtLen );
505 : : }
506 : 0 : return bRes;
507 : : }
508 : :
509 : :
510 : 0 : static sal_Int16 GetOrigWordPos( const OUString &rOrigWord, sal_Int16 nPos )
511 : : {
512 : 0 : sal_Int32 nLen = rOrigWord.getLength();
513 : 0 : sal_Int32 i = -1;
514 [ # # ][ # # ]: 0 : while (nPos >= 0 && i++ < nLen)
[ # # ]
515 : : {
516 : 0 : sal_Unicode cChar = rOrigWord[i];
517 [ # # ][ # # ]: 0 : sal_Bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
518 [ # # ]: 0 : if (!bSkip)
519 : 0 : --nPos;
520 : : }
521 [ # # ][ # # ]: 0 : return sal::static_int_cast< sal_Int16 >((0 <= i && i < nLen) ? i : -1);
522 : : }
523 : :
524 : :
525 : 67206 : sal_Int32 GetPosInWordToCheck( const OUString &rTxt, sal_Int32 nPos )
526 : : {
527 : 67206 : sal_Int32 nRes = -1;
528 : 67206 : sal_Int32 nLen = rTxt.getLength();
529 [ + - ][ + - ]: 67206 : if (0 <= nPos && nPos < nLen)
530 : : {
531 : 67206 : nRes = 0;
532 [ + + ]: 140096 : for (sal_Int32 i = 0; i < nPos; ++i)
533 : : {
534 : 72890 : sal_Unicode cChar = rTxt[i];
535 [ - + ][ + - ]: 72890 : sal_Bool bSkip = IsHyphen( cChar ) || IsControlChar( cChar );
536 [ + - ]: 72890 : if (!bSkip)
537 : 72890 : ++nRes;
538 : : }
539 : : }
540 : 67206 : return nRes;
541 : : }
542 : :
543 : :
544 : 0 : uno::Reference< XHyphenatedWord > RebuildHyphensAndControlChars(
545 : : const OUString &rOrigWord,
546 : : uno::Reference< XHyphenatedWord > &rxHyphWord )
547 : : {
548 : 0 : uno::Reference< XHyphenatedWord > xRes;
549 [ # # ][ # # ]: 0 : if (!rOrigWord.isEmpty() && rxHyphWord.is())
[ # # ]
550 : : {
551 : 0 : sal_Int16 nChgPos = 0,
552 : 0 : nChgLen = 0;
553 : 0 : OUString aRplc;
554 [ # # ]: 0 : sal_Bool bAltSpelling = GetAltSpelling( nChgPos, nChgLen, aRplc, rxHyphWord );
555 : : #if OSL_DEBUG_LEVEL > 1
556 : : OUString aWord( rxHyphWord->getWord() );
557 : : #endif
558 : :
559 : 0 : OUString aOrigHyphenatedWord;
560 : 0 : sal_Int16 nOrigHyphenPos = -1;
561 : 0 : sal_Int16 nOrigHyphenationPos = -1;
562 [ # # ]: 0 : if (!bAltSpelling)
563 : : {
564 : 0 : aOrigHyphenatedWord = rOrigWord;
565 [ # # ][ # # ]: 0 : nOrigHyphenPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenPos() );
[ # # ]
566 [ # # ][ # # ]: 0 : nOrigHyphenationPos = GetOrigWordPos( rOrigWord, rxHyphWord->getHyphenationPos() );
[ # # ]
567 : : }
568 : : else
569 : : {
570 : : //! should at least work with the German words
571 : : //! B�-c-k-er and Sc-hif-fah-rt
572 : :
573 : 0 : OUString aLeft, aRight;
574 [ # # ]: 0 : sal_Int16 nPos = GetOrigWordPos( rOrigWord, nChgPos );
575 : :
576 : : // get words like Sc-hif-fah-rt to work correct
577 [ # # ][ # # ]: 0 : sal_Int16 nHyphenationPos = rxHyphWord->getHyphenationPos();
578 [ # # ]: 0 : if (nChgPos > nHyphenationPos)
579 : 0 : --nPos;
580 : :
581 : 0 : aLeft = rOrigWord.copy( 0, nPos );
582 : 0 : aRight = rOrigWord.copy( nPos + nChgLen );
583 : :
584 : 0 : aOrigHyphenatedWord = aLeft;
585 : 0 : aOrigHyphenatedWord += aRplc;
586 : 0 : aOrigHyphenatedWord += aRight;
587 : :
588 : 0 : nOrigHyphenPos = sal::static_int_cast< sal_Int16 >(aLeft.getLength() +
589 [ # # ][ # # ]: 0 : rxHyphWord->getHyphenPos() - nChgPos);
590 [ # # ]: 0 : nOrigHyphenationPos = GetOrigWordPos( rOrigWord, nHyphenationPos );
591 : : }
592 : :
593 [ # # ][ # # ]: 0 : if (nOrigHyphenPos == -1 || nOrigHyphenationPos == -1)
594 : : {
595 : : DBG_ASSERT( 0, "failed to get nOrigHyphenPos or nOrigHyphenationPos" );
596 : : }
597 : : else
598 : : {
599 [ # # ][ # # ]: 0 : sal_Int16 nLang = LocaleToLanguage( rxHyphWord->getLocale() );
[ # # ]
600 : : xRes = new HyphenatedWord(
601 : : rOrigWord, nLang, nOrigHyphenationPos,
602 [ # # ][ # # ]: 0 : aOrigHyphenatedWord, nOrigHyphenPos );
[ # # ]
603 : 0 : }
604 : :
605 : : }
606 : 0 : return xRes;
607 : : }
608 : :
609 : :
610 : :
611 : :
612 : 13033 : static CharClass & lcl_GetCharClass()
613 : : {
614 [ + + ][ + - ]: 13033 : static CharClass aCC( CreateLocale( LANGUAGE_ENGLISH_US ) );
[ + - ][ + - ]
[ # # ]
615 : 13033 : return aCC;
616 : : }
617 : :
618 : :
619 : 13033 : osl::Mutex & lcl_GetCharClassMutex()
620 : : {
621 [ + + ][ + - ]: 13033 : static osl::Mutex aMutex;
[ + - ][ # # ]
622 : 13033 : return aMutex;
623 : : }
624 : :
625 : :
626 : 12613 : sal_Bool IsUpper( const String &rText, xub_StrLen nPos, xub_StrLen nLen, sal_Int16 nLanguage )
627 : : {
628 [ + - ][ + - ]: 12613 : MutexGuard aGuard( lcl_GetCharClassMutex() );
629 : :
630 [ + - ]: 12613 : CharClass &rCC = lcl_GetCharClass();
631 [ + - ][ + - ]: 12613 : rCC.setLocale( CreateLocale( nLanguage ) );
632 [ + - ]: 12613 : sal_Int32 nFlags = rCC.getStringType( rText, nPos, nLen );
633 : : return (nFlags & KCharacterType::UPPER)
634 [ + + ][ + + ]: 12613 : && !(nFlags & KCharacterType::LOWER);
[ + - ]
635 : : }
636 : :
637 : :
638 : 420 : String ToLower( const String &rText, sal_Int16 nLanguage )
639 : : {
640 [ + - ][ + - ]: 420 : MutexGuard aGuard( lcl_GetCharClassMutex() );
641 : :
642 [ + - ]: 420 : CharClass &rCC = lcl_GetCharClass();
643 [ + - ][ + - ]: 420 : rCC.setLocale( CreateLocale( nLanguage ) );
644 [ + - ][ + - ]: 420 : return rCC.lowercase( rText );
[ + - ][ + - ]
645 : : }
646 : :
647 : :
648 : : // sorted(!) array of unicode ranges for code points that are exclusively(!) used as numbers
649 : : // and thus may NOT not be part of names or words like the Chinese/Japanese number characters
650 : : static const sal_uInt32 the_aDigitZeroes [] =
651 : : {
652 : : 0x00000030, //0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE
653 : : 0x00000660, //0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
654 : : 0x000006F0, //06F9 ; Decimal # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
655 : : 0x000007C0, //07C9 ; Decimal # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
656 : : 0x00000966, //096F ; Decimal # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
657 : : 0x000009E6, //09EF ; Decimal # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
658 : : 0x00000A66, //0A6F ; Decimal # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
659 : : 0x00000AE6, //0AEF ; Decimal # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
660 : : 0x00000B66, //0B6F ; Decimal # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
661 : : 0x00000BE6, //0BEF ; Decimal # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
662 : : 0x00000C66, //0C6F ; Decimal # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
663 : : 0x00000CE6, //0CEF ; Decimal # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
664 : : 0x00000D66, //0D6F ; Decimal # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
665 : : 0x00000E50, //0E59 ; Decimal # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
666 : : 0x00000ED0, //0ED9 ; Decimal # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
667 : : 0x00000F20, //0F29 ; Decimal # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
668 : : 0x00001040, //1049 ; Decimal # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
669 : : 0x00001090, //1099 ; Decimal # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
670 : : 0x000017E0, //17E9 ; Decimal # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
671 : : 0x00001810, //1819 ; Decimal # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
672 : : 0x00001946, //194F ; Decimal # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
673 : : 0x000019D0, //19D9 ; Decimal # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
674 : : 0x00001B50, //1B59 ; Decimal # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
675 : : 0x00001BB0, //1BB9 ; Decimal # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
676 : : 0x00001C40, //1C49 ; Decimal # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
677 : : 0x00001C50, //1C59 ; Decimal # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
678 : : 0x0000A620, //A629 ; Decimal # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
679 : : 0x0000A8D0, //A8D9 ; Decimal # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
680 : : 0x0000A900, //A909 ; Decimal # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
681 : : 0x0000AA50, //AA59 ; Decimal # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
682 : : 0x0000FF10, //FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
683 : : 0x000104A0, //104A9 ; Decimal # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
684 : : 0x0001D7CE //1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
685 : : };
686 : :
687 : 12449 : sal_Bool HasDigits( const OUString &rText )
688 : : {
689 : : static const int nNumDigitZeroes = sizeof(the_aDigitZeroes) / sizeof(the_aDigitZeroes[0]);
690 : 12449 : const sal_Int32 nLen = rText.getLength();
691 : :
692 : 12449 : sal_Int32 i = 0;
693 [ + + ]: 72453 : while (i < nLen) // for all characters ...
694 : : {
695 [ + - ]: 68357 : const sal_uInt32 nCodePoint = rText.iterateCodePoints( &i ); // handle unicode surrogates correctly...
696 [ + - ]: 128243 : for (int j = 0; j < nNumDigitZeroes; ++j) // ... check in all 0..9 ranges
697 : : {
698 : 128243 : sal_uInt32 nDigitZero = the_aDigitZeroes[ j ];
699 [ + + ]: 128243 : if (nDigitZero > nCodePoint)
700 : 60004 : break;
701 [ + + ]: 68239 : if (/*nDigitZero <= nCodePoint &&*/ nCodePoint <= nDigitZero + 9)
702 : 8353 : return sal_True;
703 : : }
704 : : }
705 : 12449 : return sal_False;
706 : : }
707 : :
708 : :
709 : 0 : sal_Bool IsNumeric( const String &rText )
710 : : {
711 : 0 : sal_Bool bRes = sal_False;
712 : 0 : xub_StrLen nLen = rText.Len();
713 [ # # ]: 0 : if (nLen)
714 : : {
715 : 0 : bRes = sal_True;
716 : 0 : xub_StrLen i = 0;
717 [ # # ]: 0 : while (i < nLen)
718 : : {
719 : 0 : sal_Unicode cChar = rText.GetChar( i++ );
720 [ # # ][ # # ]: 0 : if ( !((sal_Unicode)'0' <= cChar && cChar <= (sal_Unicode)'9') )
721 : : {
722 : 0 : bRes = sal_False;
723 : 0 : break;
724 : : }
725 : : }
726 : : }
727 : 0 : return bRes;
728 : : }
729 : :
730 : :
731 : :
732 : 64919 : uno::Reference< XInterface > GetOneInstanceService( const char *pServiceName )
733 : : {
734 : 64919 : uno::Reference< XInterface > xRef;
735 : :
736 [ + - ]: 64919 : if (pServiceName)
737 : : {
738 : : uno::Reference< XMultiServiceFactory > xMgr(
739 [ + - ]: 64919 : comphelper::getProcessServiceFactory() );
740 [ + - ]: 64919 : if (xMgr.is())
741 : : {
742 : : try
743 : : {
744 [ + - ][ + - ]: 64919 : xRef = xMgr->createInstance( ::rtl::OUString::createFromAscii( pServiceName ) );
[ + - ][ # # ]
745 : : }
746 [ # # ]: 0 : catch (uno::Exception &)
747 : : {
748 : : DBG_ASSERT( 0, "createInstance failed" );
749 : : }
750 : 64919 : }
751 : : }
752 : :
753 : 64919 : return xRef;
754 : : }
755 : :
756 : 330 : uno::Reference< XPropertySet > GetLinguProperties()
757 : : {
758 : : return uno::Reference< XPropertySet > (
759 [ + - ]: 330 : GetOneInstanceService( SN_LINGU_PROPERTIES ), UNO_QUERY );
760 : : }
761 : :
762 : 49 : uno::Reference< XSearchableDictionaryList > GetSearchableDictionaryList()
763 : : {
764 : : return uno::Reference< XSearchableDictionaryList > (
765 [ + - ]: 49 : GetOneInstanceService( SN_DICTIONARY_LIST ), UNO_QUERY );
766 : : }
767 : :
768 : 64540 : uno::Reference< XDictionaryList > GetDictionaryList()
769 : : {
770 : : return uno::Reference< XDictionaryList > (
771 [ + - ]: 64540 : GetOneInstanceService( SN_DICTIONARY_LIST ), UNO_QUERY );
772 : : }
773 : :
774 : 32229 : uno::Reference< XDictionary > GetIgnoreAllList()
775 : : {
776 : 32229 : uno::Reference< XDictionary > xRes;
777 [ + - ]: 32229 : uno::Reference< XDictionaryList > xDL( GetDictionaryList() );
778 [ + - ]: 32229 : if (xDL.is())
779 [ + - ][ + - ]: 32229 : xRes = xDL->getDictionaryByName( A2OU("IgnoreAllList") );
[ + - ][ + - ]
780 : 32229 : return xRes;
781 : : }
782 : :
783 : :
784 : 44 : AppExitListener::AppExitListener()
785 : : {
786 : : // add object to Desktop EventListeners in order to properly call
787 : : // the AtExit function at appliction exit.
788 : : uno::Reference< XMultiServiceFactory > xMgr(
789 [ + - ]: 44 : comphelper::getProcessServiceFactory() );
790 : :
791 [ + - ]: 44 : if (xMgr.is())
792 : : {
793 : : try
794 : : {
795 : : xDesktop = uno::Reference< frame::XDesktop >(
796 [ + - ][ + - ]: 44 : xMgr->createInstance( A2OU( SN_DESKTOP ) ), UNO_QUERY );
[ + - ][ + - ]
[ + - ][ # # ]
797 : : }
798 [ # # ]: 0 : catch (uno::Exception &)
799 : : {
800 : : DBG_ASSERT( 0, "createInstance failed" );
801 : : }
802 : 44 : }
803 : 44 : }
804 : :
805 : 42 : AppExitListener::~AppExitListener()
806 : : {
807 [ - + ]: 42 : }
808 : :
809 : :
810 : 44 : void AppExitListener::Activate()
811 : : {
812 [ + - ]: 44 : if (xDesktop.is())
813 [ + - ]: 44 : xDesktop->addTerminateListener( this );
814 : 44 : }
815 : :
816 : :
817 : 42 : void AppExitListener::Deactivate()
818 : : {
819 [ + + ]: 42 : if (xDesktop.is())
820 [ + - ]: 20 : xDesktop->removeTerminateListener( this );
821 : 42 : }
822 : :
823 : :
824 : : void SAL_CALL
825 : 24 : AppExitListener::disposing( const EventObject& rEvtSource )
826 : : throw(RuntimeException)
827 : : {
828 [ + - ][ + - ]: 24 : MutexGuard aGuard( GetLinguMutex() );
829 : :
830 [ + - ][ + - ]: 24 : if (xDesktop.is() && rEvtSource.Source == xDesktop)
[ + - ][ + - ]
831 : : {
832 [ + - ]: 24 : xDesktop = NULL; //! release reference to desktop
833 [ + - ]: 24 : }
834 : 24 : }
835 : :
836 : :
837 : : void SAL_CALL
838 : 44 : AppExitListener::queryTermination( const EventObject& /*rEvtSource*/ )
839 : : throw(frame::TerminationVetoException, RuntimeException)
840 : : {
841 : 44 : }
842 : :
843 : :
844 : : void SAL_CALL
845 : 44 : AppExitListener::notifyTermination( const EventObject& rEvtSource )
846 : : throw(RuntimeException)
847 : : {
848 [ + - ][ + - ]: 44 : MutexGuard aGuard( GetLinguMutex() );
849 : :
850 [ + - ][ + - ]: 44 : if (xDesktop.is() && rEvtSource.Source == xDesktop)
[ + - ][ + - ]
851 : : {
852 [ + - ]: 44 : AtExit();
853 [ + - ]: 44 : }
854 : 44 : }
855 : :
856 : :
857 : : } // namespace linguistic
858 : :
859 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|