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