Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <com/sun/star/io/XStream.hpp>
21 : #include <com/sun/star/lang/Locale.hpp>
22 : #include <tools/urlobj.hxx>
23 : #include <i18npool/mslangid.hxx>
24 : #include <vcl/svapp.hxx>
25 : #include <sot/storinfo.hxx>
26 : #include <svl/fstathelper.hxx>
27 : #include <svtools/helpopt.hxx>
28 : #include <svl/urihelper.hxx>
29 : #include <unotools/charclass.hxx>
30 : #include <com/sun/star/i18n/UnicodeType.hpp>
31 : #include <unotools/collatorwrapper.hxx>
32 : #include <com/sun/star/i18n/CollatorOptions.hpp>
33 : #include <com/sun/star/i18n/UnicodeScript.hpp>
34 : #include <com/sun/star/i18n/XOrdinalSuffix.hpp>
35 : #include <unotools/localedatawrapper.hxx>
36 : #include <unotools/transliterationwrapper.hxx>
37 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 : #include <com/sun/star/io/XActiveDataSource.hpp>
39 : #include <comphelper/componentcontext.hxx>
40 : #include <comphelper/processfactory.hxx>
41 : #include <comphelper/storagehelper.hxx>
42 : #include <comphelper/string.hxx>
43 : #include <editeng/editids.hrc>
44 : #include <sot/storage.hxx>
45 : #include <editeng/udlnitem.hxx>
46 : #include <editeng/wghtitem.hxx>
47 : #include <editeng/escpitem.hxx>
48 : #include <editeng/svxacorr.hxx>
49 : #include <editeng/unolingu.hxx>
50 : #include "vcl/window.hxx"
51 : #include <helpid.hrc>
52 : #include <com/sun/star/xml/sax/InputSource.hpp>
53 : #include <com/sun/star/xml/sax/Parser.hpp>
54 : #include <com/sun/star/xml/sax/Writer.hpp>
55 : #include <unotools/streamwrap.hxx>
56 : #include <SvXMLAutoCorrectImport.hxx>
57 : #include <SvXMLAutoCorrectExport.hxx>
58 : #include <ucbhelper/content.hxx>
59 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
60 : #include <com/sun/star/ucb/TransferInfo.hpp>
61 : #include <com/sun/star/ucb/NameClash.hpp>
62 : #include <xmloff/xmltoken.hxx>
63 : #include <vcl/help.hxx>
64 : #include <rtl/logfile.hxx>
65 :
66 : #define CHAR_HARDBLANK ((sal_Unicode)0x00A0)
67 :
68 : using namespace ::com::sun::star::ucb;
69 : using namespace ::com::sun::star::uno;
70 : using namespace ::com::sun::star;
71 : using namespace ::xmloff::token;
72 : using namespace ::rtl;
73 : using namespace ::utl;
74 :
75 : static const int C_NONE = 0x00;
76 : static const int C_FULL_STOP = 0x01;
77 : static const int C_EXCLAMATION_MARK = 0x02;
78 : static const int C_QUESTION_MARK = 0x04;
79 :
80 : static const sal_Char pImplWrdStt_ExcptLstStr[] = "WordExceptList";
81 : static const sal_Char pImplCplStt_ExcptLstStr[] = "SentenceExceptList";
82 : static const sal_Char pImplAutocorr_ListStr[] = "DocumentList";
83 : static const sal_Char pXMLImplWrdStt_ExcptLstStr[] = "WordExceptList.xml";
84 : static const sal_Char pXMLImplCplStt_ExcptLstStr[] = "SentenceExceptList.xml";
85 : static const sal_Char pXMLImplAutocorr_ListStr[] = "DocumentList.xml";
86 :
87 : static const sal_Char
88 : /* also at these beginnings - Brackets and all kinds of begin characters */
89 : sImplSttSkipChars[] = "\"\'([{\x83\x84\x89\x91\x92\x93\x94",
90 : /* also at these ends - Brackets and all kinds of begin characters */
91 : sImplEndSkipChars[] = "\"\')]}\x83\x84\x89\x91\x92\x93\x94";
92 :
93 : // These characters are allowed in words: (for FnCptlSttSntnc)
94 : static const sal_Char sImplWordChars[] = "-'";
95 :
96 : void EncryptBlockName_Imp( String& rName );
97 :
98 0 : TYPEINIT0(SvxAutoCorrect)
99 :
100 : typedef SvxAutoCorrectLanguageLists* SvxAutoCorrectLanguageListsPtr;
101 :
102 0 : static inline int IsWordDelim( const sal_Unicode c )
103 : {
104 : return ' ' == c || '\t' == c || 0x0a == c ||
105 0 : 0xA0 == c || 0x2011 == c || 0x1 == c;
106 : }
107 :
108 0 : static inline int IsLowerLetter( sal_Int32 nCharType )
109 : {
110 0 : return CharClass::isLetterType( nCharType ) &&
111 0 : 0 == ( ::com::sun::star::i18n::KCharacterType::UPPER & nCharType);
112 : }
113 :
114 0 : static inline int IsUpperLetter( sal_Int32 nCharType )
115 : {
116 0 : return CharClass::isLetterType( nCharType ) &&
117 0 : 0 == ( ::com::sun::star::i18n::KCharacterType::LOWER & nCharType);
118 : }
119 :
120 0 : bool lcl_IsUnsupportedUnicodeChar( CharClass& rCC, const String& rTxt,
121 : xub_StrLen nStt, xub_StrLen nEnd )
122 : {
123 0 : for( ; nStt < nEnd; ++nStt )
124 : {
125 0 : short nScript = rCC.getScript( rTxt, nStt );
126 0 : switch( nScript )
127 : {
128 : case ::com::sun::star::i18n::UnicodeScript_kCJKRadicalsSupplement:
129 : case ::com::sun::star::i18n::UnicodeScript_kHangulJamo:
130 : case ::com::sun::star::i18n::UnicodeScript_kCJKSymbolPunctuation:
131 : case ::com::sun::star::i18n::UnicodeScript_kHiragana:
132 : case ::com::sun::star::i18n::UnicodeScript_kKatakana:
133 : case ::com::sun::star::i18n::UnicodeScript_kHangulCompatibilityJamo:
134 : case ::com::sun::star::i18n::UnicodeScript_kEnclosedCJKLetterMonth:
135 : case ::com::sun::star::i18n::UnicodeScript_kCJKCompatibility:
136 : case ::com::sun::star::i18n::UnicodeScript_k_CJKUnifiedIdeographsExtensionA:
137 : case ::com::sun::star::i18n::UnicodeScript_kCJKUnifiedIdeograph:
138 : case ::com::sun::star::i18n::UnicodeScript_kHangulSyllable:
139 : case ::com::sun::star::i18n::UnicodeScript_kCJKCompatibilityIdeograph:
140 : case ::com::sun::star::i18n::UnicodeScript_kHalfwidthFullwidthForm:
141 0 : return true;
142 : default: ; //do nothing
143 : }
144 : }
145 0 : return false;
146 : }
147 :
148 0 : static sal_Bool lcl_IsSymbolChar( CharClass& rCC, const String& rTxt,
149 : xub_StrLen nStt, xub_StrLen nEnd )
150 : {
151 0 : for( ; nStt < nEnd; ++nStt )
152 : {
153 0 : if( ::com::sun::star::i18n::UnicodeType::PRIVATE_USE ==
154 0 : rCC.getType( rTxt, nStt ))
155 0 : return sal_True;
156 : }
157 0 : return sal_False;
158 : }
159 :
160 0 : static sal_Bool lcl_IsInAsciiArr( const sal_Char* pArr, const sal_Unicode c )
161 : {
162 0 : sal_Bool bRet = sal_False;
163 0 : for( ; *pArr; ++pArr )
164 0 : if( *pArr == c )
165 : {
166 0 : bRet = sal_True;
167 0 : break;
168 : }
169 0 : return bRet;
170 : }
171 :
172 0 : SvxAutoCorrDoc::~SvxAutoCorrDoc()
173 : {
174 0 : }
175 : // Is called by the functions:
176 : // - FnCptlSttWrd
177 : // - FnCptlSttSntnc
178 : // after the exchange of characters. then the words can maybe be inserted
179 : // into the exception list.
180 0 : void SvxAutoCorrDoc::SaveCpltSttWord( sal_uLong, xub_StrLen, const String&,
181 : sal_Unicode )
182 : {
183 0 : }
184 :
185 0 : LanguageType SvxAutoCorrDoc::GetLanguage( xub_StrLen , sal_Bool ) const
186 : {
187 0 : return LANGUAGE_SYSTEM;
188 : }
189 :
190 10 : static const LanguageTag& GetAppLang()
191 : {
192 10 : return Application::GetSettings().GetLanguageTag();
193 : }
194 0 : static LocaleDataWrapper& GetLocaleDataWrapper( sal_uInt16 nLang )
195 : {
196 0 : static LocaleDataWrapper aLclDtWrp( GetAppLang() );
197 0 : LanguageTag aLcl( nLang );
198 0 : const LanguageTag& rLcl = aLclDtWrp.getLoadedLanguageTag();
199 0 : if( aLcl != rLcl )
200 0 : aLclDtWrp.setLanguageTag( aLcl );
201 0 : return aLclDtWrp;
202 : }
203 0 : static TransliterationWrapper& GetIgnoreTranslWrapper()
204 : {
205 : static int bIsInit = 0;
206 : static TransliterationWrapper aWrp( ::comphelper::getProcessComponentContext(),
207 : ::com::sun::star::i18n::TransliterationModules_IGNORE_KANA |
208 0 : ::com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH );
209 0 : if( !bIsInit )
210 : {
211 0 : aWrp.loadModuleIfNeeded( GetAppLang().getLanguageType() );
212 0 : bIsInit = 1;
213 : }
214 0 : return aWrp;
215 : }
216 0 : static CollatorWrapper& GetCollatorWrapper()
217 : {
218 : static int bIsInit = 0;
219 0 : static CollatorWrapper aCollWrp( ::comphelper::getProcessComponentContext() );
220 0 : if( !bIsInit )
221 : {
222 0 : aCollWrp.loadDefaultCollator( GetAppLang().getLocale(), 0 );
223 0 : bIsInit = 1;
224 : }
225 0 : return aCollWrp;
226 : }
227 :
228 20 : static void lcl_ClearTable(boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>& rLangTable)
229 : {
230 20 : rLangTable.clear();
231 20 : }
232 :
233 0 : sal_Bool SvxAutoCorrect::IsAutoCorrectChar( sal_Unicode cChar )
234 : {
235 : return cChar == '\0' || cChar == '\t' || cChar == 0x0a ||
236 : cChar == ' ' || cChar == '\'' || cChar == '\"' ||
237 : cChar == '*' || cChar == '_' || cChar == '%' ||
238 : cChar == '.' || cChar == ',' || cChar == ';' ||
239 0 : cChar == ':' || cChar == '?' || cChar == '!' || cChar == '/';
240 : }
241 :
242 0 : sal_Bool SvxAutoCorrect::NeedsHardspaceAutocorr( sal_Unicode cChar )
243 : {
244 : return cChar == '%' || cChar == ';' || cChar == ':' || cChar == '?' || cChar == '!' ||
245 0 : cChar == '/' /*case for the urls exception*/;
246 : }
247 :
248 10 : long SvxAutoCorrect::GetDefaultFlags()
249 : {
250 : long nRet = Autocorrect
251 : | CptlSttSntnc
252 : | CptlSttWrd
253 : | ChgOrdinalNumber
254 : | ChgToEnEmDash
255 : | AddNonBrkSpace
256 : | ChgWeightUnderl
257 : | SetINetAttr
258 : | ChgQuotes
259 : | SaveWordCplSttLst
260 : | SaveWordWrdSttLst
261 10 : | CorrectCapsLock;
262 10 : LanguageType eLang = GetAppLang().getLanguageType();
263 10 : switch( eLang )
264 : {
265 : case LANGUAGE_ENGLISH:
266 : case LANGUAGE_ENGLISH_US:
267 : case LANGUAGE_ENGLISH_UK:
268 : case LANGUAGE_ENGLISH_AUS:
269 : case LANGUAGE_ENGLISH_CAN:
270 : case LANGUAGE_ENGLISH_NZ:
271 : case LANGUAGE_ENGLISH_EIRE:
272 : case LANGUAGE_ENGLISH_SAFRICA:
273 : case LANGUAGE_ENGLISH_JAMAICA:
274 : case LANGUAGE_ENGLISH_CARRIBEAN:
275 10 : nRet &= ~(ChgQuotes|ChgSglQuotes);
276 10 : break;
277 : }
278 10 : return nRet;
279 : }
280 :
281 :
282 10 : SvxAutoCorrect::SvxAutoCorrect( const String& rShareAutocorrFile,
283 : const String& rUserAutocorrFile )
284 : : sShareAutoCorrFile( rShareAutocorrFile ),
285 : sUserAutoCorrFile( rUserAutocorrFile ),
286 10 : pLangTable( new boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists> ),
287 : pCharClass( 0 ), bRunNext( false ),
288 20 : cStartDQuote( 0 ), cEndDQuote( 0 ), cStartSQuote( 0 ), cEndSQuote( 0 )
289 : {
290 10 : nFlags = SvxAutoCorrect::GetDefaultFlags();
291 :
292 10 : cEmDash = 0x2014;
293 10 : cEnDash = 0x2013;
294 10 : }
295 :
296 10 : SvxAutoCorrect::SvxAutoCorrect( const SvxAutoCorrect& rCpy )
297 : : sShareAutoCorrFile( rCpy.sShareAutoCorrFile ),
298 : sUserAutoCorrFile( rCpy.sUserAutoCorrFile ),
299 :
300 : aSwFlags( rCpy.aSwFlags ),
301 :
302 10 : pLangTable( new boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists> ),
303 : pCharClass( 0 ), bRunNext( false ),
304 :
305 : nFlags( rCpy.nFlags & ~(ChgWordLstLoad|CplSttLstLoad|WrdSttLstLoad)),
306 : cStartDQuote( rCpy.cStartDQuote ), cEndDQuote( rCpy.cEndDQuote ),
307 : cStartSQuote( rCpy.cStartSQuote ), cEndSQuote( rCpy.cEndSQuote ),
308 20 : cEmDash( rCpy.cEmDash ), cEnDash( rCpy.cEnDash )
309 : {
310 10 : }
311 :
312 :
313 50 : SvxAutoCorrect::~SvxAutoCorrect()
314 : {
315 20 : lcl_ClearTable(*pLangTable);
316 20 : delete pLangTable;
317 20 : delete pCharClass;
318 30 : }
319 :
320 0 : void SvxAutoCorrect::_GetCharClass( LanguageType eLang )
321 : {
322 0 : delete pCharClass;
323 0 : pCharClass = new CharClass( LanguageTag( eLang ));
324 0 : eCharClassLang = eLang;
325 0 : }
326 :
327 20 : void SvxAutoCorrect::SetAutoCorrFlag( long nFlag, sal_Bool bOn )
328 : {
329 20 : long nOld = nFlags;
330 : nFlags = bOn ? nFlags | nFlag
331 20 : : nFlags & ~nFlag;
332 :
333 20 : if( !bOn )
334 : {
335 10 : if( (nOld & CptlSttSntnc) != (nFlags & CptlSttSntnc) )
336 0 : nFlags &= ~CplSttLstLoad;
337 10 : if( (nOld & CptlSttWrd) != (nFlags & CptlSttWrd) )
338 0 : nFlags &= ~WrdSttLstLoad;
339 10 : if( (nOld & Autocorrect) != (nFlags & Autocorrect) )
340 0 : nFlags &= ~ChgWordLstLoad;
341 : }
342 20 : }
343 :
344 :
345 : // Two capital letters at the beginning of word?
346 0 : sal_Bool SvxAutoCorrect::FnCptlSttWrd( SvxAutoCorrDoc& rDoc, const String& rTxt,
347 : xub_StrLen nSttPos, xub_StrLen nEndPos,
348 : LanguageType eLang )
349 : {
350 0 : sal_Bool bRet = sal_False;
351 0 : CharClass& rCC = GetCharClass( eLang );
352 :
353 : // Delete all non alphanumeric. Test the characters at the beginning/end of
354 : // the word ( recognizes: "(min.", "/min.", and so on.)
355 0 : for( ; nSttPos < nEndPos; ++nSttPos )
356 0 : if( rCC.isLetterNumeric( rTxt, nSttPos ))
357 0 : break;
358 0 : for( ; nSttPos < nEndPos; --nEndPos )
359 0 : if( rCC.isLetterNumeric( rTxt, nEndPos - 1 ))
360 0 : break;
361 :
362 : // Two capital letters at the beginning of word?
363 0 : if( nSttPos+2 < nEndPos &&
364 0 : IsUpperLetter( rCC.getCharacterType( rTxt, nSttPos )) &&
365 0 : IsUpperLetter( rCC.getCharacterType( rTxt, ++nSttPos )) &&
366 : // Is the third character a lower case
367 0 : IsLowerLetter( rCC.getCharacterType( rTxt, nSttPos +1 )) &&
368 : // Do not replace special attributes
369 0 : 0x1 != rTxt.GetChar( nSttPos ) && 0x2 != rTxt.GetChar( nSttPos ))
370 : {
371 : // test if the word is in an exception list
372 0 : String sWord( rTxt.Copy( nSttPos - 1, nEndPos - nSttPos + 1 ));
373 0 : if( !FindInWrdSttExceptList(eLang, sWord) )
374 : {
375 : // Check that word isn't correctly spelled before correcting:
376 : ::com::sun::star::uno::Reference<
377 : ::com::sun::star::linguistic2::XSpellChecker1 > xSpeller =
378 0 : SvxGetSpellChecker();
379 0 : if( xSpeller->hasLanguage(eLang) )
380 : {
381 0 : Sequence< ::com::sun::star::beans::PropertyValue > aEmptySeq;
382 0 : if (!xSpeller->spell(sWord, eLang, aEmptySeq).is())
383 : {
384 0 : return false;
385 0 : }
386 : }
387 0 : sal_Unicode cSave = rTxt.GetChar( nSttPos );
388 0 : rtl::OUString sChar( cSave );
389 0 : sChar = rCC.lowercase( sChar );
390 0 : if( sChar[0] != cSave && rDoc.ReplaceRange( nSttPos, 1, sChar ))
391 : {
392 0 : if( SaveWordWrdSttLst & nFlags )
393 0 : rDoc.SaveCpltSttWord( CptlSttWrd, nSttPos, sWord, cSave );
394 0 : bRet = sal_True;
395 0 : }
396 0 : }
397 : }
398 0 : return bRet;
399 : }
400 :
401 :
402 0 : sal_Bool SvxAutoCorrect::FnChgOrdinalNumber(
403 : SvxAutoCorrDoc& rDoc, const String& rTxt,
404 : xub_StrLen nSttPos, xub_StrLen nEndPos,
405 : LanguageType eLang )
406 : {
407 : // 1st, 2nd, 3rd, 4 - 0th
408 : // 201th or 201st
409 : // 12th or 12nd
410 0 : CharClass& rCC = GetCharClass( eLang );
411 0 : sal_Bool bChg = sal_False;
412 :
413 0 : for( ; nSttPos < nEndPos; ++nSttPos )
414 0 : if( !lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nSttPos ) ))
415 0 : break;
416 0 : for( ; nSttPos < nEndPos; --nEndPos )
417 0 : if( !lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nEndPos - 1 ) ))
418 0 : break;
419 :
420 :
421 : // Get the last number in the string to check
422 0 : xub_StrLen nNumEnd = nEndPos;
423 0 : bool foundEnd = false;
424 0 : bool validNumber = true;
425 0 : xub_StrLen i = nEndPos;
426 :
427 0 : while ( i > nSttPos )
428 : {
429 0 : i--;
430 0 : bool isDigit = rCC.isDigit( rTxt, i );
431 0 : if ( foundEnd )
432 0 : validNumber |= isDigit;
433 :
434 0 : if ( isDigit && !foundEnd )
435 : {
436 0 : foundEnd = true;
437 0 : nNumEnd = i;
438 : }
439 : }
440 :
441 0 : if ( foundEnd && validNumber ) {
442 0 : sal_Int32 nNum = rTxt.Copy( nSttPos, nNumEnd - nSttPos + 1 ).ToInt32( );
443 :
444 : // Check if the characters after that number correspond to the ordinal suffix
445 0 : rtl::OUString sServiceName("com.sun.star.i18n.OrdinalSuffix");
446 : uno::Reference< i18n::XOrdinalSuffix > xOrdSuffix(
447 0 : comphelper::getProcessServiceFactory()->createInstance( sServiceName ),
448 0 : uno::UNO_QUERY );
449 :
450 0 : if ( xOrdSuffix.is( ) )
451 : {
452 0 : uno::Sequence< rtl::OUString > aSuffixes = xOrdSuffix->getOrdinalSuffix( nNum, rCC.getLanguageTag().getLocale( ) );
453 0 : for ( sal_Int32 nSuff = 0; nSuff < aSuffixes.getLength(); nSuff++ )
454 : {
455 0 : String sSuffix( aSuffixes[ nSuff ] );
456 0 : String sEnd = rTxt.Copy( nNumEnd + 1, nEndPos - nNumEnd - 1 );
457 :
458 0 : if ( sSuffix == sEnd )
459 : {
460 : // Check if the ordinal suffix has to be set as super script
461 0 : if ( rCC.isLetter( sSuffix ) )
462 : {
463 : // Do the change
464 : SvxEscapementItem aSvxEscapementItem( DFLT_ESC_AUTO_SUPER,
465 0 : DFLT_ESC_PROP, SID_ATTR_CHAR_ESCAPEMENT );
466 : rDoc.SetAttr( nNumEnd + 1 , nEndPos,
467 : SID_ATTR_CHAR_ESCAPEMENT,
468 0 : aSvxEscapementItem);
469 : }
470 : }
471 0 : }
472 0 : }
473 :
474 : }
475 0 : return bChg;
476 : }
477 :
478 :
479 0 : sal_Bool SvxAutoCorrect::FnChgToEnEmDash(
480 : SvxAutoCorrDoc& rDoc, const String& rTxt,
481 : xub_StrLen nSttPos, xub_StrLen nEndPos,
482 : LanguageType eLang )
483 : {
484 0 : sal_Bool bRet = sal_False;
485 0 : CharClass& rCC = GetCharClass( eLang );
486 0 : if (eLang == LANGUAGE_SYSTEM)
487 0 : eLang = GetAppLang().getLanguageType();
488 0 : bool bAlwaysUseEmDash = (cEmDash && (eLang == LANGUAGE_RUSSIAN || eLang == LANGUAGE_UKRAINIAN));
489 :
490 : // replace " - " or " --" with "enDash"
491 0 : if( cEnDash && 1 < nSttPos && 1 <= nEndPos - nSttPos )
492 : {
493 0 : sal_Unicode cCh = rTxt.GetChar( nSttPos );
494 0 : if( '-' == cCh )
495 : {
496 0 : if( ' ' == rTxt.GetChar( nSttPos-1 ) &&
497 0 : '-' == rTxt.GetChar( nSttPos+1 ))
498 : {
499 : xub_StrLen n;
500 0 : for( n = nSttPos+2; n < nEndPos && lcl_IsInAsciiArr(
501 0 : sImplSttSkipChars,(cCh = rTxt.GetChar( n )));
502 : ++n )
503 : ;
504 :
505 : // found: " --[<AnySttChars>][A-z0-9]
506 0 : if( rCC.isLetterNumeric( rtl::OUString(cCh) ) )
507 : {
508 0 : for( n = nSttPos-1; n && lcl_IsInAsciiArr(
509 0 : sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); )
510 : ;
511 :
512 : // found: "[A-z0-9][<AnyEndChars>] --[<AnySttChars>][A-z0-9]
513 0 : if( rCC.isLetterNumeric( rtl::OUString(cCh) ))
514 : {
515 0 : rDoc.Delete( nSttPos, nSttPos + 2 );
516 0 : rDoc.Insert( nSttPos, bAlwaysUseEmDash ? rtl::OUString(cEmDash) : rtl::OUString(cEnDash) );
517 0 : bRet = sal_True;
518 : }
519 : }
520 : }
521 : }
522 0 : else if( 3 < nSttPos &&
523 0 : ' ' == rTxt.GetChar( nSttPos-1 ) &&
524 0 : '-' == rTxt.GetChar( nSttPos-2 ))
525 : {
526 0 : xub_StrLen n, nLen = 1, nTmpPos = nSttPos - 2;
527 0 : if( '-' == ( cCh = rTxt.GetChar( nTmpPos-1 )) )
528 : {
529 0 : --nTmpPos;
530 0 : ++nLen;
531 0 : cCh = rTxt.GetChar( nTmpPos-1 );
532 : }
533 0 : if( ' ' == cCh )
534 : {
535 0 : for( n = nSttPos; n < nEndPos && lcl_IsInAsciiArr(
536 0 : sImplSttSkipChars,(cCh = rTxt.GetChar( n )));
537 : ++n )
538 : ;
539 :
540 : // found: " - [<AnySttChars>][A-z0-9]
541 0 : if( rCC.isLetterNumeric( rtl::OUString(cCh) ) )
542 : {
543 0 : cCh = ' ';
544 0 : for( n = nTmpPos-1; n && lcl_IsInAsciiArr(
545 0 : sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); )
546 : ;
547 : // found: "[A-z0-9][<AnyEndChars>] - [<AnySttChars>][A-z0-9]
548 0 : if( rCC.isLetterNumeric( rtl::OUString(cCh) ))
549 : {
550 0 : rDoc.Delete( nTmpPos, nTmpPos + nLen );
551 0 : rDoc.Insert( nTmpPos, bAlwaysUseEmDash ? rtl::OUString(cEmDash) : rtl::OUString(cEnDash) );
552 0 : bRet = sal_True;
553 : }
554 : }
555 : }
556 : }
557 : }
558 :
559 : // Replace [A-z0-9]--[A-z0-9] double dash with "emDash" or "enDash".
560 : // Finnish and Hungarian use enDash instead of emDash.
561 0 : bool bEnDash = (eLang == LANGUAGE_HUNGARIAN || eLang == LANGUAGE_FINNISH);
562 0 : if( ((cEmDash && !bEnDash) || (cEnDash && bEnDash)) && 4 <= nEndPos - nSttPos )
563 : {
564 0 : String sTmp( rTxt.Copy( nSttPos, nEndPos - nSttPos ) );
565 0 : xub_StrLen nFndPos = sTmp.SearchAscii( "--" );
566 0 : if( STRING_NOTFOUND != nFndPos && nFndPos &&
567 0 : nFndPos + 2 < sTmp.Len() &&
568 0 : ( rCC.isLetterNumeric( sTmp, nFndPos - 1 ) ||
569 0 : lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nFndPos - 1 ) )) &&
570 0 : ( rCC.isLetterNumeric( sTmp, nFndPos + 2 ) ||
571 0 : lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nFndPos + 2 ) )))
572 : {
573 0 : nSttPos = nSttPos + nFndPos;
574 0 : rDoc.Delete( nSttPos, nSttPos + 2 );
575 0 : rDoc.Insert( nSttPos, (bEnDash ? rtl::OUString(cEnDash) : rtl::OUString(cEmDash)) );
576 0 : bRet = sal_True;
577 0 : }
578 : }
579 0 : return bRet;
580 : }
581 :
582 : #ifdef _MSC_VER
583 : #pragma warning(push)
584 : #pragma warning(disable: 4706) // assignment within conditional expression
585 : #endif
586 :
587 0 : sal_Bool SvxAutoCorrect::FnAddNonBrkSpace(
588 : SvxAutoCorrDoc& rDoc, const String& rTxt,
589 : xub_StrLen, xub_StrLen nEndPos,
590 : LanguageType eLang )
591 : {
592 0 : bool bRet = false;
593 :
594 0 : CharClass& rCC = GetCharClass( eLang );
595 0 : const lang::Locale rLocale = rCC.getLanguageTag().getLocale( );
596 :
597 0 : if ( rLocale.Language == OUString( "fr" ) )
598 : {
599 0 : bool bFrCA = rLocale.Country == OUString( "CA" );
600 0 : OUString allChars = OUString( ":;?!%" );
601 0 : OUString chars( allChars );
602 0 : if ( bFrCA )
603 0 : chars = OUString( ":" );
604 :
605 0 : sal_Unicode cChar = rTxt.GetChar( nEndPos );
606 0 : bool bHasSpace = chars.indexOf( cChar ) != -1;
607 0 : bool bIsSpecial = allChars.indexOf( cChar ) != -1;
608 0 : if ( bIsSpecial )
609 : {
610 : // Get the last word delimiter position
611 0 : xub_StrLen nSttWdPos = nEndPos;
612 0 : bool bWasWordDelim = false;
613 0 : while( nSttWdPos && !(bWasWordDelim = IsWordDelim( rTxt.GetChar( --nSttWdPos ))))
614 : ;
615 :
616 0 : if(INetURLObject::CompareProtocolScheme(rTxt.Copy(nSttWdPos + (bWasWordDelim ? 1 : 0), nEndPos - nSttWdPos + 1)) != INET_PROT_NOT_VALID) {
617 0 : return sal_False;
618 : }
619 :
620 :
621 : // Check the presence of "://" in the word
622 0 : xub_StrLen nStrPos = rTxt.Search( rtl::OUString( "://" ), nSttWdPos + 1 );
623 0 : if ( STRING_NOTFOUND == nStrPos && nEndPos > 0 )
624 : {
625 : // Check the previous char
626 0 : sal_Unicode cPrevChar = rTxt.GetChar( nEndPos - 1 );
627 0 : if ( ( chars.indexOf( cPrevChar ) == -1 ) && cPrevChar != '\t' )
628 : {
629 : // Remove any previous normal space
630 0 : xub_StrLen nPos = nEndPos - 1;
631 0 : while ( cPrevChar == ' ' || cPrevChar == CHAR_HARDBLANK )
632 : {
633 0 : if ( nPos == 0 ) break;
634 0 : nPos--;
635 0 : cPrevChar = rTxt.GetChar( nPos );
636 : }
637 :
638 0 : nPos++;
639 0 : if ( nEndPos - nPos > 0 )
640 0 : rDoc.Delete( nPos, nEndPos );
641 :
642 : // Add the non-breaking space at the end pos
643 0 : if ( bHasSpace )
644 0 : rDoc.Insert( nPos, rtl::OUString(CHAR_HARDBLANK) );
645 0 : bRunNext = true;
646 0 : bRet = true;
647 : }
648 0 : else if ( chars.indexOf( cPrevChar ) != -1 )
649 0 : bRunNext = true;
650 : }
651 : }
652 0 : else if ( cChar == '/' && nEndPos > 1 && rTxt.Len() > (nEndPos - 1) )
653 : {
654 : // Remove the hardspace right before to avoid formatting URLs
655 0 : sal_Unicode cPrevChar = rTxt.GetChar( nEndPos - 1 );
656 0 : sal_Unicode cMaybeSpaceChar = rTxt.GetChar( nEndPos - 2 );
657 0 : if ( cPrevChar == ':' && cMaybeSpaceChar == CHAR_HARDBLANK )
658 : {
659 0 : rDoc.Delete( nEndPos - 2, nEndPos - 1 );
660 0 : bRet = true;
661 : }
662 0 : }
663 : }
664 :
665 0 : return bRet;
666 : }
667 :
668 : #ifdef _MSC_VER
669 : #pragma warning(pop)
670 : #endif
671 :
672 0 : sal_Bool SvxAutoCorrect::FnSetINetAttr( SvxAutoCorrDoc& rDoc, const String& rTxt,
673 : xub_StrLen nSttPos, xub_StrLen nEndPos,
674 : LanguageType eLang )
675 : {
676 0 : sal_Int32 nStart(nSttPos);
677 0 : sal_Int32 nEnd(nEndPos);
678 :
679 : String sURL( URIHelper::FindFirstURLInText( rTxt, nStart, nEnd,
680 0 : GetCharClass( eLang ) ));
681 0 : nSttPos = (xub_StrLen)nStart;
682 0 : nEndPos = (xub_StrLen)nEnd;
683 0 : sal_Bool bRet = 0 != sURL.Len();
684 0 : if( bRet ) // also Attribut setzen:
685 0 : rDoc.SetINetAttr( nSttPos, nEndPos, sURL );
686 0 : return bRet;
687 : }
688 :
689 :
690 0 : sal_Bool SvxAutoCorrect::FnChgWeightUnderl( SvxAutoCorrDoc& rDoc, const String& rTxt,
691 : xub_StrLen, xub_StrLen nEndPos,
692 : LanguageType eLang )
693 : {
694 : // Condition:
695 : // at the beginning: _ or * after Space with the folloeing !Space
696 : // at the end: _ or * before Space (word delimiter?)
697 :
698 0 : sal_Unicode c, cInsChar = rTxt.GetChar( nEndPos ); // underline or bold
699 0 : if( ++nEndPos != rTxt.Len() &&
700 0 : !IsWordDelim( rTxt.GetChar( nEndPos ) ) )
701 0 : return sal_False;
702 :
703 0 : --nEndPos;
704 :
705 0 : sal_Bool bAlphaNum = sal_False;
706 0 : xub_StrLen nPos = nEndPos, nFndPos = STRING_NOTFOUND;
707 0 : CharClass& rCC = GetCharClass( eLang );
708 :
709 0 : while( nPos )
710 : {
711 0 : switch( c = rTxt.GetChar( --nPos ) )
712 : {
713 : case '_':
714 : case '*':
715 0 : if( c == cInsChar )
716 : {
717 0 : if( bAlphaNum && nPos+1 < nEndPos && ( !nPos ||
718 0 : IsWordDelim( rTxt.GetChar( nPos-1 ))) &&
719 0 : !IsWordDelim( rTxt.GetChar( nPos+1 )))
720 0 : nFndPos = nPos;
721 : else
722 : // Condition is not satisfied, so cancel
723 0 : nFndPos = STRING_NOTFOUND;
724 0 : nPos = 0;
725 : }
726 0 : break;
727 : default:
728 0 : if( !bAlphaNum )
729 0 : bAlphaNum = rCC.isLetterNumeric( rTxt, nPos );
730 : }
731 : }
732 :
733 0 : if( STRING_NOTFOUND != nFndPos )
734 : {
735 : // Span the Attribute over the area and delete the Character found at
736 : // the end.
737 0 : if( '*' == cInsChar ) // Bold
738 : {
739 0 : SvxWeightItem aSvxWeightItem( WEIGHT_BOLD, SID_ATTR_CHAR_WEIGHT );
740 : rDoc.SetAttr( nFndPos + 1, nEndPos,
741 : SID_ATTR_CHAR_WEIGHT,
742 0 : aSvxWeightItem);
743 : }
744 : else // underline
745 : {
746 0 : SvxUnderlineItem aSvxUnderlineItem( UNDERLINE_SINGLE, SID_ATTR_CHAR_UNDERLINE );
747 : rDoc.SetAttr( nFndPos + 1, nEndPos,
748 : SID_ATTR_CHAR_UNDERLINE,
749 0 : aSvxUnderlineItem);
750 : }
751 0 : rDoc.Delete( nEndPos, nEndPos + 1 );
752 0 : rDoc.Delete( nFndPos, nFndPos + 1 );
753 : }
754 :
755 0 : return STRING_NOTFOUND != nFndPos;
756 : }
757 :
758 :
759 0 : sal_Bool SvxAutoCorrect::FnCptlSttSntnc( SvxAutoCorrDoc& rDoc,
760 : const String& rTxt, sal_Bool bNormalPos,
761 : xub_StrLen nSttPos, xub_StrLen nEndPos,
762 : LanguageType eLang )
763 : {
764 :
765 0 : if( !rTxt.Len() || nEndPos <= nSttPos )
766 0 : return sal_False;
767 :
768 0 : CharClass& rCC = GetCharClass( eLang );
769 0 : String aText( rTxt );
770 0 : const sal_Unicode *pStart = aText.GetBuffer(),
771 0 : *pStr = pStart + nEndPos,
772 0 : *pWordStt = 0,
773 0 : *pDelim = 0;
774 :
775 0 : sal_Bool bAtStart = sal_False;
776 0 : do {
777 0 : --pStr;
778 0 : if( rCC.isLetter(
779 0 : aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
780 : {
781 0 : if( !pWordStt )
782 0 : pDelim = pStr+1;
783 0 : pWordStt = pStr;
784 : }
785 0 : else if( pWordStt &&
786 : !rCC.isDigit(
787 : aText,
788 0 : sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
789 : {
790 0 : if( lcl_IsInAsciiArr( sImplWordChars, *pStr ) &&
791 0 : pWordStt - 1 == pStr &&
792 : // Installation at beginning of paragraph. Replaced < by <= (#i38971#)
793 0 : (long)(pStart + 1) <= (long)pStr &&
794 : rCC.isLetter(
795 : aText,
796 0 : sal::static_int_cast< xub_StrLen >( pStr-1 - pStart ) ) )
797 0 : pWordStt = --pStr;
798 : else
799 0 : break;
800 : }
801 : } while( 0 == ( bAtStart = (pStart == pStr)) );
802 :
803 0 : if( !pWordStt ||
804 : rCC.isDigit(
805 0 : aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) ||
806 : IsUpperLetter(
807 : rCC.getCharacterType(
808 : aText,
809 0 : sal::static_int_cast< xub_StrLen >( pWordStt - pStart ) ) ) ||
810 0 : INetURLObject::CompareProtocolScheme(rTxt.Copy(pWordStt - pStart, pDelim - pWordStt + 1)) != INET_PROT_NOT_VALID ||
811 : 0x1 == *pWordStt || 0x2 == *pWordStt )
812 0 : return sal_False; // no character to be replaced, or already ok
813 :
814 0 : if( *pDelim && 2 >= pDelim - pWordStt &&
815 0 : lcl_IsInAsciiArr( ".-)>", *pDelim ) )
816 0 : return sal_False;
817 :
818 0 : if( !bAtStart ) // Still no beginning of a paragraph?
819 : {
820 0 : if ( IsWordDelim( *pStr ) )
821 : {
822 0 : while( 0 == ( bAtStart = (pStart == pStr--) ) && IsWordDelim( *pStr ))
823 : ;
824 : }
825 : // Asian full stop, full width full stop, full width exclamation mark
826 : // and full width question marks are treated as word delimiters
827 0 : else if ( 0x3002 != *pStr && 0xFF0E != *pStr && 0xFF01 != *pStr &&
828 : 0xFF1F != *pStr )
829 0 : return sal_False; // no valid separator -> no replacement
830 : }
831 :
832 0 : if( bAtStart ) // at the beginning of a paragraph?
833 : {
834 : // Check out the previous paragraph, if it exists.
835 : // If so, then check to paragraph separator at the end.
836 0 : const String* pPrevPara = rDoc.GetPrevPara( bNormalPos );
837 0 : if( !pPrevPara )
838 : {
839 : // valid separator -> replace
840 0 : rtl::OUString sChar( *pWordStt );
841 0 : sChar = rCC.titlecase(sChar); //see fdo#56740
842 0 : return !comphelper::string::equals(sChar, *pWordStt) &&
843 0 : rDoc.ReplaceRange( xub_StrLen( pWordStt - pStart ), 1, sChar );
844 : }
845 :
846 0 : aText = *pPrevPara;
847 0 : bAtStart = sal_False;
848 0 : pStart = aText.GetBuffer();
849 0 : pStr = pStart + aText.Len();
850 :
851 0 : do { // overwrite all blanks
852 0 : --pStr;
853 0 : if( !IsWordDelim( *pStr ))
854 0 : break;
855 : } while( 0 == ( bAtStart = (pStart == pStr)) );
856 :
857 0 : if( bAtStart )
858 0 : return sal_False; // no valid separator -> no replacement
859 : }
860 :
861 : // Found [ \t]+[A-Z0-9]+ until here. Test now on the paragraph separator.
862 : // all three can happen, but not more than once!
863 0 : const sal_Unicode* pExceptStt = 0;
864 0 : if( !bAtStart )
865 : {
866 0 : sal_Bool bWeiter = sal_True;
867 0 : int nFlag = C_NONE;
868 0 : do {
869 0 : switch( *pStr )
870 : {
871 : // Western and Asian full stop
872 : case '.':
873 : case 0x3002 :
874 : case 0xFF0E :
875 : {
876 0 : if( nFlag & C_FULL_STOP )
877 0 : return sal_False; // no valid separator -> no replacement
878 0 : nFlag |= C_FULL_STOP;
879 0 : pExceptStt = pStr;
880 : }
881 0 : break;
882 : case '!':
883 : case 0xFF01 :
884 : {
885 0 : if( nFlag & C_EXCLAMATION_MARK )
886 0 : return sal_False; // no valid separator -> no replacement
887 0 : nFlag |= C_EXCLAMATION_MARK;
888 : }
889 0 : break;
890 : case '?':
891 : case 0xFF1F :
892 : {
893 0 : if( nFlag & C_QUESTION_MARK)
894 0 : return sal_False; // no valid separator -> no replacement
895 0 : nFlag |= C_QUESTION_MARK;
896 : }
897 0 : break;
898 : default:
899 0 : if( !nFlag )
900 0 : return sal_False; // no valid separator -> no replacement
901 : else
902 0 : bWeiter = sal_False;
903 0 : break;
904 : }
905 :
906 0 : if( bWeiter && pStr-- == pStart )
907 : {
908 0 : return sal_False; // no valid separator -> no replacement
909 : }
910 : } while( bWeiter );
911 0 : if( C_FULL_STOP != nFlag )
912 0 : pExceptStt = 0;
913 : }
914 :
915 0 : if( 2 > ( pStr - pStart ) )
916 0 : return sal_False;
917 :
918 0 : if( !rCC.isLetterNumeric(
919 0 : aText, sal::static_int_cast< xub_StrLen >( pStr-- - pStart ) ) )
920 : {
921 0 : sal_Bool bValid = sal_False, bAlphaFnd = sal_False;
922 0 : const sal_Unicode* pTmpStr = pStr;
923 0 : while( !bValid )
924 : {
925 0 : if( rCC.isDigit(
926 : aText,
927 0 : sal::static_int_cast< xub_StrLen >( pTmpStr - pStart ) ) )
928 : {
929 0 : bValid = sal_True;
930 0 : pStr = pTmpStr - 1;
931 : }
932 0 : else if( rCC.isLetter(
933 : aText,
934 : sal::static_int_cast< xub_StrLen >(
935 0 : pTmpStr - pStart ) ) )
936 : {
937 0 : if( bAlphaFnd )
938 : {
939 0 : bValid = sal_True;
940 0 : pStr = pTmpStr;
941 : }
942 : else
943 0 : bAlphaFnd = sal_True;
944 : }
945 0 : else if( bAlphaFnd || IsWordDelim( *pTmpStr ) )
946 0 : break;
947 :
948 0 : if( pTmpStr == pStart )
949 0 : break;
950 :
951 0 : --pTmpStr;
952 : }
953 :
954 0 : if( !bValid )
955 0 : return sal_False; // no valid separator -> no replacement
956 : }
957 :
958 0 : sal_Bool bNumericOnly = '0' <= *(pStr+1) && *(pStr+1) <= '9';
959 :
960 : // Search for the beginning of the word
961 0 : while( !IsWordDelim( *pStr ))
962 : {
963 0 : if( bNumericOnly &&
964 : rCC.isLetter(
965 0 : aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
966 0 : bNumericOnly = sal_False;
967 :
968 0 : if( pStart == pStr )
969 0 : break;
970 :
971 0 : --pStr;
972 : }
973 :
974 0 : if( bNumericOnly ) // consists of only numbers, then not
975 0 : return sal_False;
976 :
977 0 : if( IsWordDelim( *pStr ))
978 0 : ++pStr;
979 :
980 0 : String sWord;
981 :
982 : // check on the basis of the exception list
983 0 : if( pExceptStt )
984 : {
985 0 : sWord = rtl::OUString(pStr, pExceptStt - pStr + 1);
986 0 : if( FindInCplSttExceptList(eLang, sWord) )
987 0 : return sal_False;
988 :
989 : // Delete all non alphanumeric. Test the characters at the
990 : // beginning/end of the word ( recognizes: "(min.", "/min.", and so on.)
991 0 : String sTmp( sWord );
992 0 : while( sTmp.Len() &&
993 0 : !rCC.isLetterNumeric( sTmp, 0 ) )
994 0 : sTmp.Erase( 0, 1 );
995 :
996 : // Remove all non alphanumeric characters towards the end up until
997 : // the last one.
998 0 : xub_StrLen nLen = sTmp.Len();
999 0 : while( nLen && !rCC.isLetterNumeric( sTmp, nLen-1 ) )
1000 0 : --nLen;
1001 0 : if( nLen + 1 < sTmp.Len() )
1002 0 : sTmp.Erase( nLen + 1 );
1003 :
1004 0 : if( sTmp.Len() && sTmp.Len() != sWord.Len() &&
1005 0 : FindInCplSttExceptList(eLang, sTmp))
1006 0 : return sal_False;
1007 :
1008 0 : if(FindInCplSttExceptList(eLang, sWord, sal_True))
1009 0 : return sal_False;
1010 : }
1011 :
1012 : // Ok, then replace
1013 0 : sal_Unicode cSave = *pWordStt;
1014 0 : nSttPos = sal::static_int_cast< xub_StrLen >( pWordStt - rTxt.GetBuffer() );
1015 0 : rtl::OUString sChar( cSave );
1016 0 : sChar = rCC.titlecase(sChar); //see fdo#56740
1017 0 : sal_Bool bRet = sChar[0] != cSave && rDoc.ReplaceRange( nSttPos, 1, sChar );
1018 :
1019 : // Parahaps someone wants to have the word
1020 0 : if( bRet && SaveWordCplSttLst & nFlags )
1021 0 : rDoc.SaveCpltSttWord( CptlSttSntnc, nSttPos, sWord, cSave );
1022 :
1023 0 : return bRet;
1024 : }
1025 :
1026 0 : bool SvxAutoCorrect::FnCorrectCapsLock( SvxAutoCorrDoc& rDoc, const String& rTxt,
1027 : xub_StrLen nSttPos, xub_StrLen nEndPos,
1028 : LanguageType eLang )
1029 : {
1030 0 : if (nEndPos - nSttPos < 2)
1031 : // string must be at least 2-character long.
1032 0 : return false;
1033 :
1034 0 : CharClass& rCC = GetCharClass( eLang );
1035 :
1036 : // Check the first 2 letters.
1037 0 : if ( !IsLowerLetter(rCC.getCharacterType(rTxt, nSttPos)) )
1038 0 : return false;
1039 :
1040 0 : if ( !IsUpperLetter(rCC.getCharacterType(rTxt, nSttPos+1)) )
1041 0 : return false;
1042 :
1043 0 : String aConverted;
1044 0 : aConverted.Append( rCC.uppercase(rtl::OUString(rTxt.GetChar(nSttPos))) );
1045 0 : aConverted.Append( rCC.lowercase(rtl::OUString(rTxt.GetChar(nSttPos+1))) );
1046 :
1047 0 : for (xub_StrLen i = nSttPos+2; i < nEndPos; ++i)
1048 : {
1049 0 : if ( IsLowerLetter(rCC.getCharacterType(rTxt, i)) )
1050 : // A lowercase letter disqualifies the whole text.
1051 0 : return false;
1052 :
1053 0 : if ( IsUpperLetter(rCC.getCharacterType(rTxt, i)) )
1054 : // Another uppercase letter. Convert it.
1055 0 : aConverted.Append(rCC.lowercase(rtl::OUString(rTxt.GetChar(i))));
1056 : else
1057 : // This is not an alphabetic letter. Leave it as-is.
1058 0 : aConverted.Append(rTxt.GetChar(i));
1059 : }
1060 :
1061 : // Replace the word.
1062 0 : rDoc.Delete(nSttPos, nEndPos);
1063 0 : rDoc.Insert(nSttPos, aConverted);
1064 :
1065 0 : return true;
1066 : }
1067 :
1068 :
1069 0 : sal_Unicode SvxAutoCorrect::GetQuote( sal_Unicode cInsChar, sal_Bool bSttQuote,
1070 : LanguageType eLang ) const
1071 : {
1072 : sal_Unicode cRet = bSttQuote ? ( '\"' == cInsChar
1073 : ? GetStartDoubleQuote()
1074 : : GetStartSingleQuote() )
1075 : : ( '\"' == cInsChar
1076 : ? GetEndDoubleQuote()
1077 0 : : GetEndSingleQuote() );
1078 0 : if( !cRet )
1079 : {
1080 : // then through the Language find the right character
1081 0 : if( LANGUAGE_NONE == eLang )
1082 0 : cRet = cInsChar;
1083 : else
1084 : {
1085 0 : LocaleDataWrapper& rLcl = GetLocaleDataWrapper( eLang );
1086 : String sRet( bSttQuote
1087 : ? ( '\"' == cInsChar
1088 : ? rLcl.getDoubleQuotationMarkStart()
1089 : : rLcl.getQuotationMarkStart() )
1090 : : ( '\"' == cInsChar
1091 : ? rLcl.getDoubleQuotationMarkEnd()
1092 0 : : rLcl.getQuotationMarkEnd() ));
1093 0 : cRet = sRet.Len() ? sRet.GetChar( 0 ) : cInsChar;
1094 : }
1095 : }
1096 0 : return cRet;
1097 : }
1098 :
1099 0 : void SvxAutoCorrect::InsertQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos,
1100 : sal_Unicode cInsChar, sal_Bool bSttQuote,
1101 : sal_Bool bIns )
1102 : {
1103 0 : LanguageType eLang = rDoc.GetLanguage( nInsPos, sal_False );
1104 0 : sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang );
1105 :
1106 0 : rtl::OUString sChg( cInsChar );
1107 0 : if( bIns )
1108 0 : rDoc.Insert( nInsPos, sChg );
1109 : else
1110 0 : rDoc.Replace( nInsPos, sChg );
1111 :
1112 0 : sChg = rtl::OUString(cRet);
1113 :
1114 0 : if( '\"' == cInsChar )
1115 : {
1116 0 : if( LANGUAGE_SYSTEM == eLang )
1117 0 : eLang = GetAppLang().getLanguageType();
1118 0 : switch( eLang )
1119 : {
1120 : case LANGUAGE_FRENCH:
1121 : case LANGUAGE_FRENCH_BELGIAN:
1122 : case LANGUAGE_FRENCH_CANADIAN:
1123 : case LANGUAGE_FRENCH_SWISS:
1124 : case LANGUAGE_FRENCH_LUXEMBOURG:
1125 : {
1126 0 : rtl::OUString s( static_cast< sal_Unicode >(0xA0) );
1127 : // UNICODE code for no break space
1128 0 : if( rDoc.Insert( bSttQuote ? nInsPos+1 : nInsPos, s ))
1129 : {
1130 0 : if( !bSttQuote )
1131 0 : ++nInsPos;
1132 0 : }
1133 : }
1134 0 : break;
1135 : }
1136 : }
1137 :
1138 0 : rDoc.Replace( nInsPos, sChg );
1139 0 : }
1140 :
1141 0 : String SvxAutoCorrect::GetQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos,
1142 : sal_Unicode cInsChar, sal_Bool bSttQuote )
1143 : {
1144 0 : LanguageType eLang = rDoc.GetLanguage( nInsPos, sal_False );
1145 0 : sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang );
1146 :
1147 0 : String sRet = rtl::OUString(cRet);
1148 :
1149 0 : if( '\"' == cInsChar )
1150 : {
1151 0 : if( LANGUAGE_SYSTEM == eLang )
1152 0 : eLang = GetAppLang().getLanguageType();
1153 0 : switch( eLang )
1154 : {
1155 : case LANGUAGE_FRENCH:
1156 : case LANGUAGE_FRENCH_BELGIAN:
1157 : case LANGUAGE_FRENCH_CANADIAN:
1158 : case LANGUAGE_FRENCH_SWISS:
1159 : case LANGUAGE_FRENCH_LUXEMBOURG:
1160 0 : if( bSttQuote )
1161 0 : sRet += ' ';
1162 : else
1163 0 : sRet.Insert( ' ', 0 );
1164 0 : break;
1165 : }
1166 : }
1167 0 : return sRet;
1168 : }
1169 :
1170 0 : sal_uLong SvxAutoCorrect::AutoCorrect( SvxAutoCorrDoc& rDoc, const String& rTxt,
1171 : xub_StrLen nInsPos, sal_Unicode cChar,
1172 : sal_Bool bInsert, Window* pFrameWin )
1173 : {
1174 0 : sal_uLong nRet = 0;
1175 0 : bool bIsNextRun = bRunNext;
1176 0 : bRunNext = false; // if it was set, then it has to be turned off
1177 :
1178 : do{ // only for middle check loop !!
1179 0 : if( cChar )
1180 : {
1181 : // Prevent double space
1182 0 : if( nInsPos && ' ' == cChar &&
1183 0 : IsAutoCorrFlag( IgnoreDoubleSpace ) &&
1184 0 : ' ' == rTxt.GetChar( nInsPos - 1 ) )
1185 : {
1186 0 : nRet = IgnoreDoubleSpace;
1187 : break;
1188 : }
1189 :
1190 0 : sal_Bool bSingle = '\'' == cChar;
1191 : sal_Bool bIsReplaceQuote =
1192 0 : (IsAutoCorrFlag( ChgQuotes ) && ('\"' == cChar )) ||
1193 0 : (IsAutoCorrFlag( ChgSglQuotes ) && bSingle );
1194 0 : if( bIsReplaceQuote )
1195 : {
1196 : sal_Unicode cPrev;
1197 : sal_Bool bSttQuote = !nInsPos ||
1198 0 : IsWordDelim( ( cPrev = rTxt.GetChar( nInsPos-1 ))) ||
1199 0 : lcl_IsInAsciiArr( "([{", cPrev ) ||
1200 : ( cEmDash && cEmDash == cPrev ) ||
1201 0 : ( cEnDash && cEnDash == cPrev );
1202 :
1203 0 : InsertQuote( rDoc, nInsPos, cChar, bSttQuote, bInsert );
1204 0 : nRet = bSingle ? ChgSglQuotes : ChgQuotes;
1205 : break;
1206 : }
1207 :
1208 0 : if( bInsert )
1209 0 : rDoc.Insert( nInsPos, rtl::OUString(cChar) );
1210 : else
1211 0 : rDoc.Replace( nInsPos, rtl::OUString(cChar) );
1212 :
1213 : // Hardspaces autocorrection
1214 0 : if ( IsAutoCorrFlag( AddNonBrkSpace ) )
1215 : {
1216 0 : if ( NeedsHardspaceAutocorr( cChar ) &&
1217 0 : FnAddNonBrkSpace( rDoc, rTxt, 0, nInsPos, rDoc.GetLanguage( nInsPos, sal_False ) ) )
1218 : {
1219 0 : nRet = AddNonBrkSpace;
1220 : }
1221 0 : else if ( bIsNextRun && !IsAutoCorrectChar( cChar ) )
1222 : {
1223 : // Remove the NBSP if it wasn't an autocorrection
1224 0 : if ( nInsPos != 0 && NeedsHardspaceAutocorr( rTxt.GetChar( nInsPos - 1 ) ) &&
1225 : cChar != ' ' && cChar != '\t' && cChar != CHAR_HARDBLANK )
1226 : {
1227 : // Look for the last HARD_SPACE
1228 0 : xub_StrLen nPos = nInsPos - 1;
1229 0 : bool bContinue = true;
1230 0 : while ( bContinue )
1231 : {
1232 0 : const sal_Unicode cTmpChar = rTxt.GetChar( nPos );
1233 0 : if ( cTmpChar == CHAR_HARDBLANK )
1234 : {
1235 0 : rDoc.Delete( nPos, nPos + 1 );
1236 0 : nRet = AddNonBrkSpace;
1237 0 : bContinue = false;
1238 : }
1239 0 : else if ( !NeedsHardspaceAutocorr( cTmpChar ) || nPos == 0 )
1240 0 : bContinue = false;
1241 0 : nPos--;
1242 : }
1243 : }
1244 : }
1245 : }
1246 : }
1247 :
1248 0 : if( !nInsPos )
1249 : break;
1250 :
1251 0 : xub_StrLen nPos = nInsPos - 1;
1252 :
1253 0 : if( IsWordDelim( rTxt.GetChar( nPos )))
1254 : break;
1255 :
1256 : // Set bold or underline automatically?
1257 0 : if( '*' == cChar || '_' == cChar )
1258 : {
1259 0 : if( IsAutoCorrFlag( ChgWeightUnderl ) &&
1260 0 : FnChgWeightUnderl( rDoc, rTxt, 0, nPos+1 ) )
1261 0 : nRet = ChgWeightUnderl;
1262 : break;
1263 : }
1264 :
1265 0 : while( nPos && !IsWordDelim( rTxt.GetChar( --nPos )))
1266 : ;
1267 :
1268 : // Found a Paragraph-start or a Blank, search for the word shortcut in
1269 : // auto.
1270 0 : xub_StrLen nCapLttrPos = nPos+1; // on the 1st Character
1271 0 : if( !nPos && !IsWordDelim( rTxt.GetChar( 0 )))
1272 0 : --nCapLttrPos; // Absatz Anfang und kein Blank !
1273 :
1274 0 : LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, sal_False );
1275 0 : if( LANGUAGE_SYSTEM == eLang )
1276 0 : eLang = MsLangId::getSystemLanguage();
1277 0 : CharClass& rCC = GetCharClass( eLang );
1278 :
1279 : // no symbol characters
1280 0 : if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nInsPos ))
1281 : break;
1282 :
1283 0 : if( IsAutoCorrFlag( Autocorrect ) )
1284 : {
1285 0 : const String* pPara = 0;
1286 0 : const String** ppPara = IsAutoCorrFlag(CptlSttSntnc) ? &pPara : 0;
1287 :
1288 : sal_Bool bChgWord = rDoc.ChgAutoCorrWord( nCapLttrPos, nInsPos,
1289 0 : *this, ppPara );
1290 0 : if( !bChgWord )
1291 : {
1292 0 : xub_StrLen nCapLttrPos1 = nCapLttrPos, nInsPos1 = nInsPos;
1293 0 : while( nCapLttrPos1 < nInsPos &&
1294 0 : lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos1 ) )
1295 : )
1296 0 : ++nCapLttrPos1;
1297 0 : while( nCapLttrPos1 < nInsPos1 && nInsPos1 &&
1298 0 : lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nInsPos1-1 ) )
1299 : )
1300 0 : --nInsPos1;
1301 :
1302 0 : if( (nCapLttrPos1 != nCapLttrPos || nInsPos1 != nInsPos ) &&
1303 : nCapLttrPos1 < nInsPos1 &&
1304 0 : rDoc.ChgAutoCorrWord( nCapLttrPos1, nInsPos1, *this, ppPara ))
1305 : {
1306 0 : bChgWord = sal_True;
1307 0 : nCapLttrPos = nCapLttrPos1;
1308 : }
1309 : }
1310 :
1311 0 : if( bChgWord )
1312 : {
1313 0 : nRet = Autocorrect;
1314 0 : if( pPara )
1315 : {
1316 0 : xub_StrLen nEnd = nCapLttrPos;
1317 0 : while( nEnd < pPara->Len() &&
1318 0 : !IsWordDelim( pPara->GetChar( nEnd )))
1319 0 : ++nEnd;
1320 :
1321 : // Capital letter at beginning of paragraph?
1322 0 : if( IsAutoCorrFlag( CptlSttSntnc ) &&
1323 : FnCptlSttSntnc( rDoc, *pPara, sal_False,
1324 0 : nCapLttrPos, nEnd, eLang ) )
1325 0 : nRet |= CptlSttSntnc;
1326 :
1327 0 : if( IsAutoCorrFlag( ChgToEnEmDash ) &&
1328 0 : FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nEnd, eLang ) )
1329 0 : nRet |= ChgToEnEmDash;
1330 : }
1331 : break;
1332 : }
1333 : }
1334 :
1335 0 : if( ( IsAutoCorrFlag( nRet = ChgOrdinalNumber ) &&
1336 0 : FnChgOrdinalNumber( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) ||
1337 0 : ( IsAutoCorrFlag( nRet = SetINetAttr ) &&
1338 : ( ' ' == cChar || '\t' == cChar || 0x0a == cChar || !cChar ) &&
1339 0 : FnSetINetAttr( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) )
1340 : ;
1341 : else
1342 : {
1343 0 : bool bLockKeyOn = pFrameWin && (pFrameWin->GetIndicatorState() & INDICATOR_CAPSLOCK);
1344 0 : bool bUnsupported = lcl_IsUnsupportedUnicodeChar( rCC, rTxt, nCapLttrPos, nInsPos );
1345 :
1346 0 : nRet = 0;
1347 0 : if ( bLockKeyOn && IsAutoCorrFlag( CorrectCapsLock ) &&
1348 0 : FnCorrectCapsLock( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1349 : {
1350 : // Correct accidental use of cAPS LOCK key (do this only when
1351 : // the caps or shift lock key is pressed). Turn off the caps
1352 : // lock afterwords.
1353 0 : nRet |= CorrectCapsLock;
1354 0 : pFrameWin->SimulateKeyPress( KEY_CAPSLOCK );
1355 : }
1356 :
1357 : // Capital letter at beginning of paragraph ?
1358 0 : if( !bUnsupported &&
1359 0 : IsAutoCorrFlag( CptlSttSntnc ) &&
1360 0 : FnCptlSttSntnc( rDoc, rTxt, sal_True, nCapLttrPos, nInsPos, eLang ) )
1361 0 : nRet |= CptlSttSntnc;
1362 :
1363 : // Two capital letters at beginning of word ??
1364 0 : if( !bUnsupported &&
1365 0 : IsAutoCorrFlag( CptlSttWrd ) &&
1366 0 : FnCptlSttWrd( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1367 0 : nRet |= CptlSttWrd;
1368 :
1369 0 : if( IsAutoCorrFlag( ChgToEnEmDash ) &&
1370 0 : FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1371 0 : nRet |= ChgToEnEmDash;
1372 : }
1373 :
1374 : } while( sal_False );
1375 :
1376 0 : if( nRet )
1377 : {
1378 : const char* aHelpIds[] =
1379 : {
1380 : HID_AUTOCORR_HELP_WORD,
1381 : HID_AUTOCORR_HELP_SENT,
1382 : HID_AUTOCORR_HELP_SENTWORD,
1383 : HID_AUTOCORR_HELP_ACORWORD,
1384 : "",
1385 : HID_AUTOCORR_HELP_ACORSENTWORD,
1386 : "",
1387 : HID_AUTOCORR_HELP_CHGTOENEMDASH,
1388 : HID_AUTOCORR_HELP_WORDENEMDASH,
1389 : HID_AUTOCORR_HELP_SENTENEMDASH,
1390 : HID_AUTOCORR_HELP_SENTWORDENEMDASH,
1391 : HID_AUTOCORR_HELP_ACORWORDENEMDASH,
1392 : "",
1393 : HID_AUTOCORR_HELP_ACORSENTWORDENEMDASH,
1394 : "",
1395 : HID_AUTOCORR_HELP_CHGQUOTES,
1396 : HID_AUTOCORR_HELP_CHGSGLQUOTES,
1397 : HID_AUTOCORR_HELP_SETINETATTR,
1398 : HID_AUTOCORR_HELP_INGNOREDOUBLESPACE,
1399 : HID_AUTOCORR_HELP_CHGWEIGHTUNDERL,
1400 : HID_AUTOCORR_HELP_CHGFRACTIONSYMBOL,
1401 : HID_AUTOCORR_HELP_CHGORDINALNUMBER
1402 0 : };
1403 :
1404 0 : sal_uLong nHelpId = 0;
1405 0 : if( nRet & ( Autocorrect|CptlSttSntnc|CptlSttWrd|ChgToEnEmDash ) )
1406 : {
1407 : // from 0 - 15
1408 0 : if( nRet & ChgToEnEmDash )
1409 0 : nHelpId += 8;
1410 0 : if( nRet & Autocorrect )
1411 0 : nHelpId += 4;
1412 0 : if( nRet & CptlSttSntnc )
1413 0 : nHelpId += 2;
1414 0 : if( nRet & CptlSttWrd )
1415 0 : nHelpId += 1;
1416 : }
1417 : else
1418 : {
1419 0 : if( nRet & ChgQuotes) nHelpId = 16;
1420 0 : else if( nRet & ChgSglQuotes) nHelpId = 17;
1421 0 : else if( nRet & SetINetAttr) nHelpId = 18;
1422 0 : else if( nRet & IgnoreDoubleSpace) nHelpId = 19;
1423 0 : else if( nRet & ChgWeightUnderl) nHelpId = 20;
1424 0 : else if( nRet & AddNonBrkSpace) nHelpId = 21;
1425 0 : else if( nRet & ChgOrdinalNumber) nHelpId = 22;
1426 : }
1427 :
1428 0 : if( nHelpId )
1429 : {
1430 0 : nHelpId -= 1;
1431 0 : Application::GetHelp()->OpenHelpAgent( aHelpIds[nHelpId] );
1432 : }
1433 : }
1434 :
1435 :
1436 0 : return nRet;
1437 : }
1438 :
1439 0 : SvxAutoCorrectLanguageLists& SvxAutoCorrect::_GetLanguageList(
1440 : LanguageType eLang )
1441 : {
1442 0 : if(pLangTable->find(eLang) == pLangTable->end())
1443 0 : CreateLanguageFile(eLang, sal_True);
1444 0 : return *(pLangTable->find(eLang)->second);
1445 : }
1446 :
1447 0 : void SvxAutoCorrect::SaveCplSttExceptList( LanguageType eLang )
1448 : {
1449 0 : boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1450 0 : if(nTmpVal != pLangTable->end() && nTmpVal->second)
1451 0 : nTmpVal->second->SaveCplSttExceptList();
1452 : #ifdef DBG_UTIL
1453 : else
1454 : {
1455 : OSL_FAIL("Save an empty list? ");
1456 : }
1457 : #endif
1458 0 : }
1459 :
1460 0 : void SvxAutoCorrect::SaveWrdSttExceptList(LanguageType eLang)
1461 : {
1462 0 : boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1463 0 : if(nTmpVal != pLangTable->end() && nTmpVal->second)
1464 0 : nTmpVal->second->SaveWrdSttExceptList();
1465 : #ifdef DBG_UTIL
1466 : else
1467 : {
1468 : OSL_FAIL("Save an empty list? ");
1469 : }
1470 : #endif
1471 0 : }
1472 :
1473 : // Adds a single word. The list will immediately be written to the file!
1474 0 : sal_Bool SvxAutoCorrect::AddCplSttException( const String& rNew,
1475 : LanguageType eLang )
1476 : {
1477 0 : SvxAutoCorrectLanguageLists* pLists = 0;
1478 : // either the right language is present or it will be this in the general list
1479 0 : boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1480 0 : if(nTmpVal != pLangTable->end())
1481 0 : pLists = nTmpVal->second;
1482 : else
1483 : {
1484 0 : nTmpVal = pLangTable->find(LANGUAGE_UNDETERMINED);
1485 0 : if(nTmpVal != pLangTable->end())
1486 0 : pLists = nTmpVal->second;
1487 0 : else if(CreateLanguageFile(LANGUAGE_UNDETERMINED, sal_True))
1488 0 : pLists = pLangTable->find(LANGUAGE_UNDETERMINED)->second;
1489 : }
1490 : OSL_ENSURE(pLists, "No auto correction data");
1491 0 : return pLists->AddToCplSttExceptList(rNew);
1492 : }
1493 :
1494 : // Adds a single word. The list will immediately be written to the file!
1495 0 : sal_Bool SvxAutoCorrect::AddWrtSttException( const String& rNew,
1496 : LanguageType eLang )
1497 : {
1498 0 : SvxAutoCorrectLanguageLists* pLists = 0;
1499 : //either the right language is present or it is set in the general list
1500 0 : boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1501 0 : if(nTmpVal != pLangTable->end())
1502 0 : pLists = nTmpVal->second;
1503 : else
1504 : {
1505 0 : nTmpVal = pLangTable->find(LANGUAGE_UNDETERMINED);
1506 0 : if(nTmpVal != pLangTable->end())
1507 0 : pLists = nTmpVal->second;
1508 0 : else if(CreateLanguageFile(LANGUAGE_UNDETERMINED, sal_True))
1509 0 : pLists = pLangTable->find(LANGUAGE_UNDETERMINED)->second;
1510 : }
1511 : OSL_ENSURE(pLists, "No auto correction file!");
1512 0 : return pLists->AddToWrdSttExceptList(rNew);
1513 : }
1514 :
1515 0 : sal_Bool SvxAutoCorrect::GetPrevAutoCorrWord( SvxAutoCorrDoc& rDoc,
1516 : const String& rTxt, xub_StrLen nPos,
1517 : String& rWord ) const
1518 : {
1519 0 : if( !nPos )
1520 0 : return sal_False;
1521 :
1522 0 : xub_StrLen nEnde = nPos;
1523 :
1524 : // it must be followed by a blank or tab!
1525 0 : if( ( nPos < rTxt.Len() &&
1526 0 : !IsWordDelim( rTxt.GetChar( nPos ))) ||
1527 0 : IsWordDelim( rTxt.GetChar( --nPos )))
1528 0 : return sal_False;
1529 :
1530 0 : while( nPos && !IsWordDelim( rTxt.GetChar( --nPos )))
1531 : ;
1532 :
1533 : // Found a Paragraph-start or a Blank, search for the word shortcut in
1534 : // auto.
1535 0 : xub_StrLen nCapLttrPos = nPos+1; // on the 1st Character
1536 0 : if( !nPos && !IsWordDelim( rTxt.GetChar( 0 )))
1537 0 : --nCapLttrPos; // Beginning of pargraph and no Blank!
1538 :
1539 0 : while( lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos )) )
1540 0 : if( ++nCapLttrPos >= nEnde )
1541 0 : return sal_False;
1542 :
1543 0 : if( 3 > nEnde - nCapLttrPos )
1544 0 : return sal_False;
1545 :
1546 0 : LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, sal_False );
1547 0 : if( LANGUAGE_SYSTEM == eLang )
1548 0 : eLang = MsLangId::getSystemLanguage();
1549 :
1550 0 : SvxAutoCorrect* pThis = (SvxAutoCorrect*)this;
1551 0 : CharClass& rCC = pThis->GetCharClass( eLang );
1552 :
1553 0 : if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nEnde ))
1554 0 : return sal_False;
1555 :
1556 0 : rWord = rTxt.Copy( nCapLttrPos, nEnde - nCapLttrPos );
1557 0 : return sal_True;
1558 : }
1559 :
1560 0 : sal_Bool SvxAutoCorrect::CreateLanguageFile( LanguageType eLang, sal_Bool bNewFile )
1561 : {
1562 : OSL_ENSURE(pLangTable->find(eLang) == pLangTable->end(), "Language already exists ");
1563 :
1564 0 : String sUserDirFile( GetAutoCorrFileName( eLang, sal_True, sal_False ));
1565 0 : String sShareDirFile( sUserDirFile );
1566 :
1567 0 : SvxAutoCorrectLanguageListsPtr pLists = 0;
1568 :
1569 0 : Time nMinTime( 0, 2 ), nAktTime( Time::SYSTEM ), nLastCheckTime( Time::EMPTY );
1570 :
1571 0 : std::map<LanguageType, long>::iterator nFndPos = aLastFileTable.find(eLang);
1572 0 : if(nFndPos != aLastFileTable.end() &&
1573 0 : (nLastCheckTime.SetTime(nFndPos->second), nLastCheckTime < nAktTime) &&
1574 0 : nAktTime - nLastCheckTime < nMinTime)
1575 : {
1576 : // no need to test the file, because the last check is not older then
1577 : // 2 minutes.
1578 0 : if( bNewFile )
1579 : {
1580 0 : sShareDirFile = sUserDirFile;
1581 0 : pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile, sUserDirFile );
1582 0 : pLangTable->insert(eLang, pLists);
1583 0 : aLastFileTable.erase(nFndPos);
1584 : }
1585 : }
1586 0 : else if( ( FStatHelper::IsDocument( sUserDirFile ) ||
1587 : FStatHelper::IsDocument( sShareDirFile =
1588 0 : GetAutoCorrFileName( eLang, sal_False, sal_False ) ) ) ||
1589 : ( sShareDirFile = sUserDirFile, bNewFile ))
1590 : {
1591 0 : pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile, sUserDirFile );
1592 0 : pLangTable->insert(eLang, pLists);
1593 0 : if (nFndPos != aLastFileTable.end())
1594 0 : aLastFileTable.erase(nFndPos);
1595 : }
1596 0 : else if( !bNewFile )
1597 : {
1598 0 : aLastFileTable[eLang] = nAktTime.GetTime();
1599 : }
1600 0 : return pLists != 0;
1601 : }
1602 :
1603 0 : sal_Bool SvxAutoCorrect::PutText( const String& rShort, const String& rLong,
1604 : LanguageType eLang )
1605 : {
1606 0 : boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1607 0 : if(nTmpVal != pLangTable->end())
1608 0 : return nTmpVal->second->PutText(rShort, rLong);
1609 0 : if(CreateLanguageFile(eLang))
1610 0 : return pLangTable->find(eLang)->second->PutText(rShort, rLong);
1611 0 : return sal_False;
1612 : }
1613 :
1614 0 : sal_Bool SvxAutoCorrect::MakeCombinedChanges( std::vector<SvxAutocorrWord>& aNewEntries,
1615 : std::vector<SvxAutocorrWord>& aDeleteEntries,
1616 : LanguageType eLang )
1617 : {
1618 0 : boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1619 0 : if(nTmpVal != pLangTable->end())
1620 : {
1621 0 : return nTmpVal->second->MakeCombinedChanges( aNewEntries, aDeleteEntries );
1622 : }
1623 0 : else if(CreateLanguageFile( eLang ))
1624 : {
1625 0 : return pLangTable->find( eLang )->second->MakeCombinedChanges( aNewEntries, aDeleteEntries );
1626 : }
1627 0 : return sal_False;
1628 :
1629 : }
1630 :
1631 :
1632 : // - return the replacement text (only for SWG-Format, all other
1633 : // can be taken from the word list!)
1634 0 : sal_Bool SvxAutoCorrect::GetLongText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String& , String& )
1635 : {
1636 0 : return sal_False;
1637 : }
1638 :
1639 : // Text with attribution (only the SWG - SWG format!)
1640 0 : sal_Bool SvxAutoCorrect::PutText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String&, SfxObjectShell&,
1641 : String& )
1642 : {
1643 0 : return sal_False;
1644 : }
1645 :
1646 0 : void EncryptBlockName_Imp( String& rName )
1647 : {
1648 0 : xub_StrLen nLen, nPos = 1;
1649 0 : rName.Insert( '#', 0 );
1650 0 : sal_Unicode* pName = rName.GetBufferAccess();
1651 0 : for ( nLen = rName.Len(), ++pName; nPos < nLen; ++nPos, ++pName )
1652 : {
1653 0 : if( lcl_IsInAsciiArr( "!/:.\\", *pName ))
1654 0 : *pName &= 0x0f;
1655 : }
1656 0 : }
1657 :
1658 : /* This code is copied from SwXMLTextBlocks::GeneratePackageName */
1659 0 : static void GeneratePackageName ( const String& rShort, String& rPackageName )
1660 : {
1661 0 : rPackageName = rShort;
1662 0 : xub_StrLen nPos = 0;
1663 0 : sal_Unicode pDelims[] = { '!', '/', ':', '.', '\\', 0 };
1664 0 : rtl::OString sByte(rtl::OUStringToOString(rPackageName, RTL_TEXTENCODING_UTF7));
1665 0 : rPackageName = rtl::OStringToOUString(sByte, RTL_TEXTENCODING_ASCII_US);
1666 0 : while( STRING_NOTFOUND != ( nPos = rPackageName.SearchChar( pDelims, nPos )))
1667 : {
1668 0 : rPackageName.SetChar( nPos, '_' );
1669 0 : ++nPos;
1670 0 : }
1671 0 : }
1672 :
1673 0 : static const SvxAutocorrWord* lcl_SearchWordsInList(
1674 : SvxAutoCorrectLanguageListsPtr pList, const String& rTxt,
1675 : xub_StrLen& rStt, xub_StrLen nEndPos)
1676 : {
1677 0 : const SvxAutocorrWordList* pAutoCorrWordList = pList->GetAutocorrWordList();
1678 0 : return pAutoCorrWordList->SearchWordsInList( rTxt, rStt, nEndPos );
1679 : }
1680 :
1681 : // the search for the words in the substitution table
1682 0 : const SvxAutocorrWord* SvxAutoCorrect::SearchWordsInList(
1683 : const String& rTxt, xub_StrLen& rStt, xub_StrLen nEndPos,
1684 : SvxAutoCorrDoc&, LanguageType& rLang )
1685 : {
1686 0 : LanguageType eLang = rLang;
1687 0 : const SvxAutocorrWord* pRet = 0;
1688 0 : if( LANGUAGE_SYSTEM == eLang )
1689 0 : eLang = MsLangId::getSystemLanguage();
1690 :
1691 : // First search for eLang, then US-English -> English
1692 : // and last in LANGUAGE_UNDETERMINED
1693 0 : if(pLangTable->find(eLang) != pLangTable->end() || CreateLanguageFile(eLang, sal_False))
1694 : {
1695 : //the language is available - so bring it on
1696 0 : SvxAutoCorrectLanguageLists* pList = pLangTable->find(eLang)->second;
1697 0 : pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos );
1698 0 : if( pRet )
1699 : {
1700 0 : rLang = eLang;
1701 0 : return pRet;
1702 : }
1703 : }
1704 :
1705 : // If it still could not be found here, then keep on searching
1706 :
1707 0 : LanguageType nTmpKey1 = eLang & 0x7ff, // the main language in many cases DE
1708 0 : nTmpKey2 = eLang & 0x3ff; // otherwise for example EN
1709 0 : if(nTmpKey1 != eLang && (pLangTable->find(nTmpKey1) != pLangTable->end() || CreateLanguageFile(nTmpKey1, sal_False)))
1710 : {
1711 : //the language is available - so bring it on
1712 0 : SvxAutoCorrectLanguageLists* pList = pLangTable->find(nTmpKey1)->second;
1713 0 : pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos );
1714 0 : if( pRet )
1715 : {
1716 0 : rLang = nTmpKey1;
1717 0 : return pRet;
1718 : }
1719 : }
1720 :
1721 0 : if(nTmpKey2 != eLang && (pLangTable->find(nTmpKey2) != pLangTable->end() || CreateLanguageFile(nTmpKey2, sal_False)))
1722 : {
1723 : //the language is available - so bring it on
1724 0 : SvxAutoCorrectLanguageLists* pList = pLangTable->find(nTmpKey2)->second;
1725 0 : pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos );
1726 0 : if( pRet )
1727 : {
1728 0 : rLang = nTmpKey2;
1729 0 : return pRet;
1730 : }
1731 : }
1732 :
1733 0 : if(pLangTable->find(LANGUAGE_UNDETERMINED) != pLangTable->end() || CreateLanguageFile(LANGUAGE_UNDETERMINED, sal_False))
1734 : {
1735 : //the language is available - so bring it on
1736 0 : SvxAutoCorrectLanguageLists* pList = pLangTable->find(LANGUAGE_UNDETERMINED)->second;
1737 0 : pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos );
1738 0 : if( pRet )
1739 : {
1740 0 : rLang = LANGUAGE_UNDETERMINED;
1741 0 : return pRet;
1742 : }
1743 : }
1744 0 : return 0;
1745 : }
1746 :
1747 0 : sal_Bool SvxAutoCorrect::FindInWrdSttExceptList( LanguageType eLang,
1748 : const String& sWord )
1749 : {
1750 : // First search for eLang, then US-English -> English
1751 : // and last in LANGUAGE_UNDETERMINED
1752 0 : LanguageType nTmpKey1 = eLang & 0x7ff, // the main language in many cases DE
1753 0 : nTmpKey2 = eLang & 0x3ff; // otherwise for example EN
1754 0 : String sTemp(sWord);
1755 :
1756 0 : if(pLangTable->find(eLang) != pLangTable->end() || CreateLanguageFile(eLang, sal_False))
1757 : {
1758 : //the language is available - so bring it on
1759 0 : SvxAutoCorrectLanguageLists* pList = pLangTable->find(eLang)->second;
1760 0 : String _sTemp(sWord);
1761 0 : if(pList->GetWrdSttExceptList()->find(&_sTemp) != pList->GetWrdSttExceptList()->end() )
1762 0 : return sal_True;
1763 : }
1764 :
1765 : // If it still could not be found here, then keep on searching
1766 0 : if(nTmpKey1 != eLang && (pLangTable->find(nTmpKey1) != pLangTable->end() || CreateLanguageFile(nTmpKey1, sal_False)))
1767 : {
1768 : //the language is available - so bring it on
1769 0 : SvxAutoCorrectLanguageLists* pList = pLangTable->find(nTmpKey1)->second;
1770 0 : if(pList->GetWrdSttExceptList()->find(&sTemp) != pList->GetWrdSttExceptList()->end() )
1771 0 : return sal_True;
1772 : }
1773 :
1774 0 : if(nTmpKey2 != eLang && (pLangTable->find(nTmpKey2) != pLangTable->end() || CreateLanguageFile(nTmpKey2, sal_False)))
1775 : {
1776 : //the language is available - so bring it on
1777 0 : SvxAutoCorrectLanguageLists* pList = pLangTable->find(nTmpKey2)->second;
1778 0 : if(pList->GetWrdSttExceptList()->find(&sTemp) != pList->GetWrdSttExceptList()->end() )
1779 0 : return sal_True;
1780 : }
1781 :
1782 0 : if(pLangTable->find(LANGUAGE_UNDETERMINED) != pLangTable->end() || CreateLanguageFile(LANGUAGE_UNDETERMINED, sal_False))
1783 : {
1784 : //the language is available - so bring it on
1785 0 : SvxAutoCorrectLanguageLists* pList = pLangTable->find(LANGUAGE_UNDETERMINED)->second;
1786 0 : if(pList->GetWrdSttExceptList()->find(&sTemp) != pList->GetWrdSttExceptList()->end() )
1787 0 : return sal_True;
1788 : }
1789 0 : return sal_False;
1790 : }
1791 :
1792 0 : static sal_Bool lcl_FindAbbreviation( const SvStringsISortDtor* pList, const String& sWord)
1793 : {
1794 0 : String sAbk(rtl::OUString('~'));
1795 0 : SvStringsISortDtor::const_iterator it = pList->find( &sAbk );
1796 0 : sal_uInt16 nPos = it - pList->begin();
1797 0 : if( nPos < pList->size() )
1798 : {
1799 0 : String sLowerWord( sWord ); sLowerWord.ToLowerAscii();
1800 : const String* pAbk;
1801 0 : for( sal_uInt16 n = nPos;
1802 0 : n < pList->size() &&
1803 0 : '~' == ( pAbk = (*pList)[ n ])->GetChar( 0 );
1804 : ++n )
1805 : {
1806 : // ~ and ~. are not allowed!
1807 0 : if( 2 < pAbk->Len() && pAbk->Len() - 1 <= sWord.Len() )
1808 : {
1809 0 : String sLowerAbk( *pAbk ); sLowerAbk.ToLowerAscii();
1810 0 : for( xub_StrLen i = sLowerAbk.Len(), ii = sLowerWord.Len(); i; )
1811 : {
1812 0 : if( !--i ) // agrees
1813 0 : return sal_True;
1814 :
1815 0 : if( sLowerAbk.GetChar( i ) != sLowerWord.GetChar( --ii ))
1816 0 : break;
1817 0 : }
1818 : }
1819 0 : }
1820 : }
1821 : OSL_ENSURE( !(nPos && '~' == (*pList)[ --nPos ]->GetChar( 0 ) ),
1822 : "Wrongly sorted exception list?" );
1823 0 : return sal_False;
1824 : }
1825 :
1826 0 : sal_Bool SvxAutoCorrect::FindInCplSttExceptList(LanguageType eLang,
1827 : const String& sWord, sal_Bool bAbbreviation)
1828 : {
1829 : // First search for eLang, then US-English -> English
1830 : // and last in LANGUAGE_UNDETERMINED
1831 0 : LanguageType nTmpKey1 = eLang & 0x7ff, // the main language in many cases DE
1832 0 : nTmpKey2 = eLang & 0x3ff; // otherwise for example EN
1833 0 : String sTemp( sWord );
1834 :
1835 0 : if(pLangTable->find(eLang) != pLangTable->end() || CreateLanguageFile(eLang, sal_False))
1836 : {
1837 : //the language is available - so bring it on
1838 0 : const SvStringsISortDtor* pList = pLangTable->find(eLang)->second->GetCplSttExceptList();
1839 0 : if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->find(&sTemp) != pList->end() )
1840 0 : return sal_True;
1841 : }
1842 :
1843 : // If it still could not be found here, then keep on searching
1844 0 : if(nTmpKey1 != eLang && (pLangTable->find(nTmpKey1) != pLangTable->end() || CreateLanguageFile(nTmpKey1, sal_False)))
1845 : {
1846 0 : const SvStringsISortDtor* pList = pLangTable->find(nTmpKey1)->second->GetCplSttExceptList();
1847 0 : if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->find(&sTemp) != pList->end() )
1848 0 : return sal_True;
1849 : }
1850 :
1851 0 : if(nTmpKey2 != eLang && (pLangTable->find(nTmpKey2) != pLangTable->end() || CreateLanguageFile(nTmpKey2, sal_False)))
1852 : {
1853 : //the language is available - so bring it on
1854 0 : const SvStringsISortDtor* pList = pLangTable->find(nTmpKey2)->second->GetCplSttExceptList();
1855 0 : if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->find(&sTemp) != pList->end() )
1856 0 : return sal_True;
1857 : }
1858 :
1859 0 : if(pLangTable->find(LANGUAGE_UNDETERMINED) != pLangTable->end() || CreateLanguageFile(LANGUAGE_UNDETERMINED, sal_False))
1860 : {
1861 : //the language is available - so bring it on
1862 0 : const SvStringsISortDtor* pList = pLangTable->find(LANGUAGE_UNDETERMINED)->second->GetCplSttExceptList();
1863 0 : if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->find(&sTemp) != pList->end() )
1864 0 : return sal_True;
1865 : }
1866 0 : return sal_False;
1867 : }
1868 :
1869 0 : String SvxAutoCorrect::GetAutoCorrFileName( LanguageType eLang,
1870 : sal_Bool bNewFile, sal_Bool bTst ) const
1871 : {
1872 0 : String sRet, sExt( LanguageTag( eLang ).getBcp47() );
1873 :
1874 0 : sExt.Insert('_', 0);
1875 0 : sExt.AppendAscii( ".dat" );
1876 0 : if( bNewFile )
1877 0 : ( sRet = sUserAutoCorrFile ) += sExt;
1878 0 : else if( !bTst )
1879 0 : ( sRet = sShareAutoCorrFile ) += sExt;
1880 : else
1881 : {
1882 : // test first in the user directory - if not exist, then
1883 0 : ( sRet = sUserAutoCorrFile ) += sExt;
1884 0 : if( !FStatHelper::IsDocument( sRet ))
1885 0 : ( sRet = sShareAutoCorrFile ) += sExt;
1886 : }
1887 0 : return sRet;
1888 : }
1889 :
1890 0 : SvxAutoCorrectLanguageLists::SvxAutoCorrectLanguageLists(
1891 : SvxAutoCorrect& rParent,
1892 : const String& rShareAutoCorrectFile,
1893 : const String& rUserAutoCorrectFile)
1894 : : sShareAutoCorrFile( rShareAutoCorrectFile ),
1895 : sUserAutoCorrFile( rUserAutoCorrectFile ),
1896 : aModifiedDate( Date::EMPTY ),
1897 : aModifiedTime( Time::EMPTY ),
1898 : aLastCheckTime( Time::EMPTY ),
1899 : pCplStt_ExcptLst( 0 ),
1900 : pWrdStt_ExcptLst( 0 ),
1901 : pAutocorr_List( 0 ),
1902 : rAutoCorrect(rParent),
1903 0 : nFlags(0)
1904 : {
1905 0 : }
1906 :
1907 0 : SvxAutoCorrectLanguageLists::~SvxAutoCorrectLanguageLists()
1908 : {
1909 0 : delete pCplStt_ExcptLst;
1910 0 : delete pWrdStt_ExcptLst;
1911 0 : delete pAutocorr_List;
1912 0 : }
1913 :
1914 0 : sal_Bool SvxAutoCorrectLanguageLists::IsFileChanged_Imp()
1915 : {
1916 : // Access the file system only every 2 minutes to check the date stamp
1917 0 : sal_Bool bRet = sal_False;
1918 :
1919 0 : Time nMinTime( 0, 2 );
1920 0 : Time nAktTime( Time::SYSTEM );
1921 0 : if( aLastCheckTime > nAktTime || // overflow?
1922 0 : ( nAktTime -= aLastCheckTime ) > nMinTime ) // min time past
1923 : {
1924 0 : Date aTstDate( Date::EMPTY ); Time aTstTime( Time::EMPTY );
1925 0 : if( FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
1926 0 : &aTstDate, &aTstTime ) &&
1927 0 : ( aModifiedDate != aTstDate || aModifiedTime != aTstTime ))
1928 : {
1929 0 : bRet = sal_True;
1930 : // then remove all the lists fast!
1931 0 : if( CplSttLstLoad & nFlags && pCplStt_ExcptLst )
1932 0 : delete pCplStt_ExcptLst, pCplStt_ExcptLst = 0;
1933 0 : if( WrdSttLstLoad & nFlags && pWrdStt_ExcptLst )
1934 0 : delete pWrdStt_ExcptLst, pWrdStt_ExcptLst = 0;
1935 0 : if( ChgWordLstLoad & nFlags && pAutocorr_List )
1936 0 : delete pAutocorr_List, pAutocorr_List = 0;
1937 0 : nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad );
1938 : }
1939 0 : aLastCheckTime = Time( Time::SYSTEM );
1940 : }
1941 0 : return bRet;
1942 : }
1943 :
1944 0 : void SvxAutoCorrectLanguageLists::LoadXMLExceptList_Imp(
1945 : SvStringsISortDtor*& rpLst,
1946 : const sal_Char* pStrmName,
1947 : SotStorageRef& rStg)
1948 : {
1949 0 : if( rpLst )
1950 0 : rpLst->DeleteAndDestroyAll();
1951 : else
1952 0 : rpLst = new SvStringsISortDtor;
1953 :
1954 : {
1955 0 : String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 );
1956 0 : String sTmp( sStrmName );
1957 :
1958 0 : if( rStg.Is() && rStg->IsStream( sStrmName ) )
1959 : {
1960 : SvStorageStreamRef xStrm = rStg->OpenSotStream( sTmp,
1961 0 : ( STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE ) );
1962 0 : if( SVSTREAM_OK != xStrm->GetError())
1963 : {
1964 0 : xStrm.Clear();
1965 0 : rStg.Clear();
1966 0 : RemoveStream_Imp( sStrmName );
1967 : }
1968 : else
1969 : {
1970 : uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
1971 0 : comphelper::getProcessServiceFactory();
1972 : OSL_ENSURE( xServiceFactory.is(),
1973 : "XMLReader::Read: got no service manager" );
1974 0 : if( !xServiceFactory.is() )
1975 : {
1976 : // Throw an exception ?
1977 : }
1978 :
1979 0 : xml::sax::InputSource aParserInput;
1980 0 : aParserInput.sSystemId = sStrmName;
1981 :
1982 0 : xStrm->Seek( 0L );
1983 0 : xStrm->SetBufferSize( 8 * 1024 );
1984 0 : aParserInput.aInputStream = new utl::OInputStreamWrapper( *xStrm );
1985 :
1986 : // get filter
1987 0 : uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLExceptionListImport ( xServiceFactory, *rpLst );
1988 :
1989 : // connect parser and filter
1990 0 : uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create( comphelper::getComponentContext(xServiceFactory) );
1991 0 : xParser->setDocumentHandler( xFilter );
1992 :
1993 : // parse
1994 : try
1995 : {
1996 0 : xParser->parseStream( aParserInput );
1997 : }
1998 0 : catch( const xml::sax::SAXParseException& )
1999 : {
2000 : // re throw ?
2001 : }
2002 0 : catch( const xml::sax::SAXException& )
2003 : {
2004 : // re throw ?
2005 : }
2006 0 : catch( const io::IOException& )
2007 : {
2008 : // re throw ?
2009 0 : }
2010 0 : }
2011 : }
2012 :
2013 : // Set time stamp
2014 : FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
2015 0 : &aModifiedDate, &aModifiedTime );
2016 0 : aLastCheckTime = Time( Time::SYSTEM );
2017 : }
2018 :
2019 0 : }
2020 :
2021 0 : void SvxAutoCorrectLanguageLists::SaveExceptList_Imp(
2022 : const SvStringsISortDtor& rLst,
2023 : const sal_Char* pStrmName,
2024 : SotStorageRef &rStg,
2025 : sal_Bool bConvert )
2026 : {
2027 0 : if( rStg.Is() )
2028 : {
2029 0 : String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 );
2030 0 : if( rLst.empty() )
2031 : {
2032 0 : rStg->Remove( sStrmName );
2033 0 : rStg->Commit();
2034 : }
2035 : else
2036 : {
2037 : SotStorageStreamRef xStrm = rStg->OpenSotStream( sStrmName,
2038 0 : ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) );
2039 0 : if( xStrm.Is() )
2040 : {
2041 0 : xStrm->SetSize( 0 );
2042 0 : xStrm->SetBufferSize( 8192 );
2043 0 : OUString aMime( "text/xml" );
2044 0 : uno::Any aAny;
2045 0 : aAny <<= aMime;
2046 0 : xStrm->SetProperty( rtl::OUString("MediaType"), aAny );
2047 :
2048 :
2049 : uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2050 0 : comphelper::getProcessServiceFactory();
2051 : uno::Reference< uno::XComponentContext > xContext =
2052 0 : comphelper::getProcessComponentContext();
2053 :
2054 0 : uno::Reference < xml::sax::XWriter > xWriter = xml::sax::Writer::create(xContext);
2055 0 : uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *xStrm );
2056 0 : xWriter->setOutputStream(xOut);
2057 :
2058 0 : uno::Reference < xml::sax::XDocumentHandler > xHandler(xWriter, UNO_QUERY_THROW);
2059 0 : SvXMLExceptionListExport aExp( xServiceFactory, rLst, sStrmName, xHandler );
2060 :
2061 0 : aExp.exportDoc( XML_BLOCK_LIST );
2062 :
2063 0 : xStrm->Commit();
2064 0 : if( xStrm->GetError() == SVSTREAM_OK )
2065 : {
2066 0 : xStrm.Clear();
2067 0 : if (!bConvert)
2068 : {
2069 0 : rStg->Commit();
2070 0 : if( SVSTREAM_OK != rStg->GetError() )
2071 : {
2072 0 : rStg->Remove( sStrmName );
2073 0 : rStg->Commit();
2074 : }
2075 : }
2076 0 : }
2077 0 : }
2078 0 : }
2079 : }
2080 0 : }
2081 :
2082 0 : SvxAutocorrWordList* SvxAutoCorrectLanguageLists::LoadAutocorrWordList()
2083 : {
2084 0 : if( pAutocorr_List )
2085 0 : pAutocorr_List->DeleteAndDestroyAll();
2086 : else
2087 0 : pAutocorr_List = new SvxAutocorrWordList();
2088 :
2089 : try
2090 : {
2091 0 : uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sShareAutoCorrFile, embed::ElementModes::READ );
2092 0 : String aXMLWordListName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 );
2093 0 : uno::Reference < io::XStream > xStrm = xStg->openStreamElement( aXMLWordListName, embed::ElementModes::READ );
2094 0 : uno::Reference< lang::XMultiServiceFactory > xServiceFactory = comphelper::getProcessServiceFactory();
2095 0 : uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
2096 :
2097 0 : xml::sax::InputSource aParserInput;
2098 0 : aParserInput.sSystemId = aXMLWordListName;
2099 0 : aParserInput.aInputStream = xStrm->getInputStream();
2100 :
2101 : // get parser
2102 0 : uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(xContext);
2103 0 : RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "AutoCorrect Import" );
2104 0 : uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLAutoCorrectImport( xServiceFactory, pAutocorr_List, rAutoCorrect, xStg );
2105 :
2106 : // connect parser and filter
2107 0 : xParser->setDocumentHandler( xFilter );
2108 :
2109 : // parse
2110 0 : xParser->parseStream( aParserInput );
2111 : }
2112 0 : catch ( const uno::Exception& )
2113 : {
2114 : }
2115 :
2116 : // Set time stamp
2117 : FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
2118 0 : &aModifiedDate, &aModifiedTime );
2119 0 : aLastCheckTime = Time( Time::SYSTEM );
2120 :
2121 0 : return pAutocorr_List;
2122 : }
2123 :
2124 0 : void SvxAutoCorrectLanguageLists::SetAutocorrWordList( SvxAutocorrWordList* pList )
2125 : {
2126 0 : if( pAutocorr_List && pList != pAutocorr_List )
2127 0 : delete pAutocorr_List;
2128 0 : pAutocorr_List = pList;
2129 0 : if( !pAutocorr_List )
2130 : {
2131 : OSL_ENSURE( !this, "No valid list" );
2132 0 : pAutocorr_List = new SvxAutocorrWordList();
2133 : }
2134 0 : nFlags |= ChgWordLstLoad;
2135 0 : }
2136 :
2137 0 : const SvxAutocorrWordList* SvxAutoCorrectLanguageLists::GetAutocorrWordList()
2138 : {
2139 0 : if( !( ChgWordLstLoad & nFlags ) || IsFileChanged_Imp() )
2140 0 : SetAutocorrWordList( LoadAutocorrWordList() );
2141 0 : return pAutocorr_List;
2142 : }
2143 :
2144 0 : SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetCplSttExceptList()
2145 : {
2146 0 : if( !( CplSttLstLoad & nFlags ) || IsFileChanged_Imp() )
2147 0 : SetCplSttExceptList( LoadCplSttExceptList() );
2148 0 : return pCplStt_ExcptLst;
2149 : }
2150 :
2151 0 : sal_Bool SvxAutoCorrectLanguageLists::AddToCplSttExceptList(const String& rNew)
2152 : {
2153 0 : String* pNew = new String( rNew );
2154 0 : if( rNew.Len() && GetCplSttExceptList()->insert( pNew ).second )
2155 : {
2156 0 : MakeUserStorage_Impl();
2157 0 : SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2158 :
2159 0 : SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2160 :
2161 0 : xStg = 0;
2162 : // Set time stamp
2163 : FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2164 0 : &aModifiedDate, &aModifiedTime );
2165 0 : aLastCheckTime = Time( Time::SYSTEM );
2166 : }
2167 : else
2168 0 : delete pNew, pNew = 0;
2169 0 : return 0 != pNew;
2170 : }
2171 :
2172 0 : sal_Bool SvxAutoCorrectLanguageLists::AddToWrdSttExceptList(const String& rNew)
2173 : {
2174 0 : String* pNew = new String( rNew );
2175 0 : SvStringsISortDtor* pExceptList = LoadWrdSttExceptList();
2176 0 : if( rNew.Len() && pExceptList && pExceptList->insert( pNew ).second )
2177 : {
2178 0 : MakeUserStorage_Impl();
2179 0 : SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2180 :
2181 0 : SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2182 :
2183 0 : xStg = 0;
2184 : // Set time stamp
2185 : FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2186 0 : &aModifiedDate, &aModifiedTime );
2187 0 : aLastCheckTime = Time( Time::SYSTEM );
2188 : }
2189 : else
2190 0 : delete pNew, pNew = 0;
2191 0 : return 0 != pNew;
2192 : }
2193 :
2194 0 : SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadCplSttExceptList()
2195 : {
2196 0 : SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, sal_True );
2197 0 : String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) );
2198 0 : if( xStg.Is() && xStg->IsContained( sTemp ) )
2199 0 : LoadXMLExceptList_Imp( pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2200 :
2201 0 : return pCplStt_ExcptLst;
2202 : }
2203 :
2204 0 : void SvxAutoCorrectLanguageLists::SaveCplSttExceptList()
2205 : {
2206 0 : MakeUserStorage_Impl();
2207 0 : SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2208 :
2209 0 : SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2210 :
2211 0 : xStg = 0;
2212 :
2213 : // Set time stamp
2214 : FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2215 0 : &aModifiedDate, &aModifiedTime );
2216 0 : aLastCheckTime = Time( Time::SYSTEM );
2217 0 : }
2218 :
2219 0 : void SvxAutoCorrectLanguageLists::SetCplSttExceptList( SvStringsISortDtor* pList )
2220 : {
2221 0 : if( pCplStt_ExcptLst && pList != pCplStt_ExcptLst )
2222 0 : delete pCplStt_ExcptLst;
2223 :
2224 0 : pCplStt_ExcptLst = pList;
2225 0 : if( !pCplStt_ExcptLst )
2226 : {
2227 : OSL_ENSURE( !this, "No valid list" );
2228 0 : pCplStt_ExcptLst = new SvStringsISortDtor;
2229 : }
2230 0 : nFlags |= CplSttLstLoad;
2231 0 : }
2232 :
2233 0 : SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadWrdSttExceptList()
2234 : {
2235 0 : SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, sal_True );
2236 0 : String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) );
2237 0 : if( xStg.Is() && xStg->IsContained( sTemp ) )
2238 0 : LoadXMLExceptList_Imp( pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2239 0 : return pWrdStt_ExcptLst;
2240 : }
2241 :
2242 0 : void SvxAutoCorrectLanguageLists::SaveWrdSttExceptList()
2243 : {
2244 0 : MakeUserStorage_Impl();
2245 0 : SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2246 :
2247 0 : SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2248 :
2249 0 : xStg = 0;
2250 : // Set time stamp
2251 : FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2252 0 : &aModifiedDate, &aModifiedTime );
2253 0 : aLastCheckTime = Time( Time::SYSTEM );
2254 0 : }
2255 :
2256 0 : void SvxAutoCorrectLanguageLists::SetWrdSttExceptList( SvStringsISortDtor* pList )
2257 : {
2258 0 : if( pWrdStt_ExcptLst && pList != pWrdStt_ExcptLst )
2259 0 : delete pWrdStt_ExcptLst;
2260 0 : pWrdStt_ExcptLst = pList;
2261 0 : if( !pWrdStt_ExcptLst )
2262 : {
2263 : OSL_ENSURE( !this, "No valid list" );
2264 0 : pWrdStt_ExcptLst = new SvStringsISortDtor;
2265 : }
2266 0 : nFlags |= WrdSttLstLoad;
2267 0 : }
2268 :
2269 0 : SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetWrdSttExceptList()
2270 : {
2271 0 : if( !( WrdSttLstLoad & nFlags ) || IsFileChanged_Imp() )
2272 0 : SetWrdSttExceptList( LoadWrdSttExceptList() );
2273 0 : return pWrdStt_ExcptLst;
2274 : }
2275 :
2276 0 : void SvxAutoCorrectLanguageLists::RemoveStream_Imp( const String& rName )
2277 : {
2278 0 : if( sShareAutoCorrFile != sUserAutoCorrFile )
2279 : {
2280 0 : SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2281 0 : if( xStg.Is() && SVSTREAM_OK == xStg->GetError() &&
2282 0 : xStg->IsStream( rName ) )
2283 : {
2284 0 : xStg->Remove( rName );
2285 0 : xStg->Commit();
2286 :
2287 0 : xStg = 0;
2288 0 : }
2289 : }
2290 0 : }
2291 :
2292 0 : void SvxAutoCorrectLanguageLists::MakeUserStorage_Impl()
2293 : {
2294 : // The conversion needs to happen if the file is already in the user
2295 : // directory and is in the old format. Additionally it needs to
2296 : // happen when the file is being copied from share to user.
2297 :
2298 0 : sal_Bool bError = sal_False, bConvert = sal_False, bCopy = sal_False;
2299 0 : INetURLObject aDest;
2300 0 : INetURLObject aSource;
2301 :
2302 0 : if (sUserAutoCorrFile != sShareAutoCorrFile )
2303 : {
2304 0 : aSource = INetURLObject ( sShareAutoCorrFile );
2305 0 : aDest = INetURLObject ( sUserAutoCorrFile );
2306 0 : if ( SotStorage::IsOLEStorage ( sShareAutoCorrFile ) )
2307 : {
2308 0 : aDest.SetExtension ( rtl::OUString("bak") );
2309 0 : bConvert = sal_True;
2310 : }
2311 0 : bCopy = sal_True;
2312 : }
2313 0 : else if ( SotStorage::IsOLEStorage ( sUserAutoCorrFile ) )
2314 : {
2315 0 : aSource = INetURLObject ( sUserAutoCorrFile );
2316 0 : aDest = INetURLObject ( sUserAutoCorrFile );
2317 0 : aDest.SetExtension ( rtl::OUString("bak") );
2318 0 : bCopy = bConvert = sal_True;
2319 : }
2320 0 : if (bCopy)
2321 : {
2322 : try
2323 : {
2324 0 : String sMain(aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ));
2325 0 : sal_Unicode cSlash = '/';
2326 0 : xub_StrLen nSlashPos = sMain.SearchBackward(cSlash);
2327 0 : sMain.Erase(nSlashPos);
2328 0 : ::ucbhelper::Content aNewContent( sMain, uno::Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2329 0 : Any aAny;
2330 0 : TransferInfo aInfo;
2331 0 : aInfo.NameClash = NameClash::OVERWRITE;
2332 0 : aInfo.NewTitle = aDest.GetName();
2333 0 : aInfo.SourceURL = aSource.GetMainURL( INetURLObject::DECODE_TO_IURI );
2334 0 : aInfo.MoveData = sal_False;
2335 0 : aAny <<= aInfo;
2336 0 : aNewContent.executeCommand( OUString ( "transfer" ), aAny);
2337 : }
2338 0 : catch (...)
2339 : {
2340 0 : bError = sal_True;
2341 : }
2342 : }
2343 0 : if (bConvert && !bError)
2344 : {
2345 0 : SotStorageRef xSrcStg = new SotStorage( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), STREAM_READ, sal_True );
2346 0 : SotStorageRef xDstStg = new SotStorage( sUserAutoCorrFile, STREAM_WRITE, sal_True );
2347 :
2348 0 : if( xSrcStg.Is() && xDstStg.Is() )
2349 : {
2350 0 : String sWord ( RTL_CONSTASCII_USTRINGPARAM ( pImplWrdStt_ExcptLstStr ) );
2351 0 : String sSentence ( RTL_CONSTASCII_USTRINGPARAM ( pImplCplStt_ExcptLstStr ) );
2352 0 : String sXMLWord ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) );
2353 0 : String sXMLSentence ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) );
2354 0 : SvStringsISortDtor *pTmpWordList = NULL;
2355 :
2356 0 : if (xSrcStg->IsContained( sXMLWord ) )
2357 0 : LoadXMLExceptList_Imp( pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xSrcStg );
2358 :
2359 0 : if (pTmpWordList)
2360 : {
2361 0 : SaveExceptList_Imp( *pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xDstStg, sal_True );
2362 0 : pTmpWordList->DeleteAndDestroyAll();
2363 0 : pTmpWordList = NULL;
2364 : }
2365 :
2366 :
2367 0 : if (xSrcStg->IsContained( sXMLSentence ) )
2368 0 : LoadXMLExceptList_Imp( pTmpWordList, pXMLImplCplStt_ExcptLstStr, xSrcStg );
2369 :
2370 0 : if (pTmpWordList)
2371 : {
2372 0 : SaveExceptList_Imp( *pTmpWordList, pXMLImplCplStt_ExcptLstStr, xDstStg, sal_True );
2373 0 : pTmpWordList->DeleteAndDestroyAll();
2374 : }
2375 :
2376 0 : GetAutocorrWordList();
2377 0 : MakeBlocklist_Imp( *xDstStg );
2378 0 : sShareAutoCorrFile = sUserAutoCorrFile;
2379 0 : xDstStg = 0;
2380 : try
2381 : {
2382 0 : ::ucbhelper::Content aContent ( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), uno::Reference < XCommandEnvironment >(), comphelper::getProcessComponentContext() );
2383 0 : aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "delete" ) ), makeAny ( sal_Bool (sal_True ) ) );
2384 : }
2385 0 : catch (...)
2386 : {
2387 0 : }
2388 0 : }
2389 : }
2390 0 : else if( bCopy && !bError )
2391 0 : sShareAutoCorrFile = sUserAutoCorrFile;
2392 0 : }
2393 :
2394 0 : sal_Bool SvxAutoCorrectLanguageLists::MakeBlocklist_Imp( SvStorage& rStg )
2395 : {
2396 0 : String sStrmName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 );
2397 0 : sal_Bool bRet = sal_True, bRemove = !pAutocorr_List || pAutocorr_List->empty();
2398 0 : if( !bRemove )
2399 : {
2400 : SvStorageStreamRef refList = rStg.OpenSotStream( sStrmName,
2401 0 : ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) );
2402 0 : if( refList.Is() )
2403 : {
2404 0 : refList->SetSize( 0 );
2405 0 : refList->SetBufferSize( 8192 );
2406 0 : String aPropName( rtl::OUString( "MediaType" ) );
2407 0 : OUString aMime( "text/xml" );
2408 0 : uno::Any aAny;
2409 0 : aAny <<= aMime;
2410 0 : refList->SetProperty( aPropName, aAny );
2411 :
2412 : uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2413 0 : comphelper::getProcessServiceFactory();
2414 : uno::Reference< uno::XComponentContext > xContext =
2415 0 : comphelper::getProcessComponentContext();
2416 :
2417 0 : uno::Reference < xml::sax::XWriter > xWriter = xml::sax::Writer::create(xContext);
2418 0 : uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *refList );
2419 0 : xWriter->setOutputStream(xOut);
2420 :
2421 0 : uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY);
2422 0 : SvXMLAutoCorrectExport aExp( xServiceFactory, pAutocorr_List, sStrmName, xHandler );
2423 :
2424 0 : aExp.exportDoc( XML_BLOCK_LIST );
2425 :
2426 0 : refList->Commit();
2427 0 : bRet = SVSTREAM_OK == refList->GetError();
2428 0 : if( bRet )
2429 : {
2430 0 : refList.Clear();
2431 0 : rStg.Commit();
2432 0 : if( SVSTREAM_OK != rStg.GetError() )
2433 : {
2434 0 : bRemove = sal_True;
2435 0 : bRet = sal_False;
2436 : }
2437 0 : }
2438 : }
2439 : else
2440 0 : bRet = sal_False;
2441 : }
2442 :
2443 0 : if( bRemove )
2444 : {
2445 0 : rStg.Remove( sStrmName );
2446 0 : rStg.Commit();
2447 : }
2448 :
2449 0 : return bRet;
2450 : }
2451 :
2452 0 : sal_Bool SvxAutoCorrectLanguageLists::MakeCombinedChanges( std::vector<SvxAutocorrWord>& aNewEntries, std::vector<SvxAutocorrWord>& aDeleteEntries )
2453 : {
2454 : // First get the current list!
2455 0 : GetAutocorrWordList();
2456 :
2457 0 : MakeUserStorage_Impl();
2458 0 : SotStorageRef xStorage = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2459 :
2460 0 : sal_Bool bRet = xStorage.Is() && SVSTREAM_OK == xStorage->GetError();
2461 :
2462 0 : if( bRet )
2463 : {
2464 0 : for ( sal_uInt32 i=0; i < aDeleteEntries.size(); i++ )
2465 : {
2466 0 : SvxAutocorrWord aWordToDelete = aDeleteEntries[i];
2467 0 : SvxAutocorrWord *pFoundEntry = pAutocorr_List->FindAndRemove( &aWordToDelete );
2468 0 : if( pFoundEntry )
2469 : {
2470 0 : if( !pFoundEntry->IsTextOnly() )
2471 : {
2472 0 : String aName( aWordToDelete.GetShort() );
2473 0 : if (xStorage->IsOLEStorage())
2474 0 : EncryptBlockName_Imp( aName );
2475 : else
2476 0 : GeneratePackageName ( aWordToDelete.GetShort(), aName );
2477 :
2478 0 : if( xStorage->IsContained( aName ) )
2479 : {
2480 0 : xStorage->Remove( aName );
2481 0 : bRet = xStorage->Commit();
2482 0 : }
2483 : }
2484 0 : delete pFoundEntry;
2485 : }
2486 0 : }
2487 :
2488 0 : for ( sal_uInt32 i=0; i < aNewEntries.size(); i++ )
2489 : {
2490 0 : SvxAutocorrWord *pWordToAdd = new SvxAutocorrWord( aNewEntries[i].GetShort(), aNewEntries[i].GetLong(), sal_True );
2491 0 : SvxAutocorrWord *pRemoved = pAutocorr_List->FindAndRemove( pWordToAdd );
2492 0 : if( pRemoved )
2493 : {
2494 0 : if( !pRemoved->IsTextOnly() )
2495 : {
2496 : // Still have to remove the Storage
2497 0 : String sStorageName( pWordToAdd->GetShort() );
2498 0 : if (xStorage->IsOLEStorage())
2499 0 : EncryptBlockName_Imp( sStorageName );
2500 : else
2501 0 : GeneratePackageName ( pWordToAdd->GetShort(), sStorageName);
2502 :
2503 0 : if( xStorage->IsContained( sStorageName ) )
2504 0 : xStorage->Remove( sStorageName );
2505 : }
2506 0 : delete pRemoved;
2507 : }
2508 0 : bRet = pAutocorr_List->Insert( pWordToAdd );
2509 :
2510 0 : if ( !bRet )
2511 : {
2512 0 : delete pWordToAdd;
2513 0 : break;
2514 : }
2515 : }
2516 :
2517 0 : if ( bRet )
2518 : {
2519 0 : bRet = MakeBlocklist_Imp( *xStorage );
2520 : }
2521 : }
2522 0 : return bRet;
2523 : }
2524 :
2525 0 : sal_Bool SvxAutoCorrectLanguageLists::PutText( const String& rShort, const String& rLong )
2526 : {
2527 : // First get the current list!
2528 0 : GetAutocorrWordList();
2529 :
2530 0 : MakeUserStorage_Impl();
2531 0 : SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2532 :
2533 0 : sal_Bool bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError();
2534 :
2535 : // Update the word list
2536 0 : if( bRet )
2537 : {
2538 0 : SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, rLong, sal_True );
2539 0 : SvxAutocorrWord *pRemove = pAutocorr_List->FindAndRemove( pNew );
2540 0 : if( pRemove )
2541 : {
2542 0 : if( !pRemove->IsTextOnly() )
2543 : {
2544 : // Still have to remove the Storage
2545 0 : String sStgNm( rShort );
2546 0 : if (xStg->IsOLEStorage())
2547 0 : EncryptBlockName_Imp( sStgNm );
2548 : else
2549 0 : GeneratePackageName ( rShort, sStgNm);
2550 :
2551 0 : if( xStg->IsContained( sStgNm ) )
2552 0 : xStg->Remove( sStgNm );
2553 : }
2554 0 : delete pRemove;
2555 : }
2556 :
2557 0 : if( pAutocorr_List->Insert( pNew ) )
2558 : {
2559 0 : bRet = MakeBlocklist_Imp( *xStg );
2560 0 : xStg = 0;
2561 : }
2562 : else
2563 : {
2564 0 : delete pNew;
2565 0 : bRet = sal_False;
2566 : }
2567 : }
2568 0 : return bRet;
2569 : }
2570 :
2571 0 : sal_Bool SvxAutoCorrectLanguageLists::PutText( const String& rShort,
2572 : SfxObjectShell& rShell )
2573 : {
2574 : // First get the current list!
2575 0 : GetAutocorrWordList();
2576 :
2577 0 : MakeUserStorage_Impl();
2578 :
2579 0 : sal_Bool bRet = sal_False;
2580 0 : String sLong;
2581 : try
2582 : {
2583 0 : uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sUserAutoCorrFile, embed::ElementModes::READWRITE );
2584 0 : bRet = rAutoCorrect.PutText( xStg, sUserAutoCorrFile, rShort, rShell, sLong );
2585 0 : xStg = 0;
2586 :
2587 : // Update the word list
2588 0 : if( bRet )
2589 : {
2590 0 : SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, sLong, sal_False );
2591 0 : if( pAutocorr_List->Insert( pNew ) )
2592 : {
2593 0 : SotStorageRef xStor = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2594 0 : MakeBlocklist_Imp( *xStor );
2595 : }
2596 : else
2597 0 : delete pNew;
2598 0 : }
2599 : }
2600 0 : catch ( const uno::Exception& )
2601 : {
2602 : }
2603 :
2604 0 : return bRet;
2605 : }
2606 :
2607 : // Delete an entry
2608 0 : sal_Bool SvxAutoCorrectLanguageLists::DeleteText( const String& rShort )
2609 : {
2610 : // First get the current list!
2611 0 : GetAutocorrWordList();
2612 :
2613 0 : MakeUserStorage_Impl();
2614 :
2615 0 : SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2616 0 : sal_Bool bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError();
2617 0 : if( bRet )
2618 : {
2619 0 : SvxAutocorrWord aTmp( rShort, rShort );
2620 0 : SvxAutocorrWord *pFnd = pAutocorr_List->FindAndRemove( &aTmp );
2621 0 : if( pFnd )
2622 : {
2623 0 : if( !pFnd->IsTextOnly() )
2624 : {
2625 0 : String aName( rShort );
2626 0 : if (xStg->IsOLEStorage())
2627 0 : EncryptBlockName_Imp( aName );
2628 : else
2629 0 : GeneratePackageName ( rShort, aName );
2630 0 : if( xStg->IsContained( aName ) )
2631 : {
2632 0 : xStg->Remove( aName );
2633 0 : bRet = xStg->Commit();
2634 0 : }
2635 :
2636 : }
2637 0 : delete pFnd;
2638 0 : MakeBlocklist_Imp( *xStg );
2639 0 : xStg = 0;
2640 : }
2641 : else
2642 0 : bRet = sal_False;
2643 : }
2644 0 : return bRet;
2645 : }
2646 :
2647 : // Keep the list sorted ...
2648 0 : bool CompareSvxAutocorrWordList::operator()( SvxAutocorrWord* const& lhs, SvxAutocorrWord* const& rhs ) const
2649 : {
2650 0 : CollatorWrapper& rCmp = ::GetCollatorWrapper();
2651 0 : return rCmp.compareString( lhs->GetShort(), rhs->GetShort() ) < 0;
2652 : }
2653 :
2654 0 : SvxAutocorrWordList::~SvxAutocorrWordList()
2655 : {
2656 0 : DeleteAndDestroyAll();
2657 0 : }
2658 :
2659 0 : void SvxAutocorrWordList::DeleteAndDestroyAll()
2660 : {
2661 0 : for( SvxAutocorrWordList_Hash::const_iterator it = maHash.begin(); it != maHash.end(); ++it )
2662 0 : delete it->second;
2663 0 : maHash.clear();
2664 :
2665 0 : for( SvxAutocorrWordList_Set::const_iterator it2 = maSet.begin(); it2 != maSet.end(); ++it2 )
2666 0 : delete *it2;
2667 0 : maSet.clear();
2668 0 : }
2669 :
2670 : // returns true if inserted
2671 0 : bool SvxAutocorrWordList::Insert(SvxAutocorrWord *pWord)
2672 : {
2673 0 : if ( maSet.empty() ) // use the hash
2674 : {
2675 0 : rtl::OUString aShort( pWord->GetShort() );
2676 0 : return maHash.insert( std::pair<rtl::OUString, SvxAutocorrWord *>( aShort, pWord ) ).second;
2677 : }
2678 : else
2679 0 : return maSet.insert( pWord ).second;
2680 : }
2681 :
2682 0 : void SvxAutocorrWordList::LoadEntry(String sWrong, String sRight, sal_Bool bOnlyTxt)
2683 : {
2684 0 : SvxAutocorrWord* pNew = new SvxAutocorrWord( sWrong, sRight, bOnlyTxt );
2685 0 : if( !Insert( pNew ) )
2686 0 : delete pNew;
2687 0 : }
2688 :
2689 0 : bool SvxAutocorrWordList::empty() const
2690 : {
2691 0 : return maHash.empty() && maSet.empty();
2692 : }
2693 :
2694 0 : SvxAutocorrWord *SvxAutocorrWordList::FindAndRemove(SvxAutocorrWord *pWord)
2695 : {
2696 0 : SvxAutocorrWord *pMatch = NULL;
2697 :
2698 0 : if ( maSet.empty() ) // use the hash
2699 : {
2700 0 : SvxAutocorrWordList_Hash::iterator it = maHash.find( pWord->GetShort() );
2701 0 : if( it != maHash.end() )
2702 : {
2703 0 : pMatch = it->second;
2704 0 : maHash.erase (it);
2705 : }
2706 : }
2707 : else
2708 : {
2709 0 : SvxAutocorrWordList_Set::iterator it = maSet.find( pWord );
2710 0 : if( it != maSet.end() )
2711 : {
2712 0 : pMatch = *it;
2713 0 : maSet.erase (it);
2714 : }
2715 : }
2716 0 : return pMatch;
2717 : }
2718 :
2719 : // return the sorted contents - defer sorting until we have to.
2720 0 : SvxAutocorrWordList::Content SvxAutocorrWordList::getSortedContent() const
2721 : {
2722 0 : Content aContent;
2723 :
2724 : // convert from hash to set permanantly
2725 0 : if ( maSet.empty() )
2726 : {
2727 : // This beasty has some O(N log(N)) in a terribly slow ICU collate fn.
2728 0 : for( SvxAutocorrWordList_Hash::const_iterator it = maHash.begin(); it != maHash.end(); ++it )
2729 0 : maSet.insert( it->second );
2730 0 : maHash.clear();
2731 : }
2732 0 : for( SvxAutocorrWordList_Set::const_iterator it = maSet.begin(); it != maSet.end(); ++it )
2733 0 : aContent.push_back( *it );
2734 :
2735 0 : return aContent;
2736 : }
2737 :
2738 0 : bool SvxAutocorrWordList::WordMatches(const SvxAutocorrWord *pFnd,
2739 : const String &rTxt,
2740 : xub_StrLen &rStt,
2741 : xub_StrLen nEndPos) const
2742 : {
2743 0 : const String& rChk = pFnd->GetShort();
2744 0 : if( nEndPos >= rChk.Len() )
2745 : {
2746 0 : xub_StrLen nCalcStt = nEndPos - rChk.Len();
2747 0 : if( ( !nCalcStt || nCalcStt == rStt ||
2748 : ( nCalcStt < rStt &&
2749 0 : IsWordDelim( rTxt.GetChar( nCalcStt - 1 ) ))) )
2750 : {
2751 0 : TransliterationWrapper& rCmp = GetIgnoreTranslWrapper();
2752 :
2753 0 : rtl::OUString sWord(rTxt.GetBuffer() + nCalcStt, rChk.Len());
2754 0 : if( rCmp.isEqual( rChk, sWord ))
2755 : {
2756 0 : rStt = nCalcStt;
2757 0 : return true;
2758 0 : }
2759 : }
2760 : }
2761 0 : return false;
2762 : }
2763 :
2764 0 : const SvxAutocorrWord* SvxAutocorrWordList::SearchWordsInList(const String& rTxt, xub_StrLen& rStt,
2765 : xub_StrLen nEndPos) const
2766 : {
2767 0 : for( SvxAutocorrWordList_Hash::const_iterator it = maHash.begin(); it != maHash.end(); ++it )
2768 : {
2769 0 : if( WordMatches( it->second, rTxt, rStt, nEndPos ) )
2770 0 : return it->second;
2771 : }
2772 :
2773 0 : for( SvxAutocorrWordList_Set::const_iterator it2 = maSet.begin(); it2 != maSet.end(); ++it2 )
2774 : {
2775 0 : if( WordMatches( *it2, rTxt, rStt, nEndPos ) )
2776 0 : return *it2;
2777 : }
2778 0 : return 0;
2779 : }
2780 :
2781 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|